🐛 Fix lyrics fetch
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_media_metadata/flutter_media_metadata.dart';
|
||||
import 'package:groovybox/providers/db_provider.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
@@ -69,7 +70,7 @@ class TrackRepository extends _$TrackRepository {
|
||||
mode: InsertMode.insertOrIgnore,
|
||||
);
|
||||
} catch (e) {
|
||||
print('Error importing file $path: $e');
|
||||
debugPrint('Error importing file $path: $e');
|
||||
// Continue to next file
|
||||
}
|
||||
}
|
||||
@@ -112,7 +113,7 @@ class TrackRepository extends _$TrackRepository {
|
||||
try {
|
||||
await file.delete();
|
||||
} catch (e) {
|
||||
print("Error deleting file: $e");
|
||||
debugPrint("Error deleting file: $e");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +124,7 @@ class TrackRepository extends _$TrackRepository {
|
||||
try {
|
||||
await artFile.delete();
|
||||
} catch (e) {
|
||||
print("Error deleting art: $e");
|
||||
debugPrint("Error deleting art: $e");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@ class Lyrics {
|
||||
}
|
||||
|
||||
/// Abstract base class for LRC providers
|
||||
abstract class LRCProvider {
|
||||
abstract class LrcProvider {
|
||||
late final http.Client session;
|
||||
|
||||
LRCProvider() {
|
||||
LrcProvider() {
|
||||
session = http.Client();
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ abstract class LRCProvider {
|
||||
}
|
||||
|
||||
/// Musixmatch LRC provider
|
||||
class MusixmatchProvider extends LRCProvider {
|
||||
class MusixmatchProvider extends LrcProvider {
|
||||
static const String rootUrl = "https://apic-desktop.musixmatch.com/ws/1.1/";
|
||||
|
||||
final String? lang;
|
||||
@@ -38,6 +38,7 @@ class MusixmatchProvider extends LRCProvider {
|
||||
|
||||
MusixmatchProvider({this.lang, this.enhanced = false});
|
||||
|
||||
@override
|
||||
String get name => 'Musixmatch';
|
||||
|
||||
Future<http.Response> _get(
|
||||
@@ -178,7 +179,7 @@ class MusixmatchProvider extends LRCProvider {
|
||||
}
|
||||
|
||||
/// NetEase provider
|
||||
class NetEaseProvider extends LRCProvider {
|
||||
class NetEaseProvider extends LrcProvider {
|
||||
static const String apiEndpointMetadata =
|
||||
"https://music.163.com/api/search/pc";
|
||||
static const String apiEndpointLyrics =
|
||||
@@ -211,7 +212,7 @@ class NetEaseProvider extends LRCProvider {
|
||||
headers: {"cookie": cookie},
|
||||
);
|
||||
final data = jsonDecode(response.body);
|
||||
final lrc = Lyrics(plain: data["lrc"]["lyric"]);
|
||||
final lrc = Lyrics(synced: data["lrc"]["lyric"]);
|
||||
return lrc;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:groovybox/data/db.dart' as db;
|
||||
import 'package:drift/drift.dart' as drift;
|
||||
import 'package:groovybox/logic/lrc_providers.dart';
|
||||
import 'package:groovybox/logic/lyrics_parser.dart';
|
||||
import 'package:groovybox/providers/db_provider.dart';
|
||||
import 'package:groovybox/ui/screens/player_screen.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
@@ -18,14 +20,18 @@ class LyricsFetcher extends _$LyricsFetcher {
|
||||
Future<void> fetchLyricsForTrack({
|
||||
required int trackId,
|
||||
required String searchTerm,
|
||||
required LRCProvider provider,
|
||||
required LrcProvider provider,
|
||||
required String trackPath,
|
||||
}) async {
|
||||
debugPrint(
|
||||
'Fetching lyrics for track $trackId with search term: $searchTerm',
|
||||
);
|
||||
state = state.copyWith(isLoading: true, error: null);
|
||||
|
||||
try {
|
||||
final lyrics = await provider.getLrc(searchTerm);
|
||||
if (lyrics == null) {
|
||||
debugPrint('No lyrics found from ${provider.name}');
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
error: 'No lyrics found from ${provider.name}',
|
||||
@@ -52,17 +58,26 @@ class LyricsFetcher extends _$LyricsFetcher {
|
||||
..where((t) => t.id.equals(trackId)))
|
||||
.write(db.TracksCompanion(lyrics: drift.Value(lyricsJson)));
|
||||
|
||||
debugPrint('Updated database with lyrics for track $trackId');
|
||||
|
||||
// Invalidate the track provider to refresh the UI
|
||||
ref.invalidate(trackByPathProvider(trackPath));
|
||||
|
||||
debugPrint('Invalidated track provider for $trackPath');
|
||||
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
successMessage: 'Lyrics fetched from ${provider.name}',
|
||||
);
|
||||
} else {
|
||||
debugPrint('Failed to parse lyrics');
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
error: 'Failed to parse lyrics',
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Error fetching lyrics: $e');
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
error: 'Error fetching lyrics: $e',
|
||||
|
||||
@@ -41,7 +41,7 @@ final class LyricsFetcherProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$lyricsFetcherHash() => r'49468a75e00ab1533368acb52328b059831836d3';
|
||||
String _$lyricsFetcherHash() => r'52296b2ccb55755ec5ad7ab751fe974dc3c64024';
|
||||
|
||||
abstract class _$LyricsFetcher extends $Notifier<LyricsFetcherState> {
|
||||
LyricsFetcherState build();
|
||||
|
||||
@@ -295,7 +295,7 @@ class _PlayerLyrics extends HookConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
// Watch for track data (including lyrics) by path
|
||||
final trackAsync = trackPath != null
|
||||
? ref.watch(_trackByPathProvider(trackPath!))
|
||||
? ref.watch(trackByPathProvider(trackPath!))
|
||||
: const AsyncValue<db.Track?>.data(null);
|
||||
|
||||
final metadataAsync = trackPath != null
|
||||
@@ -497,7 +497,7 @@ class _LyricsRefreshButton extends HookConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final trackAsync = ref.watch(_trackByPathProvider(trackPath));
|
||||
final trackAsync = ref.watch(trackByPathProvider(trackPath));
|
||||
final metadataAsync = ref.watch(trackMetadataProvider(trackPath));
|
||||
final musixmatchProviderInstance = ref.watch(musixmatchProvider);
|
||||
final neteaseProviderInstance = ref.watch(neteaseProvider);
|
||||
@@ -522,6 +522,76 @@ class _LyricsRefreshButton extends HookConsumerWidget {
|
||||
);
|
||||
}
|
||||
|
||||
void _showFetchLyricsDialog(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
db.Track track,
|
||||
String trackPath,
|
||||
dynamic metadataObj,
|
||||
musixmatchProvider,
|
||||
neteaseProvider,
|
||||
) {
|
||||
final metadata = metadataObj as TrackMetadata?;
|
||||
final searchTerm =
|
||||
'${metadata?.title ?? track.title} ${metadata?.artist ?? track.artist}'
|
||||
.trim();
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Fetch Lyrics'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('Search term: $searchTerm'),
|
||||
const SizedBox(height: 16),
|
||||
Text('Choose a provider:'),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
_ProviderButton(
|
||||
name: 'Musixmatch',
|
||||
onPressed: () async {
|
||||
Navigator.of(context).pop();
|
||||
await ref
|
||||
.read(lyricsFetcherProvider.notifier)
|
||||
.fetchLyricsForTrack(
|
||||
trackId: track.id,
|
||||
searchTerm: searchTerm,
|
||||
provider: musixmatchProvider,
|
||||
trackPath: trackPath,
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
_ProviderButton(
|
||||
name: 'NetEase',
|
||||
onPressed: () async {
|
||||
Navigator.of(context).pop();
|
||||
await ref
|
||||
.read(lyricsFetcherProvider.notifier)
|
||||
.fetchLyricsForTrack(
|
||||
trackId: track.id,
|
||||
searchTerm: searchTerm,
|
||||
provider: neteaseProvider,
|
||||
trackPath: trackPath,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showLyricsRefreshDialog(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
@@ -547,20 +617,17 @@ class _LyricsRefreshButton extends HookConsumerWidget {
|
||||
label: const Text('Re-fetch'),
|
||||
onPressed: trackAsync.maybeWhen(
|
||||
data: (track) => track != null
|
||||
? () async {
|
||||
? () {
|
||||
Navigator.of(context).pop();
|
||||
final metadata = metadataAsync.value;
|
||||
final searchTerm =
|
||||
'${metadata?.title ?? track.title} ${metadata?.artist ?? track.artist}'
|
||||
.trim();
|
||||
await ref
|
||||
.read(lyricsFetcherProvider.notifier)
|
||||
.fetchLyricsForTrack(
|
||||
trackId: track.id,
|
||||
searchTerm: searchTerm,
|
||||
provider:
|
||||
musixmatchProvider, // Default to Musixmatch
|
||||
trackPath: trackPath,
|
||||
_showFetchLyricsDialog(
|
||||
context,
|
||||
ref,
|
||||
track,
|
||||
trackPath,
|
||||
metadata,
|
||||
musixmatchProvider,
|
||||
neteaseProvider,
|
||||
);
|
||||
}
|
||||
: null,
|
||||
@@ -581,6 +648,9 @@ class _LyricsRefreshButton extends HookConsumerWidget {
|
||||
data: (track) => track != null
|
||||
? () async {
|
||||
Navigator.of(context).pop();
|
||||
debugPrint(
|
||||
'Clearing lyrics for track ${track.id}',
|
||||
);
|
||||
final database = ref.read(databaseProvider);
|
||||
await (database.update(
|
||||
database.tracks,
|
||||
@@ -589,6 +659,12 @@ class _LyricsRefreshButton extends HookConsumerWidget {
|
||||
lyrics: const drift.Value.absent(),
|
||||
),
|
||||
);
|
||||
debugPrint('Cleared lyrics from database');
|
||||
// Invalidate the track provider to refresh the UI
|
||||
ref.invalidate(trackByPathProvider(trackPath));
|
||||
debugPrint(
|
||||
'Invalidated track provider for $trackPath',
|
||||
);
|
||||
}
|
||||
: null,
|
||||
orElse: () => null,
|
||||
@@ -611,7 +687,7 @@ class _LyricsRefreshButton extends HookConsumerWidget {
|
||||
}
|
||||
|
||||
// Provider to fetch a single track by path
|
||||
final _trackByPathProvider = FutureProvider.family<db.Track?, String>((
|
||||
final trackByPathProvider = FutureProvider.family<db.Track?, String>((
|
||||
ref,
|
||||
trackPath,
|
||||
) async {
|
||||
|
||||
Reference in New Issue
Block a user