Skip to content

Commit

Permalink
feat: Add JioSaavn as audio source (#881)
Browse files Browse the repository at this point in the history
* feat: implement new SourcedTrack for youtube and piped

* refactor: replace old spotube track with sourced track

* feat: add jiosaavn as audio source

* fix: download not working other than jiosaavn

* Merge branch 'dev' into feat-jiosaavn
  • Loading branch information
KRTirtho authored Nov 15, 2023
1 parent 57c03ad commit 14069cd
Show file tree
Hide file tree
Showing 45 changed files with 1,691 additions and 1,009 deletions.
36 changes: 18 additions & 18 deletions lib/components/library/user_downloads/download_item.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import 'package:spotify/spotify.dart';
import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/components/shared/image/universal_image.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/models/spotube_track.dart';
import 'package:spotube/provider/download_manager_provider.dart';
import 'package:spotube/services/download_manager/download_status.dart';
import 'package:spotube/services/sourced_track/sourced_track.dart';
import 'package:spotube/utils/type_conversion_utils.dart';

class DownloadItem extends HookConsumerWidget {
Expand All @@ -24,25 +24,25 @@ class DownloadItem extends HookConsumerWidget {
final taskStatus = useState<DownloadStatus?>(null);

useEffect(() {
if (track is! SpotubeTrack) return null;
final notifier = downloadManager.getStatusNotifier(track as SpotubeTrack);
if (track is! SourcedTrack) return null;
final notifier = downloadManager.getStatusNotifier(track as SourcedTrack);

taskStatus.value = notifier?.value;
listener() {

void listener() {
taskStatus.value = notifier?.value;
}

downloadManager
.getStatusNotifier(track as SpotubeTrack)
?.addListener(listener);
notifier?.addListener(listener);

return () {
downloadManager
.getStatusNotifier(track as SpotubeTrack)
?.removeListener(listener);
notifier?.removeListener(listener);
};
}, [track]);

final isQueryingSourceInfo =
taskStatus.value == null || track is! SourcedTrack;

return ListTile(
leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5),
Expand All @@ -63,7 +63,7 @@ class DownloadItem extends HookConsumerWidget {
track.artists ?? <Artist>[],
mainAxisAlignment: WrapAlignment.start,
),
trailing: taskStatus.value == null || track is! SpotubeTrack
trailing: isQueryingSourceInfo
? Text(
context.l10n.querying_info,
style: Theme.of(context).textTheme.labelMedium,
Expand All @@ -72,7 +72,7 @@ class DownloadItem extends HookConsumerWidget {
DownloadStatus.downloading => HookBuilder(builder: (context) {
final taskProgress = useListenable(useMemoized(
() => downloadManager
.getProgressNotifier(track as SpotubeTrack),
.getProgressNotifier(track as SourcedTrack),
[track],
));
return SizedBox(
Expand All @@ -86,13 +86,13 @@ class DownloadItem extends HookConsumerWidget {
IconButton(
icon: const Icon(SpotubeIcons.pause),
onPressed: () {
downloadManager.pause(track as SpotubeTrack);
downloadManager.pause(track as SourcedTrack);
}),
const SizedBox(width: 10),
IconButton(
icon: const Icon(SpotubeIcons.close),
onPressed: () {
downloadManager.cancel(track as SpotubeTrack);
downloadManager.cancel(track as SourcedTrack);
}),
],
),
Expand All @@ -104,13 +104,13 @@ class DownloadItem extends HookConsumerWidget {
IconButton(
icon: const Icon(SpotubeIcons.play),
onPressed: () {
downloadManager.resume(track as SpotubeTrack);
downloadManager.resume(track as SourcedTrack);
}),
const SizedBox(width: 10),
IconButton(
icon: const Icon(SpotubeIcons.close),
onPressed: () {
downloadManager.cancel(track as SpotubeTrack);
downloadManager.cancel(track as SourcedTrack);
})
],
),
Expand All @@ -126,7 +126,7 @@ class DownloadItem extends HookConsumerWidget {
IconButton(
icon: const Icon(SpotubeIcons.refresh),
onPressed: () {
downloadManager.retry(track as SpotubeTrack);
downloadManager.retry(track as SourcedTrack);
},
),
],
Expand All @@ -137,7 +137,7 @@ class DownloadItem extends HookConsumerWidget {
DownloadStatus.queued => IconButton(
icon: const Icon(SpotubeIcons.close),
onPressed: () {
downloadManager.removeFromQueue(track as SpotubeTrack);
downloadManager.removeFromQueue(track as SourcedTrack);
}),
},
);
Expand Down
57 changes: 36 additions & 21 deletions lib/components/player/sibling_tracks_sheet.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:ui';

import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
Expand All @@ -12,13 +13,13 @@ import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/extensions/duration.dart';
import 'package:spotube/hooks/utils/use_debounce.dart';
import 'package:spotube/models/matched_track.dart';
import 'package:spotube/models/spotube_track.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
import 'package:spotube/provider/youtube_provider.dart';
import 'package:spotube/services/youtube/youtube.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/youtube.dart';
import 'package:spotube/utils/service_utils.dart';
import 'package:spotube/utils/type_conversion_utils.dart';

Expand All @@ -35,7 +36,6 @@ class SiblingTracksSheet extends HookConsumerWidget {
final playlist = ref.watch(ProxyPlaylistNotifier.provider);
final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier);
final preferences = ref.watch(userPreferencesProvider);
final youtube = ref.watch(youtubeProvider);

final isSearching = useState(false);
final searchMode = useState(preferences.searchMode);
Expand All @@ -61,18 +61,31 @@ class SiblingTracksSheet extends HookConsumerWidget {

final searchRequest = useMemoized(() async {
if (searchTerm.trim().isEmpty) {
return <YoutubeVideoInfo>[];
return <SourceInfo>[];
}

return youtube.search(searchTerm.trim());
final results = await youtubeClient.search.search(searchTerm.trim());

return await Future.wait(
results.map(YoutubeVideoInfo.fromVideo).mapIndexed((i, video) async {
final siblingType = await YoutubeSourcedTrack.toSiblingType(i, video);
return siblingType.info;
}),
);
}, [
searchTerm,
searchMode.value,
]);

final siblings = playlist.isFetching == false
? (playlist.activeTrack as SpotubeTrack).siblings
: <YoutubeVideoInfo>[];
final siblings = useMemoized(
() => playlist.isFetching == false
? [
(playlist.activeTrack as SourcedTrack).sourceInfo,
...(playlist.activeTrack as SourcedTrack).siblings,
]
: <SourceInfo>[],
[playlist.isFetching, playlist.activeTrack],
);

final borderRadius = floating
? BorderRadius.circular(10)
Expand All @@ -82,38 +95,40 @@ class SiblingTracksSheet extends HookConsumerWidget {
);

useEffect(() {
if (playlist.activeTrack is SpotubeTrack &&
(playlist.activeTrack as SpotubeTrack).siblings.isEmpty) {
if (playlist.activeTrack is SourcedTrack &&
(playlist.activeTrack as SourcedTrack).siblings.isEmpty) {
playlistNotifier.populateSibling();
}
return null;
}, [playlist.activeTrack]);

final itemBuilder = useCallback(
(YoutubeVideoInfo video) {
(SourceInfo sourceInfo) {
return ListTile(
title: Text(video.title),
title: Text(sourceInfo.title),
leading: Padding(
padding: const EdgeInsets.all(8.0),
child: UniversalImage(
path: video.thumbnailUrl,
path: sourceInfo.thumbnail,
height: 60,
width: 60,
),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
trailing: Text(video.duration.toHumanReadableString()),
subtitle: Text(video.channelName),
trailing: Text(sourceInfo.duration.toHumanReadableString()),
subtitle: Text(sourceInfo.artist),
enabled: playlist.isFetching != true,
selected: playlist.isFetching != true &&
video.id == (playlist.activeTrack as SpotubeTrack).ytTrack.id,
sourceInfo.id ==
(playlist.activeTrack as SourcedTrack).sourceInfo.id,
selectedTileColor: theme.popupMenuTheme.color,
onTap: () {
if (playlist.isFetching == false &&
video.id != (playlist.activeTrack as SpotubeTrack).ytTrack.id) {
playlistNotifier.swapSibling(video);
sourceInfo.id !=
(playlist.activeTrack as SourcedTrack).sourceInfo.id) {
playlistNotifier.swapSibling(sourceInfo);
Navigator.of(context).pop();
}
},
Expand Down Expand Up @@ -175,7 +190,7 @@ class SiblingTracksSheet extends HookConsumerWidget {
},
)
else ...[
if (preferences.youtubeApiType == YoutubeApiType.piped)
if (preferences.audioSource == AudioSource.piped)
PopupMenuButton(
icon: const Icon(SpotubeIcons.filter, size: 18),
onSelected: (SearchMode mode) {
Expand Down
31 changes: 12 additions & 19 deletions lib/components/shared/dialogs/track_details_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import 'package:spotube/components/shared/links/hyper_link.dart';
import 'package:spotube/components/shared/links/link_text.dart';
import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/models/spotube_track.dart';
import 'package:spotube/utils/primitive_utils.dart';
import 'package:spotube/services/sourced_track/sourced_track.dart';
import 'package:spotube/utils/type_conversion_utils.dart';
import 'package:spotube/extensions/duration.dart';

Expand Down Expand Up @@ -37,42 +36,36 @@ class TrackDetailsDialog extends HookWidget {
overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Colors.blue),
),
context.l10n.duration: (track is SpotubeTrack
? (track as SpotubeTrack).ytTrack.duration
context.l10n.duration: (track is SourcedTrack
? (track as SourcedTrack).sourceInfo.duration
: track.duration!)
.toHumanReadableString(),
if (track.album!.releaseDate != null)
context.l10n.released: track.album!.releaseDate,
context.l10n.popularity: track.popularity?.toString() ?? "0",
};

final ytTrack =
track is SpotubeTrack ? (track as SpotubeTrack).ytTrack : null;
final sourceInfo =
track is SourcedTrack ? (track as SourcedTrack).sourceInfo : null;

final ytTracksDetailsMap = ytTrack == null
final ytTracksDetailsMap = sourceInfo == null
? {}
: {
context.l10n.youtube: Hyperlink(
"https://piped.video/watch?v=${ytTrack.id}",
"https://piped.video/watch?v=${ytTrack.id}",
"https://piped.video/watch?v=${sourceInfo.id}",
"https://piped.video/watch?v=${sourceInfo.id}",
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
context.l10n.channel: Hyperlink(
ytTrack.channelName,
"https://youtube.com${ytTrack.channelName}",
sourceInfo.artist,
sourceInfo.artistUrl,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
context.l10n.likes:
PrimitiveUtils.toReadableNumber(ytTrack.likes.toDouble()),
context.l10n.dislikes:
PrimitiveUtils.toReadableNumber(ytTrack.dislikes.toDouble()),
context.l10n.views:
PrimitiveUtils.toReadableNumber(ytTrack.views.toDouble()),
context.l10n.streamUrl: Hyperlink(
(track as SpotubeTrack).ytUri,
(track as SpotubeTrack).ytUri,
(track as SourcedTrack).url,
(track as SourcedTrack).url,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
Expand Down
2 changes: 1 addition & 1 deletion lib/components/shared/track_table/track_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ class TrackOptions extends HookConsumerWidget {
]);

final progressNotifier = useMemoized(() {
final spotubeTrack = downloadManager.mapToSpotubeTrack(track);
final spotubeTrack = downloadManager.mapToSourcedTrack(track);
if (spotubeTrack == null) return null;
return downloadManager.getProgressNotifier(spotubeTrack);
});
Expand Down
4 changes: 2 additions & 2 deletions lib/components/shared/track_table/tracks_table_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class TracksTableView extends HookConsumerWidget {
ref.watch(downloadManagerProvider);
final downloader = ref.watch(downloadManagerProvider.notifier);
final apiType =
ref.watch(userPreferencesProvider.select((s) => s.youtubeApiType));
ref.watch(userPreferencesProvider.select((s) => s.audioSource));
const tableHeadStyle = TextStyle(fontWeight: FontWeight.bold, fontSize: 16);

final selected = useState<List<String>>([]);
Expand Down Expand Up @@ -195,7 +195,7 @@ class TracksTableView extends HookConsumerWidget {
switch (action) {
case "download":
{
final confirmed = apiType == YoutubeApiType.piped ||
final confirmed = apiType == AudioSource.piped ||
await showDialog(
context: context,
builder: (context) {
Expand Down
14 changes: 8 additions & 6 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import 'package:spotube/hooks/configurators/use_disable_battery_optimizations.da
import 'package:spotube/hooks/configurators/use_get_storage_perms.dart';
import 'package:spotube/l10n/l10n.dart';
import 'package:spotube/models/logger.dart';
import 'package:spotube/models/matched_track.dart';
import 'package:spotube/models/skip_segment.dart';
import 'package:spotube/models/source_match.dart';
import 'package:spotube/provider/palette_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/services/audio_player/audio_player.dart';
Expand Down Expand Up @@ -71,16 +71,18 @@ Future<void> main(List<String> rawArgs) async {
cacheDir: hiveCacheDir,
connectivity: FlQueryInternetConnectionCheckerAdapter(),
);
Hive.registerAdapter(MatchedTrackAdapter());

Hive.registerAdapter(SkipSegmentAdapter());
Hive.registerAdapter(SearchModeAdapter());

Hive.registerAdapter(SourceMatchAdapter());
Hive.registerAdapter(SourceTypeAdapter());

// Cache versioning entities with Adapter
MatchedTrack.version = 'v1';
SourceMatch.version = 'v1';
SkipSegment.version = 'v1';

await Hive.openLazyBox<MatchedTrack>(
MatchedTrack.boxName,
await Hive.openLazyBox<SourceMatch>(
SourceMatch.boxName,
path: hiveCacheDir,
);
await Hive.openLazyBox(
Expand Down
Loading

0 comments on commit 14069cd

Please sign in to comment.