mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-12 23:45:18 +00:00
activate log level in release with env var
Check if the track already exists in the disk while download button is pressed
This commit is contained in:
parent
6111e8c291
commit
0036df6e12
@ -24,7 +24,7 @@ class _ArtistAlbumViewState extends ConsumerState<ArtistAlbumView> {
|
||||
final PagingController<int, Album> _pagingController =
|
||||
PagingController<int, Album>(firstPageKey: 0);
|
||||
|
||||
final logger = createLogger(ArtistAlbumView);
|
||||
final logger = getLogger(ArtistAlbumView);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:marquee/marquee.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/components/Shared/SpotubeWidgets.dart';
|
||||
import 'package:spotube/components/Shared/SpotubeMarqueeText.dart';
|
||||
|
||||
class ArtistCard extends StatelessWidget {
|
||||
final Artist artist;
|
||||
|
@ -21,7 +21,7 @@ import 'package:spotube/provider/SpotifyDI.dart';
|
||||
|
||||
class ArtistProfile extends HookConsumerWidget {
|
||||
final String artistId;
|
||||
final logger = createLogger(ArtistProfile);
|
||||
final logger = getLogger(ArtistProfile);
|
||||
ArtistProfile(this.artistId, {Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
|
@ -17,7 +17,7 @@ class CategoryCard extends HookWidget {
|
||||
this.playlists,
|
||||
}) : super(key: key);
|
||||
|
||||
final logger = createLogger(CategoryCard);
|
||||
final logger = getLogger(CategoryCard);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -42,7 +42,7 @@ List<String> spotifyScopes = [
|
||||
|
||||
class Home extends HookConsumerWidget {
|
||||
Home({Key? key}) : super(key: key);
|
||||
final logger = createLogger(Home);
|
||||
final logger = getLogger(Home);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, ref) {
|
||||
|
@ -16,7 +16,7 @@ class UserArtists extends ConsumerStatefulWidget {
|
||||
class _UserArtistsState extends ConsumerState<UserArtists> {
|
||||
final PagingController<String, Artist> _pagingController =
|
||||
PagingController(firstPageKey: "");
|
||||
final logger = createLogger(UserArtists);
|
||||
final logger = getLogger(UserArtists);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -14,7 +14,7 @@ import 'package:spotube/provider/UserPreferences.dart';
|
||||
|
||||
class Login extends HookConsumerWidget {
|
||||
Login({Key? key}) : super(key: key);
|
||||
final log = createLogger(Login);
|
||||
final log = getLogger(Login);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, ref) {
|
||||
|
@ -19,7 +19,7 @@ import 'package:flutter/material.dart';
|
||||
class Player extends HookConsumerWidget {
|
||||
Player({Key? key}) : super(key: key);
|
||||
|
||||
final logger = createLogger(Player);
|
||||
final logger = getLogger(Player);
|
||||
@override
|
||||
Widget build(BuildContext context, ref) {
|
||||
Playback playback = ref.watch(playbackProvider);
|
||||
|
@ -15,7 +15,7 @@ class PlayerActions extends HookConsumerWidget {
|
||||
this.mainAxisAlignment = MainAxisAlignment.center,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
final logger = createLogger(PlayerActions);
|
||||
final logger = getLogger(PlayerActions);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, ref) {
|
||||
|
@ -14,7 +14,7 @@ class PlayerControls extends HookConsumerWidget {
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
final logger = createLogger(PlayerControls);
|
||||
final logger = getLogger(PlayerControls);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, ref) {
|
||||
@ -47,7 +47,9 @@ class PlayerControls extends HookConsumerWidget {
|
||||
child: Column(
|
||||
children: [
|
||||
StreamBuilder<Duration>(
|
||||
stream: player.positionStream,
|
||||
stream: player.positionStream.isBroadcast
|
||||
? player.positionStream
|
||||
: player.positionStream.asBroadcastStream(),
|
||||
builder: (context, snapshot) {
|
||||
final totalMinutes =
|
||||
zeroPadNumStr(duration.inMinutes.remainder(60));
|
||||
|
@ -12,7 +12,7 @@ import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/provider/SpotifyDI.dart';
|
||||
|
||||
class PlaylistView extends HookConsumerWidget {
|
||||
final logger = createLogger(PlaylistView);
|
||||
final logger = getLogger(PlaylistView);
|
||||
final PlaylistSimple playlist;
|
||||
PlaylistView(this.playlist, {Key? key}) : super(key: key);
|
||||
|
||||
|
@ -17,10 +17,10 @@ class DownloadTrackButton extends HookWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var status = useState<TrackStatus>(TrackStatus.idle);
|
||||
final status = useState<TrackStatus>(TrackStatus.idle);
|
||||
YoutubeExplode yt = useMemoized(() => YoutubeExplode());
|
||||
|
||||
var _downloadTrack = useCallback(() async {
|
||||
final _downloadTrack = useCallback(() async {
|
||||
if (track == null) return;
|
||||
if ((Platform.isAndroid || Platform.isIOS) &&
|
||||
!await Permission.storage.isGranted &&
|
||||
@ -38,6 +38,43 @@ class DownloadTrackButton extends HookWidget {
|
||||
StreamManifest manifest =
|
||||
await yt.videos.streamsClient.getManifest(track?.href);
|
||||
|
||||
String downloadFolder = path.join(
|
||||
Platform.isAndroid
|
||||
? "/storage/emulated/0/Download"
|
||||
: (await path_provider.getDownloadsDirectory())!.path,
|
||||
"Spotube");
|
||||
String fileName =
|
||||
"${track?.name} - ${artistsToString<Artist>(track?.artists ?? [])}.mp3";
|
||||
File outputFile = File(path.join(downloadFolder, fileName));
|
||||
|
||||
if (await outputFile.exists()) {
|
||||
final shouldReplace = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: const Text("Track Already Exists"),
|
||||
content: const Text(
|
||||
"Do you want to replace the already downloaded track?"),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: const Text("No"),
|
||||
onPressed: () {
|
||||
Navigator.pop(context, false);
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: const Text("Yes"),
|
||||
onPressed: () {
|
||||
Navigator.pop(context, true);
|
||||
},
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
if (shouldReplace != true) return;
|
||||
}
|
||||
|
||||
final audioStream = yt.videos.streamsClient
|
||||
.get(
|
||||
manifest.audioOnly
|
||||
@ -65,16 +102,7 @@ class DownloadTrackButton extends HookWidget {
|
||||
},
|
||||
);
|
||||
|
||||
String downloadFolder = path.join(
|
||||
Platform.isAndroid
|
||||
? "/storage/emulated/0/Download"
|
||||
: (await path_provider.getDownloadsDirectory())!.path,
|
||||
"Spotube");
|
||||
String fileName =
|
||||
"${track?.name} - ${artistsToString<Artist>(track?.artists ?? [])}.mp3";
|
||||
File outputFile = File(path.join(downloadFolder, fileName));
|
||||
if (!outputFile.existsSync()) {
|
||||
outputFile.createSync(recursive: true);
|
||||
if (!outputFile.existsSync()) outputFile.createSync(recursive: true);
|
||||
IOSink outputFileStream = outputFile.openWrite();
|
||||
await audioStream.pipe(outputFileStream);
|
||||
await outputFileStream.flush();
|
||||
@ -92,7 +120,6 @@ class DownloadTrackButton extends HookWidget {
|
||||
}
|
||||
return statusCb.cancel();
|
||||
});
|
||||
}
|
||||
}, [track, status, yt]);
|
||||
|
||||
useEffect(() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:spotube/components/Shared/SpotubeWidgets.dart';
|
||||
import 'package:spotube/components/Shared/SpotubeMarqueeText.dart';
|
||||
|
||||
class PlaybuttonCard extends StatelessWidget {
|
||||
final void Function()? onTap;
|
||||
|
@ -6,7 +6,7 @@ import 'package:spotube/helpers/get-random-element.dart';
|
||||
import 'package:spotube/models/Logger.dart';
|
||||
import 'package:spotube/models/generated_secrets.dart';
|
||||
|
||||
final logger = createLogger("GetLyrics");
|
||||
final logger = getLogger("GetLyrics");
|
||||
|
||||
String getTitle(String title, String artist) {
|
||||
return "$title $artist"
|
||||
|
@ -7,7 +7,7 @@ import 'package:spotube/models/Logger.dart';
|
||||
import 'package:spotube/provider/Auth.dart';
|
||||
|
||||
const redirectUri = "http://localhost:4304/auth/spotify/callback";
|
||||
final logger = createLogger("OAuthLogin");
|
||||
final logger = getLogger("OAuthLogin");
|
||||
|
||||
Future<void> oauthLogin(Auth auth,
|
||||
{required String clientId, required String clientSecret}) async {
|
||||
|
@ -3,7 +3,7 @@ import 'dart:io';
|
||||
import 'package:spotube/models/Logger.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
final logger = createLogger("ServerIPC");
|
||||
final logger = getLogger("ServerIPC");
|
||||
|
||||
Future<String?> connectIpc(String authUri, String redirectUri) async {
|
||||
try {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:spotube/models/Logger.dart';
|
||||
import 'package:spotube/provider/Playback.dart';
|
||||
|
||||
final logger = createLogger("PlaybackHook");
|
||||
final logger = getLogger("PlaybackHook");
|
||||
|
||||
Future<void> Function() useNextTrack(Playback playback) {
|
||||
return () async {
|
||||
|
@ -39,7 +39,7 @@ void main() async {
|
||||
|
||||
class MyApp extends HookConsumerWidget {
|
||||
final GoRouter _router = createGoRouter();
|
||||
final logger = createLogger(MyApp);
|
||||
final logger = getLogger(MyApp);
|
||||
|
||||
MyApp({Key? key}) : super(key: key);
|
||||
@override
|
||||
|
@ -4,12 +4,16 @@ import 'package:logger/logger.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
_SpotubeLogger createLogger<T>(T owner) =>
|
||||
_SpotubeLogger(owner is String ? owner : owner.toString());
|
||||
final _loggerFactory = _SpotubeLogger();
|
||||
|
||||
_SpotubeLogger getLogger<T>(T owner) {
|
||||
_loggerFactory.owner = owner is String ? owner : owner.toString();
|
||||
return _loggerFactory;
|
||||
}
|
||||
|
||||
class _SpotubeLogger extends Logger {
|
||||
String owner;
|
||||
_SpotubeLogger(this.owner);
|
||||
String? owner;
|
||||
_SpotubeLogger([this.owner]) : super(filter: _SpotubeLogFilter());
|
||||
|
||||
@override
|
||||
void log(Level level, message, [error, StackTrace? stackTrace]) {
|
||||
@ -23,3 +27,16 @@ class _SpotubeLogger extends Logger {
|
||||
super.log(level, "[$owner] $message", error, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
class _SpotubeLogFilter extends DevelopmentFilter {
|
||||
@override
|
||||
bool shouldLog(LogEvent event) {
|
||||
final env = Platform.environment;
|
||||
if ((env["DEBUG"] == "true" && event.level == Level.debug) ||
|
||||
(env["VERBOSE"] == "true" && event.level == Level.verbose) ||
|
||||
(env["ERROR"] == "true" && event.level == Level.error)) {
|
||||
return true;
|
||||
}
|
||||
return super.shouldLog(event);
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,8 @@ class CurrentPlaylist {
|
||||
}
|
||||
|
||||
class Playback extends ChangeNotifier {
|
||||
final _logger = createLogger(Playback);
|
||||
AudioSource? _currentAudioSource;
|
||||
final _logger = getLogger(Playback);
|
||||
CurrentPlaylist? _currentPlaylist;
|
||||
Track? _currentTrack;
|
||||
|
||||
@ -67,6 +68,7 @@ class Playback extends ChangeNotifier {
|
||||
StreamSubscription<Duration?>? _durationStreamListener;
|
||||
StreamSubscription<ProcessingState>? _processingStateStreamListener;
|
||||
StreamSubscription<AudioInterruptionEvent>? _audioInterruptionEventListener;
|
||||
StreamSubscription<Duration>? _positionStreamListener;
|
||||
|
||||
AudioPlayer player;
|
||||
YoutubeExplode youtube;
|
||||
@ -97,15 +99,17 @@ class Playback extends ChangeNotifier {
|
||||
if (player.playing) await player.pause();
|
||||
await player.play();
|
||||
}
|
||||
|
||||
_duration = duration;
|
||||
_callAllDurationListeners(duration);
|
||||
// for avoiding unnecessary re-renders in other components that
|
||||
// doesn't need duration
|
||||
_callAllDurationListeners(duration);
|
||||
}
|
||||
});
|
||||
|
||||
_processingStateStreamListener =
|
||||
player.processingStateStream.listen((event) async {
|
||||
_logger.v("[Processing State Change] $event");
|
||||
try {
|
||||
if (event != ProcessingState.completed) return;
|
||||
if (_currentTrack?.id != null) {
|
||||
@ -122,6 +126,11 @@ class Playback extends ChangeNotifier {
|
||||
}
|
||||
});
|
||||
|
||||
_positionStreamListener = (player.positionStream.isBroadcast
|
||||
? player.positionStream
|
||||
: player.positionStream.asBroadcastStream())
|
||||
.listen((position) async {});
|
||||
|
||||
AudioSession.instance.then((session) async {
|
||||
_audioSession = session;
|
||||
await session.configure(const AudioSessionConfiguration.music());
|
||||
@ -159,16 +168,19 @@ class Playback extends ChangeNotifier {
|
||||
}
|
||||
|
||||
set setCurrentTrack(Track track) {
|
||||
_logger.v("[Setting Current Track] ${track.name} - ${track.id}");
|
||||
_currentTrack = track;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
set setCurrentPlaylist(CurrentPlaylist playlist) {
|
||||
_logger.v("[Current Playlist Changed] ${playlist.name} - ${playlist.id}");
|
||||
_currentPlaylist = playlist;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
_logger.v("Playback Reset");
|
||||
_isPlaying = false;
|
||||
_duration = null;
|
||||
_callAllDurationListeners(null);
|
||||
@ -200,11 +212,13 @@ class Playback extends ChangeNotifier {
|
||||
_durationStreamListener?.cancel();
|
||||
_playingStreamListener?.cancel();
|
||||
_audioInterruptionEventListener?.cancel();
|
||||
_positionStreamListener?.cancel();
|
||||
_audioSession?.setActive(false);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void movePlaylistPositionBy(int pos) {
|
||||
_logger.v("[Playlist Position Move] $pos");
|
||||
if (_currentTrack != null && _currentPlaylist != null) {
|
||||
int index = _currentPlaylist!.trackIds.indexOf(_currentTrack!.id!) + pos;
|
||||
|
||||
@ -228,6 +242,7 @@ class Playback extends ChangeNotifier {
|
||||
}
|
||||
|
||||
Future<void> startPlaying([Track? track]) async {
|
||||
_logger.v("[Track Playing] ${track?.name} - ${track?.id}");
|
||||
try {
|
||||
// the track is already playing so no need to change that
|
||||
if (track != null && track.id == _currentTrack?.id) return;
|
||||
@ -242,9 +257,10 @@ class Playback extends ChangeNotifier {
|
||||
artUri: Uri.parse(imageToUrlString(track.album?.images)),
|
||||
);
|
||||
if (parsedUri != null && parsedUri.hasAbsolutePath) {
|
||||
_currentAudioSource = AudioSource.uri(parsedUri, tag: tag);
|
||||
await player
|
||||
.setAudioSource(
|
||||
AudioSource.uri(parsedUri, tag: tag),
|
||||
_currentAudioSource!,
|
||||
preload: true,
|
||||
)
|
||||
.then((value) async {
|
||||
@ -256,9 +272,11 @@ class Playback extends ChangeNotifier {
|
||||
}
|
||||
final ytTrack = await toYoutubeTrack(youtube, track);
|
||||
if (setTrackUriById(track.id!, ytTrack.uri!)) {
|
||||
_currentAudioSource =
|
||||
AudioSource.uri(Uri.parse(ytTrack.uri!), tag: tag);
|
||||
await player
|
||||
.setAudioSource(
|
||||
AudioSource.uri(Uri.parse(ytTrack.uri!), tag: tag),
|
||||
_currentAudioSource!,
|
||||
preload: true,
|
||||
)
|
||||
.then((value) {
|
||||
|
@ -23,7 +23,7 @@ class UserPreferences extends ChangeNotifier {
|
||||
onInit();
|
||||
}
|
||||
|
||||
final logger = createLogger(UserPreferences);
|
||||
final logger = getLogger(UserPreferences);
|
||||
|
||||
Future<HotKey?> _getHotKeyFromLocalStorage(
|
||||
SharedPreferences preferences, String key) async {
|
||||
|
Loading…
Reference in New Issue
Block a user