Added a "Playlist" class.

This commit is contained in:
The Wobbler 2024-12-24 17:22:30 +01:00
parent 1190059218
commit 94269fdae4
7 changed files with 119 additions and 53 deletions

View file

@ -13,7 +13,7 @@ class Settings:
self.settings.visibilityChanged.connect(self.update_all) self.settings.visibilityChanged.connect(self.update_all)
self.settings.save_button.pressed.connect(self.write_settings) 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) self.settings.file_settings.library_path_input.setText(self.app.settings.library_path)
def update_settings(self, key, value): def update_settings(self, key, value):

View file

@ -37,24 +37,24 @@ class TrackControl:
self.track_control.track_progress_slider.sliderReleased.connect(self.on_slider_release) self.track_control.track_progress_slider.sliderReleased.connect(self.on_slider_release)
def previous_track(self): 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() self.app.player.previous_track()
def stop(self): def stop(self):
if len(self.app.player.current_playlist) > 0: if self.app.player.current_playlist.has_tracks():
self.app.player.stop() self.app.player.stop()
def next_track(self): 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() self.app.player.next_track()
def on_slider_release(self): 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()) self.app.player.seek(self.track_control.track_progress_slider.value())
def on_track_start(self): def on_track_start(self):
if self.app.player.playing: 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( self.track_control.track_progress_slider.setRange(
0, 0,
@ -73,7 +73,7 @@ class TrackControl:
if remaining == -1: if remaining == -1:
remaining = self.app.player.track_progress.remaining_time 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 progress = track_duration - remaining
@ -95,7 +95,7 @@ class TrackControl:
self.app.player.pause() self.app.player.pause()
self.track_control.toggle_play_button.setIcon(self.play_icon) 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.app.player.start_playing()
self.track_control.toggle_play_button.setIcon(self.pause_icon) self.track_control.toggle_play_button.setIcon(self.pause_icon)

View file

@ -5,6 +5,7 @@ import os
import pygame.mixer import pygame.mixer
import pygame.event import pygame.event
from .track import Track from .track import Track
from .playlist import Playlist
from .track_progress_timer import TrackProgress from .track_progress_timer import TrackProgress
@ -18,14 +19,11 @@ class Player:
self.track_progress = TrackProgress(self.app) self.track_progress = TrackProgress(self.app)
self.current_playlist = Playlist(self.app)
self.playing = False self.playing = False
self.paused = False self.paused = False
self.current_playlist = []
self.current_playlist_index = 0
self.current_track = None
self.current_sound = None self.current_sound = None
self.current_sound_duration = 0 self.current_sound_duration = 0
@ -34,19 +32,11 @@ class Player:
Load tracks from list of paths. 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: self.current_sound = self.current_playlist.current_track.sound
if os.path.isfile(track_path): self.current_sound_duration = self.current_playlist.current_track.duration
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
def play(self): def play(self):
self.music_channel.play(self.current_sound) self.music_channel.play(self.current_sound)
@ -55,14 +45,8 @@ class Player:
self.paused = False self.paused = False
def track_finished(self): def track_finished(self):
if not self.current_playlist.on_last_track():
# if the last track wasn't the last in the playlist self.current_sound, self.current_sound_duration = self.current_playlist.next_track()
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
self.play() self.play()
self.track_progress.start() self.track_progress.start()
@ -72,8 +56,8 @@ class Player:
self.stop() self.stop()
def start_playing(self): def start_playing(self):
self.current_sound = self.current_track.sound self.current_sound = self.current_playlist.current_track.sound
self.current_sound_duration = self.current_track.duration self.current_sound_duration = self.current_playlist.current_track.duration
self.play() self.play()
self.track_progress.start() self.track_progress.start()
@ -91,23 +75,19 @@ class Player:
self.paused = False self.paused = False
def next_track(self): 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.music_channel.stop()
self.track_progress.stop() self.track_progress.stop()
self.track_finished() self.track_finished()
def previous_track(self): 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.music_channel.stop()
self.current_playlist_index -= 1 self.current_sound, self.current_sound_duration = self.current_playlist.previous_track()
self.current_track = self.current_playlist[self.current_playlist_index]
self.track_progress.stop() self.track_progress.stop()
self.current_sound = self.current_track.sound
self.current_sound_duration = self.current_track.duration
self.play() self.play()
self.track_progress.start() self.track_progress.start()
@ -116,7 +96,7 @@ class Player:
def stop(self): def stop(self):
self.music_channel.stop() self.music_channel.stop()
self.track_progress.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.playing = False
self.paused = False self.paused = False
@ -125,7 +105,7 @@ class Player:
self.music_channel.stop() self.music_channel.stop()
self.track_progress.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.play()
self.track_progress.start() self.track_progress.start()

80
wobuzz/player/playlist.py Normal file
View file

@ -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

View file

@ -10,22 +10,28 @@ class Track:
Class containing data for a track like file path, raw data... 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.path = path
self.property_string = property_string
self.cached = cache 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): def cache(self):
audio = AudioSegment.from_mp3(self.path) self.audio = AudioSegment.from_mp3(self.path)
# audio = normalize(audio) # 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 self.duration = len(self.audio) # track duration in milliseconds
return audio, sound, len(audio)
def remaining(self, position: int): def remaining(self, position: int):
remaining_audio = self.audio[position:] remaining_audio = self.audio[position:]
@ -34,4 +40,5 @@ class Track:
sound = Sound(wav) sound = Sound(wav)
# return the remaining part of the track's audio and the duration of the remaining part
return sound, len(remaining_audio) return sound, len(remaining_audio)

View file

@ -28,4 +28,4 @@ class TrackProgress:
def stop(self): def stop(self):
self.timer.stop() self.timer.stop()
self.remaining_time = self.app.player.current_track.duration self.remaining_time = self.app.player.current_playlist.current_track.duration

View file

@ -33,4 +33,3 @@ class MainWindow(QMainWindow):
self.library_dock = LibraryDock() self.library_dock = LibraryDock()
self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.library_dock) self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.library_dock)