mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-15 08:35:18 +00:00

Configuration File Removals: .vscode/c_cpp_properties.json: Removed the entire configuration for C/C++ properties. .vscode/launch.json: Removed the Dart launch configurations for different environments and modes. .vscode/settings.json: Removed settings related to CMake, spell checking, file nesting, and Dart Flutter SDK path. .vscode/snippets.code-snippets: Removed code snippets for Dart, including PaginatedState and PaginatedNotifier templates. .vscode/tasks.json: Removed the tasks configuration file. Documentation Updates: CONTRIBUTION.md: Removed heart emoji from the introductory text. README.md: Updated the logo image and made minor text adjustments, including removing emojis and updating section titles. [1] [2] [3] [4] [5] Asset Removals: lib/collections/assets.gen.dart: Removed multiple unused asset references, including images related to Spotube logos and banners. [1] [2] [3] Minor Code Cleanups: cli/commands/build/linux.dart, cli/commands/build/windows.dart, cli/commands/translated.dart, cli/commands/untranslated.dart: Adjusted import statements for consistency. [1] [2] [3] [4] integration_test/app_test.dart: Removed an unnecessary blank line. lib/collections/routes.dart: Commented out the TrackRoute configuration.
182 lines
5.5 KiB
Dart
182 lines
5.5 KiB
Dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:spotify/spotify.dart';
|
|
import 'package:spotube/models/database/database.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/models/source_info.dart';
|
|
import 'package:spotube/services/sourced_track/models/source_map.dart';
|
|
import 'package:spotube/services/sourced_track/sources/invidious.dart';
|
|
import 'package:spotube/services/sourced_track/sources/jiosaavn.dart';
|
|
import 'package:spotube/services/sourced_track/sources/piped.dart';
|
|
import 'package:spotube/services/sourced_track/sources/youtube.dart';
|
|
import 'package:spotube/utils/service_utils.dart';
|
|
|
|
abstract class SourcedTrack extends Track {
|
|
final SourceMap source;
|
|
final List<SourceInfo> siblings;
|
|
final SourceInfo sourceInfo;
|
|
final Ref ref;
|
|
|
|
SourcedTrack({
|
|
required this.ref,
|
|
required this.source,
|
|
required this.siblings,
|
|
required this.sourceInfo,
|
|
required Track track,
|
|
}) {
|
|
id = track.id;
|
|
name = track.name;
|
|
artists = track.artists;
|
|
album = track.album;
|
|
durationMs = track.durationMs;
|
|
discNumber = track.discNumber;
|
|
explicit = track.explicit;
|
|
externalIds = track.externalIds;
|
|
href = track.href;
|
|
isPlayable = track.isPlayable;
|
|
linkedFrom = track.linkedFrom;
|
|
popularity = track.popularity;
|
|
previewUrl = track.previewUrl;
|
|
trackNumber = track.trackNumber;
|
|
type = track.type;
|
|
uri = track.uri;
|
|
}
|
|
|
|
static SourcedTrack fromJson(
|
|
Map<String, dynamic> json, {
|
|
required Ref ref,
|
|
}) {
|
|
final preferences = ref.read(userPreferencesProvider);
|
|
|
|
final sourceInfo = SourceInfo.fromJson(json);
|
|
final source = SourceMap.fromJson(json);
|
|
final track = Track.fromJson(json);
|
|
final siblings = (json["siblings"] as List)
|
|
.map((sibling) => SourceInfo.fromJson(sibling))
|
|
.toList()
|
|
.cast<SourceInfo>();
|
|
|
|
return switch (preferences.audioSource) {
|
|
AudioSource.youtube => YoutubeSourcedTrack(
|
|
ref: ref,
|
|
source: source,
|
|
siblings: siblings,
|
|
sourceInfo: sourceInfo,
|
|
track: track,
|
|
),
|
|
AudioSource.piped => PipedSourcedTrack(
|
|
ref: ref,
|
|
source: source,
|
|
siblings: siblings,
|
|
sourceInfo: sourceInfo,
|
|
track: track,
|
|
),
|
|
AudioSource.jiosaavn => JioSaavnSourcedTrack(
|
|
ref: ref,
|
|
source: source,
|
|
siblings: siblings,
|
|
sourceInfo: sourceInfo,
|
|
track: track,
|
|
),
|
|
AudioSource.invidious => InvidiousSourcedTrack(
|
|
ref: ref,
|
|
source: source,
|
|
siblings: siblings,
|
|
sourceInfo: sourceInfo,
|
|
track: track,
|
|
),
|
|
};
|
|
}
|
|
|
|
static String getSearchTerm(Track track) {
|
|
final artists =
|
|
(track.artists ?? []).map((ar) => ar.name).toList().nonNulls.toList();
|
|
|
|
final title = ServiceUtils.getTitle(
|
|
track.name!,
|
|
artists: artists,
|
|
onlyCleanArtist: true,
|
|
).trim();
|
|
|
|
return "$title - ${artists.join(", ")}";
|
|
}
|
|
|
|
static Future<SourcedTrack> fetchFromTrack({
|
|
required Track track,
|
|
required Ref ref,
|
|
}) async {
|
|
final preferences = ref.read(userPreferencesProvider);
|
|
try {
|
|
return switch (preferences.audioSource) {
|
|
AudioSource.youtube =>
|
|
await YoutubeSourcedTrack.fetchFromTrack(track: track, ref: ref),
|
|
AudioSource.piped =>
|
|
await PipedSourcedTrack.fetchFromTrack(track: track, ref: ref),
|
|
AudioSource.invidious =>
|
|
await InvidiousSourcedTrack.fetchFromTrack(track: track, ref: ref),
|
|
AudioSource.jiosaavn =>
|
|
await JioSaavnSourcedTrack.fetchFromTrack(track: track, ref: ref),
|
|
};
|
|
} catch (e) {
|
|
if (preferences.audioSource == AudioSource.youtube) {
|
|
rethrow;
|
|
}
|
|
|
|
return await YoutubeSourcedTrack.fetchFromTrack(track: track, ref: ref);
|
|
}
|
|
}
|
|
|
|
static Future<List<SiblingType>> fetchSiblings({
|
|
required Track track,
|
|
required Ref ref,
|
|
}) {
|
|
final preferences = ref.read(userPreferencesProvider);
|
|
|
|
return switch (preferences.audioSource) {
|
|
AudioSource.piped =>
|
|
PipedSourcedTrack.fetchSiblings(track: track, ref: ref),
|
|
AudioSource.youtube =>
|
|
YoutubeSourcedTrack.fetchSiblings(track: track, ref: ref),
|
|
AudioSource.jiosaavn =>
|
|
JioSaavnSourcedTrack.fetchSiblings(track: track, ref: ref),
|
|
AudioSource.invidious =>
|
|
InvidiousSourcedTrack.fetchSiblings(track: track, ref: ref),
|
|
};
|
|
}
|
|
|
|
Future<SourcedTrack> copyWithSibling();
|
|
|
|
Future<SourcedTrack?> swapWithSibling(SourceInfo sibling);
|
|
|
|
Future<SourcedTrack?> swapWithSiblingOfIndex(int index) {
|
|
return swapWithSibling(siblings[index]);
|
|
}
|
|
|
|
String get url {
|
|
final preferences = ref.read(userPreferencesProvider);
|
|
|
|
final codec = preferences.audioSource == AudioSource.jiosaavn
|
|
? SourceCodecs.m4a
|
|
: preferences.streamMusicCodec;
|
|
|
|
return getUrlOfCodec(codec);
|
|
}
|
|
|
|
String getUrlOfCodec(SourceCodecs codec) {
|
|
final preferences = ref.read(userPreferencesProvider);
|
|
|
|
return source[codec]?[preferences.audioQuality] ??
|
|
// this will ensure playback doesn't break
|
|
source[codec == SourceCodecs.m4a ? SourceCodecs.weba : SourceCodecs.m4a]
|
|
[preferences.audioQuality];
|
|
}
|
|
|
|
SourceCodecs get codec {
|
|
final preferences = ref.read(userPreferencesProvider);
|
|
|
|
return preferences.audioSource == AudioSource.jiosaavn
|
|
? SourceCodecs.m4a
|
|
: preferences.streamMusicCodec;
|
|
}
|
|
}
|