mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
chore: re-enable endless playback
This commit is contained in:
parent
3e7b36f4e6
commit
d2e0dc1ac9
@ -29,7 +29,6 @@ import 'package:spotube/provider/audio_player/audio_player.dart';
|
|||||||
import 'package:spotube/provider/metadata_plugin/core/auth.dart';
|
import 'package:spotube/provider/metadata_plugin/core/auth.dart';
|
||||||
import 'package:spotube/provider/metadata_plugin/library/playlists.dart';
|
import 'package:spotube/provider/metadata_plugin/library/playlists.dart';
|
||||||
import 'package:spotube/provider/metadata_plugin/metadata_plugin_provider.dart';
|
import 'package:spotube/provider/metadata_plugin/metadata_plugin_provider.dart';
|
||||||
import 'package:spotube/provider/metadata_plugin/tracks/playlist.dart';
|
|
||||||
import 'package:spotube/provider/metadata_plugin/core/user.dart';
|
import 'package:spotube/provider/metadata_plugin/core/user.dart';
|
||||||
import 'package:spotube/services/metadata/endpoints/error.dart';
|
import 'package:spotube/services/metadata/endpoints/error.dart';
|
||||||
|
|
||||||
@ -107,71 +106,53 @@ class TrackOptions extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// void actionStartRadio(
|
void actionStartRadio(
|
||||||
// BuildContext context,
|
BuildContext context,
|
||||||
// WidgetRef ref,
|
WidgetRef ref,
|
||||||
// SpotubeTrackObject track,
|
SpotubeTrackObject track,
|
||||||
// ) async {
|
) async {
|
||||||
// final playback = ref.read(audioPlayerProvider.notifier);
|
final playback = ref.read(audioPlayerProvider.notifier);
|
||||||
// final playlist = ref.read(audioPlayerProvider);
|
final playlist = ref.read(audioPlayerProvider);
|
||||||
// final query = "${track.name} Radio";
|
final metadataPlugin = await ref.read(metadataPluginProvider.future);
|
||||||
// final metadataPlugin = await ref.read(metadataPluginProvider.future);
|
|
||||||
|
|
||||||
// if (metadataPlugin == null) {
|
if (metadataPlugin == null) {
|
||||||
// throw MetadataPluginException.noDefaultPlugin(
|
throw MetadataPluginException.noDefaultPlugin(
|
||||||
// "No default metadata plugin set",
|
"No default metadata plugin set",
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// final pages = await metadataPlugin.search.playlists(query);
|
final tracks = await metadataPlugin.track.radio(track.id);
|
||||||
|
|
||||||
// final artists = track.artists.map((e) => e.name);
|
bool replaceQueue = false;
|
||||||
|
|
||||||
// final radio = pages.items.firstWhere(
|
if (context.mounted && playlist.tracks.isNotEmpty) {
|
||||||
// (e) {
|
replaceQueue = await showPromptDialog(
|
||||||
// final validPlaylists = artists.where((a) => e.description.contains(a));
|
context: context,
|
||||||
// return e.name.contains(track.name) &&
|
title: context.l10n.how_to_start_radio,
|
||||||
// e.name.contains("Radio") &&
|
message: context.l10n.replace_queue_question,
|
||||||
// (validPlaylists.length >= 2 ||
|
okText: context.l10n.replace,
|
||||||
// validPlaylists.length == artists.length);
|
cancelText: context.l10n.add_to_queue,
|
||||||
// },
|
);
|
||||||
// orElse: () => pages.items.first,
|
}
|
||||||
// );
|
|
||||||
|
|
||||||
// bool replaceQueue = false;
|
if (replaceQueue || playlist.tracks.isEmpty) {
|
||||||
|
await playback.stop();
|
||||||
|
await playback.load([track], autoPlay: true);
|
||||||
|
|
||||||
// if (context.mounted && playlist.tracks.isNotEmpty) {
|
// we don't have to add those tracks as useEndlessPlayback will do it for us
|
||||||
// replaceQueue = await showPromptDialog(
|
return;
|
||||||
// context: context,
|
} else {
|
||||||
// title: context.l10n.how_to_start_radio,
|
await playback.addTrack(track);
|
||||||
// message: context.l10n.replace_queue_question,
|
}
|
||||||
// okText: context.l10n.replace,
|
|
||||||
// cancelText: context.l10n.add_to_queue,
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (replaceQueue || playlist.tracks.isEmpty) {
|
await playback.addTracks(
|
||||||
// await playback.stop();
|
tracks.toList()
|
||||||
// await playback.load([track], autoPlay: true);
|
..removeWhere((e) {
|
||||||
|
final isDuplicate = playlist.tracks.any((t) => t.id == e.id);
|
||||||
// // we don't have to add those tracks as useEndlessPlayback will do it for us
|
return e.id == track.id || isDuplicate;
|
||||||
// return;
|
}),
|
||||||
// } else {
|
);
|
||||||
// await playback.addTrack(track);
|
}
|
||||||
// }
|
|
||||||
// await ref.read(metadataPluginPlaylistTracksProvider(radio.id).future);
|
|
||||||
// final tracks = await ref
|
|
||||||
// .read(metadataPluginPlaylistTracksProvider(radio.id).notifier)
|
|
||||||
// .fetchAll();
|
|
||||||
|
|
||||||
// await playback.addTracks(
|
|
||||||
// tracks.toList()
|
|
||||||
// ..removeWhere((e) {
|
|
||||||
// final isDuplicate = playlist.tracks.any((t) => t.id == e.id);
|
|
||||||
// return e.id == track.id || isDuplicate;
|
|
||||||
// }),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
@ -338,7 +319,7 @@ class TrackOptions extends HookConsumerWidget {
|
|||||||
await downloadManager.addToQueue(track as SpotubeFullTrackObject);
|
await downloadManager.addToQueue(track as SpotubeFullTrackObject);
|
||||||
break;
|
break;
|
||||||
case TrackOptionValue.startRadio:
|
case TrackOptionValue.startRadio:
|
||||||
// actionStartRadio(context, ref, track);
|
actionStartRadio(context, ref, track);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -430,11 +411,11 @@ class TrackOptions extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (authenticated.asData?.value == true && !isLocalTrack) ...[
|
if (authenticated.asData?.value == true && !isLocalTrack) ...[
|
||||||
// AdaptiveMenuButton(
|
AdaptiveMenuButton(
|
||||||
// value: TrackOptionValue.startRadio,
|
value: TrackOptionValue.startRadio,
|
||||||
// leading: const Icon(SpotubeIcons.radio),
|
leading: const Icon(SpotubeIcons.radio),
|
||||||
// child: Text(context.l10n.start_a_radio),
|
child: Text(context.l10n.start_a_radio),
|
||||||
// ),
|
),
|
||||||
AdaptiveMenuButton(
|
AdaptiveMenuButton(
|
||||||
value: TrackOptionValue.addToPlaylist,
|
value: TrackOptionValue.addToPlaylist,
|
||||||
leading: const Icon(SpotubeIcons.playlistAdd),
|
leading: const Icon(SpotubeIcons.playlistAdd),
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import 'package:spotube/provider/metadata_plugin/tracks/playlist.dart';
|
import 'package:spotube/provider/metadata_plugin/metadata_plugin_provider.dart';
|
||||||
import 'package:spotube/services/logger/logger.dart';
|
import 'package:spotube/services/logger/logger.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
@ -6,85 +6,60 @@ import 'package:spotube/provider/audio_player/audio_player.dart';
|
|||||||
import 'package:spotube/provider/user_preferences/user_preferences_provider.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_player/audio_player.dart';
|
||||||
|
|
||||||
// TODO: Implement endless playback functionality
|
|
||||||
void useEndlessPlayback(WidgetRef ref) {
|
void useEndlessPlayback(WidgetRef ref) {
|
||||||
// final auth = ref.watch(authenticationProvider);
|
final playback = ref.watch(audioPlayerProvider.notifier);
|
||||||
// final playback = ref.watch(audioPlayerProvider.notifier);
|
final audioPlayerState = ref.watch(audioPlayerProvider);
|
||||||
// final audioPlayerState = ref.watch(audioPlayerProvider);
|
final endlessPlayback =
|
||||||
// final spotify = ref.watch(spotifyProvider);
|
ref.watch(userPreferencesProvider.select((s) => s.endlessPlayback));
|
||||||
// final endlessPlayback =
|
final metadataPlugin = ref.watch(metadataPluginProvider.future);
|
||||||
// ref.watch(userPreferencesProvider.select((s) => s.endlessPlayback));
|
|
||||||
|
|
||||||
// useEffect(
|
useEffect(
|
||||||
// () {
|
() {
|
||||||
// if (!endlessPlayback || auth.asData?.value == null) return null;
|
if (!endlessPlayback) return null;
|
||||||
|
|
||||||
// void listener(int index) async {
|
void listener(int index) async {
|
||||||
// try {
|
try {
|
||||||
// final playlist = ref.read(audioPlayerProvider);
|
final playlist = ref.read(audioPlayerProvider);
|
||||||
// if (index != playlist.tracks.length - 1) return;
|
if (index != playlist.tracks.length - 1) return;
|
||||||
|
|
||||||
// final track = playlist.tracks.last;
|
final track = playlist.tracks.last;
|
||||||
|
|
||||||
// final query = "${track.name} Radio";
|
final tracks = await (await metadataPlugin)?.track.radio(track.id);
|
||||||
// final pages = await spotify.invoke((api) =>
|
|
||||||
// api.search.get(query, types: [SearchType.playlist]).first());
|
|
||||||
|
|
||||||
// final radios = pages
|
if (tracks == null || tracks.isEmpty) return;
|
||||||
// .expand((e) => e.items?.toList() ?? <PlaylistSimple>[])
|
|
||||||
// .toList()
|
|
||||||
// .cast<PlaylistSimple>();
|
|
||||||
|
|
||||||
// final artists = track.artists.map((e) => e.name);
|
await playback.addTracks(
|
||||||
|
tracks.toList()
|
||||||
|
..removeWhere((e) {
|
||||||
|
final playlist = ref.read(audioPlayerProvider);
|
||||||
|
final isDuplicate = playlist.tracks.any((t) => t.id == e.id);
|
||||||
|
return e.id == track.id || isDuplicate;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
} catch (e, stack) {
|
||||||
|
AppLogger.reportError(e, stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// final radio = radios.firstWhere(
|
// Sometimes user can change settings for which the currentIndexChanged
|
||||||
// (e) {
|
// might not be called. So we need to check if the current track is the
|
||||||
// final validPlaylists =
|
// last track and if it is then we need to call the listener manually.
|
||||||
// artists.where((a) => e.description!.contains(a));
|
if (audioPlayerState.currentIndex == audioPlayerState.tracks.length - 1 &&
|
||||||
// return e.name == "${track.name} Radio" &&
|
audioPlayer.isPlaying) {
|
||||||
// (validPlaylists.length >= 2 ||
|
listener(audioPlayerState.currentIndex);
|
||||||
// validPlaylists.length == artists.length) &&
|
}
|
||||||
// e.owner?.displayName != "Spotify";
|
|
||||||
// },
|
|
||||||
// orElse: () => radios.first,
|
|
||||||
// );
|
|
||||||
|
|
||||||
// final tracks =
|
final subscription =
|
||||||
// ref.read(metadataPluginPlaylistTracksProvider(radio.id!));
|
audioPlayer.currentIndexChangedStream.listen(listener);
|
||||||
|
|
||||||
// await playback.addTracks(
|
return subscription.cancel;
|
||||||
// tracks.toList()
|
},
|
||||||
// ..removeWhere((e) {
|
[
|
||||||
// final playlist = ref.read(audioPlayerProvider);
|
metadataPlugin,
|
||||||
// final isDuplicate = playlist.tracks.any((t) => t.id == e.id);
|
playback,
|
||||||
// return e.id == track.id || isDuplicate;
|
audioPlayerState.tracks,
|
||||||
// }),
|
audioPlayerState.currentIndex,
|
||||||
// );
|
endlessPlayback,
|
||||||
// } catch (e, stack) {
|
],
|
||||||
// AppLogger.reportError(e, stack);
|
);
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Sometimes user can change settings for which the currentIndexChanged
|
|
||||||
// // might not be called. So we need to check if the current track is the
|
|
||||||
// // last track and if it is then we need to call the listener manually.
|
|
||||||
// if (audioPlayerState.currentIndex == audioPlayerState.tracks.length - 1 &&
|
|
||||||
// audioPlayer.isPlaying) {
|
|
||||||
// listener(audioPlayerState.currentIndex);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// final subscription =
|
|
||||||
// audioPlayer.currentIndexChangedStream.listen(listener);
|
|
||||||
|
|
||||||
// return subscription.cancel;
|
|
||||||
// },
|
|
||||||
// [
|
|
||||||
// spotify,
|
|
||||||
// playback,
|
|
||||||
// audioPlayerState.tracks,
|
|
||||||
// audioPlayerState.currentIndex,
|
|
||||||
// endlessPlayback,
|
|
||||||
// auth,
|
|
||||||
// ],
|
|
||||||
// );
|
|
||||||
}
|
}
|
||||||
|
@ -4861,6 +4861,198 @@ abstract class _PluginConfiguration extends PluginConfiguration {
|
|||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PluginUpdateAvailable _$PluginUpdateAvailableFromJson(
|
||||||
|
Map<String, dynamic> json) {
|
||||||
|
return _PluginUpdateAvailable.fromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$PluginUpdateAvailable {
|
||||||
|
String get downloadUrl => throw _privateConstructorUsedError;
|
||||||
|
String get version => throw _privateConstructorUsedError;
|
||||||
|
String? get changelog => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Serializes this PluginUpdateAvailable to a JSON map.
|
||||||
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Create a copy of PluginUpdateAvailable
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
$PluginUpdateAvailableCopyWith<PluginUpdateAvailable> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class $PluginUpdateAvailableCopyWith<$Res> {
|
||||||
|
factory $PluginUpdateAvailableCopyWith(PluginUpdateAvailable value,
|
||||||
|
$Res Function(PluginUpdateAvailable) then) =
|
||||||
|
_$PluginUpdateAvailableCopyWithImpl<$Res, PluginUpdateAvailable>;
|
||||||
|
@useResult
|
||||||
|
$Res call({String downloadUrl, String version, String? changelog});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$PluginUpdateAvailableCopyWithImpl<$Res,
|
||||||
|
$Val extends PluginUpdateAvailable>
|
||||||
|
implements $PluginUpdateAvailableCopyWith<$Res> {
|
||||||
|
_$PluginUpdateAvailableCopyWithImpl(this._value, this._then);
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Val _value;
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of PluginUpdateAvailable
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? downloadUrl = null,
|
||||||
|
Object? version = null,
|
||||||
|
Object? changelog = freezed,
|
||||||
|
}) {
|
||||||
|
return _then(_value.copyWith(
|
||||||
|
downloadUrl: null == downloadUrl
|
||||||
|
? _value.downloadUrl
|
||||||
|
: downloadUrl // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
version: null == version
|
||||||
|
? _value.version
|
||||||
|
: version // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
changelog: freezed == changelog
|
||||||
|
? _value.changelog
|
||||||
|
: changelog // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
) as $Val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$PluginUpdateAvailableImplCopyWith<$Res>
|
||||||
|
implements $PluginUpdateAvailableCopyWith<$Res> {
|
||||||
|
factory _$$PluginUpdateAvailableImplCopyWith(
|
||||||
|
_$PluginUpdateAvailableImpl value,
|
||||||
|
$Res Function(_$PluginUpdateAvailableImpl) then) =
|
||||||
|
__$$PluginUpdateAvailableImplCopyWithImpl<$Res>;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call({String downloadUrl, String version, String? changelog});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$PluginUpdateAvailableImplCopyWithImpl<$Res>
|
||||||
|
extends _$PluginUpdateAvailableCopyWithImpl<$Res,
|
||||||
|
_$PluginUpdateAvailableImpl>
|
||||||
|
implements _$$PluginUpdateAvailableImplCopyWith<$Res> {
|
||||||
|
__$$PluginUpdateAvailableImplCopyWithImpl(_$PluginUpdateAvailableImpl _value,
|
||||||
|
$Res Function(_$PluginUpdateAvailableImpl) _then)
|
||||||
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of PluginUpdateAvailable
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? downloadUrl = null,
|
||||||
|
Object? version = null,
|
||||||
|
Object? changelog = freezed,
|
||||||
|
}) {
|
||||||
|
return _then(_$PluginUpdateAvailableImpl(
|
||||||
|
downloadUrl: null == downloadUrl
|
||||||
|
? _value.downloadUrl
|
||||||
|
: downloadUrl // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
version: null == version
|
||||||
|
? _value.version
|
||||||
|
: version // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
changelog: freezed == changelog
|
||||||
|
? _value.changelog
|
||||||
|
: changelog // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _$PluginUpdateAvailableImpl implements _PluginUpdateAvailable {
|
||||||
|
_$PluginUpdateAvailableImpl(
|
||||||
|
{required this.downloadUrl, required this.version, this.changelog});
|
||||||
|
|
||||||
|
factory _$PluginUpdateAvailableImpl.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$$PluginUpdateAvailableImplFromJson(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String downloadUrl;
|
||||||
|
@override
|
||||||
|
final String version;
|
||||||
|
@override
|
||||||
|
final String? changelog;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'PluginUpdateAvailable(downloadUrl: $downloadUrl, version: $version, changelog: $changelog)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$PluginUpdateAvailableImpl &&
|
||||||
|
(identical(other.downloadUrl, downloadUrl) ||
|
||||||
|
other.downloadUrl == downloadUrl) &&
|
||||||
|
(identical(other.version, version) || other.version == version) &&
|
||||||
|
(identical(other.changelog, changelog) ||
|
||||||
|
other.changelog == changelog));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType, downloadUrl, version, changelog);
|
||||||
|
|
||||||
|
/// Create a copy of PluginUpdateAvailable
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$$PluginUpdateAvailableImplCopyWith<_$PluginUpdateAvailableImpl>
|
||||||
|
get copyWith => __$$PluginUpdateAvailableImplCopyWithImpl<
|
||||||
|
_$PluginUpdateAvailableImpl>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$$PluginUpdateAvailableImplToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _PluginUpdateAvailable implements PluginUpdateAvailable {
|
||||||
|
factory _PluginUpdateAvailable(
|
||||||
|
{required final String downloadUrl,
|
||||||
|
required final String version,
|
||||||
|
final String? changelog}) = _$PluginUpdateAvailableImpl;
|
||||||
|
|
||||||
|
factory _PluginUpdateAvailable.fromJson(Map<String, dynamic> json) =
|
||||||
|
_$PluginUpdateAvailableImpl.fromJson;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get downloadUrl;
|
||||||
|
@override
|
||||||
|
String get version;
|
||||||
|
@override
|
||||||
|
String? get changelog;
|
||||||
|
|
||||||
|
/// Create a copy of PluginUpdateAvailable
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
_$$PluginUpdateAvailableImplCopyWith<_$PluginUpdateAvailableImpl>
|
||||||
|
get copyWith => throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
MetadataPluginRepository _$MetadataPluginRepositoryFromJson(
|
MetadataPluginRepository _$MetadataPluginRepositoryFromJson(
|
||||||
Map<String, dynamic> json) {
|
Map<String, dynamic> json) {
|
||||||
return _MetadataPluginRepository.fromJson(json);
|
return _MetadataPluginRepository.fromJson(json);
|
||||||
|
@ -467,6 +467,21 @@ const _$PluginAbilitiesEnumMap = {
|
|||||||
PluginAbilities.authentication: 'authentication',
|
PluginAbilities.authentication: 'authentication',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_$PluginUpdateAvailableImpl _$$PluginUpdateAvailableImplFromJson(Map json) =>
|
||||||
|
_$PluginUpdateAvailableImpl(
|
||||||
|
downloadUrl: json['downloadUrl'] as String,
|
||||||
|
version: json['version'] as String,
|
||||||
|
changelog: json['changelog'] as String?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$PluginUpdateAvailableImplToJson(
|
||||||
|
_$PluginUpdateAvailableImpl instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'downloadUrl': instance.downloadUrl,
|
||||||
|
'version': instance.version,
|
||||||
|
'changelog': instance.changelog,
|
||||||
|
};
|
||||||
|
|
||||||
_$MetadataPluginRepositoryImpl _$$MetadataPluginRepositoryImplFromJson(
|
_$MetadataPluginRepositoryImpl _$$MetadataPluginRepositoryImplFromJson(
|
||||||
Map json) =>
|
Map json) =>
|
||||||
_$MetadataPluginRepositoryImpl(
|
_$MetadataPluginRepositoryImpl(
|
||||||
|
@ -28,3 +28,15 @@ class PluginConfiguration with _$PluginConfiguration {
|
|||||||
|
|
||||||
String get slug => name.toLowerCase().replaceAll(RegExp(r'[^a-z0-9]+'), '-');
|
String get slug => name.toLowerCase().replaceAll(RegExp(r'[^a-z0-9]+'), '-');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class PluginUpdateAvailable with _$PluginUpdateAvailable {
|
||||||
|
factory PluginUpdateAvailable({
|
||||||
|
required String downloadUrl,
|
||||||
|
required String version,
|
||||||
|
String? changelog,
|
||||||
|
}) = _PluginUpdateAvailable;
|
||||||
|
|
||||||
|
factory PluginUpdateAvailable.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$PluginUpdateAvailableFromJson(json);
|
||||||
|
}
|
||||||
|
@ -76,4 +76,26 @@ class MetadataPluginArtistEndpoint {
|
|||||||
positionalArgs: [ids],
|
positionalArgs: [ids],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<SpotubePaginationResponseObject<SpotubeFullArtistObject>> related(
|
||||||
|
String id, {
|
||||||
|
int? offset,
|
||||||
|
int? limit,
|
||||||
|
}) async {
|
||||||
|
final raw = await hetuMetadataArtist.invoke(
|
||||||
|
"related",
|
||||||
|
positionalArgs: [id],
|
||||||
|
namedArgs: {
|
||||||
|
"offset": offset,
|
||||||
|
"limit": limit ?? 20,
|
||||||
|
}..removeWhere((key, value) => value == null),
|
||||||
|
) as Map;
|
||||||
|
|
||||||
|
return SpotubePaginationResponseObject<SpotubeFullArtistObject>.fromJson(
|
||||||
|
raw.cast<String, dynamic>(),
|
||||||
|
(Map json) => SpotubeFullArtistObject.fromJson(
|
||||||
|
json.cast<String, dynamic>(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,4 +26,19 @@ class MetadataPluginTrackEndpoint {
|
|||||||
Future<void> unsave(List<String> ids) async {
|
Future<void> unsave(List<String> ids) async {
|
||||||
await hetuMetadataTrack.invoke("unsave", positionalArgs: [ids]);
|
await hetuMetadataTrack.invoke("unsave", positionalArgs: [ids]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<SpotubeFullTrackObject>> radio(String id) async {
|
||||||
|
final result = await hetuMetadataTrack.invoke(
|
||||||
|
"radio",
|
||||||
|
positionalArgs: [id],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (result as List)
|
||||||
|
.map(
|
||||||
|
(e) => SpotubeFullTrackObject.fromJson(
|
||||||
|
(e as Map).cast<String, dynamic>(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
26
lib/services/metadata/endpoints/updater.dart
Normal file
26
lib/services/metadata/endpoints/updater.dart
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import 'package:hetu_script/hetu_script.dart';
|
||||||
|
import 'package:hetu_script/values.dart';
|
||||||
|
import 'package:spotube/models/metadata/metadata.dart';
|
||||||
|
|
||||||
|
class MetadataPluginUpdaterEndpoint {
|
||||||
|
final Hetu hetu;
|
||||||
|
|
||||||
|
MetadataPluginUpdaterEndpoint(this.hetu);
|
||||||
|
|
||||||
|
HTInstance get hetuMetadataPluginUpdater =>
|
||||||
|
(hetu.fetch("metadataPlugin") as HTInstance).memberGet("updater")
|
||||||
|
as HTInstance;
|
||||||
|
|
||||||
|
Future<PluginUpdateAvailable?> check(PluginConfiguration pluginConfig) async {
|
||||||
|
final result = await hetuMetadataPluginUpdater.invoke(
|
||||||
|
"check",
|
||||||
|
positionalArgs: [pluginConfig.toJson()],
|
||||||
|
);
|
||||||
|
|
||||||
|
return result == null
|
||||||
|
? null
|
||||||
|
: PluginUpdateAvailable.fromJson(
|
||||||
|
(result as Map).cast<String, dynamic>(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user