From 63118319021e5b9e35b023792122345aad74e628 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 3 Nov 2025 19:33:47 +0600 Subject: [PATCH] feat: move away from track source query and preferences audio quality and codec --- drift_schemas/app_db/drift_schema_v10.json | 1 + .../dialogs/track_details_dialog.dart | 11 +- .../presentation_actions.dart | 19 +- lib/models/database/database.dart | 9 + lib/models/database/database.g.dart | 602 +++---------- lib/models/database/database.steps.dart | 307 ++++++- lib/models/database/tables/preferences.dart | 6 - lib/models/database/tables/source_match.dart | 2 +- lib/models/metadata/audio_source.dart | 22 +- lib/models/metadata/metadata.dart | 1 + lib/models/metadata/metadata.freezed.dart | 62 +- lib/models/metadata/metadata.g.dart | 4 +- lib/models/playback/track_sources.dart | 1 - .../playback/track_sources.freezed.dart | 800 ------------------ lib/models/playback/track_sources.g.dart | 99 +-- .../local_folder/cache_export_dialog.dart | 5 +- lib/modules/player/player.dart | 56 +- lib/modules/player/sibling_tracks_sheet.dart | 347 ++------ .../getting_started/sections/playback.dart | 123 ++- lib/pages/settings/sections/playback.dart | 439 ++-------- lib/provider/audio_player/audio_player.dart | 11 +- .../audio_player/audio_player_streams.dart | 7 +- .../audio_player/querying_track_info.dart | 12 +- .../sources/invidious_instances_provider.dart | 12 - .../sources/piped_instances_provider.dart | 17 - lib/provider/download_manager_provider.dart | 71 +- .../audio_source/quality_label.dart | 12 + .../audio_source/quality_presets.dart | 120 +++ .../audio_source/quality_presets.freezed.dart | 289 +++++++ .../audio_source/quality_presets.g.dart | 38 + lib/provider/server/active_track_sources.dart | 17 +- lib/provider/server/routes/playback.dart | 49 +- .../server/sourced_track_provider.dart | 49 ++ lib/provider/server/track_sources.dart | 48 -- lib/provider/skip_segments/skip_segments.dart | 14 +- .../user_preferences_provider.dart | 61 -- lib/services/audio_player/audio_player.dart | 25 +- lib/services/sourced_track/exceptions.dart | 6 +- lib/services/sourced_track/sourced_track.dart | 55 +- lib/utils/service_utils.dart | 91 -- pubspec.lock | 32 - pubspec.yaml | 3 - test/drift/app_db/generated/schema_v10.dart | 73 +- 43 files changed, 1352 insertions(+), 2676 deletions(-) create mode 100644 drift_schemas/app_db/drift_schema_v10.json delete mode 100644 lib/models/playback/track_sources.freezed.dart delete mode 100644 lib/provider/audio_player/sources/invidious_instances_provider.dart delete mode 100644 lib/provider/audio_player/sources/piped_instances_provider.dart create mode 100644 lib/provider/metadata_plugin/audio_source/quality_label.dart create mode 100644 lib/provider/metadata_plugin/audio_source/quality_presets.dart create mode 100644 lib/provider/metadata_plugin/audio_source/quality_presets.freezed.dart create mode 100644 lib/provider/metadata_plugin/audio_source/quality_presets.g.dart create mode 100644 lib/provider/server/sourced_track_provider.dart delete mode 100644 lib/provider/server/track_sources.dart diff --git a/drift_schemas/app_db/drift_schema_v10.json b/drift_schemas/app_db/drift_schema_v10.json new file mode 100644 index 00000000..5fb86d25 --- /dev/null +++ b/drift_schemas/app_db/drift_schema_v10.json @@ -0,0 +1 @@ +{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.2.0"},"options":{"store_date_time_values_as_text":false},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"authentication_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"cookie","getter_name":"cookie","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"EncryptedTextConverter()","dart_type_name":"DecryptedText"}},{"name":"access_token","getter_name":"accessToken","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"EncryptedTextConverter()","dart_type_name":"DecryptedText"}},{"name":"expiration","getter_name":"expiration","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":1,"references":[],"type":"table","data":{"name":"blacklist_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"element_type","getter_name":"elementType","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(BlacklistedType.values)","dart_type_name":"BlacklistedType"}},{"name":"element_id","getter_name":"elementId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":2,"references":[],"type":"table","data":{"name":"preferences_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"album_color_sync","getter_name":"albumColorSync","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"album_color_sync\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"album_color_sync\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]},{"name":"amoled_dark_theme","getter_name":"amoledDarkTheme","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"amoled_dark_theme\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"amoled_dark_theme\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"check_update","getter_name":"checkUpdate","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"check_update\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"check_update\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]},{"name":"normalize_audio","getter_name":"normalizeAudio","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"normalize_audio\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"normalize_audio\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"show_system_tray_icon","getter_name":"showSystemTrayIcon","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"show_system_tray_icon\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"show_system_tray_icon\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"system_title_bar","getter_name":"systemTitleBar","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"system_title_bar\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"system_title_bar\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"skip_non_music","getter_name":"skipNonMusic","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"skip_non_music\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"skip_non_music\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"close_behavior","getter_name":"closeBehavior","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(CloseBehavior.close.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(CloseBehavior.values)","dart_type_name":"CloseBehavior"}},{"name":"accent_color_scheme","getter_name":"accentColorScheme","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"Slate:0xff64748b\")","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const SpotubeColorConverter()","dart_type_name":"SpotubeColor"}},{"name":"layout_mode","getter_name":"layoutMode","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(LayoutMode.adaptive.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(LayoutMode.values)","dart_type_name":"LayoutMode"}},{"name":"locale","getter_name":"locale","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant('{\"languageCode\":\"system\",\"countryCode\":\"system\"}')","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const LocaleConverter()","dart_type_name":"Locale"}},{"name":"market","getter_name":"market","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(Market.US.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(Market.values)","dart_type_name":"Market"}},{"name":"search_mode","getter_name":"searchMode","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(SearchMode.youtube.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(SearchMode.values)","dart_type_name":"SearchMode"}},{"name":"download_location","getter_name":"downloadLocation","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"\")","default_client_dart":null,"dsl_features":[]},{"name":"local_library_location","getter_name":"localLibraryLocation","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"\")","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const StringListConverter()","dart_type_name":"List"}},{"name":"theme_mode","getter_name":"themeMode","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(ThemeMode.system.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(ThemeMode.values)","dart_type_name":"ThemeMode"}},{"name":"audio_source_id","getter_name":"audioSourceId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"youtube_client_engine","getter_name":"youtubeClientEngine","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(YoutubeClientEngine.youtubeExplode.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(YoutubeClientEngine.values)","dart_type_name":"YoutubeClientEngine"}},{"name":"discord_presence","getter_name":"discordPresence","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"discord_presence\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"discord_presence\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]},{"name":"endless_playback","getter_name":"endlessPlayback","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"endless_playback\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"endless_playback\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]},{"name":"enable_connect","getter_name":"enableConnect","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"enable_connect\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"enable_connect\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"connect_port","getter_name":"connectPort","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const Constant(-1)","default_client_dart":null,"dsl_features":[]},{"name":"cache_music","getter_name":"cacheMusic","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"cache_music\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"cache_music\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":3,"references":[],"type":"table","data":{"name":"scrobbler_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"currentDateAndTime","default_client_dart":null,"dsl_features":[]},{"name":"username","getter_name":"username","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"password_hash","getter_name":"passwordHash","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"EncryptedTextConverter()","dart_type_name":"DecryptedText"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":4,"references":[],"type":"table","data":{"name":"skip_segment_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"start","getter_name":"start","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"end","getter_name":"end","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"track_id","getter_name":"trackId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"currentDateAndTime","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":5,"references":[],"type":"table","data":{"name":"source_match_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"track_id","getter_name":"trackId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"source_info","getter_name":"sourceInfo","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"{}\")","default_client_dart":null,"dsl_features":[]},{"name":"source_type","getter_name":"sourceType","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"currentDateAndTime","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":6,"references":[],"type":"table","data":{"name":"audio_player_state_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"playing","getter_name":"playing","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"playing\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"playing\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"loop_mode","getter_name":"loopMode","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(PlaylistMode.values)","dart_type_name":"PlaylistMode"}},{"name":"shuffled","getter_name":"shuffled","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"shuffled\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"shuffled\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"collections","getter_name":"collections","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const StringListConverter()","dart_type_name":"List"}},{"name":"tracks","getter_name":"tracks","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"[]\")","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const SpotubeTrackObjectListConverter()","dart_type_name":"List"}},{"name":"current_index","getter_name":"currentIndex","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const Constant(0)","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":7,"references":[],"type":"table","data":{"name":"history_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"currentDateAndTime","default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(HistoryEntryType.values)","dart_type_name":"HistoryEntryType"}},{"name":"item_id","getter_name":"itemId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"data","getter_name":"data","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const MapTypeConverter()","dart_type_name":"Map"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":8,"references":[],"type":"table","data":{"name":"lyrics_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"track_id","getter_name":"trackId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"data","getter_name":"data","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"SubtitleTypeConverter()","dart_type_name":"SubtitleSimple"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":9,"references":[],"type":"table","data":{"name":"plugins_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[{"allowed-lengths":{"min":1,"max":50}}]},{"name":"description","getter_name":"description","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"version","getter_name":"version","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"author","getter_name":"author","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"entry_point","getter_name":"entryPoint","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"apis","getter_name":"apis","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const StringListConverter()","dart_type_name":"List"}},{"name":"abilities","getter_name":"abilities","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const StringListConverter()","dart_type_name":"List"}},{"name":"selected_for_metadata","getter_name":"selectedForMetadata","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"selected_for_metadata\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"selected_for_metadata\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"selected_for_audio_source","getter_name":"selectedForAudioSource","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"selected_for_audio_source\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"selected_for_audio_source\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"repository","getter_name":"repository","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"plugin_api_version","getter_name":"pluginApiVersion","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant('2.0.0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":10,"references":[1],"type":"index","data":{"on":1,"name":"unique_blacklist","sql":null,"unique":true,"columns":["element_type","element_id"]}},{"id":11,"references":[5],"type":"index","data":{"on":5,"name":"uniq_track_match","sql":null,"unique":true,"columns":["track_id","source_info","source_type"]}}]} \ No newline at end of file diff --git a/lib/components/dialogs/track_details_dialog.dart b/lib/components/dialogs/track_details_dialog.dart index 3d3fd7e9..9d35a6fb 100644 --- a/lib/components/dialogs/track_details_dialog.dart +++ b/lib/components/dialogs/track_details_dialog.dart @@ -7,8 +7,7 @@ import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/duration.dart'; import 'package:spotube/models/metadata/metadata.dart'; -import 'package:spotube/models/playback/track_sources.dart'; -import 'package:spotube/provider/server/track_sources.dart'; +import 'package:spotube/provider/server/sourced_track_provider.dart'; class TrackDetailsDialog extends HookConsumerWidget { final SpotubeFullTrackObject track; @@ -21,8 +20,7 @@ class TrackDetailsDialog extends HookConsumerWidget { Widget build(BuildContext context, ref) { final theme = Theme.of(context); final mediaQuery = MediaQuery.of(context); - final sourcedTrack = - ref.read(trackSourcesProvider(TrackSourceQuery.fromTrack(track))); + final sourcedTrack = ref.read(sourcedTrackProvider(track)); final detailsMap = { context.l10n.title: track.name, @@ -39,8 +37,7 @@ class TrackDetailsDialog extends HookConsumerWidget { // style: const TextStyle(color: Colors.blue), // ), context.l10n.duration: sourcedTrack.asData != null - ? Duration(milliseconds: sourcedTrack.asData!.value.info.durationMs) - .toHumanReadableString() + ? sourcedTrack.asData!.value.info.duration.toHumanReadableString() : Duration(milliseconds: track.durationMs).toHumanReadableString(), if (track.album.releaseDate != null) context.l10n.released: track.album.releaseDate, @@ -57,7 +54,7 @@ class TrackDetailsDialog extends HookConsumerWidget { maxLines: 2, overflow: TextOverflow.ellipsis, ), - context.l10n.channel: Text(sourceInfo.artists), + context.l10n.channel: Text(sourceInfo.artists.join(", ")), if (sourcedTrack.asData?.value.url != null) context.l10n.streamUrl: Hyperlink( sourcedTrack.asData!.value.url ?? "", diff --git a/lib/components/track_presentation/presentation_actions.dart b/lib/components/track_presentation/presentation_actions.dart index 735a4514..54aa3428 100644 --- a/lib/components/track_presentation/presentation_actions.dart +++ b/lib/components/track_presentation/presentation_actions.dart @@ -8,12 +8,10 @@ import 'package:spotube/components/dialogs/playlist_add_track_dialog.dart'; import 'package:spotube/components/track_presentation/presentation_props.dart'; import 'package:spotube/components/track_presentation/presentation_state.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/models/database/database.dart'; import 'package:spotube/models/metadata/metadata.dart'; import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/provider/history/history.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; -import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; ToastOverlay showToastForAction( BuildContext context, @@ -70,8 +68,6 @@ class TrackPresentationActionsSection extends HookConsumerWidget { final downloader = ref.watch(downloadManagerProvider.notifier); final playlistNotifier = ref.watch(audioPlayerProvider.notifier); final historyNotifier = ref.watch(playbackHistoryActionsProvider); - final audioSource = - ref.watch(userPreferencesProvider.select((s) => s.audioSource)); final state = ref.watch(presentationStateProvider(options.collection)); final notifier = @@ -85,14 +81,13 @@ class TrackPresentationActionsSection extends HookConsumerWidget { }) async { final fullTrackObjects = tracks.whereType().toList(); - final confirmed = audioSource == AudioSource.piped || - (await showDialog( - context: context, - builder: (context) { - return const ConfirmDownloadDialog(); - }, - ) ?? - false); + final confirmed = await showDialog( + context: context, + builder: (context) { + return const ConfirmDownloadDialog(); + }, + ) ?? + false; if (confirmed != true) return; downloader.batchAddToQueue(fullTrackObjects); notifier.deselectAllTracks(); diff --git a/lib/models/database/database.dart b/lib/models/database/database.dart index a03cdb8c..786b813f 100644 --- a/lib/models/database/database.dart +++ b/lib/models/database/database.dart @@ -210,6 +210,15 @@ class AppDatabase extends _$AppDatabase { pluginsTable.selectedForAudioSource, ); }, + from9To10: (m, schema) async { + await m.dropColumn(schema.preferencesTable, "piped_instance"); + await m.dropColumn(schema.preferencesTable, "invidious_instance"); + await m.addColumn( + schema.sourceMatchTable, + sourceMatchTable.sourceInfo, + ); + await m.dropColumn(schema.sourceMatchTable, "source_id"); + }, ), ); } diff --git a/lib/models/database/database.g.dart b/lib/models/database/database.g.dart index 70f6aa26..4a9a7eba 100644 --- a/lib/models/database/database.g.dart +++ b/lib/models/database/database.g.dart @@ -558,15 +558,6 @@ class $PreferencesTableTable extends PreferencesTable requiredDuringInsert: false, defaultConstraints: GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT')); - @override - late final GeneratedColumnWithTypeConverter - audioQuality = GeneratedColumn( - 'audio_quality', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: Constant(SourceQualities.high.name)) - .withConverter( - $PreferencesTableTable.$converteraudioQuality); static const VerificationMeta _albumColorSyncMeta = const VerificationMeta('albumColorSync'); @override @@ -703,22 +694,6 @@ class $PreferencesTableTable extends PreferencesTable defaultValue: const Constant("")) .withConverter>( $PreferencesTableTable.$converterlocalLibraryLocation); - static const VerificationMeta _pipedInstanceMeta = - const VerificationMeta('pipedInstance'); - @override - late final GeneratedColumn pipedInstance = GeneratedColumn( - 'piped_instance', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: const Constant("https://pipedapi.kavin.rocks")); - static const VerificationMeta _invidiousInstanceMeta = - const VerificationMeta('invidiousInstance'); - @override - late final GeneratedColumn invidiousInstance = - GeneratedColumn('invidious_instance', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: const Constant("https://inv.nadeko.net")); @override late final GeneratedColumnWithTypeConverter themeMode = GeneratedColumn('theme_mode', aliasedName, false, @@ -726,14 +701,12 @@ class $PreferencesTableTable extends PreferencesTable requiredDuringInsert: false, defaultValue: Constant(ThemeMode.system.name)) .withConverter($PreferencesTableTable.$converterthemeMode); + static const VerificationMeta _audioSourceIdMeta = + const VerificationMeta('audioSourceId'); @override - late final GeneratedColumnWithTypeConverter audioSource = - GeneratedColumn('audio_source', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: Constant(AudioSource.youtube.name)) - .withConverter( - $PreferencesTableTable.$converteraudioSource); + late final GeneratedColumn audioSourceId = GeneratedColumn( + 'audio_source_id', aliasedName, true, + type: DriftSqlType.string, requiredDuringInsert: false); @override late final GeneratedColumnWithTypeConverter youtubeClientEngine = GeneratedColumn( @@ -743,24 +716,6 @@ class $PreferencesTableTable extends PreferencesTable defaultValue: Constant(YoutubeClientEngine.youtubeExplode.name)) .withConverter( $PreferencesTableTable.$converteryoutubeClientEngine); - @override - late final GeneratedColumnWithTypeConverter - streamMusicCodec = GeneratedColumn( - 'stream_music_codec', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: Constant(SourceCodecs.weba.name)) - .withConverter( - $PreferencesTableTable.$converterstreamMusicCodec); - @override - late final GeneratedColumnWithTypeConverter - downloadMusicCodec = GeneratedColumn( - 'download_music_codec', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: Constant(SourceCodecs.m4a.name)) - .withConverter( - $PreferencesTableTable.$converterdownloadMusicCodec); static const VerificationMeta _discordPresenceMeta = const VerificationMeta('discordPresence'); @override @@ -812,7 +767,6 @@ class $PreferencesTableTable extends PreferencesTable @override List get $columns => [ id, - audioQuality, albumColorSync, amoledDarkTheme, checkUpdate, @@ -828,13 +782,9 @@ class $PreferencesTableTable extends PreferencesTable searchMode, downloadLocation, localLibraryLocation, - pipedInstance, - invidiousInstance, themeMode, - audioSource, + audioSourceId, youtubeClientEngine, - streamMusicCodec, - downloadMusicCodec, discordPresence, endlessPlayback, enableConnect, @@ -903,17 +853,11 @@ class $PreferencesTableTable extends PreferencesTable downloadLocation.isAcceptableOrUnknown( data['download_location']!, _downloadLocationMeta)); } - if (data.containsKey('piped_instance')) { + if (data.containsKey('audio_source_id')) { context.handle( - _pipedInstanceMeta, - pipedInstance.isAcceptableOrUnknown( - data['piped_instance']!, _pipedInstanceMeta)); - } - if (data.containsKey('invidious_instance')) { - context.handle( - _invidiousInstanceMeta, - invidiousInstance.isAcceptableOrUnknown( - data['invidious_instance']!, _invidiousInstanceMeta)); + _audioSourceIdMeta, + audioSourceId.isAcceptableOrUnknown( + data['audio_source_id']!, _audioSourceIdMeta)); } if (data.containsKey('discord_presence')) { context.handle( @@ -956,9 +900,6 @@ class $PreferencesTableTable extends PreferencesTable return PreferencesTableData( id: attachedDatabase.typeMapping .read(DriftSqlType.int, data['${effectivePrefix}id'])!, - audioQuality: $PreferencesTableTable.$converteraudioQuality.fromSql( - attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}audio_quality'])!), albumColorSync: attachedDatabase.typeMapping .read(DriftSqlType.bool, data['${effectivePrefix}album_color_sync'])!, amoledDarkTheme: attachedDatabase.typeMapping.read( @@ -997,25 +938,14 @@ class $PreferencesTableTable extends PreferencesTable .$converterlocalLibraryLocation .fromSql(attachedDatabase.typeMapping.read(DriftSqlType.string, data['${effectivePrefix}local_library_location'])!), - pipedInstance: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}piped_instance'])!, - invidiousInstance: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}invidious_instance'])!, themeMode: $PreferencesTableTable.$converterthemeMode.fromSql( attachedDatabase.typeMapping.read( DriftSqlType.string, data['${effectivePrefix}theme_mode'])!), - audioSource: $PreferencesTableTable.$converteraudioSource.fromSql( - attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}audio_source'])!), + audioSourceId: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}audio_source_id']), youtubeClientEngine: $PreferencesTableTable.$converteryoutubeClientEngine .fromSql(attachedDatabase.typeMapping.read(DriftSqlType.string, data['${effectivePrefix}youtube_client_engine'])!), - streamMusicCodec: $PreferencesTableTable.$converterstreamMusicCodec - .fromSql(attachedDatabase.typeMapping.read(DriftSqlType.string, - data['${effectivePrefix}stream_music_codec'])!), - downloadMusicCodec: $PreferencesTableTable.$converterdownloadMusicCodec - .fromSql(attachedDatabase.typeMapping.read(DriftSqlType.string, - data['${effectivePrefix}download_music_codec'])!), discordPresence: attachedDatabase.typeMapping .read(DriftSqlType.bool, data['${effectivePrefix}discord_presence'])!, endlessPlayback: attachedDatabase.typeMapping @@ -1034,9 +964,6 @@ class $PreferencesTableTable extends PreferencesTable return $PreferencesTableTable(attachedDatabase, alias); } - static JsonTypeConverter2 - $converteraudioQuality = - const EnumNameConverter(SourceQualities.values); static JsonTypeConverter2 $convertercloseBehavior = const EnumNameConverter(CloseBehavior.values); @@ -1054,23 +981,14 @@ class $PreferencesTableTable extends PreferencesTable const StringListConverter(); static JsonTypeConverter2 $converterthemeMode = const EnumNameConverter(ThemeMode.values); - static JsonTypeConverter2 $converteraudioSource = - const EnumNameConverter(AudioSource.values); static JsonTypeConverter2 $converteryoutubeClientEngine = const EnumNameConverter(YoutubeClientEngine.values); - static JsonTypeConverter2 - $converterstreamMusicCodec = - const EnumNameConverter(SourceCodecs.values); - static JsonTypeConverter2 - $converterdownloadMusicCodec = - const EnumNameConverter(SourceCodecs.values); } class PreferencesTableData extends DataClass implements Insertable { final int id; - final SourceQualities audioQuality; final bool albumColorSync; final bool amoledDarkTheme; final bool checkUpdate; @@ -1086,13 +1004,9 @@ class PreferencesTableData extends DataClass final SearchMode searchMode; final String downloadLocation; final List localLibraryLocation; - final String pipedInstance; - final String invidiousInstance; final ThemeMode themeMode; - final AudioSource audioSource; + final String? audioSourceId; final YoutubeClientEngine youtubeClientEngine; - final SourceCodecs streamMusicCodec; - final SourceCodecs downloadMusicCodec; final bool discordPresence; final bool endlessPlayback; final bool enableConnect; @@ -1100,7 +1014,6 @@ class PreferencesTableData extends DataClass final bool cacheMusic; const PreferencesTableData( {required this.id, - required this.audioQuality, required this.albumColorSync, required this.amoledDarkTheme, required this.checkUpdate, @@ -1116,13 +1029,9 @@ class PreferencesTableData extends DataClass required this.searchMode, required this.downloadLocation, required this.localLibraryLocation, - required this.pipedInstance, - required this.invidiousInstance, required this.themeMode, - required this.audioSource, + this.audioSourceId, required this.youtubeClientEngine, - required this.streamMusicCodec, - required this.downloadMusicCodec, required this.discordPresence, required this.endlessPlayback, required this.enableConnect, @@ -1132,10 +1041,6 @@ class PreferencesTableData extends DataClass Map toColumns(bool nullToAbsent) { final map = {}; map['id'] = Variable(id); - { - map['audio_quality'] = Variable( - $PreferencesTableTable.$converteraudioQuality.toSql(audioQuality)); - } map['album_color_sync'] = Variable(albumColorSync); map['amoled_dark_theme'] = Variable(amoledDarkTheme); map['check_update'] = Variable(checkUpdate); @@ -1174,31 +1079,18 @@ class PreferencesTableData extends DataClass .$converterlocalLibraryLocation .toSql(localLibraryLocation)); } - map['piped_instance'] = Variable(pipedInstance); - map['invidious_instance'] = Variable(invidiousInstance); { map['theme_mode'] = Variable( $PreferencesTableTable.$converterthemeMode.toSql(themeMode)); } - { - map['audio_source'] = Variable( - $PreferencesTableTable.$converteraudioSource.toSql(audioSource)); + if (!nullToAbsent || audioSourceId != null) { + map['audio_source_id'] = Variable(audioSourceId); } { map['youtube_client_engine'] = Variable($PreferencesTableTable .$converteryoutubeClientEngine .toSql(youtubeClientEngine)); } - { - map['stream_music_codec'] = Variable($PreferencesTableTable - .$converterstreamMusicCodec - .toSql(streamMusicCodec)); - } - { - map['download_music_codec'] = Variable($PreferencesTableTable - .$converterdownloadMusicCodec - .toSql(downloadMusicCodec)); - } map['discord_presence'] = Variable(discordPresence); map['endless_playback'] = Variable(endlessPlayback); map['enable_connect'] = Variable(enableConnect); @@ -1210,7 +1102,6 @@ class PreferencesTableData extends DataClass PreferencesTableCompanion toCompanion(bool nullToAbsent) { return PreferencesTableCompanion( id: Value(id), - audioQuality: Value(audioQuality), albumColorSync: Value(albumColorSync), amoledDarkTheme: Value(amoledDarkTheme), checkUpdate: Value(checkUpdate), @@ -1226,13 +1117,11 @@ class PreferencesTableData extends DataClass searchMode: Value(searchMode), downloadLocation: Value(downloadLocation), localLibraryLocation: Value(localLibraryLocation), - pipedInstance: Value(pipedInstance), - invidiousInstance: Value(invidiousInstance), themeMode: Value(themeMode), - audioSource: Value(audioSource), + audioSourceId: audioSourceId == null && nullToAbsent + ? const Value.absent() + : Value(audioSourceId), youtubeClientEngine: Value(youtubeClientEngine), - streamMusicCodec: Value(streamMusicCodec), - downloadMusicCodec: Value(downloadMusicCodec), discordPresence: Value(discordPresence), endlessPlayback: Value(endlessPlayback), enableConnect: Value(enableConnect), @@ -1246,8 +1135,6 @@ class PreferencesTableData extends DataClass serializer ??= driftRuntimeOptions.defaultSerializer; return PreferencesTableData( id: serializer.fromJson(json['id']), - audioQuality: $PreferencesTableTable.$converteraudioQuality - .fromJson(serializer.fromJson(json['audioQuality'])), albumColorSync: serializer.fromJson(json['albumColorSync']), amoledDarkTheme: serializer.fromJson(json['amoledDarkTheme']), checkUpdate: serializer.fromJson(json['checkUpdate']), @@ -1269,18 +1156,11 @@ class PreferencesTableData extends DataClass downloadLocation: serializer.fromJson(json['downloadLocation']), localLibraryLocation: serializer.fromJson>(json['localLibraryLocation']), - pipedInstance: serializer.fromJson(json['pipedInstance']), - invidiousInstance: serializer.fromJson(json['invidiousInstance']), themeMode: $PreferencesTableTable.$converterthemeMode .fromJson(serializer.fromJson(json['themeMode'])), - audioSource: $PreferencesTableTable.$converteraudioSource - .fromJson(serializer.fromJson(json['audioSource'])), + audioSourceId: serializer.fromJson(json['audioSourceId']), youtubeClientEngine: $PreferencesTableTable.$converteryoutubeClientEngine .fromJson(serializer.fromJson(json['youtubeClientEngine'])), - streamMusicCodec: $PreferencesTableTable.$converterstreamMusicCodec - .fromJson(serializer.fromJson(json['streamMusicCodec'])), - downloadMusicCodec: $PreferencesTableTable.$converterdownloadMusicCodec - .fromJson(serializer.fromJson(json['downloadMusicCodec'])), discordPresence: serializer.fromJson(json['discordPresence']), endlessPlayback: serializer.fromJson(json['endlessPlayback']), enableConnect: serializer.fromJson(json['enableConnect']), @@ -1293,8 +1173,6 @@ class PreferencesTableData extends DataClass serializer ??= driftRuntimeOptions.defaultSerializer; return { 'id': serializer.toJson(id), - 'audioQuality': serializer.toJson( - $PreferencesTableTable.$converteraudioQuality.toJson(audioQuality)), 'albumColorSync': serializer.toJson(albumColorSync), 'amoledDarkTheme': serializer.toJson(amoledDarkTheme), 'checkUpdate': serializer.toJson(checkUpdate), @@ -1315,21 +1193,12 @@ class PreferencesTableData extends DataClass 'downloadLocation': serializer.toJson(downloadLocation), 'localLibraryLocation': serializer.toJson>(localLibraryLocation), - 'pipedInstance': serializer.toJson(pipedInstance), - 'invidiousInstance': serializer.toJson(invidiousInstance), 'themeMode': serializer.toJson( $PreferencesTableTable.$converterthemeMode.toJson(themeMode)), - 'audioSource': serializer.toJson( - $PreferencesTableTable.$converteraudioSource.toJson(audioSource)), + 'audioSourceId': serializer.toJson(audioSourceId), 'youtubeClientEngine': serializer.toJson($PreferencesTableTable .$converteryoutubeClientEngine .toJson(youtubeClientEngine)), - 'streamMusicCodec': serializer.toJson($PreferencesTableTable - .$converterstreamMusicCodec - .toJson(streamMusicCodec)), - 'downloadMusicCodec': serializer.toJson($PreferencesTableTable - .$converterdownloadMusicCodec - .toJson(downloadMusicCodec)), 'discordPresence': serializer.toJson(discordPresence), 'endlessPlayback': serializer.toJson(endlessPlayback), 'enableConnect': serializer.toJson(enableConnect), @@ -1340,7 +1209,6 @@ class PreferencesTableData extends DataClass PreferencesTableData copyWith( {int? id, - SourceQualities? audioQuality, bool? albumColorSync, bool? amoledDarkTheme, bool? checkUpdate, @@ -1356,13 +1224,9 @@ class PreferencesTableData extends DataClass SearchMode? searchMode, String? downloadLocation, List? localLibraryLocation, - String? pipedInstance, - String? invidiousInstance, ThemeMode? themeMode, - AudioSource? audioSource, + Value audioSourceId = const Value.absent(), YoutubeClientEngine? youtubeClientEngine, - SourceCodecs? streamMusicCodec, - SourceCodecs? downloadMusicCodec, bool? discordPresence, bool? endlessPlayback, bool? enableConnect, @@ -1370,7 +1234,6 @@ class PreferencesTableData extends DataClass bool? cacheMusic}) => PreferencesTableData( id: id ?? this.id, - audioQuality: audioQuality ?? this.audioQuality, albumColorSync: albumColorSync ?? this.albumColorSync, amoledDarkTheme: amoledDarkTheme ?? this.amoledDarkTheme, checkUpdate: checkUpdate ?? this.checkUpdate, @@ -1386,13 +1249,10 @@ class PreferencesTableData extends DataClass searchMode: searchMode ?? this.searchMode, downloadLocation: downloadLocation ?? this.downloadLocation, localLibraryLocation: localLibraryLocation ?? this.localLibraryLocation, - pipedInstance: pipedInstance ?? this.pipedInstance, - invidiousInstance: invidiousInstance ?? this.invidiousInstance, themeMode: themeMode ?? this.themeMode, - audioSource: audioSource ?? this.audioSource, + audioSourceId: + audioSourceId.present ? audioSourceId.value : this.audioSourceId, youtubeClientEngine: youtubeClientEngine ?? this.youtubeClientEngine, - streamMusicCodec: streamMusicCodec ?? this.streamMusicCodec, - downloadMusicCodec: downloadMusicCodec ?? this.downloadMusicCodec, discordPresence: discordPresence ?? this.discordPresence, endlessPlayback: endlessPlayback ?? this.endlessPlayback, enableConnect: enableConnect ?? this.enableConnect, @@ -1402,9 +1262,6 @@ class PreferencesTableData extends DataClass PreferencesTableData copyWithCompanion(PreferencesTableCompanion data) { return PreferencesTableData( id: data.id.present ? data.id.value : this.id, - audioQuality: data.audioQuality.present - ? data.audioQuality.value - : this.audioQuality, albumColorSync: data.albumColorSync.present ? data.albumColorSync.value : this.albumColorSync, @@ -1443,24 +1300,13 @@ class PreferencesTableData extends DataClass localLibraryLocation: data.localLibraryLocation.present ? data.localLibraryLocation.value : this.localLibraryLocation, - pipedInstance: data.pipedInstance.present - ? data.pipedInstance.value - : this.pipedInstance, - invidiousInstance: data.invidiousInstance.present - ? data.invidiousInstance.value - : this.invidiousInstance, themeMode: data.themeMode.present ? data.themeMode.value : this.themeMode, - audioSource: - data.audioSource.present ? data.audioSource.value : this.audioSource, + audioSourceId: data.audioSourceId.present + ? data.audioSourceId.value + : this.audioSourceId, youtubeClientEngine: data.youtubeClientEngine.present ? data.youtubeClientEngine.value : this.youtubeClientEngine, - streamMusicCodec: data.streamMusicCodec.present - ? data.streamMusicCodec.value - : this.streamMusicCodec, - downloadMusicCodec: data.downloadMusicCodec.present - ? data.downloadMusicCodec.value - : this.downloadMusicCodec, discordPresence: data.discordPresence.present ? data.discordPresence.value : this.discordPresence, @@ -1481,7 +1327,6 @@ class PreferencesTableData extends DataClass String toString() { return (StringBuffer('PreferencesTableData(') ..write('id: $id, ') - ..write('audioQuality: $audioQuality, ') ..write('albumColorSync: $albumColorSync, ') ..write('amoledDarkTheme: $amoledDarkTheme, ') ..write('checkUpdate: $checkUpdate, ') @@ -1497,13 +1342,9 @@ class PreferencesTableData extends DataClass ..write('searchMode: $searchMode, ') ..write('downloadLocation: $downloadLocation, ') ..write('localLibraryLocation: $localLibraryLocation, ') - ..write('pipedInstance: $pipedInstance, ') - ..write('invidiousInstance: $invidiousInstance, ') ..write('themeMode: $themeMode, ') - ..write('audioSource: $audioSource, ') + ..write('audioSourceId: $audioSourceId, ') ..write('youtubeClientEngine: $youtubeClientEngine, ') - ..write('streamMusicCodec: $streamMusicCodec, ') - ..write('downloadMusicCodec: $downloadMusicCodec, ') ..write('discordPresence: $discordPresence, ') ..write('endlessPlayback: $endlessPlayback, ') ..write('enableConnect: $enableConnect, ') @@ -1516,7 +1357,6 @@ class PreferencesTableData extends DataClass @override int get hashCode => Object.hashAll([ id, - audioQuality, albumColorSync, amoledDarkTheme, checkUpdate, @@ -1532,13 +1372,9 @@ class PreferencesTableData extends DataClass searchMode, downloadLocation, localLibraryLocation, - pipedInstance, - invidiousInstance, themeMode, - audioSource, + audioSourceId, youtubeClientEngine, - streamMusicCodec, - downloadMusicCodec, discordPresence, endlessPlayback, enableConnect, @@ -1550,7 +1386,6 @@ class PreferencesTableData extends DataClass identical(this, other) || (other is PreferencesTableData && other.id == this.id && - other.audioQuality == this.audioQuality && other.albumColorSync == this.albumColorSync && other.amoledDarkTheme == this.amoledDarkTheme && other.checkUpdate == this.checkUpdate && @@ -1566,13 +1401,9 @@ class PreferencesTableData extends DataClass other.searchMode == this.searchMode && other.downloadLocation == this.downloadLocation && other.localLibraryLocation == this.localLibraryLocation && - other.pipedInstance == this.pipedInstance && - other.invidiousInstance == this.invidiousInstance && other.themeMode == this.themeMode && - other.audioSource == this.audioSource && + other.audioSourceId == this.audioSourceId && other.youtubeClientEngine == this.youtubeClientEngine && - other.streamMusicCodec == this.streamMusicCodec && - other.downloadMusicCodec == this.downloadMusicCodec && other.discordPresence == this.discordPresence && other.endlessPlayback == this.endlessPlayback && other.enableConnect == this.enableConnect && @@ -1582,7 +1413,6 @@ class PreferencesTableData extends DataClass class PreferencesTableCompanion extends UpdateCompanion { final Value id; - final Value audioQuality; final Value albumColorSync; final Value amoledDarkTheme; final Value checkUpdate; @@ -1598,13 +1428,9 @@ class PreferencesTableCompanion extends UpdateCompanion { final Value searchMode; final Value downloadLocation; final Value> localLibraryLocation; - final Value pipedInstance; - final Value invidiousInstance; final Value themeMode; - final Value audioSource; + final Value audioSourceId; final Value youtubeClientEngine; - final Value streamMusicCodec; - final Value downloadMusicCodec; final Value discordPresence; final Value endlessPlayback; final Value enableConnect; @@ -1612,7 +1438,6 @@ class PreferencesTableCompanion extends UpdateCompanion { final Value cacheMusic; const PreferencesTableCompanion({ this.id = const Value.absent(), - this.audioQuality = const Value.absent(), this.albumColorSync = const Value.absent(), this.amoledDarkTheme = const Value.absent(), this.checkUpdate = const Value.absent(), @@ -1628,13 +1453,9 @@ class PreferencesTableCompanion extends UpdateCompanion { this.searchMode = const Value.absent(), this.downloadLocation = const Value.absent(), this.localLibraryLocation = const Value.absent(), - this.pipedInstance = const Value.absent(), - this.invidiousInstance = const Value.absent(), this.themeMode = const Value.absent(), - this.audioSource = const Value.absent(), + this.audioSourceId = const Value.absent(), this.youtubeClientEngine = const Value.absent(), - this.streamMusicCodec = const Value.absent(), - this.downloadMusicCodec = const Value.absent(), this.discordPresence = const Value.absent(), this.endlessPlayback = const Value.absent(), this.enableConnect = const Value.absent(), @@ -1643,7 +1464,6 @@ class PreferencesTableCompanion extends UpdateCompanion { }); PreferencesTableCompanion.insert({ this.id = const Value.absent(), - this.audioQuality = const Value.absent(), this.albumColorSync = const Value.absent(), this.amoledDarkTheme = const Value.absent(), this.checkUpdate = const Value.absent(), @@ -1659,13 +1479,9 @@ class PreferencesTableCompanion extends UpdateCompanion { this.searchMode = const Value.absent(), this.downloadLocation = const Value.absent(), this.localLibraryLocation = const Value.absent(), - this.pipedInstance = const Value.absent(), - this.invidiousInstance = const Value.absent(), this.themeMode = const Value.absent(), - this.audioSource = const Value.absent(), + this.audioSourceId = const Value.absent(), this.youtubeClientEngine = const Value.absent(), - this.streamMusicCodec = const Value.absent(), - this.downloadMusicCodec = const Value.absent(), this.discordPresence = const Value.absent(), this.endlessPlayback = const Value.absent(), this.enableConnect = const Value.absent(), @@ -1674,7 +1490,6 @@ class PreferencesTableCompanion extends UpdateCompanion { }); static Insertable custom({ Expression? id, - Expression? audioQuality, Expression? albumColorSync, Expression? amoledDarkTheme, Expression? checkUpdate, @@ -1690,13 +1505,9 @@ class PreferencesTableCompanion extends UpdateCompanion { Expression? searchMode, Expression? downloadLocation, Expression? localLibraryLocation, - Expression? pipedInstance, - Expression? invidiousInstance, Expression? themeMode, - Expression? audioSource, + Expression? audioSourceId, Expression? youtubeClientEngine, - Expression? streamMusicCodec, - Expression? downloadMusicCodec, Expression? discordPresence, Expression? endlessPlayback, Expression? enableConnect, @@ -1705,7 +1516,6 @@ class PreferencesTableCompanion extends UpdateCompanion { }) { return RawValuesInsertable({ if (id != null) 'id': id, - if (audioQuality != null) 'audio_quality': audioQuality, if (albumColorSync != null) 'album_color_sync': albumColorSync, if (amoledDarkTheme != null) 'amoled_dark_theme': amoledDarkTheme, if (checkUpdate != null) 'check_update': checkUpdate, @@ -1723,15 +1533,10 @@ class PreferencesTableCompanion extends UpdateCompanion { if (downloadLocation != null) 'download_location': downloadLocation, if (localLibraryLocation != null) 'local_library_location': localLibraryLocation, - if (pipedInstance != null) 'piped_instance': pipedInstance, - if (invidiousInstance != null) 'invidious_instance': invidiousInstance, if (themeMode != null) 'theme_mode': themeMode, - if (audioSource != null) 'audio_source': audioSource, + if (audioSourceId != null) 'audio_source_id': audioSourceId, if (youtubeClientEngine != null) 'youtube_client_engine': youtubeClientEngine, - if (streamMusicCodec != null) 'stream_music_codec': streamMusicCodec, - if (downloadMusicCodec != null) - 'download_music_codec': downloadMusicCodec, if (discordPresence != null) 'discord_presence': discordPresence, if (endlessPlayback != null) 'endless_playback': endlessPlayback, if (enableConnect != null) 'enable_connect': enableConnect, @@ -1742,7 +1547,6 @@ class PreferencesTableCompanion extends UpdateCompanion { PreferencesTableCompanion copyWith( {Value? id, - Value? audioQuality, Value? albumColorSync, Value? amoledDarkTheme, Value? checkUpdate, @@ -1758,13 +1562,9 @@ class PreferencesTableCompanion extends UpdateCompanion { Value? searchMode, Value? downloadLocation, Value>? localLibraryLocation, - Value? pipedInstance, - Value? invidiousInstance, Value? themeMode, - Value? audioSource, + Value? audioSourceId, Value? youtubeClientEngine, - Value? streamMusicCodec, - Value? downloadMusicCodec, Value? discordPresence, Value? endlessPlayback, Value? enableConnect, @@ -1772,7 +1572,6 @@ class PreferencesTableCompanion extends UpdateCompanion { Value? cacheMusic}) { return PreferencesTableCompanion( id: id ?? this.id, - audioQuality: audioQuality ?? this.audioQuality, albumColorSync: albumColorSync ?? this.albumColorSync, amoledDarkTheme: amoledDarkTheme ?? this.amoledDarkTheme, checkUpdate: checkUpdate ?? this.checkUpdate, @@ -1788,13 +1587,9 @@ class PreferencesTableCompanion extends UpdateCompanion { searchMode: searchMode ?? this.searchMode, downloadLocation: downloadLocation ?? this.downloadLocation, localLibraryLocation: localLibraryLocation ?? this.localLibraryLocation, - pipedInstance: pipedInstance ?? this.pipedInstance, - invidiousInstance: invidiousInstance ?? this.invidiousInstance, themeMode: themeMode ?? this.themeMode, - audioSource: audioSource ?? this.audioSource, + audioSourceId: audioSourceId ?? this.audioSourceId, youtubeClientEngine: youtubeClientEngine ?? this.youtubeClientEngine, - streamMusicCodec: streamMusicCodec ?? this.streamMusicCodec, - downloadMusicCodec: downloadMusicCodec ?? this.downloadMusicCodec, discordPresence: discordPresence ?? this.discordPresence, endlessPlayback: endlessPlayback ?? this.endlessPlayback, enableConnect: enableConnect ?? this.enableConnect, @@ -1809,11 +1604,6 @@ class PreferencesTableCompanion extends UpdateCompanion { if (id.present) { map['id'] = Variable(id.value); } - if (audioQuality.present) { - map['audio_quality'] = Variable($PreferencesTableTable - .$converteraudioQuality - .toSql(audioQuality.value)); - } if (albumColorSync.present) { map['album_color_sync'] = Variable(albumColorSync.value); } @@ -1869,36 +1659,18 @@ class PreferencesTableCompanion extends UpdateCompanion { .$converterlocalLibraryLocation .toSql(localLibraryLocation.value)); } - if (pipedInstance.present) { - map['piped_instance'] = Variable(pipedInstance.value); - } - if (invidiousInstance.present) { - map['invidious_instance'] = Variable(invidiousInstance.value); - } if (themeMode.present) { map['theme_mode'] = Variable( $PreferencesTableTable.$converterthemeMode.toSql(themeMode.value)); } - if (audioSource.present) { - map['audio_source'] = Variable($PreferencesTableTable - .$converteraudioSource - .toSql(audioSource.value)); + if (audioSourceId.present) { + map['audio_source_id'] = Variable(audioSourceId.value); } if (youtubeClientEngine.present) { map['youtube_client_engine'] = Variable($PreferencesTableTable .$converteryoutubeClientEngine .toSql(youtubeClientEngine.value)); } - if (streamMusicCodec.present) { - map['stream_music_codec'] = Variable($PreferencesTableTable - .$converterstreamMusicCodec - .toSql(streamMusicCodec.value)); - } - if (downloadMusicCodec.present) { - map['download_music_codec'] = Variable($PreferencesTableTable - .$converterdownloadMusicCodec - .toSql(downloadMusicCodec.value)); - } if (discordPresence.present) { map['discord_presence'] = Variable(discordPresence.value); } @@ -1921,7 +1693,6 @@ class PreferencesTableCompanion extends UpdateCompanion { String toString() { return (StringBuffer('PreferencesTableCompanion(') ..write('id: $id, ') - ..write('audioQuality: $audioQuality, ') ..write('albumColorSync: $albumColorSync, ') ..write('amoledDarkTheme: $amoledDarkTheme, ') ..write('checkUpdate: $checkUpdate, ') @@ -1937,13 +1708,9 @@ class PreferencesTableCompanion extends UpdateCompanion { ..write('searchMode: $searchMode, ') ..write('downloadLocation: $downloadLocation, ') ..write('localLibraryLocation: $localLibraryLocation, ') - ..write('pipedInstance: $pipedInstance, ') - ..write('invidiousInstance: $invidiousInstance, ') ..write('themeMode: $themeMode, ') - ..write('audioSource: $audioSource, ') + ..write('audioSourceId: $audioSourceId, ') ..write('youtubeClientEngine: $youtubeClientEngine, ') - ..write('streamMusicCodec: $streamMusicCodec, ') - ..write('downloadMusicCodec: $downloadMusicCodec, ') ..write('discordPresence: $discordPresence, ') ..write('endlessPlayback: $endlessPlayback, ') ..write('enableConnect: $enableConnect, ') @@ -2539,20 +2306,20 @@ class $SourceMatchTableTable extends SourceMatchTable late final GeneratedColumn trackId = GeneratedColumn( 'track_id', aliasedName, false, type: DriftSqlType.string, requiredDuringInsert: true); - static const VerificationMeta _sourceIdMeta = - const VerificationMeta('sourceId'); + static const VerificationMeta _sourceInfoMeta = + const VerificationMeta('sourceInfo'); @override - late final GeneratedColumn sourceId = GeneratedColumn( - 'source_id', aliasedName, false, + late final GeneratedColumn sourceInfo = GeneratedColumn( + 'source_info', aliasedName, false, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultValue: const Constant("{}")); + static const VerificationMeta _sourceTypeMeta = + const VerificationMeta('sourceType'); + @override + late final GeneratedColumn sourceType = GeneratedColumn( + 'source_type', aliasedName, false, type: DriftSqlType.string, requiredDuringInsert: true); - @override - late final GeneratedColumnWithTypeConverter sourceType = - GeneratedColumn('source_type', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: Constant(SourceType.youtube.name)) - .withConverter( - $SourceMatchTableTable.$convertersourceType); static const VerificationMeta _createdAtMeta = const VerificationMeta('createdAt'); @override @@ -2563,7 +2330,7 @@ class $SourceMatchTableTable extends SourceMatchTable defaultValue: currentDateAndTime); @override List get $columns => - [id, trackId, sourceId, sourceType, createdAt]; + [id, trackId, sourceInfo, sourceType, createdAt]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -2584,11 +2351,19 @@ class $SourceMatchTableTable extends SourceMatchTable } else if (isInserting) { context.missing(_trackIdMeta); } - if (data.containsKey('source_id')) { - context.handle(_sourceIdMeta, - sourceId.isAcceptableOrUnknown(data['source_id']!, _sourceIdMeta)); + if (data.containsKey('source_info')) { + context.handle( + _sourceInfoMeta, + sourceInfo.isAcceptableOrUnknown( + data['source_info']!, _sourceInfoMeta)); + } + if (data.containsKey('source_type')) { + context.handle( + _sourceTypeMeta, + sourceType.isAcceptableOrUnknown( + data['source_type']!, _sourceTypeMeta)); } else if (isInserting) { - context.missing(_sourceIdMeta); + context.missing(_sourceTypeMeta); } if (data.containsKey('created_at')) { context.handle(_createdAtMeta, @@ -2607,11 +2382,10 @@ class $SourceMatchTableTable extends SourceMatchTable .read(DriftSqlType.int, data['${effectivePrefix}id'])!, trackId: attachedDatabase.typeMapping .read(DriftSqlType.string, data['${effectivePrefix}track_id'])!, - sourceId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}source_id'])!, - sourceType: $SourceMatchTableTable.$convertersourceType.fromSql( - attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}source_type'])!), + sourceInfo: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}source_info'])!, + sourceType: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}source_type'])!, createdAt: attachedDatabase.typeMapping .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, ); @@ -2621,22 +2395,19 @@ class $SourceMatchTableTable extends SourceMatchTable $SourceMatchTableTable createAlias(String alias) { return $SourceMatchTableTable(attachedDatabase, alias); } - - static JsonTypeConverter2 $convertersourceType = - const EnumNameConverter(SourceType.values); } class SourceMatchTableData extends DataClass implements Insertable { final int id; final String trackId; - final String sourceId; - final SourceType sourceType; + final String sourceInfo; + final String sourceType; final DateTime createdAt; const SourceMatchTableData( {required this.id, required this.trackId, - required this.sourceId, + required this.sourceInfo, required this.sourceType, required this.createdAt}); @override @@ -2644,11 +2415,8 @@ class SourceMatchTableData extends DataClass final map = {}; map['id'] = Variable(id); map['track_id'] = Variable(trackId); - map['source_id'] = Variable(sourceId); - { - map['source_type'] = Variable( - $SourceMatchTableTable.$convertersourceType.toSql(sourceType)); - } + map['source_info'] = Variable(sourceInfo); + map['source_type'] = Variable(sourceType); map['created_at'] = Variable(createdAt); return map; } @@ -2657,7 +2425,7 @@ class SourceMatchTableData extends DataClass return SourceMatchTableCompanion( id: Value(id), trackId: Value(trackId), - sourceId: Value(sourceId), + sourceInfo: Value(sourceInfo), sourceType: Value(sourceType), createdAt: Value(createdAt), ); @@ -2669,9 +2437,8 @@ class SourceMatchTableData extends DataClass return SourceMatchTableData( id: serializer.fromJson(json['id']), trackId: serializer.fromJson(json['trackId']), - sourceId: serializer.fromJson(json['sourceId']), - sourceType: $SourceMatchTableTable.$convertersourceType - .fromJson(serializer.fromJson(json['sourceType'])), + sourceInfo: serializer.fromJson(json['sourceInfo']), + sourceType: serializer.fromJson(json['sourceType']), createdAt: serializer.fromJson(json['createdAt']), ); } @@ -2681,9 +2448,8 @@ class SourceMatchTableData extends DataClass return { 'id': serializer.toJson(id), 'trackId': serializer.toJson(trackId), - 'sourceId': serializer.toJson(sourceId), - 'sourceType': serializer.toJson( - $SourceMatchTableTable.$convertersourceType.toJson(sourceType)), + 'sourceInfo': serializer.toJson(sourceInfo), + 'sourceType': serializer.toJson(sourceType), 'createdAt': serializer.toJson(createdAt), }; } @@ -2691,13 +2457,13 @@ class SourceMatchTableData extends DataClass SourceMatchTableData copyWith( {int? id, String? trackId, - String? sourceId, - SourceType? sourceType, + String? sourceInfo, + String? sourceType, DateTime? createdAt}) => SourceMatchTableData( id: id ?? this.id, trackId: trackId ?? this.trackId, - sourceId: sourceId ?? this.sourceId, + sourceInfo: sourceInfo ?? this.sourceInfo, sourceType: sourceType ?? this.sourceType, createdAt: createdAt ?? this.createdAt, ); @@ -2705,7 +2471,8 @@ class SourceMatchTableData extends DataClass return SourceMatchTableData( id: data.id.present ? data.id.value : this.id, trackId: data.trackId.present ? data.trackId.value : this.trackId, - sourceId: data.sourceId.present ? data.sourceId.value : this.sourceId, + sourceInfo: + data.sourceInfo.present ? data.sourceInfo.value : this.sourceInfo, sourceType: data.sourceType.present ? data.sourceType.value : this.sourceType, createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, @@ -2717,7 +2484,7 @@ class SourceMatchTableData extends DataClass return (StringBuffer('SourceMatchTableData(') ..write('id: $id, ') ..write('trackId: $trackId, ') - ..write('sourceId: $sourceId, ') + ..write('sourceInfo: $sourceInfo, ') ..write('sourceType: $sourceType, ') ..write('createdAt: $createdAt') ..write(')')) @@ -2725,14 +2492,15 @@ class SourceMatchTableData extends DataClass } @override - int get hashCode => Object.hash(id, trackId, sourceId, sourceType, createdAt); + int get hashCode => + Object.hash(id, trackId, sourceInfo, sourceType, createdAt); @override bool operator ==(Object other) => identical(this, other) || (other is SourceMatchTableData && other.id == this.id && other.trackId == this.trackId && - other.sourceId == this.sourceId && + other.sourceInfo == this.sourceInfo && other.sourceType == this.sourceType && other.createdAt == this.createdAt); } @@ -2740,35 +2508,35 @@ class SourceMatchTableData extends DataClass class SourceMatchTableCompanion extends UpdateCompanion { final Value id; final Value trackId; - final Value sourceId; - final Value sourceType; + final Value sourceInfo; + final Value sourceType; final Value createdAt; const SourceMatchTableCompanion({ this.id = const Value.absent(), this.trackId = const Value.absent(), - this.sourceId = const Value.absent(), + this.sourceInfo = const Value.absent(), this.sourceType = const Value.absent(), this.createdAt = const Value.absent(), }); SourceMatchTableCompanion.insert({ this.id = const Value.absent(), required String trackId, - required String sourceId, - this.sourceType = const Value.absent(), + this.sourceInfo = const Value.absent(), + required String sourceType, this.createdAt = const Value.absent(), }) : trackId = Value(trackId), - sourceId = Value(sourceId); + sourceType = Value(sourceType); static Insertable custom({ Expression? id, Expression? trackId, - Expression? sourceId, + Expression? sourceInfo, Expression? sourceType, Expression? createdAt, }) { return RawValuesInsertable({ if (id != null) 'id': id, if (trackId != null) 'track_id': trackId, - if (sourceId != null) 'source_id': sourceId, + if (sourceInfo != null) 'source_info': sourceInfo, if (sourceType != null) 'source_type': sourceType, if (createdAt != null) 'created_at': createdAt, }); @@ -2777,13 +2545,13 @@ class SourceMatchTableCompanion extends UpdateCompanion { SourceMatchTableCompanion copyWith( {Value? id, Value? trackId, - Value? sourceId, - Value? sourceType, + Value? sourceInfo, + Value? sourceType, Value? createdAt}) { return SourceMatchTableCompanion( id: id ?? this.id, trackId: trackId ?? this.trackId, - sourceId: sourceId ?? this.sourceId, + sourceInfo: sourceInfo ?? this.sourceInfo, sourceType: sourceType ?? this.sourceType, createdAt: createdAt ?? this.createdAt, ); @@ -2798,12 +2566,11 @@ class SourceMatchTableCompanion extends UpdateCompanion { if (trackId.present) { map['track_id'] = Variable(trackId.value); } - if (sourceId.present) { - map['source_id'] = Variable(sourceId.value); + if (sourceInfo.present) { + map['source_info'] = Variable(sourceInfo.value); } if (sourceType.present) { - map['source_type'] = Variable( - $SourceMatchTableTable.$convertersourceType.toSql(sourceType.value)); + map['source_type'] = Variable(sourceType.value); } if (createdAt.present) { map['created_at'] = Variable(createdAt.value); @@ -2816,7 +2583,7 @@ class SourceMatchTableCompanion extends UpdateCompanion { return (StringBuffer('SourceMatchTableCompanion(') ..write('id: $id, ') ..write('trackId: $trackId, ') - ..write('sourceId: $sourceId, ') + ..write('sourceInfo: $sourceInfo, ') ..write('sourceType: $sourceType, ') ..write('createdAt: $createdAt') ..write(')')) @@ -4377,7 +4144,7 @@ abstract class _$AppDatabase extends GeneratedDatabase { 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_id, source_type)'); + 'CREATE UNIQUE INDEX uniq_track_match ON source_match_table (track_id, source_info, source_type)'); @override Iterable> get allTables => allSchemaEntities.whereType>(); @@ -4719,7 +4486,6 @@ typedef $$BlacklistTableTableProcessedTableManager = ProcessedTableManager< typedef $$PreferencesTableTableCreateCompanionBuilder = PreferencesTableCompanion Function({ Value id, - Value audioQuality, Value albumColorSync, Value amoledDarkTheme, Value checkUpdate, @@ -4735,13 +4501,9 @@ typedef $$PreferencesTableTableCreateCompanionBuilder Value searchMode, Value downloadLocation, Value> localLibraryLocation, - Value pipedInstance, - Value invidiousInstance, Value themeMode, - Value audioSource, + Value audioSourceId, Value youtubeClientEngine, - Value streamMusicCodec, - Value downloadMusicCodec, Value discordPresence, Value endlessPlayback, Value enableConnect, @@ -4751,7 +4513,6 @@ typedef $$PreferencesTableTableCreateCompanionBuilder typedef $$PreferencesTableTableUpdateCompanionBuilder = PreferencesTableCompanion Function({ Value id, - Value audioQuality, Value albumColorSync, Value amoledDarkTheme, Value checkUpdate, @@ -4767,13 +4528,9 @@ typedef $$PreferencesTableTableUpdateCompanionBuilder Value searchMode, Value downloadLocation, Value> localLibraryLocation, - Value pipedInstance, - Value invidiousInstance, Value themeMode, - Value audioSource, + Value audioSourceId, Value youtubeClientEngine, - Value streamMusicCodec, - Value downloadMusicCodec, Value discordPresence, Value endlessPlayback, Value enableConnect, @@ -4793,11 +4550,6 @@ class $$PreferencesTableTableFilterComposer ColumnFilters get id => $composableBuilder( column: $table.id, builder: (column) => ColumnFilters(column)); - ColumnWithTypeConverterFilters - get audioQuality => $composableBuilder( - column: $table.audioQuality, - builder: (column) => ColumnWithTypeConverterFilters(column)); - ColumnFilters get albumColorSync => $composableBuilder( column: $table.albumColorSync, builder: (column) => ColumnFilters(column)); @@ -4863,22 +4615,13 @@ class $$PreferencesTableTableFilterComposer column: $table.localLibraryLocation, builder: (column) => ColumnWithTypeConverterFilters(column)); - ColumnFilters get pipedInstance => $composableBuilder( - column: $table.pipedInstance, builder: (column) => ColumnFilters(column)); - - ColumnFilters get invidiousInstance => $composableBuilder( - column: $table.invidiousInstance, - builder: (column) => ColumnFilters(column)); - ColumnWithTypeConverterFilters get themeMode => $composableBuilder( column: $table.themeMode, builder: (column) => ColumnWithTypeConverterFilters(column)); - ColumnWithTypeConverterFilters - get audioSource => $composableBuilder( - column: $table.audioSource, - builder: (column) => ColumnWithTypeConverterFilters(column)); + ColumnFilters get audioSourceId => $composableBuilder( + column: $table.audioSourceId, builder: (column) => ColumnFilters(column)); ColumnWithTypeConverterFilters @@ -4886,16 +4629,6 @@ class $$PreferencesTableTableFilterComposer column: $table.youtubeClientEngine, builder: (column) => ColumnWithTypeConverterFilters(column)); - ColumnWithTypeConverterFilters - get streamMusicCodec => $composableBuilder( - column: $table.streamMusicCodec, - builder: (column) => ColumnWithTypeConverterFilters(column)); - - ColumnWithTypeConverterFilters - get downloadMusicCodec => $composableBuilder( - column: $table.downloadMusicCodec, - builder: (column) => ColumnWithTypeConverterFilters(column)); - ColumnFilters get discordPresence => $composableBuilder( column: $table.discordPresence, builder: (column) => ColumnFilters(column)); @@ -4926,10 +4659,6 @@ class $$PreferencesTableTableOrderingComposer ColumnOrderings get id => $composableBuilder( column: $table.id, builder: (column) => ColumnOrderings(column)); - ColumnOrderings get audioQuality => $composableBuilder( - column: $table.audioQuality, - builder: (column) => ColumnOrderings(column)); - ColumnOrderings get albumColorSync => $composableBuilder( column: $table.albumColorSync, builder: (column) => ColumnOrderings(column)); @@ -4985,32 +4714,17 @@ class $$PreferencesTableTableOrderingComposer column: $table.localLibraryLocation, builder: (column) => ColumnOrderings(column)); - ColumnOrderings get pipedInstance => $composableBuilder( - column: $table.pipedInstance, - builder: (column) => ColumnOrderings(column)); - - ColumnOrderings get invidiousInstance => $composableBuilder( - column: $table.invidiousInstance, - builder: (column) => ColumnOrderings(column)); - ColumnOrderings get themeMode => $composableBuilder( column: $table.themeMode, builder: (column) => ColumnOrderings(column)); - ColumnOrderings get audioSource => $composableBuilder( - column: $table.audioSource, builder: (column) => ColumnOrderings(column)); + ColumnOrderings get audioSourceId => $composableBuilder( + column: $table.audioSourceId, + builder: (column) => ColumnOrderings(column)); ColumnOrderings get youtubeClientEngine => $composableBuilder( column: $table.youtubeClientEngine, builder: (column) => ColumnOrderings(column)); - ColumnOrderings get streamMusicCodec => $composableBuilder( - column: $table.streamMusicCodec, - builder: (column) => ColumnOrderings(column)); - - ColumnOrderings get downloadMusicCodec => $composableBuilder( - column: $table.downloadMusicCodec, - builder: (column) => ColumnOrderings(column)); - ColumnOrderings get discordPresence => $composableBuilder( column: $table.discordPresence, builder: (column) => ColumnOrderings(column)); @@ -5042,10 +4756,6 @@ class $$PreferencesTableTableAnnotationComposer GeneratedColumn get id => $composableBuilder(column: $table.id, builder: (column) => column); - GeneratedColumnWithTypeConverter get audioQuality => - $composableBuilder( - column: $table.audioQuality, builder: (column) => column); - GeneratedColumn get albumColorSync => $composableBuilder( column: $table.albumColorSync, builder: (column) => column); @@ -5096,31 +4806,16 @@ class $$PreferencesTableTableAnnotationComposer get localLibraryLocation => $composableBuilder( column: $table.localLibraryLocation, builder: (column) => column); - GeneratedColumn get pipedInstance => $composableBuilder( - column: $table.pipedInstance, builder: (column) => column); - - GeneratedColumn get invidiousInstance => $composableBuilder( - column: $table.invidiousInstance, builder: (column) => column); - GeneratedColumnWithTypeConverter get themeMode => $composableBuilder(column: $table.themeMode, builder: (column) => column); - GeneratedColumnWithTypeConverter get audioSource => - $composableBuilder( - column: $table.audioSource, builder: (column) => column); + GeneratedColumn get audioSourceId => $composableBuilder( + column: $table.audioSourceId, builder: (column) => column); GeneratedColumnWithTypeConverter get youtubeClientEngine => $composableBuilder( column: $table.youtubeClientEngine, builder: (column) => column); - GeneratedColumnWithTypeConverter get streamMusicCodec => - $composableBuilder( - column: $table.streamMusicCodec, builder: (column) => column); - - GeneratedColumnWithTypeConverter - get downloadMusicCodec => $composableBuilder( - column: $table.downloadMusicCodec, builder: (column) => column); - GeneratedColumn get discordPresence => $composableBuilder( column: $table.discordPresence, builder: (column) => column); @@ -5166,7 +4861,6 @@ class $$PreferencesTableTableTableManager extends RootTableManager< $$PreferencesTableTableAnnotationComposer($db: db, $table: table), updateCompanionCallback: ({ Value id = const Value.absent(), - Value audioQuality = const Value.absent(), Value albumColorSync = const Value.absent(), Value amoledDarkTheme = const Value.absent(), Value checkUpdate = const Value.absent(), @@ -5182,14 +4876,10 @@ class $$PreferencesTableTableTableManager extends RootTableManager< Value searchMode = const Value.absent(), Value downloadLocation = const Value.absent(), Value> localLibraryLocation = const Value.absent(), - Value pipedInstance = const Value.absent(), - Value invidiousInstance = const Value.absent(), Value themeMode = const Value.absent(), - Value audioSource = const Value.absent(), + Value audioSourceId = const Value.absent(), Value youtubeClientEngine = const Value.absent(), - Value streamMusicCodec = const Value.absent(), - Value downloadMusicCodec = const Value.absent(), Value discordPresence = const Value.absent(), Value endlessPlayback = const Value.absent(), Value enableConnect = const Value.absent(), @@ -5198,7 +4888,6 @@ class $$PreferencesTableTableTableManager extends RootTableManager< }) => PreferencesTableCompanion( id: id, - audioQuality: audioQuality, albumColorSync: albumColorSync, amoledDarkTheme: amoledDarkTheme, checkUpdate: checkUpdate, @@ -5214,13 +4903,9 @@ class $$PreferencesTableTableTableManager extends RootTableManager< searchMode: searchMode, downloadLocation: downloadLocation, localLibraryLocation: localLibraryLocation, - pipedInstance: pipedInstance, - invidiousInstance: invidiousInstance, themeMode: themeMode, - audioSource: audioSource, + audioSourceId: audioSourceId, youtubeClientEngine: youtubeClientEngine, - streamMusicCodec: streamMusicCodec, - downloadMusicCodec: downloadMusicCodec, discordPresence: discordPresence, endlessPlayback: endlessPlayback, enableConnect: enableConnect, @@ -5229,7 +4914,6 @@ class $$PreferencesTableTableTableManager extends RootTableManager< ), createCompanionCallback: ({ Value id = const Value.absent(), - Value audioQuality = const Value.absent(), Value albumColorSync = const Value.absent(), Value amoledDarkTheme = const Value.absent(), Value checkUpdate = const Value.absent(), @@ -5245,14 +4929,10 @@ class $$PreferencesTableTableTableManager extends RootTableManager< Value searchMode = const Value.absent(), Value downloadLocation = const Value.absent(), Value> localLibraryLocation = const Value.absent(), - Value pipedInstance = const Value.absent(), - Value invidiousInstance = const Value.absent(), Value themeMode = const Value.absent(), - Value audioSource = const Value.absent(), + Value audioSourceId = const Value.absent(), Value youtubeClientEngine = const Value.absent(), - Value streamMusicCodec = const Value.absent(), - Value downloadMusicCodec = const Value.absent(), Value discordPresence = const Value.absent(), Value endlessPlayback = const Value.absent(), Value enableConnect = const Value.absent(), @@ -5261,7 +4941,6 @@ class $$PreferencesTableTableTableManager extends RootTableManager< }) => PreferencesTableCompanion.insert( id: id, - audioQuality: audioQuality, albumColorSync: albumColorSync, amoledDarkTheme: amoledDarkTheme, checkUpdate: checkUpdate, @@ -5277,13 +4956,9 @@ class $$PreferencesTableTableTableManager extends RootTableManager< searchMode: searchMode, downloadLocation: downloadLocation, localLibraryLocation: localLibraryLocation, - pipedInstance: pipedInstance, - invidiousInstance: invidiousInstance, themeMode: themeMode, - audioSource: audioSource, + audioSourceId: audioSourceId, youtubeClientEngine: youtubeClientEngine, - streamMusicCodec: streamMusicCodec, - downloadMusicCodec: downloadMusicCodec, discordPresence: discordPresence, endlessPlayback: endlessPlayback, enableConnect: enableConnect, @@ -5644,16 +5319,16 @@ typedef $$SourceMatchTableTableCreateCompanionBuilder = SourceMatchTableCompanion Function({ Value id, required String trackId, - required String sourceId, - Value sourceType, + Value sourceInfo, + required String sourceType, Value createdAt, }); typedef $$SourceMatchTableTableUpdateCompanionBuilder = SourceMatchTableCompanion Function({ Value id, Value trackId, - Value sourceId, - Value sourceType, + Value sourceInfo, + Value sourceType, Value createdAt, }); @@ -5672,13 +5347,11 @@ class $$SourceMatchTableTableFilterComposer ColumnFilters get trackId => $composableBuilder( column: $table.trackId, builder: (column) => ColumnFilters(column)); - ColumnFilters get sourceId => $composableBuilder( - column: $table.sourceId, builder: (column) => ColumnFilters(column)); + ColumnFilters get sourceInfo => $composableBuilder( + column: $table.sourceInfo, builder: (column) => ColumnFilters(column)); - ColumnWithTypeConverterFilters - get sourceType => $composableBuilder( - column: $table.sourceType, - builder: (column) => ColumnWithTypeConverterFilters(column)); + ColumnFilters get sourceType => $composableBuilder( + column: $table.sourceType, builder: (column) => ColumnFilters(column)); ColumnFilters get createdAt => $composableBuilder( column: $table.createdAt, builder: (column) => ColumnFilters(column)); @@ -5699,8 +5372,8 @@ class $$SourceMatchTableTableOrderingComposer ColumnOrderings get trackId => $composableBuilder( column: $table.trackId, builder: (column) => ColumnOrderings(column)); - ColumnOrderings get sourceId => $composableBuilder( - column: $table.sourceId, builder: (column) => ColumnOrderings(column)); + ColumnOrderings get sourceInfo => $composableBuilder( + column: $table.sourceInfo, builder: (column) => ColumnOrderings(column)); ColumnOrderings get sourceType => $composableBuilder( column: $table.sourceType, builder: (column) => ColumnOrderings(column)); @@ -5724,12 +5397,11 @@ class $$SourceMatchTableTableAnnotationComposer GeneratedColumn get trackId => $composableBuilder(column: $table.trackId, builder: (column) => column); - GeneratedColumn get sourceId => - $composableBuilder(column: $table.sourceId, builder: (column) => column); + GeneratedColumn get sourceInfo => $composableBuilder( + column: $table.sourceInfo, builder: (column) => column); - GeneratedColumnWithTypeConverter get sourceType => - $composableBuilder( - column: $table.sourceType, builder: (column) => column); + GeneratedColumn get sourceType => $composableBuilder( + column: $table.sourceType, builder: (column) => column); GeneratedColumn get createdAt => $composableBuilder(column: $table.createdAt, builder: (column) => column); @@ -5765,28 +5437,28 @@ class $$SourceMatchTableTableTableManager extends RootTableManager< updateCompanionCallback: ({ Value id = const Value.absent(), Value trackId = const Value.absent(), - Value sourceId = const Value.absent(), - Value sourceType = const Value.absent(), + Value sourceInfo = const Value.absent(), + Value sourceType = const Value.absent(), Value createdAt = const Value.absent(), }) => SourceMatchTableCompanion( id: id, trackId: trackId, - sourceId: sourceId, + sourceInfo: sourceInfo, sourceType: sourceType, createdAt: createdAt, ), createCompanionCallback: ({ Value id = const Value.absent(), required String trackId, - required String sourceId, - Value sourceType = const Value.absent(), + Value sourceInfo = const Value.absent(), + required String sourceType, Value createdAt = const Value.absent(), }) => SourceMatchTableCompanion.insert( id: id, trackId: trackId, - sourceId: sourceId, + sourceInfo: sourceInfo, sourceType: sourceType, createdAt: createdAt, ), diff --git a/lib/models/database/database.steps.dart b/lib/models/database/database.steps.dart index babe71b9..42cbdf6d 100644 --- a/lib/models/database/database.steps.dart +++ b/lib/models/database/database.steps.dart @@ -5,7 +5,6 @@ import 'package:drift/drift.dart'; // ignore_for_file: type=lint,unused_import import 'package:flutter/material.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/models/metadata/market.dart'; -import 'package:spotube/services/sourced_track/enums.dart'; // GENERATED BY drift_dev, DO NOT MODIFY. final class Schema2 extends i0.VersionedSchema { @@ -330,8 +329,7 @@ class Shape2 extends i0.VersionedTable { i1.GeneratedColumn _column_7(String aliasedName) => i1.GeneratedColumn('audio_quality', aliasedName, false, - type: i1.DriftSqlType.string, - defaultValue: Constant(SourceQualities.high.name)); + type: i1.DriftSqlType.string, defaultValue: Constant("high")); i1.GeneratedColumn _column_8(String aliasedName) => i1.GeneratedColumn('album_color_sync', aliasedName, false, type: i1.DriftSqlType.bool, @@ -418,16 +416,13 @@ i1.GeneratedColumn _column_25(String aliasedName) => defaultValue: Constant(ThemeMode.system.name)); i1.GeneratedColumn _column_26(String aliasedName) => i1.GeneratedColumn('audio_source', aliasedName, false, - type: i1.DriftSqlType.string, - defaultValue: Constant(AudioSource.youtube.name)); + type: i1.DriftSqlType.string, defaultValue: Constant("youtube")); i1.GeneratedColumn _column_27(String aliasedName) => i1.GeneratedColumn('stream_music_codec', aliasedName, false, - type: i1.DriftSqlType.string, - defaultValue: Constant(SourceCodecs.weba.name)); + type: i1.DriftSqlType.string, defaultValue: Constant("weba")); i1.GeneratedColumn _column_28(String aliasedName) => i1.GeneratedColumn('download_music_codec', aliasedName, false, - type: i1.DriftSqlType.string, - defaultValue: Constant(SourceCodecs.m4a.name)); + type: i1.DriftSqlType.string, defaultValue: Constant("m4a")); i1.GeneratedColumn _column_29(String aliasedName) => i1.GeneratedColumn('discord_presence', aliasedName, false, type: i1.DriftSqlType.bool, @@ -512,8 +507,7 @@ i1.GeneratedColumn _column_38(String aliasedName) => type: i1.DriftSqlType.string); i1.GeneratedColumn _column_39(String aliasedName) => i1.GeneratedColumn('source_type', aliasedName, false, - type: i1.DriftSqlType.string, - defaultValue: Constant(SourceType.youtube.name)); + type: i1.DriftSqlType.string, defaultValue: Constant("youtube")); class Shape6 extends i0.VersionedTable { Shape6({required super.source, required super.alias}) : super.aliased(); @@ -2462,6 +2456,289 @@ i1.GeneratedColumn _column_72(String aliasedName) => i1.GeneratedColumn _column_73(String aliasedName) => i1.GeneratedColumn('plugin_api_version', aliasedName, false, type: i1.DriftSqlType.string, defaultValue: const Constant('2.0.0')); + +final class Schema10 extends i0.VersionedSchema { + Schema10({required super.database}) : super(version: 10); + @override + late final List entities = [ + authenticationTable, + blacklistTable, + preferencesTable, + scrobblerTable, + skipSegmentTable, + sourceMatchTable, + audioPlayerStateTable, + historyTable, + lyricsTable, + pluginsTable, + uniqueBlacklist, + uniqTrackMatch, + ]; + late final Shape0 authenticationTable = Shape0( + source: i0.VersionedTable( + entityName: 'authentication_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_1, + _column_2, + _column_3, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape1 blacklistTable = Shape1( + source: i0.VersionedTable( + entityName: 'blacklist_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_4, + _column_5, + _column_6, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape17 preferencesTable = Shape17( + source: i0.VersionedTable( + entityName: 'preferences_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_8, + _column_9, + _column_10, + _column_11, + _column_12, + _column_13, + _column_14, + _column_15, + _column_69, + _column_17, + _column_18, + _column_19, + _column_20, + _column_21, + _column_22, + _column_25, + _column_74, + _column_54, + _column_29, + _column_30, + _column_31, + _column_56, + _column_53, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape3 scrobblerTable = Shape3( + source: i0.VersionedTable( + entityName: 'scrobbler_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_32, + _column_33, + _column_34, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape4 skipSegmentTable = Shape4( + source: i0.VersionedTable( + entityName: 'skip_segment_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_35, + _column_36, + _column_37, + _column_32, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape18 sourceMatchTable = Shape18( + source: i0.VersionedTable( + entityName: 'source_match_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_37, + _column_75, + _column_76, + _column_32, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape14 audioPlayerStateTable = Shape14( + source: i0.VersionedTable( + entityName: 'audio_player_state_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_40, + _column_41, + _column_42, + _column_43, + _column_57, + _column_58, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape9 historyTable = Shape9( + source: i0.VersionedTable( + entityName: 'history_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_32, + _column_50, + _column_51, + _column_52, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape10 lyricsTable = Shape10( + source: i0.VersionedTable( + entityName: 'lyrics_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_37, + _column_52, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape16 pluginsTable = Shape16( + source: i0.VersionedTable( + entityName: 'plugins_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_59, + _column_60, + _column_61, + _column_62, + _column_63, + _column_64, + _column_65, + _column_71, + _column_72, + _column_67, + _column_73, + ], + attachedDatabase: database, + ), + alias: null); + final i1.Index uniqueBlacklist = i1.Index('unique_blacklist', + 'CREATE UNIQUE INDEX unique_blacklist ON blacklist_table (element_type, element_id)'); + final i1.Index uniqTrackMatch = i1.Index('uniq_track_match', + 'CREATE UNIQUE INDEX uniq_track_match ON source_match_table (track_id, source_info, source_type)'); +} + +class Shape17 extends i0.VersionedTable { + Shape17({required super.source, required super.alias}) : super.aliased(); + i1.GeneratedColumn get id => + columnsByName['id']! as i1.GeneratedColumn; + i1.GeneratedColumn get albumColorSync => + columnsByName['album_color_sync']! as i1.GeneratedColumn; + i1.GeneratedColumn get amoledDarkTheme => + columnsByName['amoled_dark_theme']! as i1.GeneratedColumn; + i1.GeneratedColumn get checkUpdate => + columnsByName['check_update']! as i1.GeneratedColumn; + i1.GeneratedColumn get normalizeAudio => + columnsByName['normalize_audio']! as i1.GeneratedColumn; + i1.GeneratedColumn get showSystemTrayIcon => + columnsByName['show_system_tray_icon']! as i1.GeneratedColumn; + i1.GeneratedColumn get systemTitleBar => + columnsByName['system_title_bar']! as i1.GeneratedColumn; + i1.GeneratedColumn get skipNonMusic => + columnsByName['skip_non_music']! as i1.GeneratedColumn; + i1.GeneratedColumn get closeBehavior => + columnsByName['close_behavior']! as i1.GeneratedColumn; + i1.GeneratedColumn get accentColorScheme => + columnsByName['accent_color_scheme']! as i1.GeneratedColumn; + i1.GeneratedColumn get layoutMode => + columnsByName['layout_mode']! as i1.GeneratedColumn; + i1.GeneratedColumn get locale => + columnsByName['locale']! as i1.GeneratedColumn; + i1.GeneratedColumn get market => + columnsByName['market']! as i1.GeneratedColumn; + i1.GeneratedColumn get searchMode => + columnsByName['search_mode']! as i1.GeneratedColumn; + i1.GeneratedColumn get downloadLocation => + columnsByName['download_location']! as i1.GeneratedColumn; + i1.GeneratedColumn get localLibraryLocation => + columnsByName['local_library_location']! as i1.GeneratedColumn; + i1.GeneratedColumn get themeMode => + columnsByName['theme_mode']! as i1.GeneratedColumn; + i1.GeneratedColumn get audioSourceId => + columnsByName['audio_source_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get youtubeClientEngine => + columnsByName['youtube_client_engine']! as i1.GeneratedColumn; + i1.GeneratedColumn get discordPresence => + columnsByName['discord_presence']! as i1.GeneratedColumn; + i1.GeneratedColumn get endlessPlayback => + columnsByName['endless_playback']! as i1.GeneratedColumn; + i1.GeneratedColumn get enableConnect => + columnsByName['enable_connect']! as i1.GeneratedColumn; + i1.GeneratedColumn get connectPort => + columnsByName['connect_port']! as i1.GeneratedColumn; + i1.GeneratedColumn get cacheMusic => + columnsByName['cache_music']! as i1.GeneratedColumn; +} + +i1.GeneratedColumn _column_74(String aliasedName) => + i1.GeneratedColumn('audio_source_id', aliasedName, true, + type: i1.DriftSqlType.string); + +class Shape18 extends i0.VersionedTable { + Shape18({required super.source, required super.alias}) : super.aliased(); + i1.GeneratedColumn get id => + columnsByName['id']! as i1.GeneratedColumn; + i1.GeneratedColumn get trackId => + columnsByName['track_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get sourceInfo => + columnsByName['source_info']! as i1.GeneratedColumn; + i1.GeneratedColumn get sourceType => + columnsByName['source_type']! as i1.GeneratedColumn; + i1.GeneratedColumn get createdAt => + columnsByName['created_at']! as i1.GeneratedColumn; +} + +i1.GeneratedColumn _column_75(String aliasedName) => + i1.GeneratedColumn('source_info', aliasedName, false, + type: i1.DriftSqlType.string, defaultValue: const Constant("{}")); +i1.GeneratedColumn _column_76(String aliasedName) => + i1.GeneratedColumn('source_type', aliasedName, false, + type: i1.DriftSqlType.string); i0.MigrationStepWithVersion migrationSteps({ required Future Function(i1.Migrator m, Schema2 schema) from1To2, required Future Function(i1.Migrator m, Schema3 schema) from2To3, @@ -2471,6 +2748,7 @@ i0.MigrationStepWithVersion migrationSteps({ required Future Function(i1.Migrator m, Schema7 schema) from6To7, required Future Function(i1.Migrator m, Schema8 schema) from7To8, required Future Function(i1.Migrator m, Schema9 schema) from8To9, + required Future Function(i1.Migrator m, Schema10 schema) from9To10, }) { return (currentVersion, database) async { switch (currentVersion) { @@ -2514,6 +2792,11 @@ i0.MigrationStepWithVersion migrationSteps({ final migrator = i1.Migrator(database, schema); await from8To9(migrator, schema); return 9; + case 9: + final schema = Schema10(database: database); + final migrator = i1.Migrator(database, schema); + await from9To10(migrator, schema); + return 10; default: throw ArgumentError.value('Unknown migration from $currentVersion'); } @@ -2529,6 +2812,7 @@ i1.OnUpgrade stepByStep({ required Future Function(i1.Migrator m, Schema7 schema) from6To7, required Future Function(i1.Migrator m, Schema8 schema) from7To8, required Future Function(i1.Migrator m, Schema9 schema) from8To9, + required Future Function(i1.Migrator m, Schema10 schema) from9To10, }) => i0.VersionedSchema.stepByStepHelper( step: migrationSteps( @@ -2540,4 +2824,5 @@ i1.OnUpgrade stepByStep({ from6To7: from6To7, from7To8: from7To8, from8To9: from8To9, + from9To10: from9To10, )); diff --git a/lib/models/database/tables/preferences.dart b/lib/models/database/tables/preferences.dart index ea2f7538..cc810ae7 100644 --- a/lib/models/database/tables/preferences.dart +++ b/lib/models/database/tables/preferences.dart @@ -76,10 +76,6 @@ class PreferencesTable extends Table { TextColumn get downloadLocation => text().withDefault(const Constant(""))(); TextColumn get localLibraryLocation => text().withDefault(const Constant("")).map(const StringListConverter())(); - TextColumn get pipedInstance => - text().withDefault(const Constant("https://pipedapi.kavin.rocks"))(); - TextColumn get invidiousInstance => - text().withDefault(const Constant("https://inv.nadeko.net"))(); TextColumn get themeMode => textEnum().withDefault(Constant(ThemeMode.system.name))(); TextColumn get audioSourceId => text().nullable()(); @@ -113,8 +109,6 @@ class PreferencesTable extends Table { searchMode: SearchMode.youtube, downloadLocation: "", localLibraryLocation: [], - pipedInstance: "https://pipedapi.kavin.rocks", - invidiousInstance: "https://inv.nadeko.net", themeMode: ThemeMode.system, audioSourceId: null, youtubeClientEngine: YoutubeClientEngine.youtubeExplode, diff --git a/lib/models/database/tables/source_match.dart b/lib/models/database/tables/source_match.dart index b5661137..9ef79e9b 100644 --- a/lib/models/database/tables/source_match.dart +++ b/lib/models/database/tables/source_match.dart @@ -8,7 +8,7 @@ part of '../database.dart'; class SourceMatchTable extends Table { IntColumn get id => integer().autoIncrement()(); TextColumn get trackId => text()(); - TextColumn get sourceInfo => text()(); + TextColumn get sourceInfo => text().withDefault(const Constant("{}"))(); TextColumn get sourceType => text()(); DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)(); } diff --git a/lib/models/metadata/audio_source.dart b/lib/models/metadata/audio_source.dart index c429ec74..44804285 100644 --- a/lib/models/metadata/audio_source.dart +++ b/lib/models/metadata/audio_source.dart @@ -1,5 +1,7 @@ part of 'metadata.dart'; +final oneOptionalDecimalFormatter = NumberFormat('0.#', 'en_US'); + enum SpotubeMediaCompressionType { lossy, lossless, @@ -30,26 +32,40 @@ class SpotubeAudioSourceContainerPreset @freezed class SpotubeAudioLossyContainerQuality with _$SpotubeAudioLossyContainerQuality { + const SpotubeAudioLossyContainerQuality._(); + factory SpotubeAudioLossyContainerQuality({ - required double bitrate, + required int bitrate, // bits per second }) = _SpotubeAudioLossyContainerQuality; factory SpotubeAudioLossyContainerQuality.fromJson( Map json) => _$SpotubeAudioLossyContainerQualityFromJson(json); + + @override + toString() { + return "${oneOptionalDecimalFormatter.format(bitrate)}kbps"; + } } @freezed class SpotubeAudioLosslessContainerQuality with _$SpotubeAudioLosslessContainerQuality { + const SpotubeAudioLosslessContainerQuality._(); + factory SpotubeAudioLosslessContainerQuality({ - required int bitDepth, - required double sampleRate, + required int bitDepth, // bit + required int sampleRate, // hz }) = _SpotubeAudioLosslessContainerQuality; factory SpotubeAudioLosslessContainerQuality.fromJson( Map json) => _$SpotubeAudioLosslessContainerQualityFromJson(json); + + @override + toString() { + return "${bitDepth}bit • ${oneOptionalDecimalFormatter.format(sampleRate / 1000)}kHz"; + } } @freezed diff --git a/lib/models/metadata/metadata.dart b/lib/models/metadata/metadata.dart index 4c6eb2ac..e68bcd14 100644 --- a/lib/models/metadata/metadata.dart +++ b/lib/models/metadata/metadata.dart @@ -5,6 +5,7 @@ import 'dart:typed_data'; import 'package:collection/collection.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:intl/intl.dart'; import 'package:metadata_god/metadata_god.dart'; import 'package:mime/mime.dart'; import 'package:path/path.dart'; diff --git a/lib/models/metadata/metadata.freezed.dart b/lib/models/metadata/metadata.freezed.dart index f54ee379..301929a5 100644 --- a/lib/models/metadata/metadata.freezed.dart +++ b/lib/models/metadata/metadata.freezed.dart @@ -595,7 +595,7 @@ SpotubeAudioLossyContainerQuality _$SpotubeAudioLossyContainerQualityFromJson( /// @nodoc mixin _$SpotubeAudioLossyContainerQuality { - double get bitrate => throw _privateConstructorUsedError; + int get bitrate => throw _privateConstructorUsedError; /// Serializes this SpotubeAudioLossyContainerQuality to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -615,7 +615,7 @@ abstract class $SpotubeAudioLossyContainerQualityCopyWith<$Res> { _$SpotubeAudioLossyContainerQualityCopyWithImpl<$Res, SpotubeAudioLossyContainerQuality>; @useResult - $Res call({double bitrate}); + $Res call({int bitrate}); } /// @nodoc @@ -640,7 +640,7 @@ class _$SpotubeAudioLossyContainerQualityCopyWithImpl<$Res, bitrate: null == bitrate ? _value.bitrate : bitrate // ignore: cast_nullable_to_non_nullable - as double, + as int, ) as $Val); } } @@ -654,7 +654,7 @@ abstract class _$$SpotubeAudioLossyContainerQualityImplCopyWith<$Res> __$$SpotubeAudioLossyContainerQualityImplCopyWithImpl<$Res>; @override @useResult - $Res call({double bitrate}); + $Res call({int bitrate}); } /// @nodoc @@ -678,7 +678,7 @@ class __$$SpotubeAudioLossyContainerQualityImplCopyWithImpl<$Res> bitrate: null == bitrate ? _value.bitrate : bitrate // ignore: cast_nullable_to_non_nullable - as double, + as int, )); } } @@ -686,20 +686,15 @@ class __$$SpotubeAudioLossyContainerQualityImplCopyWithImpl<$Res> /// @nodoc @JsonSerializable() class _$SpotubeAudioLossyContainerQualityImpl - implements _SpotubeAudioLossyContainerQuality { - _$SpotubeAudioLossyContainerQualityImpl({required this.bitrate}); + extends _SpotubeAudioLossyContainerQuality { + _$SpotubeAudioLossyContainerQualityImpl({required this.bitrate}) : super._(); factory _$SpotubeAudioLossyContainerQualityImpl.fromJson( Map json) => _$$SpotubeAudioLossyContainerQualityImplFromJson(json); @override - final double bitrate; - - @override - String toString() { - return 'SpotubeAudioLossyContainerQuality(bitrate: $bitrate)'; - } + final int bitrate; @override bool operator ==(Object other) { @@ -732,16 +727,17 @@ class _$SpotubeAudioLossyContainerQualityImpl } abstract class _SpotubeAudioLossyContainerQuality - implements SpotubeAudioLossyContainerQuality { - factory _SpotubeAudioLossyContainerQuality({required final double bitrate}) = + extends SpotubeAudioLossyContainerQuality { + factory _SpotubeAudioLossyContainerQuality({required final int bitrate}) = _$SpotubeAudioLossyContainerQualityImpl; + _SpotubeAudioLossyContainerQuality._() : super._(); factory _SpotubeAudioLossyContainerQuality.fromJson( Map json) = _$SpotubeAudioLossyContainerQualityImpl.fromJson; @override - double get bitrate; + int get bitrate; /// Create a copy of SpotubeAudioLossyContainerQuality /// with the given fields replaced by the non-null parameter values. @@ -759,8 +755,8 @@ SpotubeAudioLosslessContainerQuality /// @nodoc mixin _$SpotubeAudioLosslessContainerQuality { - int get bitDepth => throw _privateConstructorUsedError; - double get sampleRate => throw _privateConstructorUsedError; + int get bitDepth => throw _privateConstructorUsedError; // bit + int get sampleRate => throw _privateConstructorUsedError; /// Serializes this SpotubeAudioLosslessContainerQuality to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -781,7 +777,7 @@ abstract class $SpotubeAudioLosslessContainerQualityCopyWith<$Res> { _$SpotubeAudioLosslessContainerQualityCopyWithImpl<$Res, SpotubeAudioLosslessContainerQuality>; @useResult - $Res call({int bitDepth, double sampleRate}); + $Res call({int bitDepth, int sampleRate}); } /// @nodoc @@ -811,7 +807,7 @@ class _$SpotubeAudioLosslessContainerQualityCopyWithImpl<$Res, sampleRate: null == sampleRate ? _value.sampleRate : sampleRate // ignore: cast_nullable_to_non_nullable - as double, + as int, ) as $Val); } } @@ -825,7 +821,7 @@ abstract class _$$SpotubeAudioLosslessContainerQualityImplCopyWith<$Res> __$$SpotubeAudioLosslessContainerQualityImplCopyWithImpl<$Res>; @override @useResult - $Res call({int bitDepth, double sampleRate}); + $Res call({int bitDepth, int sampleRate}); } /// @nodoc @@ -854,7 +850,7 @@ class __$$SpotubeAudioLosslessContainerQualityImplCopyWithImpl<$Res> sampleRate: null == sampleRate ? _value.sampleRate : sampleRate // ignore: cast_nullable_to_non_nullable - as double, + as int, )); } } @@ -862,9 +858,10 @@ class __$$SpotubeAudioLosslessContainerQualityImplCopyWithImpl<$Res> /// @nodoc @JsonSerializable() class _$SpotubeAudioLosslessContainerQualityImpl - implements _SpotubeAudioLosslessContainerQuality { + extends _SpotubeAudioLosslessContainerQuality { _$SpotubeAudioLosslessContainerQualityImpl( - {required this.bitDepth, required this.sampleRate}); + {required this.bitDepth, required this.sampleRate}) + : super._(); factory _$SpotubeAudioLosslessContainerQualityImpl.fromJson( Map json) => @@ -872,13 +869,9 @@ class _$SpotubeAudioLosslessContainerQualityImpl @override final int bitDepth; +// bit @override - final double sampleRate; - - @override - String toString() { - return 'SpotubeAudioLosslessContainerQuality(bitDepth: $bitDepth, sampleRate: $sampleRate)'; - } + final int sampleRate; @override bool operator ==(Object other) { @@ -914,19 +907,20 @@ class _$SpotubeAudioLosslessContainerQualityImpl } abstract class _SpotubeAudioLosslessContainerQuality - implements SpotubeAudioLosslessContainerQuality { + extends SpotubeAudioLosslessContainerQuality { factory _SpotubeAudioLosslessContainerQuality( - {required final int bitDepth, required final double sampleRate}) = + {required final int bitDepth, required final int sampleRate}) = _$SpotubeAudioLosslessContainerQualityImpl; + _SpotubeAudioLosslessContainerQuality._() : super._(); factory _SpotubeAudioLosslessContainerQuality.fromJson( Map json) = _$SpotubeAudioLosslessContainerQualityImpl.fromJson; @override - int get bitDepth; + int get bitDepth; // bit @override - double get sampleRate; + int get sampleRate; /// Create a copy of SpotubeAudioLosslessContainerQuality /// with the given fields replaced by the non-null parameter values. diff --git a/lib/models/metadata/metadata.g.dart b/lib/models/metadata/metadata.g.dart index 7497053c..56783d80 100644 --- a/lib/models/metadata/metadata.g.dart +++ b/lib/models/metadata/metadata.g.dart @@ -52,7 +52,7 @@ Map _$$SpotubeAudioSourceContainerPresetLosslessImplToJson( _$SpotubeAudioLossyContainerQualityImpl _$$SpotubeAudioLossyContainerQualityImplFromJson(Map json) => _$SpotubeAudioLossyContainerQualityImpl( - bitrate: (json['bitrate'] as num).toDouble(), + bitrate: (json['bitrate'] as num).toInt(), ); Map _$$SpotubeAudioLossyContainerQualityImplToJson( @@ -65,7 +65,7 @@ _$SpotubeAudioLosslessContainerQualityImpl _$$SpotubeAudioLosslessContainerQualityImplFromJson(Map json) => _$SpotubeAudioLosslessContainerQualityImpl( bitDepth: (json['bitDepth'] as num).toInt(), - sampleRate: (json['sampleRate'] as num).toDouble(), + sampleRate: (json['sampleRate'] as num).toInt(), ); Map _$$SpotubeAudioLosslessContainerQualityImplToJson( diff --git a/lib/models/playback/track_sources.dart b/lib/models/playback/track_sources.dart index 262fcefa..677b34b8 100644 --- a/lib/models/playback/track_sources.dart +++ b/lib/models/playback/track_sources.dart @@ -1,7 +1,6 @@ import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:spotube/models/metadata/metadata.dart'; -part 'track_sources.freezed.dart'; part 'track_sources.g.dart'; @JsonSerializable() diff --git a/lib/models/playback/track_sources.freezed.dart b/lib/models/playback/track_sources.freezed.dart deleted file mode 100644 index 09ceb399..00000000 --- a/lib/models/playback/track_sources.freezed.dart +++ /dev/null @@ -1,800 +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 'track_sources.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'); - -TrackSourceQuery _$TrackSourceQueryFromJson(Map json) { - return _TrackSourceQuery.fromJson(json); -} - -/// @nodoc -mixin _$TrackSourceQuery { - String get id => throw _privateConstructorUsedError; - String get title => throw _privateConstructorUsedError; - List get artists => throw _privateConstructorUsedError; - String get album => throw _privateConstructorUsedError; - int get durationMs => throw _privateConstructorUsedError; - String get isrc => throw _privateConstructorUsedError; - bool get explicit => throw _privateConstructorUsedError; - - /// Serializes this TrackSourceQuery to a JSON map. - Map toJson() => throw _privateConstructorUsedError; - - /// Create a copy of TrackSourceQuery - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - $TrackSourceQueryCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $TrackSourceQueryCopyWith<$Res> { - factory $TrackSourceQueryCopyWith( - TrackSourceQuery value, $Res Function(TrackSourceQuery) then) = - _$TrackSourceQueryCopyWithImpl<$Res, TrackSourceQuery>; - @useResult - $Res call( - {String id, - String title, - List artists, - String album, - int durationMs, - String isrc, - bool explicit}); -} - -/// @nodoc -class _$TrackSourceQueryCopyWithImpl<$Res, $Val extends TrackSourceQuery> - implements $TrackSourceQueryCopyWith<$Res> { - _$TrackSourceQueryCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - /// Create a copy of TrackSourceQuery - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? id = null, - Object? title = null, - Object? artists = null, - Object? album = null, - Object? durationMs = null, - Object? isrc = null, - Object? explicit = null, - }) { - return _then(_value.copyWith( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as String, - title: null == title - ? _value.title - : title // ignore: cast_nullable_to_non_nullable - as String, - artists: null == artists - ? _value.artists - : artists // ignore: cast_nullable_to_non_nullable - as List, - album: null == album - ? _value.album - : album // ignore: cast_nullable_to_non_nullable - as String, - durationMs: null == durationMs - ? _value.durationMs - : durationMs // ignore: cast_nullable_to_non_nullable - as int, - isrc: null == isrc - ? _value.isrc - : isrc // ignore: cast_nullable_to_non_nullable - as String, - explicit: null == explicit - ? _value.explicit - : explicit // ignore: cast_nullable_to_non_nullable - as bool, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$TrackSourceQueryImplCopyWith<$Res> - implements $TrackSourceQueryCopyWith<$Res> { - factory _$$TrackSourceQueryImplCopyWith(_$TrackSourceQueryImpl value, - $Res Function(_$TrackSourceQueryImpl) then) = - __$$TrackSourceQueryImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {String id, - String title, - List artists, - String album, - int durationMs, - String isrc, - bool explicit}); -} - -/// @nodoc -class __$$TrackSourceQueryImplCopyWithImpl<$Res> - extends _$TrackSourceQueryCopyWithImpl<$Res, _$TrackSourceQueryImpl> - implements _$$TrackSourceQueryImplCopyWith<$Res> { - __$$TrackSourceQueryImplCopyWithImpl(_$TrackSourceQueryImpl _value, - $Res Function(_$TrackSourceQueryImpl) _then) - : super(_value, _then); - - /// Create a copy of TrackSourceQuery - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? id = null, - Object? title = null, - Object? artists = null, - Object? album = null, - Object? durationMs = null, - Object? isrc = null, - Object? explicit = null, - }) { - return _then(_$TrackSourceQueryImpl( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as String, - title: null == title - ? _value.title - : title // ignore: cast_nullable_to_non_nullable - as String, - artists: null == artists - ? _value._artists - : artists // ignore: cast_nullable_to_non_nullable - as List, - album: null == album - ? _value.album - : album // ignore: cast_nullable_to_non_nullable - as String, - durationMs: null == durationMs - ? _value.durationMs - : durationMs // ignore: cast_nullable_to_non_nullable - as int, - isrc: null == isrc - ? _value.isrc - : isrc // ignore: cast_nullable_to_non_nullable - as String, - explicit: null == explicit - ? _value.explicit - : explicit // ignore: cast_nullable_to_non_nullable - as bool, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$TrackSourceQueryImpl extends _TrackSourceQuery { - _$TrackSourceQueryImpl( - {required this.id, - required this.title, - required final List artists, - required this.album, - required this.durationMs, - required this.isrc, - required this.explicit}) - : _artists = artists, - super._(); - - factory _$TrackSourceQueryImpl.fromJson(Map json) => - _$$TrackSourceQueryImplFromJson(json); - - @override - final String id; - @override - final String title; - final List _artists; - @override - List get artists { - if (_artists is EqualUnmodifiableListView) return _artists; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_artists); - } - - @override - final String album; - @override - final int durationMs; - @override - final String isrc; - @override - final bool explicit; - - @override - String toString() { - return 'TrackSourceQuery(id: $id, title: $title, artists: $artists, album: $album, durationMs: $durationMs, isrc: $isrc, explicit: $explicit)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$TrackSourceQueryImpl && - (identical(other.id, id) || other.id == id) && - (identical(other.title, title) || other.title == title) && - const DeepCollectionEquality().equals(other._artists, _artists) && - (identical(other.album, album) || other.album == album) && - (identical(other.durationMs, durationMs) || - other.durationMs == durationMs) && - (identical(other.isrc, isrc) || other.isrc == isrc) && - (identical(other.explicit, explicit) || - other.explicit == explicit)); - } - - @JsonKey(includeFromJson: false, includeToJson: false) - @override - int get hashCode => Object.hash( - runtimeType, - id, - title, - const DeepCollectionEquality().hash(_artists), - album, - durationMs, - isrc, - explicit); - - /// Create a copy of TrackSourceQuery - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$TrackSourceQueryImplCopyWith<_$TrackSourceQueryImpl> get copyWith => - __$$TrackSourceQueryImplCopyWithImpl<_$TrackSourceQueryImpl>( - this, _$identity); - - @override - Map toJson() { - return _$$TrackSourceQueryImplToJson( - this, - ); - } -} - -abstract class _TrackSourceQuery extends TrackSourceQuery { - factory _TrackSourceQuery( - {required final String id, - required final String title, - required final List artists, - required final String album, - required final int durationMs, - required final String isrc, - required final bool explicit}) = _$TrackSourceQueryImpl; - _TrackSourceQuery._() : super._(); - - factory _TrackSourceQuery.fromJson(Map json) = - _$TrackSourceQueryImpl.fromJson; - - @override - String get id; - @override - String get title; - @override - List get artists; - @override - String get album; - @override - int get durationMs; - @override - String get isrc; - @override - bool get explicit; - - /// Create a copy of TrackSourceQuery - /// with the given fields replaced by the non-null parameter values. - @override - @JsonKey(includeFromJson: false, includeToJson: false) - _$$TrackSourceQueryImplCopyWith<_$TrackSourceQueryImpl> get copyWith => - throw _privateConstructorUsedError; -} - -TrackSourceInfo _$TrackSourceInfoFromJson(Map json) { - return _TrackSourceInfo.fromJson(json); -} - -/// @nodoc -mixin _$TrackSourceInfo { - String get id => throw _privateConstructorUsedError; - String get title => throw _privateConstructorUsedError; - String get artists => throw _privateConstructorUsedError; - String get thumbnail => throw _privateConstructorUsedError; - String get pageUrl => throw _privateConstructorUsedError; - int get durationMs => throw _privateConstructorUsedError; - - /// Serializes this TrackSourceInfo to a JSON map. - Map toJson() => throw _privateConstructorUsedError; - - /// Create a copy of TrackSourceInfo - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - $TrackSourceInfoCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $TrackSourceInfoCopyWith<$Res> { - factory $TrackSourceInfoCopyWith( - TrackSourceInfo value, $Res Function(TrackSourceInfo) then) = - _$TrackSourceInfoCopyWithImpl<$Res, TrackSourceInfo>; - @useResult - $Res call( - {String id, - String title, - String artists, - String thumbnail, - String pageUrl, - int durationMs}); -} - -/// @nodoc -class _$TrackSourceInfoCopyWithImpl<$Res, $Val extends TrackSourceInfo> - implements $TrackSourceInfoCopyWith<$Res> { - _$TrackSourceInfoCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - /// Create a copy of TrackSourceInfo - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? id = null, - Object? title = null, - Object? artists = null, - Object? thumbnail = null, - Object? pageUrl = null, - Object? durationMs = null, - }) { - return _then(_value.copyWith( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as String, - title: null == title - ? _value.title - : title // ignore: cast_nullable_to_non_nullable - as String, - artists: null == artists - ? _value.artists - : artists // ignore: cast_nullable_to_non_nullable - as String, - thumbnail: null == thumbnail - ? _value.thumbnail - : thumbnail // ignore: cast_nullable_to_non_nullable - as String, - pageUrl: null == pageUrl - ? _value.pageUrl - : pageUrl // ignore: cast_nullable_to_non_nullable - as String, - durationMs: null == durationMs - ? _value.durationMs - : durationMs // ignore: cast_nullable_to_non_nullable - as int, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$TrackSourceInfoImplCopyWith<$Res> - implements $TrackSourceInfoCopyWith<$Res> { - factory _$$TrackSourceInfoImplCopyWith(_$TrackSourceInfoImpl value, - $Res Function(_$TrackSourceInfoImpl) then) = - __$$TrackSourceInfoImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {String id, - String title, - String artists, - String thumbnail, - String pageUrl, - int durationMs}); -} - -/// @nodoc -class __$$TrackSourceInfoImplCopyWithImpl<$Res> - extends _$TrackSourceInfoCopyWithImpl<$Res, _$TrackSourceInfoImpl> - implements _$$TrackSourceInfoImplCopyWith<$Res> { - __$$TrackSourceInfoImplCopyWithImpl( - _$TrackSourceInfoImpl _value, $Res Function(_$TrackSourceInfoImpl) _then) - : super(_value, _then); - - /// Create a copy of TrackSourceInfo - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? id = null, - Object? title = null, - Object? artists = null, - Object? thumbnail = null, - Object? pageUrl = null, - Object? durationMs = null, - }) { - return _then(_$TrackSourceInfoImpl( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as String, - title: null == title - ? _value.title - : title // ignore: cast_nullable_to_non_nullable - as String, - artists: null == artists - ? _value.artists - : artists // ignore: cast_nullable_to_non_nullable - as String, - thumbnail: null == thumbnail - ? _value.thumbnail - : thumbnail // ignore: cast_nullable_to_non_nullable - as String, - pageUrl: null == pageUrl - ? _value.pageUrl - : pageUrl // ignore: cast_nullable_to_non_nullable - as String, - durationMs: null == durationMs - ? _value.durationMs - : durationMs // ignore: cast_nullable_to_non_nullable - as int, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$TrackSourceInfoImpl implements _TrackSourceInfo { - _$TrackSourceInfoImpl( - {required this.id, - required this.title, - required this.artists, - required this.thumbnail, - required this.pageUrl, - required this.durationMs}); - - factory _$TrackSourceInfoImpl.fromJson(Map json) => - _$$TrackSourceInfoImplFromJson(json); - - @override - final String id; - @override - final String title; - @override - final String artists; - @override - final String thumbnail; - @override - final String pageUrl; - @override - final int durationMs; - - @override - String toString() { - return 'TrackSourceInfo(id: $id, title: $title, artists: $artists, thumbnail: $thumbnail, pageUrl: $pageUrl, durationMs: $durationMs)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$TrackSourceInfoImpl && - (identical(other.id, id) || other.id == id) && - (identical(other.title, title) || other.title == title) && - (identical(other.artists, artists) || other.artists == artists) && - (identical(other.thumbnail, thumbnail) || - other.thumbnail == thumbnail) && - (identical(other.pageUrl, pageUrl) || other.pageUrl == pageUrl) && - (identical(other.durationMs, durationMs) || - other.durationMs == durationMs)); - } - - @JsonKey(includeFromJson: false, includeToJson: false) - @override - int get hashCode => Object.hash( - runtimeType, id, title, artists, thumbnail, pageUrl, durationMs); - - /// Create a copy of TrackSourceInfo - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$TrackSourceInfoImplCopyWith<_$TrackSourceInfoImpl> get copyWith => - __$$TrackSourceInfoImplCopyWithImpl<_$TrackSourceInfoImpl>( - this, _$identity); - - @override - Map toJson() { - return _$$TrackSourceInfoImplToJson( - this, - ); - } -} - -abstract class _TrackSourceInfo implements TrackSourceInfo { - factory _TrackSourceInfo( - {required final String id, - required final String title, - required final String artists, - required final String thumbnail, - required final String pageUrl, - required final int durationMs}) = _$TrackSourceInfoImpl; - - factory _TrackSourceInfo.fromJson(Map json) = - _$TrackSourceInfoImpl.fromJson; - - @override - String get id; - @override - String get title; - @override - String get artists; - @override - String get thumbnail; - @override - String get pageUrl; - @override - int get durationMs; - - /// Create a copy of TrackSourceInfo - /// with the given fields replaced by the non-null parameter values. - @override - @JsonKey(includeFromJson: false, includeToJson: false) - _$$TrackSourceInfoImplCopyWith<_$TrackSourceInfoImpl> get copyWith => - throw _privateConstructorUsedError; -} - -TrackSource _$TrackSourceFromJson(Map json) { - return _TrackSource.fromJson(json); -} - -/// @nodoc -mixin _$TrackSource { - String get url => throw _privateConstructorUsedError; - SourceQualities get quality => throw _privateConstructorUsedError; - SourceCodecs get codec => throw _privateConstructorUsedError; - String get bitrate => throw _privateConstructorUsedError; - String get qualityLabel => throw _privateConstructorUsedError; - - /// Serializes this TrackSource to a JSON map. - Map toJson() => throw _privateConstructorUsedError; - - /// Create a copy of TrackSource - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - $TrackSourceCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $TrackSourceCopyWith<$Res> { - factory $TrackSourceCopyWith( - TrackSource value, $Res Function(TrackSource) then) = - _$TrackSourceCopyWithImpl<$Res, TrackSource>; - @useResult - $Res call( - {String url, - SourceQualities quality, - SourceCodecs codec, - String bitrate, - String qualityLabel}); -} - -/// @nodoc -class _$TrackSourceCopyWithImpl<$Res, $Val extends TrackSource> - implements $TrackSourceCopyWith<$Res> { - _$TrackSourceCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - /// Create a copy of TrackSource - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? url = null, - Object? quality = null, - Object? codec = null, - Object? bitrate = null, - Object? qualityLabel = null, - }) { - return _then(_value.copyWith( - url: null == url - ? _value.url - : url // ignore: cast_nullable_to_non_nullable - as String, - quality: null == quality - ? _value.quality - : quality // ignore: cast_nullable_to_non_nullable - as SourceQualities, - codec: null == codec - ? _value.codec - : codec // ignore: cast_nullable_to_non_nullable - as SourceCodecs, - bitrate: null == bitrate - ? _value.bitrate - : bitrate // ignore: cast_nullable_to_non_nullable - as String, - qualityLabel: null == qualityLabel - ? _value.qualityLabel - : qualityLabel // ignore: cast_nullable_to_non_nullable - as String, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$TrackSourceImplCopyWith<$Res> - implements $TrackSourceCopyWith<$Res> { - factory _$$TrackSourceImplCopyWith( - _$TrackSourceImpl value, $Res Function(_$TrackSourceImpl) then) = - __$$TrackSourceImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {String url, - SourceQualities quality, - SourceCodecs codec, - String bitrate, - String qualityLabel}); -} - -/// @nodoc -class __$$TrackSourceImplCopyWithImpl<$Res> - extends _$TrackSourceCopyWithImpl<$Res, _$TrackSourceImpl> - implements _$$TrackSourceImplCopyWith<$Res> { - __$$TrackSourceImplCopyWithImpl( - _$TrackSourceImpl _value, $Res Function(_$TrackSourceImpl) _then) - : super(_value, _then); - - /// Create a copy of TrackSource - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? url = null, - Object? quality = null, - Object? codec = null, - Object? bitrate = null, - Object? qualityLabel = null, - }) { - return _then(_$TrackSourceImpl( - url: null == url - ? _value.url - : url // ignore: cast_nullable_to_non_nullable - as String, - quality: null == quality - ? _value.quality - : quality // ignore: cast_nullable_to_non_nullable - as SourceQualities, - codec: null == codec - ? _value.codec - : codec // ignore: cast_nullable_to_non_nullable - as SourceCodecs, - bitrate: null == bitrate - ? _value.bitrate - : bitrate // ignore: cast_nullable_to_non_nullable - as String, - qualityLabel: null == qualityLabel - ? _value.qualityLabel - : qualityLabel // ignore: cast_nullable_to_non_nullable - as String, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$TrackSourceImpl implements _TrackSource { - _$TrackSourceImpl( - {required this.url, - required this.quality, - required this.codec, - required this.bitrate, - required this.qualityLabel}); - - factory _$TrackSourceImpl.fromJson(Map json) => - _$$TrackSourceImplFromJson(json); - - @override - final String url; - @override - final SourceQualities quality; - @override - final SourceCodecs codec; - @override - final String bitrate; - @override - final String qualityLabel; - - @override - String toString() { - return 'TrackSource(url: $url, quality: $quality, codec: $codec, bitrate: $bitrate, qualityLabel: $qualityLabel)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$TrackSourceImpl && - (identical(other.url, url) || other.url == url) && - (identical(other.quality, quality) || other.quality == quality) && - (identical(other.codec, codec) || other.codec == codec) && - (identical(other.bitrate, bitrate) || other.bitrate == bitrate) && - (identical(other.qualityLabel, qualityLabel) || - other.qualityLabel == qualityLabel)); - } - - @JsonKey(includeFromJson: false, includeToJson: false) - @override - int get hashCode => - Object.hash(runtimeType, url, quality, codec, bitrate, qualityLabel); - - /// Create a copy of TrackSource - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$TrackSourceImplCopyWith<_$TrackSourceImpl> get copyWith => - __$$TrackSourceImplCopyWithImpl<_$TrackSourceImpl>(this, _$identity); - - @override - Map toJson() { - return _$$TrackSourceImplToJson( - this, - ); - } -} - -abstract class _TrackSource implements TrackSource { - factory _TrackSource( - {required final String url, - required final SourceQualities quality, - required final SourceCodecs codec, - required final String bitrate, - required final String qualityLabel}) = _$TrackSourceImpl; - - factory _TrackSource.fromJson(Map json) = - _$TrackSourceImpl.fromJson; - - @override - String get url; - @override - SourceQualities get quality; - @override - SourceCodecs get codec; - @override - String get bitrate; - @override - String get qualityLabel; - - /// Create a copy of TrackSource - /// with the given fields replaced by the non-null parameter values. - @override - @JsonKey(includeFromJson: false, includeToJson: false) - _$$TrackSourceImplCopyWith<_$TrackSourceImpl> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/lib/models/playback/track_sources.g.dart b/lib/models/playback/track_sources.g.dart index dd63aebb..3088493a 100644 --- a/lib/models/playback/track_sources.g.dart +++ b/lib/models/playback/track_sources.g.dart @@ -7,17 +7,18 @@ part of 'track_sources.dart'; // ************************************************************************** BasicSourcedTrack _$BasicSourcedTrackFromJson(Map json) => BasicSourcedTrack( - query: TrackSourceQuery.fromJson( + query: SpotubeFullTrackObject.fromJson( Map.from(json['query'] as Map)), - source: $enumDecode(_$AudioSourceEnumMap, json['source']), - info: TrackSourceInfo.fromJson( + source: json['source'] as String, + info: SpotubeAudioSourceMatchObject.fromJson( Map.from(json['info'] as Map)), sources: (json['sources'] as List) - .map((e) => TrackSource.fromJson(Map.from(e as Map))) + .map((e) => SpotubeAudioSourceStreamObject.fromJson( + Map.from(e as Map))) .toList(), siblings: (json['siblings'] as List?) - ?.map((e) => - TrackSourceInfo.fromJson(Map.from(e as Map))) + ?.map((e) => SpotubeAudioSourceMatchObject.fromJson( + Map.from(e as Map))) .toList() ?? const [], ); @@ -25,92 +26,8 @@ BasicSourcedTrack _$BasicSourcedTrackFromJson(Map json) => BasicSourcedTrack( Map _$BasicSourcedTrackToJson(BasicSourcedTrack instance) => { 'query': instance.query.toJson(), - 'source': _$AudioSourceEnumMap[instance.source]!, 'info': instance.info.toJson(), + 'source': instance.source, 'sources': instance.sources.map((e) => e.toJson()).toList(), 'siblings': instance.siblings.map((e) => e.toJson()).toList(), }; - -const _$AudioSourceEnumMap = { - AudioSource.youtube: 'youtube', - AudioSource.piped: 'piped', - AudioSource.jiosaavn: 'jiosaavn', - AudioSource.invidious: 'invidious', - AudioSource.dabMusic: 'dabMusic', -}; - -_$TrackSourceQueryImpl _$$TrackSourceQueryImplFromJson(Map json) => - _$TrackSourceQueryImpl( - id: json['id'] as String, - title: json['title'] as String, - artists: - (json['artists'] as List).map((e) => e as String).toList(), - album: json['album'] as String, - durationMs: (json['durationMs'] as num).toInt(), - isrc: json['isrc'] as String, - explicit: json['explicit'] as bool, - ); - -Map _$$TrackSourceQueryImplToJson( - _$TrackSourceQueryImpl instance) => - { - 'id': instance.id, - 'title': instance.title, - 'artists': instance.artists, - 'album': instance.album, - 'durationMs': instance.durationMs, - 'isrc': instance.isrc, - 'explicit': instance.explicit, - }; - -_$TrackSourceInfoImpl _$$TrackSourceInfoImplFromJson(Map json) => - _$TrackSourceInfoImpl( - id: json['id'] as String, - title: json['title'] as String, - artists: json['artists'] as String, - thumbnail: json['thumbnail'] as String, - pageUrl: json['pageUrl'] as String, - durationMs: (json['durationMs'] as num).toInt(), - ); - -Map _$$TrackSourceInfoImplToJson( - _$TrackSourceInfoImpl instance) => - { - 'id': instance.id, - 'title': instance.title, - 'artists': instance.artists, - 'thumbnail': instance.thumbnail, - 'pageUrl': instance.pageUrl, - 'durationMs': instance.durationMs, - }; - -_$TrackSourceImpl _$$TrackSourceImplFromJson(Map json) => _$TrackSourceImpl( - url: json['url'] as String, - quality: $enumDecode(_$SourceQualitiesEnumMap, json['quality']), - codec: $enumDecode(_$SourceCodecsEnumMap, json['codec']), - bitrate: json['bitrate'] as String, - qualityLabel: json['qualityLabel'] as String, - ); - -Map _$$TrackSourceImplToJson(_$TrackSourceImpl instance) => - { - 'url': instance.url, - 'quality': _$SourceQualitiesEnumMap[instance.quality]!, - 'codec': _$SourceCodecsEnumMap[instance.codec]!, - 'bitrate': instance.bitrate, - 'qualityLabel': instance.qualityLabel, - }; - -const _$SourceQualitiesEnumMap = { - SourceQualities.uncompressed: 'uncompressed', - SourceQualities.high: 'high', - SourceQualities.medium: 'medium', - SourceQualities.low: 'low', -}; - -const _$SourceCodecsEnumMap = { - SourceCodecs.m4a: 'm4a', - SourceCodecs.weba: 'weba', - SourceCodecs.mp3: 'mp3', - SourceCodecs.flac: 'flac', -}; diff --git a/lib/modules/library/local_folder/cache_export_dialog.dart b/lib/modules/library/local_folder/cache_export_dialog.dart index fde219c9..4c86a8d5 100644 --- a/lib/modules/library/local_folder/cache_export_dialog.dart +++ b/lib/modules/library/local_folder/cache_export_dialog.dart @@ -7,7 +7,7 @@ import 'package:path/path.dart' as path; import 'package:spotube/extensions/context.dart'; import 'package:spotube/services/logger/logger.dart'; -final codecs = SourceCodecs.values.map((s) => s.name); +const containers = ["m4a", "mp3", "mp4", "ogg", "wav", "flac"]; class LocalFolderCacheExportDialog extends HookConsumerWidget { final Directory exportDir; @@ -29,7 +29,8 @@ class LocalFolderCacheExportDialog extends HookConsumerWidget { final stream = cacheDir.list().where( (event) => event is File && - codecs.contains(path.extension(event.path).replaceAll(".", "")), + containers + .contains(path.extension(event.path).replaceAll(".", "")), ); stream.listen( diff --git a/lib/modules/player/player.dart b/lib/modules/player/player.dart index 69262641..5ea690e0 100644 --- a/lib/modules/player/player.dart +++ b/lib/modules/player/player.dart @@ -21,11 +21,9 @@ import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/modules/root/spotube_navigation_bar.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; +import 'package:spotube/provider/metadata_plugin/audio_source/quality_label.dart'; import 'package:spotube/provider/server/active_track_sources.dart'; import 'package:spotube/provider/volume_provider.dart'; -import 'package:spotube/services/sourced_track/sources/youtube.dart'; - -import 'package:url_launcher/url_launcher_string.dart'; class PlayerView extends HookConsumerWidget { final PanelController panelController; @@ -45,14 +43,7 @@ class PlayerView extends HookConsumerWidget { final currentActiveTrackSource = sourcedCurrentTrack.asData?.value?.source; final isLocalTrack = currentActiveTrack is SpotubeLocalTrackObject; final mediaQuery = MediaQuery.sizeOf(context); - - final activeSourceCodec = useMemoized( - () { - return currentActiveTrackSource - ?.getStreamOfCodec(currentActiveTrackSource.codec); - }, - [currentActiveTrackSource?.sources, currentActiveTrackSource?.codec], - ); + final qualityLabel = ref.watch(audioSourceQualityLabelProvider); final shouldHide = useState(true); @@ -117,22 +108,6 @@ class PlayerView extends HookConsumerWidget { ) ], trailing: [ - if (currentActiveTrackSource is YoutubeSourcedTrack) - TextButton( - size: const ButtonSize(1.2), - leading: Assets.images.logos.songlinkTransparent.image( - width: 20, - height: 20, - color: theme.colorScheme.foreground, - ), - onPressed: () { - final url = - "https://song.link/s/${currentActiveTrack?.id}"; - - launchUrlString(url); - }, - child: Text(context.l10n.song_link), - ), if (!isLocalTrack) Tooltip( tooltip: TooltipContainer( @@ -276,20 +251,19 @@ class PlayerView extends HookConsumerWidget { }), ), const Gap(25), - if (activeSourceCodec != null) - OutlineBadge( - style: const ButtonStyle.outline( - size: ButtonSize.normal, - density: ButtonDensity.dense, - shape: ButtonShape.rectangle, - ).copyWith( - textStyle: (context, states, value) { - return value.copyWith(fontWeight: FontWeight.w500); - }, - ), - leading: const Icon(SpotubeIcons.lightningOutlined), - child: Text(activeSourceCodec.qualityLabel), - ) + OutlineBadge( + style: const ButtonStyle.outline( + size: ButtonSize.normal, + density: ButtonDensity.dense, + shape: ButtonShape.rectangle, + ).copyWith( + textStyle: (context, states, value) { + return value.copyWith(fontWeight: FontWeight.w500); + }, + ), + leading: const Icon(SpotubeIcons.lightningOutlined), + child: Text(qualityLabel), + ) ], ), ), diff --git a/lib/modules/player/sibling_tracks_sheet.dart b/lib/modules/player/sibling_tracks_sheet.dart index a6c3ae32..7b780143 100644 --- a/lib/modules/player/sibling_tracks_sheet.dart +++ b/lib/modules/player/sibling_tracks_sheet.dart @@ -1,60 +1,16 @@ -import 'package:collection/collection.dart'; - import 'package:flutter_hooks/flutter_hooks.dart'; 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/spotube_icons.dart'; -import 'package:spotube/components/button/back_button.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/duration.dart'; -import 'package:spotube/hooks/controllers/use_shadcn_text_editing_controller.dart'; -import 'package:spotube/hooks/utils/use_debounce.dart'; -import 'package:spotube/models/database/database.dart'; import 'package:spotube/models/metadata/metadata.dart'; -import 'package:spotube/models/playback/track_sources.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/audio_player/querying_track_info.dart'; import 'package:spotube/provider/server/active_track_sources.dart'; -import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; -import 'package:spotube/provider/youtube_engine/youtube_engine.dart'; -import 'package:spotube/services/sourced_track/models/video_info.dart'; -import 'package:spotube/services/sourced_track/sources/jiosaavn.dart'; -import 'package:spotube/services/sourced_track/sources/youtube.dart'; -import 'package:spotube/utils/service_utils.dart'; - -final sourceInfoToIconMap = { - AudioSource.youtube: - const Icon(SpotubeIcons.youtube, color: Color(0xFFFF0000)), - AudioSource.jiosaavn: Container( - height: 30, - width: 30, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(90), - image: DecorationImage( - image: Assets.images.logos.jiosaavn.provider(), - fit: BoxFit.cover, - ), - ), - ), - AudioSource.piped: const Icon(SpotubeIcons.piped), - AudioSource.invidious: Container( - height: 18, - width: 18, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(90), - image: DecorationImage( - image: Assets.images.logos.invidious.provider(), - fit: BoxFit.cover, - ), - ), - ), -}; class SiblingTracksSheet extends HookConsumerWidget { final bool floating; @@ -65,94 +21,21 @@ class SiblingTracksSheet extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final theme = Theme.of(context); - final isFetchingActiveTrack = ref.watch(queryingTrackInfoProvider); - final preferences = ref.watch(userPreferencesProvider); - final youtubeEngine = ref.watch(youtubeEngineProvider); + final controller = useScrollController(); - final isLoading = useState(false); - final isSearching = useState(false); - final searchMode = useState(preferences.searchMode); + final isFetchingActiveTrack = ref.watch(queryingTrackInfoProvider); final activeTrackSources = ref.watch(activeTrackSourcesProvider); final activeTrackNotifier = activeTrackSources.asData?.value?.notifier; final activeTrack = activeTrackSources.asData?.value?.track; final activeTrackSource = activeTrackSources.asData?.value?.source; - final title = ServiceUtils.getTitle( - activeTrack?.name ?? "", - artists: activeTrack?.artists.map((e) => e.name).toList() ?? [], - onlyCleanArtist: true, - ).trim(); - - final defaultSearchTerm = - "$title - ${activeTrack?.artists.asString() ?? ""}"; - final searchController = useShadcnTextEditingController( - text: defaultSearchTerm, - ); - - final searchTerm = useDebounce( - useValueListenable(searchController).text, - ); - - final controller = useScrollController(); - - final searchRequest = useMemoized(() async { - if (searchTerm.trim().isEmpty || activeTrackSource == null) { - return []; - } - if (preferences.audioSource == AudioSource.jiosaavn) { - final resultsJioSaavn = - await jiosaavnClient.search.songs(searchTerm.trim()); - final results = await Future.wait( - resultsJioSaavn.results.mapIndexed((i, song) async { - final siblingType = JioSaavnSourcedTrack.toSiblingType(song); - return siblingType.info; - })); - - final activeSourceInfo = activeTrackSource.info; - - return results - ..removeWhere((element) => element.id == activeSourceInfo.id) - ..insert( - 0, - activeSourceInfo, - ); - } else { - final resultsYt = await youtubeEngine.searchVideos(searchTerm.trim()); - - final searchResults = await Future.wait( - resultsYt - .map(YoutubeVideoInfo.fromVideo) - .mapIndexed((i, video) async { - if (!context.mounted) return null; - final siblingType = - await YoutubeSourcedTrack.toSiblingType(i, video, ref); - return siblingType.info; - }) - .whereType>() - .toList(), - ); - final activeSourceInfo = activeTrackSource.info; - return searchResults - ..removeWhere((element) => element.id == activeSourceInfo.id) - ..insert(0, activeSourceInfo); - } - }, [ - searchTerm, - searchMode.value, - activeTrack, - activeTrackSource, - preferences.audioSource, - youtubeEngine, - ]); - - final siblings = useMemoized( + final siblings = useMemoized>( () => !isFetchingActiveTrack ? [ if (activeTrackSource != null) activeTrackSource.info, ...?activeTrackSource?.siblings, ] - : [], + : [], [activeTrackSource, isFetchingActiveTrack], ); @@ -166,74 +49,6 @@ class SiblingTracksSheet extends HookConsumerWidget { return null; }, [activeTrack, previousActiveTrack]); - final itemBuilder = useCallback( - (TrackSourceInfo sourceInfo, AudioSource source) { - final icon = sourceInfoToIconMap[source]; - return ButtonTile( - style: ButtonVariance.ghost, - padding: const EdgeInsets.symmetric(horizontal: 8), - title: Text( - sourceInfo.title, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - leading: UniversalImage( - path: sourceInfo.thumbnail, - height: 60, - width: 60, - ), - trailing: Text(Duration(milliseconds: sourceInfo.durationMs) - .toHumanReadableString()), - subtitle: Row( - children: [ - if (icon != null) icon, - Flexible( - child: Text( - " • ${sourceInfo.artists}", - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - enabled: !isFetchingActiveTrack && !isLoading.value, - selected: !isFetchingActiveTrack && - sourceInfo.id == activeTrackSource?.info.id, - onPressed: () async { - if (!isFetchingActiveTrack && - sourceInfo.id != activeTrackSource?.info.id) { - try { - isLoading.value = true; - await activeTrackNotifier?.swapWithSibling(sourceInfo); - await ref.read(audioPlayerProvider.notifier).swapActiveSource(); - - if (context.mounted) { - if (MediaQuery.sizeOf(context).mdAndUp) { - closeOverlay(context); - } else { - closeDrawer(context); - } - } - } finally { - if (context.mounted) { - isLoading.value = false; - } - } - } - }, - ); - }, - [ - activeTrackSource, - activeTrackNotifier, - siblings, - isFetchingActiveTrack, - isLoading.value, - ], - ); - - final scale = context.theme.scaling; - return SafeArea( child: Column( mainAxisSize: MainAxisSize.min, @@ -244,72 +59,16 @@ class SiblingTracksSheet extends HookConsumerWidget { spacing: 5, children: [ AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: !isSearching.value - ? Text( - context.l10n.alternative_track_sources, - ).bold() - : ConstrainedBox( - constraints: BoxConstraints( - maxWidth: 320 * scale, - maxHeight: 38 * scale, - ), - child: TextField( - autofocus: true, - controller: searchController, - placeholder: Text(context.l10n.search), - style: theme.typography.bold, - ), - ), - ), - const Spacer(), - if (!isSearching.value) ...[ - IconButton.outline( - icon: const Icon(SpotubeIcons.search, size: 18), - onPressed: () { - isSearching.value = true; - }, - ), - if (!floating) const BackButton(icon: SpotubeIcons.angleDown) - ] else ...[ - if (preferences.audioSource == AudioSource.piped) - IconButton.outline( - icon: const Icon(SpotubeIcons.filter, size: 18), - onPressed: () { - showPopover( - context: context, - alignment: Alignment.bottomRight, - builder: (context) { - return DropdownMenu( - children: SearchMode.values - .map( - (e) => MenuButton( - onPressed: (context) { - searchMode.value = e; - }, - enabled: searchMode.value != e, - child: Text(e.label), - ), - ) - .toList(), - ); - }, - ); - }, - ), - IconButton.outline( - icon: const Icon(SpotubeIcons.close, size: 18), - onPressed: () { - isSearching.value = false; - }, - ), - ] + duration: const Duration(milliseconds: 300), + child: Text( + context.l10n.alternative_track_sources, + ).bold()), ], ), ), AnimatedSwitcher( duration: const Duration(milliseconds: 300), - child: isLoading.value + child: activeTrackSources.isLoading ? const SizedBox( width: double.infinity, child: LinearProgressIndicator(), @@ -323,42 +82,62 @@ class SiblingTracksSheet extends HookConsumerWidget { FadeTransition(opacity: animation, child: child), child: InterScrollbar( controller: controller, - child: switch (isSearching.value) { - false => ListView.separated( - padding: const EdgeInsets.all(8.0), - controller: controller, - itemCount: siblings.length, - separatorBuilder: (context, index) => const Gap(8), - itemBuilder: (context, index) => itemBuilder( - siblings[index], - activeTrackSource!.source, - ), - ), - true => FutureBuilder( - future: searchRequest, - builder: (context, snapshot) { - if (snapshot.hasError) { - return Center( - child: Text(snapshot.error.toString()), - ); - } else if (!snapshot.hasData) { - return const Center( - child: CircularProgressIndicator()); - } + child: ListView.separated( + padding: const EdgeInsets.all(8.0), + controller: controller, + itemCount: siblings.length, + separatorBuilder: (context, index) => const Gap(8), + itemBuilder: (context, index) { + final sourceInfo = siblings[index]; - return ListView.separated( - padding: const EdgeInsets.all(8.0), - controller: controller, - itemCount: snapshot.data!.length, - separatorBuilder: (context, index) => const Gap(8), - itemBuilder: (context, index) => itemBuilder( - snapshot.data![index], - preferences.audioSource, - ), - ); + return ButtonTile( + style: ButtonVariance.ghost, + padding: const EdgeInsets.symmetric(horizontal: 8), + title: Text( + sourceInfo.title, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + leading: sourceInfo.thumbnail != null + ? UniversalImage( + path: sourceInfo.thumbnail!, + height: 60, + width: 60, + ) + : null, + trailing: + Text(sourceInfo.duration.toHumanReadableString()), + subtitle: Flexible( + child: Text( + sourceInfo.artists.join(", "), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + enabled: !isFetchingActiveTrack, + selected: !isFetchingActiveTrack && + sourceInfo.id == activeTrackSource?.info.id, + onPressed: () async { + if (!isFetchingActiveTrack && + sourceInfo.id != activeTrackSource?.info.id) { + await activeTrackNotifier + ?.swapWithSibling(sourceInfo); + await ref + .read(audioPlayerProvider.notifier) + .swapActiveSource(); + + if (context.mounted) { + if (MediaQuery.sizeOf(context).mdAndUp) { + closeOverlay(context); + } else { + closeDrawer(context); + } + } + } }, - ), - }, + ); + }, + ), ), ), ), diff --git a/lib/pages/getting_started/sections/playback.dart b/lib/pages/getting_started/sections/playback.dart index a6f887cb..699024b1 100644 --- a/lib/pages/getting_started/sections/playback.dart +++ b/lib/pages/getting_started/sections/playback.dart @@ -1,32 +1,11 @@ -import 'package:flutter/material.dart' show Badge; -import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; -import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/ui/button_tile.dart'; -import 'package:spotube/models/database/database.dart'; import 'package:spotube/modules/getting_started/blur_card.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; -final audioSourceToIconMap = { - AudioSource.youtube: const Icon( - SpotubeIcons.youtube, - color: Colors.red, - size: 20, - ), - AudioSource.piped: const Icon(SpotubeIcons.piped, size: 20), - AudioSource.invidious: ClipRRect( - borderRadius: BorderRadius.circular(26), - child: Assets.images.logos.invidious.image(width: 26, height: 26), - ), - AudioSource.jiosaavn: - Assets.images.logos.jiosaavn.image(width: 20, height: 20), - AudioSource.dabMusic: - Assets.images.logos.dabMusic.image(width: 20, height: 20), -}; - class GettingStartedPagePlaybackSection extends HookConsumerWidget { final VoidCallback onNext; final VoidCallback onPrevious; @@ -42,19 +21,19 @@ class GettingStartedPagePlaybackSection extends HookConsumerWidget { final preferences = ref.watch(userPreferencesProvider); final preferencesNotifier = ref.read(userPreferencesProvider.notifier); - final audioSourceToDescription = useMemoized( - () => { - AudioSource.youtube: "${context.l10n.youtube_source_description}\n" - "${context.l10n.highest_quality("148kbps mp4, 128kbps opus")}", - AudioSource.piped: context.l10n.piped_source_description, - AudioSource.jiosaavn: - "${context.l10n.jiosaavn_source_description}\n" - "${context.l10n.highest_quality("320kbps mp4")}", - AudioSource.invidious: context.l10n.invidious_source_description, - AudioSource.dabMusic: "${context.l10n.dab_music_source_description}\n" - "${context.l10n.highest_quality("320kbps mp3, HI-RES 24bit 44.1kHz-96kHz flac")}", - }, - []); + // final audioSourceToDescription = useMemoized( + // () => { + // AudioSource.youtube: "${context.l10n.youtube_source_description}\n" + // "${context.l10n.highest_quality("148kbps mp4, 128kbps opus")}", + // AudioSource.piped: context.l10n.piped_source_description, + // AudioSource.jiosaavn: + // "${context.l10n.jiosaavn_source_description}\n" + // "${context.l10n.highest_quality("320kbps mp4")}", + // AudioSource.invidious: context.l10n.invidious_source_description, + // AudioSource.dabMusic: "${context.l10n.dab_music_source_description}\n" + // "${context.l10n.highest_quality("320kbps mp3, HI-RES 24bit 44.1kHz-96kHz flac")}", + // }, + // []); return Center( child: BlurCard( @@ -69,44 +48,44 @@ class GettingStartedPagePlaybackSection extends HookConsumerWidget { ], ), const Gap(16), - Align( - alignment: Alignment.centerLeft, - child: Text(context.l10n.select_audio_source).semiBold().large(), - ), - const Gap(16), - RadioGroup( - value: preferences.audioSource, - onChanged: (value) { - preferencesNotifier.setAudioSource(value); - }, - child: Wrap( - spacing: 6, - runSpacing: 6, - children: [ - for (final source in AudioSource.values) - Badge( - isLabelVisible: source == AudioSource.dabMusic, - label: const Text("NEW"), - backgroundColor: Colors.lime[300], - textColor: Colors.black, - child: RadioCard( - value: source, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - audioSourceToIconMap[source]!, - Text(source.label), - ], - ), - ), - ), - ], - ), - ), - const Gap(16), - Text( - audioSourceToDescription[preferences.audioSource]!, - ).small().muted(), + // Align( + // alignment: Alignment.centerLeft, + // child: Text(context.l10n.select_audio_source).semiBold().large(), + // ), + // const Gap(16), + // RadioGroup( + // value: preferences.audioSource, + // onChanged: (value) { + // preferencesNotifier.setAudioSource(value); + // }, + // child: Wrap( + // spacing: 6, + // runSpacing: 6, + // children: [ + // for (final source in AudioSource.values) + // Badge( + // isLabelVisible: source == AudioSource.dabMusic, + // label: const Text("NEW"), + // backgroundColor: Colors.lime[300], + // textColor: Colors.black, + // child: RadioCard( + // value: source, + // child: Column( + // mainAxisSize: MainAxisSize.min, + // children: [ + // audioSourceToIconMap[source]!, + // Text(source.label), + // ], + // ), + // ), + // ), + // ], + // ), + // ), + // const Gap(16), + // Text( + // audioSourceToDescription[preferences.audioSource]!, + // ).small().muted(), const Gap(16), ButtonTile( title: Text(context.l10n.endless_playback), diff --git a/lib/pages/settings/sections/playback.dart b/lib/pages/settings/sections/playback.dart index 77eaa0c5..29a8c2ea 100644 --- a/lib/pages/settings/sections/playback.dart +++ b/lib/pages/settings/sections/playback.dart @@ -1,29 +1,18 @@ -import 'dart:io'; - import 'package:auto_route/auto_route.dart'; -import 'package:collection/collection.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart' show ListTile; -import 'package:google_fonts/google_fonts.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:piped_client/piped_client.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/models/database/database.dart'; -import 'package:spotube/modules/settings/playback/edit_connect_port_dialog.dart'; -import 'package:spotube/modules/settings/playback/edit_instance_url_dialog.dart'; -import 'package:spotube/modules/settings/section_card_with_heading.dart'; import 'package:spotube/components/adaptive/adaptive_select_tile.dart'; +import 'package:spotube/modules/settings/playback/edit_connect_port_dialog.dart'; +import 'package:spotube/modules/settings/section_card_with_heading.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/modules/settings/youtube_engine_not_installed_dialog.dart'; -import 'package:spotube/provider/audio_player/sources/invidious_instances_provider.dart'; -import 'package:spotube/provider/audio_player/sources/piped_instances_provider.dart'; +import 'package:spotube/provider/metadata_plugin/audio_source/quality_presets.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; -import 'package:spotube/services/kv_store/kv_store.dart'; -import 'package:spotube/services/youtube_engine/yt_dlp_engine.dart'; import 'package:spotube/utils/platform.dart'; class SettingsPlaybackSection extends HookConsumerWidget { @@ -33,332 +22,78 @@ class SettingsPlaybackSection extends HookConsumerWidget { Widget build(BuildContext context, ref) { final preferences = ref.watch(userPreferencesProvider); final preferencesNotifier = ref.watch(userPreferencesProvider.notifier); + final sourcePresets = ref.watch(audioSourcePresetsProvider); + final sourcePresetsNotifier = + ref.watch(audioSourcePresetsProvider.notifier); final theme = Theme.of(context); return SectionCardWithHeading( heading: context.l10n.playback, children: [ - AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.audioQuality), - title: Text(context.l10n.audio_quality), - value: preferences.audioQuality, - options: [ - if (preferences.audioSource == AudioSource.dabMusic) - SelectItemButton( - value: SourceQualities.uncompressed, - child: Text(context.l10n.uncompressed), - ), - SelectItemButton( - value: SourceQualities.high, - child: Text(context.l10n.high), - ), - if (preferences.audioSource != AudioSource.dabMusic) ...[ - SelectItemButton( - value: SourceQualities.medium, - child: Text(context.l10n.medium), - ), - SelectItemButton( - value: SourceQualities.low, - child: Text(context.l10n.low), - ), - ] - ], - onChanged: (value) { - if (value != null) { - preferencesNotifier.setAudioQuality(value); - } - }, - ), - AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.api), - title: Text(context.l10n.audio_source), - value: preferences.audioSource, - options: AudioSource.values - .map((e) => SelectItemButton( - value: e, - child: Text(e.label), - )) - .toList(), - onChanged: (value) { - if (value == null) return; - preferencesNotifier.setAudioSource(value); - }, - ), - AnimatedCrossFade( - duration: const Duration(milliseconds: 300), - crossFadeState: preferences.audioSource != AudioSource.piped - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - firstChild: const SizedBox.shrink(), - secondChild: Consumer( - builder: (context, ref, child) { - final instanceList = ref.watch(pipedInstancesFutureProvider); - - return instanceList.when( - data: (data) { - return AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.piped), - title: Text(context.l10n.piped_instance), - subtitle: Text( - "${context.l10n.piped_description}\n" - "${context.l10n.piped_warning}", - ), - value: preferences.pipedInstance, - showValueWhenUnfolded: false, - trailing: [ - Tooltip( - tooltip: TooltipContainer( - child: Text(context.l10n.add_custom_url), - ).call, - child: IconButton.outline( - icon: const Icon(SpotubeIcons.edit), - size: ButtonSize.small, - onPressed: () { - showDialog( - context: context, - barrierColor: Colors.black.withValues(alpha: 0.5), - builder: (context) => - SettingsPlaybackEditInstanceUrlDialog( - title: context.l10n.piped_instance, - initialValue: preferences.pipedInstance, - onSave: (value) { - preferencesNotifier.setPipedInstance(value); - }, - ), - ); - }, - ), - ) - ], - options: [ - if (data - .none((e) => e.apiUrl == preferences.pipedInstance)) - SelectItemButton( - value: preferences.pipedInstance, - child: Text.rich( - TextSpan( - style: theme.typography.xSmall.copyWith( - color: theme.colorScheme.foreground, - ), - children: [ - TextSpan(text: context.l10n.custom), - const TextSpan(text: "\n"), - TextSpan(text: preferences.pipedInstance), - ], - ), - ), - ), - for (final e in data.sortedBy((e) => e.name)) - SelectItemButton( - value: e.apiUrl, - child: RichText( - text: TextSpan( - style: theme.typography.normal.copyWith( - color: theme.colorScheme.foreground, - ), - children: [ - TextSpan( - text: "${e.name.trim()}\n", - ), - TextSpan( - text: e.locations - .map(countryCodeToEmoji) - .join(""), - style: GoogleFonts.notoColorEmoji(), - ), - ], - ), - ), - ), - ], - onChanged: (value) { - if (value != null) { - preferencesNotifier.setPipedInstance(value); - } - }, - ); - }, - loading: () => const Center( - child: CircularProgressIndicator(), - ), - error: (error, stackTrace) => Text(error.toString()), - ); + if (sourcePresets.presets.isNotEmpty) ...[ + AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.api), + title: Text(context.l10n.streaming_music_codec), + value: sourcePresets.selectedStreamingContainerIndex, + options: [ + for (final MapEntry(:key, value: preset) + in sourcePresets.presets.asMap().entries) + SelectItemButton(value: key, child: Text(preset.name)), + ], + onChanged: (value) { + if (value == null) return; + sourcePresetsNotifier.setSelectedStreamingContainerIndex(value); }, ), - ), - AnimatedCrossFade( - duration: const Duration(milliseconds: 300), - crossFadeState: preferences.audioSource != AudioSource.invidious - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - firstChild: const SizedBox.shrink(), - secondChild: Consumer( - builder: (context, ref, child) { - final instanceList = ref.watch(invidiousInstancesProvider); - - return instanceList.when( - data: (data) { - return AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.piped), - title: Text(context.l10n.invidious_instance), - subtitle: Text( - "${context.l10n.invidious_description}\n" - "${context.l10n.invidious_warning}", - ), - trailing: [ - Tooltip( - tooltip: TooltipContainer( - child: Text(context.l10n.add_custom_url), - ).call, - child: IconButton.outline( - icon: const Icon(SpotubeIcons.edit), - size: ButtonSize.small, - onPressed: () { - showDialog( - context: context, - barrierColor: Colors.black.withValues(alpha: 0.5), - builder: (context) => - SettingsPlaybackEditInstanceUrlDialog( - title: context.l10n.invidious_instance, - initialValue: preferences.invidiousInstance, - onSave: (value) { - preferencesNotifier - .setInvidiousInstance(value); - }, - ), - ); - }, - ), - ) - ], - value: preferences.invidiousInstance, - showValueWhenUnfolded: false, - options: [ - if (data.none((e) => - e.details.uri == preferences.invidiousInstance)) - SelectItemButton( - value: preferences.invidiousInstance, - child: Text.rich( - TextSpan( - style: theme.typography.xSmall.copyWith( - color: theme.colorScheme.foreground, - ), - children: [ - TextSpan(text: context.l10n.custom), - const TextSpan(text: "\n"), - TextSpan(text: preferences.invidiousInstance), - ], - ), - ), - ), - for (final e in data.sortedBy((e) => e.name)) - SelectItemButton( - value: e.details.uri, - child: RichText( - text: TextSpan( - style: theme.typography.normal.copyWith( - color: theme.colorScheme.foreground, - ), - children: [ - TextSpan( - text: "${e.name.trim()}\n", - ), - TextSpan( - text: countryCodeToEmoji( - e.details.region, - ), - style: GoogleFonts.notoColorEmoji(), - ), - ], - ), - ), - ), - ], - onChanged: (value) { - if (value != null) { - preferencesNotifier.setInvidiousInstance(value); - } - }, - ); - }, - loading: () => const Center( - child: CircularProgressIndicator(), - ), - error: (error, stackTrace) => Text(error.toString()), - ); + AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.api), + title: const Text("Streaming music quality"), + value: sourcePresets.selectedStreamingQualityIndex, + options: [ + for (final MapEntry(:key, value: quality) in sourcePresets + .presets[sourcePresets.selectedStreamingContainerIndex] + .qualities + .asMap() + .entries) + SelectItemButton(value: key, child: Text(quality.toString())), + ], + onChanged: (value) { + if (value == null) return; + sourcePresetsNotifier.setSelectedStreamingQualityIndex(value); }, ), - ), - switch (preferences.audioSource) { - AudioSource.youtube => AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.engine), - title: Text(context.l10n.youtube_engine), - value: preferences.youtubeClientEngine, - options: YoutubeClientEngine.values - .where((e) => e.isAvailableForPlatform()) - .map((e) => SelectItemButton( - value: e, - child: Text(e.label), - )) - .toList(), - onChanged: (value) async { - if (value == null) return; - if (value == YoutubeClientEngine.ytDlp) { - final customPath = KVStoreService.getYoutubeEnginePath(value); - if (!await YtDlpEngine.isInstalled() && - (customPath == null || - !await File(customPath).exists()) && - context.mounted) { - final hasInstalled = await showDialog( - context: context, - builder: (context) => - YouTubeEngineNotInstalledDialog(engine: value), - ); - if (hasInstalled != true) return; - } - } - preferencesNotifier.setYoutubeClientEngine(value); - }, - ), - AudioSource.piped || - AudioSource.invidious => - AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.search), - title: Text(context.l10n.search_mode), - value: preferences.searchMode, - options: SearchMode.values - .map((e) => SelectItemButton( - value: e, - child: Text(e.label), - )) - .toList(), - onChanged: (value) { - if (value == null) return; - preferencesNotifier.setSearchMode(value); - }, - ), - _ => const SizedBox.shrink(), - }, - AnimatedCrossFade( - duration: const Duration(milliseconds: 300), - crossFadeState: preferences.searchMode == SearchMode.youtube && - (preferences.audioSource == AudioSource.piped || - preferences.audioSource == AudioSource.youtube || - preferences.audioSource == AudioSource.invidious) - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - firstChild: ListTile( - leading: const Icon(SpotubeIcons.skip), - title: Text(context.l10n.skip_non_music), - trailing: Switch( - value: preferences.skipNonMusic, - onChanged: (state) { - preferencesNotifier.setSkipNonMusic(state); - }, - ), + AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.api), + title: Text(context.l10n.download_music_codec), + value: sourcePresets.selectedDownloadingContainerIndex, + options: [ + for (final MapEntry(:key, value: preset) + in sourcePresets.presets.asMap().entries) + SelectItemButton(value: key, child: Text(preset.name)), + ], + onChanged: (value) { + if (value == null) return; + sourcePresetsNotifier.setSelectedDownloadingContainerIndex(value); + }, ), - secondChild: const SizedBox.shrink(), - ), + AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.api), + title: const Text("Downloading music quality"), + value: sourcePresets.selectedStreamingQualityIndex, + options: [ + for (final MapEntry(:key, value: quality) in sourcePresets + .presets[sourcePresets.selectedDownloadingContainerIndex] + .qualities + .asMap() + .entries) + SelectItemButton(value: key, child: Text(quality.toString())), + ], + onChanged: (value) { + if (value == null) return; + sourcePresetsNotifier.setSelectedStreamingQualityIndex(value); + }, + ), + ], ListTile( title: Text(context.l10n.cache_music), subtitle: kIsMobile @@ -402,50 +137,6 @@ class SettingsPlaybackSection extends HookConsumerWidget { onChanged: preferencesNotifier.setNormalizeAudio, ), ), - if (const [AudioSource.jiosaavn, AudioSource.dabMusic] - .contains(preferences.audioSource) == - false) ...[ - AdaptiveSelectTile( - popupConstraints: const BoxConstraints(maxWidth: 300), - secondary: const Icon(SpotubeIcons.stream), - title: Text(context.l10n.streaming_music_codec), - value: preferences.streamMusicCodec, - showValueWhenUnfolded: false, - options: SourceCodecs.values - .map((e) => SelectItemButton( - value: e, - child: Text( - e.label, - style: theme.typography.small, - ), - )) - .toList(), - onChanged: (value) { - if (value == null) return; - preferencesNotifier.setStreamMusicCodec(value); - }, - ), - AdaptiveSelectTile( - popupConstraints: const BoxConstraints(maxWidth: 300), - secondary: const Icon(SpotubeIcons.file), - title: Text(context.l10n.download_music_codec), - value: preferences.downloadMusicCodec, - showValueWhenUnfolded: false, - options: SourceCodecs.values - .map((e) => SelectItemButton( - value: e, - child: Text( - e.label, - style: theme.typography.small, - ), - )) - .toList(), - onChanged: (value) { - if (value == null) return; - preferencesNotifier.setDownloadMusicCodec(value); - }, - ), - ], ListTile( leading: const Icon(SpotubeIcons.repeat), title: Text(context.l10n.endless_playback), diff --git a/lib/provider/audio_player/audio_player.dart b/lib/provider/audio_player/audio_player.dart index 5db28125..2d569ab5 100644 --- a/lib/provider/audio_player/audio_player.dart +++ b/lib/provider/audio_player/audio_player.dart @@ -12,7 +12,7 @@ import 'package:spotube/provider/audio_player/state.dart'; import 'package:spotube/provider/blacklist_provider.dart'; import 'package:spotube/provider/database/database.dart'; import 'package:spotube/provider/discord_provider.dart'; -import 'package:spotube/provider/server/track_sources.dart'; +import 'package:spotube/provider/server/sourced_track_provider.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/services/logger/logger.dart'; @@ -164,8 +164,8 @@ class AudioPlayerNotifier extends Notifier { final tracks = []; for (final media in playlist.medias) { - final trackQuery = TrackSourceQuery.parseUri(media.uri); - final track = trackGroupedById[trackQuery.id]?.firstOrNull; + final track = trackGroupedById[SpotubeMedia.media(media).track.id] + ?.firstOrNull; if (track != null) { tracks.add(track); } @@ -401,9 +401,8 @@ class AudioPlayerNotifier extends Notifier { final intendedActiveTrack = medias.elementAt(initialIndex); if (intendedActiveTrack.track is! SpotubeLocalTrackObject) { await ref.read( - trackSourcesProvider( - TrackSourceQuery.fromTrack( - intendedActiveTrack.track as SpotubeFullTrackObject), + sourcedTrackProvider( + intendedActiveTrack.track as SpotubeFullTrackObject, ).future, ); } diff --git a/lib/provider/audio_player/audio_player_streams.dart b/lib/provider/audio_player/audio_player_streams.dart index 507e9d49..eff13134 100644 --- a/lib/provider/audio_player/audio_player_streams.dart +++ b/lib/provider/audio_player/audio_player_streams.dart @@ -3,14 +3,13 @@ import 'dart:math'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/models/metadata/metadata.dart'; -import 'package:spotube/models/playback/track_sources.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/audio_player/state.dart'; import 'package:spotube/provider/discord_provider.dart'; import 'package:spotube/provider/history/history.dart'; import 'package:spotube/provider/metadata_plugin/core/scrobble.dart'; import 'package:spotube/provider/metadata_plugin/metadata_plugin_provider.dart'; -import 'package:spotube/provider/server/track_sources.dart'; +import 'package:spotube/provider/server/sourced_track_provider.dart'; import 'package:spotube/provider/skip_segments/skip_segments.dart'; import 'package:spotube/provider/scrobbler/scrobbler.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; @@ -156,9 +155,7 @@ class AudioPlayerStreamListeners { try { await ref.read( - trackSourcesProvider( - TrackSourceQuery.fromTrack(nextTrack as SpotubeFullTrackObject), - ).future, + sourcedTrackProvider(nextTrack as SpotubeFullTrackObject).future, ); } finally { lastTrack = nextTrack.id; diff --git a/lib/provider/audio_player/querying_track_info.dart b/lib/provider/audio_player/querying_track_info.dart index ce99b261..06e9653c 100644 --- a/lib/provider/audio_player/querying_track_info.dart +++ b/lib/provider/audio_player/querying_track_info.dart @@ -1,8 +1,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/models/metadata/metadata.dart'; -import 'package:spotube/models/playback/track_sources.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; -import 'package:spotube/provider/server/track_sources.dart'; +import 'package:spotube/provider/server/sourced_track_provider.dart'; final queryingTrackInfoProvider = Provider((ref) { final audioPlayer = ref.watch(audioPlayerProvider); @@ -16,10 +15,9 @@ final queryingTrackInfoProvider = Provider((ref) { } return ref - .watch(trackSourcesProvider( - TrackSourceQuery.fromTrack( - audioPlayer.activeTrack! as SpotubeFullTrackObject, - ), - )) + .watch( + sourcedTrackProvider( + audioPlayer.activeTrack! as SpotubeFullTrackObject), + ) .isLoading; }); diff --git a/lib/provider/audio_player/sources/invidious_instances_provider.dart b/lib/provider/audio_player/sources/invidious_instances_provider.dart deleted file mode 100644 index c04ac765..00000000 --- a/lib/provider/audio_player/sources/invidious_instances_provider.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:spotube/services/sourced_track/sources/invidious.dart'; - -final invidiousInstancesProvider = FutureProvider((ref) async { - final invidious = ref.watch(invidiousProvider); - - final instances = await invidious.instances(); - - return instances - .where((instance) => instance.details.type == "https") - .toList(); -}); diff --git a/lib/provider/audio_player/sources/piped_instances_provider.dart b/lib/provider/audio_player/sources/piped_instances_provider.dart deleted file mode 100644 index 3c5d5f04..00000000 --- a/lib/provider/audio_player/sources/piped_instances_provider.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:spotube/services/logger/logger.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:piped_client/piped_client.dart'; -import 'package:spotube/services/sourced_track/sources/piped.dart'; - -final pipedInstancesFutureProvider = FutureProvider>( - (ref) async { - try { - final pipedClient = ref.watch(pipedProvider); - - return await pipedClient.instanceList(); - } catch (e, stack) { - AppLogger.reportError(e, stack); - return []; - } - }, -); diff --git a/lib/provider/download_manager_provider.dart b/lib/provider/download_manager_provider.dart index d0112765..bc1de813 100644 --- a/lib/provider/download_manager_provider.dart +++ b/lib/provider/download_manager_provider.dart @@ -2,8 +2,8 @@ import 'dart:async'; import 'dart:io'; import 'package:spotube/models/metadata/metadata.dart'; -import 'package:spotube/models/playback/track_sources.dart'; -import 'package:spotube/provider/server/track_sources.dart'; +import 'package:spotube/provider/metadata_plugin/audio_source/quality_presets.dart'; +import 'package:spotube/provider/server/sourced_track_provider.dart'; import 'package:spotube/services/logger/logger.dart'; import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; @@ -26,7 +26,10 @@ class DownloadManagerProvider extends ChangeNotifier { final (:request, :status) = event; final sourcedTrack = $history.firstWhereOrNull( - (element) => element.getUrlOfCodec(downloadCodec) == request.url, + (element) => + element.getUrlOfQuality( + downloadContainer, downloadQualityIndex) == + request.url, ); if (sourcedTrack == null) return; final track = $backHistory.firstWhereOrNull( @@ -48,7 +51,8 @@ class DownloadManagerProvider extends ChangeNotifier { //? WebA audiotagging is not supported yet //? Although in future by converting weba to opus & then tagging it //? is possible using vorbis comments - downloadCodec == SourceCodecs.weba) { + downloadContainer.name == "weba" || + downloadContainer.name == "webm") { return; } @@ -87,8 +91,13 @@ class DownloadManagerProvider extends ChangeNotifier { String get downloadDirectory => ref.read(userPreferencesProvider.select((s) => s.downloadLocation)); - SourceCodecs get downloadCodec => - ref.read(userPreferencesProvider.select((s) => s.downloadMusicCodec)); + SpotubeAudioSourceContainerPreset get downloadContainer => ref.read( + audioSourcePresetsProvider + .select((s) => s.presets[s.selectedDownloadingContainerIndex]), + ); + + int get downloadQualityIndex => ref.read(audioSourcePresetsProvider + .select((s) => s.selectedDownloadingQualityIndex)); int get $downloadCount => dl .getAllDownloads() @@ -107,7 +116,7 @@ class DownloadManagerProvider extends ChangeNotifier { String getTrackFileUrl(SourcedTrack track) { final name = - "${track.query.title} - ${track.query.artists.join(", ")}.${downloadCodec.name}"; + "${track.query.name} - ${track.query.artists.join(", ")}.${downloadContainer.name}"; return join(downloadDirectory, PrimitiveUtils.toSafeFileName(name)); } @@ -129,13 +138,16 @@ class DownloadManagerProvider extends ChangeNotifier { download.status.value == DownloadStatus.queued, ) .map((e) => e.request.url) - .contains(sourcedTrack.getUrlOfCodec(downloadCodec)!); + .contains(sourcedTrack.getUrlOfQuality( + downloadContainer, + downloadQualityIndex, + )!); } /// For singular downloads Future addToQueue(SpotubeFullTrackObject track) async { final sourcedTrack = await ref.read( - trackSourcesProvider(TrackSourceQuery.fromTrack(track)).future, + sourcedTrackProvider(track).future, ); final savePath = getTrackFileUrl(sourcedTrack); @@ -149,9 +161,9 @@ class DownloadManagerProvider extends ChangeNotifier { await oldFile.rename("$savePath.old"); } - if (sourcedTrack.codec == downloadCodec) { + if (sourcedTrack.qualityPreset == downloadContainer) { final downloadTask = await dl.addDownload( - sourcedTrack.getUrlOfCodec(downloadCodec)!, + sourcedTrack.getUrlOfQuality(downloadContainer, downloadQualityIndex)!, savePath, ); if (downloadTask != null) { @@ -159,18 +171,13 @@ class DownloadManagerProvider extends ChangeNotifier { } } else { $backHistory.add(track); - final sourcedTrack = await ref - .read( - trackSourcesProvider( - TrackSourceQuery.fromTrack(track), - ).future, - ) - .then((d) { + final sourcedTrack = + await ref.read(sourcedTrackProvider(track).future).then((d) { $backHistory.remove(track); return d; }); final downloadTask = await dl.addDownload( - sourcedTrack.getUrlOfCodec(downloadCodec)!, + sourcedTrack.getUrlOfQuality(downloadContainer, downloadQualityIndex)!, savePath, ); if (downloadTask != null) { @@ -203,18 +210,21 @@ class DownloadManagerProvider extends ChangeNotifier { Future removeFromQueue(SpotubeFullTrackObject track) async { final sourcedTrack = await mapToSourcedTrack(track); - await dl.removeDownload(sourcedTrack.getUrlOfCodec(downloadCodec)!); + await dl.removeDownload( + sourcedTrack.getUrlOfQuality(downloadContainer, downloadQualityIndex)!); $history.remove(sourcedTrack); } Future pause(SpotubeFullTrackObject track) async { final sourcedTrack = await mapToSourcedTrack(track); - return dl.pauseDownload(sourcedTrack.getUrlOfCodec(downloadCodec)!); + return dl.pauseDownload( + sourcedTrack.getUrlOfQuality(downloadContainer, downloadQualityIndex)!); } Future resume(SpotubeFullTrackObject track) async { final sourcedTrack = await mapToSourcedTrack(track); - return dl.resumeDownload(sourcedTrack.getUrlOfCodec(downloadCodec)!); + return dl.resumeDownload( + sourcedTrack.getUrlOfQuality(downloadContainer, downloadQualityIndex)!); } Future retry(SpotubeFullTrackObject track) { @@ -223,7 +233,8 @@ class DownloadManagerProvider extends ChangeNotifier { void cancel(SpotubeFullTrackObject track) async { final sourcedTrack = await mapToSourcedTrack(track); - return dl.cancelDownload(sourcedTrack.getUrlOfCodec(downloadCodec)!); + return dl.cancelDownload( + sourcedTrack.getUrlOfQuality(downloadContainer, downloadQualityIndex)!); } void cancelAll() { @@ -241,9 +252,7 @@ class DownloadManagerProvider extends ChangeNotifier { return historicTrack; } - final sourcedTrack = await ref.read( - trackSourcesProvider(TrackSourceQuery.fromTrack(track)).future, - ); + final sourcedTrack = await ref.read(sourcedTrackProvider(track).future); return sourcedTrack; } @@ -257,7 +266,10 @@ class DownloadManagerProvider extends ChangeNotifier { if (sourcedTrack == null) { return null; } - return dl.getDownload(sourcedTrack.getUrlOfCodec(downloadCodec)!)?.status; + return dl + .getDownload(sourcedTrack.getUrlOfQuality( + downloadContainer, downloadQualityIndex)!) + ?.status; } ValueNotifier? getProgressNotifier(SpotubeFullTrackObject track) { @@ -267,7 +279,10 @@ class DownloadManagerProvider extends ChangeNotifier { if (sourcedTrack == null) { return null; } - return dl.getDownload(sourcedTrack.getUrlOfCodec(downloadCodec)!)?.progress; + return dl + .getDownload(sourcedTrack.getUrlOfQuality( + downloadContainer, downloadQualityIndex)!) + ?.progress; } } diff --git a/lib/provider/metadata_plugin/audio_source/quality_label.dart b/lib/provider/metadata_plugin/audio_source/quality_label.dart new file mode 100644 index 00000000..7d1dc95a --- /dev/null +++ b/lib/provider/metadata_plugin/audio_source/quality_label.dart @@ -0,0 +1,12 @@ +import 'package:riverpod/riverpod.dart'; +import 'package:spotube/provider/metadata_plugin/audio_source/quality_presets.dart'; + +final audioSourceQualityLabelProvider = Provider((ref) { + final sourceQuality = ref.watch(audioSourcePresetsProvider); + final sourceContainer = + sourceQuality.presets[sourceQuality.selectedStreamingContainerIndex]; + final quality = + sourceContainer.qualities[sourceQuality.selectedStreamingQualityIndex]; + + return "${sourceContainer.name} • ${quality.toString()}"; +}); diff --git a/lib/provider/metadata_plugin/audio_source/quality_presets.dart b/lib/provider/metadata_plugin/audio_source/quality_presets.dart new file mode 100644 index 00000000..9cc7dc44 --- /dev/null +++ b/lib/provider/metadata_plugin/audio_source/quality_presets.dart @@ -0,0 +1,120 @@ +import 'dart:convert'; + +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:spotube/models/metadata/metadata.dart'; +import 'package:spotube/provider/metadata_plugin/metadata_plugin_provider.dart'; +import 'package:spotube/services/audio_player/audio_player.dart'; + +part 'quality_presets.g.dart'; +part 'quality_presets.freezed.dart'; + +@freezed +class AudioSourcePresetsState with _$AudioSourcePresetsState { + factory AudioSourcePresetsState({ + @Default([]) final List presets, + @Default(0) final int selectedStreamingQualityIndex, + @Default(0) final int selectedStreamingContainerIndex, + @Default(0) final int selectedDownloadingQualityIndex, + @Default(0) final int selectedDownloadingContainerIndex, + }) = _AudioSourcePresetsState; + + factory AudioSourcePresetsState.fromJson(Map json) => + _$AudioSourcePresetsStateFromJson(json); +} + +class AudioSourceAvailableQualityPresetsNotifier + extends Notifier { + @override + build() { + ref.watch(audioSourcePluginProvider); + + _initialize(); + + listenSelf((previous, next) { + final isNewLossless = + next.presets.elementAtOrNull(next.selectedStreamingContainerIndex) + is SpotubeAudioSourceContainerPresetLossless; + final isOldLossless = previous?.presets + .elementAtOrNull(previous.selectedStreamingContainerIndex) + is SpotubeAudioSourceContainerPresetLossless; + if (!isOldLossless && isNewLossless) { + audioPlayer.setDemuxerBufferSize(6 * 1024 * 1024); // 6MB + } else if (isOldLossless && !isNewLossless) { + audioPlayer.setDemuxerBufferSize(4 * 1024 * 1024); // 4MB + } + }); + + return AudioSourcePresetsState(); + } + + void _initialize() async { + final audioSource = await ref.read(audioSourcePluginProvider.future); + final audioSourceConfig = await ref.read( + metadataPluginsProvider + .selectAsync((data) => data.defaultAudioSourcePluginConfig), + ); + if (audioSource == null || audioSourceConfig == null) { + throw Exception("Dude wat?"); + } + final preferences = await SharedPreferences.getInstance(); + final persistedStateStr = + preferences.getString("audioSourceState-${audioSourceConfig.slug}"); + + if (persistedStateStr != null) { + state = AudioSourcePresetsState.fromJson(jsonDecode(persistedStateStr)); + } else { + state = AudioSourcePresetsState( + presets: audioSource.audioSource.supportedPresets, + ); + } + } + + void setSelectedStreamingContainerIndex(int index) { + state = state.copyWith( + selectedStreamingContainerIndex: index, + selectedStreamingQualityIndex: + 0, // Resetting both because it's a different quality + ); + _updatePreferences(); + } + + void setSelectedStreamingQualityIndex(int index) { + state = state.copyWith(selectedStreamingQualityIndex: index); + _updatePreferences(); + } + + void setSelectedDownloadingContainerIndex(int index) { + state = state.copyWith( + selectedDownloadingContainerIndex: index, + selectedDownloadingQualityIndex: + 0, // Resetting both because it's a different quality + ); + _updatePreferences(); + } + + void setSelectedDownloadingQualityIndex(int index) { + state = state.copyWith(selectedDownloadingQualityIndex: index); + _updatePreferences(); + } + + void _updatePreferences() async { + final audioSourceConfig = await ref.read(metadataPluginsProvider + .selectAsync((data) => data.defaultAudioSourcePluginConfig)); + if (audioSourceConfig == null) { + throw Exception("Dude wat?"); + } + + final preferences = await SharedPreferences.getInstance(); + await preferences.setString( + "audioSourceState-${audioSourceConfig.slug}", + jsonEncode(state), + ); + } +} + +final audioSourcePresetsProvider = NotifierProvider< + AudioSourceAvailableQualityPresetsNotifier, AudioSourcePresetsState>( + () => AudioSourceAvailableQualityPresetsNotifier(), +); diff --git a/lib/provider/metadata_plugin/audio_source/quality_presets.freezed.dart b/lib/provider/metadata_plugin/audio_source/quality_presets.freezed.dart new file mode 100644 index 00000000..a8e0c9f7 --- /dev/null +++ b/lib/provider/metadata_plugin/audio_source/quality_presets.freezed.dart @@ -0,0 +1,289 @@ +// 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 'quality_presets.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'); + +AudioSourcePresetsState _$AudioSourcePresetsStateFromJson( + Map json) { + return _AudioSourcePresetsState.fromJson(json); +} + +/// @nodoc +mixin _$AudioSourcePresetsState { + List get presets => + throw _privateConstructorUsedError; + int get selectedStreamingQualityIndex => throw _privateConstructorUsedError; + int get selectedStreamingContainerIndex => throw _privateConstructorUsedError; + int get selectedDownloadingQualityIndex => throw _privateConstructorUsedError; + int get selectedDownloadingContainerIndex => + throw _privateConstructorUsedError; + + /// Serializes this AudioSourcePresetsState to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of AudioSourcePresetsState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $AudioSourcePresetsStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AudioSourcePresetsStateCopyWith<$Res> { + factory $AudioSourcePresetsStateCopyWith(AudioSourcePresetsState value, + $Res Function(AudioSourcePresetsState) then) = + _$AudioSourcePresetsStateCopyWithImpl<$Res, AudioSourcePresetsState>; + @useResult + $Res call( + {List presets, + int selectedStreamingQualityIndex, + int selectedStreamingContainerIndex, + int selectedDownloadingQualityIndex, + int selectedDownloadingContainerIndex}); +} + +/// @nodoc +class _$AudioSourcePresetsStateCopyWithImpl<$Res, + $Val extends AudioSourcePresetsState> + implements $AudioSourcePresetsStateCopyWith<$Res> { + _$AudioSourcePresetsStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of AudioSourcePresetsState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? presets = null, + Object? selectedStreamingQualityIndex = null, + Object? selectedStreamingContainerIndex = null, + Object? selectedDownloadingQualityIndex = null, + Object? selectedDownloadingContainerIndex = null, + }) { + return _then(_value.copyWith( + presets: null == presets + ? _value.presets + : presets // ignore: cast_nullable_to_non_nullable + as List, + selectedStreamingQualityIndex: null == selectedStreamingQualityIndex + ? _value.selectedStreamingQualityIndex + : selectedStreamingQualityIndex // ignore: cast_nullable_to_non_nullable + as int, + selectedStreamingContainerIndex: null == selectedStreamingContainerIndex + ? _value.selectedStreamingContainerIndex + : selectedStreamingContainerIndex // ignore: cast_nullable_to_non_nullable + as int, + selectedDownloadingQualityIndex: null == selectedDownloadingQualityIndex + ? _value.selectedDownloadingQualityIndex + : selectedDownloadingQualityIndex // ignore: cast_nullable_to_non_nullable + as int, + selectedDownloadingContainerIndex: null == + selectedDownloadingContainerIndex + ? _value.selectedDownloadingContainerIndex + : selectedDownloadingContainerIndex // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$AudioSourcePresetsStateImplCopyWith<$Res> + implements $AudioSourcePresetsStateCopyWith<$Res> { + factory _$$AudioSourcePresetsStateImplCopyWith( + _$AudioSourcePresetsStateImpl value, + $Res Function(_$AudioSourcePresetsStateImpl) then) = + __$$AudioSourcePresetsStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {List presets, + int selectedStreamingQualityIndex, + int selectedStreamingContainerIndex, + int selectedDownloadingQualityIndex, + int selectedDownloadingContainerIndex}); +} + +/// @nodoc +class __$$AudioSourcePresetsStateImplCopyWithImpl<$Res> + extends _$AudioSourcePresetsStateCopyWithImpl<$Res, + _$AudioSourcePresetsStateImpl> + implements _$$AudioSourcePresetsStateImplCopyWith<$Res> { + __$$AudioSourcePresetsStateImplCopyWithImpl( + _$AudioSourcePresetsStateImpl _value, + $Res Function(_$AudioSourcePresetsStateImpl) _then) + : super(_value, _then); + + /// Create a copy of AudioSourcePresetsState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? presets = null, + Object? selectedStreamingQualityIndex = null, + Object? selectedStreamingContainerIndex = null, + Object? selectedDownloadingQualityIndex = null, + Object? selectedDownloadingContainerIndex = null, + }) { + return _then(_$AudioSourcePresetsStateImpl( + presets: null == presets + ? _value._presets + : presets // ignore: cast_nullable_to_non_nullable + as List, + selectedStreamingQualityIndex: null == selectedStreamingQualityIndex + ? _value.selectedStreamingQualityIndex + : selectedStreamingQualityIndex // ignore: cast_nullable_to_non_nullable + as int, + selectedStreamingContainerIndex: null == selectedStreamingContainerIndex + ? _value.selectedStreamingContainerIndex + : selectedStreamingContainerIndex // ignore: cast_nullable_to_non_nullable + as int, + selectedDownloadingQualityIndex: null == selectedDownloadingQualityIndex + ? _value.selectedDownloadingQualityIndex + : selectedDownloadingQualityIndex // ignore: cast_nullable_to_non_nullable + as int, + selectedDownloadingContainerIndex: null == + selectedDownloadingContainerIndex + ? _value.selectedDownloadingContainerIndex + : selectedDownloadingContainerIndex // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$AudioSourcePresetsStateImpl implements _AudioSourcePresetsState { + _$AudioSourcePresetsStateImpl( + {final List presets = const [], + this.selectedStreamingQualityIndex = 0, + this.selectedStreamingContainerIndex = 0, + this.selectedDownloadingQualityIndex = 0, + this.selectedDownloadingContainerIndex = 0}) + : _presets = presets; + + factory _$AudioSourcePresetsStateImpl.fromJson(Map json) => + _$$AudioSourcePresetsStateImplFromJson(json); + + final List _presets; + @override + @JsonKey() + List get presets { + if (_presets is EqualUnmodifiableListView) return _presets; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_presets); + } + + @override + @JsonKey() + final int selectedStreamingQualityIndex; + @override + @JsonKey() + final int selectedStreamingContainerIndex; + @override + @JsonKey() + final int selectedDownloadingQualityIndex; + @override + @JsonKey() + final int selectedDownloadingContainerIndex; + + @override + String toString() { + return 'AudioSourcePresetsState(presets: $presets, selectedStreamingQualityIndex: $selectedStreamingQualityIndex, selectedStreamingContainerIndex: $selectedStreamingContainerIndex, selectedDownloadingQualityIndex: $selectedDownloadingQualityIndex, selectedDownloadingContainerIndex: $selectedDownloadingContainerIndex)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AudioSourcePresetsStateImpl && + const DeepCollectionEquality().equals(other._presets, _presets) && + (identical(other.selectedStreamingQualityIndex, + selectedStreamingQualityIndex) || + other.selectedStreamingQualityIndex == + selectedStreamingQualityIndex) && + (identical(other.selectedStreamingContainerIndex, + selectedStreamingContainerIndex) || + other.selectedStreamingContainerIndex == + selectedStreamingContainerIndex) && + (identical(other.selectedDownloadingQualityIndex, + selectedDownloadingQualityIndex) || + other.selectedDownloadingQualityIndex == + selectedDownloadingQualityIndex) && + (identical(other.selectedDownloadingContainerIndex, + selectedDownloadingContainerIndex) || + other.selectedDownloadingContainerIndex == + selectedDownloadingContainerIndex)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(_presets), + selectedStreamingQualityIndex, + selectedStreamingContainerIndex, + selectedDownloadingQualityIndex, + selectedDownloadingContainerIndex); + + /// Create a copy of AudioSourcePresetsState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$AudioSourcePresetsStateImplCopyWith<_$AudioSourcePresetsStateImpl> + get copyWith => __$$AudioSourcePresetsStateImplCopyWithImpl< + _$AudioSourcePresetsStateImpl>(this, _$identity); + + @override + Map toJson() { + return _$$AudioSourcePresetsStateImplToJson( + this, + ); + } +} + +abstract class _AudioSourcePresetsState implements AudioSourcePresetsState { + factory _AudioSourcePresetsState( + {final List presets, + final int selectedStreamingQualityIndex, + final int selectedStreamingContainerIndex, + final int selectedDownloadingQualityIndex, + final int selectedDownloadingContainerIndex}) = + _$AudioSourcePresetsStateImpl; + + factory _AudioSourcePresetsState.fromJson(Map json) = + _$AudioSourcePresetsStateImpl.fromJson; + + @override + List get presets; + @override + int get selectedStreamingQualityIndex; + @override + int get selectedStreamingContainerIndex; + @override + int get selectedDownloadingQualityIndex; + @override + int get selectedDownloadingContainerIndex; + + /// Create a copy of AudioSourcePresetsState + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$AudioSourcePresetsStateImplCopyWith<_$AudioSourcePresetsStateImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/provider/metadata_plugin/audio_source/quality_presets.g.dart b/lib/provider/metadata_plugin/audio_source/quality_presets.g.dart new file mode 100644 index 00000000..f3d8fd41 --- /dev/null +++ b/lib/provider/metadata_plugin/audio_source/quality_presets.g.dart @@ -0,0 +1,38 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'quality_presets.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$AudioSourcePresetsStateImpl _$$AudioSourcePresetsStateImplFromJson( + Map json) => + _$AudioSourcePresetsStateImpl( + presets: (json['presets'] as List?) + ?.map((e) => SpotubeAudioSourceContainerPreset.fromJson( + Map.from(e as Map))) + .toList() ?? + const [], + selectedStreamingQualityIndex: + (json['selectedStreamingQualityIndex'] as num?)?.toInt() ?? 0, + selectedStreamingContainerIndex: + (json['selectedStreamingContainerIndex'] as num?)?.toInt() ?? 0, + selectedDownloadingQualityIndex: + (json['selectedDownloadingQualityIndex'] as num?)?.toInt() ?? 0, + selectedDownloadingContainerIndex: + (json['selectedDownloadingContainerIndex'] as num?)?.toInt() ?? 0, + ); + +Map _$$AudioSourcePresetsStateImplToJson( + _$AudioSourcePresetsStateImpl instance) => + { + 'presets': instance.presets.map((e) => e.toJson()).toList(), + 'selectedStreamingQualityIndex': instance.selectedStreamingQualityIndex, + 'selectedStreamingContainerIndex': + instance.selectedStreamingContainerIndex, + 'selectedDownloadingQualityIndex': + instance.selectedDownloadingQualityIndex, + 'selectedDownloadingContainerIndex': + instance.selectedDownloadingContainerIndex, + }; diff --git a/lib/provider/server/active_track_sources.dart b/lib/provider/server/active_track_sources.dart index 5b64dc26..603ca0e4 100644 --- a/lib/provider/server/active_track_sources.dart +++ b/lib/provider/server/active_track_sources.dart @@ -1,14 +1,13 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/models/metadata/metadata.dart'; -import 'package:spotube/models/playback/track_sources.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; -import 'package:spotube/provider/server/track_sources.dart'; +import 'package:spotube/provider/server/sourced_track_provider.dart'; import 'package:spotube/services/sourced_track/sourced_track.dart'; final activeTrackSourcesProvider = FutureProvider< ({ SourcedTrack? source, - TrackSourcesNotifier? notifier, + SourcedTrackNotifier? notifier, SpotubeTrackObject track, })?>((ref) async { final audioPlayerState = ref.watch(audioPlayerProvider); @@ -25,13 +24,15 @@ final activeTrackSourcesProvider = FutureProvider< ); } - final trackQuery = TrackSourceQuery.fromTrack( - audioPlayerState.activeTrack! as SpotubeFullTrackObject, + final sourcedTrack = await ref.watch( + sourcedTrackProvider( + audioPlayerState.activeTrack! as SpotubeFullTrackObject, + ).future, ); - - final sourcedTrack = await ref.watch(trackSourcesProvider(trackQuery).future); final sourcedTrackNotifier = ref.watch( - trackSourcesProvider(trackQuery).notifier, + sourcedTrackProvider( + audioPlayerState.activeTrack! as SpotubeFullTrackObject, + ).notifier, ); return ( diff --git a/lib/provider/server/routes/playback.dart b/lib/provider/server/routes/playback.dart index 7155edca..ec3a98a1 100644 --- a/lib/provider/server/routes/playback.dart +++ b/lib/provider/server/routes/playback.dart @@ -11,12 +11,11 @@ import 'package:path/path.dart'; import 'package:shelf/shelf.dart'; import 'package:spotube/models/metadata/metadata.dart'; import 'package:spotube/models/parser/range_headers.dart'; -import 'package:spotube/models/playback/track_sources.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/audio_player/state.dart'; import 'package:spotube/provider/server/active_track_sources.dart'; -import 'package:spotube/provider/server/track_sources.dart'; +import 'package:spotube/provider/server/sourced_track_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/logger/logger.dart'; @@ -49,26 +48,30 @@ class ServerPlaybackRoutes { return join( await UserPreferencesNotifier.getMusicCacheDir(), ServiceUtils.sanitizeFilename( - '${track.query.title} - ${track.query.artists.join(",")} (${track.info.id}).${track.codec.name}', + '${track.query.name} - ${track.query.artists.join(",")} (${track.info.id}).${track.qualityPreset!.name}', ), ); } Future _getSourcedTrack( - Request request, String trackId) async { + Request request, + String trackId, + ) async { final track = playlist.tracks.firstWhere((element) => element.id == trackId); final activeSourcedTrack = await ref.read(activeTrackSourcesProvider.future); + + final media = audioPlayer.playlist.medias + .firstWhere((e) => e.uri == request.requestedUri.toString()); + final spotubeMedia = + media is SpotubeMedia ? media : SpotubeMedia.media(media); final sourcedTrack = activeSourcedTrack?.track.id == track.id ? activeSourcedTrack?.source : await ref.read( - trackSourcesProvider( - //! Use [Request.requestedUri] as it contains full https url. - //! [Request.url] will exclude and starts relatively. (streams/... basically) - TrackSourceQuery.parseUri(request.requestedUri.toString()), - ).future, + sourcedTrackProvider(spotubeMedia.track as SpotubeFullTrackObject) + .future, ); return sourcedTrack; @@ -79,7 +82,7 @@ class ServerPlaybackRoutes { SourcedTrack track, ) async { AppLogger.log.i( - "HEAD request for track: ${track.query.title}\n" + "HEAD request for track: ${track.query.name}\n" "Headers: ${request.headers}", ); @@ -91,7 +94,7 @@ class ServerPlaybackRoutes { return dio_lib.Response( statusCode: 200, headers: Headers.fromMap({ - "content-type": ["audio/${track.codec.name}"], + "content-type": ["audio/${track.qualityPreset!.name}"], "content-length": ["$fileLength"], "accept-ranges": ["bytes"], "content-range": ["bytes 0-$fileLength/$fileLength"], @@ -102,7 +105,7 @@ class ServerPlaybackRoutes { String url = track.url ?? await ref - .read(trackSourcesProvider(track.query).notifier) + .read(sourcedTrackProvider(track.query).notifier) .swapWithNextSibling() .then((track) => track.url!); @@ -128,7 +131,7 @@ class ServerPlaybackRoutes { Map headers, ) async { AppLogger.log.i( - "GET request for track: ${track.query.title}\n" + "GET request for track: ${track.query.name}\n" "Headers: ${request.headers}", ); @@ -142,7 +145,7 @@ class ServerPlaybackRoutes { response: dio_lib.Response( statusCode: 200, headers: Headers.fromMap({ - "content-type": ["audio/${track.codec.name}"], + "content-type": ["audio/${track.qualityPreset!.name}"], "content-length": ["$cachedFileLength"], "accept-ranges": ["bytes"], "content-range": ["bytes 0-$cachedFileLength/$cachedFileLength"], @@ -157,7 +160,7 @@ class ServerPlaybackRoutes { String url = track.url ?? await ref - .read(trackSourcesProvider(track.query).notifier) + .read(sourcedTrackProvider(track.query).notifier) .swapWithNextSibling() .then((track) => track.url!); @@ -179,7 +182,7 @@ class ServerPlaybackRoutes { AppLogger.reportError(e, stack); final sourcedTrack = await ref - .read(trackSourcesProvider(track.query).notifier) + .read(sourcedTrackProvider(track.query).notifier) .refreshStreamingUrl(); url = sourcedTrack.url!; @@ -205,11 +208,9 @@ class ServerPlaybackRoutes { ); } - if (headers["range"] == "bytes=0-" && track.codec == SourceCodecs.flac) { - final bufferSize = - userPreferences.audioQuality == SourceQualities.uncompressed - ? 6 * 1024 * 1024 // 6MB for lossless - : 4 * 1024 * 1024; // 4MB for lossy + if (headers["range"] == "bytes=0-" && + track.qualityPreset is SpotubeAudioSourceContainerPresetLossless) { + const bufferSize = 6 * 1024 * 1024; // 6MB for lossless final endRange = min( bufferSize, @@ -227,7 +228,7 @@ class ServerPlaybackRoutes { final res = await dio.get(url, options: options); AppLogger.log.i( - "Response for track: ${track.query.title}\n" + "Response for track: ${track.query.name}\n" "Status Code: ${res.statusCode}\n" "Headers: ${res.headers.map}", ); @@ -261,7 +262,9 @@ class ServerPlaybackRoutes { await trackPartialCacheFile.rename(trackCacheFile.path); } - if (contentRange.total == fileLength && track.codec != SourceCodecs.weba) { + if (contentRange.total == fileLength && + track.qualityPreset!.name != "webm" || + track.qualityPreset!.name != "weba") { final playlistTrack = playlist.tracks.firstWhereOrNull( (element) => element.id == track.query.id, ); diff --git a/lib/provider/server/sourced_track_provider.dart b/lib/provider/server/sourced_track_provider.dart new file mode 100644 index 00000000..7934ecc7 --- /dev/null +++ b/lib/provider/server/sourced_track_provider.dart @@ -0,0 +1,49 @@ +import 'dart:async'; + +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/models/metadata/metadata.dart'; +import 'package:spotube/provider/metadata_plugin/audio_source/quality_presets.dart'; +import 'package:spotube/provider/metadata_plugin/metadata_plugin_provider.dart'; +import 'package:spotube/services/sourced_track/sourced_track.dart'; + +class SourcedTrackNotifier + extends FamilyAsyncNotifier { + @override + FutureOr build(query) { + ref.watch(audioSourcePluginProvider); + ref.watch(audioSourcePresetsProvider); + + return SourcedTrack.fetchFromTrack(query: query, ref: ref); + } + + Future refreshStreamingUrl() async { + return await update((prev) async { + return await prev.refreshStream(); + }); + } + + Future copyWithSibling() async { + return await update((prev) async { + return prev.copyWithSibling(); + }); + } + + Future swapWithSibling( + SpotubeAudioSourceMatchObject sibling, + ) async { + return await update((prev) async { + return await prev.swapWithSibling(sibling) ?? prev; + }); + } + + Future swapWithNextSibling() async { + return await update((prev) async { + return await prev.swapWithSibling(prev.siblings.first) as SourcedTrack; + }); + } +} + +final sourcedTrackProvider = AsyncNotifierProviderFamily( + () => SourcedTrackNotifier(), +); diff --git a/lib/provider/server/track_sources.dart b/lib/provider/server/track_sources.dart deleted file mode 100644 index 24502471..00000000 --- a/lib/provider/server/track_sources.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'dart:async'; - -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotube/models/playback/track_sources.dart'; -import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; -import 'package:spotube/services/sourced_track/sourced_track.dart'; - -class TrackSourcesNotifier - extends FamilyAsyncNotifier { - @override - FutureOr build(query) { - ref.watch(userPreferencesProvider.select((p) => p.audioQuality)); - ref.watch(userPreferencesProvider.select((p) => p.audioSource)); - ref.watch(userPreferencesProvider.select((p) => p.streamMusicCodec)); - ref.watch(userPreferencesProvider.select((p) => p.downloadMusicCodec)); - - return SourcedTrack.fetchFromQuery(query: query, ref: ref); - } - - Future refreshStreamingUrl() async { - return await update((prev) async { - return await prev.refreshStream(); - }); - } - - Future copyWithSibling() async { - return await update((prev) async { - return prev.copyWithSibling(); - }); - } - - Future swapWithSibling(TrackSourceInfo sibling) async { - return await update((prev) async { - return await prev.swapWithSibling(sibling) ?? prev; - }); - } - - Future swapWithNextSibling() async { - return await update((prev) async { - return await prev.swapWithSibling(prev.siblings.first) as SourcedTrack; - }); - } -} - -final trackSourcesProvider = AsyncNotifierProviderFamily( - () => TrackSourcesNotifier(), -); diff --git a/lib/provider/skip_segments/skip_segments.dart b/lib/provider/skip_segments/skip_segments.dart index accccddd..dc06f326 100644 --- a/lib/provider/skip_segments/skip_segments.dart +++ b/lib/provider/skip_segments/skip_segments.dart @@ -86,18 +86,10 @@ final segmentProvider = FutureProvider( if (snapshot == null) return null; final (:track, :source, :notifier) = snapshot; if (track is SpotubeLocalTrackObject) return null; - if (source!.source case AudioSource.jiosaavn) return null; + if (!source!.source.toLowerCase().contains("youtube")) return null; - final skipNonMusic = ref.watch( - userPreferencesProvider.select( - (s) { - final isPipedYTMusicMode = s.audioSource == AudioSource.piped && - s.searchMode == SearchMode.youtubeMusic; - - return s.skipNonMusic && !isPipedYTMusicMode; - }, - ), - ); + final skipNonMusic = + ref.watch(userPreferencesProvider.select((s) => s.skipNonMusic)); if (!skipNonMusic) { return SourcedSegments(segments: [], source: source.info.id); diff --git a/lib/provider/user_preferences/user_preferences_provider.dart b/lib/provider/user_preferences/user_preferences_provider.dart index 9bc64f4f..0b43d043 100644 --- a/lib/provider/user_preferences/user_preferences_provider.dart +++ b/lib/provider/user_preferences/user_preferences_provider.dart @@ -53,7 +53,6 @@ class UserPreferencesNotifier extends Notifier { } await audioPlayer.setAudioNormalization(state.normalizeAudio); - await _updatePlayerBufferSize(event.audioQuality, state.audioQuality); } catch (e, stack) { AppLogger.reportError(e, stack); } @@ -79,24 +78,6 @@ class UserPreferencesNotifier extends Notifier { }); } - /// Sets audio player's buffer size based on the selected audio quality - /// Uncompressed quality gets a larger buffer size for smoother playback - /// while other qualities use a standard buffer size. - Future _updatePlayerBufferSize( - SourceQualities newQuality, - SourceQualities oldQuality, - ) async { - if (newQuality == SourceQualities.uncompressed) { - audioPlayer.setDemuxerBufferSize(6 * 1024 * 1024); // 6MB - return; - } - - if (oldQuality == SourceQualities.uncompressed && - newQuality != SourceQualities.uncompressed) { - audioPlayer.setDemuxerBufferSize(4 * 1024 * 1024); // 4MB - } - } - Future setData(PreferencesTableCompanion data) async { final db = ref.read(databaseProvider); @@ -137,14 +118,6 @@ class UserPreferencesNotifier extends Notifier { } } - void setStreamMusicCodec(SourceCodecs codec) { - setData(PreferencesTableCompanion(streamMusicCodec: Value(codec))); - } - - void setDownloadMusicCodec(SourceCodecs codec) { - setData(PreferencesTableCompanion(downloadMusicCodec: Value(codec))); - } - void setThemeMode(ThemeMode mode) { setData(PreferencesTableCompanion(themeMode: Value(mode))); } @@ -171,11 +144,6 @@ class UserPreferencesNotifier extends Notifier { setData(PreferencesTableCompanion(checkUpdate: Value(check))); } - void setAudioQuality(SourceQualities quality) { - setData(PreferencesTableCompanion(audioQuality: Value(quality))); - _updatePlayerBufferSize(quality, state.audioQuality); - } - void setDownloadLocation(String downloadDir) { if (downloadDir.isEmpty) return; setData(PreferencesTableCompanion(downloadLocation: Value(downloadDir))); @@ -206,14 +174,6 @@ class UserPreferencesNotifier extends Notifier { setData(PreferencesTableCompanion(locale: Value(locale))); } - void setPipedInstance(String instance) { - setData(PreferencesTableCompanion(pipedInstance: Value(instance))); - } - - void setInvidiousInstance(String instance) { - setData(PreferencesTableCompanion(invidiousInstance: Value(instance))); - } - void setSearchMode(SearchMode mode) { setData(PreferencesTableCompanion(searchMode: Value(mode))); } @@ -222,27 +182,6 @@ class UserPreferencesNotifier extends Notifier { setData(PreferencesTableCompanion(skipNonMusic: Value(skip))); } - void setAudioSource(AudioSource type) { - switch ((type, state.audioQuality)) { - // DAB music only supports high quality/uncompressed streams - case ( - AudioSource.dabMusic, - SourceQualities.low || SourceQualities.medium - ): - setAudioQuality(SourceQualities.high); - break; - // If the user switches from DAB music to other sources and has - // uncompressed quality selected, downgrade to high quality - case (!= AudioSource.dabMusic, SourceQualities.uncompressed): - setAudioQuality(SourceQualities.high); - break; - default: - break; - } - - setData(PreferencesTableCompanion(audioSource: Value(type))); - } - void setYoutubeClientEngine(YoutubeClientEngine engine) { setData(PreferencesTableCompanion(youtubeClientEngine: Value(engine))); } diff --git a/lib/services/audio_player/audio_player.dart b/lib/services/audio_player/audio_player.dart index 262b9d10..a30fafba 100644 --- a/lib/services/audio_player/audio_player.dart +++ b/lib/services/audio_player/audio_player.dart @@ -2,7 +2,6 @@ import 'dart:io'; import 'package:media_kit/media_kit.dart' hide Track; import 'package:spotube/models/metadata/metadata.dart'; -import 'package:spotube/models/playback/track_sources.dart'; import 'package:spotube/services/logger/logger.dart'; import 'package:flutter/foundation.dart'; import 'package:spotube/services/audio_player/custom_player.dart'; @@ -22,21 +21,9 @@ class SpotubeMedia extends mk.Media { static String get _host => kIsWindows ? "localhost" : InternetAddress.anyIPv4.address; - static String _queries(SpotubeFullTrackObject track) { - final params = TrackSourceQuery.fromTrack(track).toJson(); - - return params.entries - .map((e) => - "${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value is List ? e.value.join(",") : e.value.toString())}") - .join("&"); - } - final SpotubeTrackObject track; - SpotubeMedia( - this.track, { - Map? extras, - super.httpHeaders, - }) : assert( + SpotubeMedia(this.track) + : assert( track is SpotubeLocalTrackObject || track is SpotubeFullTrackObject, "Track must be a either a local track or a full track object with ISRC", ), @@ -44,8 +31,14 @@ class SpotubeMedia extends mk.Media { super( track is SpotubeLocalTrackObject ? track.path - : "http://$_host:$serverPort/stream/${track.id}?${_queries(track as SpotubeFullTrackObject)}", + : "http://$_host:$serverPort/stream/${track.id}", + extras: track.toJson(), ); + + factory SpotubeMedia.media(Media media) { + assert(media.extras != null, "[Media] must have extra metadata set"); + return SpotubeMedia(SpotubeFullTrackObject.fromJson(media.extras!)); + } } abstract class AudioPlayerInterface { diff --git a/lib/services/sourced_track/exceptions.dart b/lib/services/sourced_track/exceptions.dart index c841e1e2..4817c9fb 100644 --- a/lib/services/sourced_track/exceptions.dart +++ b/lib/services/sourced_track/exceptions.dart @@ -1,12 +1,12 @@ -import 'package:spotube/models/playback/track_sources.dart'; +import 'package:spotube/models/metadata/metadata.dart'; class TrackNotFoundError extends Error { - final TrackSourceQuery track; + final SpotubeTrackObject track; TrackNotFoundError(this.track); @override String toString() { - return '[TrackNotFoundError] ${track.title} - ${track.artists.join(", ")}'; + return '[TrackNotFoundError] ${track.name} - ${track.artists.join(", ")}'; } } diff --git a/lib/services/sourced_track/sourced_track.dart b/lib/services/sourced_track/sourced_track.dart index 661a8447..76b202da 100644 --- a/lib/services/sourced_track/sourced_track.dart +++ b/lib/services/sourced_track/sourced_track.dart @@ -4,13 +4,12 @@ import 'package:collection/collection.dart'; import 'package:dio/dio.dart'; import 'package:drift/drift.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:spotube/extensions/string.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/models/metadata/metadata.dart'; import 'package:spotube/models/playback/track_sources.dart'; import 'package:spotube/provider/database/database.dart'; +import 'package:spotube/provider/metadata_plugin/audio_source/quality_presets.dart'; import 'package:spotube/provider/metadata_plugin/metadata_plugin_provider.dart'; -import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/services/dio/dio.dart'; import 'package:spotube/services/logger/logger.dart'; @@ -34,19 +33,7 @@ class SourcedTrack extends BasicSourcedTrack { required super.sources, }); - static String getSearchTerm(SpotubeFullTrackObject track) { - final title = ServiceUtils.getTitle( - track.name, - artists: track.artists.map((e) => e.name).toList(), - onlyCleanArtist: true, - ).trim(); - - assert(title.trim().isNotEmpty, "Title should not be empty"); - - return "$title - ${track.artists.join(", ")}"; - } - - static Future fetchFromQuery({ + static Future fetchFromTrack({ required SpotubeFullTrackObject query, required Ref ref, }) async { @@ -79,22 +66,25 @@ class SourcedTrack extends BasicSourcedTrack { await database.into(database.sourceMatchTable).insert( SourceMatchTableCompanion.insert( trackId: query.id, - source: jsonEncode(siblings.first), - sourceType: Value(audioSourceConfig.slug), + sourceInfo: Value(jsonEncode(siblings.first)), + sourceType: audioSourceConfig.slug, ), ); + final manifest = await audioSource.audioSource.streams(siblings.first); + return SourcedTrack( ref: ref, - siblings: siblings.map((s) => s.info).skip(1).toList(), - info: siblings.first.info, + siblings: siblings.skip(1).toList(), + info: siblings.first, source: audioSourceConfig.slug, - sources: siblings.first.source ?? [], + sources: manifest, query: query, ); } - final item = - SpotubeAudioSourceMatchObject.fromJson(jsonDecode(cachedSource.source)); + final item = SpotubeAudioSourceMatchObject.fromJson( + jsonDecode(cachedSource.sourceInfo), + ); final manifest = await audioSource.audioSource.streams(item); final sourcedTrack = SourcedTrack( @@ -229,8 +219,8 @@ class SourcedTrack extends BasicSourcedTrack { await database.into(database.sourceMatchTable).insert( SourceMatchTableCompanion.insert( trackId: query.id, - source: jsonEncode(siblings.first), - sourceType: Value(audioSourceConfig.slug), + sourceInfo: Value(jsonEncode(siblings.first)), + sourceType: audioSourceConfig.slug, createdAt: Value(DateTime.now()), ), mode: InsertMode.replace, @@ -298,13 +288,12 @@ class SourcedTrack extends BasicSourcedTrack { } String? get url { - final preferences = ref.read(userPreferencesProvider); + final preferences = ref.read(audioSourcePresetsProvider); - final codec = preferences.audioSource == AudioSource.jiosaavn - ? SourceCodecs.m4a - : preferences.streamMusicCodec; - - return getUrlOfCodec(codec); + return getUrlOfQuality( + preferences.presets[preferences.selectedStreamingContainerIndex], + preferences.selectedStreamingQualityIndex, + ); } /// Returns the URL of the track based on the codec and quality preferences. @@ -384,4 +373,10 @@ class SourcedTrack extends BasicSourcedTrack { ) { return getStreamOfQuality(preset, qualityIndex)?.url; } + + SpotubeAudioSourceContainerPreset? get qualityPreset { + final presetState = ref.read(audioSourcePresetsProvider); + return presetState.presets + .elementAtOrNull(presetState.selectedStreamingContainerIndex); + } } diff --git a/lib/utils/service_utils.dart b/lib/utils/service_utils.dart index 81c4bfe4..738e4033 100644 --- a/lib/utils/service_utils.dart +++ b/lib/utils/service_utils.dart @@ -10,11 +10,9 @@ import 'package:spotube/models/metadata/metadata.dart'; import 'package:spotube/pages/library/user_local_tracks/user_local_tracks.dart'; import 'package:spotube/modules/root/update_dialog.dart'; -import 'package:spotube/models/lyrics.dart'; import 'package:spotube/provider/database/database.dart'; import 'package:spotube/services/dio/dio.dart'; import 'package:spotube/services/logger/logger.dart'; -import 'package:spotube/services/sourced_track/sourced_track.dart'; import 'package:spotube/utils/primitive_utils.dart'; import 'package:collection/collection.dart'; @@ -189,95 +187,6 @@ abstract class ServiceUtils { return lyrics; } - @Deprecated("In favor spotify lyrics api, this isn't needed anymore") - static const baseUri = "https://www.rentanadviser.com/subtitles"; - - @Deprecated("In favor spotify lyrics api, this isn't needed anymore") - static Future getTimedLyrics(SourcedTrack track) async { - final artistNames = track.query.artists; - final query = getTitle( - track.query.title, - artists: artistNames, - ); - - final searchUri = Uri.parse("$baseUri/subtitles4songs.aspx").replace( - queryParameters: {"q": query}, - ); - - final res = await globalDio.getUri( - searchUri, - options: Options(responseType: ResponseType.plain), - ); - final document = parser.parse(res.data); - final results = - document.querySelectorAll("#tablecontainer table tbody tr td a"); - - final rateSortedResults = results.map((result) { - final title = result.text.trim().toLowerCase(); - int points = 0; - final hasAllArtists = track.query.artists - .every((artist) => title.contains(artist.toLowerCase())); - final hasTrackName = title.contains(track.query.title.toLowerCase()); - final isNotLive = !PrimitiveUtils.containsTextInBracket(title, "live"); - final exactYtMatch = title == track.info.title.toLowerCase(); - if (exactYtMatch) points = 7; - for (final criteria in [hasTrackName, hasAllArtists, isNotLive]) { - if (criteria) points++; - } - return {"result": result, "points": points}; - }).sorted((a, b) => (b["points"] as int).compareTo(a["points"] as int)); - - // not result was found at all - if (rateSortedResults.first["points"] == 0) { - return Future.error("Subtitle lookup failed", StackTrace.current); - } - - final topResult = rateSortedResults.first["result"] as Element; - final subtitleUri = - Uri.parse("$baseUri/${topResult.attributes["href"]}&type=lrc"); - - final lrcDocument = parser.parse((await globalDio.getUri( - subtitleUri, - options: Options(responseType: ResponseType.plain), - )) - .data); - final lrcList = lrcDocument - .querySelector("#ctl00_ContentPlaceHolder1_lbllyrics") - ?.innerHtml - .replaceAll(RegExp(r'

.*

'), "") - .split("
") - .map((e) { - e = e.trim(); - final regexp = RegExp(r'\[.*\]'); - final timeStr = regexp - .firstMatch(e) - ?.group(0) - ?.replaceAll(RegExp(r'\[|\]'), "") - .trim() - .split(":"); - final minuteSeconds = timeStr?.last.split("."); - - return LyricSlice( - time: Duration( - minutes: int.parse(timeStr?.first ?? "0"), - seconds: int.parse(minuteSeconds?.first ?? "0"), - milliseconds: int.parse(minuteSeconds?.last ?? "0"), - ), - text: e.split(regexp).last); - }).toList() ?? - []; - - final subtitle = SubtitleSimple( - name: topResult.text.trim(), - uri: subtitleUri, - lyrics: lrcList, - rating: rateSortedResults.first["points"] as int, - provider: "Rent An Adviser", - ); - - return subtitle; - } - static DateTime parseSpotifyAlbumDate(SpotubeFullAlbumObject? album) { if (album == null) { return DateTime.parse("1975-01-01"); diff --git a/pubspec.lock b/pubspec.lock index 8623af4e..0ae02b4c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -467,14 +467,6 @@ packages: url: "https://github.com/KRTirtho/dab_music_api.git" source: git version: "0.1.0" - dart_des: - dependency: transitive - description: - name: dart_des - sha256: "0a66afb8883368c824497fd2a1fd67bdb1a785965a3956728382c03d40747c33" - url: "https://pub.dev" - source: hosted - version: "1.0.2" dart_mappable: dependency: transitive description: @@ -1408,14 +1400,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.20.2" - invidious: - dependency: "direct main" - description: - name: invidious - sha256: "0da8ebc4c4110057f03302bbd54514b10642154d7be569e7994172f2202dcfe8" - url: "https://pub.dev" - source: hosted - version: "0.1.2" io: dependency: "direct dev" description: @@ -1440,14 +1424,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.0" - jiosaavn: - dependency: "direct main" - description: - name: jiosaavn - sha256: b6bde15c56398ebfd439825a64fb540a265773d1a518ba103e79988e13d16e1d - url: "https://pub.dev" - source: hosted - version: "0.1.1" jovial_misc: dependency: transitive description: @@ -1935,14 +1911,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.4" - piped_client: - dependency: "direct main" - description: - name: piped_client - sha256: "947613e2a8d368b72cb36473de2c5c2784e4e72b2d3f17e5a5181b98b1a5436e" - url: "https://pub.dev" - source: hosted - version: "0.1.2" pixel_snap: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 4087bc0d..812e690f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -81,8 +81,6 @@ dependencies: http: ^1.2.1 image_picker: ^1.1.0 intl: any - invidious: ^0.1.2 - jiosaavn: ^0.1.1 json_annotation: ^4.8.1 local_notifier: ^0.1.6 logger: ^2.0.2 @@ -104,7 +102,6 @@ dependencies: path: ^1.9.0 path_provider: ^2.1.3 permission_handler: ^11.3.1 - piped_client: ^0.1.2 riverpod: ^2.5.1 scrobblenaut: git: diff --git a/test/drift/app_db/generated/schema_v10.dart b/test/drift/app_db/generated/schema_v10.dart index 36cc2a6b..2811ad02 100644 --- a/test/drift/app_db/generated/schema_v10.dart +++ b/test/drift/app_db/generated/schema_v10.dart @@ -552,16 +552,6 @@ class PreferencesTable extends Table type: DriftSqlType.string, requiredDuringInsert: false, defaultValue: const Constant("")); - late final GeneratedColumn pipedInstance = GeneratedColumn( - 'piped_instance', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: const Constant("https://pipedapi.kavin.rocks")); - late final GeneratedColumn invidiousInstance = - GeneratedColumn('invidious_instance', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: const Constant("https://inv.nadeko.net")); late final GeneratedColumn themeMode = GeneratedColumn( 'theme_mode', aliasedName, false, type: DriftSqlType.string, @@ -626,8 +616,6 @@ class PreferencesTable extends Table searchMode, downloadLocation, localLibraryLocation, - pipedInstance, - invidiousInstance, themeMode, audioSourceId, youtubeClientEngine, @@ -681,10 +669,6 @@ class PreferencesTable extends Table localLibraryLocation: attachedDatabase.typeMapping.read( DriftSqlType.string, data['${effectivePrefix}local_library_location'])!, - pipedInstance: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}piped_instance'])!, - invidiousInstance: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}invidious_instance'])!, themeMode: attachedDatabase.typeMapping .read(DriftSqlType.string, data['${effectivePrefix}theme_mode'])!, audioSourceId: attachedDatabase.typeMapping @@ -729,8 +713,6 @@ class PreferencesTableData extends DataClass final String searchMode; final String downloadLocation; final String localLibraryLocation; - final String pipedInstance; - final String invidiousInstance; final String themeMode; final String? audioSourceId; final String youtubeClientEngine; @@ -756,8 +738,6 @@ class PreferencesTableData extends DataClass required this.searchMode, required this.downloadLocation, required this.localLibraryLocation, - required this.pipedInstance, - required this.invidiousInstance, required this.themeMode, this.audioSourceId, required this.youtubeClientEngine, @@ -785,8 +765,6 @@ class PreferencesTableData extends DataClass map['search_mode'] = Variable(searchMode); map['download_location'] = Variable(downloadLocation); map['local_library_location'] = Variable(localLibraryLocation); - map['piped_instance'] = Variable(pipedInstance); - map['invidious_instance'] = Variable(invidiousInstance); map['theme_mode'] = Variable(themeMode); if (!nullToAbsent || audioSourceId != null) { map['audio_source_id'] = Variable(audioSourceId); @@ -818,8 +796,6 @@ class PreferencesTableData extends DataClass searchMode: Value(searchMode), downloadLocation: Value(downloadLocation), localLibraryLocation: Value(localLibraryLocation), - pipedInstance: Value(pipedInstance), - invidiousInstance: Value(invidiousInstance), themeMode: Value(themeMode), audioSourceId: audioSourceId == null && nullToAbsent ? const Value.absent() @@ -854,8 +830,6 @@ class PreferencesTableData extends DataClass downloadLocation: serializer.fromJson(json['downloadLocation']), localLibraryLocation: serializer.fromJson(json['localLibraryLocation']), - pipedInstance: serializer.fromJson(json['pipedInstance']), - invidiousInstance: serializer.fromJson(json['invidiousInstance']), themeMode: serializer.fromJson(json['themeMode']), audioSourceId: serializer.fromJson(json['audioSourceId']), youtubeClientEngine: @@ -887,8 +861,6 @@ class PreferencesTableData extends DataClass 'searchMode': serializer.toJson(searchMode), 'downloadLocation': serializer.toJson(downloadLocation), 'localLibraryLocation': serializer.toJson(localLibraryLocation), - 'pipedInstance': serializer.toJson(pipedInstance), - 'invidiousInstance': serializer.toJson(invidiousInstance), 'themeMode': serializer.toJson(themeMode), 'audioSourceId': serializer.toJson(audioSourceId), 'youtubeClientEngine': serializer.toJson(youtubeClientEngine), @@ -917,8 +889,6 @@ class PreferencesTableData extends DataClass String? searchMode, String? downloadLocation, String? localLibraryLocation, - String? pipedInstance, - String? invidiousInstance, String? themeMode, Value audioSourceId = const Value.absent(), String? youtubeClientEngine, @@ -944,8 +914,6 @@ class PreferencesTableData extends DataClass searchMode: searchMode ?? this.searchMode, downloadLocation: downloadLocation ?? this.downloadLocation, localLibraryLocation: localLibraryLocation ?? this.localLibraryLocation, - pipedInstance: pipedInstance ?? this.pipedInstance, - invidiousInstance: invidiousInstance ?? this.invidiousInstance, themeMode: themeMode ?? this.themeMode, audioSourceId: audioSourceId.present ? audioSourceId.value : this.audioSourceId, @@ -997,12 +965,6 @@ class PreferencesTableData extends DataClass localLibraryLocation: data.localLibraryLocation.present ? data.localLibraryLocation.value : this.localLibraryLocation, - pipedInstance: data.pipedInstance.present - ? data.pipedInstance.value - : this.pipedInstance, - invidiousInstance: data.invidiousInstance.present - ? data.invidiousInstance.value - : this.invidiousInstance, themeMode: data.themeMode.present ? data.themeMode.value : this.themeMode, audioSourceId: data.audioSourceId.present ? data.audioSourceId.value @@ -1045,8 +1007,6 @@ class PreferencesTableData extends DataClass ..write('searchMode: $searchMode, ') ..write('downloadLocation: $downloadLocation, ') ..write('localLibraryLocation: $localLibraryLocation, ') - ..write('pipedInstance: $pipedInstance, ') - ..write('invidiousInstance: $invidiousInstance, ') ..write('themeMode: $themeMode, ') ..write('audioSourceId: $audioSourceId, ') ..write('youtubeClientEngine: $youtubeClientEngine, ') @@ -1077,8 +1037,6 @@ class PreferencesTableData extends DataClass searchMode, downloadLocation, localLibraryLocation, - pipedInstance, - invidiousInstance, themeMode, audioSourceId, youtubeClientEngine, @@ -1108,8 +1066,6 @@ class PreferencesTableData extends DataClass other.searchMode == this.searchMode && other.downloadLocation == this.downloadLocation && other.localLibraryLocation == this.localLibraryLocation && - other.pipedInstance == this.pipedInstance && - other.invidiousInstance == this.invidiousInstance && other.themeMode == this.themeMode && other.audioSourceId == this.audioSourceId && other.youtubeClientEngine == this.youtubeClientEngine && @@ -1137,8 +1093,6 @@ class PreferencesTableCompanion extends UpdateCompanion { final Value searchMode; final Value downloadLocation; final Value localLibraryLocation; - final Value pipedInstance; - final Value invidiousInstance; final Value themeMode; final Value audioSourceId; final Value youtubeClientEngine; @@ -1164,8 +1118,6 @@ class PreferencesTableCompanion extends UpdateCompanion { this.searchMode = const Value.absent(), this.downloadLocation = const Value.absent(), this.localLibraryLocation = const Value.absent(), - this.pipedInstance = const Value.absent(), - this.invidiousInstance = const Value.absent(), this.themeMode = const Value.absent(), this.audioSourceId = const Value.absent(), this.youtubeClientEngine = const Value.absent(), @@ -1192,8 +1144,6 @@ class PreferencesTableCompanion extends UpdateCompanion { this.searchMode = const Value.absent(), this.downloadLocation = const Value.absent(), this.localLibraryLocation = const Value.absent(), - this.pipedInstance = const Value.absent(), - this.invidiousInstance = const Value.absent(), this.themeMode = const Value.absent(), this.audioSourceId = const Value.absent(), this.youtubeClientEngine = const Value.absent(), @@ -1220,8 +1170,6 @@ class PreferencesTableCompanion extends UpdateCompanion { Expression? searchMode, Expression? downloadLocation, Expression? localLibraryLocation, - Expression? pipedInstance, - Expression? invidiousInstance, Expression? themeMode, Expression? audioSourceId, Expression? youtubeClientEngine, @@ -1250,8 +1198,6 @@ class PreferencesTableCompanion extends UpdateCompanion { if (downloadLocation != null) 'download_location': downloadLocation, if (localLibraryLocation != null) 'local_library_location': localLibraryLocation, - if (pipedInstance != null) 'piped_instance': pipedInstance, - if (invidiousInstance != null) 'invidious_instance': invidiousInstance, if (themeMode != null) 'theme_mode': themeMode, if (audioSourceId != null) 'audio_source_id': audioSourceId, if (youtubeClientEngine != null) @@ -1281,8 +1227,6 @@ class PreferencesTableCompanion extends UpdateCompanion { Value? searchMode, Value? downloadLocation, Value? localLibraryLocation, - Value? pipedInstance, - Value? invidiousInstance, Value? themeMode, Value? audioSourceId, Value? youtubeClientEngine, @@ -1308,8 +1252,6 @@ class PreferencesTableCompanion extends UpdateCompanion { searchMode: searchMode ?? this.searchMode, downloadLocation: downloadLocation ?? this.downloadLocation, localLibraryLocation: localLibraryLocation ?? this.localLibraryLocation, - pipedInstance: pipedInstance ?? this.pipedInstance, - invidiousInstance: invidiousInstance ?? this.invidiousInstance, themeMode: themeMode ?? this.themeMode, audioSourceId: audioSourceId ?? this.audioSourceId, youtubeClientEngine: youtubeClientEngine ?? this.youtubeClientEngine, @@ -1373,12 +1315,6 @@ class PreferencesTableCompanion extends UpdateCompanion { map['local_library_location'] = Variable(localLibraryLocation.value); } - if (pipedInstance.present) { - map['piped_instance'] = Variable(pipedInstance.value); - } - if (invidiousInstance.present) { - map['invidious_instance'] = Variable(invidiousInstance.value); - } if (themeMode.present) { map['theme_mode'] = Variable(themeMode.value); } @@ -1426,8 +1362,6 @@ class PreferencesTableCompanion extends UpdateCompanion { ..write('searchMode: $searchMode, ') ..write('downloadLocation: $downloadLocation, ') ..write('localLibraryLocation: $localLibraryLocation, ') - ..write('pipedInstance: $pipedInstance, ') - ..write('invidiousInstance: $invidiousInstance, ') ..write('themeMode: $themeMode, ') ..write('audioSourceId: $audioSourceId, ') ..write('youtubeClientEngine: $youtubeClientEngine, ') @@ -1935,7 +1869,9 @@ class SourceMatchTable extends Table type: DriftSqlType.string, requiredDuringInsert: true); late final GeneratedColumn sourceInfo = GeneratedColumn( 'source_info', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultValue: const Constant("{}")); late final GeneratedColumn sourceType = GeneratedColumn( 'source_type', aliasedName, false, type: DriftSqlType.string, requiredDuringInsert: true); @@ -2101,11 +2037,10 @@ class SourceMatchTableCompanion extends UpdateCompanion { SourceMatchTableCompanion.insert({ this.id = const Value.absent(), required String trackId, - required String sourceInfo, + this.sourceInfo = const Value.absent(), required String sourceType, this.createdAt = const Value.absent(), }) : trackId = Value(trackId), - sourceInfo = Value(sourceInfo), sourceType = Value(sourceType); static Insertable custom({ Expression? id,