From 34ffbca3e84dfb37c7f67000b03e90b280fc8846 Mon Sep 17 00:00:00 2001 From: zarzet Date: Wed, 4 Feb 2026 12:18:53 +0700 Subject: [PATCH] fix: improve share intent handling for YouTube Music links - Check both path and message fields for shared URLs - Wait for extensions to initialize before handling shared URLs - Add retry logic (3 attempts) for extension URL handlers with empty data - Show error message if metadata fails to load after retries --- lib/providers/track_provider.dart | 35 ++++++++++++++++++++++++-- lib/screens/main_shell.dart | 20 ++++++++++++++- lib/services/share_intent_service.dart | 22 ++++++++++------ 3 files changed, 66 insertions(+), 11 deletions(-) diff --git a/lib/providers/track_provider.dart b/lib/providers/track_provider.dart index b088bb4..7101c12 100644 --- a/lib/providers/track_provider.dart +++ b/lib/providers/track_provider.dart @@ -197,8 +197,30 @@ class TrackNotifier extends Notifier { final extensionHandler = await PlatformBridge.findURLHandler(url); if (extensionHandler != null) { _log.i('Found extension URL handler: $extensionHandler for URL: $url'); - final result = await PlatformBridge.handleURLWithExtension(url); - if (!_isRequestValid(requestId)) return; + + // Retry logic for extension URL handlers (up to 3 attempts) + Map? result; + for (int attempt = 1; attempt <= 3; attempt++) { + result = await PlatformBridge.handleURLWithExtension(url); + if (!_isRequestValid(requestId)) return; + + // Check if we got valid data + if (result != null && result['type'] == 'track' && result['track'] != null) { + final trackData = result['track'] as Map; + final name = trackData['name']?.toString() ?? ''; + if (name.isNotEmpty) { + break; + } + } else if (result != null && (result['type'] == 'album' || result['type'] == 'playlist')) { + break; + } else if (result != null && result['type'] == 'artist') { + break; + } + + if (attempt < 3) { + await Future.delayed(const Duration(milliseconds: 500)); + } + } if (result != null) { final type = result['type'] as String?; @@ -207,6 +229,15 @@ class TrackNotifier extends Notifier { if (type == 'track' && result['track'] != null) { final trackData = result['track'] as Map; final track = _parseSearchTrack(trackData, source: extensionId); + + if (track.name.isEmpty) { + state = TrackState( + isLoading: false, + error: 'Failed to load track metadata from extension', + ); + return; + } + state = TrackState( tracks: [track], isLoading: false, diff --git a/lib/screens/main_shell.dart b/lib/screens/main_shell.dart index b2b0eb8..06e2877 100644 --- a/lib/screens/main_shell.dart +++ b/lib/screens/main_shell.dart @@ -4,6 +4,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:spotiflac_android/l10n/l10n.dart'; import 'package:spotiflac_android/providers/download_queue_provider.dart'; +import 'package:spotiflac_android/providers/extension_provider.dart'; import 'package:spotiflac_android/providers/settings_provider.dart'; import 'package:spotiflac_android/providers/store_provider.dart'; import 'package:spotiflac_android/providers/track_provider.dart'; @@ -61,7 +62,24 @@ class _MainShellState extends ConsumerState { ); } - void _handleSharedUrl(String url) { + Future _handleSharedUrl(String url) async { + // Wait for extensions to be initialized before handling URL + final extState = ref.read(extensionProvider); + if (!extState.isInitialized) { + _log.d('Waiting for extensions to initialize before handling URL...'); + // Wait up to 5 seconds for extensions to initialize + for (int i = 0; i < 50; i++) { + await Future.delayed(const Duration(milliseconds: 100)); + if (!mounted) return; + if (ref.read(extensionProvider).isInitialized) { + _log.d('Extensions initialized, proceeding with URL handling'); + break; + } + } + } + + if (!mounted) return; + Navigator.of(context).popUntil((route) => route.isFirst); if (_currentIndex != 0) { diff --git a/lib/services/share_intent_service.dart b/lib/services/share_intent_service.dart index 2ba7966..274bd23 100644 --- a/lib/services/share_intent_service.dart +++ b/lib/services/share_intent_service.dart @@ -65,16 +65,22 @@ class ShareIntentService { void _handleSharedMedia(List files, {bool isInitial = false}) { for (final file in files) { - final textToCheck = file.path; + // Check both path and message - apps may share URL in either field + final textsToCheck = [ + file.path, + if (file.message != null) file.message!, + ]; - final url = _extractMusicUrl(textToCheck); - if (url != null) { - _log.i('Received music URL: $url (initial: $isInitial)'); - if (isInitial) { - _pendingUrl = url; + for (final textToCheck in textsToCheck) { + final url = _extractMusicUrl(textToCheck); + if (url != null) { + _log.i('Received music URL: $url (initial: $isInitial)'); + if (isInitial) { + _pendingUrl = url; + } + _sharedUrlController.add(url); + return; } - _sharedUrlController.add(url); - return; } } }