mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 16:05:18 +00:00
feat: track caching and cached track export support (#2117)
* feat: add caching support with track metadata * feat(settings): add cache music toggle * fix(mobile): cache dir not open-able * feat(local folder): add cache export/clear actions and size of the folder * chore: ios deps upgrades * chore: upgrade lint flutter version * chore: lint secrets causing error * cd: invalid value for env var
This commit is contained in:
parent
499ecfba26
commit
8ca2115ef0
12
.env.example
12
.env.example
@ -1,16 +1,16 @@
|
|||||||
# The format:
|
# The format:
|
||||||
# SPOTIFY_SECRETS=clintId1:clientSecret1,clientId2:clientSecret2
|
# SPOTIFY_SECRETS=clintId1:clientSecret1,clientId2:clientSecret2
|
||||||
SPOTIFY_SECRETS=
|
SPOTIFY_SECRETS=$SPOTIFY_SECRETS
|
||||||
|
|
||||||
# 0 or 1
|
# 0 or 1
|
||||||
# 0 = disable
|
# 0 = disable
|
||||||
# 1 = enable
|
# 1 = enable
|
||||||
ENABLE_UPDATE_CHECK=
|
ENABLE_UPDATE_CHECK=$ENABLE_UPDATE_CHECK
|
||||||
|
|
||||||
LASTFM_API_KEY=
|
LASTFM_API_KEY=$LASTFM_API_KEY
|
||||||
LASTFM_API_SECRET=
|
LASTFM_API_SECRET=$LASTFM_API_SECRET
|
||||||
|
|
||||||
# Release channel. Can be: nightly, stable
|
# Release channel. Can be: nightly, stable
|
||||||
RELEASE_CHANNEL=
|
RELEASE_CHANNEL=$RELEASE_CHANNEL
|
||||||
|
|
||||||
HIDE_DONATIONS=
|
HIDE_DONATIONS=$HIDE_DONATIONS
|
||||||
|
21
.github/workflows/pr-lint.yml
vendored
21
.github/workflows/pr-lint.yml
vendored
@ -4,7 +4,7 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
FLUTTER_VERSION: 3.22.2
|
FLUTTER_VERSION: 3.24.5
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
@ -17,18 +17,23 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||||
|
|
||||||
|
- name: Dummy Envs
|
||||||
|
run: |
|
||||||
|
envsubst < .env.example > .env
|
||||||
|
env:
|
||||||
|
SPOTIFY_SECRETS: xxx:xxx
|
||||||
|
ENABLE_UPDATE_CHECK: true
|
||||||
|
LASTFM_API_KEY: xxx
|
||||||
|
LASTFM_API_SECRET: xxx
|
||||||
|
RELEASE_CHANNEL: nightly
|
||||||
|
HIDE_DONATIONS: 0
|
||||||
|
|
||||||
|
|
||||||
- name: Configure repo
|
- name: Configure repo
|
||||||
run: |
|
run: |
|
||||||
flutter pub get
|
flutter pub get
|
||||||
echo '${{ secrets.DOTENV_NIGHTLY }}' > .env
|
|
||||||
dart run build_runner build --delete-conflicting-outputs
|
dart run build_runner build --delete-conflicting-outputs
|
||||||
|
|
||||||
- name: Lint Dart files
|
- name: Lint Dart files
|
||||||
run: |
|
run: |
|
||||||
dart analyze --no-fatal-warnings
|
dart analyze --no-fatal-warnings
|
||||||
|
|
||||||
- name: Lint translations & config files
|
|
||||||
run: |
|
|
||||||
npm install -g @prantlf/jsonlint
|
|
||||||
jsonlint -q -D --enforce-double-quotes ./lib/l10n/*.arb
|
|
||||||
jsonlint -q -D --enforce-double-quotes -T .vscode/*.json
|
|
3
Makefile
3
Makefile
@ -43,3 +43,6 @@ apk:
|
|||||||
|
|
||||||
gensums:
|
gensums:
|
||||||
sh -c scripts/gensums.sh
|
sh -c scripts/gensums.sh
|
||||||
|
|
||||||
|
migrate:
|
||||||
|
dart run drift_dev make-migrations
|
@ -39,3 +39,4 @@ analyzer:
|
|||||||
- "**.g.dart"
|
- "**.g.dart"
|
||||||
- "**.gr.dart"
|
- "**.gr.dart"
|
||||||
- "**/generated_plugin_registrant.dart"
|
- "**/generated_plugin_registrant.dart"
|
||||||
|
- test/**/*.dart
|
||||||
|
1
drift_schemas/app_db/drift_schema_v3.json
Normal file
1
drift_schemas/app_db/drift_schema_v3.json
Normal file
File diff suppressed because one or more lines are too long
@ -58,7 +58,7 @@ PODS:
|
|||||||
- flutter_inappwebview_ios/Core (0.0.1):
|
- flutter_inappwebview_ios/Core (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- OrderedSet (~> 6.0.3)
|
- OrderedSet (~> 6.0.3)
|
||||||
- flutter_native_splash (0.0.1):
|
- flutter_native_splash (2.4.3):
|
||||||
- Flutter
|
- Flutter
|
||||||
- flutter_secure_storage (6.0.0):
|
- flutter_secure_storage (6.0.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
@ -74,6 +74,8 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- metadata_god (0.0.1):
|
- metadata_god (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- open_file_ios (0.0.1):
|
||||||
|
- Flutter
|
||||||
- OrderedSet (6.0.3)
|
- OrderedSet (6.0.3)
|
||||||
- package_info_plus (0.4.5):
|
- package_info_plus (0.4.5):
|
||||||
- Flutter
|
- Flutter
|
||||||
@ -88,21 +90,24 @@ PODS:
|
|||||||
- shared_preferences_foundation (0.0.1):
|
- shared_preferences_foundation (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- sqflite (0.0.3):
|
- sqflite_darwin (0.0.4):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- "sqlite3 (3.46.0+1)":
|
- sqlite3 (3.47.1):
|
||||||
- "sqlite3/common (= 3.46.0+1)"
|
- sqlite3/common (= 3.47.1)
|
||||||
- "sqlite3/common (3.46.0+1)"
|
- sqlite3/common (3.47.1)
|
||||||
- "sqlite3/fts5 (3.46.0+1)":
|
- sqlite3/dbstatvtab (3.47.1):
|
||||||
- sqlite3/common
|
- sqlite3/common
|
||||||
- "sqlite3/perf-threadsafe (3.46.0+1)":
|
- sqlite3/fts5 (3.47.1):
|
||||||
- sqlite3/common
|
- sqlite3/common
|
||||||
- "sqlite3/rtree (3.46.0+1)":
|
- sqlite3/perf-threadsafe (3.47.1):
|
||||||
|
- sqlite3/common
|
||||||
|
- sqlite3/rtree (3.47.1):
|
||||||
- sqlite3/common
|
- sqlite3/common
|
||||||
- sqlite3_flutter_libs (0.0.1):
|
- sqlite3_flutter_libs (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- sqlite3 (~> 3.46.0)
|
- sqlite3 (~> 3.47.0)
|
||||||
|
- sqlite3/dbstatvtab
|
||||||
- sqlite3/fts5
|
- sqlite3/fts5
|
||||||
- sqlite3/perf-threadsafe
|
- sqlite3/perf-threadsafe
|
||||||
- sqlite3/rtree
|
- sqlite3/rtree
|
||||||
@ -130,11 +135,12 @@ DEPENDENCIES:
|
|||||||
- media_kit_libs_ios_audio (from `.symlinks/plugins/media_kit_libs_ios_audio/ios`)
|
- media_kit_libs_ios_audio (from `.symlinks/plugins/media_kit_libs_ios_audio/ios`)
|
||||||
- media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`)
|
- media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`)
|
||||||
- metadata_god (from `.symlinks/plugins/metadata_god/ios`)
|
- metadata_god (from `.symlinks/plugins/metadata_god/ios`)
|
||||||
|
- open_file_ios (from `.symlinks/plugins/open_file_ios/ios`)
|
||||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
|
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
||||||
- sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`)
|
- sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`)
|
||||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
|
|
||||||
@ -186,6 +192,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/media_kit_native_event_loop/ios"
|
:path: ".symlinks/plugins/media_kit_native_event_loop/ios"
|
||||||
metadata_god:
|
metadata_god:
|
||||||
:path: ".symlinks/plugins/metadata_god/ios"
|
:path: ".symlinks/plugins/metadata_god/ios"
|
||||||
|
open_file_ios:
|
||||||
|
:path: ".symlinks/plugins/open_file_ios/ios"
|
||||||
package_info_plus:
|
package_info_plus:
|
||||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
@ -194,8 +202,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||||
sqflite:
|
sqflite_darwin:
|
||||||
:path: ".symlinks/plugins/sqflite/darwin"
|
:path: ".symlinks/plugins/sqflite_darwin/darwin"
|
||||||
sqlite3_flutter_libs:
|
sqlite3_flutter_libs:
|
||||||
:path: ".symlinks/plugins/sqlite3_flutter_libs/ios"
|
:path: ".symlinks/plugins/sqlite3_flutter_libs/ios"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
@ -206,35 +214,36 @@ SPEC CHECKSUMS:
|
|||||||
audio_service: f509d65da41b9521a61f1c404dd58651f265a567
|
audio_service: f509d65da41b9521a61f1c404dd58651f265a567
|
||||||
audio_session: 088d2483ebd1dc43f51d253d4a1c517d9a2e7207
|
audio_session: 088d2483ebd1dc43f51d253d4a1c517d9a2e7207
|
||||||
bonsoir_darwin: e3b8526c42ca46a885142df84229131dfabea842
|
bonsoir_darwin: e3b8526c42ca46a885142df84229131dfabea842
|
||||||
device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
|
device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342
|
||||||
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
|
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
|
||||||
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
|
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
|
||||||
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
|
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
|
||||||
file_selector_ios: 78baf21d03f1e37a7df97bb2494f9cd86de8fa5d
|
file_selector_ios: f0670c1064a8c8450e38145d8043160105d0b97c
|
||||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||||
flutter_broadcasts: 3ece15b27d8ccbe2132c3df303e7c3401feab882
|
flutter_broadcasts: 3ece15b27d8ccbe2132c3df303e7c3401feab882
|
||||||
flutter_discord_rpc: e1c342f29ceb9dd76cdc01db59a70c93bb4d9ec5
|
flutter_discord_rpc: e1c342f29ceb9dd76cdc01db59a70c93bb4d9ec5
|
||||||
flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4
|
flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4
|
||||||
flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778
|
flutter_native_splash: e8a1e01082d97a8099d973f919f57904c925008a
|
||||||
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
|
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
|
||||||
flutter_sharing_intent: e35380d0e1501d7111dbb7e46d5ac6339da6da98
|
flutter_sharing_intent: e35380d0e1501d7111dbb7e46d5ac6339da6da98
|
||||||
image_picker_ios: b545a5f16c0fa88e3ecbbce3ed4de45567a8ec18
|
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
||||||
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
|
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
|
||||||
media_kit_libs_ios_audio: 8f39d96a9c630685dfb844c289bd1d114c486fb3
|
media_kit_libs_ios_audio: 8f39d96a9c630685dfb844c289bd1d114c486fb3
|
||||||
media_kit_native_event_loop: 99111eded5acbdc9c2738021ea6550dd36ca8837
|
media_kit_native_event_loop: 99111eded5acbdc9c2738021ea6550dd36ca8837
|
||||||
metadata_god: 4bbd8523cdb5d42c5e59d2fabad01ff8f4bc53f9
|
metadata_god: 4bbd8523cdb5d42c5e59d2fabad01ff8f4bc53f9
|
||||||
|
open_file_ios: 461db5853723763573e140de3193656f91990d9e
|
||||||
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
||||||
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
|
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
|
||||||
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
|
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||||
SDWebImage: a81bbb3ba4ea5f810f4069c68727cb118467a04a
|
SDWebImage: a81bbb3ba4ea5f810f4069c68727cb118467a04a
|
||||||
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
|
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||||
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
|
||||||
sqlite3: 292c3e1bfe89f64e51ea7fc7dab9182a017c8630
|
sqlite3: 1e522f0938463e44b7faf50393b40bdc1e1e456d
|
||||||
sqlite3_flutter_libs: 0d611efdf6d1c9297d5ab03dab21b75aeebdae31
|
sqlite3_flutter_libs: b55ef23cfafea5318ae5081e0bf3fbbce8417c94
|
||||||
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
|
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
|
||||||
url_launcher_ios: 6116280ddcfe98ab8820085d8d76ae7449447586
|
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||||
|
|
||||||
PODFILE CHECKSUM: 0659b64ac6e9e96b61d8550decffa8bff51a957e
|
PODFILE CHECKSUM: 0659b64ac6e9e96b61d8550decffa8bff51a957e
|
||||||
|
|
||||||
COCOAPODS: 1.15.2
|
COCOAPODS: 1.16.2
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
import Flutter
|
import Flutter
|
||||||
|
|
||||||
@UIApplicationMain
|
@main
|
||||||
@objc class AppDelegate: FlutterAppDelegate {
|
@objc class AppDelegate: FlutterAppDelegate {
|
||||||
override func application(
|
override func application(
|
||||||
_ application: UIApplication,
|
_ application: UIApplication,
|
||||||
|
@ -43,6 +43,7 @@ class $AssetsTutorialGen {
|
|||||||
class Assets {
|
class Assets {
|
||||||
Assets._();
|
Assets._();
|
||||||
|
|
||||||
|
static const String license = 'LICENSE';
|
||||||
static const AssetGenImage albumPlaceholder =
|
static const AssetGenImage albumPlaceholder =
|
||||||
AssetGenImage('assets/album-placeholder.png');
|
AssetGenImage('assets/album-placeholder.png');
|
||||||
static const AssetGenImage bengaliPatternsBg =
|
static const AssetGenImage bengaliPatternsBg =
|
||||||
@ -92,6 +93,7 @@ class Assets {
|
|||||||
|
|
||||||
/// List of all assets
|
/// List of all assets
|
||||||
static List<dynamic> get values => [
|
static List<dynamic> get values => [
|
||||||
|
license,
|
||||||
albumPlaceholder,
|
albumPlaceholder,
|
||||||
bengaliPatternsBg,
|
bengaliPatternsBg,
|
||||||
branding,
|
branding,
|
||||||
@ -122,10 +124,17 @@ class Assets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class AssetGenImage {
|
class AssetGenImage {
|
||||||
const AssetGenImage(this._assetName);
|
const AssetGenImage(
|
||||||
|
this._assetName, {
|
||||||
|
this.size,
|
||||||
|
this.flavors = const {},
|
||||||
|
});
|
||||||
|
|
||||||
final String _assetName;
|
final String _assetName;
|
||||||
|
|
||||||
|
final Size? size;
|
||||||
|
final Set<String> flavors;
|
||||||
|
|
||||||
Image image({
|
Image image({
|
||||||
Key? key,
|
Key? key,
|
||||||
AssetBundle? bundle,
|
AssetBundle? bundle,
|
||||||
@ -144,7 +153,7 @@ class AssetGenImage {
|
|||||||
ImageRepeat repeat = ImageRepeat.noRepeat,
|
ImageRepeat repeat = ImageRepeat.noRepeat,
|
||||||
Rect? centerSlice,
|
Rect? centerSlice,
|
||||||
bool matchTextDirection = false,
|
bool matchTextDirection = false,
|
||||||
bool gaplessPlayback = false,
|
bool gaplessPlayback = true,
|
||||||
bool isAntiAlias = false,
|
bool isAntiAlias = false,
|
||||||
String? package,
|
String? package,
|
||||||
FilterQuality filterQuality = FilterQuality.low,
|
FilterQuality filterQuality = FilterQuality.low,
|
||||||
|
@ -128,9 +128,12 @@ final routerProvider = Provider((ref) {
|
|||||||
pageBuilder: (context, state) {
|
pageBuilder: (context, state) {
|
||||||
assert(state.extra is String);
|
assert(state.extra is String);
|
||||||
return SpotubePage(
|
return SpotubePage(
|
||||||
child: LocalLibraryPage(state.extra as String,
|
child: LocalLibraryPage(
|
||||||
isDownloads:
|
state.extra as String,
|
||||||
state.uri.queryParameters["downloads"] != null),
|
isDownloads:
|
||||||
|
state.uri.queryParameters["downloads"] != null,
|
||||||
|
isCache: state.uri.queryParameters["cache"] != null,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -124,4 +124,7 @@ abstract class SpotubeIcons {
|
|||||||
static const chart = FeatherIcons.barChart2;
|
static const chart = FeatherIcons.barChart2;
|
||||||
static const folderAdd = FeatherIcons.folderPlus;
|
static const folderAdd = FeatherIcons.folderPlus;
|
||||||
static const folderRemove = FeatherIcons.folderMinus;
|
static const folderRemove = FeatherIcons.folderMinus;
|
||||||
|
static const cache = FeatherIcons.hardDrive;
|
||||||
|
static const export = Icons.file_open_outlined;
|
||||||
|
static const delete = FeatherIcons.trash2;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:metadata_god/metadata_god.dart';
|
import 'package:metadata_god/metadata_god.dart';
|
||||||
import 'package:path/path.dart';
|
import 'package:path/path.dart';
|
||||||
@ -37,6 +38,33 @@ extension TrackExtensions on Track {
|
|||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Metadata toMetadata({
|
||||||
|
required int fileLength,
|
||||||
|
Uint8List? imageBytes,
|
||||||
|
}) {
|
||||||
|
return Metadata(
|
||||||
|
title: name,
|
||||||
|
artist: artists?.map((a) => a.name).join(", "),
|
||||||
|
album: album?.name,
|
||||||
|
albumArtist: artists?.map((a) => a.name).join(", "),
|
||||||
|
year: album?.releaseDate != null
|
||||||
|
? int.tryParse(album!.releaseDate!.split("-").first) ?? 1969
|
||||||
|
: 1969,
|
||||||
|
trackNumber: trackNumber,
|
||||||
|
discNumber: discNumber,
|
||||||
|
durationMs: durationMs?.toDouble() ?? 0.0,
|
||||||
|
fileSize: BigInt.from(fileLength),
|
||||||
|
trackTotal: album?.tracks?.length ?? 0,
|
||||||
|
picture: imageBytes != null
|
||||||
|
? Picture(
|
||||||
|
data: imageBytes,
|
||||||
|
// Spotify images are always JPEGs
|
||||||
|
mimeType: 'image/jpeg',
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TrackSimpleExtensions on TrackSimple {
|
extension TrackSimpleExtensions on TrackSimple {
|
||||||
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
|
||||||
void useCustomStatusBarColor(
|
VoidCallback useCustomStatusBarColor(
|
||||||
Color color,
|
Color color,
|
||||||
bool isCurrentRoute, {
|
bool isCurrentRoute, {
|
||||||
bool noSetBGColor = false,
|
bool noSetBGColor = false,
|
||||||
@ -10,14 +10,19 @@ void useCustomStatusBarColor(
|
|||||||
}) {
|
}) {
|
||||||
final context = useContext();
|
final context = useContext();
|
||||||
final backgroundColor = Theme.of(context).scaffoldBackgroundColor;
|
final backgroundColor = Theme.of(context).scaffoldBackgroundColor;
|
||||||
resetStatusbar() => SystemChrome.setSystemUIOverlayStyle(
|
// ignore: invalid_use_of_visible_for_testing_member
|
||||||
SystemUiOverlayStyle(
|
final previousState = SystemChrome.latestStyle;
|
||||||
statusBarColor: backgroundColor, // status bar color
|
|
||||||
statusBarIconBrightness: backgroundColor.computeLuminance() > 0.179
|
void resetStatusbar() => previousState != null
|
||||||
? Brightness.dark
|
? SystemChrome.setSystemUIOverlayStyle(previousState)
|
||||||
: Brightness.light,
|
: SystemChrome.setSystemUIOverlayStyle(
|
||||||
),
|
SystemUiOverlayStyle(
|
||||||
);
|
statusBarColor: backgroundColor, // status bar color
|
||||||
|
statusBarIconBrightness: backgroundColor.computeLuminance() > 0.179
|
||||||
|
? Brightness.dark
|
||||||
|
: Brightness.light,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
// ignore: invalid_use_of_visible_for_testing_member
|
// ignore: invalid_use_of_visible_for_testing_member
|
||||||
final statusBarColor = SystemChrome.latestStyle?.statusBarColor;
|
final statusBarColor = SystemChrome.latestStyle?.statusBarColor;
|
||||||
@ -54,4 +59,6 @@ void useCustomStatusBarColor(
|
|||||||
useEffect(() {
|
useEffect(() {
|
||||||
return resetStatusbar;
|
return resetStatusbar;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
return resetStatusbar;
|
||||||
}
|
}
|
||||||
|
@ -391,5 +391,15 @@
|
|||||||
"total_money": "Total {money}",
|
"total_money": "Total {money}",
|
||||||
"webview_not_found": "Webview not found",
|
"webview_not_found": "Webview not found",
|
||||||
"webview_not_found_description": "No webview runtime is installed in your device.\nIf it's installed make sure it's in the Environment PATH\n\nAfter installing, restart the app",
|
"webview_not_found_description": "No webview runtime is installed in your device.\nIf it's installed make sure it's in the Environment PATH\n\nAfter installing, restart the app",
|
||||||
"unsupported_platform": "Unsupported platform"
|
"unsupported_platform": "Unsupported platform",
|
||||||
|
"cache_music": "Cache music",
|
||||||
|
"open": "Open",
|
||||||
|
"cache_folder": "Cache folder",
|
||||||
|
"export": "Export",
|
||||||
|
"clear_cache": "Clear cache",
|
||||||
|
"clear_cache_confirmation": "Do you want to clear the cache?",
|
||||||
|
"export_cache_files": "Export Cached Files",
|
||||||
|
"found_n_files": "Found {count} files",
|
||||||
|
"export_cache_confirmation": "Do you want to export these files to",
|
||||||
|
"exported_n_out_of_m_files": "Exported {filesExported} out of {files} files"
|
||||||
}
|
}
|
@ -99,8 +99,13 @@ mixin _$WebSocketLoadEventData {
|
|||||||
required TResult orElse(),
|
required TResult orElse(),
|
||||||
}) =>
|
}) =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Serializes this WebSocketLoadEventData to a JSON map.
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
@JsonKey(ignore: true)
|
|
||||||
|
/// Create a copy of WebSocketLoadEventData
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
$WebSocketLoadEventDataCopyWith<WebSocketLoadEventData> get copyWith =>
|
$WebSocketLoadEventDataCopyWith<WebSocketLoadEventData> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -127,6 +132,8 @@ class _$WebSocketLoadEventDataCopyWithImpl<$Res,
|
|||||||
// ignore: unused_field
|
// ignore: unused_field
|
||||||
final $Res Function($Val) _then;
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of WebSocketLoadEventData
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -171,6 +178,8 @@ class __$$WebSocketLoadEventDataPlaylistImplCopyWithImpl<$Res>
|
|||||||
$Res Function(_$WebSocketLoadEventDataPlaylistImpl) _then)
|
$Res Function(_$WebSocketLoadEventDataPlaylistImpl) _then)
|
||||||
: super(_value, _then);
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of WebSocketLoadEventData
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -247,12 +256,14 @@ class _$WebSocketLoadEventDataPlaylistImpl
|
|||||||
other.initialIndex == initialIndex));
|
other.initialIndex == initialIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,
|
int get hashCode => Object.hash(runtimeType,
|
||||||
const DeepCollectionEquality().hash(_tracks), collection, initialIndex);
|
const DeepCollectionEquality().hash(_tracks), collection, initialIndex);
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
/// Create a copy of WebSocketLoadEventData
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
_$$WebSocketLoadEventDataPlaylistImplCopyWith<
|
_$$WebSocketLoadEventDataPlaylistImplCopyWith<
|
||||||
@ -372,8 +383,11 @@ abstract class WebSocketLoadEventDataPlaylist extends WebSocketLoadEventData {
|
|||||||
PlaylistSimple? get collection;
|
PlaylistSimple? get collection;
|
||||||
@override
|
@override
|
||||||
int? get initialIndex;
|
int? get initialIndex;
|
||||||
|
|
||||||
|
/// Create a copy of WebSocketLoadEventData
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
_$$WebSocketLoadEventDataPlaylistImplCopyWith<
|
_$$WebSocketLoadEventDataPlaylistImplCopyWith<
|
||||||
_$WebSocketLoadEventDataPlaylistImpl>
|
_$WebSocketLoadEventDataPlaylistImpl>
|
||||||
get copyWith => throw _privateConstructorUsedError;
|
get copyWith => throw _privateConstructorUsedError;
|
||||||
@ -404,6 +418,8 @@ class __$$WebSocketLoadEventDataAlbumImplCopyWithImpl<$Res>
|
|||||||
$Res Function(_$WebSocketLoadEventDataAlbumImpl) _then)
|
$Res Function(_$WebSocketLoadEventDataAlbumImpl) _then)
|
||||||
: super(_value, _then);
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of WebSocketLoadEventData
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -479,12 +495,14 @@ class _$WebSocketLoadEventDataAlbumImpl extends WebSocketLoadEventDataAlbum {
|
|||||||
other.initialIndex == initialIndex));
|
other.initialIndex == initialIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,
|
int get hashCode => Object.hash(runtimeType,
|
||||||
const DeepCollectionEquality().hash(_tracks), collection, initialIndex);
|
const DeepCollectionEquality().hash(_tracks), collection, initialIndex);
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
/// Create a copy of WebSocketLoadEventData
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
_$$WebSocketLoadEventDataAlbumImplCopyWith<_$WebSocketLoadEventDataAlbumImpl>
|
_$$WebSocketLoadEventDataAlbumImplCopyWith<_$WebSocketLoadEventDataAlbumImpl>
|
||||||
@ -603,8 +621,11 @@ abstract class WebSocketLoadEventDataAlbum extends WebSocketLoadEventData {
|
|||||||
AlbumSimple? get collection;
|
AlbumSimple? get collection;
|
||||||
@override
|
@override
|
||||||
int? get initialIndex;
|
int? get initialIndex;
|
||||||
|
|
||||||
|
/// Create a copy of WebSocketLoadEventData
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
_$$WebSocketLoadEventDataAlbumImplCopyWith<_$WebSocketLoadEventDataAlbumImpl>
|
_$$WebSocketLoadEventDataAlbumImplCopyWith<_$WebSocketLoadEventDataAlbumImpl>
|
||||||
get copyWith => throw _privateConstructorUsedError;
|
get copyWith => throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
|
@ -58,18 +58,26 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
AppDatabase() : super(_openConnection());
|
AppDatabase() : super(_openConnection());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get schemaVersion => 2;
|
int get schemaVersion => 3;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MigrationStrategy get migration {
|
MigrationStrategy get migration {
|
||||||
return MigrationStrategy(
|
return MigrationStrategy(
|
||||||
onUpgrade: stepByStep(from1To2: (m, schema) async {
|
onUpgrade: stepByStep(
|
||||||
// Add invidiousInstance column to preferences table
|
from1To2: (m, schema) async {
|
||||||
await m.addColumn(
|
// Add invidiousInstance column to preferences table
|
||||||
schema.preferencesTable,
|
await m.addColumn(
|
||||||
schema.preferencesTable.invidiousInstance,
|
schema.preferencesTable,
|
||||||
);
|
schema.preferencesTable.invidiousInstance,
|
||||||
}),
|
);
|
||||||
|
},
|
||||||
|
from2To3: (m, schema) async {
|
||||||
|
await m.addColumn(
|
||||||
|
schema.preferencesTable,
|
||||||
|
schema.preferencesTable.cacheMusic,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -812,6 +812,16 @@ class $PreferencesTableTable extends PreferencesTable
|
|||||||
defaultConstraints: GeneratedColumn.constraintIsAlways(
|
defaultConstraints: GeneratedColumn.constraintIsAlways(
|
||||||
'CHECK ("enable_connect" IN (0, 1))'),
|
'CHECK ("enable_connect" IN (0, 1))'),
|
||||||
defaultValue: const Constant(false));
|
defaultValue: const Constant(false));
|
||||||
|
static const VerificationMeta _cacheMusicMeta =
|
||||||
|
const VerificationMeta('cacheMusic');
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<bool> cacheMusic = GeneratedColumn<bool>(
|
||||||
|
'cache_music', aliasedName, false,
|
||||||
|
type: DriftSqlType.bool,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
defaultConstraints:
|
||||||
|
GeneratedColumn.constraintIsAlways('CHECK ("cache_music" IN (0, 1))'),
|
||||||
|
defaultValue: const Constant(true));
|
||||||
@override
|
@override
|
||||||
List<GeneratedColumn> get $columns => [
|
List<GeneratedColumn> get $columns => [
|
||||||
id,
|
id,
|
||||||
@ -839,7 +849,8 @@ class $PreferencesTableTable extends PreferencesTable
|
|||||||
downloadMusicCodec,
|
downloadMusicCodec,
|
||||||
discordPresence,
|
discordPresence,
|
||||||
endlessPlayback,
|
endlessPlayback,
|
||||||
enableConnect
|
enableConnect,
|
||||||
|
cacheMusic
|
||||||
];
|
];
|
||||||
@override
|
@override
|
||||||
String get aliasedName => _alias ?? actualTableName;
|
String get aliasedName => _alias ?? actualTableName;
|
||||||
@ -946,6 +957,12 @@ class $PreferencesTableTable extends PreferencesTable
|
|||||||
enableConnect.isAcceptableOrUnknown(
|
enableConnect.isAcceptableOrUnknown(
|
||||||
data['enable_connect']!, _enableConnectMeta));
|
data['enable_connect']!, _enableConnectMeta));
|
||||||
}
|
}
|
||||||
|
if (data.containsKey('cache_music')) {
|
||||||
|
context.handle(
|
||||||
|
_cacheMusicMeta,
|
||||||
|
cacheMusic.isAcceptableOrUnknown(
|
||||||
|
data['cache_music']!, _cacheMusicMeta));
|
||||||
|
}
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1020,6 +1037,8 @@ class $PreferencesTableTable extends PreferencesTable
|
|||||||
.read(DriftSqlType.bool, data['${effectivePrefix}endless_playback'])!,
|
.read(DriftSqlType.bool, data['${effectivePrefix}endless_playback'])!,
|
||||||
enableConnect: attachedDatabase.typeMapping
|
enableConnect: attachedDatabase.typeMapping
|
||||||
.read(DriftSqlType.bool, data['${effectivePrefix}enable_connect'])!,
|
.read(DriftSqlType.bool, data['${effectivePrefix}enable_connect'])!,
|
||||||
|
cacheMusic: attachedDatabase.typeMapping
|
||||||
|
.read(DriftSqlType.bool, data['${effectivePrefix}cache_music'])!,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1086,6 +1105,7 @@ class PreferencesTableData extends DataClass
|
|||||||
final bool discordPresence;
|
final bool discordPresence;
|
||||||
final bool endlessPlayback;
|
final bool endlessPlayback;
|
||||||
final bool enableConnect;
|
final bool enableConnect;
|
||||||
|
final bool cacheMusic;
|
||||||
const PreferencesTableData(
|
const PreferencesTableData(
|
||||||
{required this.id,
|
{required this.id,
|
||||||
required this.audioQuality,
|
required this.audioQuality,
|
||||||
@ -1112,7 +1132,8 @@ class PreferencesTableData extends DataClass
|
|||||||
required this.downloadMusicCodec,
|
required this.downloadMusicCodec,
|
||||||
required this.discordPresence,
|
required this.discordPresence,
|
||||||
required this.endlessPlayback,
|
required this.endlessPlayback,
|
||||||
required this.enableConnect});
|
required this.enableConnect,
|
||||||
|
required this.cacheMusic});
|
||||||
@override
|
@override
|
||||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||||
final map = <String, Expression>{};
|
final map = <String, Expression>{};
|
||||||
@ -1182,6 +1203,7 @@ class PreferencesTableData extends DataClass
|
|||||||
map['discord_presence'] = Variable<bool>(discordPresence);
|
map['discord_presence'] = Variable<bool>(discordPresence);
|
||||||
map['endless_playback'] = Variable<bool>(endlessPlayback);
|
map['endless_playback'] = Variable<bool>(endlessPlayback);
|
||||||
map['enable_connect'] = Variable<bool>(enableConnect);
|
map['enable_connect'] = Variable<bool>(enableConnect);
|
||||||
|
map['cache_music'] = Variable<bool>(cacheMusic);
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1213,6 +1235,7 @@ class PreferencesTableData extends DataClass
|
|||||||
discordPresence: Value(discordPresence),
|
discordPresence: Value(discordPresence),
|
||||||
endlessPlayback: Value(endlessPlayback),
|
endlessPlayback: Value(endlessPlayback),
|
||||||
enableConnect: Value(enableConnect),
|
enableConnect: Value(enableConnect),
|
||||||
|
cacheMusic: Value(cacheMusic),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1257,6 +1280,7 @@ class PreferencesTableData extends DataClass
|
|||||||
discordPresence: serializer.fromJson<bool>(json['discordPresence']),
|
discordPresence: serializer.fromJson<bool>(json['discordPresence']),
|
||||||
endlessPlayback: serializer.fromJson<bool>(json['endlessPlayback']),
|
endlessPlayback: serializer.fromJson<bool>(json['endlessPlayback']),
|
||||||
enableConnect: serializer.fromJson<bool>(json['enableConnect']),
|
enableConnect: serializer.fromJson<bool>(json['enableConnect']),
|
||||||
|
cacheMusic: serializer.fromJson<bool>(json['cacheMusic']),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@override
|
@override
|
||||||
@ -1301,6 +1325,7 @@ class PreferencesTableData extends DataClass
|
|||||||
'discordPresence': serializer.toJson<bool>(discordPresence),
|
'discordPresence': serializer.toJson<bool>(discordPresence),
|
||||||
'endlessPlayback': serializer.toJson<bool>(endlessPlayback),
|
'endlessPlayback': serializer.toJson<bool>(endlessPlayback),
|
||||||
'enableConnect': serializer.toJson<bool>(enableConnect),
|
'enableConnect': serializer.toJson<bool>(enableConnect),
|
||||||
|
'cacheMusic': serializer.toJson<bool>(cacheMusic),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1330,7 +1355,8 @@ class PreferencesTableData extends DataClass
|
|||||||
SourceCodecs? downloadMusicCodec,
|
SourceCodecs? downloadMusicCodec,
|
||||||
bool? discordPresence,
|
bool? discordPresence,
|
||||||
bool? endlessPlayback,
|
bool? endlessPlayback,
|
||||||
bool? enableConnect}) =>
|
bool? enableConnect,
|
||||||
|
bool? cacheMusic}) =>
|
||||||
PreferencesTableData(
|
PreferencesTableData(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
audioQuality: audioQuality ?? this.audioQuality,
|
audioQuality: audioQuality ?? this.audioQuality,
|
||||||
@ -1358,6 +1384,7 @@ class PreferencesTableData extends DataClass
|
|||||||
discordPresence: discordPresence ?? this.discordPresence,
|
discordPresence: discordPresence ?? this.discordPresence,
|
||||||
endlessPlayback: endlessPlayback ?? this.endlessPlayback,
|
endlessPlayback: endlessPlayback ?? this.endlessPlayback,
|
||||||
enableConnect: enableConnect ?? this.enableConnect,
|
enableConnect: enableConnect ?? this.enableConnect,
|
||||||
|
cacheMusic: cacheMusic ?? this.cacheMusic,
|
||||||
);
|
);
|
||||||
PreferencesTableData copyWithCompanion(PreferencesTableCompanion data) {
|
PreferencesTableData copyWithCompanion(PreferencesTableCompanion data) {
|
||||||
return PreferencesTableData(
|
return PreferencesTableData(
|
||||||
@ -1427,6 +1454,8 @@ class PreferencesTableData extends DataClass
|
|||||||
enableConnect: data.enableConnect.present
|
enableConnect: data.enableConnect.present
|
||||||
? data.enableConnect.value
|
? data.enableConnect.value
|
||||||
: this.enableConnect,
|
: this.enableConnect,
|
||||||
|
cacheMusic:
|
||||||
|
data.cacheMusic.present ? data.cacheMusic.value : this.cacheMusic,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1458,7 +1487,8 @@ class PreferencesTableData extends DataClass
|
|||||||
..write('downloadMusicCodec: $downloadMusicCodec, ')
|
..write('downloadMusicCodec: $downloadMusicCodec, ')
|
||||||
..write('discordPresence: $discordPresence, ')
|
..write('discordPresence: $discordPresence, ')
|
||||||
..write('endlessPlayback: $endlessPlayback, ')
|
..write('endlessPlayback: $endlessPlayback, ')
|
||||||
..write('enableConnect: $enableConnect')
|
..write('enableConnect: $enableConnect, ')
|
||||||
|
..write('cacheMusic: $cacheMusic')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
@ -1490,7 +1520,8 @@ class PreferencesTableData extends DataClass
|
|||||||
downloadMusicCodec,
|
downloadMusicCodec,
|
||||||
discordPresence,
|
discordPresence,
|
||||||
endlessPlayback,
|
endlessPlayback,
|
||||||
enableConnect
|
enableConnect,
|
||||||
|
cacheMusic
|
||||||
]);
|
]);
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
@ -1521,7 +1552,8 @@ class PreferencesTableData extends DataClass
|
|||||||
other.downloadMusicCodec == this.downloadMusicCodec &&
|
other.downloadMusicCodec == this.downloadMusicCodec &&
|
||||||
other.discordPresence == this.discordPresence &&
|
other.discordPresence == this.discordPresence &&
|
||||||
other.endlessPlayback == this.endlessPlayback &&
|
other.endlessPlayback == this.endlessPlayback &&
|
||||||
other.enableConnect == this.enableConnect);
|
other.enableConnect == this.enableConnect &&
|
||||||
|
other.cacheMusic == this.cacheMusic);
|
||||||
}
|
}
|
||||||
|
|
||||||
class PreferencesTableCompanion extends UpdateCompanion<PreferencesTableData> {
|
class PreferencesTableCompanion extends UpdateCompanion<PreferencesTableData> {
|
||||||
@ -1551,6 +1583,7 @@ class PreferencesTableCompanion extends UpdateCompanion<PreferencesTableData> {
|
|||||||
final Value<bool> discordPresence;
|
final Value<bool> discordPresence;
|
||||||
final Value<bool> endlessPlayback;
|
final Value<bool> endlessPlayback;
|
||||||
final Value<bool> enableConnect;
|
final Value<bool> enableConnect;
|
||||||
|
final Value<bool> cacheMusic;
|
||||||
const PreferencesTableCompanion({
|
const PreferencesTableCompanion({
|
||||||
this.id = const Value.absent(),
|
this.id = const Value.absent(),
|
||||||
this.audioQuality = const Value.absent(),
|
this.audioQuality = const Value.absent(),
|
||||||
@ -1578,6 +1611,7 @@ class PreferencesTableCompanion extends UpdateCompanion<PreferencesTableData> {
|
|||||||
this.discordPresence = const Value.absent(),
|
this.discordPresence = const Value.absent(),
|
||||||
this.endlessPlayback = const Value.absent(),
|
this.endlessPlayback = const Value.absent(),
|
||||||
this.enableConnect = const Value.absent(),
|
this.enableConnect = const Value.absent(),
|
||||||
|
this.cacheMusic = const Value.absent(),
|
||||||
});
|
});
|
||||||
PreferencesTableCompanion.insert({
|
PreferencesTableCompanion.insert({
|
||||||
this.id = const Value.absent(),
|
this.id = const Value.absent(),
|
||||||
@ -1606,6 +1640,7 @@ class PreferencesTableCompanion extends UpdateCompanion<PreferencesTableData> {
|
|||||||
this.discordPresence = const Value.absent(),
|
this.discordPresence = const Value.absent(),
|
||||||
this.endlessPlayback = const Value.absent(),
|
this.endlessPlayback = const Value.absent(),
|
||||||
this.enableConnect = const Value.absent(),
|
this.enableConnect = const Value.absent(),
|
||||||
|
this.cacheMusic = const Value.absent(),
|
||||||
});
|
});
|
||||||
static Insertable<PreferencesTableData> custom({
|
static Insertable<PreferencesTableData> custom({
|
||||||
Expression<int>? id,
|
Expression<int>? id,
|
||||||
@ -1634,6 +1669,7 @@ class PreferencesTableCompanion extends UpdateCompanion<PreferencesTableData> {
|
|||||||
Expression<bool>? discordPresence,
|
Expression<bool>? discordPresence,
|
||||||
Expression<bool>? endlessPlayback,
|
Expression<bool>? endlessPlayback,
|
||||||
Expression<bool>? enableConnect,
|
Expression<bool>? enableConnect,
|
||||||
|
Expression<bool>? cacheMusic,
|
||||||
}) {
|
}) {
|
||||||
return RawValuesInsertable({
|
return RawValuesInsertable({
|
||||||
if (id != null) 'id': id,
|
if (id != null) 'id': id,
|
||||||
@ -1665,6 +1701,7 @@ class PreferencesTableCompanion extends UpdateCompanion<PreferencesTableData> {
|
|||||||
if (discordPresence != null) 'discord_presence': discordPresence,
|
if (discordPresence != null) 'discord_presence': discordPresence,
|
||||||
if (endlessPlayback != null) 'endless_playback': endlessPlayback,
|
if (endlessPlayback != null) 'endless_playback': endlessPlayback,
|
||||||
if (enableConnect != null) 'enable_connect': enableConnect,
|
if (enableConnect != null) 'enable_connect': enableConnect,
|
||||||
|
if (cacheMusic != null) 'cache_music': cacheMusic,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1694,7 +1731,8 @@ class PreferencesTableCompanion extends UpdateCompanion<PreferencesTableData> {
|
|||||||
Value<SourceCodecs>? downloadMusicCodec,
|
Value<SourceCodecs>? downloadMusicCodec,
|
||||||
Value<bool>? discordPresence,
|
Value<bool>? discordPresence,
|
||||||
Value<bool>? endlessPlayback,
|
Value<bool>? endlessPlayback,
|
||||||
Value<bool>? enableConnect}) {
|
Value<bool>? enableConnect,
|
||||||
|
Value<bool>? cacheMusic}) {
|
||||||
return PreferencesTableCompanion(
|
return PreferencesTableCompanion(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
audioQuality: audioQuality ?? this.audioQuality,
|
audioQuality: audioQuality ?? this.audioQuality,
|
||||||
@ -1722,6 +1760,7 @@ class PreferencesTableCompanion extends UpdateCompanion<PreferencesTableData> {
|
|||||||
discordPresence: discordPresence ?? this.discordPresence,
|
discordPresence: discordPresence ?? this.discordPresence,
|
||||||
endlessPlayback: endlessPlayback ?? this.endlessPlayback,
|
endlessPlayback: endlessPlayback ?? this.endlessPlayback,
|
||||||
enableConnect: enableConnect ?? this.enableConnect,
|
enableConnect: enableConnect ?? this.enableConnect,
|
||||||
|
cacheMusic: cacheMusic ?? this.cacheMusic,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1825,6 +1864,9 @@ class PreferencesTableCompanion extends UpdateCompanion<PreferencesTableData> {
|
|||||||
if (enableConnect.present) {
|
if (enableConnect.present) {
|
||||||
map['enable_connect'] = Variable<bool>(enableConnect.value);
|
map['enable_connect'] = Variable<bool>(enableConnect.value);
|
||||||
}
|
}
|
||||||
|
if (cacheMusic.present) {
|
||||||
|
map['cache_music'] = Variable<bool>(cacheMusic.value);
|
||||||
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1856,7 +1898,8 @@ class PreferencesTableCompanion extends UpdateCompanion<PreferencesTableData> {
|
|||||||
..write('downloadMusicCodec: $downloadMusicCodec, ')
|
..write('downloadMusicCodec: $downloadMusicCodec, ')
|
||||||
..write('discordPresence: $discordPresence, ')
|
..write('discordPresence: $discordPresence, ')
|
||||||
..write('endlessPlayback: $endlessPlayback, ')
|
..write('endlessPlayback: $endlessPlayback, ')
|
||||||
..write('enableConnect: $enableConnect')
|
..write('enableConnect: $enableConnect, ')
|
||||||
|
..write('cacheMusic: $cacheMusic')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
@ -4527,6 +4570,7 @@ typedef $$PreferencesTableTableCreateCompanionBuilder
|
|||||||
Value<bool> discordPresence,
|
Value<bool> discordPresence,
|
||||||
Value<bool> endlessPlayback,
|
Value<bool> endlessPlayback,
|
||||||
Value<bool> enableConnect,
|
Value<bool> enableConnect,
|
||||||
|
Value<bool> cacheMusic,
|
||||||
});
|
});
|
||||||
typedef $$PreferencesTableTableUpdateCompanionBuilder
|
typedef $$PreferencesTableTableUpdateCompanionBuilder
|
||||||
= PreferencesTableCompanion Function({
|
= PreferencesTableCompanion Function({
|
||||||
@ -4556,6 +4600,7 @@ typedef $$PreferencesTableTableUpdateCompanionBuilder
|
|||||||
Value<bool> discordPresence,
|
Value<bool> discordPresence,
|
||||||
Value<bool> endlessPlayback,
|
Value<bool> endlessPlayback,
|
||||||
Value<bool> enableConnect,
|
Value<bool> enableConnect,
|
||||||
|
Value<bool> cacheMusic,
|
||||||
});
|
});
|
||||||
|
|
||||||
class $$PreferencesTableTableFilterComposer
|
class $$PreferencesTableTableFilterComposer
|
||||||
@ -4677,6 +4722,9 @@ class $$PreferencesTableTableFilterComposer
|
|||||||
|
|
||||||
ColumnFilters<bool> get enableConnect => $composableBuilder(
|
ColumnFilters<bool> get enableConnect => $composableBuilder(
|
||||||
column: $table.enableConnect, builder: (column) => ColumnFilters(column));
|
column: $table.enableConnect, builder: (column) => ColumnFilters(column));
|
||||||
|
|
||||||
|
ColumnFilters<bool> get cacheMusic => $composableBuilder(
|
||||||
|
column: $table.cacheMusic, builder: (column) => ColumnFilters(column));
|
||||||
}
|
}
|
||||||
|
|
||||||
class $$PreferencesTableTableOrderingComposer
|
class $$PreferencesTableTableOrderingComposer
|
||||||
@ -4783,6 +4831,9 @@ class $$PreferencesTableTableOrderingComposer
|
|||||||
ColumnOrderings<bool> get enableConnect => $composableBuilder(
|
ColumnOrderings<bool> get enableConnect => $composableBuilder(
|
||||||
column: $table.enableConnect,
|
column: $table.enableConnect,
|
||||||
builder: (column) => ColumnOrderings(column));
|
builder: (column) => ColumnOrderings(column));
|
||||||
|
|
||||||
|
ColumnOrderings<bool> get cacheMusic => $composableBuilder(
|
||||||
|
column: $table.cacheMusic, builder: (column) => ColumnOrderings(column));
|
||||||
}
|
}
|
||||||
|
|
||||||
class $$PreferencesTableTableAnnotationComposer
|
class $$PreferencesTableTableAnnotationComposer
|
||||||
@ -4880,6 +4931,9 @@ class $$PreferencesTableTableAnnotationComposer
|
|||||||
|
|
||||||
GeneratedColumn<bool> get enableConnect => $composableBuilder(
|
GeneratedColumn<bool> get enableConnect => $composableBuilder(
|
||||||
column: $table.enableConnect, builder: (column) => column);
|
column: $table.enableConnect, builder: (column) => column);
|
||||||
|
|
||||||
|
GeneratedColumn<bool> get cacheMusic => $composableBuilder(
|
||||||
|
column: $table.cacheMusic, builder: (column) => column);
|
||||||
}
|
}
|
||||||
|
|
||||||
class $$PreferencesTableTableTableManager extends RootTableManager<
|
class $$PreferencesTableTableTableManager extends RootTableManager<
|
||||||
@ -4936,6 +4990,7 @@ class $$PreferencesTableTableTableManager extends RootTableManager<
|
|||||||
Value<bool> discordPresence = const Value.absent(),
|
Value<bool> discordPresence = const Value.absent(),
|
||||||
Value<bool> endlessPlayback = const Value.absent(),
|
Value<bool> endlessPlayback = const Value.absent(),
|
||||||
Value<bool> enableConnect = const Value.absent(),
|
Value<bool> enableConnect = const Value.absent(),
|
||||||
|
Value<bool> cacheMusic = const Value.absent(),
|
||||||
}) =>
|
}) =>
|
||||||
PreferencesTableCompanion(
|
PreferencesTableCompanion(
|
||||||
id: id,
|
id: id,
|
||||||
@ -4964,6 +5019,7 @@ class $$PreferencesTableTableTableManager extends RootTableManager<
|
|||||||
discordPresence: discordPresence,
|
discordPresence: discordPresence,
|
||||||
endlessPlayback: endlessPlayback,
|
endlessPlayback: endlessPlayback,
|
||||||
enableConnect: enableConnect,
|
enableConnect: enableConnect,
|
||||||
|
cacheMusic: cacheMusic,
|
||||||
),
|
),
|
||||||
createCompanionCallback: ({
|
createCompanionCallback: ({
|
||||||
Value<int> id = const Value.absent(),
|
Value<int> id = const Value.absent(),
|
||||||
@ -4992,6 +5048,7 @@ class $$PreferencesTableTableTableManager extends RootTableManager<
|
|||||||
Value<bool> discordPresence = const Value.absent(),
|
Value<bool> discordPresence = const Value.absent(),
|
||||||
Value<bool> endlessPlayback = const Value.absent(),
|
Value<bool> endlessPlayback = const Value.absent(),
|
||||||
Value<bool> enableConnect = const Value.absent(),
|
Value<bool> enableConnect = const Value.absent(),
|
||||||
|
Value<bool> cacheMusic = const Value.absent(),
|
||||||
}) =>
|
}) =>
|
||||||
PreferencesTableCompanion.insert(
|
PreferencesTableCompanion.insert(
|
||||||
id: id,
|
id: id,
|
||||||
@ -5020,6 +5077,7 @@ class $$PreferencesTableTableTableManager extends RootTableManager<
|
|||||||
discordPresence: discordPresence,
|
discordPresence: discordPresence,
|
||||||
endlessPlayback: endlessPlayback,
|
endlessPlayback: endlessPlayback,
|
||||||
enableConnect: enableConnect,
|
enableConnect: enableConnect,
|
||||||
|
cacheMusic: cacheMusic,
|
||||||
),
|
),
|
||||||
withReferenceMapper: (p0) => p0
|
withReferenceMapper: (p0) => p0
|
||||||
.map((e) => (e.readTable(table), BaseReferences(db, table, e)))
|
.map((e) => (e.readTable(table), BaseReferences(db, table, e)))
|
||||||
@ -5829,8 +5887,7 @@ final class $$PlaylistTableTableReferences extends BaseReferences<_$AppDatabase,
|
|||||||
db.audioPlayerStateTable.createAlias($_aliasNameGenerator(
|
db.audioPlayerStateTable.createAlias($_aliasNameGenerator(
|
||||||
db.playlistTable.audioPlayerStateId, db.audioPlayerStateTable.id));
|
db.playlistTable.audioPlayerStateId, db.audioPlayerStateTable.id));
|
||||||
|
|
||||||
$$AudioPlayerStateTableTableProcessedTableManager? get audioPlayerStateId {
|
$$AudioPlayerStateTableTableProcessedTableManager get audioPlayerStateId {
|
||||||
if ($_item.audioPlayerStateId == null) return null;
|
|
||||||
final manager = $$AudioPlayerStateTableTableTableManager(
|
final manager = $$AudioPlayerStateTableTableTableManager(
|
||||||
$_db, $_db.audioPlayerStateTable)
|
$_db, $_db.audioPlayerStateTable)
|
||||||
.filter((f) => f.id($_item.audioPlayerStateId!));
|
.filter((f) => f.id($_item.audioPlayerStateId!));
|
||||||
@ -6156,8 +6213,7 @@ final class $$PlaylistMediaTableTableReferences extends BaseReferences<
|
|||||||
db.playlistTable.createAlias($_aliasNameGenerator(
|
db.playlistTable.createAlias($_aliasNameGenerator(
|
||||||
db.playlistMediaTable.playlistId, db.playlistTable.id));
|
db.playlistMediaTable.playlistId, db.playlistTable.id));
|
||||||
|
|
||||||
$$PlaylistTableTableProcessedTableManager? get playlistId {
|
$$PlaylistTableTableProcessedTableManager get playlistId {
|
||||||
if ($_item.playlistId == null) return null;
|
|
||||||
final manager = $$PlaylistTableTableTableManager($_db, $_db.playlistTable)
|
final manager = $$PlaylistTableTableTableManager($_db, $_db.playlistTable)
|
||||||
.filter((f) => f.id($_item.playlistId!));
|
.filter((f) => f.id($_item.playlistId!));
|
||||||
final item = $_typedResult.readTableOrNull(_playlistIdTable($_db));
|
final item = $_typedResult.readTableOrNull(_playlistIdTable($_db));
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
|
// dart format width=80
|
||||||
import 'package:drift/internal/versioned_schema.dart' as i0;
|
import 'package:drift/internal/versioned_schema.dart' as i0;
|
||||||
import 'package:drift/drift.dart' as i1;
|
import 'package:drift/drift.dart' as i1;
|
||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart'; // ignore_for_file: type=lint,unused_import
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/services/sourced_track/enums.dart';
|
import 'package:spotube/services/sourced_track/enums.dart';
|
||||||
import 'package:spotube/utils/migrations/adapters.dart'; // ignore_for_file: type=lint,unused_import
|
import 'package:spotube/utils/migrations/adapters.dart';
|
||||||
|
|
||||||
// GENERATED BY drift_dev, DO NOT MODIFY.
|
// GENERATED BY drift_dev, DO NOT MODIFY.
|
||||||
final class Schema2 extends i0.VersionedSchema {
|
final class Schema2 extends i0.VersionedSchema {
|
||||||
@ -627,8 +628,288 @@ class Shape10 extends i0.VersionedTable {
|
|||||||
columnsByName['data']! as i1.GeneratedColumn<String>;
|
columnsByName['data']! as i1.GeneratedColumn<String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class Schema3 extends i0.VersionedSchema {
|
||||||
|
Schema3({required super.database}) : super(version: 3);
|
||||||
|
@override
|
||||||
|
late final List<i1.DatabaseSchemaEntity> entities = [
|
||||||
|
authenticationTable,
|
||||||
|
blacklistTable,
|
||||||
|
preferencesTable,
|
||||||
|
scrobblerTable,
|
||||||
|
skipSegmentTable,
|
||||||
|
sourceMatchTable,
|
||||||
|
audioPlayerStateTable,
|
||||||
|
playlistTable,
|
||||||
|
playlistMediaTable,
|
||||||
|
historyTable,
|
||||||
|
lyricsTable,
|
||||||
|
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 Shape11 preferencesTable = Shape11(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'preferences_table',
|
||||||
|
withoutRowId: false,
|
||||||
|
isStrict: false,
|
||||||
|
tableConstraints: [],
|
||||||
|
columns: [
|
||||||
|
_column_0,
|
||||||
|
_column_7,
|
||||||
|
_column_8,
|
||||||
|
_column_9,
|
||||||
|
_column_10,
|
||||||
|
_column_11,
|
||||||
|
_column_12,
|
||||||
|
_column_13,
|
||||||
|
_column_14,
|
||||||
|
_column_15,
|
||||||
|
_column_16,
|
||||||
|
_column_17,
|
||||||
|
_column_18,
|
||||||
|
_column_19,
|
||||||
|
_column_20,
|
||||||
|
_column_21,
|
||||||
|
_column_22,
|
||||||
|
_column_23,
|
||||||
|
_column_24,
|
||||||
|
_column_25,
|
||||||
|
_column_26,
|
||||||
|
_column_27,
|
||||||
|
_column_28,
|
||||||
|
_column_29,
|
||||||
|
_column_30,
|
||||||
|
_column_31,
|
||||||
|
_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 Shape5 sourceMatchTable = Shape5(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'source_match_table',
|
||||||
|
withoutRowId: false,
|
||||||
|
isStrict: false,
|
||||||
|
tableConstraints: [],
|
||||||
|
columns: [
|
||||||
|
_column_0,
|
||||||
|
_column_37,
|
||||||
|
_column_38,
|
||||||
|
_column_39,
|
||||||
|
_column_32,
|
||||||
|
],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null);
|
||||||
|
late final Shape6 audioPlayerStateTable = Shape6(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'audio_player_state_table',
|
||||||
|
withoutRowId: false,
|
||||||
|
isStrict: false,
|
||||||
|
tableConstraints: [],
|
||||||
|
columns: [
|
||||||
|
_column_0,
|
||||||
|
_column_40,
|
||||||
|
_column_41,
|
||||||
|
_column_42,
|
||||||
|
_column_43,
|
||||||
|
],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null);
|
||||||
|
late final Shape7 playlistTable = Shape7(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'playlist_table',
|
||||||
|
withoutRowId: false,
|
||||||
|
isStrict: false,
|
||||||
|
tableConstraints: [],
|
||||||
|
columns: [
|
||||||
|
_column_0,
|
||||||
|
_column_44,
|
||||||
|
_column_45,
|
||||||
|
],
|
||||||
|
attachedDatabase: database,
|
||||||
|
),
|
||||||
|
alias: null);
|
||||||
|
late final Shape8 playlistMediaTable = Shape8(
|
||||||
|
source: i0.VersionedTable(
|
||||||
|
entityName: 'playlist_media_table',
|
||||||
|
withoutRowId: false,
|
||||||
|
isStrict: false,
|
||||||
|
tableConstraints: [],
|
||||||
|
columns: [
|
||||||
|
_column_0,
|
||||||
|
_column_46,
|
||||||
|
_column_47,
|
||||||
|
_column_48,
|
||||||
|
_column_49,
|
||||||
|
],
|
||||||
|
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);
|
||||||
|
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_id, source_type)');
|
||||||
|
}
|
||||||
|
|
||||||
|
class Shape11 extends i0.VersionedTable {
|
||||||
|
Shape11({required super.source, required super.alias}) : super.aliased();
|
||||||
|
i1.GeneratedColumn<int> get id =>
|
||||||
|
columnsByName['id']! as i1.GeneratedColumn<int>;
|
||||||
|
i1.GeneratedColumn<String> get audioQuality =>
|
||||||
|
columnsByName['audio_quality']! as i1.GeneratedColumn<String>;
|
||||||
|
i1.GeneratedColumn<bool> get albumColorSync =>
|
||||||
|
columnsByName['album_color_sync']! as i1.GeneratedColumn<bool>;
|
||||||
|
i1.GeneratedColumn<bool> get amoledDarkTheme =>
|
||||||
|
columnsByName['amoled_dark_theme']! as i1.GeneratedColumn<bool>;
|
||||||
|
i1.GeneratedColumn<bool> get checkUpdate =>
|
||||||
|
columnsByName['check_update']! as i1.GeneratedColumn<bool>;
|
||||||
|
i1.GeneratedColumn<bool> get normalizeAudio =>
|
||||||
|
columnsByName['normalize_audio']! as i1.GeneratedColumn<bool>;
|
||||||
|
i1.GeneratedColumn<bool> get showSystemTrayIcon =>
|
||||||
|
columnsByName['show_system_tray_icon']! as i1.GeneratedColumn<bool>;
|
||||||
|
i1.GeneratedColumn<bool> get systemTitleBar =>
|
||||||
|
columnsByName['system_title_bar']! as i1.GeneratedColumn<bool>;
|
||||||
|
i1.GeneratedColumn<bool> get skipNonMusic =>
|
||||||
|
columnsByName['skip_non_music']! as i1.GeneratedColumn<bool>;
|
||||||
|
i1.GeneratedColumn<String> get closeBehavior =>
|
||||||
|
columnsByName['close_behavior']! as i1.GeneratedColumn<String>;
|
||||||
|
i1.GeneratedColumn<String> get accentColorScheme =>
|
||||||
|
columnsByName['accent_color_scheme']! as i1.GeneratedColumn<String>;
|
||||||
|
i1.GeneratedColumn<String> get layoutMode =>
|
||||||
|
columnsByName['layout_mode']! as i1.GeneratedColumn<String>;
|
||||||
|
i1.GeneratedColumn<String> get locale =>
|
||||||
|
columnsByName['locale']! as i1.GeneratedColumn<String>;
|
||||||
|
i1.GeneratedColumn<String> get market =>
|
||||||
|
columnsByName['market']! as i1.GeneratedColumn<String>;
|
||||||
|
i1.GeneratedColumn<String> get searchMode =>
|
||||||
|
columnsByName['search_mode']! as i1.GeneratedColumn<String>;
|
||||||
|
i1.GeneratedColumn<String> get downloadLocation =>
|
||||||
|
columnsByName['download_location']! as i1.GeneratedColumn<String>;
|
||||||
|
i1.GeneratedColumn<String> get localLibraryLocation =>
|
||||||
|
columnsByName['local_library_location']! as i1.GeneratedColumn<String>;
|
||||||
|
i1.GeneratedColumn<String> get pipedInstance =>
|
||||||
|
columnsByName['piped_instance']! as i1.GeneratedColumn<String>;
|
||||||
|
i1.GeneratedColumn<String> get invidiousInstance =>
|
||||||
|
columnsByName['invidious_instance']! as i1.GeneratedColumn<String>;
|
||||||
|
i1.GeneratedColumn<String> get themeMode =>
|
||||||
|
columnsByName['theme_mode']! as i1.GeneratedColumn<String>;
|
||||||
|
i1.GeneratedColumn<String> get audioSource =>
|
||||||
|
columnsByName['audio_source']! as i1.GeneratedColumn<String>;
|
||||||
|
i1.GeneratedColumn<String> get streamMusicCodec =>
|
||||||
|
columnsByName['stream_music_codec']! as i1.GeneratedColumn<String>;
|
||||||
|
i1.GeneratedColumn<String> get downloadMusicCodec =>
|
||||||
|
columnsByName['download_music_codec']! as i1.GeneratedColumn<String>;
|
||||||
|
i1.GeneratedColumn<bool> get discordPresence =>
|
||||||
|
columnsByName['discord_presence']! as i1.GeneratedColumn<bool>;
|
||||||
|
i1.GeneratedColumn<bool> get endlessPlayback =>
|
||||||
|
columnsByName['endless_playback']! as i1.GeneratedColumn<bool>;
|
||||||
|
i1.GeneratedColumn<bool> get enableConnect =>
|
||||||
|
columnsByName['enable_connect']! as i1.GeneratedColumn<bool>;
|
||||||
|
i1.GeneratedColumn<bool> get cacheMusic =>
|
||||||
|
columnsByName['cache_music']! as i1.GeneratedColumn<bool>;
|
||||||
|
}
|
||||||
|
|
||||||
|
i1.GeneratedColumn<bool> _column_53(String aliasedName) =>
|
||||||
|
i1.GeneratedColumn<bool>('cache_music', aliasedName, false,
|
||||||
|
type: i1.DriftSqlType.bool,
|
||||||
|
defaultConstraints: i1.GeneratedColumn.constraintIsAlways(
|
||||||
|
'CHECK ("cache_music" IN (0, 1))'),
|
||||||
|
defaultValue: const Constant(true));
|
||||||
i0.MigrationStepWithVersion migrationSteps({
|
i0.MigrationStepWithVersion migrationSteps({
|
||||||
required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
|
required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
|
||||||
|
required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
|
||||||
}) {
|
}) {
|
||||||
return (currentVersion, database) async {
|
return (currentVersion, database) async {
|
||||||
switch (currentVersion) {
|
switch (currentVersion) {
|
||||||
@ -637,6 +918,11 @@ i0.MigrationStepWithVersion migrationSteps({
|
|||||||
final migrator = i1.Migrator(database, schema);
|
final migrator = i1.Migrator(database, schema);
|
||||||
await from1To2(migrator, schema);
|
await from1To2(migrator, schema);
|
||||||
return 2;
|
return 2;
|
||||||
|
case 2:
|
||||||
|
final schema = Schema3(database: database);
|
||||||
|
final migrator = i1.Migrator(database, schema);
|
||||||
|
await from2To3(migrator, schema);
|
||||||
|
return 3;
|
||||||
default:
|
default:
|
||||||
throw ArgumentError.value('Unknown migration from $currentVersion');
|
throw ArgumentError.value('Unknown migration from $currentVersion');
|
||||||
}
|
}
|
||||||
@ -645,8 +931,10 @@ i0.MigrationStepWithVersion migrationSteps({
|
|||||||
|
|
||||||
i1.OnUpgrade stepByStep({
|
i1.OnUpgrade stepByStep({
|
||||||
required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
|
required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
|
||||||
|
required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
|
||||||
}) =>
|
}) =>
|
||||||
i0.VersionedSchema.stepByStepHelper(
|
i0.VersionedSchema.stepByStepHelper(
|
||||||
step: migrationSteps(
|
step: migrationSteps(
|
||||||
from1To2: from1To2,
|
from1To2: from1To2,
|
||||||
|
from2To3: from2To3,
|
||||||
));
|
));
|
||||||
|
@ -94,6 +94,7 @@ class PreferencesTable extends Table {
|
|||||||
boolean().withDefault(const Constant(true))();
|
boolean().withDefault(const Constant(true))();
|
||||||
BoolColumn get enableConnect =>
|
BoolColumn get enableConnect =>
|
||||||
boolean().withDefault(const Constant(false))();
|
boolean().withDefault(const Constant(false))();
|
||||||
|
BoolColumn get cacheMusic => boolean().withDefault(const Constant(true))();
|
||||||
|
|
||||||
// Default values as PreferencesTableData
|
// Default values as PreferencesTableData
|
||||||
static PreferencesTableData defaults() {
|
static PreferencesTableData defaults() {
|
||||||
@ -119,11 +120,12 @@ class PreferencesTable extends Table {
|
|||||||
invidiousInstance: "https://inv.nadeko.net",
|
invidiousInstance: "https://inv.nadeko.net",
|
||||||
themeMode: ThemeMode.system,
|
themeMode: ThemeMode.system,
|
||||||
audioSource: AudioSource.youtube,
|
audioSource: AudioSource.youtube,
|
||||||
streamMusicCodec: SourceCodecs.weba,
|
streamMusicCodec: SourceCodecs.m4a,
|
||||||
downloadMusicCodec: SourceCodecs.m4a,
|
downloadMusicCodec: SourceCodecs.m4a,
|
||||||
discordPresence: true,
|
discordPresence: true,
|
||||||
endlessPlayback: true,
|
endlessPlayback: true,
|
||||||
enableConnect: false,
|
enableConnect: false,
|
||||||
|
cacheMusic: true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
71
lib/models/parser/range_headers.dart
Normal file
71
lib/models/parser/range_headers.dart
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
class ContentRangeHeader {
|
||||||
|
final int start;
|
||||||
|
final int end;
|
||||||
|
final int total;
|
||||||
|
|
||||||
|
ContentRangeHeader(this.start, this.end, this.total);
|
||||||
|
|
||||||
|
factory ContentRangeHeader.parse(String value) {
|
||||||
|
if (value.isEmpty) {
|
||||||
|
throw FormatException('Invalid Content-Range header: $value');
|
||||||
|
}
|
||||||
|
|
||||||
|
final parts = value.split(' ');
|
||||||
|
if (parts.length != 2) {
|
||||||
|
throw FormatException('Invalid Content-Range header: $value');
|
||||||
|
}
|
||||||
|
|
||||||
|
final rangeParts = parts[1].split('/');
|
||||||
|
if (rangeParts.length != 2) {
|
||||||
|
throw FormatException('Invalid Content-Range header: $value');
|
||||||
|
}
|
||||||
|
|
||||||
|
final range = rangeParts[0].split('-');
|
||||||
|
if (range.length != 2) {
|
||||||
|
throw FormatException('Invalid Content-Range header: $value');
|
||||||
|
}
|
||||||
|
|
||||||
|
return ContentRangeHeader(
|
||||||
|
int.parse(range[0]),
|
||||||
|
int.parse(range[1]),
|
||||||
|
int.parse(rangeParts[1]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'bytes $start-$end/$total';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RangeHeader {
|
||||||
|
final int start;
|
||||||
|
final int? end;
|
||||||
|
|
||||||
|
RangeHeader(this.start, this.end);
|
||||||
|
|
||||||
|
factory RangeHeader.parse(String value) {
|
||||||
|
if (value.isEmpty) {
|
||||||
|
return RangeHeader(0, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
final parts = value.split('=');
|
||||||
|
if (parts.length != 2) {
|
||||||
|
throw FormatException('Invalid Range header: $value');
|
||||||
|
}
|
||||||
|
|
||||||
|
final ranges = parts[1].split('-');
|
||||||
|
|
||||||
|
return RangeHeader(
|
||||||
|
int.parse(ranges[0]),
|
||||||
|
ranges.elementAtOrNull(1) != null && ranges[1].isNotEmpty
|
||||||
|
? int.parse(ranges[1])
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'bytes=$start-${end ?? ""}';
|
||||||
|
}
|
||||||
|
}
|
@ -29,8 +29,12 @@ mixin _$SpotifySectionPlaylist {
|
|||||||
String get owner => throw _privateConstructorUsedError;
|
String get owner => throw _privateConstructorUsedError;
|
||||||
String get uri => throw _privateConstructorUsedError;
|
String get uri => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Serializes this SpotifySectionPlaylist to a JSON map.
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
@JsonKey(ignore: true)
|
|
||||||
|
/// Create a copy of SpotifySectionPlaylist
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
$SpotifySectionPlaylistCopyWith<SpotifySectionPlaylist> get copyWith =>
|
$SpotifySectionPlaylistCopyWith<SpotifySectionPlaylist> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -61,6 +65,8 @@ class _$SpotifySectionPlaylistCopyWithImpl<$Res,
|
|||||||
// ignore: unused_field
|
// ignore: unused_field
|
||||||
final $Res Function($Val) _then;
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SpotifySectionPlaylist
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -128,6 +134,8 @@ class __$$SpotifySectionPlaylistImplCopyWithImpl<$Res>
|
|||||||
$Res Function(_$SpotifySectionPlaylistImpl) _then)
|
$Res Function(_$SpotifySectionPlaylistImpl) _then)
|
||||||
: super(_value, _then);
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of SpotifySectionPlaylist
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -221,12 +229,14 @@ class _$SpotifySectionPlaylistImpl extends _SpotifySectionPlaylist {
|
|||||||
(identical(other.uri, uri) || other.uri == uri));
|
(identical(other.uri, uri) || other.uri == uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType, description, format,
|
int get hashCode => Object.hash(runtimeType, description, format,
|
||||||
const DeepCollectionEquality().hash(_images), name, owner, uri);
|
const DeepCollectionEquality().hash(_images), name, owner, uri);
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
/// Create a copy of SpotifySectionPlaylist
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
_$$SpotifySectionPlaylistImplCopyWith<_$SpotifySectionPlaylistImpl>
|
_$$SpotifySectionPlaylistImplCopyWith<_$SpotifySectionPlaylistImpl>
|
||||||
@ -266,8 +276,11 @@ abstract class _SpotifySectionPlaylist extends SpotifySectionPlaylist {
|
|||||||
String get owner;
|
String get owner;
|
||||||
@override
|
@override
|
||||||
String get uri;
|
String get uri;
|
||||||
|
|
||||||
|
/// Create a copy of SpotifySectionPlaylist
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
_$$SpotifySectionPlaylistImplCopyWith<_$SpotifySectionPlaylistImpl>
|
_$$SpotifySectionPlaylistImplCopyWith<_$SpotifySectionPlaylistImpl>
|
||||||
get copyWith => throw _privateConstructorUsedError;
|
get copyWith => throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -283,8 +296,12 @@ mixin _$SpotifySectionArtist {
|
|||||||
List<SpotifySectionItemImage> get images =>
|
List<SpotifySectionItemImage> get images =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Serializes this SpotifySectionArtist to a JSON map.
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
@JsonKey(ignore: true)
|
|
||||||
|
/// Create a copy of SpotifySectionArtist
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
$SpotifySectionArtistCopyWith<SpotifySectionArtist> get copyWith =>
|
$SpotifySectionArtistCopyWith<SpotifySectionArtist> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -309,6 +326,8 @@ class _$SpotifySectionArtistCopyWithImpl<$Res,
|
|||||||
// ignore: unused_field
|
// ignore: unused_field
|
||||||
final $Res Function($Val) _then;
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SpotifySectionArtist
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -352,6 +371,8 @@ class __$$SpotifySectionArtistImplCopyWithImpl<$Res>
|
|||||||
$Res Function(_$SpotifySectionArtistImpl) _then)
|
$Res Function(_$SpotifySectionArtistImpl) _then)
|
||||||
: super(_value, _then);
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of SpotifySectionArtist
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -416,12 +437,14 @@ class _$SpotifySectionArtistImpl extends _SpotifySectionArtist {
|
|||||||
const DeepCollectionEquality().equals(other._images, _images));
|
const DeepCollectionEquality().equals(other._images, _images));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(
|
int get hashCode => Object.hash(
|
||||||
runtimeType, name, uri, const DeepCollectionEquality().hash(_images));
|
runtimeType, name, uri, const DeepCollectionEquality().hash(_images));
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
/// Create a copy of SpotifySectionArtist
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
_$$SpotifySectionArtistImplCopyWith<_$SpotifySectionArtistImpl>
|
_$$SpotifySectionArtistImplCopyWith<_$SpotifySectionArtistImpl>
|
||||||
@ -454,8 +477,11 @@ abstract class _SpotifySectionArtist extends SpotifySectionArtist {
|
|||||||
String get uri;
|
String get uri;
|
||||||
@override
|
@override
|
||||||
List<SpotifySectionItemImage> get images;
|
List<SpotifySectionItemImage> get images;
|
||||||
|
|
||||||
|
/// Create a copy of SpotifySectionArtist
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
_$$SpotifySectionArtistImplCopyWith<_$SpotifySectionArtistImpl>
|
_$$SpotifySectionArtistImplCopyWith<_$SpotifySectionArtistImpl>
|
||||||
get copyWith => throw _privateConstructorUsedError;
|
get copyWith => throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -473,8 +499,12 @@ mixin _$SpotifySectionAlbum {
|
|||||||
String get name => throw _privateConstructorUsedError;
|
String get name => throw _privateConstructorUsedError;
|
||||||
String get uri => throw _privateConstructorUsedError;
|
String get uri => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Serializes this SpotifySectionAlbum to a JSON map.
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
@JsonKey(ignore: true)
|
|
||||||
|
/// Create a copy of SpotifySectionAlbum
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
$SpotifySectionAlbumCopyWith<SpotifySectionAlbum> get copyWith =>
|
$SpotifySectionAlbumCopyWith<SpotifySectionAlbum> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -502,6 +532,8 @@ class _$SpotifySectionAlbumCopyWithImpl<$Res, $Val extends SpotifySectionAlbum>
|
|||||||
// ignore: unused_field
|
// ignore: unused_field
|
||||||
final $Res Function($Val) _then;
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SpotifySectionAlbum
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -554,6 +586,8 @@ class __$$SpotifySectionAlbumImplCopyWithImpl<$Res>
|
|||||||
$Res Function(_$SpotifySectionAlbumImpl) _then)
|
$Res Function(_$SpotifySectionAlbumImpl) _then)
|
||||||
: super(_value, _then);
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of SpotifySectionAlbum
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -635,7 +669,7 @@ class _$SpotifySectionAlbumImpl extends _SpotifySectionAlbum {
|
|||||||
(identical(other.uri, uri) || other.uri == uri));
|
(identical(other.uri, uri) || other.uri == uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(
|
int get hashCode => Object.hash(
|
||||||
runtimeType,
|
runtimeType,
|
||||||
@ -644,7 +678,9 @@ class _$SpotifySectionAlbumImpl extends _SpotifySectionAlbum {
|
|||||||
name,
|
name,
|
||||||
uri);
|
uri);
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
/// Create a copy of SpotifySectionAlbum
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
_$$SpotifySectionAlbumImplCopyWith<_$SpotifySectionAlbumImpl> get copyWith =>
|
_$$SpotifySectionAlbumImplCopyWith<_$SpotifySectionAlbumImpl> get copyWith =>
|
||||||
@ -678,8 +714,11 @@ abstract class _SpotifySectionAlbum extends SpotifySectionAlbum {
|
|||||||
String get name;
|
String get name;
|
||||||
@override
|
@override
|
||||||
String get uri;
|
String get uri;
|
||||||
|
|
||||||
|
/// Create a copy of SpotifySectionAlbum
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
_$$SpotifySectionAlbumImplCopyWith<_$SpotifySectionAlbumImpl> get copyWith =>
|
_$$SpotifySectionAlbumImplCopyWith<_$SpotifySectionAlbumImpl> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -694,8 +733,12 @@ mixin _$SpotifySectionAlbumArtist {
|
|||||||
String get name => throw _privateConstructorUsedError;
|
String get name => throw _privateConstructorUsedError;
|
||||||
String get uri => throw _privateConstructorUsedError;
|
String get uri => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Serializes this SpotifySectionAlbumArtist to a JSON map.
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
@JsonKey(ignore: true)
|
|
||||||
|
/// Create a copy of SpotifySectionAlbumArtist
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
$SpotifySectionAlbumArtistCopyWith<SpotifySectionAlbumArtist> get copyWith =>
|
$SpotifySectionAlbumArtistCopyWith<SpotifySectionAlbumArtist> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -720,6 +763,8 @@ class _$SpotifySectionAlbumArtistCopyWithImpl<$Res,
|
|||||||
// ignore: unused_field
|
// ignore: unused_field
|
||||||
final $Res Function($Val) _then;
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SpotifySectionAlbumArtist
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -761,6 +806,8 @@ class __$$SpotifySectionAlbumArtistImplCopyWithImpl<$Res>
|
|||||||
$Res Function(_$SpotifySectionAlbumArtistImpl) _then)
|
$Res Function(_$SpotifySectionAlbumArtistImpl) _then)
|
||||||
: super(_value, _then);
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of SpotifySectionAlbumArtist
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -808,11 +855,13 @@ class _$SpotifySectionAlbumArtistImpl extends _SpotifySectionAlbumArtist {
|
|||||||
(identical(other.uri, uri) || other.uri == uri));
|
(identical(other.uri, uri) || other.uri == uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType, name, uri);
|
int get hashCode => Object.hash(runtimeType, name, uri);
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
/// Create a copy of SpotifySectionAlbumArtist
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
_$$SpotifySectionAlbumArtistImplCopyWith<_$SpotifySectionAlbumArtistImpl>
|
_$$SpotifySectionAlbumArtistImplCopyWith<_$SpotifySectionAlbumArtistImpl>
|
||||||
@ -840,8 +889,11 @@ abstract class _SpotifySectionAlbumArtist extends SpotifySectionAlbumArtist {
|
|||||||
String get name;
|
String get name;
|
||||||
@override
|
@override
|
||||||
String get uri;
|
String get uri;
|
||||||
|
|
||||||
|
/// Create a copy of SpotifySectionAlbumArtist
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
_$$SpotifySectionAlbumArtistImplCopyWith<_$SpotifySectionAlbumArtistImpl>
|
_$$SpotifySectionAlbumArtistImplCopyWith<_$SpotifySectionAlbumArtistImpl>
|
||||||
get copyWith => throw _privateConstructorUsedError;
|
get copyWith => throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -857,8 +909,12 @@ mixin _$SpotifySectionItemImage {
|
|||||||
String get url => throw _privateConstructorUsedError;
|
String get url => throw _privateConstructorUsedError;
|
||||||
num? get width => throw _privateConstructorUsedError;
|
num? get width => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Serializes this SpotifySectionItemImage to a JSON map.
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
@JsonKey(ignore: true)
|
|
||||||
|
/// Create a copy of SpotifySectionItemImage
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
$SpotifySectionItemImageCopyWith<SpotifySectionItemImage> get copyWith =>
|
$SpotifySectionItemImageCopyWith<SpotifySectionItemImage> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -883,6 +939,8 @@ class _$SpotifySectionItemImageCopyWithImpl<$Res,
|
|||||||
// ignore: unused_field
|
// ignore: unused_field
|
||||||
final $Res Function($Val) _then;
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SpotifySectionItemImage
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -929,6 +987,8 @@ class __$$SpotifySectionItemImageImplCopyWithImpl<$Res>
|
|||||||
$Res Function(_$SpotifySectionItemImageImpl) _then)
|
$Res Function(_$SpotifySectionItemImageImpl) _then)
|
||||||
: super(_value, _then);
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of SpotifySectionItemImage
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -985,11 +1045,13 @@ class _$SpotifySectionItemImageImpl extends _SpotifySectionItemImage {
|
|||||||
(identical(other.width, width) || other.width == width));
|
(identical(other.width, width) || other.width == width));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType, height, url, width);
|
int get hashCode => Object.hash(runtimeType, height, url, width);
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
/// Create a copy of SpotifySectionItemImage
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
_$$SpotifySectionItemImageImplCopyWith<_$SpotifySectionItemImageImpl>
|
_$$SpotifySectionItemImageImplCopyWith<_$SpotifySectionItemImageImpl>
|
||||||
@ -1020,8 +1082,11 @@ abstract class _SpotifySectionItemImage extends SpotifySectionItemImage {
|
|||||||
String get url;
|
String get url;
|
||||||
@override
|
@override
|
||||||
num? get width;
|
num? get width;
|
||||||
|
|
||||||
|
/// Create a copy of SpotifySectionItemImage
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
_$$SpotifySectionItemImageImplCopyWith<_$SpotifySectionItemImageImpl>
|
_$$SpotifySectionItemImageImplCopyWith<_$SpotifySectionItemImageImpl>
|
||||||
get copyWith => throw _privateConstructorUsedError;
|
get copyWith => throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -1038,8 +1103,12 @@ mixin _$SpotifyHomeFeedSectionItem {
|
|||||||
SpotifySectionArtist? get artist => throw _privateConstructorUsedError;
|
SpotifySectionArtist? get artist => throw _privateConstructorUsedError;
|
||||||
SpotifySectionAlbum? get album => throw _privateConstructorUsedError;
|
SpotifySectionAlbum? get album => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Serializes this SpotifyHomeFeedSectionItem to a JSON map.
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
@JsonKey(ignore: true)
|
|
||||||
|
/// Create a copy of SpotifyHomeFeedSectionItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
$SpotifyHomeFeedSectionItemCopyWith<SpotifyHomeFeedSectionItem>
|
$SpotifyHomeFeedSectionItemCopyWith<SpotifyHomeFeedSectionItem>
|
||||||
get copyWith => throw _privateConstructorUsedError;
|
get copyWith => throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -1073,6 +1142,8 @@ class _$SpotifyHomeFeedSectionItemCopyWithImpl<$Res,
|
|||||||
// ignore: unused_field
|
// ignore: unused_field
|
||||||
final $Res Function($Val) _then;
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SpotifyHomeFeedSectionItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -1101,6 +1172,8 @@ class _$SpotifyHomeFeedSectionItemCopyWithImpl<$Res,
|
|||||||
) as $Val);
|
) as $Val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a copy of SpotifyHomeFeedSectionItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
$SpotifySectionPlaylistCopyWith<$Res>? get playlist {
|
$SpotifySectionPlaylistCopyWith<$Res>? get playlist {
|
||||||
@ -1113,6 +1186,8 @@ class _$SpotifyHomeFeedSectionItemCopyWithImpl<$Res,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a copy of SpotifyHomeFeedSectionItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
$SpotifySectionArtistCopyWith<$Res>? get artist {
|
$SpotifySectionArtistCopyWith<$Res>? get artist {
|
||||||
@ -1125,6 +1200,8 @@ class _$SpotifyHomeFeedSectionItemCopyWithImpl<$Res,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a copy of SpotifyHomeFeedSectionItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
$SpotifySectionAlbumCopyWith<$Res>? get album {
|
$SpotifySectionAlbumCopyWith<$Res>? get album {
|
||||||
@ -1171,6 +1248,8 @@ class __$$SpotifyHomeFeedSectionItemImplCopyWithImpl<$Res>
|
|||||||
$Res Function(_$SpotifyHomeFeedSectionItemImpl) _then)
|
$Res Function(_$SpotifyHomeFeedSectionItemImpl) _then)
|
||||||
: super(_value, _then);
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of SpotifyHomeFeedSectionItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -1237,12 +1316,14 @@ class _$SpotifyHomeFeedSectionItemImpl implements _SpotifyHomeFeedSectionItem {
|
|||||||
(identical(other.album, album) || other.album == album));
|
(identical(other.album, album) || other.album == album));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
Object.hash(runtimeType, typename, playlist, artist, album);
|
Object.hash(runtimeType, typename, playlist, artist, album);
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
/// Create a copy of SpotifyHomeFeedSectionItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
_$$SpotifyHomeFeedSectionItemImplCopyWith<_$SpotifyHomeFeedSectionItemImpl>
|
_$$SpotifyHomeFeedSectionItemImplCopyWith<_$SpotifyHomeFeedSectionItemImpl>
|
||||||
@ -1276,8 +1357,11 @@ abstract class _SpotifyHomeFeedSectionItem
|
|||||||
SpotifySectionArtist? get artist;
|
SpotifySectionArtist? get artist;
|
||||||
@override
|
@override
|
||||||
SpotifySectionAlbum? get album;
|
SpotifySectionAlbum? get album;
|
||||||
|
|
||||||
|
/// Create a copy of SpotifyHomeFeedSectionItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
_$$SpotifyHomeFeedSectionItemImplCopyWith<_$SpotifyHomeFeedSectionItemImpl>
|
_$$SpotifyHomeFeedSectionItemImplCopyWith<_$SpotifyHomeFeedSectionItemImpl>
|
||||||
get copyWith => throw _privateConstructorUsedError;
|
get copyWith => throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -1295,8 +1379,12 @@ mixin _$SpotifyHomeFeedSection {
|
|||||||
List<SpotifyHomeFeedSectionItem> get items =>
|
List<SpotifyHomeFeedSectionItem> get items =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Serializes this SpotifyHomeFeedSection to a JSON map.
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
@JsonKey(ignore: true)
|
|
||||||
|
/// Create a copy of SpotifyHomeFeedSection
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
$SpotifyHomeFeedSectionCopyWith<SpotifyHomeFeedSection> get copyWith =>
|
$SpotifyHomeFeedSectionCopyWith<SpotifyHomeFeedSection> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -1325,6 +1413,8 @@ class _$SpotifyHomeFeedSectionCopyWithImpl<$Res,
|
|||||||
// ignore: unused_field
|
// ignore: unused_field
|
||||||
final $Res Function($Val) _then;
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SpotifyHomeFeedSection
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -1380,6 +1470,8 @@ class __$$SpotifyHomeFeedSectionImplCopyWithImpl<$Res>
|
|||||||
$Res Function(_$SpotifyHomeFeedSectionImpl) _then)
|
$Res Function(_$SpotifyHomeFeedSectionImpl) _then)
|
||||||
: super(_value, _then);
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of SpotifyHomeFeedSection
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -1453,12 +1545,14 @@ class _$SpotifyHomeFeedSectionImpl implements _SpotifyHomeFeedSection {
|
|||||||
const DeepCollectionEquality().equals(other._items, _items));
|
const DeepCollectionEquality().equals(other._items, _items));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType, typename, title, uri,
|
int get hashCode => Object.hash(runtimeType, typename, title, uri,
|
||||||
const DeepCollectionEquality().hash(_items));
|
const DeepCollectionEquality().hash(_items));
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
/// Create a copy of SpotifyHomeFeedSection
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
_$$SpotifyHomeFeedSectionImplCopyWith<_$SpotifyHomeFeedSectionImpl>
|
_$$SpotifyHomeFeedSectionImplCopyWith<_$SpotifyHomeFeedSectionImpl>
|
||||||
@ -1492,8 +1586,11 @@ abstract class _SpotifyHomeFeedSection implements SpotifyHomeFeedSection {
|
|||||||
String get uri;
|
String get uri;
|
||||||
@override
|
@override
|
||||||
List<SpotifyHomeFeedSectionItem> get items;
|
List<SpotifyHomeFeedSectionItem> get items;
|
||||||
|
|
||||||
|
/// Create a copy of SpotifyHomeFeedSection
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
_$$SpotifyHomeFeedSectionImplCopyWith<_$SpotifyHomeFeedSectionImpl>
|
_$$SpotifyHomeFeedSectionImplCopyWith<_$SpotifyHomeFeedSectionImpl>
|
||||||
get copyWith => throw _privateConstructorUsedError;
|
get copyWith => throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -1508,8 +1605,12 @@ mixin _$SpotifyHomeFeed {
|
|||||||
List<SpotifyHomeFeedSection> get sections =>
|
List<SpotifyHomeFeedSection> get sections =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Serializes this SpotifyHomeFeed to a JSON map.
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
@JsonKey(ignore: true)
|
|
||||||
|
/// Create a copy of SpotifyHomeFeed
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
$SpotifyHomeFeedCopyWith<SpotifyHomeFeed> get copyWith =>
|
$SpotifyHomeFeedCopyWith<SpotifyHomeFeed> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -1533,6 +1634,8 @@ class _$SpotifyHomeFeedCopyWithImpl<$Res, $Val extends SpotifyHomeFeed>
|
|||||||
// ignore: unused_field
|
// ignore: unused_field
|
||||||
final $Res Function($Val) _then;
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SpotifyHomeFeed
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -1571,6 +1674,8 @@ class __$$SpotifyHomeFeedImplCopyWithImpl<$Res>
|
|||||||
_$SpotifyHomeFeedImpl _value, $Res Function(_$SpotifyHomeFeedImpl) _then)
|
_$SpotifyHomeFeedImpl _value, $Res Function(_$SpotifyHomeFeedImpl) _then)
|
||||||
: super(_value, _then);
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of SpotifyHomeFeed
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -1626,12 +1731,14 @@ class _$SpotifyHomeFeedImpl implements _SpotifyHomeFeed {
|
|||||||
const DeepCollectionEquality().equals(other._sections, _sections));
|
const DeepCollectionEquality().equals(other._sections, _sections));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(
|
int get hashCode => Object.hash(
|
||||||
runtimeType, greeting, const DeepCollectionEquality().hash(_sections));
|
runtimeType, greeting, const DeepCollectionEquality().hash(_sections));
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
/// Create a copy of SpotifyHomeFeed
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
_$$SpotifyHomeFeedImplCopyWith<_$SpotifyHomeFeedImpl> get copyWith =>
|
_$$SpotifyHomeFeedImplCopyWith<_$SpotifyHomeFeedImpl> get copyWith =>
|
||||||
@ -1659,8 +1766,11 @@ abstract class _SpotifyHomeFeed implements SpotifyHomeFeed {
|
|||||||
String get greeting;
|
String get greeting;
|
||||||
@override
|
@override
|
||||||
List<SpotifyHomeFeedSection> get sections;
|
List<SpotifyHomeFeedSection> get sections;
|
||||||
|
|
||||||
|
/// Create a copy of SpotifyHomeFeed
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
_$$SpotifyHomeFeedImplCopyWith<_$SpotifyHomeFeedImpl> get copyWith =>
|
_$$SpotifyHomeFeedImplCopyWith<_$SpotifyHomeFeedImpl> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,9 @@ mixin _$GeneratePlaylistProviderInput {
|
|||||||
RecommendationSeeds? get min => throw _privateConstructorUsedError;
|
RecommendationSeeds? get min => throw _privateConstructorUsedError;
|
||||||
RecommendationSeeds? get target => throw _privateConstructorUsedError;
|
RecommendationSeeds? get target => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
/// Create a copy of GeneratePlaylistProviderInput
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
$GeneratePlaylistProviderInputCopyWith<GeneratePlaylistProviderInput>
|
$GeneratePlaylistProviderInputCopyWith<GeneratePlaylistProviderInput>
|
||||||
get copyWith => throw _privateConstructorUsedError;
|
get copyWith => throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -62,6 +64,8 @@ class _$GeneratePlaylistProviderInputCopyWithImpl<$Res,
|
|||||||
// ignore: unused_field
|
// ignore: unused_field
|
||||||
final $Res Function($Val) _then;
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of GeneratePlaylistProviderInput
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -105,6 +109,8 @@ class _$GeneratePlaylistProviderInputCopyWithImpl<$Res,
|
|||||||
) as $Val);
|
) as $Val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a copy of GeneratePlaylistProviderInput
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
$RecommendationSeedsCopyWith<$Res>? get max {
|
$RecommendationSeedsCopyWith<$Res>? get max {
|
||||||
@ -117,6 +123,8 @@ class _$GeneratePlaylistProviderInputCopyWithImpl<$Res,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a copy of GeneratePlaylistProviderInput
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
$RecommendationSeedsCopyWith<$Res>? get min {
|
$RecommendationSeedsCopyWith<$Res>? get min {
|
||||||
@ -129,6 +137,8 @@ class _$GeneratePlaylistProviderInputCopyWithImpl<$Res,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a copy of GeneratePlaylistProviderInput
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
$RecommendationSeedsCopyWith<$Res>? get target {
|
$RecommendationSeedsCopyWith<$Res>? get target {
|
||||||
@ -178,6 +188,8 @@ class __$$GeneratePlaylistProviderInputImplCopyWithImpl<$Res>
|
|||||||
$Res Function(_$GeneratePlaylistProviderInputImpl) _then)
|
$Res Function(_$GeneratePlaylistProviderInputImpl) _then)
|
||||||
: super(_value, _then);
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of GeneratePlaylistProviderInput
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -283,7 +295,9 @@ class _$GeneratePlaylistProviderInputImpl
|
|||||||
min,
|
min,
|
||||||
target);
|
target);
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
/// Create a copy of GeneratePlaylistProviderInput
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
_$$GeneratePlaylistProviderInputImplCopyWith<
|
_$$GeneratePlaylistProviderInputImplCopyWith<
|
||||||
@ -317,8 +331,11 @@ abstract class _GeneratePlaylistProviderInput
|
|||||||
RecommendationSeeds? get min;
|
RecommendationSeeds? get min;
|
||||||
@override
|
@override
|
||||||
RecommendationSeeds? get target;
|
RecommendationSeeds? get target;
|
||||||
|
|
||||||
|
/// Create a copy of GeneratePlaylistProviderInput
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
_$$GeneratePlaylistProviderInputImplCopyWith<
|
_$$GeneratePlaylistProviderInputImplCopyWith<
|
||||||
_$GeneratePlaylistProviderInputImpl>
|
_$GeneratePlaylistProviderInputImpl>
|
||||||
get copyWith => throw _privateConstructorUsedError;
|
get copyWith => throw _privateConstructorUsedError;
|
||||||
@ -347,8 +364,12 @@ mixin _$RecommendationSeeds {
|
|||||||
num? get timeSignature => throw _privateConstructorUsedError;
|
num? get timeSignature => throw _privateConstructorUsedError;
|
||||||
num? get valence => throw _privateConstructorUsedError;
|
num? get valence => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Serializes this RecommendationSeeds to a JSON map.
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
@JsonKey(ignore: true)
|
|
||||||
|
/// Create a copy of RecommendationSeeds
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
$RecommendationSeedsCopyWith<RecommendationSeeds> get copyWith =>
|
$RecommendationSeedsCopyWith<RecommendationSeeds> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -386,6 +407,8 @@ class _$RecommendationSeedsCopyWithImpl<$Res, $Val extends RecommendationSeeds>
|
|||||||
// ignore: unused_field
|
// ignore: unused_field
|
||||||
final $Res Function($Val) _then;
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of RecommendationSeeds
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -498,6 +521,8 @@ class __$$RecommendationSeedsImplCopyWithImpl<$Res>
|
|||||||
$Res Function(_$RecommendationSeedsImpl) _then)
|
$Res Function(_$RecommendationSeedsImpl) _then)
|
||||||
: super(_value, _then);
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of RecommendationSeeds
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -665,7 +690,7 @@ class _$RecommendationSeedsImpl implements _RecommendationSeeds {
|
|||||||
(identical(other.valence, valence) || other.valence == valence));
|
(identical(other.valence, valence) || other.valence == valence));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(
|
int get hashCode => Object.hash(
|
||||||
runtimeType,
|
runtimeType,
|
||||||
@ -684,7 +709,9 @@ class _$RecommendationSeedsImpl implements _RecommendationSeeds {
|
|||||||
timeSignature,
|
timeSignature,
|
||||||
valence);
|
valence);
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
/// Create a copy of RecommendationSeeds
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
_$$RecommendationSeedsImplCopyWith<_$RecommendationSeedsImpl> get copyWith =>
|
_$$RecommendationSeedsImplCopyWith<_$RecommendationSeedsImpl> get copyWith =>
|
||||||
@ -749,8 +776,11 @@ abstract class _RecommendationSeeds implements RecommendationSeeds {
|
|||||||
num? get timeSignature;
|
num? get timeSignature;
|
||||||
@override
|
@override
|
||||||
num? get valence;
|
num? get valence;
|
||||||
|
|
||||||
|
/// Create a copy of RecommendationSeeds
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
_$$RecommendationSeedsImplCopyWith<_$RecommendationSeedsImpl> get copyWith =>
|
_$$RecommendationSeedsImplCopyWith<_$RecommendationSeedsImpl> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
|
139
lib/modules/library/local_folder/cache_export_dialog.dart
Normal file
139
lib/modules/library/local_folder/cache_export_dialog.dart
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:gap/gap.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:path/path.dart';
|
||||||
|
import 'package:spotube/extensions/context.dart';
|
||||||
|
import 'package:spotube/services/logger/logger.dart';
|
||||||
|
import 'package:spotube/services/sourced_track/enums.dart';
|
||||||
|
|
||||||
|
final codecs = SourceCodecs.values.map((s) => s.name);
|
||||||
|
|
||||||
|
class LocalFolderCacheExportDialog extends HookConsumerWidget {
|
||||||
|
final Directory exportDir;
|
||||||
|
final Directory cacheDir;
|
||||||
|
const LocalFolderCacheExportDialog({
|
||||||
|
super.key,
|
||||||
|
required this.exportDir,
|
||||||
|
required this.cacheDir,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, ref) {
|
||||||
|
final ThemeData(:textTheme, :colorScheme) = Theme.of(context);
|
||||||
|
|
||||||
|
final files = useState<List<File>>([]);
|
||||||
|
final filesExported = useState<int>(0);
|
||||||
|
|
||||||
|
useEffect(() {
|
||||||
|
final stream = cacheDir.list().where(
|
||||||
|
(event) =>
|
||||||
|
event is File &&
|
||||||
|
codecs.contains(extension(event.path).replaceAll(".", "")),
|
||||||
|
);
|
||||||
|
|
||||||
|
stream.listen(
|
||||||
|
(event) {
|
||||||
|
files.value = [...files.value, event as File];
|
||||||
|
},
|
||||||
|
onError: (e, stack) {
|
||||||
|
AppLogger.reportError(e, stack);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() {
|
||||||
|
if (filesExported.value == files.value.length &&
|
||||||
|
filesExported.value > 0) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}, [filesExported.value, files.value]);
|
||||||
|
|
||||||
|
final isExportInProgress =
|
||||||
|
filesExported.value > 0 && filesExported.value != files.value.length;
|
||||||
|
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(context.l10n.export_cache_files),
|
||||||
|
content: AnimatedSwitcher(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
child: filesExported.value == 0
|
||||||
|
? Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
context.l10n.found_n_files(files.value.length.toString()),
|
||||||
|
),
|
||||||
|
const Gap(10),
|
||||||
|
Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: context.l10n.export_cache_confirmation,
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: "\n${exportDir.path}?",
|
||||||
|
style: textTheme.labelMedium!.copyWith(
|
||||||
|
color: colorScheme.secondary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
context.l10n.exported_n_out_of_m_files(
|
||||||
|
files.value.length.toString(),
|
||||||
|
filesExported.value.toString(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Gap(10),
|
||||||
|
LinearProgressIndicator(
|
||||||
|
value: filesExported.value / files.value.length,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: isExportInProgress
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: Text(context.l10n.cancel),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: isExportInProgress
|
||||||
|
? null
|
||||||
|
: () async {
|
||||||
|
for (final file in files.value) {
|
||||||
|
try {
|
||||||
|
final destinationFile = File(
|
||||||
|
join(exportDir.path, basename(file.path)),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (await destinationFile.exists()) {
|
||||||
|
await destinationFile.delete();
|
||||||
|
}
|
||||||
|
await file.copy(destinationFile.path);
|
||||||
|
filesExported.value++;
|
||||||
|
} catch (e, stack) {
|
||||||
|
AppLogger.reportError(e, stack);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text(context.l10n.export),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
@ -10,6 +11,7 @@ import 'package:spotube/components/image/universal_image.dart';
|
|||||||
import 'package:spotube/extensions/constrains.dart';
|
import 'package:spotube/extensions/constrains.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
import 'package:spotube/extensions/image.dart';
|
import 'package:spotube/extensions/image.dart';
|
||||||
|
import 'package:spotube/extensions/string.dart';
|
||||||
import 'package:spotube/hooks/utils/use_brightness_value.dart';
|
import 'package:spotube/hooks/utils/use_brightness_value.dart';
|
||||||
import 'package:spotube/pages/library/local_folder.dart';
|
import 'package:spotube/pages/library/local_folder.dart';
|
||||||
import 'package:spotube/provider/local_tracks/local_tracks_provider.dart';
|
import 'package:spotube/provider/local_tracks/local_tracks_provider.dart';
|
||||||
@ -28,8 +30,10 @@ class LocalFolderItem extends HookConsumerWidget {
|
|||||||
|
|
||||||
final downloadFolder =
|
final downloadFolder =
|
||||||
ref.watch(userPreferencesProvider.select((s) => s.downloadLocation));
|
ref.watch(userPreferencesProvider.select((s) => s.downloadLocation));
|
||||||
|
final cacheFolder = useFuture(UserPreferencesNotifier.getMusicCacheDir());
|
||||||
|
|
||||||
final isDownloadFolder = folder == downloadFolder;
|
final isDownloadFolder = folder == downloadFolder;
|
||||||
|
final isCacheFolder = folder == cacheFolder.data;
|
||||||
|
|
||||||
final Uri(:pathSegments) = Uri.parse(
|
final Uri(:pathSegments) = Uri.parse(
|
||||||
folder
|
folder
|
||||||
@ -62,6 +66,7 @@ class LocalFolderItem extends HookConsumerWidget {
|
|||||||
LocalLibraryPage.name,
|
LocalLibraryPage.name,
|
||||||
queryParameters: {
|
queryParameters: {
|
||||||
if (isDownloadFolder) "downloads": "true",
|
if (isDownloadFolder) "downloads": "true",
|
||||||
|
if (isCacheFolder) "cache": "true",
|
||||||
},
|
},
|
||||||
extra: folder,
|
extra: folder,
|
||||||
);
|
);
|
||||||
@ -123,7 +128,9 @@ class LocalFolderItem extends HookConsumerWidget {
|
|||||||
child: Text(
|
child: Text(
|
||||||
isDownloadFolder
|
isDownloadFolder
|
||||||
? context.l10n.downloads
|
? context.l10n.downloads
|
||||||
: basename(folder),
|
: isCacheFolder
|
||||||
|
? context.l10n.cache_folder.capitalize()
|
||||||
|
: basename(folder),
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
|
@ -30,6 +30,7 @@ class UserLocalTracks extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
|
final cacheDir = useFuture(UserPreferencesNotifier.getMusicCacheDir());
|
||||||
final preferencesNotifier = ref.watch(userPreferencesProvider.notifier);
|
final preferencesNotifier = ref.watch(userPreferencesProvider.notifier);
|
||||||
final preferences = ref.watch(userPreferencesProvider);
|
final preferences = ref.watch(userPreferencesProvider);
|
||||||
|
|
||||||
@ -83,12 +84,16 @@ class UserLocalTracks extends HookConsumerWidget {
|
|||||||
crossAxisSpacing: 10,
|
crossAxisSpacing: 10,
|
||||||
mainAxisSpacing: 10,
|
mainAxisSpacing: 10,
|
||||||
),
|
),
|
||||||
itemCount: preferences.localLibraryLocation.length + 1,
|
itemCount: preferences.localLibraryLocation.length +
|
||||||
|
1 +
|
||||||
|
(cacheDir.hasData ? 1 : 0),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return LocalFolderItem(
|
return LocalFolderItem(
|
||||||
folder: index == 0
|
folder: index == 0
|
||||||
? preferences.downloadLocation
|
? preferences.downloadLocation
|
||||||
: preferences.localLibraryLocation[index - 1],
|
: index == 1 && cacheDir.hasData
|
||||||
|
? cacheDir.data!
|
||||||
|
: preferences.localLibraryLocation[index - 1],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:skeletonizer/skeletonizer.dart';
|
import 'package:skeletonizer/skeletonizer.dart';
|
||||||
import 'package:spotify/spotify.dart' hide Offset;
|
import 'package:spotify/spotify.dart' hide Offset;
|
||||||
import 'package:spotube/collections/fake.dart';
|
import 'package:spotube/collections/fake.dart';
|
||||||
|
import 'package:spotube/hooks/utils/use_custom_status_bar_color.dart';
|
||||||
import 'package:spotube/modules/playlist/playlist_card.dart';
|
import 'package:spotube/modules/playlist/playlist_card.dart';
|
||||||
import 'package:spotube/components/image/universal_image.dart';
|
import 'package:spotube/components/image/universal_image.dart';
|
||||||
import 'package:spotube/components/titlebar/titlebar.dart';
|
import 'package:spotube/components/titlebar/titlebar.dart';
|
||||||
@ -27,6 +29,14 @@ class GenrePlaylistsPage extends HookConsumerWidget {
|
|||||||
final playlistsNotifier =
|
final playlistsNotifier =
|
||||||
ref.read(categoryPlaylistsProvider(category.id!).notifier);
|
ref.read(categoryPlaylistsProvider(category.id!).notifier);
|
||||||
final scrollController = useScrollController();
|
final scrollController = useScrollController();
|
||||||
|
final routeName = GoRouterState.of(context).name;
|
||||||
|
|
||||||
|
useCustomStatusBarColor(
|
||||||
|
Colors.black,
|
||||||
|
routeName == GenrePlaylistsPage.name,
|
||||||
|
noSetBGColor: true,
|
||||||
|
automaticSystemUiAdjustment: false,
|
||||||
|
);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: kIsDesktop
|
appBar: kIsDesktop
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:fuzzywuzzy/fuzzywuzzy.dart';
|
import 'package:fuzzywuzzy/fuzzywuzzy.dart';
|
||||||
@ -6,6 +10,8 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:skeletonizer/skeletonizer.dart';
|
import 'package:skeletonizer/skeletonizer.dart';
|
||||||
import 'package:spotube/collections/fake.dart';
|
import 'package:spotube/collections/fake.dart';
|
||||||
import 'package:spotube/collections/spotube_icons.dart';
|
import 'package:spotube/collections/spotube_icons.dart';
|
||||||
|
import 'package:spotube/extensions/string.dart';
|
||||||
|
import 'package:spotube/modules/library/local_folder/cache_export_dialog.dart';
|
||||||
import 'package:spotube/modules/library/user_local_tracks.dart';
|
import 'package:spotube/modules/library/user_local_tracks.dart';
|
||||||
import 'package:spotube/components/expandable_search/expandable_search.dart';
|
import 'package:spotube/components/expandable_search/expandable_search.dart';
|
||||||
import 'package:spotube/components/fallbacks/not_found.dart';
|
import 'package:spotube/components/fallbacks/not_found.dart';
|
||||||
@ -18,6 +24,7 @@ import 'package:spotube/extensions/context.dart';
|
|||||||
import 'package:spotube/models/local_track.dart';
|
import 'package:spotube/models/local_track.dart';
|
||||||
import 'package:spotube/provider/local_tracks/local_tracks_provider.dart';
|
import 'package:spotube/provider/local_tracks/local_tracks_provider.dart';
|
||||||
import 'package:spotube/provider/audio_player/audio_player.dart';
|
import 'package:spotube/provider/audio_player/audio_player.dart';
|
||||||
|
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
||||||
import 'package:spotube/utils/service_utils.dart';
|
import 'package:spotube/utils/service_utils.dart';
|
||||||
|
|
||||||
class LocalLibraryPage extends HookConsumerWidget {
|
class LocalLibraryPage extends HookConsumerWidget {
|
||||||
@ -25,7 +32,13 @@ class LocalLibraryPage extends HookConsumerWidget {
|
|||||||
|
|
||||||
final String location;
|
final String location;
|
||||||
final bool isDownloads;
|
final bool isDownloads;
|
||||||
const LocalLibraryPage(this.location, {super.key, this.isDownloads = false});
|
final bool isCache;
|
||||||
|
const LocalLibraryPage(
|
||||||
|
this.location, {
|
||||||
|
super.key,
|
||||||
|
this.isDownloads = false,
|
||||||
|
this.isCache = false,
|
||||||
|
});
|
||||||
|
|
||||||
Future<void> playLocalTracks(
|
Future<void> playLocalTracks(
|
||||||
WidgetRef ref,
|
WidgetRef ref,
|
||||||
@ -52,6 +65,8 @@ class LocalLibraryPage extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
|
final ThemeData(:textTheme) = Theme.of(context);
|
||||||
|
|
||||||
final sortBy = useState<SortBy>(SortBy.none);
|
final sortBy = useState<SortBy>(SortBy.none);
|
||||||
final playlist = ref.watch(audioPlayerProvider);
|
final playlist = ref.watch(audioPlayerProvider);
|
||||||
final trackSnapshot = ref.watch(localTracksProvider);
|
final trackSnapshot = ref.watch(localTracksProvider);
|
||||||
@ -65,14 +80,133 @@ class LocalLibraryPage extends HookConsumerWidget {
|
|||||||
|
|
||||||
final controller = useScrollController();
|
final controller = useScrollController();
|
||||||
|
|
||||||
|
final directorySize = useMemoized(() async {
|
||||||
|
final dir = Directory(location);
|
||||||
|
final files = await dir.list(recursive: true).toList();
|
||||||
|
|
||||||
|
final filesLength =
|
||||||
|
await Future.wait(files.whereType<File>().map((e) => e.length()));
|
||||||
|
|
||||||
|
return (filesLength.sum.toInt() / pow(10, 9)).toStringAsFixed(2);
|
||||||
|
}, [location]);
|
||||||
|
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
bottom: false,
|
bottom: false,
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
appBar: PageWindowTitleBar(
|
appBar: PageWindowTitleBar(
|
||||||
leading: const BackButton(),
|
leading: const BackButton(),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
title: Text(isDownloads ? context.l10n.downloads : location),
|
title: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
isDownloads
|
||||||
|
? context.l10n.downloads
|
||||||
|
: isCache
|
||||||
|
? context.l10n.cache_folder.capitalize()
|
||||||
|
: location,
|
||||||
|
style: textTheme.titleLarge,
|
||||||
|
),
|
||||||
|
FutureBuilder<String>(
|
||||||
|
future: directorySize,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
return Text(
|
||||||
|
"${(snapshot.data ?? 0)} GB",
|
||||||
|
style: textTheme.labelSmall,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
|
actions: [
|
||||||
|
if (isCache) ...[
|
||||||
|
IconButton(
|
||||||
|
iconSize: 16,
|
||||||
|
icon: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const Icon(SpotubeIcons.delete),
|
||||||
|
Text(
|
||||||
|
context.l10n.clear_cache,
|
||||||
|
style: textTheme.labelSmall,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
final accepted = await showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog.adaptive(
|
||||||
|
title: Text(context.l10n.clear_cache_confirmation),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop(false);
|
||||||
|
},
|
||||||
|
child: Text(context.l10n.decline),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
Navigator.of(context).pop(true);
|
||||||
|
},
|
||||||
|
child: Text(context.l10n.accept),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (accepted ?? false) return;
|
||||||
|
|
||||||
|
final cacheDir = Directory(
|
||||||
|
await UserPreferencesNotifier.getMusicCacheDir(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (cacheDir.existsSync()) {
|
||||||
|
await cacheDir.delete(recursive: true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
iconSize: 16,
|
||||||
|
icon: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const Icon(SpotubeIcons.export),
|
||||||
|
Text(
|
||||||
|
context.l10n.export,
|
||||||
|
style: textTheme.labelSmall,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
final exportPath =
|
||||||
|
await FilePicker.platform.getDirectoryPath();
|
||||||
|
|
||||||
|
if (exportPath == null) return;
|
||||||
|
final exportDirectory = Directory(exportPath);
|
||||||
|
|
||||||
|
if (!exportDirectory.existsSync()) {
|
||||||
|
await exportDirectory.create(recursive: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
final cacheDir = Directory(
|
||||||
|
await UserPreferencesNotifier.getMusicCacheDir());
|
||||||
|
|
||||||
|
if (!context.mounted) return;
|
||||||
|
await showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return LocalFolderCacheExportDialog(
|
||||||
|
cacheDir: cacheDir,
|
||||||
|
exportDir: exportDirectory,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
],
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
|
@ -38,10 +38,11 @@ class LyricsPage extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
final palette = usePaletteColor(albumArt, ref);
|
final palette = usePaletteColor(albumArt, ref);
|
||||||
final mediaQuery = MediaQuery.of(context);
|
final mediaQuery = MediaQuery.of(context);
|
||||||
|
final route = ModalRoute.of(context);
|
||||||
|
|
||||||
useCustomStatusBarColor(
|
final resetStatusBar = useCustomStatusBarColor(
|
||||||
palette.color,
|
palette.color,
|
||||||
true,
|
route?.isCurrent ?? false,
|
||||||
noSetBGColor: true,
|
noSetBGColor: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -81,53 +82,57 @@ class LyricsPage extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (isModal) {
|
if (isModal) {
|
||||||
return DefaultTabController(
|
return PopScope(
|
||||||
length: 2,
|
canPop: true,
|
||||||
child: SafeArea(
|
onPopInvokedWithResult: (_, __) => resetStatusBar(),
|
||||||
child: BackdropFilter(
|
child: DefaultTabController(
|
||||||
filter: ImageFilter.blur(sigmaX: 15, sigmaY: 15),
|
length: 2,
|
||||||
child: Container(
|
child: SafeArea(
|
||||||
clipBehavior: Clip.hardEdge,
|
child: BackdropFilter(
|
||||||
decoration: BoxDecoration(
|
filter: ImageFilter.blur(sigmaX: 15, sigmaY: 15),
|
||||||
color: Theme.of(context).colorScheme.surface.withOpacity(.4),
|
child: Container(
|
||||||
borderRadius: const BorderRadius.only(
|
clipBehavior: Clip.hardEdge,
|
||||||
topLeft: Radius.circular(10),
|
decoration: BoxDecoration(
|
||||||
topRight: Radius.circular(10),
|
color: Theme.of(context).colorScheme.surface.withOpacity(.4),
|
||||||
|
borderRadius: const BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(10),
|
||||||
|
topRight: Radius.circular(10),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
child: Column(
|
||||||
child: Column(
|
children: [
|
||||||
children: [
|
const SizedBox(height: 5),
|
||||||
const SizedBox(height: 5),
|
Container(
|
||||||
Container(
|
height: 7,
|
||||||
height: 7,
|
width: 150,
|
||||||
width: 150,
|
decoration: BoxDecoration(
|
||||||
decoration: BoxDecoration(
|
color: palette.titleTextColor,
|
||||||
color: palette.titleTextColor,
|
borderRadius: BorderRadius.circular(10),
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
AppBar(
|
|
||||||
leadingWidth: double.infinity,
|
|
||||||
leading: tabbar,
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
automaticallyImplyLeading: false,
|
|
||||||
actions: [
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(SpotubeIcons.minimize),
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
),
|
),
|
||||||
const SizedBox(width: 5),
|
),
|
||||||
],
|
AppBar(
|
||||||
),
|
leadingWidth: double.infinity,
|
||||||
Expanded(
|
leading: tabbar,
|
||||||
child: TabBarView(
|
backgroundColor: Colors.transparent,
|
||||||
children: [
|
automaticallyImplyLeading: false,
|
||||||
SyncedLyrics(palette: palette, isModal: isModal),
|
actions: [
|
||||||
PlainLyrics(palette: palette, isModal: isModal),
|
IconButton(
|
||||||
|
icon: const Icon(SpotubeIcons.minimize),
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 5),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
Expanded(
|
||||||
],
|
child: TabBarView(
|
||||||
|
children: [
|
||||||
|
SyncedLyrics(palette: palette, isModal: isModal),
|
||||||
|
PlainLyrics(palette: palette, isModal: isModal),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
@ -15,6 +16,7 @@ import 'package:spotube/provider/audio_player/sources/piped_instances_provider.d
|
|||||||
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
||||||
|
|
||||||
import 'package:spotube/services/sourced_track/enums.dart';
|
import 'package:spotube/services/sourced_track/enums.dart';
|
||||||
|
import 'package:spotube/utils/platform.dart';
|
||||||
|
|
||||||
class SettingsPlaybackSection extends HookConsumerWidget {
|
class SettingsPlaybackSection extends HookConsumerWidget {
|
||||||
const SettingsPlaybackSection({super.key});
|
const SettingsPlaybackSection({super.key});
|
||||||
@ -239,6 +241,30 @@ class SettingsPlaybackSection extends HookConsumerWidget {
|
|||||||
)
|
)
|
||||||
: const SizedBox.shrink(),
|
: const SizedBox.shrink(),
|
||||||
),
|
),
|
||||||
|
SwitchListTile(
|
||||||
|
title: Text(context.l10n.cache_music),
|
||||||
|
subtitle: kIsMobile
|
||||||
|
? null
|
||||||
|
: Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(text: "${context.l10n.open} "),
|
||||||
|
TextSpan(
|
||||||
|
text: context.l10n.cache_folder.toLowerCase(),
|
||||||
|
recognizer: TapGestureRecognizer()
|
||||||
|
..onTap = preferencesNotifier.openCacheFolder,
|
||||||
|
style: theme.textTheme.bodyMedium?.copyWith(
|
||||||
|
color: theme.colorScheme.primary,
|
||||||
|
decoration: TextDecoration.underline,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
secondary: const Icon(SpotubeIcons.cache),
|
||||||
|
value: preferences.cacheMusic,
|
||||||
|
onChanged: preferencesNotifier.setCacheMusic,
|
||||||
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(SpotubeIcons.playlistRemove),
|
leading: const Icon(SpotubeIcons.playlistRemove),
|
||||||
title: Text(context.l10n.blacklist),
|
title: Text(context.l10n.blacklist),
|
||||||
|
@ -74,6 +74,7 @@ class AudioPlayerStreamListeners {
|
|||||||
StreamSubscription subscribeToPlaylist() {
|
StreamSubscription subscribeToPlaylist() {
|
||||||
return audioPlayer.playlistStream.listen((mpvPlaylist) {
|
return audioPlayer.playlistStream.listen((mpvPlaylist) {
|
||||||
try {
|
try {
|
||||||
|
if (audioPlayerState.activeTrack == null) return;
|
||||||
notificationService.addTrack(audioPlayerState.activeTrack!);
|
notificationService.addTrack(audioPlayerState.activeTrack!);
|
||||||
discord.updatePresence(audioPlayerState.activeTrack!);
|
discord.updatePresence(audioPlayerState.activeTrack!);
|
||||||
updatePalette();
|
updatePalette();
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:spotube/extensions/track.dart';
|
||||||
import 'package:spotube/services/logger/logger.dart';
|
import 'package:spotube/services/logger/logger.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:metadata_god/metadata_god.dart';
|
import 'package:metadata_god/metadata_god.dart';
|
||||||
import 'package:path/path.dart';
|
import 'package:path/path.dart';
|
||||||
@ -16,6 +16,7 @@ import 'package:spotube/services/download_manager/download_manager.dart';
|
|||||||
import 'package:spotube/services/sourced_track/enums.dart';
|
import 'package:spotube/services/sourced_track/enums.dart';
|
||||||
import 'package:spotube/services/sourced_track/sourced_track.dart';
|
import 'package:spotube/services/sourced_track/sourced_track.dart';
|
||||||
import 'package:spotube/utils/primitive_utils.dart';
|
import 'package:spotube/utils/primitive_utils.dart';
|
||||||
|
import 'package:spotube/utils/service_utils.dart';
|
||||||
|
|
||||||
class DownloadManagerProvider extends ChangeNotifier {
|
class DownloadManagerProvider extends ChangeNotifier {
|
||||||
DownloadManagerProvider({required this.ref})
|
DownloadManagerProvider({required this.ref})
|
||||||
@ -53,33 +54,16 @@ class DownloadManagerProvider extends ChangeNotifier {
|
|||||||
await oldFile.delete();
|
await oldFile.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
final imageBytes = await downloadImage(
|
final imageBytes = await ServiceUtils.downloadImage(
|
||||||
(track.album?.images).asUrlString(
|
(track.album?.images).asUrlString(
|
||||||
placeholder: ImagePlaceholder.albumArt,
|
placeholder: ImagePlaceholder.albumArt,
|
||||||
index: 1,
|
index: 1,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final metadata = Metadata(
|
final metadata = track.toMetadata(
|
||||||
title: track.name,
|
fileLength: await file.length(),
|
||||||
artist: track.artists?.map((a) => a.name).join(", "),
|
imageBytes: imageBytes,
|
||||||
album: track.album?.name,
|
|
||||||
albumArtist: track.artists?.map((a) => a.name).join(", "),
|
|
||||||
year: track.album?.releaseDate != null
|
|
||||||
? int.tryParse(track.album!.releaseDate!.split("-").first) ?? 1969
|
|
||||||
: 1969,
|
|
||||||
trackNumber: track.trackNumber,
|
|
||||||
discNumber: track.discNumber,
|
|
||||||
durationMs: track.durationMs?.toDouble() ?? 0.0,
|
|
||||||
fileSize: BigInt.from(await file.length()),
|
|
||||||
trackTotal: track.album?.tracks?.length ?? 0,
|
|
||||||
picture: imageBytes != null
|
|
||||||
? Picture(
|
|
||||||
data: imageBytes,
|
|
||||||
// Spotify images are always JPEGs
|
|
||||||
mimeType: 'image/jpeg',
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await MetadataGod.writeMetadata(
|
await MetadataGod.writeMetadata(
|
||||||
@ -116,29 +100,6 @@ class DownloadManagerProvider extends ChangeNotifier {
|
|||||||
final Set<Track> $backHistory;
|
final Set<Track> $backHistory;
|
||||||
final DownloadManager dl;
|
final DownloadManager dl;
|
||||||
|
|
||||||
/// Spotify Images are always JPEGs
|
|
||||||
Future<Uint8List?> downloadImage(
|
|
||||||
String imageUrl,
|
|
||||||
) async {
|
|
||||||
try {
|
|
||||||
final fileStream = DefaultCacheManager().getImageFile(imageUrl);
|
|
||||||
|
|
||||||
final bytes = List<int>.empty(growable: true);
|
|
||||||
|
|
||||||
await for (final data in fileStream) {
|
|
||||||
if (data is FileInfo) {
|
|
||||||
bytes.addAll(data.file.readAsBytesSync());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Uint8List.fromList(bytes);
|
|
||||||
} catch (e, stackTrace) {
|
|
||||||
AppLogger.reportError(e, stackTrace);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String getTrackFileUrl(Track track) {
|
String getTrackFileUrl(Track track) {
|
||||||
final name =
|
final name =
|
||||||
"${track.name} - ${track.artists?.asString() ?? ""}.${downloadCodec.name}";
|
"${track.name} - ${track.artists?.asString() ?? ""}.${downloadCodec.name}";
|
||||||
|
@ -44,14 +44,23 @@ final localTracksProvider =
|
|||||||
userPreferencesProvider.select((s) => s.downloadLocation),
|
userPreferencesProvider.select((s) => s.downloadLocation),
|
||||||
);
|
);
|
||||||
final downloadDir = Directory(downloadLocation);
|
final downloadDir = Directory(downloadLocation);
|
||||||
|
final cacheDir =
|
||||||
|
Directory(await UserPreferencesNotifier.getMusicCacheDir());
|
||||||
if (!await downloadDir.exists()) {
|
if (!await downloadDir.exists()) {
|
||||||
await downloadDir.create(recursive: true);
|
await downloadDir.create(recursive: true);
|
||||||
}
|
}
|
||||||
|
if (!await cacheDir.exists()) {
|
||||||
|
await cacheDir.create(recursive: true);
|
||||||
|
}
|
||||||
final localLibraryLocations = ref.watch(
|
final localLibraryLocations = ref.watch(
|
||||||
userPreferencesProvider.select((s) => s.localLibraryLocation),
|
userPreferencesProvider.select((s) => s.localLibraryLocation),
|
||||||
);
|
);
|
||||||
|
|
||||||
for (final location in [downloadLocation, ...localLibraryLocations]) {
|
for (final location in [
|
||||||
|
downloadLocation,
|
||||||
|
cacheDir.path,
|
||||||
|
...localLibraryLocations
|
||||||
|
]) {
|
||||||
if (location.isEmpty) continue;
|
if (location.isEmpty) continue;
|
||||||
final entities = <File>[];
|
final entities = <File>[];
|
||||||
if (await Directory(location).exists()) {
|
if (await Directory(location).exists()) {
|
||||||
|
@ -1,14 +1,27 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:dio/dio.dart' hide Response;
|
import 'package:dio/dio.dart' hide Response;
|
||||||
|
import 'package:dio/dio.dart' as dio_lib;
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:metadata_god/metadata_god.dart';
|
||||||
|
import 'package:path/path.dart';
|
||||||
import 'package:shelf/shelf.dart';
|
import 'package:shelf/shelf.dart';
|
||||||
|
import 'package:spotube/extensions/artist_simple.dart';
|
||||||
|
import 'package:spotube/extensions/image.dart';
|
||||||
|
import 'package:spotube/extensions/track.dart';
|
||||||
|
import 'package:spotube/models/parser/range_headers.dart';
|
||||||
import 'package:spotube/provider/audio_player/audio_player.dart';
|
import 'package:spotube/provider/audio_player/audio_player.dart';
|
||||||
import 'package:spotube/provider/audio_player/state.dart';
|
import 'package:spotube/provider/audio_player/state.dart';
|
||||||
|
|
||||||
import 'package:spotube/provider/server/active_sourced_track.dart';
|
import 'package:spotube/provider/server/active_sourced_track.dart';
|
||||||
import 'package:spotube/provider/server/sourced_track.dart';
|
import 'package:spotube/provider/server/sourced_track.dart';
|
||||||
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
||||||
import 'package:spotube/services/audio_player/audio_player.dart';
|
import 'package:spotube/services/audio_player/audio_player.dart';
|
||||||
import 'package:spotube/services/logger/logger.dart';
|
import 'package:spotube/services/logger/logger.dart';
|
||||||
|
import 'package:spotube/services/sourced_track/enums.dart';
|
||||||
|
import 'package:spotube/services/sourced_track/sourced_track.dart';
|
||||||
|
import 'package:spotube/utils/service_utils.dart';
|
||||||
|
|
||||||
class ServerPlaybackRoutes {
|
class ServerPlaybackRoutes {
|
||||||
final Ref ref;
|
final Ref ref;
|
||||||
@ -18,19 +31,139 @@ class ServerPlaybackRoutes {
|
|||||||
|
|
||||||
ServerPlaybackRoutes(this.ref) : dio = Dio();
|
ServerPlaybackRoutes(this.ref) : dio = Dio();
|
||||||
|
|
||||||
/// @get('/stream/<trackId>')
|
Future<({dio_lib.Response<Uint8List> response, Uint8List? bytes})>
|
||||||
Future<Response> getStreamTrackId(Request request, String trackId) async {
|
streamTrack(
|
||||||
final options = Options(
|
SourcedTrack track,
|
||||||
|
Map<String, dynamic> headers,
|
||||||
|
) async {
|
||||||
|
final trackCacheFile = File(
|
||||||
|
join(
|
||||||
|
await UserPreferencesNotifier.getMusicCacheDir(),
|
||||||
|
'${track.name} - ${track.artists?.asString()} (${track.sourceInfo.id}).${track.codec.name}',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
final trackPartialCacheFile = File("${trackCacheFile.path}.part");
|
||||||
|
|
||||||
|
var options = Options(
|
||||||
headers: {
|
headers: {
|
||||||
...request.headers,
|
...headers,
|
||||||
"User-Agent":
|
"User-Agent":
|
||||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
|
||||||
"Cache-Control": "max-age=0",
|
"Cache-Control": "max-age=0",
|
||||||
"Connection": "keep-alive",
|
"Connection": "keep-alive",
|
||||||
|
"host": Uri.parse(track.url).host,
|
||||||
},
|
},
|
||||||
responseType: ResponseType.stream,
|
responseType: ResponseType.bytes,
|
||||||
validateStatus: (status) => status! < 400,
|
validateStatus: (status) => status! < 400,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final headersRes = await Future<dio_lib.Response?>.value(
|
||||||
|
dio.head(
|
||||||
|
track.url,
|
||||||
|
options: options,
|
||||||
|
),
|
||||||
|
).catchError((_) async => null);
|
||||||
|
|
||||||
|
final contentLength = headersRes?.headers.value("content-length");
|
||||||
|
|
||||||
|
if (await trackCacheFile.exists() && userPreferences.cacheMusic) {
|
||||||
|
final bytes = await trackCacheFile.readAsBytes();
|
||||||
|
final cachedFileLength = bytes.length;
|
||||||
|
|
||||||
|
return (
|
||||||
|
response: dio_lib.Response<Uint8List>(
|
||||||
|
statusCode: 200,
|
||||||
|
headers: Headers.fromMap({
|
||||||
|
"content-type": ["audio/${track.codec.name}"],
|
||||||
|
"content-length": ["$cachedFileLength"],
|
||||||
|
"accept-ranges": ["bytes"],
|
||||||
|
"content-range": ["bytes 0-$cachedFileLength/$cachedFileLength"],
|
||||||
|
}),
|
||||||
|
requestOptions: RequestOptions(path: track.url),
|
||||||
|
),
|
||||||
|
bytes: bytes,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Forcing partial content range as mpv sometimes greedily wants
|
||||||
|
/// everything at one go. Slows down overall streaming.
|
||||||
|
final range = RangeHeader.parse(headers["range"] ?? "");
|
||||||
|
final contentPartialLength = int.tryParse(contentLength ?? "");
|
||||||
|
if ((range.end == null) &&
|
||||||
|
contentPartialLength != null &&
|
||||||
|
range.start == 0) {
|
||||||
|
options = options.copyWith(
|
||||||
|
headers: {
|
||||||
|
...?options.headers,
|
||||||
|
"range": "$range${(contentPartialLength * 0.3).ceil()}",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final res =
|
||||||
|
await dio.get<Uint8List>(track.url, options: options).catchError(
|
||||||
|
(e, stack) async {
|
||||||
|
final sourcedTrack = await ref
|
||||||
|
.read(sourcedTrackProvider(SpotubeMedia(track)).notifier)
|
||||||
|
.switchToAlternativeSources();
|
||||||
|
|
||||||
|
ref.read(activeSourcedTrackProvider.notifier).update(sourcedTrack);
|
||||||
|
|
||||||
|
return await dio.get<Uint8List>(sourcedTrack!.url, options: options);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
final bytes = res.data;
|
||||||
|
|
||||||
|
if (bytes == null || !userPreferences.cacheMusic) {
|
||||||
|
return (response: res, bytes: bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
final contentRange =
|
||||||
|
ContentRangeHeader.parse(res.headers.value("content-range") ?? "");
|
||||||
|
|
||||||
|
if (!await trackPartialCacheFile.exists()) {
|
||||||
|
await trackPartialCacheFile.create(recursive: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the stream to the file based on the range
|
||||||
|
final partialCacheFile =
|
||||||
|
await trackPartialCacheFile.open(mode: FileMode.writeOnlyAppend);
|
||||||
|
int fileLength = 0;
|
||||||
|
try {
|
||||||
|
await partialCacheFile.setPosition(contentRange.start);
|
||||||
|
await partialCacheFile.writeFrom(bytes);
|
||||||
|
fileLength = await partialCacheFile.length();
|
||||||
|
} finally {
|
||||||
|
await partialCacheFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileLength == contentRange.total) {
|
||||||
|
await trackPartialCacheFile.rename(trackCacheFile.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentRange.total == fileLength && track.codec != SourceCodecs.weba) {
|
||||||
|
final imageBytes = await ServiceUtils.downloadImage(
|
||||||
|
(track.album?.images).asUrlString(
|
||||||
|
placeholder: ImagePlaceholder.albumArt,
|
||||||
|
index: 1,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await MetadataGod.writeMetadata(
|
||||||
|
file: trackCacheFile.path,
|
||||||
|
metadata: track.toMetadata(
|
||||||
|
fileLength: fileLength,
|
||||||
|
imageBytes: imageBytes,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (bytes: bytes, response: res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @get('/stream/<trackId>')
|
||||||
|
Future<Response> getStreamTrackId(Request request, String trackId) async {
|
||||||
try {
|
try {
|
||||||
final track =
|
final track =
|
||||||
playlist.tracks.firstWhere((element) => element.id == trackId);
|
playlist.tracks.firstWhere((element) => element.id == trackId);
|
||||||
@ -41,48 +174,13 @@ class ServerPlaybackRoutes {
|
|||||||
: await ref.read(sourcedTrackProvider(SpotubeMedia(track)).future);
|
: await ref.read(sourcedTrackProvider(SpotubeMedia(track)).future);
|
||||||
|
|
||||||
ref.read(activeSourcedTrackProvider.notifier).update(sourcedTrack);
|
ref.read(activeSourcedTrackProvider.notifier).update(sourcedTrack);
|
||||||
final res = await dio
|
|
||||||
.get(
|
|
||||||
sourcedTrack!.url,
|
|
||||||
options: options.copyWith(
|
|
||||||
headers: {
|
|
||||||
...options.headers!,
|
|
||||||
"host": Uri.parse(sourcedTrack.url).host,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.catchError((e, stack) async {
|
|
||||||
final sourcedTrack = await ref
|
|
||||||
.read(sourcedTrackProvider(SpotubeMedia(track)).notifier)
|
|
||||||
.switchToAlternativeSources();
|
|
||||||
|
|
||||||
ref.read(activeSourcedTrackProvider.notifier).update(sourcedTrack);
|
final (bytes: audioBytes, response: res) =
|
||||||
|
await streamTrack(sourcedTrack!, request.headers);
|
||||||
return await dio.get(
|
|
||||||
sourcedTrack!.url,
|
|
||||||
options: options.copyWith(
|
|
||||||
headers: {
|
|
||||||
...options.headers!,
|
|
||||||
"host": Uri.parse(sourcedTrack.url).host,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
final audioStream =
|
|
||||||
(res.data?.stream as Stream<Uint8List>?)?.asBroadcastStream();
|
|
||||||
|
|
||||||
audioStream!.listen(
|
|
||||||
(event) {},
|
|
||||||
cancelOnError: true,
|
|
||||||
);
|
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
res.statusCode!,
|
res.statusCode!,
|
||||||
body: audioStream,
|
body: audioBytes,
|
||||||
context: {
|
|
||||||
"shelf.io.buffer_output": false,
|
|
||||||
},
|
|
||||||
headers: res.headers.map,
|
headers: res.headers.map,
|
||||||
);
|
);
|
||||||
} catch (e, stack) {
|
} catch (e, stack) {
|
||||||
|
@ -2,7 +2,7 @@ import 'package:drift/drift.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:path/path.dart';
|
import 'package:path/path.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart' as paths;
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/models/database/database.dart';
|
import 'package:spotube/models/database/database.dart';
|
||||||
import 'package:spotube/modules/settings/color_scheme_picker_dialog.dart';
|
import 'package:spotube/modules/settings/color_scheme_picker_dialog.dart';
|
||||||
@ -14,6 +14,7 @@ import 'package:spotube/services/logger/logger.dart';
|
|||||||
import 'package:spotube/services/sourced_track/enums.dart';
|
import 'package:spotube/services/sourced_track/enums.dart';
|
||||||
import 'package:spotube/utils/platform.dart';
|
import 'package:spotube/utils/platform.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
import 'package:open_file/open_file.dart';
|
||||||
|
|
||||||
typedef UserPreferences = PreferencesTableData;
|
typedef UserPreferences = PreferencesTableData;
|
||||||
|
|
||||||
@ -71,10 +72,10 @@ class UserPreferencesNotifier extends Notifier<PreferencesTableData> {
|
|||||||
if (kIsAndroid) return "/storage/emulated/0/Download/Spotube";
|
if (kIsAndroid) return "/storage/emulated/0/Download/Spotube";
|
||||||
|
|
||||||
if (kIsMacOS) {
|
if (kIsMacOS) {
|
||||||
return join((await getLibraryDirectory()).path, "Caches");
|
return join((await paths.getLibraryDirectory()).path, "Caches");
|
||||||
}
|
}
|
||||||
|
|
||||||
return getDownloadsDirectory().then((dir) {
|
return paths.getDownloadsDirectory().then((dir) {
|
||||||
return join(dir!.path, "Spotube");
|
return join(dir!.path, "Spotube");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -95,6 +96,30 @@ class UserPreferencesNotifier extends Notifier<PreferencesTableData> {
|
|||||||
await query.replace(PreferencesTableCompanion.insert());
|
await query.replace(PreferencesTableCompanion.insert());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<String> getMusicCacheDir() async {
|
||||||
|
if (kIsAndroid) {
|
||||||
|
final dir =
|
||||||
|
await paths.getExternalCacheDirectories().then((dirs) => dirs!.first);
|
||||||
|
if (!await dir.exists()) {
|
||||||
|
await dir.create(recursive: true);
|
||||||
|
}
|
||||||
|
return join(dir.path, 'Cached Tracks');
|
||||||
|
}
|
||||||
|
|
||||||
|
final dir = await paths.getApplicationCacheDirectory();
|
||||||
|
return join(dir.path, 'cached_tracks');
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> openCacheFolder() async {
|
||||||
|
try {
|
||||||
|
final filePath = await getMusicCacheDir();
|
||||||
|
|
||||||
|
await OpenFile.open(filePath);
|
||||||
|
} catch (e, stack) {
|
||||||
|
AppLogger.reportError(e, stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void setStreamMusicCodec(SourceCodecs codec) {
|
void setStreamMusicCodec(SourceCodecs codec) {
|
||||||
setData(PreferencesTableCompanion(streamMusicCodec: Value(codec)));
|
setData(PreferencesTableCompanion(streamMusicCodec: Value(codec)));
|
||||||
}
|
}
|
||||||
@ -211,6 +236,10 @@ class UserPreferencesNotifier extends Notifier<PreferencesTableData> {
|
|||||||
void setEnableConnect(bool enable) {
|
void setEnableConnect(bool enable) {
|
||||||
setData(PreferencesTableCompanion(enableConnect: Value(enable)));
|
setData(PreferencesTableCompanion(enableConnect: Value(enable)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setCacheMusic(bool cache) {
|
||||||
|
setData(PreferencesTableCompanion(cacheMusic: Value(cache)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final userPreferencesProvider =
|
final userPreferencesProvider =
|
||||||
|
@ -30,8 +30,12 @@ mixin _$SongLink {
|
|||||||
String? get nativeAppUriMobile => throw _privateConstructorUsedError;
|
String? get nativeAppUriMobile => throw _privateConstructorUsedError;
|
||||||
String? get nativeAppUriDesktop => throw _privateConstructorUsedError;
|
String? get nativeAppUriDesktop => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Serializes this SongLink to a JSON map.
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
@JsonKey(ignore: true)
|
|
||||||
|
/// Create a copy of SongLink
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
$SongLinkCopyWith<SongLink> get copyWith =>
|
$SongLinkCopyWith<SongLink> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -63,6 +67,8 @@ class _$SongLinkCopyWithImpl<$Res, $Val extends SongLink>
|
|||||||
// ignore: unused_field
|
// ignore: unused_field
|
||||||
final $Res Function($Val) _then;
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SongLink
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -145,6 +151,8 @@ class __$$SongLinkImplCopyWithImpl<$Res>
|
|||||||
_$SongLinkImpl _value, $Res Function(_$SongLinkImpl) _then)
|
_$SongLinkImpl _value, $Res Function(_$SongLinkImpl) _then)
|
||||||
: super(_value, _then);
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of SongLink
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -261,12 +269,14 @@ class _$SongLinkImpl implements _SongLink {
|
|||||||
other.nativeAppUriDesktop == nativeAppUriDesktop));
|
other.nativeAppUriDesktop == nativeAppUriDesktop));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType, displayName, linkId, platform,
|
int get hashCode => Object.hash(runtimeType, displayName, linkId, platform,
|
||||||
show, uniqueId, country, url, nativeAppUriMobile, nativeAppUriDesktop);
|
show, uniqueId, country, url, nativeAppUriMobile, nativeAppUriDesktop);
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
/// Create a copy of SongLink
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
_$$SongLinkImplCopyWith<_$SongLinkImpl> get copyWith =>
|
_$$SongLinkImplCopyWith<_$SongLinkImpl> get copyWith =>
|
||||||
@ -313,8 +323,11 @@ abstract class _SongLink implements SongLink {
|
|||||||
String? get nativeAppUriMobile;
|
String? get nativeAppUriMobile;
|
||||||
@override
|
@override
|
||||||
String? get nativeAppUriDesktop;
|
String? get nativeAppUriDesktop;
|
||||||
|
|
||||||
|
/// Create a copy of SongLink
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
_$$SongLinkImplCopyWith<_$SongLinkImpl> get copyWith =>
|
_$$SongLinkImplCopyWith<_$SongLinkImpl> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
|
@ -53,8 +53,12 @@ mixin _$UserPreferences {
|
|||||||
bool get endlessPlayback => throw _privateConstructorUsedError;
|
bool get endlessPlayback => throw _privateConstructorUsedError;
|
||||||
bool get enableConnect => throw _privateConstructorUsedError;
|
bool get enableConnect => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Serializes this UserPreferences to a JSON map.
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
@JsonKey(ignore: true)
|
|
||||||
|
/// Create a copy of UserPreferences
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
$UserPreferencesCopyWith<UserPreferences> get copyWith =>
|
$UserPreferencesCopyWith<UserPreferences> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -110,6 +114,8 @@ class _$UserPreferencesCopyWithImpl<$Res, $Val extends UserPreferences>
|
|||||||
// ignore: unused_field
|
// ignore: unused_field
|
||||||
final $Res Function($Val) _then;
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of UserPreferences
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -290,6 +296,8 @@ class __$$UserPreferencesImplCopyWithImpl<$Res>
|
|||||||
_$UserPreferencesImpl _value, $Res Function(_$UserPreferencesImpl) _then)
|
_$UserPreferencesImpl _value, $Res Function(_$UserPreferencesImpl) _then)
|
||||||
: super(_value, _then);
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of UserPreferences
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -605,7 +613,7 @@ class _$UserPreferencesImpl implements _UserPreferences {
|
|||||||
other.enableConnect == enableConnect));
|
other.enableConnect == enableConnect));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hashAll([
|
int get hashCode => Object.hashAll([
|
||||||
runtimeType,
|
runtimeType,
|
||||||
@ -635,7 +643,9 @@ class _$UserPreferencesImpl implements _UserPreferences {
|
|||||||
enableConnect
|
enableConnect
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
/// Create a copy of UserPreferences
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
_$$UserPreferencesImplCopyWith<_$UserPreferencesImpl> get copyWith =>
|
_$$UserPreferencesImplCopyWith<_$UserPreferencesImpl> get copyWith =>
|
||||||
@ -744,8 +754,11 @@ abstract class _UserPreferences implements UserPreferences {
|
|||||||
bool get endlessPlayback;
|
bool get endlessPlayback;
|
||||||
@override
|
@override
|
||||||
bool get enableConnect;
|
bool get enableConnect;
|
||||||
|
|
||||||
|
/// Create a copy of UserPreferences
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
_$$UserPreferencesImplCopyWith<_$UserPreferencesImpl> get copyWith =>
|
_$$UserPreferencesImplCopyWith<_$UserPreferencesImpl> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -812,8 +825,13 @@ mixin _$PlaybackHistoryItem {
|
|||||||
required TResult orElse(),
|
required TResult orElse(),
|
||||||
}) =>
|
}) =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Serializes this PlaybackHistoryItem to a JSON map.
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
@JsonKey(ignore: true)
|
|
||||||
|
/// Create a copy of PlaybackHistoryItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
$PlaybackHistoryItemCopyWith<PlaybackHistoryItem> get copyWith =>
|
$PlaybackHistoryItemCopyWith<PlaybackHistoryItem> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -837,6 +855,8 @@ class _$PlaybackHistoryItemCopyWithImpl<$Res, $Val extends PlaybackHistoryItem>
|
|||||||
// ignore: unused_field
|
// ignore: unused_field
|
||||||
final $Res Function($Val) _then;
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of PlaybackHistoryItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -873,6 +893,8 @@ class __$$PlaybackHistoryPlaylistImplCopyWithImpl<$Res>
|
|||||||
$Res Function(_$PlaybackHistoryPlaylistImpl) _then)
|
$Res Function(_$PlaybackHistoryPlaylistImpl) _then)
|
||||||
: super(_value, _then);
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of PlaybackHistoryItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -925,11 +947,13 @@ class _$PlaybackHistoryPlaylistImpl implements PlaybackHistoryPlaylist {
|
|||||||
other.playlist == playlist));
|
other.playlist == playlist));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType, date, playlist);
|
int get hashCode => Object.hash(runtimeType, date, playlist);
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
/// Create a copy of PlaybackHistoryItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
_$$PlaybackHistoryPlaylistImplCopyWith<_$PlaybackHistoryPlaylistImpl>
|
_$$PlaybackHistoryPlaylistImplCopyWith<_$PlaybackHistoryPlaylistImpl>
|
||||||
@ -1023,8 +1047,11 @@ abstract class PlaybackHistoryPlaylist implements PlaybackHistoryItem {
|
|||||||
@override
|
@override
|
||||||
DateTime get date;
|
DateTime get date;
|
||||||
PlaylistSimple get playlist;
|
PlaylistSimple get playlist;
|
||||||
|
|
||||||
|
/// Create a copy of PlaybackHistoryItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
_$$PlaybackHistoryPlaylistImplCopyWith<_$PlaybackHistoryPlaylistImpl>
|
_$$PlaybackHistoryPlaylistImplCopyWith<_$PlaybackHistoryPlaylistImpl>
|
||||||
get copyWith => throw _privateConstructorUsedError;
|
get copyWith => throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -1048,6 +1075,8 @@ class __$$PlaybackHistoryAlbumImplCopyWithImpl<$Res>
|
|||||||
$Res Function(_$PlaybackHistoryAlbumImpl) _then)
|
$Res Function(_$PlaybackHistoryAlbumImpl) _then)
|
||||||
: super(_value, _then);
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of PlaybackHistoryItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -1099,11 +1128,13 @@ class _$PlaybackHistoryAlbumImpl implements PlaybackHistoryAlbum {
|
|||||||
(identical(other.album, album) || other.album == album));
|
(identical(other.album, album) || other.album == album));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType, date, album);
|
int get hashCode => Object.hash(runtimeType, date, album);
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
/// Create a copy of PlaybackHistoryItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
_$$PlaybackHistoryAlbumImplCopyWith<_$PlaybackHistoryAlbumImpl>
|
_$$PlaybackHistoryAlbumImplCopyWith<_$PlaybackHistoryAlbumImpl>
|
||||||
@ -1198,8 +1229,11 @@ abstract class PlaybackHistoryAlbum implements PlaybackHistoryItem {
|
|||||||
@override
|
@override
|
||||||
DateTime get date;
|
DateTime get date;
|
||||||
AlbumSimple get album;
|
AlbumSimple get album;
|
||||||
|
|
||||||
|
/// Create a copy of PlaybackHistoryItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
_$$PlaybackHistoryAlbumImplCopyWith<_$PlaybackHistoryAlbumImpl>
|
_$$PlaybackHistoryAlbumImplCopyWith<_$PlaybackHistoryAlbumImpl>
|
||||||
get copyWith => throw _privateConstructorUsedError;
|
get copyWith => throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
@ -1223,6 +1257,8 @@ class __$$PlaybackHistoryTrackImplCopyWithImpl<$Res>
|
|||||||
$Res Function(_$PlaybackHistoryTrackImpl) _then)
|
$Res Function(_$PlaybackHistoryTrackImpl) _then)
|
||||||
: super(_value, _then);
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of PlaybackHistoryItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
@ -1274,11 +1310,13 @@ class _$PlaybackHistoryTrackImpl implements PlaybackHistoryTrack {
|
|||||||
(identical(other.track, track) || other.track == track));
|
(identical(other.track, track) || other.track == track));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType, date, track);
|
int get hashCode => Object.hash(runtimeType, date, track);
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
/// Create a copy of PlaybackHistoryItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
@pragma('vm:prefer-inline')
|
@pragma('vm:prefer-inline')
|
||||||
_$$PlaybackHistoryTrackImplCopyWith<_$PlaybackHistoryTrackImpl>
|
_$$PlaybackHistoryTrackImplCopyWith<_$PlaybackHistoryTrackImpl>
|
||||||
@ -1373,8 +1411,11 @@ abstract class PlaybackHistoryTrack implements PlaybackHistoryItem {
|
|||||||
@override
|
@override
|
||||||
DateTime get date;
|
DateTime get date;
|
||||||
Track get track;
|
Track get track;
|
||||||
|
|
||||||
|
/// Create a copy of PlaybackHistoryItem
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
_$$PlaybackHistoryTrackImplCopyWith<_$PlaybackHistoryTrackImpl>
|
_$$PlaybackHistoryTrackImplCopyWith<_$PlaybackHistoryTrackImpl>
|
||||||
get copyWith => throw _privateConstructorUsedError;
|
get copyWith => throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:html/dom.dart' hide Text;
|
import 'package:html/dom.dart' hide Text;
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
@ -8,6 +11,7 @@ import 'package:spotube/modules/root/update_dialog.dart';
|
|||||||
import 'package:spotube/models/lyrics.dart';
|
import 'package:spotube/models/lyrics.dart';
|
||||||
import 'package:spotube/provider/database/database.dart';
|
import 'package:spotube/provider/database/database.dart';
|
||||||
import 'package:spotube/services/dio/dio.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/services/sourced_track/sourced_track.dart';
|
||||||
|
|
||||||
import 'package:spotube/utils/primitive_utils.dart';
|
import 'package:spotube/utils/primitive_utils.dart';
|
||||||
@ -449,4 +453,27 @@ abstract class ServiceUtils {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Spotify Images are always JPEGs
|
||||||
|
static Future<Uint8List?> downloadImage(
|
||||||
|
String imageUrl,
|
||||||
|
) async {
|
||||||
|
try {
|
||||||
|
final fileStream = DefaultCacheManager().getImageFile(imageUrl);
|
||||||
|
|
||||||
|
final bytes = List<int>.empty(growable: true);
|
||||||
|
|
||||||
|
await for (final data in fileStream) {
|
||||||
|
if (data is FileInfo) {
|
||||||
|
bytes.addAll(data.file.readAsBytesSync());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Uint8List.fromList(bytes);
|
||||||
|
} catch (e, stackTrace) {
|
||||||
|
AppLogger.reportError(e, stackTrace);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <gtk/gtk_plugin.h>
|
#include <gtk/gtk_plugin.h>
|
||||||
#include <local_notifier/local_notifier_plugin.h>
|
#include <local_notifier/local_notifier_plugin.h>
|
||||||
#include <media_kit_libs_linux/media_kit_libs_linux_plugin.h>
|
#include <media_kit_libs_linux/media_kit_libs_linux_plugin.h>
|
||||||
|
#include <open_file_linux/open_file_linux_plugin.h>
|
||||||
#include <screen_retriever_linux/screen_retriever_linux_plugin.h>
|
#include <screen_retriever_linux/screen_retriever_linux_plugin.h>
|
||||||
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
||||||
#include <system_theme/system_theme_plugin.h>
|
#include <system_theme/system_theme_plugin.h>
|
||||||
@ -38,6 +39,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
|||||||
g_autoptr(FlPluginRegistrar) media_kit_libs_linux_registrar =
|
g_autoptr(FlPluginRegistrar) media_kit_libs_linux_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitLibsLinuxPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitLibsLinuxPlugin");
|
||||||
media_kit_libs_linux_plugin_register_with_registrar(media_kit_libs_linux_registrar);
|
media_kit_libs_linux_plugin_register_with_registrar(media_kit_libs_linux_registrar);
|
||||||
|
g_autoptr(FlPluginRegistrar) open_file_linux_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "OpenFileLinuxPlugin");
|
||||||
|
open_file_linux_plugin_register_with_registrar(open_file_linux_registrar);
|
||||||
g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar =
|
g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin");
|
||||||
screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar);
|
screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar);
|
||||||
|
@ -9,6 +9,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
|||||||
gtk
|
gtk
|
||||||
local_notifier
|
local_notifier
|
||||||
media_kit_libs_linux
|
media_kit_libs_linux
|
||||||
|
open_file_linux
|
||||||
screen_retriever_linux
|
screen_retriever_linux
|
||||||
sqlite3_flutter_libs
|
sqlite3_flutter_libs
|
||||||
system_theme
|
system_theme
|
||||||
|
@ -16,6 +16,7 @@ import flutter_inappwebview_macos
|
|||||||
import flutter_secure_storage_macos
|
import flutter_secure_storage_macos
|
||||||
import local_notifier
|
import local_notifier
|
||||||
import media_kit_libs_macos_audio
|
import media_kit_libs_macos_audio
|
||||||
|
import open_file_mac
|
||||||
import package_info_plus
|
import package_info_plus
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
import screen_retriever_macos
|
import screen_retriever_macos
|
||||||
@ -39,6 +40,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|||||||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||||
LocalNotifierPlugin.register(with: registry.registrar(forPlugin: "LocalNotifierPlugin"))
|
LocalNotifierPlugin.register(with: registry.registrar(forPlugin: "LocalNotifierPlugin"))
|
||||||
MediaKitLibsMacosAudioPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosAudioPlugin"))
|
MediaKitLibsMacosAudioPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosAudioPlugin"))
|
||||||
|
OpenFilePlugin.register(with: registry.registrar(forPlugin: "OpenFilePlugin"))
|
||||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin"))
|
ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin"))
|
||||||
|
@ -30,6 +30,8 @@ PODS:
|
|||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- metadata_god (0.0.1):
|
- metadata_god (0.0.1):
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
- open_file_mac (0.0.1):
|
||||||
|
- FlutterMacOS
|
||||||
- OrderedSet (6.0.3)
|
- OrderedSet (6.0.3)
|
||||||
- package_info_plus (0.0.1):
|
- package_info_plus (0.0.1):
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
@ -87,6 +89,7 @@ DEPENDENCIES:
|
|||||||
- media_kit_libs_macos_audio (from `Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_audio/macos`)
|
- media_kit_libs_macos_audio (from `Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_audio/macos`)
|
||||||
- media_kit_native_event_loop (from `Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos`)
|
- media_kit_native_event_loop (from `Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos`)
|
||||||
- metadata_god (from `Flutter/ephemeral/.symlinks/plugins/metadata_god/macos`)
|
- metadata_god (from `Flutter/ephemeral/.symlinks/plugins/metadata_god/macos`)
|
||||||
|
- open_file_mac (from `Flutter/ephemeral/.symlinks/plugins/open_file_mac/macos`)
|
||||||
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
|
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
|
||||||
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
- screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`)
|
- screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`)
|
||||||
@ -134,6 +137,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos
|
||||||
metadata_god:
|
metadata_god:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/metadata_god/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/metadata_god/macos
|
||||||
|
open_file_mac:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/open_file_mac/macos
|
||||||
package_info_plus:
|
package_info_plus:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
@ -171,6 +176,7 @@ SPEC CHECKSUMS:
|
|||||||
media_kit_libs_macos_audio: 3871782a4f3f84c77f04d7666c87800a781c24da
|
media_kit_libs_macos_audio: 3871782a4f3f84c77f04d7666c87800a781c24da
|
||||||
media_kit_native_event_loop: 7321675377cb9ae8596a29bddf3a3d2b5e8792c5
|
media_kit_native_event_loop: 7321675377cb9ae8596a29bddf3a3d2b5e8792c5
|
||||||
metadata_god: 829f61208b44ac1173e7cd32ab740d8776be5435
|
metadata_god: 829f61208b44ac1173e7cd32ab740d8776be5435
|
||||||
|
open_file_mac: 0e554648e2a87ce59e9438e3e5ca3e552e90d89a
|
||||||
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
||||||
package_info_plus: fa739dd842b393193c5ca93c26798dff6e3d0e0c
|
package_info_plus: fa739dd842b393193c5ca93c26798dff6e3d0e0c
|
||||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||||
@ -186,4 +192,4 @@ SPEC CHECKSUMS:
|
|||||||
|
|
||||||
PODFILE CHECKSUM: 0d3963a09fc94f580682bd88480486da345dc3f0
|
PODFILE CHECKSUM: 0d3963a09fc94f580682bd88480486da345dc3f0
|
||||||
|
|
||||||
COCOAPODS: 1.15.2
|
COCOAPODS: 1.16.2
|
||||||
|
64
pubspec.lock
64
pubspec.lock
@ -1555,6 +1555,70 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.0"
|
||||||
|
open_file:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: open_file
|
||||||
|
sha256: d17e2bddf5b278cb2ae18393d0496aa4f162142ba97d1a9e0c30d476adf99c0e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.5.10"
|
||||||
|
open_file_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: open_file_android
|
||||||
|
sha256: "58141fcaece2f453a9684509a7275f231ac0e3d6ceb9a5e6de310a7dff9084aa"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.6"
|
||||||
|
open_file_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: open_file_ios
|
||||||
|
sha256: "02996f01e5f6863832068e97f8f3a5ef9b613516db6897f373b43b79849e4d07"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
|
open_file_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: open_file_linux
|
||||||
|
sha256: d189f799eecbb139c97f8bc7d303f9e720954fa4e0fa1b0b7294767e5f2d7550
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.5"
|
||||||
|
open_file_mac:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: open_file_mac
|
||||||
|
sha256: "1440b1e37ceb0642208cfeb2c659c6cda27b25187a90635c9d1acb7d0584d324"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
|
open_file_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: open_file_platform_interface
|
||||||
|
sha256: "101b424ca359632699a7e1213e83d025722ab668b9fd1412338221bf9b0e5757"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
|
open_file_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: open_file_web
|
||||||
|
sha256: e3dbc9584856283dcb30aef5720558b90f88036360bd078e494ab80a80130c4f
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.4"
|
||||||
|
open_file_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: open_file_windows
|
||||||
|
sha256: d26c31ddf935a94a1a3aa43a23f4fff8a5ff4eea395fe7a8cb819cf55431c875
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.3"
|
||||||
package_config:
|
package_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -84,6 +84,7 @@ dependencies:
|
|||||||
media_kit_libs_audio: ^1.0.4
|
media_kit_libs_audio: ^1.0.4
|
||||||
metadata_god: ^1.0.0
|
metadata_god: ^1.0.0
|
||||||
mime: ^1.0.2
|
mime: ^1.0.2
|
||||||
|
open_file: ^3.5.10
|
||||||
package_info_plus: ^6.0.0
|
package_info_plus: ^6.0.0
|
||||||
palette_generator: ^0.3.3
|
palette_generator: ^0.3.3
|
||||||
path: ^1.9.0
|
path: ^1.9.0
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
// dart format width=80
|
||||||
// GENERATED CODE, DO NOT EDIT BY HAND.
|
// GENERATED CODE, DO NOT EDIT BY HAND.
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
//@dart=2.12
|
|
||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:drift/internal/migrations.dart';
|
import 'package:drift/internal/migrations.dart';
|
||||||
|
import 'schema_v3.dart' as v3;
|
||||||
import 'schema_v2.dart' as v2;
|
import 'schema_v2.dart' as v2;
|
||||||
import 'schema_v1.dart' as v1;
|
import 'schema_v1.dart' as v1;
|
||||||
|
|
||||||
@ -10,6 +11,8 @@ class GeneratedHelper implements SchemaInstantiationHelper {
|
|||||||
@override
|
@override
|
||||||
GeneratedDatabase databaseForVersion(QueryExecutor db, int version) {
|
GeneratedDatabase databaseForVersion(QueryExecutor db, int version) {
|
||||||
switch (version) {
|
switch (version) {
|
||||||
|
case 3:
|
||||||
|
return v3.DatabaseAtV3(db);
|
||||||
case 2:
|
case 2:
|
||||||
return v2.DatabaseAtV2(db);
|
return v2.DatabaseAtV2(db);
|
||||||
case 1:
|
case 1:
|
||||||
@ -19,5 +22,5 @@ class GeneratedHelper implements SchemaInstantiationHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const versions = const [1, 2];
|
static const versions = const [1, 2, 3];
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
|
// dart format width=80
|
||||||
// GENERATED CODE, DO NOT EDIT BY HAND.
|
// GENERATED CODE, DO NOT EDIT BY HAND.
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
//@dart=2.12
|
|
||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:flutter/material.dart' hide Table;
|
|
||||||
import 'package:spotify/spotify.dart';
|
|
||||||
import 'package:spotube/services/sourced_track/enums.dart';
|
|
||||||
import 'package:spotube/utils/migrations/adapters.dart';
|
|
||||||
|
|
||||||
class AuthenticationTable extends Table
|
class AuthenticationTable extends Table
|
||||||
with TableInfo<AuthenticationTable, AuthenticationTableData> {
|
with TableInfo<AuthenticationTable, AuthenticationTableData> {
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
|
// dart format width=80
|
||||||
// GENERATED CODE, DO NOT EDIT BY HAND.
|
// GENERATED CODE, DO NOT EDIT BY HAND.
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
//@dart=2.12
|
|
||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:flutter/material.dart' hide Table;
|
|
||||||
import 'package:spotify/spotify.dart';
|
|
||||||
import 'package:spotube/services/sourced_track/enums.dart';
|
|
||||||
import 'package:spotube/utils/migrations/adapters.dart';
|
|
||||||
|
|
||||||
class AuthenticationTable extends Table
|
class AuthenticationTable extends Table
|
||||||
with TableInfo<AuthenticationTable, AuthenticationTableData> {
|
with TableInfo<AuthenticationTable, AuthenticationTableData> {
|
||||||
|
3396
test/drift/app_db/generated/schema_v3.dart
Normal file
3396
test/drift/app_db/generated/schema_v3.dart
Normal file
File diff suppressed because it is too large
Load Diff
@ -3,181 +3,441 @@
|
|||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"bn": [
|
"bn": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"ca": [
|
"ca": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"cs": [
|
"cs": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"de": [
|
"de": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"es": [
|
"es": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"eu": [
|
"eu": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"fa": [
|
"fa": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"fi": [
|
"fi": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"fr": [
|
"fr": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"hi": [
|
"hi": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"id": [
|
"id": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"it": [
|
"it": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"ja": [
|
"ja": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"ka": [
|
"ka": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"ko": [
|
"ko": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"ne": [
|
"ne": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"nl": [
|
"nl": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"pl": [
|
"pl": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"pt": [
|
"pt": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"ru": [
|
"ru": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"th": [
|
"th": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"tr": [
|
"tr": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"uk": [
|
"uk": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"vi": [
|
"vi": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
],
|
],
|
||||||
|
|
||||||
"zh": [
|
"zh": [
|
||||||
"invidious_instance",
|
"invidious_instance",
|
||||||
"invidious_description",
|
"invidious_description",
|
||||||
"invidious_warning",
|
"invidious_warning",
|
||||||
"invidious_source_description"
|
"invidious_source_description",
|
||||||
|
"cache_music",
|
||||||
|
"open",
|
||||||
|
"cache_folder",
|
||||||
|
"export",
|
||||||
|
"clear_cache",
|
||||||
|
"clear_cache_confirmation",
|
||||||
|
"export_cache_files",
|
||||||
|
"found_n_files",
|
||||||
|
"export_cache_confirmation",
|
||||||
|
"exported_n_out_of_m_files"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user