Compare commits

..

2 Commits

Author SHA1 Message Date
Seungmin Kim
4277c5af47
Merge 2c5cd8d505 into 0ec9f3535b 2025-03-26 13:30:23 +00:00
Seungmin Kim
2c5cd8d505 Add ISRC track search for YouTube 2025-03-26 06:30:08 -07:00
4 changed files with 34 additions and 36 deletions

View File

@ -75,7 +75,7 @@ extension TrackSimpleExtensions on TrackSimple {
final spotify = ref.read(spotifyProvider); final spotify = ref.read(spotifyProvider);
return await spotify.invoke((api) => api.tracks.get(id!)); return await spotify.invoke((api) => api.tracks.get(id!));
} catch (e, stack) { } catch (e, stack) {
// Ignore this error and create the Track locally // Ignore errors and create the track locally
AppLogger.reportError(e, stack); AppLogger.reportError(e, stack);
Track track = Track(); Track track = Track();

View File

@ -54,8 +54,8 @@ class AlbumCard extends HookConsumerWidget {
Future<List<Track>> fetchAllTrack() async { Future<List<Track>> fetchAllTrack() async {
if (album.tracks != null && album.tracks!.isNotEmpty) { if (album.tracks != null && album.tracks!.isNotEmpty) {
return Future.wait( return await Future.wait(
album.tracks!.map((track) => track.asTrack(album, ref)).toList()); album.tracks!.map((track) => track.asTrack(album, ref)));
} }
await ref.read(albumTracksProvider(album).future); await ref.read(albumTracksProvider(album).future);
return ref.read(albumTracksProvider(album).notifier).fetchAll(); return ref.read(albumTracksProvider(album).notifier).fetchAll();

View File

@ -33,7 +33,7 @@ class AlbumTracksNotifier extends AutoDisposeFamilyPaginatedAsyncNotifier<Track,
final tracks = await spotify.invoke( final tracks = await spotify.invoke(
(api) => api.albums.tracks(arg.id!).getPage(limit, offset), (api) => api.albums.tracks(arg.id!).getPage(limit, offset),
); );
final List<Track> items = await Future.wait(tracks.items?.map((e) => e.asTrack(arg, ref)).toList() ?? []); final List<Track> items = await Future.wait(tracks.items?.map((e) => e.asTrack(arg, ref)) ?? []);
return ( return (
items: items, items: items,

View File

@ -248,30 +248,31 @@ class YoutubeSourcedTrack extends SourcedTrack {
.read(provider) .read(provider)
.searchVideos(isrc.toString()); .searchVideos(isrc.toString());
if (searchedVideos.isNotEmpty) { if (searchedVideos.isNotEmpty) {
isrcResults.addAll(await Future.wait( isrcResults.addAll(searchedVideos
searchedVideos .map<YoutubeVideoInfo>(YoutubeVideoInfo.fromVideo)
.map<YoutubeVideoInfo>(YoutubeVideoInfo.fromVideo) .map((YoutubeVideoInfo videoInfo) {
.map((YoutubeVideoInfo videoInfo) async { final ytWords =
final titleWords = videoInfo.title
videoInfo.title .toLowerCase()
.toLowerCase() .replaceAll(RegExp(r'[^a-zA-Z0-9\s]+'), '')
.replaceAll(RegExp(r'[^a-zA-Z0-9\s]+'), '') .split(RegExp(r'\s+'))
.split(RegExp(r'\s+')) .where((item) => item.isNotEmpty);
.where((item) => item.isNotEmpty) final spWords =
.toList(); track.name!
final nameLower = .toLowerCase()
track.name! .replaceAll(RegExp(r'\((.*)\)'), '')
.toLowerCase() .replaceAll(RegExp(r'[^a-zA-Z0-9\s]+'), '')
.replaceAll(RegExp(r'[^a-zA-Z0-9\s]+'), '') .split(RegExp(r'\s+'))
.split(RegExp(r'\s+')) .where((item) => item.isNotEmpty);
.where((item) => item.isNotEmpty) // Word match to filter out unrelated results
.toList(); final matchCount =
if (titleWords.any((word) => nameLower.contains(word))) { ytWords.where((word) => spWords.contains(word)).length;
return videoInfo; if (matchCount > spWords.length ~/ 2) {
return videoInfo;
}
return null;
} }
return null; ).whereType<YoutubeVideoInfo>().toList());
}
)).then((s) => s.whereType<YoutubeVideoInfo>().toList()));
} }
} }
return isrcResults; return isrcResults;
@ -292,11 +293,9 @@ class YoutubeSourcedTrack extends SourcedTrack {
try { try {
videoResults.add( videoResults.add(
YoutubeVideoInfo.fromVideo( YoutubeVideoInfo.fromVideo(
await ref await ref.read(youtubeEngineProvider)
.read(youtubeEngineProvider) .getVideo(Uri.parse(ytLink!.url!).queryParameters["v"]!)
.getVideo(Uri.parse(ytLink!.url!).queryParameters["v"]!), ));
)
);
} on VideoUnplayableException catch (e, stack) { } on VideoUnplayableException catch (e, stack) {
// Ignore this error and continue with the search // Ignore this error and continue with the search
AppLogger.reportError(e, stack); AppLogger.reportError(e, stack);
@ -305,13 +304,12 @@ class YoutubeSourcedTrack extends SourcedTrack {
final query = SourcedTrack.getSearchTerm(track); final query = SourcedTrack.getSearchTerm(track);
final searchResults = await ref final searchResults =
.read(youtubeEngineProvider) await ref.read(youtubeEngineProvider).searchVideos(query);
.searchVideos(query);
if (ServiceUtils.onlyContainsEnglish(query)) { if (ServiceUtils.onlyContainsEnglish(query)) {
videoResults.addAll( videoResults.addAll(
searchResults.map(YoutubeVideoInfo.fromVideo).toList(), searchResults.map(YoutubeVideoInfo.fromVideo).toList()
); );
} else { } else {
videoResults.addAll(rankResults( videoResults.addAll(rankResults(