#!/usr/bin/python3 import threading import pygame.mixer import pygame.event from .playlist import Playlist from .track_progress_timer import TrackProgress class Player: def __init__(self, app): self.app = app pygame.mixer.init() self.mixer = pygame.mixer self.music_channel = self.mixer.Channel(0) self.track_progress = TrackProgress(self.app) self.history = Playlist(self.app, "History") self.current_playlist = Playlist(self.app, "None") self.playing = False self.paused = False self.current_sound = None self.current_sound_duration = 0 def play(self): self.music_channel.play(self.current_sound) self.playing = True self.paused = False self.app.gui.track_control.on_playstate_update() # cache next track so it immediately starts when the current track finishes self.cache_next_track() def track_finished(self): 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() self.history.append_track(self.current_playlist.current_track) last_track = self.history.h_last_track() self.app.gui.on_track_change(last_track, self.current_playlist.current_track) if self.app.settings.clear_track_cache: last_track.clear_cache() else: self.stop() def start_playing(self): 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() self.history.append_track(self.current_playlist.current_track) self.app.gui.on_track_change(self.history.h_last_track(), self.current_playlist.current_track) self.app.gui.track_control.on_playstate_update() def play_track_in_playlist(self, track_index): self.stop() if len(self.history.tracks) == 0: self.history.append_track(self.current_playlist.current_track) self.current_sound, self.current_sound_duration = self.current_playlist.set_track(track_index) self.play() self.track_progress.start() self.history.append_track(self.current_playlist.current_track) last_track = self.history.h_last_track() self.app.gui.on_track_change(last_track, self.current_playlist.current_track) if ( self.app.settings.clear_track_cache and not last_track is None and not last_track == self.current_playlist.current_track ): last_track.clear_cache() def pause(self): self.music_channel.pause() self.track_progress.pause() self.paused = True self.app.gui.track_control.on_playstate_update() def unpause(self): self.music_channel.unpause() self.track_progress.unpause() self.playing = True self.paused = False self.app.gui.track_control.on_playstate_update() def next_track(self): if not self.current_playlist.on_last_track(): self.music_channel.stop() self.track_progress.stop() self.track_finished() def previous_track(self): if not self.current_playlist.on_first_track(): self.music_channel.stop() self.current_sound, self.current_sound_duration = self.current_playlist.previous_track() self.track_progress.stop() self.play() self.track_progress.start() self.history.append_track(self.current_playlist.current_track) self.app.gui.on_track_change(self.history.h_last_track(), self.current_playlist.current_track) def stop(self): self.music_channel.stop() self.track_progress.stop() if not self.current_playlist.current_track is None: self.current_sound_duration = self.current_playlist.current_track.duration self.playing = False self.paused = False self.app.gui.track_control.on_playstate_update() def seek(self, position: int): self.music_channel.stop() self.track_progress.stop() (self.current_sound, self.current_sound_duration) = self.current_playlist.current_track.remaining(position) self.play() self.track_progress.start() def caching_thread_function(self): # cache the next track # (usually ran in separate thread) if self.current_playlist.on_last_track(): return track = self.current_playlist.tracks[self.current_playlist.current_track_index + 1] if not track.cached: self.app.gui.on_background_job_start("track_caching") track.cache() self.app.gui.on_background_job_stop("track_caching") def cache_next_track(self): # function that creates a thread which will cache the next track caching_thread = threading.Thread(target=self.caching_thread_function) caching_thread.start() def start_playlist(self, playlist): self.stop() self.current_sound, self.current_sound_duration = playlist.set_track(0) # first track self.current_playlist = playlist self.start_playing()