V2 using ids rather than objects. Looking good.
This commit is contained in:
parent
26edd5a2d0
commit
e8211414f9
@ -118,9 +118,9 @@ class NoteColours(Base):
|
||||
|
||||
for rec in (
|
||||
session.query(NoteColours)
|
||||
.filter(NoteColours.enabled.is_(True))
|
||||
.order_by(NoteColours.order)
|
||||
.all()
|
||||
.filter(NoteColours.enabled.is_(True))
|
||||
.order_by(NoteColours.order)
|
||||
.all()
|
||||
):
|
||||
if rec.is_regex:
|
||||
flags = re.UNICODE
|
||||
@ -175,6 +175,18 @@ class Notes(Base):
|
||||
session.query(Notes).filter_by(id=self.id).delete()
|
||||
session.commit()
|
||||
|
||||
@classmethod
|
||||
def get_by_id(cls, session: Session, note_id: int) -> Optional["Notes"]:
|
||||
"""Return note or None"""
|
||||
|
||||
try:
|
||||
DEBUG(f"Notes.get_track(track_id={note_id})")
|
||||
note = session.query(cls).filter(cls.id == note_id).one()
|
||||
return note
|
||||
except NoResultFound:
|
||||
ERROR(f"get_track({note_id}): not found")
|
||||
return None
|
||||
|
||||
def update_note(
|
||||
self, session: Session, row: int,
|
||||
text: Optional[str] = None) -> None:
|
||||
@ -215,8 +227,9 @@ class Playdates(Base):
|
||||
"""Return datetime track last played or None"""
|
||||
|
||||
last_played: Optional[Playdates] = session.query(
|
||||
Playdates.lastplayed).filter((Playdates.track_id == track_id)
|
||||
).order_by(Playdates.lastplayed.desc()).first()
|
||||
Playdates.lastplayed).filter(
|
||||
(Playdates.track_id == track_id)
|
||||
).order_by(Playdates.lastplayed.desc()).first()
|
||||
if last_played:
|
||||
return last_played[0]
|
||||
else:
|
||||
@ -246,7 +259,9 @@ class Playlists(Base):
|
||||
last_used: datetime = Column(DateTime, default=None, nullable=True)
|
||||
loaded: bool = Column(Boolean, default=True, nullable=False)
|
||||
notes = relationship(
|
||||
"Notes", order_by="Notes.row", back_populates="playlist", lazy="joined")
|
||||
"Notes", order_by="Notes.row",
|
||||
back_populates="playlist", lazy="joined"
|
||||
)
|
||||
|
||||
tracks = association_proxy('playlist_tracks', 'tracks')
|
||||
row = association_proxy('playlist_tracks', 'row')
|
||||
@ -265,7 +280,7 @@ class Playlists(Base):
|
||||
return Notes(session, self.id, row, text)
|
||||
|
||||
def add_track(
|
||||
self, session: Session, track: "Tracks",
|
||||
self, session: Session, track_id: int,
|
||||
row: Optional[int] = None) -> None:
|
||||
"""
|
||||
Add track to playlist at given row.
|
||||
@ -275,7 +290,7 @@ class Playlists(Base):
|
||||
if not row:
|
||||
row = PlaylistTracks.next_free_row(session, self)
|
||||
|
||||
PlaylistTracks(session, self.id, track.id, row)
|
||||
PlaylistTracks(session, self.id, track_id, row)
|
||||
|
||||
def close(self, session: Session) -> None:
|
||||
"""Record playlist as no longer loaded"""
|
||||
@ -289,8 +304,7 @@ class Playlists(Base):
|
||||
"""Returns a list of all playlists ordered by last use"""
|
||||
|
||||
return (
|
||||
session.query(cls)
|
||||
.order_by(cls.last_used.desc())
|
||||
session.query(cls).order_by(cls.last_used.desc())
|
||||
).all()
|
||||
|
||||
@classmethod
|
||||
@ -303,8 +317,8 @@ class Playlists(Base):
|
||||
|
||||
return (
|
||||
session.query(cls)
|
||||
.filter(cls.loaded.is_(False))
|
||||
.order_by(cls.last_used.desc())
|
||||
.filter(cls.loaded.is_(False))
|
||||
.order_by(cls.last_used.desc())
|
||||
).all()
|
||||
|
||||
@classmethod
|
||||
@ -315,8 +329,8 @@ class Playlists(Base):
|
||||
|
||||
return (
|
||||
session.query(cls)
|
||||
.filter(cls.loaded.is_(True))
|
||||
.order_by(cls.last_used.desc())
|
||||
.filter(cls.loaded.is_(True))
|
||||
.order_by(cls.last_used.desc())
|
||||
).all()
|
||||
|
||||
def mark_open(self, session: Session) -> None:
|
||||
@ -353,7 +367,7 @@ class PlaylistTracks(Base):
|
||||
|
||||
id: int = Column(Integer, primary_key=True, autoincrement=True)
|
||||
playlist_id: int = Column(Integer, ForeignKey('playlists.id'),
|
||||
primary_key=True)
|
||||
primary_key=True)
|
||||
track_id: int = Column(Integer, ForeignKey('tracks.id'), primary_key=True)
|
||||
row: int = Column(Integer, nullable=False)
|
||||
tracks: RelationshipProperty = relationship("Tracks")
|
||||
@ -421,7 +435,7 @@ class PlaylistTracks(Base):
|
||||
|
||||
row: int
|
||||
|
||||
last_row: int = session.query(
|
||||
last_row = session.query(
|
||||
func.max(PlaylistTracks.row)
|
||||
).filter_by(playlist_id=playlist.id).first()
|
||||
# if there are no rows, the above returns (None, ) which is True
|
||||
@ -480,11 +494,11 @@ class Tracks(Base):
|
||||
mtime: float = Column(Float, index=True)
|
||||
lastplayed: datetime = Column(DateTime, index=True, default=None)
|
||||
playlists: RelationshipProperty = relationship("PlaylistTracks",
|
||||
back_populates="tracks",
|
||||
lazy="joined")
|
||||
back_populates="tracks",
|
||||
lazy="joined")
|
||||
playdates: RelationshipProperty = relationship("Playdates",
|
||||
back_populates="tracks",
|
||||
lazy="joined")
|
||||
back_populates="tracks",
|
||||
lazy="joined")
|
||||
|
||||
def __init__(self, session: Session, path: str) -> None:
|
||||
self.path = path
|
||||
@ -572,10 +586,10 @@ class Tracks(Base):
|
||||
audio: AudioSegment = get_audio_segment(self.path)
|
||||
self.duration = len(audio)
|
||||
self.fade_at = round(fade_point(audio) / 1000,
|
||||
Config.MILLISECOND_SIGFIGS) * 1000
|
||||
Config.MILLISECOND_SIGFIGS) * 1000
|
||||
self.mtime = os.path.getmtime(self.path)
|
||||
self.silence_at = round(trailing_silence(audio) / 1000,
|
||||
Config.MILLISECOND_SIGFIGS) * 1000
|
||||
Config.MILLISECOND_SIGFIGS) * 1000
|
||||
self.start_gap = leading_silence(audio)
|
||||
session.add(self)
|
||||
session.commit()
|
||||
@ -597,16 +611,16 @@ class Tracks(Base):
|
||||
|
||||
return (
|
||||
session.query(cls)
|
||||
.filter(cls.artist.ilike(f"%{text}%"))
|
||||
.order_by(cls.title)
|
||||
.filter(cls.artist.ilike(f"%{text}%"))
|
||||
.order_by(cls.title)
|
||||
).all()
|
||||
|
||||
@classmethod
|
||||
def search_titles(cls, session: Session, text: str) -> List["Tracks"]:
|
||||
return (
|
||||
session.query(cls)
|
||||
.filter(cls.title.ilike(f"%{text}%"))
|
||||
.order_by(cls.title)
|
||||
.filter(cls.title.ilike(f"%{text}%"))
|
||||
.order_by(cls.title)
|
||||
).all()
|
||||
|
||||
def update_lastplayed(self, session: Session) -> None:
|
||||
|
||||
@ -86,8 +86,6 @@ class Music:
|
||||
p.stop()
|
||||
DEBUG(f"Releasing player {p=}", True)
|
||||
p.release()
|
||||
# Ensure we don't reference player after release
|
||||
p = None
|
||||
|
||||
self.fading -= 1
|
||||
|
||||
|
||||
@ -397,6 +397,9 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
if not dlg.plid:
|
||||
return
|
||||
|
||||
# TODO: just update dest playlist and call populate if
|
||||
# visible
|
||||
|
||||
# If destination playlist is visible, we need to add the moved
|
||||
# tracks to it. If not, they will be automatically loaded when
|
||||
# the playlistis opened.
|
||||
@ -753,7 +756,8 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
session.add(self.current_track)
|
||||
playtime: int = self.music.get_playtime()
|
||||
time_to_fade: int = (self.current_track.fade_at - playtime)
|
||||
time_to_silence: int = (self.current_track.silence_at - playtime)
|
||||
time_to_silence: int = (
|
||||
self.current_track.silence_at - playtime)
|
||||
time_to_end: int = (self.current_track.duration - playtime)
|
||||
|
||||
# Elapsed time
|
||||
@ -762,7 +766,8 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
helpers.ms_to_mmss(self.current_track.duration)
|
||||
)
|
||||
else:
|
||||
self.label_elapsed_timer.setText(helpers.ms_to_mmss(playtime))
|
||||
self.label_elapsed_timer.setText(
|
||||
helpers.ms_to_mmss(playtime))
|
||||
|
||||
# Time to fade
|
||||
self.label_fade_timer.setText(helpers.ms_to_mmss(time_to_fade))
|
||||
@ -935,9 +940,11 @@ class SelectPlaylistDialog(QDialog):
|
||||
self.plid = None
|
||||
|
||||
with Session() as session:
|
||||
record = Settings.get_int_settings(session, "select_playlist_dialog_width")
|
||||
record = Settings.get_int_settings(
|
||||
session, "select_playlist_dialog_width")
|
||||
width = record.f_int or 800
|
||||
record = Settings.get_int_settings(session, "select_playlist_dialog_height")
|
||||
record = Settings.get_int_settings(
|
||||
session, "select_playlist_dialog_height")
|
||||
height = record.f_int or 600
|
||||
self.resize(width, height)
|
||||
|
||||
@ -949,11 +956,13 @@ class SelectPlaylistDialog(QDialog):
|
||||
|
||||
def __del__(self): # review
|
||||
with Session() as session:
|
||||
record = Settings.get_int_settings(session, "select_playlist_dialog_height")
|
||||
record = Settings.get_int_settings(
|
||||
session, "select_playlist_dialog_height")
|
||||
if record.f_int != self.height():
|
||||
record.update(session, {'f_int': self.height()})
|
||||
|
||||
record = Settings.get_int_settings(session, "select_playlist_dialog_width")
|
||||
record = Settings.get_int_settings(
|
||||
session, "select_playlist_dialog_width")
|
||||
if record.f_int != self.width():
|
||||
record.update(session, {'f_int': self.width()})
|
||||
|
||||
|
||||
279
app/playlists.py
279
app/playlists.py
@ -15,8 +15,6 @@ from PyQt5.QtWidgets import (
|
||||
QTableWidget,
|
||||
QTableWidgetItem,
|
||||
)
|
||||
from sqlalchemy import inspect
|
||||
from sqlalchemy.orm.exc import DetachedInstanceError
|
||||
|
||||
import helpers
|
||||
import os
|
||||
@ -40,9 +38,9 @@ class RowMeta:
|
||||
CLEAR = 0
|
||||
NOTE = 1
|
||||
UNREADABLE = 2
|
||||
NEXT = 4
|
||||
CURRENT = 8
|
||||
PLAYED = 16
|
||||
NEXT = 3
|
||||
CURRENT = 4
|
||||
PLAYED = 5
|
||||
|
||||
|
||||
class PlaylistTab(QTableWidget):
|
||||
@ -142,7 +140,7 @@ class PlaylistTab(QTableWidget):
|
||||
self.cellEditingEnded.connect(self._cell_edit_ended)
|
||||
|
||||
# Now load our tracks and notes
|
||||
self._populate(session)
|
||||
self._populate(session, playlist)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
@ -180,7 +178,7 @@ class PlaylistTab(QTableWidget):
|
||||
# rows. Check and fix:
|
||||
row = 0 # So row is defined even if there are no rows in range
|
||||
for row in range(drop_row, drop_row + len(rows_to_move)):
|
||||
if row in self._meta_get_notes():
|
||||
if row in self._get_notes_rows():
|
||||
self.setSpan(
|
||||
row, self.COL_NOTE, self.NOTE_ROW_SPAN, self.NOTE_COL_SPAN)
|
||||
|
||||
@ -217,13 +215,13 @@ class PlaylistTab(QTableWidget):
|
||||
if item is not None:
|
||||
row = item.row()
|
||||
DEBUG(f"playlist.eventFilter(): Right-click on row {row}")
|
||||
current = row == self._meta_get_current()
|
||||
next_row = row == self._meta_get_next()
|
||||
current = row == self._get_current_track_row()
|
||||
next_row = row == self._get_next_track_row()
|
||||
self.menu = QMenu(self)
|
||||
act_info = self.menu.addAction('Info')
|
||||
act_info.triggered.connect(lambda: self._info_row(row))
|
||||
self.menu.addSeparator()
|
||||
if row not in self._meta_get_notes():
|
||||
if row not in self._get_notes_rows():
|
||||
if not current and not next_row:
|
||||
act_setnext = self.menu.addAction("Set next")
|
||||
act_setnext.triggered.connect(
|
||||
@ -375,12 +373,12 @@ class PlaylistTab(QTableWidget):
|
||||
stop_item: QTableWidgetItem = QTableWidgetItem()
|
||||
self.setItem(row, self.COL_END_TIME, stop_item)
|
||||
|
||||
# Attach track object to row
|
||||
self._set_row_content(row, track)
|
||||
# Attach track.id object to row
|
||||
self._set_row_content(row, track.id)
|
||||
|
||||
# Mark track if file is unreadable
|
||||
if not self._file_is_readable(track.path):
|
||||
self._meta_set_unreadable(row)
|
||||
self._set_unreadable_row(row)
|
||||
# Scroll to new row
|
||||
self.scrollToItem(title_item, QAbstractItemView.PositionAtCenter)
|
||||
|
||||
@ -418,11 +416,11 @@ class PlaylistTab(QTableWidget):
|
||||
self.current_track_start_time = datetime.now()
|
||||
|
||||
# Mark next-track row as current
|
||||
current_row = self._meta_get_next()
|
||||
self._meta_set_current(current_row)
|
||||
current_row = self._get_next_track_row()
|
||||
self._set_current_track_row(current_row)
|
||||
|
||||
# Mark current row as played
|
||||
self._meta_set_played(current_row)
|
||||
self._set_played_row(current_row)
|
||||
|
||||
# Scroll to put current track in middle
|
||||
scroll_to = self.item(current_row, self.COL_MSS)
|
||||
@ -447,7 +445,7 @@ class PlaylistTab(QTableWidget):
|
||||
- Update display
|
||||
"""
|
||||
|
||||
self._meta_clear_current()
|
||||
self._clear_current_track_row()
|
||||
self.current_track_start_time = None
|
||||
|
||||
def save_playlist(self, session) -> None:
|
||||
@ -470,11 +468,11 @@ class PlaylistTab(QTableWidget):
|
||||
# Create dictionaries indexed by note_id
|
||||
playlist_notes: Dict[int, Notes] = {}
|
||||
database_notes: Dict[int, Notes] = {}
|
||||
notes_rows: List[int] = self._meta_get_notes()
|
||||
notes_rows: List[int] = self._get_notes_rows()
|
||||
|
||||
# PlaylistTab
|
||||
for row in notes_rows:
|
||||
note: Notes = self._get_row_object(row, session)
|
||||
note: Notes = self._get_row_notes_object(row, session)
|
||||
session.add(note)
|
||||
playlist_notes[note.id] = note
|
||||
|
||||
@ -512,9 +510,9 @@ class PlaylistTab(QTableWidget):
|
||||
for row in range(self.rowCount()):
|
||||
if row in notes_rows:
|
||||
continue
|
||||
track: Tracks = self.item(
|
||||
track_id: int = self.item(
|
||||
row, self.COL_USERDATA).data(self.CONTENT_OBJECT)
|
||||
self.playlist.add_track(session, track, row)
|
||||
self.playlist.add_track(session, track_id, row)
|
||||
|
||||
def select_next_row(self) -> None:
|
||||
"""
|
||||
@ -539,7 +537,7 @@ class PlaylistTab(QTableWidget):
|
||||
|
||||
# Don't select notes
|
||||
wrapped: bool = False
|
||||
while row in self._meta_get_notes():
|
||||
while row in self._get_notes_rows():
|
||||
row += 1
|
||||
if row >= self.rowCount():
|
||||
if wrapped:
|
||||
@ -580,7 +578,7 @@ class PlaylistTab(QTableWidget):
|
||||
|
||||
# Don't select notes
|
||||
wrapped: bool = False
|
||||
while row in self._meta_get_notes():
|
||||
while row in self._get_notes_rows():
|
||||
row -= 1
|
||||
if row < 0:
|
||||
if wrapped:
|
||||
@ -620,17 +618,17 @@ class PlaylistTab(QTableWidget):
|
||||
|
||||
if self.playlist not in session:
|
||||
session.add(self.playlist)
|
||||
DEBUG(f"playlist. update_display [{self.playlist=}]")
|
||||
DEBUG(f"playlist.update_display [{self.playlist=}]")
|
||||
|
||||
# Clear selection if required
|
||||
if clear_selection:
|
||||
self.clearSelection()
|
||||
|
||||
current_row: Optional[int] = self._meta_get_current()
|
||||
next_row: Optional[int] = self._meta_get_next()
|
||||
notes: Optional[List[int]] = self._meta_get_notes()
|
||||
played: Optional[List[int]] = self._meta_get_played()
|
||||
unreadable: Optional[List[int]] = self._meta_get_unreadable()
|
||||
current_row: Optional[int] = self._get_current_track_row()
|
||||
next_row: Optional[int] = self._get_next_track_row()
|
||||
notes: Optional[List[int]] = self._get_notes_rows()
|
||||
played: Optional[List[int]] = self._get_played_track_rows()
|
||||
unreadable: Optional[List[int]] = self._get_unreadable_track_rows()
|
||||
|
||||
last_played_str: Optional[str]
|
||||
last_playedtime: Optional[datetime]
|
||||
@ -697,7 +695,7 @@ class PlaylistTab(QTableWidget):
|
||||
last_played_str)
|
||||
|
||||
# Calculate next_start_time
|
||||
track = self._get_row_object(row, session)
|
||||
track = self._get_row_track_object(row, session)
|
||||
next_start_time = self._calculate_track_end_time(
|
||||
track, self.current_track_start_time)
|
||||
|
||||
@ -725,7 +723,7 @@ class PlaylistTab(QTableWidget):
|
||||
self._set_row_start_time(row, start_time)
|
||||
|
||||
# Set end time
|
||||
track = self._get_row_object(row, session)
|
||||
track = self._get_row_track_object(row, session)
|
||||
next_start_time = self._calculate_track_end_time(
|
||||
track, start_time)
|
||||
self._set_row_end_time(row, next_start_time)
|
||||
@ -739,7 +737,7 @@ class PlaylistTab(QTableWidget):
|
||||
|
||||
else:
|
||||
# This is a track row other than next or current
|
||||
track = self._get_row_object(row, session)
|
||||
track = self._get_row_track_object(row, session)
|
||||
if row in played:
|
||||
# Played today, so update last played column
|
||||
last_playedtime = Playdates.last_played(
|
||||
@ -777,11 +775,11 @@ class PlaylistTab(QTableWidget):
|
||||
|
||||
DEBUG(f"_audacity({row})")
|
||||
|
||||
if row in self._meta_get_notes():
|
||||
if row in self._get_notes_rows():
|
||||
return None
|
||||
|
||||
with Session() as session:
|
||||
track: Tracks = self._get_row_object(row, session)
|
||||
track: Tracks = self._get_row_track_object(row, session)
|
||||
open_in_audacity(track.path)
|
||||
|
||||
@staticmethod
|
||||
@ -810,11 +808,11 @@ class PlaylistTab(QTableWidget):
|
||||
|
||||
DEBUG(f"_copy_path({row})")
|
||||
|
||||
if row in self._meta_get_notes():
|
||||
if row in self._get_notes_rows():
|
||||
return None
|
||||
|
||||
with Session() as session:
|
||||
track: Optional[Tracks] = self._get_row_object(row, session)
|
||||
track: Optional[Tracks] = self._get_row_track_object(row, session)
|
||||
if track:
|
||||
cb: QApplication.clipboard = QApplication.clipboard()
|
||||
cb.clear(mode=cb.Clipboard)
|
||||
@ -832,12 +830,11 @@ class PlaylistTab(QTableWidget):
|
||||
DEBUG(f"_cell_changed({row=}, {column=}, {new_text=}")
|
||||
|
||||
with Session() as session:
|
||||
row_object: Union[Tracks, Notes] = self._get_row_object(
|
||||
row, session)
|
||||
if row in self._meta_get_notes():
|
||||
if row in self._get_notes_rows():
|
||||
# Save change to database
|
||||
DEBUG(f"Notes.update_note: saving new note text '{new_text=}'")
|
||||
row_object.update_note(session, row, new_text)
|
||||
note: Notes = self._get_notes_row_object(row, session)
|
||||
note.update_note(session, row, new_text)
|
||||
# Set/clear row start time accordingly
|
||||
start_time = self._get_note_text_time(new_text)
|
||||
if start_time:
|
||||
@ -854,10 +851,11 @@ class PlaylistTab(QTableWidget):
|
||||
"start time"
|
||||
)
|
||||
else:
|
||||
track: Tracks = self._get_track_row_object(row, session)
|
||||
if column == self.COL_ARTIST:
|
||||
row_object.update_artist(session, artist=new_text)
|
||||
track.update_artist(session, artist=new_text)
|
||||
elif column == self.COL_TITLE:
|
||||
row_object.update_title(session, title=new_text)
|
||||
track.update_title(session, title=new_text)
|
||||
else:
|
||||
ERROR("_cell_changed(): unrecognised column")
|
||||
|
||||
@ -896,7 +894,7 @@ class PlaylistTab(QTableWidget):
|
||||
set(item.row() for item in self.selectedItems())
|
||||
)
|
||||
rows_to_delete: List[int] = []
|
||||
note_rows: Optional[List[int]] = self._meta_get_notes()
|
||||
note_rows: Optional[List[int]] = self._get_notes_rows()
|
||||
row: int
|
||||
row_object: Union[Tracks, Notes]
|
||||
|
||||
@ -913,15 +911,15 @@ class PlaylistTab(QTableWidget):
|
||||
if msg.exec() == QMessageBox.Yes:
|
||||
rows_to_delete.append(row)
|
||||
|
||||
# delete in reverse row order so row numbers don't
|
||||
# change
|
||||
for row in sorted(rows_to_delete, reverse=True):
|
||||
row_object = self._get_row_object(row, session)
|
||||
if row in note_rows:
|
||||
row_object.delete_note(session)
|
||||
else:
|
||||
self.remove_track(session, row)
|
||||
self.removeRow(row)
|
||||
# delete in reverse row order so row numbers don't
|
||||
# change
|
||||
for row in sorted(rows_to_delete, reverse=True):
|
||||
if row in note_rows:
|
||||
note: Notes = self._get_row_notes_object(row, session)
|
||||
note.delete_note(session)
|
||||
else:
|
||||
self.remove_track(session, row)
|
||||
self.removeRow(row)
|
||||
|
||||
self.save_playlist(session)
|
||||
self.update_display(session)
|
||||
@ -963,14 +961,21 @@ class PlaylistTab(QTableWidget):
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
def _get_row_object(self, row: int, session: Session) \
|
||||
-> Union[Tracks, Notes]:
|
||||
"""Return content associated with this row"""
|
||||
def _get_row_track_object(self, row: int, session: Session) \
|
||||
-> Optional[Tracks]:
|
||||
"""Return track associated with this row"""
|
||||
|
||||
obj = self.item(row, self.COL_USERDATA).data(self.CONTENT_OBJECT)
|
||||
if obj not in session:
|
||||
session.add(obj)
|
||||
return obj
|
||||
track_id = self.item(row, self.COL_USERDATA).data(self.CONTENT_OBJECT)
|
||||
track = Tracks.get_by_id(session, track_id)
|
||||
return track
|
||||
|
||||
def _get_row_notes_object(self, row: int, session: Session) \
|
||||
-> Optional[Notes]:
|
||||
"""Return note associated with this row"""
|
||||
|
||||
note_id = self.item(row, self.COL_USERDATA).data(self.CONTENT_OBJECT)
|
||||
note = Notes.get_by_id(session, note_id)
|
||||
return note
|
||||
|
||||
def _get_row_start_time(self, row: int) -> Optional[datetime]:
|
||||
try:
|
||||
@ -990,12 +995,11 @@ class PlaylistTab(QTableWidget):
|
||||
txt: str
|
||||
|
||||
with Session() as session:
|
||||
row_object: Union[Tracks, Notes] = self._get_row_object(
|
||||
row, session)
|
||||
if row in self._meta_get_notes():
|
||||
txt = row_object.note
|
||||
if row in self._get_notes_rows():
|
||||
note: Notes = self._get_row_notes_object(row, session)
|
||||
txt = note.note
|
||||
else:
|
||||
track = row_object
|
||||
track: Tracks = self._get_row_track_object(row, session)
|
||||
txt = (
|
||||
f"Title: {track.title}\n"
|
||||
f"Artist: {track.artist}\n"
|
||||
@ -1038,13 +1042,14 @@ class PlaylistTab(QTableWidget):
|
||||
# Add text of note from title column onwards
|
||||
titleitem: QTableWidgetItem = QTableWidgetItem(note.note)
|
||||
self.setItem(row, self.COL_NOTE, titleitem)
|
||||
self.setSpan(row, self.COL_NOTE, self.NOTE_ROW_SPAN, self.NOTE_COL_SPAN)
|
||||
self.setSpan(row, self.COL_NOTE, self.NOTE_ROW_SPAN,
|
||||
self.NOTE_COL_SPAN)
|
||||
|
||||
# Attach note object to row
|
||||
self._set_row_content(row, note)
|
||||
# Attach note id to row
|
||||
self._set_row_content(row, note.id)
|
||||
|
||||
# Mark row as a Note row
|
||||
self._meta_set_note(row)
|
||||
self._set_note_row(row)
|
||||
|
||||
# Scroll to new row
|
||||
self.scrollToItem(titleitem, QAbstractItemView.PositionAtCenter)
|
||||
@ -1088,13 +1093,13 @@ class PlaylistTab(QTableWidget):
|
||||
"""
|
||||
|
||||
if starting_row is None:
|
||||
current_row = self._meta_get_current()
|
||||
current_row = self._get_current_track_row()
|
||||
if current_row is not None:
|
||||
starting_row = current_row + 1
|
||||
else:
|
||||
starting_row = 0
|
||||
notes_rows = self._meta_get_notes()
|
||||
played_rows = self._meta_get_played()
|
||||
notes_rows = self._get_notes_rows()
|
||||
played_rows = self._get_played_track_rows()
|
||||
for row in range(starting_row, self.rowCount()):
|
||||
if row in notes_rows or row in played_rows:
|
||||
continue
|
||||
@ -1109,16 +1114,16 @@ class PlaylistTab(QTableWidget):
|
||||
if row is None:
|
||||
raise ValueError(f"_meta_clear_attribute({row=}, {attribute=})")
|
||||
|
||||
new_metadata: int = self._meta_get(row) ^ attribute
|
||||
new_metadata: int = self._meta_get(row) & ~(1 << attribute)
|
||||
self.item(row, self.COL_USERDATA).setData(
|
||||
self.ROW_METADATA, new_metadata)
|
||||
|
||||
def _meta_clear_current(self) -> None:
|
||||
def _clear_current_track_row(self) -> None:
|
||||
"""
|
||||
Clear current row if there is one.
|
||||
"""
|
||||
|
||||
current_row: Optional[int] = self._meta_get_current()
|
||||
current_row: Optional[int] = self._get_current_track_row()
|
||||
if current_row is not None:
|
||||
self._meta_clear_attribute(current_row, RowMeta.CURRENT)
|
||||
# Reset row colour
|
||||
@ -1134,11 +1139,11 @@ class PlaylistTab(QTableWidget):
|
||||
Clear next row if there is one.
|
||||
"""
|
||||
|
||||
next_row: Optional[int] = self._meta_get_next()
|
||||
next_row: Optional[int] = self._get_next_track_row()
|
||||
if next_row is not None:
|
||||
self._meta_clear_attribute(next_row, RowMeta.NEXT)
|
||||
|
||||
def _meta_clear_played(self, row: int) -> None:
|
||||
def _clear_played_row_status(self, row: int) -> None:
|
||||
"""Clear played status on row"""
|
||||
|
||||
self._meta_clear_attribute(row, RowMeta.PLAYED)
|
||||
@ -1148,31 +1153,51 @@ class PlaylistTab(QTableWidget):
|
||||
|
||||
return self.item(row, self.COL_USERDATA).data(self.ROW_METADATA)
|
||||
|
||||
def _meta_get_current(self) -> Optional[int]:
|
||||
def _get_current_track_row(self) -> Optional[int]:
|
||||
"""Return row marked as current, or None"""
|
||||
|
||||
return self._meta_search(RowMeta.CURRENT)
|
||||
|
||||
def _meta_get_next(self) -> Optional[int]:
|
||||
def _get_next_track_row(self) -> Optional[int]:
|
||||
"""Return row marked as next, or None"""
|
||||
|
||||
return self._meta_search(RowMeta.NEXT)
|
||||
|
||||
def _meta_get_notes(self) -> Optional[List[int]]:
|
||||
def _get_notes_rows(self) -> Optional[List[int]]:
|
||||
"""Return rows marked as notes, or None"""
|
||||
|
||||
return self._meta_search(RowMeta.NOTE, one=False)
|
||||
|
||||
def _meta_get_played(self) -> Optional[List[int]]:
|
||||
def _get_track_rows(self) -> Optional[List[int]]:
|
||||
"""Return rows marked as tracks, or None"""
|
||||
|
||||
return self._meta_notset(RowMeta.NOTE)
|
||||
|
||||
def _get_played_track_rows(self) -> Optional[List[int]]:
|
||||
"""Return rows marked as played, or None"""
|
||||
|
||||
return self._meta_search(RowMeta.PLAYED, one=False)
|
||||
|
||||
def _meta_get_unreadable(self) -> Optional[List[int]]:
|
||||
def _get_unreadable_track_rows(self) -> Optional[List[int]]:
|
||||
"""Return rows marked as unreadable, or None"""
|
||||
|
||||
return self._meta_search(RowMeta.UNREADABLE, one=False)
|
||||
|
||||
def _meta_notset(self, metadata: int) -> Union[List[int]]:
|
||||
"""
|
||||
Search rows for metadata not set.
|
||||
|
||||
Return a list of matching row numbers.
|
||||
"""
|
||||
|
||||
matches = []
|
||||
for row in range(self.rowCount()):
|
||||
if self._meta_get(row):
|
||||
if not self._meta_get(row) & (1 << metadata):
|
||||
matches.append(row)
|
||||
|
||||
return matches
|
||||
|
||||
def _meta_search(self, metadata: int, one: bool = True) -> Union[
|
||||
List[int], int, None]:
|
||||
"""
|
||||
@ -1187,7 +1212,7 @@ class PlaylistTab(QTableWidget):
|
||||
matches = []
|
||||
for row in range(self.rowCount()):
|
||||
if self._meta_get(row):
|
||||
if self._meta_get(row) & metadata:
|
||||
if self._meta_get(row) & (1 << metadata):
|
||||
matches.append(row)
|
||||
|
||||
if not one:
|
||||
@ -1212,40 +1237,40 @@ class PlaylistTab(QTableWidget):
|
||||
|
||||
current_metadata: int = self._meta_get(row)
|
||||
if not current_metadata:
|
||||
new_metadata = attribute
|
||||
new_metadata = (1 << attribute)
|
||||
else:
|
||||
new_metadata: int = self._meta_get(row) | attribute
|
||||
new_metadata: int = self._meta_get(row) | (1 << attribute)
|
||||
self.item(row, self.COL_USERDATA).setData(
|
||||
self.ROW_METADATA, new_metadata)
|
||||
|
||||
def _meta_set_current(self, row: int) -> None:
|
||||
def _set_current_track_row(self, row: int) -> None:
|
||||
"""Mark this row as current track"""
|
||||
|
||||
self._meta_clear_current()
|
||||
self._clear_current_track_row()
|
||||
self._meta_set_attribute(row, RowMeta.CURRENT)
|
||||
|
||||
def _meta_set_next(self, row: int) -> None:
|
||||
def _set_next_track_row(self, row: int) -> None:
|
||||
"""Mark this row as next track"""
|
||||
|
||||
self._meta_clear_next()
|
||||
self._meta_set_attribute(row, RowMeta.NEXT)
|
||||
|
||||
def _meta_set_note(self, row: int) -> None:
|
||||
def _set_note_row(self, row: int) -> None:
|
||||
"""Mark this row as a note"""
|
||||
|
||||
self._meta_set_attribute(row, RowMeta.NOTE)
|
||||
|
||||
def _meta_set_played(self, row: int) -> None:
|
||||
def _set_played_row(self, row: int) -> None:
|
||||
"""Mark this row as played"""
|
||||
|
||||
self._meta_set_attribute(row, RowMeta.PLAYED)
|
||||
|
||||
def _meta_set_unreadable(self, row: int) -> None:
|
||||
def _set_unreadable_row(self, row: int) -> None:
|
||||
"""Mark this row as unreadable"""
|
||||
|
||||
self._meta_set_attribute(row, RowMeta.UNREADABLE)
|
||||
|
||||
def _populate(self, session: Session) -> None:
|
||||
def _populate(self, session: Session, playlist: Playlists) -> None:
|
||||
"""
|
||||
Populate from the associated playlist object
|
||||
|
||||
@ -1261,16 +1286,11 @@ class PlaylistTab(QTableWidget):
|
||||
row: int
|
||||
track: Tracks
|
||||
|
||||
# Make sure the database object is usable
|
||||
insp = inspect(self.playlist)
|
||||
if insp.detached:
|
||||
session.add(self.playlist)
|
||||
assert insp.persistent
|
||||
if playlist not in session:
|
||||
session.add(playlist)
|
||||
|
||||
for row, track in self.playlist.tracks.items():
|
||||
data.append(([row], track))
|
||||
# Add track to session to expose attributes
|
||||
session.add(track)
|
||||
for note in self.playlist.notes:
|
||||
data.append(([note.row], note))
|
||||
|
||||
@ -1302,14 +1322,12 @@ class PlaylistTab(QTableWidget):
|
||||
|
||||
DEBUG(f"_rescan({row=})")
|
||||
|
||||
if row in self._meta_get_notes():
|
||||
return None
|
||||
|
||||
with Session() as session:
|
||||
track: Tracks = self._get_row_object(row, session)
|
||||
if track:
|
||||
track.rescan(session)
|
||||
self._update_row(session, row, track)
|
||||
for row in self._get_track_rows():
|
||||
track: Tracks = self._get_row_track_object(row, session)
|
||||
if track:
|
||||
track.rescan(session)
|
||||
self._update_row(session, row, track)
|
||||
|
||||
def _select_event(self) -> None:
|
||||
"""
|
||||
@ -1317,24 +1335,21 @@ class PlaylistTab(QTableWidget):
|
||||
If multiple rows are selected, display sum of durations in status bar.
|
||||
"""
|
||||
|
||||
row_set: Set[int] = set([item.row() for item in self.selectedItems()])
|
||||
note_row_set: Set[int] = set(self._meta_get_notes())
|
||||
track_rows = list(row_set - note_row_set)
|
||||
tracks: List[Tracks]
|
||||
# Get the row number of all selected items and put into a set
|
||||
# to deduplicate
|
||||
sel_rows: Set[int] = set([item.row() for item in self.selectedItems()])
|
||||
notes_rows: Set[int] = set(self._get_notes_rows())
|
||||
ms: int = 0
|
||||
with Session() as session:
|
||||
for row in (sel_rows - notes_rows):
|
||||
ms += self._get_row_track_object(row, session).duration
|
||||
|
||||
with Session() as session: # checked
|
||||
tracks = [self._get_row_object(row, session) for row in track_rows]
|
||||
for track in tracks:
|
||||
if track not in session:
|
||||
session.add(track)
|
||||
ms: int = sum([track.duration for track in tracks])
|
||||
|
||||
# Only paint message if there are selected track rows
|
||||
if ms > 0:
|
||||
self.parent.lblSumPlaytime.setText(
|
||||
f"Selected duration: {helpers.ms_to_mmss(ms)}")
|
||||
else:
|
||||
self.parent.lblSumPlaytime.setText("")
|
||||
# Only paint message if there are selected track rows
|
||||
if ms > 0:
|
||||
self.parent.lblSumPlaytime.setText(
|
||||
f"Selected duration: {helpers.ms_to_mmss(ms)}")
|
||||
else:
|
||||
self.parent.lblSumPlaytime.setText("")
|
||||
|
||||
def _set_column_widths(self) -> None:
|
||||
"""Column widths from settings"""
|
||||
@ -1342,7 +1357,7 @@ class PlaylistTab(QTableWidget):
|
||||
with Session() as session:
|
||||
for column in range(self.columnCount()):
|
||||
name: str = f"playlist_col_{str(column)}_width"
|
||||
record: int = Settings.get_int_settings(session, name)
|
||||
record: Settings = Settings.get_int_settings(session, name)
|
||||
if record and record.f_int is not None:
|
||||
self.setColumnWidth(column, record.f_int)
|
||||
else:
|
||||
@ -1364,19 +1379,19 @@ class PlaylistTab(QTableWidget):
|
||||
|
||||
with Session() as session:
|
||||
# Check row is a track row
|
||||
if row in self._meta_get_notes():
|
||||
if row in self._get_notes_rows():
|
||||
return None
|
||||
track: Tracks = self._get_row_object(row, session)
|
||||
track: Tracks = self._get_row_track_object(row, session)
|
||||
if not track:
|
||||
return None
|
||||
|
||||
# Check track is readable
|
||||
if not self._file_is_readable(track.path):
|
||||
self._meta_set_unreadable(row)
|
||||
self._set_unreadable_row(row)
|
||||
return None
|
||||
|
||||
# Mark as next track
|
||||
self._meta_set_next(row)
|
||||
self._set_next_track_row(row)
|
||||
|
||||
# Notify musicmuster
|
||||
self.parent.this_is_the_next_track(self, track)
|
||||
@ -1405,13 +1420,13 @@ class PlaylistTab(QTableWidget):
|
||||
if self.item(row, j):
|
||||
self.item(row, j).setBackground(colour)
|
||||
|
||||
def _set_row_content(self, row: int, content: Union[Tracks, Notes]) \
|
||||
-> None:
|
||||
def _set_row_content(self, row: int, object_id: int) -> None:
|
||||
"""Set content associated with this row"""
|
||||
|
||||
assert self.item(row, self.COL_USERDATA)
|
||||
|
||||
self.item(row, self.COL_USERDATA).setData(self.CONTENT_OBJECT, content)
|
||||
self.item(row, self.COL_USERDATA).setData(
|
||||
self.CONTENT_OBJECT, object_id)
|
||||
|
||||
def _set_row_end_time(self, row: int, time: Optional[datetime]) -> None:
|
||||
"""Set passed row end time to passed time"""
|
||||
@ -1446,10 +1461,10 @@ class PlaylistTab(QTableWidget):
|
||||
|
||||
# Need to allow multiple rows to be selected
|
||||
self.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
||||
notes_rows: List[int] = self._meta_get_notes()
|
||||
notes_rows: List[int] = self._get_notes_rows()
|
||||
self.clearSelection()
|
||||
|
||||
played_rows: List[int] = self._meta_get_played()
|
||||
played_rows: List[int] = self._get_played_track_rows()
|
||||
for row in range(self.rowCount()):
|
||||
if row in notes_rows:
|
||||
continue
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtGui import QFontMetrics, QPainter
|
||||
from PyQt5.QtWidgets import QLabel
|
||||
|
||||
|
||||
class ElideLabel(QLabel):
|
||||
|
||||
@ -6,12 +6,11 @@ import shutil
|
||||
import tempfile
|
||||
|
||||
from config import Config
|
||||
from helpers import show_warning
|
||||
from log import DEBUG, INFO
|
||||
from models import Notes, Playdates, Session, Tracks
|
||||
from mutagen.flac import FLAC
|
||||
from mutagen.mp3 import MP3
|
||||
from pydub import AudioSegment, effects
|
||||
from pydub import effects
|
||||
|
||||
# Globals (I know)
|
||||
messages = []
|
||||
|
||||
@ -5,8 +5,8 @@ from models import Tracks
|
||||
|
||||
|
||||
def test_fade_point():
|
||||
test_track_path = "../testdata/isa.mp3"
|
||||
test_track_data = "../testdata/isa.py"
|
||||
test_track_path = "testdata/isa.mp3"
|
||||
test_track_data = "testdata/isa.py"
|
||||
|
||||
audio_segment = get_audio_segment(test_track_path)
|
||||
assert audio_segment
|
||||
@ -23,8 +23,8 @@ def test_fade_point():
|
||||
|
||||
|
||||
def test_get_tags():
|
||||
test_track_path = "../testdata/mom.mp3"
|
||||
test_track_data = "../testdata/mom.py"
|
||||
test_track_path = "testdata/mom.mp3"
|
||||
test_track_data = "testdata/mom.py"
|
||||
|
||||
tags = get_tags(test_track_path)
|
||||
|
||||
@ -49,8 +49,8 @@ def test_get_relative_date():
|
||||
|
||||
|
||||
def test_leading_silence():
|
||||
test_track_path = "../testdata/isa.mp3"
|
||||
test_track_data = "../testdata/isa.py"
|
||||
test_track_path = "testdata/isa.mp3"
|
||||
test_track_data = "testdata/isa.py"
|
||||
|
||||
audio_segment = get_audio_segment(test_track_path)
|
||||
assert audio_segment
|
||||
@ -69,4 +69,4 @@ def test_leading_silence():
|
||||
def test_ms_to_mmss():
|
||||
assert ms_to_mmss(None) == "-"
|
||||
assert ms_to_mmss(59600) == "0:59"
|
||||
assert ms_to_mmss((5 * 60 * 1000) + 23000) == "5:23"
|
||||
assert ms_to_mmss((5 * 60 * 1000) + 23000) == "5:23"
|
||||
|
||||
@ -172,7 +172,7 @@ def test_playlist_add_track(session):
|
||||
|
||||
row = 17
|
||||
|
||||
playlist.add_track(session, track, row)
|
||||
playlist.add_track(session, track.id, row)
|
||||
|
||||
assert len(playlist.tracks) == 1
|
||||
playlist_track = playlist.tracks[row]
|
||||
@ -192,8 +192,8 @@ def test_playlist_tracks(session):
|
||||
track2_row = 29
|
||||
track2 = Tracks(session, track2_path)
|
||||
|
||||
playlist.add_track(session, track1, track1_row)
|
||||
playlist.add_track(session, track2, track2_row)
|
||||
playlist.add_track(session, track1.id, track1_row)
|
||||
playlist.add_track(session, track2.id, track2_row)
|
||||
|
||||
tracks = playlist.tracks
|
||||
assert tracks[track1_row] == track1
|
||||
@ -269,7 +269,7 @@ def test_playlist_remove_tracks(session):
|
||||
# Add all tracks to both playlists
|
||||
for p in [playlist1, playlist2]:
|
||||
for t in [track1, track2, track3]:
|
||||
p.add_track(session, t)
|
||||
p.add_track(session, t.id)
|
||||
|
||||
assert len(playlist1.tracks) == 3
|
||||
assert len(playlist2.tracks) == 3
|
||||
@ -295,9 +295,9 @@ def test_playlist_get_track_playlists(session):
|
||||
track2 = Tracks(session, track2_path)
|
||||
|
||||
# Put track1 in both playlists, track2 only in playlist1
|
||||
playlist1.add_track(session, track1)
|
||||
playlist2.add_track(session, track1)
|
||||
playlist1.add_track(session, track2)
|
||||
playlist1.add_track(session, track1.id)
|
||||
playlist2.add_track(session, track1.id)
|
||||
playlist1.add_track(session, track2.id)
|
||||
|
||||
playlists_track1 = track1.playlists
|
||||
playlists_track2 = track2.playlists
|
||||
@ -324,8 +324,8 @@ def test_playlisttracks_move_track(session):
|
||||
track1 = Tracks(session, track1_path)
|
||||
|
||||
# Add both to playlist1 and check
|
||||
playlist1.add_track(session, track1, track1_row)
|
||||
playlist1.add_track(session, track2, track2_row)
|
||||
playlist1.add_track(session, track1.id, track1_row)
|
||||
playlist1.add_track(session, track2.id, track2_row)
|
||||
|
||||
tracks = playlist1.tracks
|
||||
assert tracks[track1_row] == track1
|
||||
|
||||
@ -2,7 +2,6 @@ from PyQt5.QtCore import Qt
|
||||
|
||||
from app.playlists import Notes, PlaylistTab, Tracks
|
||||
from app.models import Playlists
|
||||
# from musicmuster import Window
|
||||
from musicmuster import Window
|
||||
|
||||
|
||||
@ -60,11 +59,11 @@ def test_meta_all_clear(qtbot, session):
|
||||
track3 = Tracks(session, track3_path)
|
||||
playlist_tab.insert_track(session, track3)
|
||||
|
||||
assert playlist_tab._meta_get_current() is None
|
||||
assert playlist_tab._meta_get_next() is None
|
||||
assert playlist_tab._meta_get_notes() == []
|
||||
assert playlist_tab._meta_get_played() == []
|
||||
assert len(playlist_tab._meta_get_unreadable()) == 3
|
||||
assert playlist_tab._get_current_track_row() is None
|
||||
assert playlist_tab._get_next_track_row() is None
|
||||
assert playlist_tab._get_notes_rows() == []
|
||||
assert playlist_tab._get_played_track_rows() == []
|
||||
assert len(playlist_tab._get_unreadable_track_rows()) == 3
|
||||
|
||||
|
||||
def test_meta(qtbot, session):
|
||||
@ -84,18 +83,18 @@ def test_meta(qtbot, session):
|
||||
track3 = Tracks(session, track3_path)
|
||||
playlist_tab.insert_track(session, track3)
|
||||
|
||||
assert len(playlist_tab._meta_get_unreadable()) == 3
|
||||
assert len(playlist_tab._get_unreadable_track_rows()) == 3
|
||||
|
||||
assert playlist_tab._meta_get_played() == []
|
||||
assert playlist_tab._meta_get_current() is None
|
||||
assert playlist_tab._meta_get_next() is None
|
||||
assert playlist_tab._meta_get_notes() == []
|
||||
assert playlist_tab._get_played_track_rows() == []
|
||||
assert playlist_tab._get_current_track_row() is None
|
||||
assert playlist_tab._get_next_track_row() is None
|
||||
assert playlist_tab._get_notes_rows() == []
|
||||
|
||||
playlist_tab._meta_set_played(0)
|
||||
assert playlist_tab._meta_get_played() == [0]
|
||||
assert playlist_tab._meta_get_current() is None
|
||||
assert playlist_tab._meta_get_next() is None
|
||||
assert playlist_tab._meta_get_notes() == []
|
||||
playlist_tab._set_played_row(0)
|
||||
assert playlist_tab._get_played_track_rows() == [0]
|
||||
assert playlist_tab._get_current_track_row() is None
|
||||
assert playlist_tab._get_next_track_row() is None
|
||||
assert playlist_tab._get_notes_rows() == []
|
||||
|
||||
# Add a note
|
||||
note_text = "my note"
|
||||
@ -103,40 +102,47 @@ def test_meta(qtbot, session):
|
||||
note = Notes(session, playlist.id, note_row, note_text)
|
||||
playlist_tab._insert_note(session, note)
|
||||
|
||||
assert playlist_tab._meta_get_played() == [0]
|
||||
assert playlist_tab._meta_get_current() is None
|
||||
assert playlist_tab._meta_get_next() is None
|
||||
assert playlist_tab._meta_get_notes() == [3]
|
||||
assert playlist_tab._get_played_track_rows() == [0]
|
||||
assert playlist_tab._get_current_track_row() is None
|
||||
assert playlist_tab._get_next_track_row() is None
|
||||
assert playlist_tab._get_notes_rows() == [3]
|
||||
|
||||
playlist_tab._meta_set_next(1)
|
||||
assert playlist_tab._meta_get_played() == [0]
|
||||
assert playlist_tab._meta_get_current() is None
|
||||
assert playlist_tab._meta_get_next() == 1
|
||||
assert playlist_tab._meta_get_notes() == [3]
|
||||
playlist_tab._set_next_track_row(1)
|
||||
assert playlist_tab._get_played_track_rows() == [0]
|
||||
assert playlist_tab._get_current_track_row() is None
|
||||
assert playlist_tab._get_next_track_row() == 1
|
||||
assert playlist_tab._get_notes_rows() == [3]
|
||||
|
||||
playlist_tab._meta_set_current(2)
|
||||
assert playlist_tab._meta_get_played() == [0]
|
||||
assert playlist_tab._meta_get_current() == 2
|
||||
assert playlist_tab._meta_get_next() == 1
|
||||
assert playlist_tab._meta_get_notes() == [3]
|
||||
playlist_tab._set_current_track_row(2)
|
||||
assert playlist_tab._get_played_track_rows() == [0]
|
||||
assert playlist_tab._get_current_track_row() == 2
|
||||
assert playlist_tab._get_next_track_row() == 1
|
||||
assert playlist_tab._get_notes_rows() == [3]
|
||||
|
||||
playlist_tab._meta_clear_played(0)
|
||||
assert playlist_tab._meta_get_played() == []
|
||||
assert playlist_tab._meta_get_current() == 2
|
||||
assert playlist_tab._meta_get_next() == 1
|
||||
assert playlist_tab._meta_get_notes() == [3]
|
||||
playlist_tab._clear_played_row_status(0)
|
||||
assert playlist_tab._get_played_track_rows() == []
|
||||
assert playlist_tab._get_current_track_row() == 2
|
||||
assert playlist_tab._get_next_track_row() == 1
|
||||
assert playlist_tab._get_notes_rows() == [3]
|
||||
|
||||
playlist_tab._meta_clear_next()
|
||||
assert playlist_tab._meta_get_played() == []
|
||||
assert playlist_tab._meta_get_current() == 2
|
||||
assert playlist_tab._meta_get_next() is None
|
||||
assert playlist_tab._meta_get_notes() == [3]
|
||||
assert playlist_tab._get_played_track_rows() == []
|
||||
assert playlist_tab._get_current_track_row() == 2
|
||||
assert playlist_tab._get_next_track_row() is None
|
||||
assert playlist_tab._get_notes_rows() == [3]
|
||||
|
||||
playlist_tab._meta_clear_current()
|
||||
assert playlist_tab._meta_get_played() == []
|
||||
assert playlist_tab._meta_get_current() is None
|
||||
assert playlist_tab._meta_get_next() is None
|
||||
assert playlist_tab._meta_get_notes() == [3]
|
||||
playlist_tab._clear_current_track_row()
|
||||
assert playlist_tab._get_played_track_rows() == []
|
||||
assert playlist_tab._get_current_track_row() is None
|
||||
assert playlist_tab._get_next_track_row() is None
|
||||
assert playlist_tab._get_notes_rows() == [3]
|
||||
|
||||
# Test clearing again has no effect
|
||||
playlist_tab._clear_current_track_row()
|
||||
assert playlist_tab._get_played_track_rows() == []
|
||||
assert playlist_tab._get_current_track_row() is None
|
||||
assert playlist_tab._get_next_track_row() is None
|
||||
assert playlist_tab._get_notes_rows() == [3]
|
||||
|
||||
|
||||
def test_clear_next(qtbot, session):
|
||||
@ -152,11 +158,11 @@ def test_clear_next(qtbot, session):
|
||||
track2 = Tracks(session, track2_path)
|
||||
playlist_tab.insert_track(session, track2)
|
||||
|
||||
playlist_tab._meta_set_next(1)
|
||||
assert playlist_tab._meta_get_next() == 1
|
||||
playlist_tab._set_next_track_row(1)
|
||||
assert playlist_tab._get_next_track_row() == 1
|
||||
|
||||
playlist_tab.clear_next()
|
||||
assert playlist_tab._meta_get_next() is None
|
||||
playlist_tab.clear_next(session)
|
||||
assert playlist_tab._get_next_track_row() is None
|
||||
|
||||
|
||||
def test_get_selected_row(qtbot, session):
|
||||
@ -174,10 +180,9 @@ def test_get_selected_row(qtbot, session):
|
||||
playlist_tab.insert_track(session, track2)
|
||||
|
||||
window = Window()
|
||||
window.show()
|
||||
qtbot.addWidget(playlist_tab)
|
||||
qtbot.wait_for_window_shown(playlist_tab)
|
||||
|
||||
with qtbot.waitExposed(window):
|
||||
window.show()
|
||||
row0_item0 = playlist_tab.item(0, 0)
|
||||
assert row0_item0 is not None
|
||||
rect = playlist_tab.visualItemRect(row0_item0)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user