mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-04-01 01:20:21 +02:00
Add a new 'Auto Scan' setting under Local Library with four modes: off, every app open (10min cooldown), daily, and weekly. The app uses WidgetsBindingObserver to trigger incremental scans on launch and when resuming from background, respecting the configured cooldown based on the last scan timestamp.
279 lines
11 KiB
Dart
279 lines
11 KiB
Dart
import 'package:json_annotation/json_annotation.dart';
|
|
|
|
part 'settings.g.dart';
|
|
|
|
@JsonSerializable()
|
|
class AppSettings {
|
|
final String defaultService;
|
|
final String audioQuality;
|
|
final String filenameFormat;
|
|
final String downloadDirectory;
|
|
final String storageMode; // 'app' or 'saf'
|
|
final String downloadTreeUri; // SAF persistable tree URI
|
|
final bool autoFallback;
|
|
final bool embedMetadata; // Master switch for metadata/cover/lyrics embedding
|
|
final bool embedLyrics;
|
|
final bool maxQualityCover;
|
|
final bool isFirstLaunch;
|
|
final int concurrentDownloads;
|
|
final bool checkForUpdates;
|
|
final String updateChannel;
|
|
final bool hasSearchedBefore;
|
|
final String folderOrganization;
|
|
final bool useAlbumArtistForFolders;
|
|
final bool usePrimaryArtistOnly; // Strip featured artists from folder name
|
|
final bool filterContributingArtistsInAlbumArtist;
|
|
final String historyViewMode;
|
|
final String historyFilterMode;
|
|
final bool askQualityBeforeDownload;
|
|
final String spotifyClientId;
|
|
final String spotifyClientSecret;
|
|
final bool useCustomSpotifyCredentials;
|
|
final String metadataSource;
|
|
final bool enableLogging;
|
|
final bool useExtensionProviders;
|
|
final String? searchProvider;
|
|
final bool separateSingles;
|
|
final String albumFolderStructure;
|
|
final bool showExtensionStore;
|
|
final String locale;
|
|
final String lyricsMode;
|
|
final int
|
|
youtubeOpusBitrate; // YouTube Opus bitrate (supported: 128/256/320 kbps)
|
|
final int
|
|
youtubeMp3Bitrate; // YouTube MP3 bitrate (supported: 128/256/320 kbps)
|
|
final bool
|
|
useAllFilesAccess; // Android 13+ only: enable MANAGE_EXTERNAL_STORAGE
|
|
final bool
|
|
autoExportFailedDownloads; // Auto export failed downloads to TXT file
|
|
final String
|
|
downloadNetworkMode; // 'any' = WiFi + Mobile, 'wifi_only' = WiFi only
|
|
final bool
|
|
networkCompatibilityMode; // Try HTTP + allow invalid TLS cert for API requests
|
|
final String
|
|
songLinkRegion; // SongLink userCountry region code used for platform lookup
|
|
|
|
final bool localLibraryEnabled; // Enable local library scanning
|
|
final String localLibraryPath; // Path to scan for audio files
|
|
final String
|
|
localLibraryBookmark; // Base64-encoded iOS security-scoped bookmark
|
|
final bool
|
|
localLibraryShowDuplicates; // Show indicator when searching for existing tracks
|
|
final String
|
|
localLibraryAutoScan; // Auto-scan mode: 'off', 'on_open', 'daily', 'weekly'
|
|
|
|
final bool
|
|
hasCompletedTutorial; // Track if user has completed the app tutorial
|
|
|
|
final List<String>
|
|
lyricsProviders; // Ordered list of enabled lyrics provider IDs
|
|
final bool
|
|
lyricsIncludeTranslationNetease; // Append translated lyrics (Netease)
|
|
final bool
|
|
lyricsIncludeRomanizationNetease; // Append romanized lyrics (Netease)
|
|
final bool
|
|
lyricsMultiPersonWordByWord; // Enable v1/v2 + [bg:] tags for Apple/QQ syllable lyrics
|
|
final String
|
|
musixmatchLanguage; // Optional ISO language code for Musixmatch localized lyrics
|
|
|
|
final String
|
|
lastSeenVersion; // Last app version the user has acknowledged (e.g. '3.7.0')
|
|
|
|
const AppSettings({
|
|
this.defaultService = 'tidal',
|
|
this.audioQuality = 'LOSSLESS',
|
|
this.filenameFormat = '{title} - {artist}',
|
|
this.downloadDirectory = '',
|
|
this.storageMode = 'app',
|
|
this.downloadTreeUri = '',
|
|
this.autoFallback = true,
|
|
this.embedMetadata = true,
|
|
this.embedLyrics = true,
|
|
this.maxQualityCover = true,
|
|
this.isFirstLaunch = true,
|
|
this.concurrentDownloads = 1,
|
|
this.checkForUpdates = true,
|
|
this.updateChannel = 'stable',
|
|
this.hasSearchedBefore = false,
|
|
this.folderOrganization = 'none',
|
|
this.useAlbumArtistForFolders = true,
|
|
this.usePrimaryArtistOnly = false,
|
|
this.filterContributingArtistsInAlbumArtist = false,
|
|
this.historyViewMode = 'grid',
|
|
this.historyFilterMode = 'all',
|
|
this.askQualityBeforeDownload = true,
|
|
this.spotifyClientId = '',
|
|
this.spotifyClientSecret = '',
|
|
this.useCustomSpotifyCredentials = false,
|
|
this.metadataSource = 'deezer',
|
|
this.enableLogging = false,
|
|
this.useExtensionProviders = true,
|
|
this.searchProvider,
|
|
this.separateSingles = false,
|
|
this.albumFolderStructure = 'artist_album',
|
|
this.showExtensionStore = true,
|
|
this.locale = 'system',
|
|
this.lyricsMode = 'embed',
|
|
this.youtubeOpusBitrate = 256,
|
|
this.youtubeMp3Bitrate = 320,
|
|
this.useAllFilesAccess = false,
|
|
this.autoExportFailedDownloads = false,
|
|
this.downloadNetworkMode = 'any',
|
|
this.networkCompatibilityMode = false,
|
|
this.songLinkRegion = 'US',
|
|
this.localLibraryEnabled = false,
|
|
this.localLibraryPath = '',
|
|
this.localLibraryBookmark = '',
|
|
this.localLibraryShowDuplicates = true,
|
|
this.localLibraryAutoScan = 'off',
|
|
this.hasCompletedTutorial = false,
|
|
this.lyricsProviders = const [
|
|
'lrclib',
|
|
'spotify_api',
|
|
'musixmatch',
|
|
'netease',
|
|
'apple_music',
|
|
'qqmusic',
|
|
],
|
|
this.lyricsIncludeTranslationNetease = false,
|
|
this.lyricsIncludeRomanizationNetease = false,
|
|
this.lyricsMultiPersonWordByWord = false,
|
|
this.musixmatchLanguage = '',
|
|
this.lastSeenVersion = '',
|
|
});
|
|
|
|
AppSettings copyWith({
|
|
String? defaultService,
|
|
String? audioQuality,
|
|
String? filenameFormat,
|
|
String? downloadDirectory,
|
|
String? storageMode,
|
|
String? downloadTreeUri,
|
|
bool? autoFallback,
|
|
bool? embedMetadata,
|
|
bool? embedLyrics,
|
|
bool? maxQualityCover,
|
|
bool? isFirstLaunch,
|
|
int? concurrentDownloads,
|
|
bool? checkForUpdates,
|
|
String? updateChannel,
|
|
bool? hasSearchedBefore,
|
|
String? folderOrganization,
|
|
bool? useAlbumArtistForFolders,
|
|
bool? usePrimaryArtistOnly,
|
|
bool? filterContributingArtistsInAlbumArtist,
|
|
String? historyViewMode,
|
|
String? historyFilterMode,
|
|
bool? askQualityBeforeDownload,
|
|
String? spotifyClientId,
|
|
String? spotifyClientSecret,
|
|
bool? useCustomSpotifyCredentials,
|
|
String? metadataSource,
|
|
bool? enableLogging,
|
|
bool? useExtensionProviders,
|
|
String? searchProvider,
|
|
bool clearSearchProvider = false,
|
|
bool? separateSingles,
|
|
String? albumFolderStructure,
|
|
bool? showExtensionStore,
|
|
String? locale,
|
|
String? lyricsMode,
|
|
int? youtubeOpusBitrate,
|
|
int? youtubeMp3Bitrate,
|
|
bool? useAllFilesAccess,
|
|
bool? autoExportFailedDownloads,
|
|
String? downloadNetworkMode,
|
|
bool? networkCompatibilityMode,
|
|
String? songLinkRegion,
|
|
bool? localLibraryEnabled,
|
|
String? localLibraryPath,
|
|
String? localLibraryBookmark,
|
|
bool? localLibraryShowDuplicates,
|
|
String? localLibraryAutoScan,
|
|
bool? hasCompletedTutorial,
|
|
List<String>? lyricsProviders,
|
|
bool? lyricsIncludeTranslationNetease,
|
|
bool? lyricsIncludeRomanizationNetease,
|
|
bool? lyricsMultiPersonWordByWord,
|
|
String? musixmatchLanguage,
|
|
String? lastSeenVersion,
|
|
}) {
|
|
return AppSettings(
|
|
defaultService: defaultService ?? this.defaultService,
|
|
audioQuality: audioQuality ?? this.audioQuality,
|
|
filenameFormat: filenameFormat ?? this.filenameFormat,
|
|
downloadDirectory: downloadDirectory ?? this.downloadDirectory,
|
|
storageMode: storageMode ?? this.storageMode,
|
|
downloadTreeUri: downloadTreeUri ?? this.downloadTreeUri,
|
|
autoFallback: autoFallback ?? this.autoFallback,
|
|
embedMetadata: embedMetadata ?? this.embedMetadata,
|
|
embedLyrics: embedLyrics ?? this.embedLyrics,
|
|
maxQualityCover: maxQualityCover ?? this.maxQualityCover,
|
|
isFirstLaunch: isFirstLaunch ?? this.isFirstLaunch,
|
|
concurrentDownloads: concurrentDownloads ?? this.concurrentDownloads,
|
|
checkForUpdates: checkForUpdates ?? this.checkForUpdates,
|
|
updateChannel: updateChannel ?? this.updateChannel,
|
|
hasSearchedBefore: hasSearchedBefore ?? this.hasSearchedBefore,
|
|
folderOrganization: folderOrganization ?? this.folderOrganization,
|
|
useAlbumArtistForFolders:
|
|
useAlbumArtistForFolders ?? this.useAlbumArtistForFolders,
|
|
usePrimaryArtistOnly: usePrimaryArtistOnly ?? this.usePrimaryArtistOnly,
|
|
filterContributingArtistsInAlbumArtist:
|
|
filterContributingArtistsInAlbumArtist ??
|
|
this.filterContributingArtistsInAlbumArtist,
|
|
historyViewMode: historyViewMode ?? this.historyViewMode,
|
|
historyFilterMode: historyFilterMode ?? this.historyFilterMode,
|
|
askQualityBeforeDownload:
|
|
askQualityBeforeDownload ?? this.askQualityBeforeDownload,
|
|
spotifyClientId: spotifyClientId ?? this.spotifyClientId,
|
|
spotifyClientSecret: spotifyClientSecret ?? this.spotifyClientSecret,
|
|
useCustomSpotifyCredentials:
|
|
useCustomSpotifyCredentials ?? this.useCustomSpotifyCredentials,
|
|
metadataSource: metadataSource ?? this.metadataSource,
|
|
enableLogging: enableLogging ?? this.enableLogging,
|
|
useExtensionProviders:
|
|
useExtensionProviders ?? this.useExtensionProviders,
|
|
searchProvider: clearSearchProvider
|
|
? null
|
|
: (searchProvider ?? this.searchProvider),
|
|
separateSingles: separateSingles ?? this.separateSingles,
|
|
albumFolderStructure: albumFolderStructure ?? this.albumFolderStructure,
|
|
showExtensionStore: showExtensionStore ?? this.showExtensionStore,
|
|
locale: locale ?? this.locale,
|
|
lyricsMode: lyricsMode ?? this.lyricsMode,
|
|
youtubeOpusBitrate: youtubeOpusBitrate ?? this.youtubeOpusBitrate,
|
|
youtubeMp3Bitrate: youtubeMp3Bitrate ?? this.youtubeMp3Bitrate,
|
|
useAllFilesAccess: useAllFilesAccess ?? this.useAllFilesAccess,
|
|
autoExportFailedDownloads:
|
|
autoExportFailedDownloads ?? this.autoExportFailedDownloads,
|
|
downloadNetworkMode: downloadNetworkMode ?? this.downloadNetworkMode,
|
|
networkCompatibilityMode:
|
|
networkCompatibilityMode ?? this.networkCompatibilityMode,
|
|
songLinkRegion: songLinkRegion ?? this.songLinkRegion,
|
|
localLibraryEnabled: localLibraryEnabled ?? this.localLibraryEnabled,
|
|
localLibraryPath: localLibraryPath ?? this.localLibraryPath,
|
|
localLibraryBookmark: localLibraryBookmark ?? this.localLibraryBookmark,
|
|
localLibraryShowDuplicates:
|
|
localLibraryShowDuplicates ?? this.localLibraryShowDuplicates,
|
|
localLibraryAutoScan:
|
|
localLibraryAutoScan ?? this.localLibraryAutoScan,
|
|
hasCompletedTutorial: hasCompletedTutorial ?? this.hasCompletedTutorial,
|
|
lyricsProviders: lyricsProviders ?? this.lyricsProviders,
|
|
lyricsIncludeTranslationNetease:
|
|
lyricsIncludeTranslationNetease ??
|
|
this.lyricsIncludeTranslationNetease,
|
|
lyricsIncludeRomanizationNetease:
|
|
lyricsIncludeRomanizationNetease ??
|
|
this.lyricsIncludeRomanizationNetease,
|
|
lyricsMultiPersonWordByWord:
|
|
lyricsMultiPersonWordByWord ?? this.lyricsMultiPersonWordByWord,
|
|
musixmatchLanguage: musixmatchLanguage ?? this.musixmatchLanguage,
|
|
lastSeenVersion: lastSeenVersion ?? this.lastSeenVersion,
|
|
);
|
|
}
|
|
|
|
factory AppSettings.fromJson(Map<String, dynamic> json) =>
|
|
_$AppSettingsFromJson(json);
|
|
Map<String, dynamic> toJson() => _$AppSettingsToJson(this);
|
|
}
|