Compare commits

..

2 Commits

Author SHA1 Message Date
Kingkor Roy Tirtho
e1fa9efa14 fix: selection preset quality returning null 2025-11-04 13:45:23 +06:00
Kingkor Roy Tirtho
6272f376ea fix: quality preset initialization fails and audio source auth 2025-11-04 12:02:10 +06:00
7 changed files with 63 additions and 67 deletions

1
android/.gitignore vendored
View File

@ -11,3 +11,4 @@ GeneratedPluginRegistrant.java
key.properties key.properties
**/*.keystore **/*.keystore
**/*.jks **/*.jks
.kotlin

View File

@ -44,7 +44,7 @@ class SpotubeAudioLossyContainerQuality
@override @override
toString() { toString() {
return "${oneOptionalDecimalFormatter.format(bitrate)}kbps"; return "${oneOptionalDecimalFormatter.format(bitrate / 1000)}kbps";
} }
} }

View File

@ -52,9 +52,10 @@ class MetadataInstalledPluginItem extends HookConsumerWidget {
ref.watch(metadataPluginAuthenticatedProvider); ref.watch(metadataPluginAuthenticatedProvider);
final isAudioSourceAuthenticatedSnapshot = final isAudioSourceAuthenticatedSnapshot =
ref.watch(audioSourcePluginAuthenticatedProvider); ref.watch(audioSourcePluginAuthenticatedProvider);
final isAuthenticated = final isAuthenticated = (isDefaultMetadata &&
isMetadataAuthenticatedSnapshot.asData?.value == true || isMetadataAuthenticatedSnapshot.asData?.value == true) ||
isAudioSourceAuthenticatedSnapshot.asData?.value == true; (isDefaultAudioSource &&
isAudioSourceAuthenticatedSnapshot.asData?.value == true);
final metadataUpdateAvailable = final metadataUpdateAvailable =
ref.watch(metadataPluginUpdateCheckerProvider); ref.watch(metadataPluginUpdateCheckerProvider);

View File

@ -6,6 +6,7 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:spotube/models/metadata/metadata.dart'; import 'package:spotube/models/metadata/metadata.dart';
import 'package:spotube/provider/metadata_plugin/metadata_plugin_provider.dart'; import 'package:spotube/provider/metadata_plugin/metadata_plugin_provider.dart';
import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/services/audio_player/audio_player.dart';
import 'package:spotube/services/metadata/metadata.dart';
part 'quality_presets.g.dart'; part 'quality_presets.g.dart';
part 'quality_presets.freezed.dart'; part 'quality_presets.freezed.dart';
@ -28,9 +29,13 @@ class AudioSourceAvailableQualityPresetsNotifier
extends Notifier<AudioSourcePresetsState> { extends Notifier<AudioSourcePresetsState> {
@override @override
build() { build() {
ref.watch(audioSourcePluginProvider); final audioSourceSnapshot = ref.watch(audioSourcePluginProvider);
final audioSourceConfigSnapshot = ref.watch(
metadataPluginsProvider.select((data) =>
data.whenData((value) => value.defaultAudioSourcePluginConfig)),
);
_initialize(); _initialize(audioSourceSnapshot, audioSourceConfigSnapshot);
listenSelf((previous, next) { listenSelf((previous, next) {
final isNewLossless = final isNewLossless =
@ -49,12 +54,12 @@ class AudioSourceAvailableQualityPresetsNotifier
return AudioSourcePresetsState(); return AudioSourcePresetsState();
} }
void _initialize() async { void _initialize(
final audioSource = await ref.read(audioSourcePluginProvider.future); AsyncValue<MetadataPlugin?> audioSourceSnapshot,
final audioSourceConfig = await ref.read( AsyncValue<PluginConfiguration?> audioSourceConfigSnapshot,
metadataPluginsProvider ) async {
.selectAsync((data) => data.defaultAudioSourcePluginConfig), audioSourceConfigSnapshot.whenData((audioSourceConfig) {
); audioSourceSnapshot.whenData((audioSource) async {
if (audioSource == null || audioSourceConfig == null) { if (audioSource == null || audioSourceConfig == null) {
throw Exception("Dude wat?"); throw Exception("Dude wat?");
} }
@ -63,12 +68,18 @@ class AudioSourceAvailableQualityPresetsNotifier
preferences.getString("audioSourceState-${audioSourceConfig.slug}"); preferences.getString("audioSourceState-${audioSourceConfig.slug}");
if (persistedStateStr != null) { if (persistedStateStr != null) {
state = AudioSourcePresetsState.fromJson(jsonDecode(persistedStateStr)); state =
AudioSourcePresetsState.fromJson(jsonDecode(persistedStateStr))
.copyWith(
presets: audioSource.audioSource.supportedPresets,
);
} else { } else {
state = AudioSourcePresetsState( state = AudioSourcePresetsState(
presets: audioSource.audioSource.supportedPresets, presets: audioSource.audioSource.supportedPresets,
); );
} }
});
});
} }
void setSelectedStreamingContainerIndex(int index) { void setSelectedStreamingContainerIndex(int index) {

View File

@ -65,6 +65,6 @@ class AudioSourcePluginAuthenticatedNotifier extends AsyncNotifier<bool> {
} }
final audioSourcePluginAuthenticatedProvider = final audioSourcePluginAuthenticatedProvider =
AsyncNotifierProvider<MetadataPluginAuthenticatedNotifier, bool>( AsyncNotifierProvider<AudioSourcePluginAuthenticatedNotifier, bool>(
MetadataPluginAuthenticatedNotifier.new, AudioSourcePluginAuthenticatedNotifier.new,
); );

View File

@ -48,7 +48,7 @@ class ServerPlaybackRoutes {
return join( return join(
await UserPreferencesNotifier.getMusicCacheDir(), await UserPreferencesNotifier.getMusicCacheDir(),
ServiceUtils.sanitizeFilename( ServiceUtils.sanitizeFilename(
'${track.query.name} - ${track.query.artists.join(",")} (${track.info.id}).${track.qualityPreset!.name}', '${track.query.name} - ${track.query.artists.map((d) => d.name).join(",")} (${track.info.id}).${track.qualityPreset!.name}',
), ),
); );
} }
@ -288,7 +288,9 @@ class ServerPlaybackRoutes {
imageBytes: imageBytes, imageBytes: imageBytes,
fileLength: fileLength, fileLength: fileLength,
), ),
); ).catchError((e, stackTrace) {
AppLogger.reportError(e, stackTrace);
});
} }
return (bytes: bytes, response: res); return (bytes: bytes, response: res);

View File

@ -306,6 +306,8 @@ class SourcedTrack extends BasicSourcedTrack {
SpotubeAudioSourceContainerPreset preset, SpotubeAudioSourceContainerPreset preset,
int qualityIndex, int qualityIndex,
) { ) {
if (sources.isEmpty) return null;
final quality = preset.qualities[qualityIndex]; final quality = preset.qualities[qualityIndex];
final exactMatch = sources.firstWhereOrNull( final exactMatch = sources.firstWhereOrNull(
@ -317,7 +319,7 @@ class SourcedTrack extends BasicSourcedTrack {
source.bitDepth == quality.bitDepth; source.bitDepth == quality.bitDepth;
} else { } else {
return source.bitrate == return source.bitrate ==
(preset as SpotubeAudioLossyContainerQuality).bitrate; (quality as SpotubeAudioLossyContainerQuality).bitrate;
} }
}, },
); );
@ -326,45 +328,24 @@ class SourcedTrack extends BasicSourcedTrack {
return exactMatch; return exactMatch;
} }
// Find the closest to preset // Find the preset with closest quality to the supplied quality
SpotubeAudioSourceStreamObject? closest; return sources.where((source) {
for (final source in sources) { return source.container == preset.name;
if (source.container != preset.name) continue; }).reduce((prev, curr) {
if (quality is SpotubeAudioLosslessContainerQuality) {
if (quality case SpotubeAudioLosslessContainerQuality()) { final prevDiff = ((prev.sampleRate ?? 0) - quality.sampleRate).abs() +
final sourceBps = (source.bitDepth ?? 0) * (source.sampleRate ?? 0); ((prev.bitDepth ?? 0) - quality.bitDepth).abs();
final qualityBps = quality.bitDepth * quality.sampleRate; final currDiff = ((curr.sampleRate ?? 0) - quality.sampleRate).abs() +
final closestBps = ((curr.bitDepth ?? 0) - quality.bitDepth).abs();
(closest?.bitDepth ?? 0) * (closest?.sampleRate ?? 0); return currDiff < prevDiff ? curr : prev;
if (sourceBps == qualityBps) {
closest = source;
break;
}
final closestDiff = (closestBps - qualityBps).abs();
final sourceDiff = (sourceBps - qualityBps).abs();
if (sourceDiff < closestDiff) {
closest = source;
}
} else { } else {
final presetBitrate = final prevDiff = ((prev.bitrate ?? 0) -
(preset as SpotubeAudioLossyContainerQuality).bitrate; (quality as SpotubeAudioLossyContainerQuality).bitrate)
if (presetBitrate == source.bitrate) { .abs();
closest = source; final currDiff = ((curr.bitrate ?? 0) - quality.bitrate).abs();
break; return currDiff < prevDiff ? curr : prev;
} }
});
final closestDiff = (closest?.bitrate ?? 0) - presetBitrate;
final sourceDiff = (source.bitrate ?? 0) - presetBitrate;
if (sourceDiff < closestDiff) {
closest = source;
}
}
}
return closest;
} }
String? getUrlOfQuality( String? getUrlOfQuality(