musicmuster/app/music.py

111 lines
2.5 KiB
Python

import os
import threading
import vlc
from config import Config
from time import sleep
from log import DEBUG, ERROR
class Music:
"""
Manage the playing of music tracks
"""
def __init__(self):
self.fading = False
self.player = None
self.track_path = None
def fade(self):
"""
Fade the currently playing track.
Return the current track position.
The actual management of fading runs in its own thread so as not
to hold up the UI during the fade.
"""
DEBUG("fade()")
if not self.playing():
return None
self.fading = True
position = self.player.get_position()
thread = threading.Thread(target=self._fade)
thread.start()
return position
def _fade(self):
"""
Implementation of fading the current track in a separate thread.
"""
DEBUG("_fade()")
fade_time = Config.FADE_TIME / 1000
sleep_time = fade_time / Config.FADE_STEPS
step_percent = int((Config.VOLUME_VLC_MAX / Config.FADE_STEPS) * -1)
# Take a copy of current player to allow another track to be
# started without interfering here
p = self.player
for i in range(Config.VOLUME_VLC_MAX, 0, step_percent):
p.audio_set_volume(i)
sleep(sleep_time)
p.pause()
p.release()
self.fading = False
def get_playtime(self):
"Return elapsed play time"
return self.player.get_time()
def play(self, path):
"""
Start playing the track at path.
Log and return if path not found.
"""
DEBUG(f"play({path})")
if not os.access(path, os.R_OK):
ERROR(f"play({path}): path not found")
return
self.track_path = path
self.player = vlc.MediaPlayer(path)
self.player.audio_set_volume(Config.VOLUME_VLC_MAX)
self.player.play()
def playing(self):
"""
Return True if currently playing a track, else False
vlc.is_playing() returns True if track was faded out.
get_position seems more reliable.
"""
if self.player:
if self.player.get_position() > 0 and self.player.is_playing():
return True
# We take a copy of the player when fading, so we could be
# playing in a fade nowFalse
return self.fading
def set_position(self, ms):
"Set current play time in milliseconds from start"
return self.player.set_time(ms)