From 3209c75144dbb7b6d3fbc2a3c1aff63feb3494c9 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 8 Nov 2025 15:49:37 +0600 Subject: [PATCH] fix: downloaded tracks are not tagged with metadata --- README.md | 1 - assets/images/logos/songlink-transparent.png | Bin 8758 -> 0 bytes lib/collections/assets.gen.dart | 41 ++- lib/components/track_tile/track_options.dart | 20 -- lib/models/database/database.g.dart | 5 +- lib/models/metadata/audio_source.dart | 10 + lib/models/metadata/metadata.freezed.dart | 16 +- lib/pages/library/user_downloads.dart | 4 +- .../user_local_tracks/local_folder.dart | 57 +-- lib/provider/download_manager_provider.dart | 57 +-- lib/provider/server/routes/playback.dart | 5 +- .../track_options/track_options_provider.dart | 10 +- lib/services/audio_player/audio_player.dart | 2 +- lib/services/song_link/model.dart | 19 - lib/services/song_link/song_link.dart | 54 --- lib/services/song_link/song_link.freezed.dart | 333 ------------------ lib/services/song_link/song_link.g.dart | 32 -- 17 files changed, 112 insertions(+), 554 deletions(-) delete mode 100644 assets/images/logos/songlink-transparent.png delete mode 100644 lib/services/song_link/model.dart delete mode 100644 lib/services/song_link/song_link.dart delete mode 100644 lib/services/song_link/song_link.freezed.dart delete mode 100644 lib/services/song_link/song_link.g.dart diff --git a/README.md b/README.md index 4c5c1f1c..153832ea 100644 --- a/README.md +++ b/README.md @@ -202,7 +202,6 @@ If you are curious, you can [read the reason of choosing this license](https://d 1. [Invidious](https://invidious.io/) - Invidious is an open source alternative front-end to YouTube. 1. [yt-dlp](https://github.com/yt-dlp/yt-dlp) - A feature-rich command-line audio/video downloader. 1. [NewPipeExtractor](https://github.com/TeamNewPipe/NewPipeExtractor) - NewPipe's core library for extracting data from streaming sites. -1. [SongLink](https://song.link) - SongLink is a free smart link service that helps you share music with your audience. It's a one-stop-shop for creating smart links for music, podcasts, and other audio content 1. [LRCLib](https://lrclib.net/) - A public synced lyric API. 1. [Linux](https://www.linux.org) - Linux is a family of open-source Unix-like operating systems based on the Linux kernel, an operating system kernel first released on September 17, 1991, by Linus Torvalds. Linux is typically packaged in a Linux distribution 1. [AUR](https://aur.archlinux.org) - AUR stands for Arch User Repository. It is a community-driven repository for Arch-based Linux distributions users diff --git a/assets/images/logos/songlink-transparent.png b/assets/images/logos/songlink-transparent.png deleted file mode 100644 index fc4ae54146e35ee36d490dba7541dda3b51f6c49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8758 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 diff --git a/lib/collections/assets.gen.dart b/lib/collections/assets.gen.dart index 7fa75e1d..7ab0ad03 100644 --- a/lib/collections/assets.gen.dart +++ b/lib/collections/assets.gen.dart @@ -66,6 +66,19 @@ class $AssetsImagesGen { ]; } +class $AssetsPluginsGen { + const $AssetsPluginsGen(); + + /// Directory path: assets/plugins/spotube-plugin-musicbrainz-listenbrainz + $AssetsPluginsSpotubePluginMusicbrainzListenbrainzGen + get spotubePluginMusicbrainzListenbrainz => + const $AssetsPluginsSpotubePluginMusicbrainzListenbrainzGen(); + + /// Directory path: assets/plugins/spotube-plugin-youtube-audio + $AssetsPluginsSpotubePluginYoutubeAudioGen get spotubePluginYoutubeAudio => + const $AssetsPluginsSpotubePluginYoutubeAudioGen(); +} + class $AssetsImagesLogosGen { const $AssetsImagesLogosGen(); @@ -81,13 +94,30 @@ class $AssetsImagesLogosGen { AssetGenImage get jiosaavn => const AssetGenImage('assets/images/logos/jiosaavn.png'); - /// File path: assets/images/logos/songlink-transparent.png - AssetGenImage get songlinkTransparent => - const AssetGenImage('assets/images/logos/songlink-transparent.png'); + /// List of all assets + List get values => [dabMusic, invidious, jiosaavn]; +} + +class $AssetsPluginsSpotubePluginMusicbrainzListenbrainzGen { + const $AssetsPluginsSpotubePluginMusicbrainzListenbrainzGen(); + + /// File path: assets/plugins/spotube-plugin-musicbrainz-listenbrainz/plugin.smplug + String get plugin => + 'assets/plugins/spotube-plugin-musicbrainz-listenbrainz/plugin.smplug'; /// List of all assets - List get values => - [dabMusic, invidious, jiosaavn, songlinkTransparent]; + List get values => [plugin]; +} + +class $AssetsPluginsSpotubePluginYoutubeAudioGen { + const $AssetsPluginsSpotubePluginYoutubeAudioGen(); + + /// File path: assets/plugins/spotube-plugin-youtube-audio/plugin.smplug + String get plugin => + 'assets/plugins/spotube-plugin-youtube-audio/plugin.smplug'; + + /// List of all assets + List get values => [plugin]; } class Assets { @@ -96,6 +126,7 @@ class Assets { static const String license = 'LICENSE'; static const $AssetsBrandingGen branding = $AssetsBrandingGen(); static const $AssetsImagesGen images = $AssetsImagesGen(); + static const $AssetsPluginsGen plugins = $AssetsPluginsGen(); /// List of all assets static List get values => [license]; diff --git a/lib/components/track_tile/track_options.dart b/lib/components/track_tile/track_options.dart index 6124abf0..61b47968 100644 --- a/lib/components/track_tile/track_options.dart +++ b/lib/components/track_tile/track_options.dart @@ -4,7 +4,6 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; -import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/routes.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/ui/button_tile.dart'; @@ -36,7 +35,6 @@ class TrackOptions extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { final mediaQuery = MediaQuery.of(context); - final ThemeData(:colorScheme) = Theme.of(context); final trackOptionActions = ref.watch(trackOptionActionsProvider(track)); final ( @@ -260,24 +258,6 @@ class TrackOptions extends HookConsumerWidget { leading: const Icon(SpotubeIcons.share), title: Text(context.l10n.share), ), - if (!isLocalTrack) - ButtonTile( - style: ButtonVariance.menu, - onPressed: () async { - await trackOptionActions.action( - rootNavigatorKey.currentContext!, - TrackOptionValue.songlink, - playlistId, - ); - onTapItem?.call(); - }, - leading: Assets.images.logos.songlinkTransparent.image( - width: 22, - height: 22, - color: colorScheme.foreground.withValues(alpha: 0.5), - ), - title: Text(context.l10n.song_link), - ), if (!isLocalTrack) ButtonTile( style: ButtonVariance.menu, diff --git a/lib/models/database/database.g.dart b/lib/models/database/database.g.dart index 4a9a7eba..8aa14899 100644 --- a/lib/models/database/database.g.dart +++ b/lib/models/database/database.g.dart @@ -4143,8 +4143,6 @@ abstract class _$AppDatabase extends GeneratedDatabase { late final $PluginsTableTable pluginsTable = $PluginsTableTable(this); late final Index uniqueBlacklist = Index('unique_blacklist', 'CREATE UNIQUE INDEX unique_blacklist ON blacklist_table (element_type, element_id)'); - late final Index uniqTrackMatch = Index('uniq_track_match', - 'CREATE UNIQUE INDEX uniq_track_match ON source_match_table (track_id, source_info, source_type)'); @override Iterable> get allTables => allSchemaEntities.whereType>(); @@ -4160,8 +4158,7 @@ abstract class _$AppDatabase extends GeneratedDatabase { historyTable, lyricsTable, pluginsTable, - uniqueBlacklist, - uniqTrackMatch + uniqueBlacklist ]; } diff --git a/lib/models/metadata/audio_source.dart b/lib/models/metadata/audio_source.dart index 898300e9..4fb790ea 100644 --- a/lib/models/metadata/audio_source.dart +++ b/lib/models/metadata/audio_source.dart @@ -10,6 +10,8 @@ enum SpotubeMediaCompressionType { @Freezed(unionKey: 'type') class SpotubeAudioSourceContainerPreset with _$SpotubeAudioSourceContainerPreset { + const SpotubeAudioSourceContainerPreset._(); + @FreezedUnionValue("lossy") factory SpotubeAudioSourceContainerPreset.lossy({ required SpotubeMediaCompressionType type, @@ -27,6 +29,14 @@ class SpotubeAudioSourceContainerPreset factory SpotubeAudioSourceContainerPreset.fromJson( Map json) => _$SpotubeAudioSourceContainerPresetFromJson(json); + + String getFileExtension() { + return switch (name) { + "mp4" => "m4a", + "webm" => "weba", + _ => name, + }; + } } @freezed diff --git a/lib/models/metadata/metadata.freezed.dart b/lib/models/metadata/metadata.freezed.dart index 301929a5..fee1cbc2 100644 --- a/lib/models/metadata/metadata.freezed.dart +++ b/lib/models/metadata/metadata.freezed.dart @@ -197,12 +197,13 @@ class __$$SpotubeAudioSourceContainerPresetLossyImplCopyWithImpl<$Res> /// @nodoc @JsonSerializable() class _$SpotubeAudioSourceContainerPresetLossyImpl - implements SpotubeAudioSourceContainerPresetLossy { + extends SpotubeAudioSourceContainerPresetLossy { _$SpotubeAudioSourceContainerPresetLossyImpl( {required this.type, required this.name, required final List qualities}) - : _qualities = qualities; + : _qualities = qualities, + super._(); factory _$SpotubeAudioSourceContainerPresetLossyImpl.fromJson( Map json) => @@ -338,12 +339,13 @@ class _$SpotubeAudioSourceContainerPresetLossyImpl } abstract class SpotubeAudioSourceContainerPresetLossy - implements SpotubeAudioSourceContainerPreset { + extends SpotubeAudioSourceContainerPreset { factory SpotubeAudioSourceContainerPresetLossy( {required final SpotubeMediaCompressionType type, required final String name, required final List qualities}) = _$SpotubeAudioSourceContainerPresetLossyImpl; + SpotubeAudioSourceContainerPresetLossy._() : super._(); factory SpotubeAudioSourceContainerPresetLossy.fromJson( Map json) = @@ -419,12 +421,13 @@ class __$$SpotubeAudioSourceContainerPresetLosslessImplCopyWithImpl<$Res> /// @nodoc @JsonSerializable() class _$SpotubeAudioSourceContainerPresetLosslessImpl - implements SpotubeAudioSourceContainerPresetLossless { + extends SpotubeAudioSourceContainerPresetLossless { _$SpotubeAudioSourceContainerPresetLosslessImpl( {required this.type, required this.name, required final List qualities}) - : _qualities = qualities; + : _qualities = qualities, + super._(); factory _$SpotubeAudioSourceContainerPresetLosslessImpl.fromJson( Map json) => @@ -561,12 +564,13 @@ class _$SpotubeAudioSourceContainerPresetLosslessImpl } abstract class SpotubeAudioSourceContainerPresetLossless - implements SpotubeAudioSourceContainerPreset { + extends SpotubeAudioSourceContainerPreset { factory SpotubeAudioSourceContainerPresetLossless( {required final SpotubeMediaCompressionType type, required final String name, required final List qualities}) = _$SpotubeAudioSourceContainerPresetLosslessImpl; + SpotubeAudioSourceContainerPresetLossless._() : super._(); factory SpotubeAudioSourceContainerPresetLossless.fromJson( Map json) = diff --git a/lib/pages/library/user_downloads.dart b/lib/pages/library/user_downloads.dart index 6566bed6..73dc692f 100644 --- a/lib/pages/library/user_downloads.dart +++ b/lib/pages/library/user_downloads.dart @@ -16,7 +16,7 @@ class UserDownloadsPage extends HookConsumerWidget { Widget build(BuildContext context, ref) { final downloadManager = ref.watch(downloadManagerProvider); - final history = downloadManager.$backHistory; + final history = downloadManager.$history; return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -48,7 +48,7 @@ class UserDownloadsPage extends HookConsumerWidget { child: ListView.builder( itemCount: history.length, itemBuilder: (context, index) { - return DownloadItem(track: history.elementAt(index)); + return DownloadItem(track: history.elementAt(index).query); }, ), ), diff --git a/lib/pages/library/user_local_tracks/local_folder.dart b/lib/pages/library/user_local_tracks/local_folder.dart index 27af0f57..58a7a023 100644 --- a/lib/pages/library/user_local_tracks/local_folder.dart +++ b/lib/pages/library/user_local_tracks/local_folder.dart @@ -346,36 +346,41 @@ class LocalLibraryPage extends HookConsumerWidget { controller: controller, child: Skeletonizer( enabled: trackSnapshot.isLoading, - child: ListView.builder( + child: CustomScrollView( controller: controller, physics: const AlwaysScrollableScrollPhysics(), - itemCount: trackSnapshot.isLoading - ? 5 - : filteredTracks.length, - itemBuilder: (context, index) { - if (trackSnapshot.isLoading) { - return TrackTile( - playlist: playlist, - track: FakeData.track, - index: index, - ); - } + slivers: [ + SliverList.builder( + itemCount: trackSnapshot.isLoading + ? 5 + : filteredTracks.length, + itemBuilder: (context, index) { + if (trackSnapshot.isLoading) { + return TrackTile( + playlist: playlist, + track: FakeData.track, + index: index, + ); + } - final track = filteredTracks[index]; - return TrackTile( - index: index, - playlist: playlist, - track: track, - userPlaylist: false, - onTap: () async { - await playLocalTracks( - ref, - sortedTracks, - currentTrack: track, + final track = filteredTracks[index]; + return TrackTile( + index: index, + playlist: playlist, + track: track, + userPlaylist: false, + onTap: () async { + await playLocalTracks( + ref, + sortedTracks, + currentTrack: track, + ); + }, ); }, - ); - }, + ), + const SliverGap(200), + ], ), ), ), @@ -398,7 +403,7 @@ class LocalLibraryPage extends HookConsumerWidget { error: (error, stackTrace) => Text(error.toString() + stackTrace.toString()), ); - }) + }), ], ), ), diff --git a/lib/provider/download_manager_provider.dart b/lib/provider/download_manager_provider.dart index bc1de813..d64da32e 100644 --- a/lib/provider/download_manager_provider.dart +++ b/lib/provider/download_manager_provider.dart @@ -19,7 +19,6 @@ import 'package:spotube/utils/service_utils.dart'; class DownloadManagerProvider extends ChangeNotifier { DownloadManagerProvider({required this.ref}) : $history = {}, - $backHistory = {}, dl = DownloadManager() { dl.statusStream.listen((event) async { try { @@ -28,14 +27,13 @@ class DownloadManagerProvider extends ChangeNotifier { final sourcedTrack = $history.firstWhereOrNull( (element) => element.getUrlOfQuality( - downloadContainer, downloadQualityIndex) == + downloadContainer, + downloadQualityIndex, + ) == request.url, ); + if (sourcedTrack == null) return; - final track = $backHistory.firstWhereOrNull( - (element) => element.id == sourcedTrack.query.id, - ); - if (track == null) return; final savePath = getTrackFileUrl(sourcedTrack); // related to onFileExists @@ -47,12 +45,12 @@ class DownloadManagerProvider extends ChangeNotifier { await oldFile.exists()) { await oldFile.rename(savePath); } + if (status != DownloadStatus.completed || //? WebA audiotagging is not supported yet //? Although in future by converting weba to opus & then tagging it //? is possible using vorbis comments - downloadContainer.name == "weba" || - downloadContainer.name == "webm") { + downloadContainer.getFileExtension() == "weba") { return; } @@ -63,13 +61,13 @@ class DownloadManagerProvider extends ChangeNotifier { } final imageBytes = await ServiceUtils.downloadImage( - (track.album.images).asUrlString( + (sourcedTrack.query.album.images).asUrlString( placeholder: ImagePlaceholder.albumArt, index: 1, ), ); - final metadata = track.toMetadata( + final metadata = sourcedTrack.query.toMetadata( fileLength: await file.length(), imageBytes: imageBytes, ); @@ -111,17 +109,16 @@ class DownloadManagerProvider extends ChangeNotifier { final Set $history; // these are the tracks which metadata hasn't been fetched yet - final Set $backHistory; final DownloadManager dl; String getTrackFileUrl(SourcedTrack track) { final name = - "${track.query.name} - ${track.query.artists.join(", ")}.${downloadContainer.name}"; + "${track.query.name} - ${track.query.artists.map((e) => e.name).join(", ")}.${downloadContainer.getFileExtension()}"; return join(downloadDirectory, PrimitiveUtils.toSafeFileName(name)); } bool isActive(SpotubeFullTrackObject track) { - if ($backHistory.contains(track)) return true; + if ($history.any((e) => e.query.id == track.id)) return true; final sourcedTrack = $history.firstWhereOrNull( (element) => element.query.id == track.id, @@ -146,9 +143,7 @@ class DownloadManagerProvider extends ChangeNotifier { /// For singular downloads Future addToQueue(SpotubeFullTrackObject track) async { - final sourcedTrack = await ref.read( - sourcedTrackProvider(track).future, - ); + final sourcedTrack = await ref.read(sourcedTrackProvider(track).future); final savePath = getTrackFileUrl(sourcedTrack); @@ -161,35 +156,17 @@ class DownloadManagerProvider extends ChangeNotifier { await oldFile.rename("$savePath.old"); } - if (sourcedTrack.qualityPreset == downloadContainer) { - final downloadTask = await dl.addDownload( - sourcedTrack.getUrlOfQuality(downloadContainer, downloadQualityIndex)!, - savePath, - ); - if (downloadTask != null) { - $history.add(sourcedTrack); - } - } else { - $backHistory.add(track); - final sourcedTrack = - await ref.read(sourcedTrackProvider(track).future).then((d) { - $backHistory.remove(track); - return d; - }); - final downloadTask = await dl.addDownload( - sourcedTrack.getUrlOfQuality(downloadContainer, downloadQualityIndex)!, - savePath, - ); - if (downloadTask != null) { - $history.add(sourcedTrack); - } + final downloadTask = await dl.addDownload( + sourcedTrack.getUrlOfQuality(downloadContainer, downloadQualityIndex)!, + savePath, + ); + if (downloadTask != null) { + $history.add(sourcedTrack); } - notifyListeners(); } Future batchAddToQueue(List tracks) async { - $backHistory.addAll(tracks); notifyListeners(); for (final track in tracks) { try { diff --git a/lib/provider/server/routes/playback.dart b/lib/provider/server/routes/playback.dart index 792d7797..f7085505 100644 --- a/lib/provider/server/routes/playback.dart +++ b/lib/provider/server/routes/playback.dart @@ -48,7 +48,7 @@ class ServerPlaybackRoutes { return join( await UserPreferencesNotifier.getMusicCacheDir(), ServiceUtils.sanitizeFilename( - '${track.query.name} - ${track.query.artists.map((d) => d.name).join(",")} (${track.info.id}).${track.qualityPreset!.name}', + '${track.query.name} - ${track.query.artists.map((d) => d.name).join(",")} (${track.info.id}).${track.qualityPreset!.getFileExtension()}', ), ); } @@ -263,8 +263,7 @@ class ServerPlaybackRoutes { } if (contentRange.total == fileLength && - track.qualityPreset!.name != "webm" || - track.qualityPreset!.name != "weba") { + track.qualityPreset!.getFileExtension() != "weba") { final playlistTrack = playlist.tracks.firstWhereOrNull( (element) => element.id == track.query.id, ); diff --git a/lib/provider/track_options/track_options_provider.dart b/lib/provider/track_options/track_options_provider.dart index 42f363d9..e6b05201 100644 --- a/lib/provider/track_options/track_options_provider.dart +++ b/lib/provider/track_options/track_options_provider.dart @@ -21,12 +21,10 @@ import 'package:spotube/provider/metadata_plugin/library/playlists.dart'; import 'package:spotube/provider/metadata_plugin/library/tracks.dart'; import 'package:spotube/provider/metadata_plugin/metadata_plugin_provider.dart'; import 'package:spotube/services/metadata/errors/exceptions.dart'; -import 'package:url_launcher/url_launcher_string.dart'; enum TrackOptionValue { album, share, - songlink, addToPlaylist, addToQueue, removeFromPlaylist, @@ -237,10 +235,6 @@ class TrackOptionsActions { case TrackOptionValue.share: actionShare(context); break; - case TrackOptionValue.songlink: - final url = "https://song.link/s/${track.id}"; - await launchUrlString(url); - break; case TrackOptionValue.details: if (track is! SpotubeFullTrackObject) break; showDialog( @@ -252,8 +246,8 @@ class TrackOptionsActions { ); break; case TrackOptionValue.download: - if (track is! SpotubeFullTrackObject) break; - await downloadManager.addToQueue(track as SpotubeFullTrackObject); + if (track is SpotubeLocalTrackObject) break; + downloadManager.addToQueue(track as SpotubeFullTrackObject); break; case TrackOptionValue.startRadio: actionStartRadio(context); diff --git a/lib/services/audio_player/audio_player.dart b/lib/services/audio_player/audio_player.dart index a30fafba..9ae4e973 100644 --- a/lib/services/audio_player/audio_player.dart +++ b/lib/services/audio_player/audio_player.dart @@ -37,7 +37,7 @@ class SpotubeMedia extends mk.Media { factory SpotubeMedia.media(Media media) { assert(media.extras != null, "[Media] must have extra metadata set"); - return SpotubeMedia(SpotubeFullTrackObject.fromJson(media.extras!)); + return SpotubeMedia(SpotubeTrackObject.fromJson(media.extras!)); } } diff --git a/lib/services/song_link/model.dart b/lib/services/song_link/model.dart deleted file mode 100644 index ae9d3833..00000000 --- a/lib/services/song_link/model.dart +++ /dev/null @@ -1,19 +0,0 @@ -part of './song_link.dart'; - -@freezed -class SongLink with _$SongLink { - const factory SongLink({ - required String displayName, - required String linkId, - required String platform, - required bool show, - required String? uniqueId, - required String? country, - required String? url, - required String? nativeAppUriMobile, - required String? nativeAppUriDesktop, - }) = _SongLink; - - factory SongLink.fromJson(Map json) => - _$SongLinkFromJson(json); -} diff --git a/lib/services/song_link/song_link.dart b/lib/services/song_link/song_link.dart deleted file mode 100644 index e3cffa52..00000000 --- a/lib/services/song_link/song_link.dart +++ /dev/null @@ -1,54 +0,0 @@ -library song_link; - -import 'dart:convert'; - -import 'package:spotube/services/logger/logger.dart'; -import 'package:dio/dio.dart'; -import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:html/parser.dart'; - -part 'model.dart'; - -part 'song_link.freezed.dart'; -part 'song_link.g.dart'; - -abstract class SongLinkService { - static final dio = Dio(); - static Future> links(String spotifyId) async { - try { - final res = await dio.get( - "https://song.link/s/$spotifyId", - options: Options( - headers: { - "Accept": - "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", - "User-Agent": - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36" - }, - responseType: ResponseType.plain, - ), - ); - - final document = parse(res.data); - - final script = document.getElementById("__NEXT_DATA__")?.text; - - if (script == null) { - return []; - } - - final pageProps = jsonDecode(script) as Map; - final songLinks = pageProps["props"]?["pageProps"]?["pageData"] - ?["sections"] - ?.firstWhere( - (section) => section?["sectionId"] == "section|auto|links|listen", - )?["links"] as List?; - - return songLinks?.map((link) => SongLink.fromJson(link)).toList() ?? - []; - } catch (e, stackTrace) { - AppLogger.reportError(e, stackTrace); - return []; - } - } -} diff --git a/lib/services/song_link/song_link.freezed.dart b/lib/services/song_link/song_link.freezed.dart deleted file mode 100644 index c704cde3..00000000 --- a/lib/services/song_link/song_link.freezed.dart +++ /dev/null @@ -1,333 +0,0 @@ -// coverage:ignore-file -// GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark - -part of 'song_link.dart'; - -// ************************************************************************** -// FreezedGenerator -// ************************************************************************** - -T _$identity(T value) => value; - -final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); - -SongLink _$SongLinkFromJson(Map json) { - return _SongLink.fromJson(json); -} - -/// @nodoc -mixin _$SongLink { - String get displayName => throw _privateConstructorUsedError; - String get linkId => throw _privateConstructorUsedError; - String get platform => throw _privateConstructorUsedError; - bool get show => throw _privateConstructorUsedError; - String? get uniqueId => throw _privateConstructorUsedError; - String? get country => throw _privateConstructorUsedError; - String? get url => throw _privateConstructorUsedError; - String? get nativeAppUriMobile => throw _privateConstructorUsedError; - String? get nativeAppUriDesktop => throw _privateConstructorUsedError; - - /// Serializes this SongLink to a JSON map. - Map toJson() => throw _privateConstructorUsedError; - - /// Create a copy of SongLink - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - $SongLinkCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $SongLinkCopyWith<$Res> { - factory $SongLinkCopyWith(SongLink value, $Res Function(SongLink) then) = - _$SongLinkCopyWithImpl<$Res, SongLink>; - @useResult - $Res call( - {String displayName, - String linkId, - String platform, - bool show, - String? uniqueId, - String? country, - String? url, - String? nativeAppUriMobile, - String? nativeAppUriDesktop}); -} - -/// @nodoc -class _$SongLinkCopyWithImpl<$Res, $Val extends SongLink> - implements $SongLinkCopyWith<$Res> { - _$SongLinkCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - /// Create a copy of SongLink - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? displayName = null, - Object? linkId = null, - Object? platform = null, - Object? show = null, - Object? uniqueId = freezed, - Object? country = freezed, - Object? url = freezed, - Object? nativeAppUriMobile = freezed, - Object? nativeAppUriDesktop = freezed, - }) { - return _then(_value.copyWith( - displayName: null == displayName - ? _value.displayName - : displayName // ignore: cast_nullable_to_non_nullable - as String, - linkId: null == linkId - ? _value.linkId - : linkId // ignore: cast_nullable_to_non_nullable - as String, - platform: null == platform - ? _value.platform - : platform // ignore: cast_nullable_to_non_nullable - as String, - show: null == show - ? _value.show - : show // ignore: cast_nullable_to_non_nullable - as bool, - uniqueId: freezed == uniqueId - ? _value.uniqueId - : uniqueId // ignore: cast_nullable_to_non_nullable - as String?, - country: freezed == country - ? _value.country - : country // ignore: cast_nullable_to_non_nullable - as String?, - url: freezed == url - ? _value.url - : url // ignore: cast_nullable_to_non_nullable - as String?, - nativeAppUriMobile: freezed == nativeAppUriMobile - ? _value.nativeAppUriMobile - : nativeAppUriMobile // ignore: cast_nullable_to_non_nullable - as String?, - nativeAppUriDesktop: freezed == nativeAppUriDesktop - ? _value.nativeAppUriDesktop - : nativeAppUriDesktop // ignore: cast_nullable_to_non_nullable - as String?, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$SongLinkImplCopyWith<$Res> - implements $SongLinkCopyWith<$Res> { - factory _$$SongLinkImplCopyWith( - _$SongLinkImpl value, $Res Function(_$SongLinkImpl) then) = - __$$SongLinkImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {String displayName, - String linkId, - String platform, - bool show, - String? uniqueId, - String? country, - String? url, - String? nativeAppUriMobile, - String? nativeAppUriDesktop}); -} - -/// @nodoc -class __$$SongLinkImplCopyWithImpl<$Res> - extends _$SongLinkCopyWithImpl<$Res, _$SongLinkImpl> - implements _$$SongLinkImplCopyWith<$Res> { - __$$SongLinkImplCopyWithImpl( - _$SongLinkImpl _value, $Res Function(_$SongLinkImpl) _then) - : super(_value, _then); - - /// Create a copy of SongLink - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? displayName = null, - Object? linkId = null, - Object? platform = null, - Object? show = null, - Object? uniqueId = freezed, - Object? country = freezed, - Object? url = freezed, - Object? nativeAppUriMobile = freezed, - Object? nativeAppUriDesktop = freezed, - }) { - return _then(_$SongLinkImpl( - displayName: null == displayName - ? _value.displayName - : displayName // ignore: cast_nullable_to_non_nullable - as String, - linkId: null == linkId - ? _value.linkId - : linkId // ignore: cast_nullable_to_non_nullable - as String, - platform: null == platform - ? _value.platform - : platform // ignore: cast_nullable_to_non_nullable - as String, - show: null == show - ? _value.show - : show // ignore: cast_nullable_to_non_nullable - as bool, - uniqueId: freezed == uniqueId - ? _value.uniqueId - : uniqueId // ignore: cast_nullable_to_non_nullable - as String?, - country: freezed == country - ? _value.country - : country // ignore: cast_nullable_to_non_nullable - as String?, - url: freezed == url - ? _value.url - : url // ignore: cast_nullable_to_non_nullable - as String?, - nativeAppUriMobile: freezed == nativeAppUriMobile - ? _value.nativeAppUriMobile - : nativeAppUriMobile // ignore: cast_nullable_to_non_nullable - as String?, - nativeAppUriDesktop: freezed == nativeAppUriDesktop - ? _value.nativeAppUriDesktop - : nativeAppUriDesktop // ignore: cast_nullable_to_non_nullable - as String?, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$SongLinkImpl implements _SongLink { - const _$SongLinkImpl( - {required this.displayName, - required this.linkId, - required this.platform, - required this.show, - required this.uniqueId, - required this.country, - required this.url, - required this.nativeAppUriMobile, - required this.nativeAppUriDesktop}); - - factory _$SongLinkImpl.fromJson(Map json) => - _$$SongLinkImplFromJson(json); - - @override - final String displayName; - @override - final String linkId; - @override - final String platform; - @override - final bool show; - @override - final String? uniqueId; - @override - final String? country; - @override - final String? url; - @override - final String? nativeAppUriMobile; - @override - final String? nativeAppUriDesktop; - - @override - String toString() { - return 'SongLink(displayName: $displayName, linkId: $linkId, platform: $platform, show: $show, uniqueId: $uniqueId, country: $country, url: $url, nativeAppUriMobile: $nativeAppUriMobile, nativeAppUriDesktop: $nativeAppUriDesktop)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$SongLinkImpl && - (identical(other.displayName, displayName) || - other.displayName == displayName) && - (identical(other.linkId, linkId) || other.linkId == linkId) && - (identical(other.platform, platform) || - other.platform == platform) && - (identical(other.show, show) || other.show == show) && - (identical(other.uniqueId, uniqueId) || - other.uniqueId == uniqueId) && - (identical(other.country, country) || other.country == country) && - (identical(other.url, url) || other.url == url) && - (identical(other.nativeAppUriMobile, nativeAppUriMobile) || - other.nativeAppUriMobile == nativeAppUriMobile) && - (identical(other.nativeAppUriDesktop, nativeAppUriDesktop) || - other.nativeAppUriDesktop == nativeAppUriDesktop)); - } - - @JsonKey(includeFromJson: false, includeToJson: false) - @override - int get hashCode => Object.hash(runtimeType, displayName, linkId, platform, - show, uniqueId, country, url, nativeAppUriMobile, nativeAppUriDesktop); - - /// Create a copy of SongLink - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$SongLinkImplCopyWith<_$SongLinkImpl> get copyWith => - __$$SongLinkImplCopyWithImpl<_$SongLinkImpl>(this, _$identity); - - @override - Map toJson() { - return _$$SongLinkImplToJson( - this, - ); - } -} - -abstract class _SongLink implements SongLink { - const factory _SongLink( - {required final String displayName, - required final String linkId, - required final String platform, - required final bool show, - required final String? uniqueId, - required final String? country, - required final String? url, - required final String? nativeAppUriMobile, - required final String? nativeAppUriDesktop}) = _$SongLinkImpl; - - factory _SongLink.fromJson(Map json) = - _$SongLinkImpl.fromJson; - - @override - String get displayName; - @override - String get linkId; - @override - String get platform; - @override - bool get show; - @override - String? get uniqueId; - @override - String? get country; - @override - String? get url; - @override - String? get nativeAppUriMobile; - @override - String? get nativeAppUriDesktop; - - /// Create a copy of SongLink - /// with the given fields replaced by the non-null parameter values. - @override - @JsonKey(includeFromJson: false, includeToJson: false) - _$$SongLinkImplCopyWith<_$SongLinkImpl> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/lib/services/song_link/song_link.g.dart b/lib/services/song_link/song_link.g.dart deleted file mode 100644 index 7658a74c..00000000 --- a/lib/services/song_link/song_link.g.dart +++ /dev/null @@ -1,32 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'song_link.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -_$SongLinkImpl _$$SongLinkImplFromJson(Map json) => _$SongLinkImpl( - displayName: json['displayName'] as String, - linkId: json['linkId'] as String, - platform: json['platform'] as String, - show: json['show'] as bool, - uniqueId: json['uniqueId'] as String?, - country: json['country'] as String?, - url: json['url'] as String?, - nativeAppUriMobile: json['nativeAppUriMobile'] as String?, - nativeAppUriDesktop: json['nativeAppUriDesktop'] as String?, - ); - -Map _$$SongLinkImplToJson(_$SongLinkImpl instance) => - { - 'displayName': instance.displayName, - 'linkId': instance.linkId, - 'platform': instance.platform, - 'show': instance.show, - 'uniqueId': instance.uniqueId, - 'country': instance.country, - 'url': instance.url, - 'nativeAppUriMobile': instance.nativeAppUriMobile, - 'nativeAppUriDesktop': instance.nativeAppUriDesktop, - };