mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-12 23:45:18 +00:00
fix: alternative searched sources doesn't play #1059
This commit is contained in:
parent
59e0e6bb65
commit
a8e9b824f3
BIN
assets/jiosaavn.png
Normal file
BIN
assets/jiosaavn.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
@ -34,6 +34,7 @@ class Assets {
|
||||
AssetGenImage('assets/bengali-patterns-bg.jpg');
|
||||
static const AssetGenImage branding = AssetGenImage('assets/branding.png');
|
||||
static const AssetGenImage emptyBox = AssetGenImage('assets/empty_box.png');
|
||||
static const AssetGenImage jiosaavn = AssetGenImage('assets/jiosaavn.png');
|
||||
static const AssetGenImage likedTracks =
|
||||
AssetGenImage('assets/liked-tracks.jpg');
|
||||
static const AssetGenImage placeholder =
|
||||
@ -76,6 +77,7 @@ class Assets {
|
||||
bengaliPatternsBg,
|
||||
branding,
|
||||
emptyBox,
|
||||
jiosaavn,
|
||||
likedTracks,
|
||||
placeholder,
|
||||
spotubeHeroBanner,
|
||||
|
@ -109,4 +109,5 @@ abstract class SpotubeIcons {
|
||||
static const normalize = FeatherIcons.barChart2;
|
||||
static const wikipedia = SimpleIcons.wikipedia;
|
||||
static const discord = SimpleIcons.discord;
|
||||
static const youtube = SimpleIcons.youtube;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:spotify/spotify.dart' hide Offset;
|
||||
import 'package:spotube/collections/assets.gen.dart';
|
||||
import 'package:spotube/collections/spotube_icons.dart';
|
||||
|
||||
import 'package:spotube/components/shared/image/universal_image.dart';
|
||||
@ -19,10 +20,28 @@ import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
|
||||
import 'package:spotube/services/sourced_track/models/source_info.dart';
|
||||
import 'package:spotube/services/sourced_track/models/video_info.dart';
|
||||
import 'package:spotube/services/sourced_track/sourced_track.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';
|
||||
import 'package:spotube/utils/type_conversion_utils.dart';
|
||||
|
||||
final sourceInfoToIconMap = {
|
||||
YoutubeSourceInfo: const Icon(SpotubeIcons.youtube, color: Color(0xFFFF0000)),
|
||||
JioSaavnSourceInfo: Container(
|
||||
height: 30,
|
||||
width: 30,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(90),
|
||||
image: DecorationImage(
|
||||
image: Assets.jiosaavn.provider(),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
PipedSourceInfo: const Icon(SpotubeIcons.piped),
|
||||
};
|
||||
|
||||
class SiblingTracksSheet extends HookConsumerWidget {
|
||||
final bool floating;
|
||||
const SiblingTracksSheet({
|
||||
@ -64,17 +83,34 @@ class SiblingTracksSheet extends HookConsumerWidget {
|
||||
return <SourceInfo>[];
|
||||
}
|
||||
|
||||
final results = await youtubeClient.search.search(searchTerm.trim());
|
||||
final resultsYt = await youtubeClient.search.search(searchTerm.trim());
|
||||
final resultsJioSaavn =
|
||||
await jiosaavnClient.search.songs(searchTerm.trim());
|
||||
|
||||
return await Future.wait(
|
||||
results.map(YoutubeVideoInfo.fromVideo).mapIndexed((i, video) async {
|
||||
final searchResults = await Future.wait([
|
||||
...resultsJioSaavn.results.mapIndexed((i, song) async {
|
||||
final siblingType = JioSaavnSourcedTrack.toSiblingType(song);
|
||||
return siblingType.info;
|
||||
}),
|
||||
...resultsYt
|
||||
.map(YoutubeVideoInfo.fromVideo)
|
||||
.mapIndexed((i, video) async {
|
||||
final siblingType = await YoutubeSourcedTrack.toSiblingType(i, video);
|
||||
return siblingType.info;
|
||||
}),
|
||||
);
|
||||
]);
|
||||
final activeSourceInfo =
|
||||
(playlist.activeTrack! as SourcedTrack).sourceInfo;
|
||||
return searchResults
|
||||
..removeWhere((element) => element.id == activeSourceInfo.id)
|
||||
..insert(
|
||||
0,
|
||||
activeSourceInfo,
|
||||
);
|
||||
}, [
|
||||
searchTerm,
|
||||
searchMode.value,
|
||||
playlist.activeTrack,
|
||||
]);
|
||||
|
||||
final siblings = useMemoized(
|
||||
@ -104,6 +140,7 @@ class SiblingTracksSheet extends HookConsumerWidget {
|
||||
|
||||
final itemBuilder = useCallback(
|
||||
(SourceInfo sourceInfo) {
|
||||
final icon = sourceInfoToIconMap[sourceInfo.runtimeType];
|
||||
return ListTile(
|
||||
title: Text(sourceInfo.title),
|
||||
leading: Padding(
|
||||
@ -118,7 +155,12 @@ class SiblingTracksSheet extends HookConsumerWidget {
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
),
|
||||
trailing: Text(sourceInfo.duration.toHumanReadableString()),
|
||||
subtitle: Text(sourceInfo.artist),
|
||||
subtitle: Row(
|
||||
children: [
|
||||
if (icon != null) icon,
|
||||
Text(" • ${sourceInfo.artist}"),
|
||||
],
|
||||
),
|
||||
enabled: playlist.isFetching != true,
|
||||
selected: playlist.isFetching != true &&
|
||||
sourceInfo.id ==
|
||||
@ -137,7 +179,7 @@ class SiblingTracksSheet extends HookConsumerWidget {
|
||||
[playlist.isFetching, playlist.activeTrack, siblings],
|
||||
);
|
||||
|
||||
var mediaQuery = MediaQuery.of(context);
|
||||
final mediaQuery = MediaQuery.of(context);
|
||||
return SafeArea(
|
||||
child: ClipRRect(
|
||||
borderRadius: borderRadius,
|
||||
|
@ -15,4 +15,4 @@ enum SourceQualities {
|
||||
low,
|
||||
}
|
||||
|
||||
typedef SiblingType = ({SourceInfo info, SourceMap? source});
|
||||
typedef SiblingType<T extends SourceInfo> = ({T info, SourceMap? source});
|
||||
|
@ -12,6 +12,19 @@ import 'package:spotube/extensions/string.dart';
|
||||
|
||||
final jiosaavnClient = JioSaavnClient();
|
||||
|
||||
class JioSaavnSourceInfo extends SourceInfo {
|
||||
JioSaavnSourceInfo({
|
||||
required super.id,
|
||||
required super.title,
|
||||
required super.artist,
|
||||
required super.thumbnail,
|
||||
required super.pageUrl,
|
||||
required super.duration,
|
||||
required super.artistUrl,
|
||||
required super.album,
|
||||
});
|
||||
}
|
||||
|
||||
class JioSaavnSourcedTrack extends SourcedTrack {
|
||||
JioSaavnSourcedTrack({
|
||||
required super.ref,
|
||||
@ -70,7 +83,7 @@ class JioSaavnSourcedTrack extends SourcedTrack {
|
||||
|
||||
static SiblingType toSiblingType(SongResponse result) {
|
||||
final SiblingType sibling = (
|
||||
info: SourceInfo(
|
||||
info: JioSaavnSourceInfo(
|
||||
artist: [
|
||||
result.primaryArtists,
|
||||
if (result.featuredArtists.isNotEmpty) ", ",
|
||||
@ -155,12 +168,16 @@ class JioSaavnSourcedTrack extends SourcedTrack {
|
||||
|
||||
@override
|
||||
Future<JioSaavnSourcedTrack?> swapWithSibling(SourceInfo sibling) async {
|
||||
if (sibling.id == sourceInfo.id ||
|
||||
siblings.none((s) => s.id == sibling.id)) {
|
||||
if (sibling.id == sourceInfo.id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final newSourceInfo = siblings.firstWhere((s) => s.id == sibling.id);
|
||||
// a sibling source that was fetched from the search results
|
||||
final isStepSibling = siblings.none((s) => s.id == sibling.id);
|
||||
|
||||
final newSourceInfo = isStepSibling
|
||||
? sibling
|
||||
: siblings.firstWhere((s) => s.id == sibling.id);
|
||||
final newSiblings = siblings.where((s) => s.id != sibling.id).toList()
|
||||
..insert(0, sourceInfo);
|
||||
|
||||
|
@ -22,6 +22,19 @@ final pipedProvider = Provider<PipedClient>(
|
||||
},
|
||||
);
|
||||
|
||||
class PipedSourceInfo extends SourceInfo {
|
||||
PipedSourceInfo({
|
||||
required super.id,
|
||||
required super.title,
|
||||
required super.artist,
|
||||
required super.thumbnail,
|
||||
required super.pageUrl,
|
||||
required super.duration,
|
||||
required super.artistUrl,
|
||||
required super.album,
|
||||
});
|
||||
}
|
||||
|
||||
class PipedSourcedTrack extends SourcedTrack {
|
||||
PipedSourcedTrack({
|
||||
required super.ref,
|
||||
@ -71,7 +84,7 @@ class PipedSourcedTrack extends SourcedTrack {
|
||||
ref: ref,
|
||||
siblings: [],
|
||||
source: toSourceMap(manifest),
|
||||
sourceInfo: SourceInfo(
|
||||
sourceInfo: PipedSourceInfo(
|
||||
id: manifest.id,
|
||||
artist: manifest.uploader,
|
||||
artistUrl: manifest.uploaderUrl,
|
||||
@ -122,7 +135,7 @@ class PipedSourcedTrack extends SourcedTrack {
|
||||
}
|
||||
|
||||
final SiblingType sibling = (
|
||||
info: SourceInfo(
|
||||
info: PipedSourceInfo(
|
||||
id: item.id,
|
||||
artist: item.channelName,
|
||||
artistUrl: "https://www.youtube.com/${item.channelId}",
|
||||
@ -233,12 +246,16 @@ class PipedSourcedTrack extends SourcedTrack {
|
||||
|
||||
@override
|
||||
Future<SourcedTrack?> swapWithSibling(SourceInfo sibling) async {
|
||||
if (sibling.id == sourceInfo.id ||
|
||||
siblings.none((s) => s.id == sibling.id)) {
|
||||
if (sibling.id == sourceInfo.id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final newSourceInfo = siblings.firstWhere((s) => s.id == sibling.id);
|
||||
// a sibling source that was fetched from the search results
|
||||
final isStepSibling = siblings.none((s) => s.id == sibling.id);
|
||||
|
||||
final newSourceInfo = isStepSibling
|
||||
? sibling
|
||||
: siblings.firstWhere((s) => s.id == sibling.id);
|
||||
final newSiblings = siblings.where((s) => s.id != sibling.id).toList()
|
||||
..insert(0, sourceInfo);
|
||||
|
||||
|
@ -17,6 +17,19 @@ final officialMusicRegex = RegExp(
|
||||
caseSensitive: false,
|
||||
);
|
||||
|
||||
class YoutubeSourceInfo extends SourceInfo {
|
||||
YoutubeSourceInfo({
|
||||
required super.id,
|
||||
required super.title,
|
||||
required super.artist,
|
||||
required super.thumbnail,
|
||||
required super.pageUrl,
|
||||
required super.duration,
|
||||
required super.artistUrl,
|
||||
required super.album,
|
||||
});
|
||||
}
|
||||
|
||||
class YoutubeSourcedTrack extends SourcedTrack {
|
||||
YoutubeSourcedTrack({
|
||||
required super.source,
|
||||
@ -64,7 +77,7 @@ class YoutubeSourcedTrack extends SourcedTrack {
|
||||
ref: ref,
|
||||
siblings: [],
|
||||
source: toSourceMap(manifest),
|
||||
sourceInfo: SourceInfo(
|
||||
sourceInfo: YoutubeSourceInfo(
|
||||
id: item.id.value,
|
||||
artist: item.author,
|
||||
artistUrl: "https://www.youtube.com/channel/${item.channelId}",
|
||||
@ -117,7 +130,7 @@ class YoutubeSourcedTrack extends SourcedTrack {
|
||||
}
|
||||
|
||||
final SiblingType sibling = (
|
||||
info: SourceInfo(
|
||||
info: YoutubeSourceInfo(
|
||||
id: item.id,
|
||||
artist: item.channelName,
|
||||
artistUrl: "https://www.youtube.com/channel/${item.channelId}",
|
||||
@ -217,12 +230,16 @@ class YoutubeSourcedTrack extends SourcedTrack {
|
||||
|
||||
@override
|
||||
Future<YoutubeSourcedTrack?> swapWithSibling(SourceInfo sibling) async {
|
||||
if (sibling.id == sourceInfo.id ||
|
||||
siblings.none((s) => s.id == sibling.id)) {
|
||||
if (sibling.id == sourceInfo.id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final newSourceInfo = siblings.firstWhere((s) => s.id == sibling.id);
|
||||
// a sibling source that was fetched from the search results
|
||||
final isStepSibling = siblings.none((s) => s.id == sibling.id);
|
||||
|
||||
final newSourceInfo = isStepSibling
|
||||
? sibling
|
||||
: siblings.firstWhere((s) => s.id == sibling.id);
|
||||
final newSiblings = siblings.where((s) => s.id != sibling.id).toList()
|
||||
..insert(0, sourceInfo);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user