mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00

* refactor: remove SourcedTrack based audio player and utilize mediakit playback system * feat: implement local (loopback) server to resolve stream source and leverage the media_kit playback API * feat: add source change support and re-add prefetching tracks * fix: assign lastId when track fetch completes regardless of error * chore: remove print statements * fix: remote queue not working * fix: increase mpv network timeout to reduce auto-skipping * fix: do not pre-fetch local tracks * fix(proxy-playlist): reset collections on load * chore: fix lint warnings * fix(mobile): player overlay should not be visible when the player is not playing * chore: fix typo in turkish translation * cd: checkout PR branch * cd: upgrade flutter version * chore: fix lint errors
94 lines
2.7 KiB
Dart
94 lines
2.7 KiB
Dart
import 'package:collection/collection.dart';
|
|
import 'package:spotify/spotify.dart';
|
|
import 'package:spotube/extensions/track.dart';
|
|
import 'package:spotube/models/local_track.dart';
|
|
import 'package:spotube/services/sourced_track/sourced_track.dart';
|
|
|
|
class ProxyPlaylist {
|
|
final Set<Track> tracks;
|
|
final Set<String> collections;
|
|
final int? active;
|
|
|
|
ProxyPlaylist(this.tracks, [this.active, this.collections = const {}]);
|
|
|
|
factory ProxyPlaylist.fromJson(
|
|
Map<String, dynamic> json,
|
|
) {
|
|
return ProxyPlaylist(
|
|
List.castFrom<dynamic, Map<String, dynamic>>(
|
|
json['tracks'] ?? <Map<String, dynamic>>[],
|
|
).map((t) => _makeAppropriateTrack(t)).toSet(),
|
|
json['active'] as int?,
|
|
json['collections'] == null
|
|
? {}
|
|
: (json['collections'] as List).toSet().cast<String>(),
|
|
);
|
|
}
|
|
|
|
factory ProxyPlaylist.fromJsonRaw(Map<String, dynamic> json) => ProxyPlaylist(
|
|
json['tracks'] == null
|
|
? <Track>{}
|
|
: (json['tracks'] as List).map((t) => Track.fromJson(t)).toSet(),
|
|
json['active'] as int?,
|
|
json['collections'] == null
|
|
? {}
|
|
: (json['collections'] as List).toSet().cast<String>(),
|
|
);
|
|
|
|
Track? get activeTrack =>
|
|
active == null || active == -1 ? null : tracks.elementAtOrNull(active!);
|
|
|
|
bool get isFetching => activeTrack == null && tracks.isNotEmpty;
|
|
|
|
bool containsCollection(String collection) {
|
|
return collections.contains(collection);
|
|
}
|
|
|
|
bool containsTrack(TrackSimple track) {
|
|
return tracks.firstWhereOrNull((element) => element.id == track.id) != null;
|
|
}
|
|
|
|
bool containsTracks(Iterable<TrackSimple> tracks) {
|
|
if (tracks.isEmpty) return false;
|
|
return tracks.every(containsTrack);
|
|
}
|
|
|
|
static Track _makeAppropriateTrack(Map<String, dynamic> track) {
|
|
if (track.containsKey("path")) {
|
|
return LocalTrack.fromJson(track);
|
|
} else {
|
|
return Track.fromJson(track);
|
|
}
|
|
}
|
|
|
|
/// To make sure proper instance method is used for JSON serialization
|
|
/// Otherwise default super.toJson() is used
|
|
static Map<String, dynamic> _makeAppropriateTrackJson(Track track) {
|
|
return switch (track.runtimeType) {
|
|
LocalTrack() => track.toJson(),
|
|
SourcedTrack() => track.toJson(),
|
|
_ => track.toJson(),
|
|
};
|
|
}
|
|
|
|
Map<String, dynamic> toJson() {
|
|
return {
|
|
'tracks': tracks.map(_makeAppropriateTrackJson).toList(),
|
|
'active': active,
|
|
'collections': collections.toList(),
|
|
};
|
|
}
|
|
|
|
ProxyPlaylist copyWith({
|
|
Set<Track>? tracks,
|
|
int? active,
|
|
Set<String>? collections,
|
|
}) {
|
|
return ProxyPlaylist(
|
|
tracks ?? this.tracks,
|
|
active ?? this.active,
|
|
collections ?? this.collections,
|
|
);
|
|
}
|
|
}
|