From 24f70b0d1eee8330200e993ef2f4aade4268b06a Mon Sep 17 00:00:00 2001 From: RaptaG <77157639+RaptaG@users.noreply.github.com> Date: Thu, 16 Mar 2023 16:06:21 +0200 Subject: [PATCH 1/4] Aaaaa --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f7031453..14ac5697 100644 --- a/README.md +++ b/README.md @@ -206,7 +206,7 @@ But why? You can learn about it [here](https://dev.to/krtirtho/choosing-open-sou - [Kingkor Roy Tirtho](https://github.com/KRTirtho) - The Founder, Maintainer and Lead Developer - [Owen Conor](https://github.com/owencz1998) - The Cool Discord Moderator - [Piotr Rogowski](https://github.com/karniv00l) - The MacOS Developer -- [RaptaG](https://github.com/raptag) - The Github Moderator and Community Manager +- [RaptaG](https://github.com/raptag) - The GitHub Moderator and Community Manager - [Rusty Apple](https://github.com/RustyApple) - The Mysterious Unknown Guy # Social platforms From b6cef34a3b62e1384241ba9d6ffa782bc96e900f Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 17 Mar 2023 16:15:35 +0600 Subject: [PATCH 2/4] chore: flathub yaml update script --- scripts/update_flathub_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update_flathub_version.py b/scripts/update_flathub_version.py index 8afae00e..27d6682d 100644 --- a/scripts/update_flathub_version.py +++ b/scripts/update_flathub_version.py @@ -15,7 +15,7 @@ with open(YAML_FILENAME, mode="r", encoding="utf-8") as input: # Requires the 2nd VERSION argument to be passed version = sys.argv[1:][0] -tar_url = f"https://github.com/{REPO}/releases/download/v{version}/Spotube-linux-x86_64.tar.xz" +tar_url = f"https://github.com/{REPO}/releases/download/v{version}/spotube-linux-{version}-x86_64.tar.xz" tar_sha256 = hashlib.sha256() print(f"Downloading file {tar_url} to generete sha256 sum") tar = requests.get(tar_url) From f7b12924dbba4c73f9bb682c64792d431a4933b9 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 19 Mar 2023 09:55:17 +0600 Subject: [PATCH 3/4] docs(README): add copycat take down notice --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 14ac5697..5b51d785 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,10 @@ + +# 🚨 DO NOT INSTALL Spotube FROM `PLAY STORE` +## There's an unofficial + `illegal` clone/copycat of Spotube available on `Play Store` that is full of malware, ads and trackers. To help take down this illegal copycat/clone, please FOLLOW THIS GUIDE : [wiki/Report-Spotube-Copycat-on-PlayStore](https://github.com/KRTirtho/spotube/wiki/Report-Spotube-Copycat-on-Playstore) + +Follow this issue thread to get updates on the progress of the legal action against the illegal copycat/clone: https://github.com/KRTirtho/spotube/issues/448 + +

Spotube Logo

From f160ec767d9941d33f83aba1752b28df629d0e10 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 24 Mar 2023 19:55:16 +0600 Subject: [PATCH 4/4] fix: android audio service and notification and fallback for lyrics when anonymous --- lib/pages/lyrics/lyrics.dart | 13 ++++ lib/pages/player/player.dart | 89 +++++++++++++---------- lib/pages/root/root_app.dart | 16 ++-- lib/provider/playlist_queue_provider.dart | 5 +- lib/services/mobile_audio_service.dart | 57 ++++++++++++--- 5 files changed, 120 insertions(+), 60 deletions(-) diff --git a/lib/pages/lyrics/lyrics.dart b/lib/pages/lyrics/lyrics.dart index ee61deef..3f1167a0 100644 --- a/lib/pages/lyrics/lyrics.dart +++ b/lib/pages/lyrics/lyrics.dart @@ -5,12 +5,14 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:platform_ui/platform_ui.dart'; import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/shared/fallbacks/anonymous_fallback.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/hooks/use_custom_status_bar_color.dart'; import 'package:spotube/hooks/use_palette_color.dart'; import 'package:spotube/pages/lyrics/plain_lyrics.dart'; import 'package:spotube/pages/lyrics/synced_lyrics.dart'; +import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/provider/playlist_queue_provider.dart'; import 'package:spotube/utils/platform.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; @@ -39,6 +41,17 @@ class LyricsPage extends HookConsumerWidget { noSetBGColor: true, ); + final auth = ref.watch(AuthenticationNotifier.provider); + + if (auth == null) { + return PlatformScaffold( + appBar: !kIsMacOS && platform != TargetPlatform.windows && !isModal + ? PageWindowTitleBar() + : null, + body: const AnonymousFallback(), + ); + } + Widget body = [ SyncedLyrics(palette: palette, isModal: isModal), PlainLyrics(palette: palette, isModal: isModal), diff --git a/lib/pages/player/player.dart b/lib/pages/player/player.dart index 202eb256..6ebdb99e 100644 --- a/lib/pages/player/player.dart +++ b/lib/pages/player/player.dart @@ -18,6 +18,7 @@ import 'package:spotube/hooks/use_custom_status_bar_color.dart'; import 'package:spotube/hooks/use_palette_color.dart'; import 'package:spotube/models/local_track.dart'; import 'package:spotube/pages/lyrics/lyrics.dart'; +import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/provider/playlist_queue_provider.dart'; import 'package:spotube/provider/user_preferences_provider.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; @@ -29,6 +30,7 @@ class PlayerView extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { + final auth = ref.watch(AuthenticationNotifier.provider); final currentTrack = ref.watch(PlaylistQueueNotifier.provider.select( (value) => value?.activeTrack, )); @@ -104,11 +106,13 @@ class PlayerView extends HookConsumerWidget { height: 30, child: SpotubeMarqueeText( text: currentTrack?.name ?? "Not playing", - style: - Theme.of(context).textTheme.headline5?.copyWith( - fontWeight: FontWeight.bold, - color: paletteColor.titleTextColor, - ), + style: Theme.of(context) + .textTheme + .headlineSmall + ?.copyWith( + fontWeight: FontWeight.bold, + color: paletteColor.titleTextColor, + ), isHovering: true, ), ), @@ -117,20 +121,24 @@ class PlayerView extends HookConsumerWidget { TypeConversionUtils.artists_X_String( currentTrack?.artists ?? [], ), - style: - Theme.of(context).textTheme.headline6!.copyWith( - fontWeight: FontWeight.bold, - color: paletteColor.bodyTextColor, - ), + style: Theme.of(context) + .textTheme + .titleLarge! + .copyWith( + fontWeight: FontWeight.bold, + color: paletteColor.bodyTextColor, + ), ) else TypeConversionUtils.artists_X_ClickableArtists( currentTrack?.artists ?? [], - textStyle: - Theme.of(context).textTheme.headline6!.copyWith( - fontWeight: FontWeight.bold, - color: paletteColor.bodyTextColor, - ), + textStyle: Theme.of(context) + .textTheme + .titleLarge! + .copyWith( + fontWeight: FontWeight.bold, + color: paletteColor.bodyTextColor, + ), onRouteChange: (route) { GoRouter.of(context).pop(); GoRouter.of(context).push(route); @@ -193,32 +201,33 @@ class PlayerView extends HookConsumerWidget { mainAxisAlignment: MainAxisAlignment.spaceEvenly, floatingQueue: false, extraActions: [ - PlatformIconButton( - tooltip: "Open Lyrics", - icon: const Icon(SpotubeIcons.music), - onPressed: () { - showModalBottomSheet( - context: context, - isDismissible: true, - enableDrag: true, - isScrollControlled: true, - backgroundColor: Colors.black38, - barrierColor: Colors.black12, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(20), - topRight: Radius.circular(20), + if (auth != null) + PlatformIconButton( + tooltip: "Open Lyrics", + icon: const Icon(SpotubeIcons.music), + onPressed: () { + showModalBottomSheet( + context: context, + isDismissible: true, + enableDrag: true, + isScrollControlled: true, + backgroundColor: Colors.black38, + barrierColor: Colors.black12, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), + topRight: Radius.circular(20), + ), ), - ), - constraints: BoxConstraints( - maxHeight: - MediaQuery.of(context).size.height * 0.8, - ), - builder: (context) => - const LyricsPage(isModal: true), - ); - }, - ) + constraints: BoxConstraints( + maxHeight: + MediaQuery.of(context).size.height * 0.8, + ), + builder: (context) => + const LyricsPage(isModal: true), + ); + }, + ) ], ), PlayerControls(iconColor: paletteColor.bodyTextColor), diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart index b696a5f3..f5b06672 100644 --- a/lib/pages/root/root_app.dart +++ b/lib/pages/root/root_app.dart @@ -10,15 +10,9 @@ import 'package:spotube/components/root/sidebar.dart'; import 'package:spotube/components/root/spotube_navigation_bar.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart'; import 'package:spotube/hooks/use_update_checker.dart'; +import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/provider/downloader_provider.dart'; -const rootPaths = { - 0: "/", - 1: "/search", - 2: "/library", - 3: "/lyrics", -}; - class RootApp extends HookConsumerWidget { final Widget child; const RootApp({ @@ -30,6 +24,14 @@ class RootApp extends HookConsumerWidget { Widget build(BuildContext context, ref) { final index = useState(0); final isMounted = useIsMounted(); + final auth = ref.watch(AuthenticationNotifier.provider); + + final rootPaths = [ + "/", + if (auth != null) "/search", + "/library", + if (auth != null) "/lyrics", + ].asMap(); final downloader = ref.watch(downloaderProvider); useEffect(() { diff --git a/lib/provider/playlist_queue_provider.dart b/lib/provider/playlist_queue_provider.dart index f63ff6d6..013406f9 100644 --- a/lib/provider/playlist_queue_provider.dart +++ b/lib/provider/playlist_queue_provider.dart @@ -152,7 +152,10 @@ class PlaylistQueueNotifier extends PersistedStateNotifier { void configure() async { if (kIsMobile || kIsMacOS) { mobileService = await AudioService.init( - builder: () => MobileAudioService(this), + builder: () => MobileAudioService( + this, + ref.read(VolumeProvider.provider.notifier), + ), config: const AudioServiceConfig( androidNotificationChannelId: 'com.krtirtho.Spotube', androidNotificationChannelName: 'Spotube', diff --git a/lib/services/mobile_audio_service.dart b/lib/services/mobile_audio_service.dart index c21f0c0b..ccc1d3d6 100644 --- a/lib/services/mobile_audio_service.dart +++ b/lib/services/mobile_audio_service.dart @@ -9,22 +9,28 @@ import 'package:spotube/services/audio_player.dart'; class MobileAudioService extends BaseAudioHandler { AudioSession? session; final PlaylistQueueNotifier playlistNotifier; + final VolumeProvider volumeNotifier; PlaylistQueue? get playlist => playlistNotifier.state; - MobileAudioService(this.playlistNotifier) { + MobileAudioService(this.playlistNotifier, this.volumeNotifier) { AudioSession.instance.then((s) { session = s; + session?.configure(const AudioSessionConfiguration.music()); s.interruptionEventStream.listen((event) async { - if (event.type != AudioInterruptionType.duck) { - await playlistNotifier.pause(); + switch (event.type) { + case AudioInterruptionType.duck: + await volumeNotifier.setVolume(event.begin ? 0.5 : 1.0); + break; + case AudioInterruptionType.pause: + case AudioInterruptionType.unknown: + await playlistNotifier.pause(); + break; } }); }); audioPlayer.onPlayerStateChanged.listen((state) async { - if (state != PlayerState.completed) { - playbackState.add(await _transformEvent()); - } + playbackState.add(await _transformEvent()); }); audioPlayer.onPositionChanged.listen((pos) async { @@ -46,6 +52,27 @@ class MobileAudioService extends BaseAudioHandler { @override Future seek(Duration position) => playlistNotifier.seek(position); + @override + Future setShuffleMode(AudioServiceShuffleMode shuffleMode) async { + await super.setShuffleMode(shuffleMode); + + if (shuffleMode == AudioServiceShuffleMode.all) { + playlistNotifier.shuffle(); + } else { + playlistNotifier.unshuffle(); + } + } + + @override + Future setRepeatMode(AudioServiceRepeatMode repeatMode) async { + super.setRepeatMode(repeatMode); + if (repeatMode == AudioServiceRepeatMode.all) { + playlistNotifier.loop(); + } else { + playlistNotifier.unloop(); + } + } + @override Future stop() async { await playlistNotifier.stop(); @@ -71,6 +98,7 @@ class MobileAudioService extends BaseAudioHandler { } Future _transformEvent() async { + final position = (await audioPlayer.getCurrentPosition()) ?? Duration.zero; return PlaybackState( controls: [ MediaControl.skipToPrevious, @@ -85,12 +113,17 @@ class MobileAudioService extends BaseAudioHandler { }, androidCompactActionIndices: const [0, 1, 2], playing: audioPlayer.state == PlayerState.playing, - updatePosition: (await audioPlayer.getCurrentPosition()) ?? Duration.zero, - processingState: audioPlayer.state == PlayerState.paused - ? AudioProcessingState.buffering - : audioPlayer.state == PlayerState.playing - ? AudioProcessingState.ready - : AudioProcessingState.idle, + updatePosition: position, + bufferedPosition: position, + shuffleMode: playlist?.isShuffled == true + ? AudioServiceShuffleMode.all + : AudioServiceShuffleMode.none, + repeatMode: playlist?.isLooping == true + ? AudioServiceRepeatMode.one + : AudioServiceRepeatMode.all, + processingState: playlist?.isLoading == true + ? AudioProcessingState.loading + : AudioProcessingState.ready, ); } }