spotube/lib/provider/spotify/lyrics/synced.dart
Kingkor Roy Tirtho 6673e5a8a8
feat: improved caching based on riverpod (#1343)
* feat: add riverpod based favorite album provider

* feat: add album is saved, new releases and tracks providers

* feat: add artist related providers

* feat: add all categories providers

* feat: add lyrics provider

* feat: add playlist related providers

* feat: add search provider

* feat: add view and spotify friends provider

* feat: add playlist create and update and favorite handlers

* feat: use providers in home screen

* chore: fix dart lint issues

* feat: use new providers for playlist and albums screen

* feat: use providers in artist page

* feat: use providers on library page

* feat: use provider for playlist and album card and heart button

* feat: use provider in search page

* feat: use providers in generate playlist

* feat: use provider in lyrics screen

* feat: use provider for create playlist

* feat: use provider in add track dialog

* feat: use providers in remaining pages and remove fl_query

* fix: remove direct access to provider.value

* fix: glitching when loading

* fix: user album loading next page indicator

* feat: make many provider autoDispose after 5 minutes of no usage

* fix: ignore episodes in tracks
2024-03-20 23:38:39 +06:00

78 lines
2.3 KiB
Dart

part of '../spotify.dart';
class SyncedLyricsNotifier extends FamilyAsyncNotifier<SubtitleSimple, Track?>
with Persistence<SubtitleSimple> {
SyncedLyricsNotifier() {
load();
}
@override
FutureOr<SubtitleSimple> build(track) async {
final spotify = ref.watch(spotifyProvider);
if (track == null) {
throw "No track currently";
}
final token = await spotify.getCredentials();
final res = await http.get(
Uri.parse(
"https://spclient.wg.spotify.com/color-lyrics/v2/track/${track.id}?format=json&market=from_token",
),
headers: {
"User-Agent":
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36",
"App-platform": "WebPlayer",
"authorization": "Bearer ${token.accessToken}"
});
if (res.statusCode != 200) {
throw Exception("Unable to find lyrics");
}
final linesRaw = Map.castFrom<dynamic, dynamic, String, dynamic>(
jsonDecode(res.body),
)["lyrics"]?["lines"] as List?;
final lines = linesRaw?.map((line) {
return LyricSlice(
time: Duration(milliseconds: int.parse(line["startTimeMs"])),
text: line["words"] as String,
);
}).toList() ??
[];
return SubtitleSimple(
lyrics: lines,
name: track.name!,
uri: res.request!.url,
rating: 100,
);
}
@override
FutureOr<SubtitleSimple> fromJson(Map<String, dynamic> json) =>
SubtitleSimple.fromJson(json.castKeyDeep<String>());
@override
Map<String, dynamic> toJson(SubtitleSimple data) => data.toJson();
}
final syncedLyricsDelayProvider = StateProvider<int>((ref) => 0);
final syncedLyricsProvider =
AsyncNotifierProviderFamily<SyncedLyricsNotifier, SubtitleSimple, Track?>(
() => SyncedLyricsNotifier(),
);
final syncedLyricsMapProvider =
FutureProvider.family((ref, Track? track) async {
final syncedLyrics = await ref.watch(syncedLyricsProvider(track).future);
final isStaticLyrics =
syncedLyrics.lyrics.every((l) => l.time == Duration.zero);
final lyricsMap = syncedLyrics.lyrics
.map((lyric) => {lyric.time.inSeconds: lyric.text})
.reduce((accumulator, lyricSlice) => {...accumulator, ...lyricSlice});
return (static: isStaticLyrics, lyricsMap: lyricsMap);
});