From 94269fdae48a3a095dcfd3b7b38241dcc4d6a4b3 Mon Sep 17 00:00:00 2001 From: EKNr1 Date: Tue, 24 Dec 2024 17:22:30 +0100 Subject: [PATCH] Added a "Playlist" class. --- wobuzz/gui_communication/settings.py | 2 +- wobuzz/gui_communication/track_control.py | 14 ++-- wobuzz/player/player.py | 52 +++++---------- wobuzz/player/playlist.py | 80 +++++++++++++++++++++++ wobuzz/player/track.py | 21 ++++-- wobuzz/player/track_progress_timer.py | 2 +- wobuzz/ui/main_window.py | 1 - 7 files changed, 119 insertions(+), 53 deletions(-) create mode 100644 wobuzz/player/playlist.py diff --git a/wobuzz/gui_communication/settings.py b/wobuzz/gui_communication/settings.py index 5026aad..61f8975 100644 --- a/wobuzz/gui_communication/settings.py +++ b/wobuzz/gui_communication/settings.py @@ -13,7 +13,7 @@ class Settings: self.settings.visibilityChanged.connect(self.update_all) self.settings.save_button.pressed.connect(self.write_settings) - def update_all(self, settings_visible: bool=True): + def update_all(self, _=True): # ignore visible parameter passed by visibilityChanged event self.settings.file_settings.library_path_input.setText(self.app.settings.library_path) def update_settings(self, key, value): diff --git a/wobuzz/gui_communication/track_control.py b/wobuzz/gui_communication/track_control.py index 887f4bf..d6b96d9 100644 --- a/wobuzz/gui_communication/track_control.py +++ b/wobuzz/gui_communication/track_control.py @@ -37,24 +37,24 @@ class TrackControl: self.track_control.track_progress_slider.sliderReleased.connect(self.on_slider_release) def previous_track(self): - if len(self.app.player.current_playlist) > 0: + if self.app.player.current_playlist.has_tracks(): self.app.player.previous_track() def stop(self): - if len(self.app.player.current_playlist) > 0: + if self.app.player.current_playlist.has_tracks(): self.app.player.stop() def next_track(self): - if len(self.app.player.current_playlist) > 0: + if self.app.player.current_playlist.has_tracks(): self.app.player.next_track() def on_slider_release(self): - if len(self.app.player.current_playlist) > 0: + if self.app.player.current_playlist.has_tracks(): self.app.player.seek(self.track_control.track_progress_slider.value()) def on_track_start(self): if self.app.player.playing: - duration = self.app.player.current_track.duration + duration = self.app.player.current_playlist.current_track.duration self.track_control.track_progress_slider.setRange( 0, @@ -73,7 +73,7 @@ class TrackControl: if remaining == -1: remaining = self.app.player.track_progress.remaining_time - track_duration = self.app.player.current_track.duration + track_duration = self.app.player.current_playlist.current_track.duration progress = track_duration - remaining @@ -95,7 +95,7 @@ class TrackControl: self.app.player.pause() self.track_control.toggle_play_button.setIcon(self.play_icon) - elif len(self.app.player.current_playlist) > 0: # stopped but tracks in the current playlist + elif self.app.player.current_playlist.has_tracks(): # stopped but tracks in the current playlist self.app.player.start_playing() self.track_control.toggle_play_button.setIcon(self.pause_icon) diff --git a/wobuzz/player/player.py b/wobuzz/player/player.py index 715a65b..8fd2bf6 100644 --- a/wobuzz/player/player.py +++ b/wobuzz/player/player.py @@ -5,6 +5,7 @@ import os import pygame.mixer import pygame.event from .track import Track +from .playlist import Playlist from .track_progress_timer import TrackProgress @@ -18,14 +19,11 @@ class Player: self.track_progress = TrackProgress(self.app) + self.current_playlist = Playlist(self.app) + self.playing = False self.paused = False - self.current_playlist = [] - self.current_playlist_index = 0 - - self.current_track = None - self.current_sound = None self.current_sound_duration = 0 @@ -34,19 +32,11 @@ class Player: Load tracks from list of paths. """ - tracks = [] + self.current_playlist = Playlist(self.app) + self.current_playlist.load_from_paths(track_paths) - for track_path in track_paths: - if os.path.isfile(track_path): - tracks.append(Track(track_path, True)) - - self.current_playlist = tracks - self.current_playlist_index = 0 - - self.current_track = self.current_playlist[0] - - self.current_sound = self.current_track.sound - self.current_sound_duration = self.current_track.duration + self.current_sound = self.current_playlist.current_track.sound + self.current_sound_duration = self.current_playlist.current_track.duration def play(self): self.music_channel.play(self.current_sound) @@ -55,14 +45,8 @@ class Player: self.paused = False def track_finished(self): - - # if the last track wasn't the last in the playlist - if self.current_playlist_index < len(self.current_playlist) - 1: - self.current_playlist_index += 1 - - self.current_track = self.current_playlist[self.current_playlist_index] - self.current_sound = self.current_track.sound - self.current_sound_duration = self.current_track.duration + if not self.current_playlist.on_last_track(): + self.current_sound, self.current_sound_duration = self.current_playlist.next_track() self.play() self.track_progress.start() @@ -72,8 +56,8 @@ class Player: self.stop() def start_playing(self): - self.current_sound = self.current_track.sound - self.current_sound_duration = self.current_track.duration + self.current_sound = self.current_playlist.current_track.sound + self.current_sound_duration = self.current_playlist.current_track.duration self.play() self.track_progress.start() @@ -91,23 +75,19 @@ class Player: self.paused = False def next_track(self): - if self.current_playlist_index < len(self.current_playlist) - 1: # if the playing track isn't the last + if not self.current_playlist.on_last_track(): self.music_channel.stop() self.track_progress.stop() self.track_finished() def previous_track(self): - if self.current_playlist_index > 0: # if the current track isn't the first in the playlist + if not self.current_playlist.on_first_track(): self.music_channel.stop() - self.current_playlist_index -= 1 - self.current_track = self.current_playlist[self.current_playlist_index] + self.current_sound, self.current_sound_duration = self.current_playlist.previous_track() self.track_progress.stop() - self.current_sound = self.current_track.sound - self.current_sound_duration = self.current_track.duration - self.play() self.track_progress.start() @@ -116,7 +96,7 @@ class Player: def stop(self): self.music_channel.stop() self.track_progress.stop() - self.current_sound_duration = self.current_track.duration + self.current_sound_duration = self.current_playlist.current_track.duration self.playing = False self.paused = False @@ -125,7 +105,7 @@ class Player: self.music_channel.stop() self.track_progress.stop() - (self.current_sound, self.current_sound_duration) = self.current_track.remaining(position) + (self.current_sound, self.current_sound_duration) = self.current_playlist.current_track.remaining(position) self.play() self.track_progress.start() diff --git a/wobuzz/player/playlist.py b/wobuzz/player/playlist.py new file mode 100644 index 0000000..afb2f62 --- /dev/null +++ b/wobuzz/player/playlist.py @@ -0,0 +1,80 @@ +#!/usr/bin/python3 + +import os +from .track import Track + + +class Playlist: + def __init__(self, app): + self.app = app + self.tracks: list[Track] = [] + self.current_track_index = 0 + self.current_track: Track | None = None + + def load_from_paths(self, paths): + i = 0 + + while i < len(paths): + path = paths[i] + + if os.path.isfile(path): + self.tracks.append(Track(self.app, path, cache=i==0)) # first track is cached + + i += 1 + + self.current_track = self.tracks[0] # current track is the first track in the playlist + + def load_from_m3u(self, path): + file = open(path, "r") + m3u = file.read() + file.close() + + lines = m3u.split("\n") # m3u entries + + i = 0 + + while i < len(lines): + line = lines[i] + + if line.startswith("#") or line.startswith("http"): # filter out comments, extended m3u and urls + continue + + self.tracks.append(Track(self.app, line, cache=i==0)) # first track is cached + + i += 1 + + def load_from_wbz(self, path): + pass + + def has_tracks(self): + return len(self.tracks) > 0 + + def on_first_track(self): + return self.current_track_index == 0 + + def on_last_track(self): # if the current track is the last + return self.current_track_index == len(self.tracks) - 1 + + def next_track(self): + self.current_track_index += 1 + self.current_track = self.tracks[self.current_track_index] + + if not self.current_track.cached: # make sure the track is cached because else the player can't play it + self.current_track.cache() + self.current_track.cached = True + + return self.current_track.sound, self.current_track.duration + + def previous_track(self): + if self.on_first_track(): + return self.current_track, self.current_track.duration + + self.current_track_index -= 1 + self.current_track = self.tracks[self.current_track_index] + + if not self.current_track.cached: # make sure the track is cached because else the player can't play it + self.current_track.cache() + self.current_track.cached = True + + return self.current_track.sound, self.current_track.duration + diff --git a/wobuzz/player/track.py b/wobuzz/player/track.py index a9b17ce..310fe38 100644 --- a/wobuzz/player/track.py +++ b/wobuzz/player/track.py @@ -10,22 +10,28 @@ class Track: Class containing data for a track like file path, raw data... """ - def __init__(self, path: str, cache: bool=False): + def __init__(self, app, path: str, property_string: str=None, cache: bool=False): + self.app = app self.path = path + self.property_string = property_string self.cached = cache - (self.audio, self.sound, self.duration) = self.cache() if self.cached else (None, None, 0) + self.audio = None + self.sound = None + self.duration = 0 + + if self.cached: + self.cache() def cache(self): - audio = AudioSegment.from_mp3(self.path) + self.audio = AudioSegment.from_mp3(self.path) # audio = normalize(audio) - wav = audio.export(format="wav") + wav = self.audio.export(format="wav") - sound = Sound(wav) + self.sound = Sound(wav) - # return pygame.mixer.Sound object and track duration in milliseconds - return audio, sound, len(audio) + self.duration = len(self.audio) # track duration in milliseconds def remaining(self, position: int): remaining_audio = self.audio[position:] @@ -34,4 +40,5 @@ class Track: sound = Sound(wav) + # return the remaining part of the track's audio and the duration of the remaining part return sound, len(remaining_audio) diff --git a/wobuzz/player/track_progress_timer.py b/wobuzz/player/track_progress_timer.py index e11bffd..c8bfdf5 100644 --- a/wobuzz/player/track_progress_timer.py +++ b/wobuzz/player/track_progress_timer.py @@ -28,4 +28,4 @@ class TrackProgress: def stop(self): self.timer.stop() - self.remaining_time = self.app.player.current_track.duration + self.remaining_time = self.app.player.current_playlist.current_track.duration diff --git a/wobuzz/ui/main_window.py b/wobuzz/ui/main_window.py index dcbbab6..df38598 100644 --- a/wobuzz/ui/main_window.py +++ b/wobuzz/ui/main_window.py @@ -33,4 +33,3 @@ class MainWindow(QMainWindow): self.library_dock = LibraryDock() self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.library_dock) -