Merge changes from master

This commit is contained in:
Keith Edmunds 2024-05-22 15:45:21 +01:00
parent fc4129994b
commit 71e76e02d1
5 changed files with 94 additions and 77 deletions

View File

@ -199,8 +199,12 @@ class PlaylistTrack:
)
# Calculate time fade_graph should start updating
update_graph_at_ms = max(0, self.fade_at - Config.FADE_CURVE_MS_BEFORE_FADE - 1)
self.fade_graph_start_updates = now + dt.timedelta(milliseconds=update_graph_at_ms)
update_graph_at_ms = max(
0, self.fade_at - Config.FADE_CURVE_MS_BEFORE_FADE - 1
)
self.fade_graph_start_updates = now + dt.timedelta(
milliseconds=update_graph_at_ms
)
@dataclass

View File

@ -84,7 +84,7 @@ class ReplaceFilesDialog(QDialog):
continue
rf = TrackFileData(new_file_path=new_file_path)
rf.tags = get_tags(new_file_path)
if not rf.tags['title'] or not rf.tags['artist']:
if not rf.tags["title"] or not rf.tags["artist"]:
show_warning(
parent=self.main_window,
title="Error",
@ -98,11 +98,11 @@ class ReplaceFilesDialog(QDialog):
# Check for same filename
match_track = self.check_by_basename(
session, new_file_path, rf.tags['artist'], rf.tags['title']
session, new_file_path, rf.tags["artist"], rf.tags["title"]
)
if not match_track:
match_track = self.check_by_title(
session, new_file_path, rf.tags['artist'], rf.tags['title']
session, new_file_path, rf.tags["artist"], rf.tags["title"]
)
if not match_track:
@ -113,8 +113,7 @@ class ReplaceFilesDialog(QDialog):
# We will store new file in the same directory as the
# existing file but with the new file name
rf.track_path = os.path.join(
os.path.dirname(match_track.path),
new_file_basename
os.path.dirname(match_track.path), new_file_basename
)
# We will remove existing track file
@ -125,27 +124,34 @@ class ReplaceFilesDialog(QDialog):
if match_basename == new_file_basename:
path_text = " " + new_file_basename + " (no change)"
else:
path_text = f" {match_basename}\n {new_file_basename} (replace)"
path_text = (
f" {match_basename}\n {new_file_basename} (replace)"
)
filename_item = QTableWidgetItem(path_text)
if match_track.title == rf.tags['title']:
title_text = " " + rf.tags['title'] + " (no change)"
if match_track.title == rf.tags["title"]:
title_text = " " + rf.tags["title"] + " (no change)"
else:
title_text = f" {match_track.title}\n {rf.tags['title']} (update)"
title_text = (
f" {match_track.title}\n {rf.tags['title']} (update)"
)
title_item = QTableWidgetItem(title_text)
if match_track.artist == rf.tags['artist']:
artist_text = " " + rf.tags['artist'] + " (no change)"
if match_track.artist == rf.tags["artist"]:
artist_text = " " + rf.tags["artist"] + " (no change)"
else:
artist_text = f" {match_track.artist}\n {rf.tags['artist']} (update)"
artist_text = (
f" {match_track.artist}\n {rf.tags['artist']} (update)"
)
artist_item = QTableWidgetItem(artist_text)
else:
rf.track_path = os.path.join(Config.REPLACE_FILES_DEFAULT_DESTINATION,
new_file_basename)
rf.track_path = os.path.join(
Config.REPLACE_FILES_DEFAULT_DESTINATION, new_file_basename
)
filename_item = QTableWidgetItem(" " + new_file_basename + " (new)")
title_item = QTableWidgetItem(" " + rf.tags['title'])
artist_item = QTableWidgetItem(" " + rf.tags['artist'])
title_item = QTableWidgetItem(" " + rf.tags["title"])
artist_item = QTableWidgetItem(" " + rf.tags["artist"])
self.replacement_files.append(rf)
row = self.ui.tableWidget.rowCount()

View File

@ -1,18 +1,23 @@
# Standard library imports
import datetime as dt
import threading
from time import sleep
from typing import Optional
# Third party imports
import vlc # type: ignore
from config import Config
from helpers import file_is_unreadable
from typing import Optional
from time import sleep
from log import log
# PyQt imports
from PyQt6.QtCore import (
QRunnable,
QThreadPool,
)
# App imports
from config import Config
from helpers import file_is_unreadable
from log import log
lock = threading.Lock()
@ -57,6 +62,7 @@ class Music:
self.VLC = vlc.Instance()
self.player = None
self.max_volume = Config.VOLUME_VLC_DEFAULT
self.start_dt: Optional[dt.datetime] = None
def fade(self, fade_seconds: int = Config.FADEOUT_SECONDS) -> None:
"""
@ -83,6 +89,21 @@ class Music:
pool = QThreadPool.globalInstance()
fader = FadeTrack(p, fade_seconds=fade_seconds)
pool.start(fader)
self.start_dt = None
def get_playtime(self) -> int:
"""
Return number of milliseconds current track has been playing or
zero if not playing. The vlc function get_time() only updates 3-4
times a second; this function has much better resolution.
"""
if self.start_dt is None:
return 0
now = dt.datetime.now()
elapsed_seconds = (now - self.start_dt).total_seconds()
return int(elapsed_seconds * 1000)
def get_position(self) -> Optional[float]:
"""Return current position"""
@ -91,6 +112,23 @@ class Music:
return None
return self.player.get_position()
def is_playing(self) -> bool:
"""Return True if playing"""
# There is a discrete time between starting playing a track and
# player.is_playing() returning True, so assume playing if less
# than Config.PLAY_SETTLE microseconds have passed since
# starting play.
return (
self.player is not None
and self.start_dt is not None
and (
self.player.is_playing()
or (dt.datetime.now() - self.start_dt)
< dt.timedelta(microseconds=Config.PLAY_SETTLE)
)
)
def play(self, path: str, position: Optional[float] = None) -> None:
"""
Start playing the track at path.
@ -109,8 +147,10 @@ class Music:
if self.player:
_ = self.player.play()
self.set_volume(self.max_volume)
if position:
self.player.set_position(position)
self.start_dt = dt.datetime.now()
def set_volume(self, volume=None, set_default=True) -> None:
"""Set maximum volume used for player"""
@ -125,6 +165,17 @@ class Music:
volume = Config.VOLUME_VLC_DEFAULT
self.player.audio_set_volume(volume)
# Ensure volume correct
# For as-yet unknown reasons. sometimes the volume gets
# reset to zero within 200mS or so of starting play. This
# only happened since moving to Debian 12, which uses
# Pipewire for sound (which may be irrelevant).
for _ in range(3):
current_volume = self.player.audio_get_volume()
if current_volume < volume:
self.player.audio_set_volume(volume)
log.debug(f"Reset from {volume=}")
sleep(0.1)
def stop(self) -> float:
"""Immediately stop playing"""
@ -136,6 +187,7 @@ class Music:
p = self.player
self.player = None
self.start_dt = None
with lock:
position = p.get_position()

View File

@ -781,21 +781,6 @@ class Window(QMainWindow, Ui_MainWindow):
self.stop_playing(fade=True)
def get_playtime(self) -> int:
"""
Return number of milliseconds current track has been playing or
zero if not playing. The vlc function get_time() only updates 3-4
times a second; this function has much better resolution.
"""
if track_sequence.now.track_id is None or track_sequence.now.start_time is None:
return 0
now = dt.datetime.now()
track_start = track_sequence.now.start_time
elapsed_seconds = (now - track_start).total_seconds()
return int(elapsed_seconds * 1000)
def hide_played(self):
"""Toggle hide played tracks"""
@ -1146,7 +1131,6 @@ class Window(QMainWindow, Ui_MainWindow):
- Clear next track
- Restore volume if -3dB active
- Play (new) current track.
- Ensure 100% volume
- Show closing volume graph
- Notify model
- Note that track is now playing
@ -1167,13 +1151,10 @@ class Window(QMainWindow, Ui_MainWindow):
# If return is pressed during first PLAY_NEXT_GUARD_MS then
# default to NOT playing the next track, else default to
# playing it.
default_yes: bool = (
track_sequence.now.start_time is not None
and (
(dt.datetime.now() - track_sequence.now.start_time).total_seconds()
* 1000
> Config.PLAY_NEXT_GUARD_MS
)
default_yes: bool = track_sequence.now.start_time is not None and (
(dt.datetime.now() - track_sequence.now.start_time).total_seconds()
* 1000
> Config.PLAY_NEXT_GUARD_MS
)
if not helpers.ask_yes_no(
"Track playing",
@ -1215,20 +1196,6 @@ class Window(QMainWindow, Ui_MainWindow):
return
self.music.play(track_sequence.now.path, position)
# Ensure 100% volume
# For as-yet unknown reasons. sometimes the volume gets
# reset to zero within 200mS or so of starting play. This
# only happened since moving to Debian 12, which uses
# Pipewire for sound (which may be irrelevant).
for _ in range(3):
if self.music.player:
volume = self.music.player.audio_get_volume()
if volume < Config.VOLUME_VLC_DEFAULT:
self.music.set_volume()
log.debug(f"Reset from {volume=}")
break
sleep(0.1)
# Show closing volume graph
if track_sequence.now.fade_graph:
track_sequence.now.fade_graph.plot()
@ -1715,20 +1682,8 @@ class Window(QMainWindow, Ui_MainWindow):
return
# If track is playing, update track clocks time and colours
# There is a discrete time between starting playing a track and
# player.is_playing() returning True, so assume playing if less
# than Config.PLAY_SETTLE microseconds have passed since
# starting play.
if (
self.music.player
and track_sequence.now.start_time
and (
self.music.player.is_playing()
or (dt.datetime.now() - track_sequence.now.start_time)
< dt.timedelta(microseconds=Config.PLAY_SETTLE)
)
):
playtime = self.get_playtime()
if self.music.player and self.music.player.is_playing():
playtime = self.music.player.get_playtime()
time_to_fade = track_sequence.now.fade_at - playtime
time_to_silence = track_sequence.now.silence_at - playtime

View File

@ -614,7 +614,7 @@ class PlaylistTab(QTableView):
else:
result = self.source_model.get_row_track_path(model_row_number)
log.info(f"get_selected_row_track_path() returned: {result=}")
log.debug(f"get_selected_row_track_path() returned: {result=}")
return result
def get_selected_rows(self) -> List[int]: