mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-14 16:25:16 +00:00
Merge branch 'master' into dev
This commit is contained in:
commit
7a0fd64cf9
@ -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
|
||||||
|
|
||||||
|
|
||||||
<p align="center"><img width="700" src="assets/spotube_banner.png" alt="Spotube Logo"></p>
|
<p align="center"><img width="700" src="assets/spotube_banner.png" alt="Spotube Logo"></p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
@ -206,7 +213,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
|
- [Kingkor Roy Tirtho](https://github.com/KRTirtho) - The Founder, Maintainer and Lead Developer
|
||||||
- [Owen Conor](https://github.com/owencz1998) - The Cool Discord Moderator
|
- [Owen Conor](https://github.com/owencz1998) - The Cool Discord Moderator
|
||||||
- [Piotr Rogowski](https://github.com/karniv00l) - The MacOS Developer
|
- [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
|
- [Rusty Apple](https://github.com/RustyApple) - The Mysterious Unknown Guy
|
||||||
|
|
||||||
# Social platforms
|
# Social platforms
|
||||||
|
@ -5,6 +5,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
import 'package:spotube/collections/spotube_icons.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/page_window_title_bar.dart';
|
||||||
import 'package:spotube/components/shared/image/universal_image.dart';
|
import 'package:spotube/components/shared/image/universal_image.dart';
|
||||||
import 'package:spotube/components/shared/themed_button_tab_bar.dart';
|
import 'package:spotube/components/shared/themed_button_tab_bar.dart';
|
||||||
@ -13,6 +14,7 @@ import 'package:spotube/hooks/use_custom_status_bar_color.dart';
|
|||||||
import 'package:spotube/hooks/use_palette_color.dart';
|
import 'package:spotube/hooks/use_palette_color.dart';
|
||||||
import 'package:spotube/pages/lyrics/plain_lyrics.dart';
|
import 'package:spotube/pages/lyrics/plain_lyrics.dart';
|
||||||
import 'package:spotube/pages/lyrics/synced_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/provider/playlist_queue_provider.dart';
|
||||||
import 'package:spotube/utils/platform.dart';
|
import 'package:spotube/utils/platform.dart';
|
||||||
import 'package:spotube/utils/type_conversion_utils.dart';
|
import 'package:spotube/utils/type_conversion_utils.dart';
|
||||||
@ -48,6 +50,15 @@ class LyricsPage extends HookConsumerWidget {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final auth = ref.watch(AuthenticationNotifier.provider);
|
||||||
|
|
||||||
|
if (auth == null) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: !kIsMacOS && !isModal ? const PageWindowTitleBar() : null,
|
||||||
|
body: const AnonymousFallback(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (isModal) {
|
if (isModal) {
|
||||||
return DefaultTabController(
|
return DefaultTabController(
|
||||||
length: 2,
|
length: 2,
|
||||||
|
@ -17,6 +17,7 @@ import 'package:spotube/hooks/use_custom_status_bar_color.dart';
|
|||||||
import 'package:spotube/hooks/use_palette_color.dart';
|
import 'package:spotube/hooks/use_palette_color.dart';
|
||||||
import 'package:spotube/models/local_track.dart';
|
import 'package:spotube/models/local_track.dart';
|
||||||
import 'package:spotube/pages/lyrics/lyrics.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/playlist_queue_provider.dart';
|
||||||
import 'package:spotube/provider/user_preferences_provider.dart';
|
import 'package:spotube/provider/user_preferences_provider.dart';
|
||||||
import 'package:spotube/utils/type_conversion_utils.dart';
|
import 'package:spotube/utils/type_conversion_utils.dart';
|
||||||
@ -29,6 +30,7 @@ class PlayerView extends HookConsumerWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
final auth = ref.watch(AuthenticationNotifier.provider);
|
||||||
final currentTrack = ref.watch(PlaylistQueueNotifier.provider.select(
|
final currentTrack = ref.watch(PlaylistQueueNotifier.provider.select(
|
||||||
(value) => value?.activeTrack,
|
(value) => value?.activeTrack,
|
||||||
));
|
));
|
||||||
@ -180,6 +182,7 @@ class PlayerView extends HookConsumerWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
floatingQueue: false,
|
floatingQueue: false,
|
||||||
extraActions: [
|
extraActions: [
|
||||||
|
if (auth != null)
|
||||||
IconButton(
|
IconButton(
|
||||||
tooltip: "Open Lyrics",
|
tooltip: "Open Lyrics",
|
||||||
icon: const Icon(SpotubeIcons.music),
|
icon: const Icon(SpotubeIcons.music),
|
||||||
|
@ -8,6 +8,7 @@ import 'package:spotube/components/root/bottom_player.dart';
|
|||||||
import 'package:spotube/components/root/sidebar.dart';
|
import 'package:spotube/components/root/sidebar.dart';
|
||||||
import 'package:spotube/components/root/spotube_navigation_bar.dart';
|
import 'package:spotube/components/root/spotube_navigation_bar.dart';
|
||||||
import 'package:spotube/hooks/use_update_checker.dart';
|
import 'package:spotube/hooks/use_update_checker.dart';
|
||||||
|
import 'package:spotube/provider/authentication_provider.dart';
|
||||||
import 'package:spotube/provider/downloader_provider.dart';
|
import 'package:spotube/provider/downloader_provider.dart';
|
||||||
|
|
||||||
const rootPaths = {
|
const rootPaths = {
|
||||||
@ -28,6 +29,7 @@ class RootApp extends HookConsumerWidget {
|
|||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
final index = useState(0);
|
final index = useState(0);
|
||||||
final isMounted = useIsMounted();
|
final isMounted = useIsMounted();
|
||||||
|
final auth = ref.watch(AuthenticationNotifier.provider);
|
||||||
|
|
||||||
final downloader = ref.watch(downloaderProvider);
|
final downloader = ref.watch(downloaderProvider);
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
|
@ -152,7 +152,10 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
|
|||||||
void configure() async {
|
void configure() async {
|
||||||
if (kIsMobile || kIsMacOS) {
|
if (kIsMobile || kIsMacOS) {
|
||||||
mobileService = await AudioService.init(
|
mobileService = await AudioService.init(
|
||||||
builder: () => MobileAudioService(this),
|
builder: () => MobileAudioService(
|
||||||
|
this,
|
||||||
|
ref.read(VolumeProvider.provider.notifier),
|
||||||
|
),
|
||||||
config: const AudioServiceConfig(
|
config: const AudioServiceConfig(
|
||||||
androidNotificationChannelId: 'com.krtirtho.Spotube',
|
androidNotificationChannelId: 'com.krtirtho.Spotube',
|
||||||
androidNotificationChannelName: 'Spotube',
|
androidNotificationChannelName: 'Spotube',
|
||||||
|
@ -9,22 +9,28 @@ import 'package:spotube/services/audio_player.dart';
|
|||||||
class MobileAudioService extends BaseAudioHandler {
|
class MobileAudioService extends BaseAudioHandler {
|
||||||
AudioSession? session;
|
AudioSession? session;
|
||||||
final PlaylistQueueNotifier playlistNotifier;
|
final PlaylistQueueNotifier playlistNotifier;
|
||||||
|
final VolumeProvider volumeNotifier;
|
||||||
|
|
||||||
PlaylistQueue? get playlist => playlistNotifier.state;
|
PlaylistQueue? get playlist => playlistNotifier.state;
|
||||||
|
|
||||||
MobileAudioService(this.playlistNotifier) {
|
MobileAudioService(this.playlistNotifier, this.volumeNotifier) {
|
||||||
AudioSession.instance.then((s) {
|
AudioSession.instance.then((s) {
|
||||||
session = s;
|
session = s;
|
||||||
|
session?.configure(const AudioSessionConfiguration.music());
|
||||||
s.interruptionEventStream.listen((event) async {
|
s.interruptionEventStream.listen((event) async {
|
||||||
if (event.type != AudioInterruptionType.duck) {
|
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();
|
await playlistNotifier.pause();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
audioPlayer.onPlayerStateChanged.listen((state) async {
|
audioPlayer.onPlayerStateChanged.listen((state) async {
|
||||||
if (state != PlayerState.completed) {
|
|
||||||
playbackState.add(await _transformEvent());
|
playbackState.add(await _transformEvent());
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
audioPlayer.onPositionChanged.listen((pos) async {
|
audioPlayer.onPositionChanged.listen((pos) async {
|
||||||
@ -46,6 +52,27 @@ class MobileAudioService extends BaseAudioHandler {
|
|||||||
@override
|
@override
|
||||||
Future<void> seek(Duration position) => playlistNotifier.seek(position);
|
Future<void> seek(Duration position) => playlistNotifier.seek(position);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> setShuffleMode(AudioServiceShuffleMode shuffleMode) async {
|
||||||
|
await super.setShuffleMode(shuffleMode);
|
||||||
|
|
||||||
|
if (shuffleMode == AudioServiceShuffleMode.all) {
|
||||||
|
playlistNotifier.shuffle();
|
||||||
|
} else {
|
||||||
|
playlistNotifier.unshuffle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> setRepeatMode(AudioServiceRepeatMode repeatMode) async {
|
||||||
|
super.setRepeatMode(repeatMode);
|
||||||
|
if (repeatMode == AudioServiceRepeatMode.all) {
|
||||||
|
playlistNotifier.loop();
|
||||||
|
} else {
|
||||||
|
playlistNotifier.unloop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> stop() async {
|
Future<void> stop() async {
|
||||||
await playlistNotifier.stop();
|
await playlistNotifier.stop();
|
||||||
@ -71,6 +98,7 @@ class MobileAudioService extends BaseAudioHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<PlaybackState> _transformEvent() async {
|
Future<PlaybackState> _transformEvent() async {
|
||||||
|
final position = (await audioPlayer.getCurrentPosition()) ?? Duration.zero;
|
||||||
return PlaybackState(
|
return PlaybackState(
|
||||||
controls: [
|
controls: [
|
||||||
MediaControl.skipToPrevious,
|
MediaControl.skipToPrevious,
|
||||||
@ -85,12 +113,17 @@ class MobileAudioService extends BaseAudioHandler {
|
|||||||
},
|
},
|
||||||
androidCompactActionIndices: const [0, 1, 2],
|
androidCompactActionIndices: const [0, 1, 2],
|
||||||
playing: audioPlayer.state == PlayerState.playing,
|
playing: audioPlayer.state == PlayerState.playing,
|
||||||
updatePosition: (await audioPlayer.getCurrentPosition()) ?? Duration.zero,
|
updatePosition: position,
|
||||||
processingState: audioPlayer.state == PlayerState.paused
|
bufferedPosition: position,
|
||||||
? AudioProcessingState.buffering
|
shuffleMode: playlist?.isShuffled == true
|
||||||
: audioPlayer.state == PlayerState.playing
|
? AudioServiceShuffleMode.all
|
||||||
? AudioProcessingState.ready
|
: AudioServiceShuffleMode.none,
|
||||||
: AudioProcessingState.idle,
|
repeatMode: playlist?.isLooping == true
|
||||||
|
? AudioServiceRepeatMode.one
|
||||||
|
: AudioServiceRepeatMode.all,
|
||||||
|
processingState: playlist?.isLoading == true
|
||||||
|
? AudioProcessingState.loading
|
||||||
|
: AudioProcessingState.ready,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ with open(YAML_FILENAME, mode="r", encoding="utf-8") as input:
|
|||||||
# Requires the 2nd VERSION argument to be passed
|
# Requires the 2nd VERSION argument to be passed
|
||||||
version = sys.argv[1:][0]
|
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()
|
tar_sha256 = hashlib.sha256()
|
||||||
print(f"Downloading file {tar_url} to generete sha256 sum")
|
print(f"Downloading file {tar_url} to generete sha256 sum")
|
||||||
tar = requests.get(tar_url)
|
tar = requests.get(tar_url)
|
||||||
|
Loading…
Reference in New Issue
Block a user