WIP V3: play track working
This commit is contained in:
parent
bd2fa1cab0
commit
a35905dee8
@ -1,6 +1,6 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from typing import Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
from PyQt6.QtCore import pyqtSignal, QObject, QThread
|
from PyQt6.QtCore import pyqtSignal, QObject, QThread
|
||||||
import numpy as np
|
import numpy as np
|
||||||
@ -212,16 +212,8 @@ class AddFadeCurve(QObject):
|
|||||||
self.finished.emit()
|
self.finished.emit()
|
||||||
|
|
||||||
|
|
||||||
@helpers.singleton
|
cnp_tracks = dict(
|
||||||
class CurrentTrack(PlaylistTrack):
|
CurrentTrack = PlaylistTrack(),
|
||||||
pass
|
NextTrack = PlaylistTrack(),
|
||||||
|
PreviousTrack = PlaylistTrack(),
|
||||||
|
)
|
||||||
@helpers.singleton
|
|
||||||
class NextTrack(PlaylistTrack):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@helpers.singleton
|
|
||||||
class PreviousTrack(PlaylistTrack):
|
|
||||||
pass
|
|
||||||
|
|||||||
@ -52,12 +52,10 @@ from sqlalchemy import text
|
|||||||
import stackprinter # type: ignore
|
import stackprinter # type: ignore
|
||||||
|
|
||||||
from classes import (
|
from classes import (
|
||||||
CurrentTrack,
|
cnp_tracks,
|
||||||
FadeCurve,
|
FadeCurve,
|
||||||
MusicMusterSignals,
|
MusicMusterSignals,
|
||||||
NextTrack,
|
|
||||||
PlaylistTrack,
|
PlaylistTrack,
|
||||||
PreviousTrack,
|
|
||||||
)
|
)
|
||||||
from config import Config
|
from config import Config
|
||||||
from dbconfig import (
|
from dbconfig import (
|
||||||
@ -199,10 +197,6 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
self.music: music.Music = music.Music()
|
self.music: music.Music = music.Music()
|
||||||
self.playing: bool = False
|
self.playing: bool = False
|
||||||
|
|
||||||
self.current_track = CurrentTrack()
|
|
||||||
self.next_track = NextTrack()
|
|
||||||
self.previous_track = PreviousTrack()
|
|
||||||
|
|
||||||
self.previous_track_position: Optional[float] = None
|
self.previous_track_position: Optional[float] = None
|
||||||
self.selected_plrs: Optional[List[PlaylistRows]] = None
|
self.selected_plrs: Optional[List[PlaylistRows]] = None
|
||||||
|
|
||||||
@ -393,7 +387,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
Clear next track
|
Clear next track
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.next_track = NextTrack()
|
cnp_tracks['NextTrack'] = PlaylistTrack()
|
||||||
self.update_headers()
|
self.update_headers()
|
||||||
|
|
||||||
def clear_selection(self) -> None:
|
def clear_selection(self) -> None:
|
||||||
@ -714,12 +708,13 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
# self.current_track.playlist_tab.play_ended()
|
# self.current_track.playlist_tab.play_ended()
|
||||||
|
|
||||||
# Reset fade graph
|
# Reset fade graph
|
||||||
self.current_track.fade_graph.clear()
|
if cnp_tracks['CurrentTrack'].fade_graph:
|
||||||
|
cnp_tracks['CurrentTrack'].fade_graph.clear()
|
||||||
|
|
||||||
# Reset PlaylistTrack objects
|
# Reset PlaylistTrack objects
|
||||||
if self.current_track.track_id:
|
if cnp_tracks['CurrentTrack'].track_id:
|
||||||
self.previous_track = cast(PreviousTrack, self.current_track)
|
cnp_tracks['PreviousTrack'] = cnp_tracks['CurrentTrack']
|
||||||
self.current_track = CurrentTrack()
|
cnp_tracks['CurrentTrack'] = PlaylistTrack()
|
||||||
|
|
||||||
# Reset clocks
|
# Reset clocks
|
||||||
self.frame_fade.setStyleSheet("")
|
self.frame_fade.setStyleSheet("")
|
||||||
@ -790,11 +785,11 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
times a second; this function has much better resolution.
|
times a second; this function has much better resolution.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.current_track.track_id is None or self.current_track.start_time is None:
|
if cnp_tracks['CurrentTrack'].track_id is None or cnp_tracks['CurrentTrack'].start_time is None:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
track_start = self.current_track.start_time
|
track_start = cnp_tracks['CurrentTrack'].start_time
|
||||||
elapsed_seconds = (now - track_start).total_seconds()
|
elapsed_seconds = (now - track_start).total_seconds()
|
||||||
return int(elapsed_seconds * 1000)
|
return int(elapsed_seconds * 1000)
|
||||||
|
|
||||||
@ -947,7 +942,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
plrs_to_move = [
|
plrs_to_move = [
|
||||||
plr
|
plr
|
||||||
for plr in playlistrows
|
for plr in playlistrows
|
||||||
if plr.id not in [self.current_track.plr_id, self.next_track.plr_id]
|
if plr.id not in [cnp_tracks['CurrentTrack'].plr_id, cnp_tracks['NextTrack'].plr_id]
|
||||||
]
|
]
|
||||||
|
|
||||||
rows_to_delete = [
|
rows_to_delete = [
|
||||||
@ -1143,21 +1138,24 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
- If there is no next track set, return.
|
- If there is no next track set, return.
|
||||||
- If there's currently a track playing, fade it.
|
- If there's currently a track playing, fade it.
|
||||||
- Move next track to current track.
|
- Move next track to current track.
|
||||||
- Ensure playlist tabs are the correct colour
|
- Clear next track
|
||||||
- Restore volume if -3dB active
|
- Restore volume if -3dB active
|
||||||
- Play (new) current track.
|
- Play (new) current track.
|
||||||
- Tell database to record it as played
|
- Ensure 100% volume
|
||||||
- Tell playlist track is now playing
|
- Show closing volume graph
|
||||||
|
- Notify model
|
||||||
- Note that track is now playing
|
- Note that track is now playing
|
||||||
- Disable play next controls
|
- Disable play next controls
|
||||||
- Update headers
|
- Update headers
|
||||||
- Update clocks
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# If there is no next track set, return.
|
# If there is no next track set, return.
|
||||||
if not self.next_track.track_id:
|
if not cnp_tracks['NextTrack'].track_id:
|
||||||
log.debug("musicmuster.play_next(): no next track selected")
|
log.debug("musicmuster.play_next(): no next track selected")
|
||||||
return
|
return
|
||||||
|
if not cnp_tracks['NextTrack'].path:
|
||||||
|
log.debug("musicmuster.play_next(): no path for next track")
|
||||||
|
return
|
||||||
|
|
||||||
with Session() as session:
|
with Session() as session:
|
||||||
# If there's currently a track playing, fade it.
|
# If there's currently a track playing, fade it.
|
||||||
@ -1166,15 +1164,10 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
# Move next track to current track.
|
# Move next track to current track.
|
||||||
# stop_playing() above has called end_of_track_actions()
|
# stop_playing() above has called end_of_track_actions()
|
||||||
# which will have populated self.previous_track
|
# which will have populated self.previous_track
|
||||||
self.current_track = cast(CurrentTrack, self.next_track)
|
cnp_tracks['CurrentTrack'] = cnp_tracks['NextTrack']
|
||||||
self.clear_next()
|
|
||||||
|
|
||||||
if not self.current_track.track_id:
|
# Clear next track
|
||||||
log.debug("musicmuster.play_next(): no id for next track")
|
self.clear_next()
|
||||||
return
|
|
||||||
if not self.current_track.path:
|
|
||||||
log.debug("musicmuster.play_next(): no path for next track")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Set current track playlist_tab colour
|
# Set current track playlist_tab colour
|
||||||
# TODO Reimplement without reference to self.current_track.playlist_tab
|
# TODO Reimplement without reference to self.current_track.playlist_tab
|
||||||
@ -1187,8 +1180,12 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
self.btnDrop3db.setChecked(False)
|
self.btnDrop3db.setChecked(False)
|
||||||
|
|
||||||
# Play (new) current track
|
# Play (new) current track
|
||||||
self.current_track.start()
|
if not cnp_tracks['CurrentTrack'].path:
|
||||||
self.music.play(self.current_track.path, position)
|
return
|
||||||
|
cnp_tracks['CurrentTrack'].start()
|
||||||
|
self.music.play(cnp_tracks['CurrentTrack'].path, position)
|
||||||
|
|
||||||
|
# Ensure 100% volume
|
||||||
# For as-yet unknown reasons. sometimes the volume gets
|
# For as-yet unknown reasons. sometimes the volume gets
|
||||||
# reset to zero within 200mS or so of starting play. This
|
# reset to zero within 200mS or so of starting play. This
|
||||||
# only happened since moving to Debian 12, which uses
|
# only happened since moving to Debian 12, which uses
|
||||||
@ -1203,15 +1200,11 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
sleep(0.1)
|
sleep(0.1)
|
||||||
|
|
||||||
# Show closing volume graph
|
# Show closing volume graph
|
||||||
self.current_track.fade_graph.plot()
|
if cnp_tracks['CurrentTrack'].fade_graph:
|
||||||
|
cnp_tracks['CurrentTrack'].fade_graph.plot()
|
||||||
|
|
||||||
# Tell database to record it as played
|
# Notify model
|
||||||
Playdates(session, self.current_track.track_id)
|
self.active_model().current_track_started()
|
||||||
|
|
||||||
# Tell playlist track is now playing
|
|
||||||
# TODO Reimplement without reference to self.current_track.playlist_tab:
|
|
||||||
# if self.current_track.playlist_tab:
|
|
||||||
# self.current_track.playlist_tab.play_started(session)
|
|
||||||
|
|
||||||
# Note that track is now playing
|
# Note that track is now playing
|
||||||
self.playing = True
|
self.playing = True
|
||||||
@ -1234,7 +1227,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
track_path = self.active_tab().get_selected_row_track_path()
|
track_path = self.active_tab().get_selected_row_track_path()
|
||||||
if not track_path:
|
if not track_path:
|
||||||
# Otherwise get path to next track to play
|
# Otherwise get path to next track to play
|
||||||
track_path = self.next_track.path
|
track_path = cnp_tracks['NextTrack'].path
|
||||||
if not track_path:
|
if not track_path:
|
||||||
self.btnPreview.setChecked(False)
|
self.btnPreview.setChecked(False)
|
||||||
return
|
return
|
||||||
@ -1531,7 +1524,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
Set passed plr_id as next track to play, or clear next track if None
|
Set passed plr_id as next track to play, or clear next track if None
|
||||||
|
|
||||||
Actions required:
|
Actions required:
|
||||||
- Update self.next_track PlaylistTrack structure
|
- Update cnp_tracks
|
||||||
- Tell playlist tabs to update their 'next track' highlighting
|
- Tell playlist tabs to update their 'next track' highlighting
|
||||||
- Update headers
|
- Update headers
|
||||||
- Set playlist tab colours
|
- Set playlist tab colours
|
||||||
@ -1610,14 +1603,14 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
# Update volume fade curve
|
# Update volume fade curve
|
||||||
if (
|
if (
|
||||||
self.current_track.track_id
|
cnp_tracks['CurrentTrack'].track_id
|
||||||
and self.current_track.fade_graph
|
and cnp_tracks['CurrentTrack'].fade_graph
|
||||||
and self.current_track.start_time
|
and cnp_tracks['CurrentTrack'].start_time
|
||||||
):
|
):
|
||||||
play_time = (
|
play_time = (
|
||||||
datetime.now() - self.current_track.start_time
|
datetime.now() - cnp_tracks['CurrentTrack'].start_time
|
||||||
).total_seconds() * 1000
|
).total_seconds() * 1000
|
||||||
self.current_track.fade_graph.tick(play_time)
|
cnp_tracks['CurrentTrack'].fade_graph.tick(play_time)
|
||||||
|
|
||||||
def tick_500ms(self) -> None:
|
def tick_500ms(self) -> None:
|
||||||
"""
|
"""
|
||||||
@ -1649,22 +1642,22 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
# starting play.
|
# starting play.
|
||||||
if (
|
if (
|
||||||
self.music.player
|
self.music.player
|
||||||
and self.current_track.start_time
|
and cnp_tracks['CurrentTrack'].start_time
|
||||||
and (
|
and (
|
||||||
self.music.player.is_playing()
|
self.music.player.is_playing()
|
||||||
or (datetime.now() - self.current_track.start_time)
|
or (datetime.now() - cnp_tracks['CurrentTrack'].start_time)
|
||||||
< timedelta(microseconds=Config.PLAY_SETTLE)
|
< timedelta(microseconds=Config.PLAY_SETTLE)
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
playtime = self.get_playtime()
|
playtime = self.get_playtime()
|
||||||
time_to_fade = self.current_track.fade_at - playtime
|
time_to_fade = cnp_tracks['CurrentTrack'].fade_at - playtime
|
||||||
time_to_silence = self.current_track.silence_at - playtime
|
time_to_silence = cnp_tracks['CurrentTrack'].silence_at - playtime
|
||||||
|
|
||||||
# Elapsed time
|
# Elapsed time
|
||||||
self.label_elapsed_timer.setText(
|
self.label_elapsed_timer.setText(
|
||||||
helpers.ms_to_mmss(playtime)
|
helpers.ms_to_mmss(playtime)
|
||||||
+ " / "
|
+ " / "
|
||||||
+ helpers.ms_to_mmss(self.current_track.duration)
|
+ helpers.ms_to_mmss(cnp_tracks['CurrentTrack'].duration)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Time to fade
|
# Time to fade
|
||||||
@ -1707,25 +1700,25 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
Update last / current / next track headers
|
Update last / current / next track headers
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.previous_track.title and self.previous_track.artist:
|
if cnp_tracks['PreviousTrack'].title and cnp_tracks['PreviousTrack'].artist:
|
||||||
self.hdrPreviousTrack.setText(
|
self.hdrPreviousTrack.setText(
|
||||||
f"{self.previous_track.title} - {self.previous_track.artist}"
|
f"{cnp_tracks['PreviousTrack'].title} - {cnp_tracks['PreviousTrack'].artist}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.hdrPreviousTrack.setText("")
|
self.hdrPreviousTrack.setText("")
|
||||||
|
|
||||||
if self.current_track.title and self.current_track.artist:
|
if cnp_tracks['CurrentTrack'].title and cnp_tracks['CurrentTrack'].artist:
|
||||||
self.hdrCurrentTrack.setText(
|
self.hdrCurrentTrack.setText(
|
||||||
f"{self.current_track.title.replace('&', '&&')} - "
|
f"{cnp_tracks['CurrentTrack'].title.replace('&', '&&')} - "
|
||||||
f"{self.current_track.artist.replace('&', '&&')}"
|
f"{cnp_tracks['CurrentTrack'].artist.replace('&', '&&')}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.hdrCurrentTrack.setText("")
|
self.hdrCurrentTrack.setText("")
|
||||||
|
|
||||||
if self.next_track.title and self.next_track.artist:
|
if cnp_tracks['NextTrack'].title and cnp_tracks['NextTrack'].artist:
|
||||||
self.hdrNextTrack.setText(
|
self.hdrNextTrack.setText(
|
||||||
f"{self.next_track.title.replace('&', '&&')} - "
|
f"{cnp_tracks['NextTrack'].title.replace('&', '&&')} - "
|
||||||
f"{self.next_track.artist.replace('&', '&&')}"
|
f"{cnp_tracks['NextTrack'].artist.replace('&', '&&')}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.hdrNextTrack.setText("")
|
self.hdrNextTrack.setText("")
|
||||||
|
|||||||
@ -14,12 +14,12 @@ from PyQt6.QtGui import (
|
|||||||
QFont,
|
QFont,
|
||||||
)
|
)
|
||||||
|
|
||||||
from classes import CurrentTrack, MusicMusterSignals, NextTrack
|
from classes import cnp_tracks, MusicMusterSignals, PlaylistTrack
|
||||||
from config import Config
|
from config import Config
|
||||||
from dbconfig import scoped_session, Session
|
from dbconfig import scoped_session, Session
|
||||||
from helpers import file_is_unreadable
|
from helpers import file_is_unreadable
|
||||||
from log import log
|
from log import log
|
||||||
from models import PlaylistRows, Tracks
|
from models import Playdates, PlaylistRows, Tracks
|
||||||
|
|
||||||
|
|
||||||
HEADER_NOTES_COLUMN = 1
|
HEADER_NOTES_COLUMN = 1
|
||||||
@ -104,9 +104,6 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
self.signals.add_track_to_header_signal.connect(self.add_track_to_header)
|
self.signals.add_track_to_header_signal.connect(self.add_track_to_header)
|
||||||
self.signals.add_track_to_playlist_signal.connect(self.add_track)
|
self.signals.add_track_to_playlist_signal.connect(self.add_track)
|
||||||
|
|
||||||
self.current_track = CurrentTrack()
|
|
||||||
self.next_track = NextTrack()
|
|
||||||
|
|
||||||
with Session() as session:
|
with Session() as session:
|
||||||
self.refresh_data(session)
|
self.refresh_data(session)
|
||||||
|
|
||||||
@ -194,10 +191,10 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
if file_is_unreadable(prd.path):
|
if file_is_unreadable(prd.path):
|
||||||
return QBrush(QColor(Config.COLOUR_UNREADABLE))
|
return QBrush(QColor(Config.COLOUR_UNREADABLE))
|
||||||
# Current track
|
# Current track
|
||||||
if prd.plrid == self.current_track.plr_id:
|
if prd.plrid == cnp_tracks['CurrentTrack'].plr_id:
|
||||||
return QBrush(QColor(Config.COLOUR_CURRENT_PLAYLIST))
|
return QBrush(QColor(Config.COLOUR_CURRENT_PLAYLIST))
|
||||||
# Next track
|
# Next track
|
||||||
if prd.plrid == self.next_track.plr_id:
|
if prd.plrid == cnp_tracks['NextTrack'].plr_id:
|
||||||
return QBrush(QColor(Config.COLOUR_NEXT_PLAYLIST))
|
return QBrush(QColor(Config.COLOUR_NEXT_PLAYLIST))
|
||||||
|
|
||||||
# Individual cell colouring
|
# Individual cell colouring
|
||||||
@ -219,6 +216,66 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
|
|
||||||
return 9
|
return 9
|
||||||
|
|
||||||
|
def current_track_started(self) -> None:
|
||||||
|
"""
|
||||||
|
Notification from musicmuster that the current track has just
|
||||||
|
started playing
|
||||||
|
|
||||||
|
Actions required:
|
||||||
|
- sanity check
|
||||||
|
- update display
|
||||||
|
- update track times
|
||||||
|
- update Playdates in database
|
||||||
|
- update PlaylistRows in database
|
||||||
|
- find next track
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Sanity check
|
||||||
|
if not cnp_tracks['CurrentTrack'].track_id:
|
||||||
|
log.error(
|
||||||
|
"playlistmodel:current_track_started called with no current track"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
if cnp_tracks['CurrentTrack'].plr_rownum is None:
|
||||||
|
log.error(
|
||||||
|
"playlistmodel:current_track_started called with no row number "
|
||||||
|
f"({self.current_track=})"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Update display
|
||||||
|
self.invalidate_row(cnp_tracks['CurrentTrack'].plr_rownum)
|
||||||
|
|
||||||
|
# Update track times
|
||||||
|
# TODO
|
||||||
|
|
||||||
|
# Update Playdates in database
|
||||||
|
with Session() as session:
|
||||||
|
Playdates(session, cnp_tracks['CurrentTrack'].track_id)
|
||||||
|
plr = session.get(PlaylistRows, cnp_tracks['CurrentTrack'].plr_id)
|
||||||
|
if plr:
|
||||||
|
plr.played = True
|
||||||
|
|
||||||
|
# Find next track
|
||||||
|
# Get all unplayed track rows
|
||||||
|
next_row = None
|
||||||
|
unplayed_rows = [
|
||||||
|
a.plr_rownum
|
||||||
|
for a in PlaylistRows.get_unplayed_rows(session, self.playlist_id)
|
||||||
|
]
|
||||||
|
|
||||||
|
if unplayed_rows:
|
||||||
|
try:
|
||||||
|
# Find next row after current track
|
||||||
|
next_row = min(
|
||||||
|
[a for a in unplayed_rows if a > cnp_tracks['CurrentTrack'].plr_rownum]
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
# Find first unplayed track
|
||||||
|
next_row = min(unplayed_rows)
|
||||||
|
if next_row is not None:
|
||||||
|
self.set_next_row(next_row)
|
||||||
|
|
||||||
def data(self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole):
|
def data(self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole):
|
||||||
"""Return data to view"""
|
"""Return data to view"""
|
||||||
|
|
||||||
@ -523,14 +580,14 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
|
|
||||||
return len(self.playlist_rows)
|
return len(self.playlist_rows)
|
||||||
|
|
||||||
def set_next_track(self, row_number: int) -> None:
|
def set_next_row(self, row_number: int) -> None:
|
||||||
"""
|
"""
|
||||||
Update display if necessary
|
Set row_number as next track
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Update self.next_track PlaylistTrack structure
|
# Update cnp_tracks
|
||||||
with Session() as session:
|
with Session() as session:
|
||||||
self.next_track = NextTrack()
|
cnp_tracks['NextTrack'] = PlaylistTrack()
|
||||||
try:
|
try:
|
||||||
plrid = self.playlist_rows[row_number].plrid
|
plrid = self.playlist_rows[row_number].plrid
|
||||||
except IndexError:
|
except IndexError:
|
||||||
@ -547,7 +604,7 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
# Check track is readable
|
# Check track is readable
|
||||||
if file_is_unreadable(plr.track.path):
|
if file_is_unreadable(plr.track.path):
|
||||||
return
|
return
|
||||||
self.next_track.set_plr(session, plr)
|
cnp_tracks['NextTrack'].set_plr(session, plr)
|
||||||
self.signals.next_track_changed_signal.emit()
|
self.signals.next_track_changed_signal.emit()
|
||||||
self.invalidate_row(row_number)
|
self.invalidate_row(row_number)
|
||||||
|
|
||||||
|
|||||||
@ -1028,7 +1028,7 @@ class PlaylistTab(QTableView):
|
|||||||
if selected_row is None:
|
if selected_row is None:
|
||||||
return
|
return
|
||||||
model = cast(PlaylistModel, self.model())
|
model = cast(PlaylistModel, self.model())
|
||||||
model.set_next_track(selected_row)
|
model.set_next_row(selected_row)
|
||||||
self.clearSelection()
|
self.clearSelection()
|
||||||
|
|
||||||
# def tab_visible(self) -> None:
|
# def tab_visible(self) -> None:
|
||||||
@ -1266,41 +1266,41 @@ class PlaylistTab(QTableView):
|
|||||||
|
|
||||||
self._update_start_end_times(session)
|
self._update_start_end_times(session)
|
||||||
|
|
||||||
def _find_next_track_row(
|
# def _find_next_track_row(
|
||||||
self, session: scoped_session, starting_row: Optional[int] = None
|
# self, session: scoped_session, starting_row: Optional[int] = None
|
||||||
) -> Optional[int]:
|
# ) -> Optional[int]:
|
||||||
"""
|
# """
|
||||||
Find next track to play. If a starting row is given, start there;
|
# Find next track to play. If a starting row is given, start there;
|
||||||
otherwise, start from top. Skip rows already played.
|
# otherwise, start from top. Skip rows already played.
|
||||||
|
|
||||||
If not found, return None.
|
# If not found, return None.
|
||||||
|
|
||||||
If found, return row number.
|
# If found, return row number.
|
||||||
"""
|
# """
|
||||||
|
|
||||||
if starting_row is None:
|
# if starting_row is None:
|
||||||
starting_row = 0
|
# starting_row = 0
|
||||||
|
|
||||||
track_rows = [
|
# track_rows = [
|
||||||
p.plr_rownum
|
# p.plr_rownum
|
||||||
for p in PlaylistRows.get_rows_with_tracks(session, self.playlist_id)
|
# for p in PlaylistRows.get_rows_with_tracks(session, self.playlist_id)
|
||||||
]
|
# ]
|
||||||
played_rows = [
|
# played_rows = [
|
||||||
p.plr_rownum
|
# p.plr_rownum
|
||||||
for p in PlaylistRows.get_played_rows(session, self.playlist_id)
|
# for p in PlaylistRows.get_played_rows(session, self.playlist_id)
|
||||||
]
|
# ]
|
||||||
for row_number in range(starting_row, self.rowCount()):
|
# for row_number in range(starting_row, self.rowCount()):
|
||||||
if row_number not in track_rows or row_number in played_rows:
|
# if row_number not in track_rows or row_number in played_rows:
|
||||||
continue
|
# continue
|
||||||
plr = self._get_row_plr(session, row_number)
|
# plr = self._get_row_plr(session, row_number)
|
||||||
if not plr:
|
# if not plr:
|
||||||
continue
|
# continue
|
||||||
if file_is_unreadable(plr.track.path):
|
# if file_is_unreadable(plr.track.path):
|
||||||
continue
|
# continue
|
||||||
else:
|
# else:
|
||||||
return row_number
|
# return row_number
|
||||||
|
|
||||||
return None
|
# return None
|
||||||
|
|
||||||
def _get_current_track_row_number(self) -> Optional[int]:
|
def _get_current_track_row_number(self) -> Optional[int]:
|
||||||
"""Return current track row or None"""
|
"""Return current track row or None"""
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user