mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-12 23:45:18 +00:00
fix: artist images are not loading up
This commit is contained in:
parent
d3edf07ac9
commit
5ff1fc9f82
@ -25,7 +25,13 @@ class TopArtists extends HookConsumerWidget {
|
||||
ref.watch(historyTopTracksProvider(historyDuration).notifier);
|
||||
|
||||
final artistsData = useMemoized(
|
||||
() => topTracks.asData?.value.artists ?? [], [topTracks.asData?.value]);
|
||||
() => topTracks.asData?.value.artists ?? [],
|
||||
[topTracks.asData?.value],
|
||||
);
|
||||
|
||||
for (final artist in artistsData) {
|
||||
print("${artist.artist.name} has ${artist.artist.images?.length} images");
|
||||
}
|
||||
|
||||
return Skeletonizer.sliver(
|
||||
enabled: topTracks.isLoading && !topTracks.isLoadingNextPage,
|
||||
|
@ -121,7 +121,16 @@ class SearchPage extends HookConsumerWidget {
|
||||
}
|
||||
},
|
||||
child: AutoComplete(
|
||||
suggestions: suggestions,
|
||||
suggestions: suggestions.length <= 2
|
||||
? [
|
||||
...suggestions,
|
||||
"Twenty One Pilots",
|
||||
"Linkin Park",
|
||||
"d4vd"
|
||||
]
|
||||
: suggestions,
|
||||
completer: (suggestion) => suggestion,
|
||||
mode: AutoCompleteMode.replaceAll,
|
||||
child: TextField(
|
||||
autofocus: true,
|
||||
controller: controller,
|
||||
|
@ -2,6 +2,7 @@ import 'dart:async';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/models/local_track.dart';
|
||||
import 'package:spotube/provider/audio_player/audio_player.dart';
|
||||
import 'package:spotube/provider/audio_player/state.dart';
|
||||
@ -10,6 +11,7 @@ import 'package:spotube/provider/history/history.dart';
|
||||
import 'package:spotube/provider/skip_segments/skip_segments.dart';
|
||||
import 'package:spotube/provider/scrobbler/scrobbler.dart';
|
||||
import 'package:spotube/provider/server/sourced_track.dart';
|
||||
import 'package:spotube/provider/spotify/spotify.dart';
|
||||
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
||||
import 'package:spotube/services/audio_player/audio_player.dart';
|
||||
import 'package:spotube/services/audio_services/audio_services.dart';
|
||||
@ -80,7 +82,7 @@ class AudioPlayerStreamListeners {
|
||||
|
||||
StreamSubscription subscribeToScrobbleChanged() {
|
||||
String? lastScrobbled;
|
||||
return audioPlayer.positionStream.listen((position) {
|
||||
return audioPlayer.positionStream.listen((position) async {
|
||||
try {
|
||||
final uid = audioPlayerState.activeTrack is LocalTrack
|
||||
? (audioPlayerState.activeTrack as LocalTrack).path
|
||||
@ -93,8 +95,23 @@ class AudioPlayerStreamListeners {
|
||||
}
|
||||
|
||||
scrobbler.scrobble(audioPlayerState.activeTrack!);
|
||||
history.addTrack(audioPlayerState.activeTrack!);
|
||||
lastScrobbled = uid;
|
||||
|
||||
/// The [Track] from Playlist.getTracks doesn't contain artist images
|
||||
/// so we need to fetch them from the API
|
||||
final activeTrack =
|
||||
Track.fromJson(audioPlayerState.activeTrack!.toJson());
|
||||
if (audioPlayerState.activeTrack!.artists
|
||||
?.any((a) => a.images == null) ??
|
||||
false) {
|
||||
activeTrack.artists =
|
||||
await ref.read(spotifyProvider).api.artists.list([
|
||||
for (final artist in audioPlayerState.activeTrack!.artists!)
|
||||
artist.id!,
|
||||
]).then((value) => value.toList());
|
||||
}
|
||||
|
||||
await history.addTrack(activeTrack);
|
||||
} catch (e, stack) {
|
||||
AppLogger.reportError(e, stack);
|
||||
}
|
||||
|
@ -39,6 +39,11 @@ class PlaybackHistoryActions {
|
||||
}
|
||||
|
||||
Future<void> addTracks(List<Track> tracks) async {
|
||||
assert(
|
||||
tracks.every((t) => t.artists?.every((a) => a.images != null) ?? false),
|
||||
'Track artists must have images',
|
||||
);
|
||||
|
||||
await _batchInsertHistoryEntries([
|
||||
for (final track in tracks)
|
||||
HistoryTableCompanion.insert(
|
||||
@ -50,6 +55,11 @@ class PlaybackHistoryActions {
|
||||
}
|
||||
|
||||
Future<void> addTrack(Track track) async {
|
||||
assert(
|
||||
track.artists?.every((a) => a.images != null) ?? false,
|
||||
'Track artists must have images',
|
||||
);
|
||||
|
||||
await _db.into(_db.historyTable).insert(
|
||||
HistoryTableCompanion.insert(
|
||||
type: HistoryEntryType.track,
|
||||
|
@ -28,7 +28,15 @@ class HistoryTopTracksState extends PaginatedState<PlaybackHistoryTrack> {
|
||||
return groupBy(artists, (artist) => artist.id!)
|
||||
.entries
|
||||
.map((entry) {
|
||||
return (count: entry.value.length, artist: entry.value.first);
|
||||
return (
|
||||
count: entry.value.length,
|
||||
|
||||
/// Previously, due to a bug, artist images were not being saved.
|
||||
/// Now it's fixed, but we need to handle the case where images are null.
|
||||
/// So we take the first artist with images if available, otherwise the first one.
|
||||
artist: entry.value.firstWhereOrNull((a) => a.images != null) ??
|
||||
entry.value.first,
|
||||
);
|
||||
})
|
||||
.sorted((a, b) => b.count.compareTo(a.count))
|
||||
.toList();
|
||||
@ -85,11 +93,58 @@ class HistoryTopTracksNotifier extends FamilyPaginatedAsyncNotifier<
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> fixImageNotLoadingForArtistIssue(
|
||||
List<HistoryTableData> entries,
|
||||
) async {
|
||||
final nonImageArtistTracks =
|
||||
entries.where((e) => e.track!.artists!.any((a) => a.images == null));
|
||||
|
||||
if (nonImageArtistTracks.isEmpty) return;
|
||||
|
||||
final artistIds = nonImageArtistTracks
|
||||
.map((e) => e.track!.artists!.map((a) => a.id!))
|
||||
.expand((e) => e)
|
||||
.toSet()
|
||||
.toList();
|
||||
|
||||
if (artistIds.isEmpty) return;
|
||||
|
||||
final artists = await ref.read(spotifyProvider).api.artists.list(artistIds);
|
||||
|
||||
final imagedArtistTracks = nonImageArtistTracks.map((e) {
|
||||
final track = e.track!;
|
||||
final includedArtists = track.artists!
|
||||
.map((a) => artists.firstWhereOrNull((artist) => artist.id == a.id))
|
||||
.nonNulls
|
||||
.toList();
|
||||
|
||||
track.artists = includedArtists;
|
||||
|
||||
return e.copyWith(data: track.toJson());
|
||||
});
|
||||
|
||||
assert(
|
||||
imagedArtistTracks
|
||||
.every((e) => e.track!.artists!.every((a) => a.images != null)),
|
||||
'Tracks artists should have images',
|
||||
);
|
||||
|
||||
final database = ref.read(databaseProvider);
|
||||
await database.batch((batch) {
|
||||
batch.insertAllOnConflictUpdate(
|
||||
database.historyTable,
|
||||
imagedArtistTracks,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
fetch(arg, offset, limit) async {
|
||||
final tracksQuery = createTracksQuery()..limit(limit, offset: offset);
|
||||
|
||||
final items = getTracksWithCount(await tracksQuery.get());
|
||||
final entries = await tracksQuery.get();
|
||||
|
||||
final items = getTracksWithCount(entries);
|
||||
|
||||
return (
|
||||
items: items,
|
||||
@ -123,13 +178,26 @@ class HistoryTopTracksNotifier extends FamilyPaginatedAsyncNotifier<
|
||||
}
|
||||
|
||||
List<PlaybackHistoryTrack> getTracksWithCount(List<HistoryTableData> tracks) {
|
||||
fixImageNotLoadingForArtistIssue(tracks);
|
||||
|
||||
return groupBy(
|
||||
tracks,
|
||||
(track) => track.track!.id!,
|
||||
)
|
||||
.entries
|
||||
.map((entry) {
|
||||
return (count: entry.value.length, track: entry.value.first.track!);
|
||||
return (
|
||||
count: entry.value.length,
|
||||
|
||||
/// Previously, due to a bug, artist images were not being saved.
|
||||
/// Now it's fixed, but we need to handle the case where images are null.
|
||||
/// So we take the first artist with images if available, otherwise the first one.
|
||||
track: entry.value
|
||||
.firstWhereOrNull(
|
||||
(t) => t.track!.artists!.every((a) => a.images != null))
|
||||
?.track! ??
|
||||
entry.value.first.track!,
|
||||
);
|
||||
})
|
||||
.sorted((a, b) => b.count.compareTo(a.count))
|
||||
.toList();
|
||||
|
20
pubspec.lock
20
pubspec.lock
@ -642,6 +642,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.7"
|
||||
expressions:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: expressions
|
||||
sha256: "308a621b602923dd8a0cf3072793b24850d06453eb49c6b698cbda41a282e904"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.5+2"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1919,6 +1927,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
quiver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: quiver
|
||||
sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.2"
|
||||
recase:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -2012,10 +2028,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shadcn_flutter
|
||||
sha256: "2b6faf9a93628469c29a534e653295e26781f2799efe5dc971b91e91062ebf52"
|
||||
sha256: "8635e8e0cd2e0fba0a3093a53fbe3bdd37d90d038c4c66d761728d7cfcf23ce3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.32"
|
||||
version: "0.0.34"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -102,7 +102,7 @@ dependencies:
|
||||
ref: dart-3-support
|
||||
url: https://github.com/KRTirtho/scrobblenaut.git
|
||||
scroll_to_index: ^3.0.1
|
||||
shadcn_flutter: ^0.0.32
|
||||
shadcn_flutter: ^0.0.34
|
||||
shared_preferences: ^2.2.3
|
||||
shelf: ^1.4.1
|
||||
shelf_router: ^1.1.4
|
||||
|
Loading…
Reference in New Issue
Block a user