Merge
This commit is contained in:
parent
a31718d2b9
commit
87f9e1e81b
136
app/models.py
136
app/models.py
@ -1,12 +1,11 @@
|
|||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
|
|
||||||
import dbconfig
|
|
||||||
import os.path
|
import os.path
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from dbconfig import Session
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from dbconfig import engine
|
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from pydub import AudioSegment
|
from pydub import AudioSegment
|
||||||
@ -40,10 +39,8 @@ from helpers import (
|
|||||||
)
|
)
|
||||||
from log import DEBUG, ERROR
|
from log import DEBUG, ERROR
|
||||||
|
|
||||||
Session = dbconfig.session
|
|
||||||
|
|
||||||
Base: DeclarativeMeta = declarative_base()
|
Base: DeclarativeMeta = declarative_base()
|
||||||
Base.metadata.create_all(engine)
|
|
||||||
|
|
||||||
|
|
||||||
# Database classes
|
# Database classes
|
||||||
@ -70,7 +67,7 @@ class NoteColours(Base):
|
|||||||
self.order = order
|
self.order = order
|
||||||
|
|
||||||
session.add(self)
|
session.add(self)
|
||||||
session.commit()
|
session.flush()
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return (
|
return (
|
||||||
@ -142,7 +139,7 @@ class Notes(Base):
|
|||||||
self.row = row
|
self.row = row
|
||||||
self.note = text
|
self.note = text
|
||||||
session.add(self)
|
session.add(self)
|
||||||
session.commit()
|
session.flush()
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return (
|
return (
|
||||||
@ -155,7 +152,7 @@ class Notes(Base):
|
|||||||
DEBUG(f"delete_note({self.id=}")
|
DEBUG(f"delete_note({self.id=}")
|
||||||
|
|
||||||
session.query(Notes).filter_by(id=self.id).delete()
|
session.query(Notes).filter_by(id=self.id).delete()
|
||||||
session.commit()
|
session.flush()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_by_id(cls, session: Session, note_id: int) -> Optional["Notes"]:
|
def get_by_id(cls, session: Session, note_id: int) -> Optional["Notes"]:
|
||||||
@ -181,7 +178,7 @@ class Notes(Base):
|
|||||||
self.row = row
|
self.row = row
|
||||||
if text:
|
if text:
|
||||||
self.note = text
|
self.note = text
|
||||||
session.commit()
|
session.flush()
|
||||||
|
|
||||||
|
|
||||||
class Playdates(Base):
|
class Playdates(Base):
|
||||||
@ -202,7 +199,7 @@ class Playdates(Base):
|
|||||||
self.track_id = track.id
|
self.track_id = track.id
|
||||||
track.update_lastplayed(session)
|
track.update_lastplayed(session)
|
||||||
session.add(self)
|
session.add(self)
|
||||||
session.commit()
|
session.flush()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def last_played(session: Session, track_id: int) -> Optional[datetime]:
|
def last_played(session: Session, track_id: int) -> Optional[datetime]:
|
||||||
@ -224,9 +221,8 @@ class Playdates(Base):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
session.query(Playdates).filter(
|
session.query(Playdates).filter(
|
||||||
Playdates.track_id == track_id,
|
Playdates.track_id == track_id).delete()
|
||||||
).delete()
|
session.flush()
|
||||||
session.commit()
|
|
||||||
|
|
||||||
|
|
||||||
class Playlists(Base):
|
class Playlists(Base):
|
||||||
@ -251,7 +247,7 @@ class Playlists(Base):
|
|||||||
def __init__(self, session: Session, name: str) -> None:
|
def __init__(self, session: Session, name: str) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
session.add(self)
|
session.add(self)
|
||||||
session.commit()
|
session.flush()
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"<Playlists(id={self.id}, name={self.name}>"
|
return f"<Playlists(id={self.id}, name={self.name}>"
|
||||||
@ -279,7 +275,7 @@ class Playlists(Base):
|
|||||||
|
|
||||||
self.loaded = False
|
self.loaded = False
|
||||||
session.add(self)
|
session.add(self)
|
||||||
session.commit()
|
session.flush()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_all(cls, session: Session) -> List["Playlists"]:
|
def get_all(cls, session: Session) -> List["Playlists"]:
|
||||||
@ -320,25 +316,38 @@ class Playlists(Base):
|
|||||||
|
|
||||||
self.loaded = True
|
self.loaded = True
|
||||||
self.last_used = datetime.now()
|
self.last_used = datetime.now()
|
||||||
session.commit()
|
session.flush()
|
||||||
|
|
||||||
|
def move_track(self, session: Session, rows: List[int],
|
||||||
|
to_playlist: "Playlists") -> None:
|
||||||
|
"""Move tracks to another playlist"""
|
||||||
|
|
||||||
|
for row in rows:
|
||||||
|
track = self.tracks[row]
|
||||||
|
to_playlist.add_track(session, track.id)
|
||||||
|
del self.tracks[row]
|
||||||
|
|
||||||
|
session.flush()
|
||||||
|
|
||||||
def remove_all_tracks(self, session: Session) -> None:
|
def remove_all_tracks(self, session: Session) -> None:
|
||||||
"""
|
"""
|
||||||
Remove all tracks from this playlist
|
Remove all tracks from this playlist
|
||||||
"""
|
"""
|
||||||
|
|
||||||
session.query(PlaylistTracks).filter(
|
self.tracks = {}
|
||||||
PlaylistTracks.playlist_id == self.id,
|
session.flush()
|
||||||
).delete()
|
|
||||||
session.commit()
|
|
||||||
|
|
||||||
def remove_track(self, session: Session, row: int) -> None:
|
def remove_track(self, session: Session, row: int) -> None:
|
||||||
DEBUG(f"Playlist.remove_track({self.id=}, {row=})")
|
DEBUG(f"Playlist.remove_track({self.id=}, {row=})")
|
||||||
|
|
||||||
session.query(PlaylistTracks).filter(
|
# Get tracks collection for this playlist
|
||||||
PlaylistTracks.playlist_id == self.id,
|
tracks_collections = self.tracks
|
||||||
PlaylistTracks.row == row
|
# Tracks are a dictionary of tracks keyed on row
|
||||||
).delete()
|
# number. Remove the relevant row.
|
||||||
|
del tracks_collections[row]
|
||||||
|
# Save the new tracks collection
|
||||||
|
self.tracks = tracks_collections
|
||||||
|
session.flush()
|
||||||
|
|
||||||
|
|
||||||
class PlaylistTracks(Base):
|
class PlaylistTracks(Base):
|
||||||
@ -355,7 +364,8 @@ class PlaylistTracks(Base):
|
|||||||
backref=backref(
|
backref=backref(
|
||||||
"playlist_tracks",
|
"playlist_tracks",
|
||||||
collection_class=attribute_mapped_collection("row"),
|
collection_class=attribute_mapped_collection("row"),
|
||||||
lazy="joined"
|
lazy="joined",
|
||||||
|
cascade="all, delete-orphan"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -368,45 +378,7 @@ class PlaylistTracks(Base):
|
|||||||
self.track_id = track_id
|
self.track_id = track_id
|
||||||
self.row = row
|
self.row = row
|
||||||
session.add(self)
|
session.add(self)
|
||||||
session.commit()
|
session.flush()
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def move_track(
|
|
||||||
session: Session, from_playlist_id: int, row: int,
|
|
||||||
to_playlist_id: int) -> None:
|
|
||||||
"""
|
|
||||||
Move track between playlists. This would be more efficient with
|
|
||||||
an ORM-enabled UPDATE statement, but this works just fine.
|
|
||||||
"""
|
|
||||||
DEBUG(
|
|
||||||
"PlaylistTracks.move_tracks("
|
|
||||||
f"{from_playlist_id=}, {row=}, {to_playlist_id=})"
|
|
||||||
)
|
|
||||||
|
|
||||||
new_row: int
|
|
||||||
max_row: Optional[int] = session.query(
|
|
||||||
func.max(PlaylistTracks.row)).filter(
|
|
||||||
PlaylistTracks.playlist_id == to_playlist_id).scalar()
|
|
||||||
if max_row is None:
|
|
||||||
# Destination playlist is empty; use row 0
|
|
||||||
new_row = 0
|
|
||||||
else:
|
|
||||||
# Destination playlist has tracks; add to end
|
|
||||||
new_row = max_row + 1
|
|
||||||
try:
|
|
||||||
record: PlaylistTracks = session.query(PlaylistTracks).filter(
|
|
||||||
PlaylistTracks.playlist_id == from_playlist_id,
|
|
||||||
PlaylistTracks.row == row).one()
|
|
||||||
except NoResultFound:
|
|
||||||
ERROR(
|
|
||||||
f"No rows matched in query: "
|
|
||||||
f"PlaylistTracks.playlist_id == {from_playlist_id}, "
|
|
||||||
f"PlaylistTracks.row == {row}"
|
|
||||||
)
|
|
||||||
return
|
|
||||||
record.playlist_id = to_playlist_id
|
|
||||||
record.row = new_row
|
|
||||||
session.commit()
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def next_free_row(session: Session, playlist: Playlists) -> int:
|
def next_free_row(session: Session, playlist: Playlists) -> int:
|
||||||
@ -449,14 +421,14 @@ class Settings(Base):
|
|||||||
int_setting.name = name
|
int_setting.name = name
|
||||||
int_setting.f_int = None
|
int_setting.f_int = None
|
||||||
session.add(int_setting)
|
session.add(int_setting)
|
||||||
session.commit()
|
session.flush()
|
||||||
return int_setting
|
return int_setting
|
||||||
|
|
||||||
def update(self, session: Session, data):
|
def update(self, session: Session, data):
|
||||||
for key, value in data.items():
|
for key, value in data.items():
|
||||||
assert hasattr(self, key)
|
assert hasattr(self, key)
|
||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
session.commit()
|
session.flush()
|
||||||
|
|
||||||
|
|
||||||
class Tracks(Base):
|
class Tracks(Base):
|
||||||
@ -479,10 +451,30 @@ class Tracks(Base):
|
|||||||
back_populates="tracks",
|
back_populates="tracks",
|
||||||
lazy="joined")
|
lazy="joined")
|
||||||
|
|
||||||
def __init__(self, session: Session, path: str) -> None:
|
def __init__(self,
|
||||||
|
session: Session,
|
||||||
|
path: str,
|
||||||
|
title: Optional[str] = None,
|
||||||
|
artist: Optional[str] = None,
|
||||||
|
duration: Optional[int] = None,
|
||||||
|
start_gap: Optional[int] = None,
|
||||||
|
fade_at: Optional[int] = None,
|
||||||
|
silence_at: Optional[int] = None,
|
||||||
|
mtime: Optional[float] = None,
|
||||||
|
lastplayed: Optional[datetime] = None,
|
||||||
|
) -> None:
|
||||||
self.path = path
|
self.path = path
|
||||||
|
self.title = title
|
||||||
|
self.artist = artist
|
||||||
|
self.duration = duration
|
||||||
|
self.start_gap = start_gap
|
||||||
|
self.fade_at = fade_at
|
||||||
|
self.silence_at = silence_at
|
||||||
|
self.mtime = mtime
|
||||||
|
self.lastplayed = lastplayed
|
||||||
|
|
||||||
session.add(self)
|
session.add(self)
|
||||||
session.commit()
|
session.flush()
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return (
|
return (
|
||||||
@ -571,7 +563,7 @@ class Tracks(Base):
|
|||||||
Config.MILLISECOND_SIGFIGS) * 1000
|
Config.MILLISECOND_SIGFIGS) * 1000
|
||||||
self.start_gap = leading_silence(audio)
|
self.start_gap = leading_silence(audio)
|
||||||
session.add(self)
|
session.add(self)
|
||||||
session.commit()
|
session.flush()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def remove_by_path(session: Session, path: str) -> None:
|
def remove_by_path(session: Session, path: str) -> None:
|
||||||
@ -581,7 +573,7 @@ class Tracks(Base):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
session.query(Tracks).filter(Tracks.path == path).delete()
|
session.query(Tracks).filter(Tracks.path == path).delete()
|
||||||
session.commit()
|
session.flush()
|
||||||
except IntegrityError as exception:
|
except IntegrityError as exception:
|
||||||
ERROR(f"Can't remove track with {path=} ({exception=})")
|
ERROR(f"Can't remove track with {path=} ({exception=})")
|
||||||
|
|
||||||
@ -605,17 +597,17 @@ class Tracks(Base):
|
|||||||
def update_lastplayed(self, session: Session) -> None:
|
def update_lastplayed(self, session: Session) -> None:
|
||||||
self.lastplayed = datetime.now()
|
self.lastplayed = datetime.now()
|
||||||
session.add(self)
|
session.add(self)
|
||||||
session.commit()
|
session.flush()
|
||||||
|
|
||||||
def update_artist(self, session: Session, artist: str) -> None:
|
def update_artist(self, session: Session, artist: str) -> None:
|
||||||
self.artist = artist
|
self.artist = artist
|
||||||
session.add(self)
|
session.add(self)
|
||||||
session.commit()
|
session.flush()
|
||||||
|
|
||||||
def update_title(self, session: Session, title: str) -> None:
|
def update_title(self, session: Session, title: str) -> None:
|
||||||
self.title = title
|
self.title = title
|
||||||
session.add(self)
|
session.add(self)
|
||||||
session.commit()
|
session.flush()
|
||||||
|
|
||||||
def update_path(self, newpath: str) -> None:
|
def update_path(self, newpath: str) -> None:
|
||||||
self.path = newpath
|
self.path = newpath
|
||||||
|
|||||||
@ -23,6 +23,7 @@ from PyQt5.QtWidgets import (
|
|||||||
QMainWindow,
|
QMainWindow,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
import dbconfig
|
||||||
import helpers
|
import helpers
|
||||||
import music
|
import music
|
||||||
|
|
||||||
@ -979,15 +980,13 @@ class SelectPlaylistDialog(QDialog):
|
|||||||
self.accept()
|
self.accept()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
if __name__ == "__main__":
|
||||||
try:
|
try:
|
||||||
|
Base.metadata.create_all(dbconfig.engine)
|
||||||
|
Session = dbconfig.Session
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
win = Window()
|
win = Window()
|
||||||
win.show()
|
win.show()
|
||||||
sys.exit(app.exec())
|
sys.exit(app.exec())
|
||||||
except Exception:
|
except Exception:
|
||||||
EXCEPTION("Unhandled Exception caught by musicmuster.main()")
|
EXCEPTION("Unhandled Exception caught by musicmuster.main()")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
|
|||||||
@ -27,11 +27,11 @@ from models import (
|
|||||||
Notes,
|
Notes,
|
||||||
Playdates,
|
Playdates,
|
||||||
Playlists,
|
Playlists,
|
||||||
Session,
|
|
||||||
Settings,
|
Settings,
|
||||||
Tracks,
|
Tracks,
|
||||||
NoteColours
|
NoteColours
|
||||||
)
|
)
|
||||||
|
from dbconfig import Session
|
||||||
|
|
||||||
|
|
||||||
class RowMeta:
|
class RowMeta:
|
||||||
@ -101,7 +101,7 @@ class PlaylistTab(QTableWidget):
|
|||||||
self.setHorizontalHeaderItem(7, item)
|
self.setHorizontalHeaderItem(7, item)
|
||||||
self.horizontalHeader().setMinimumSectionSize(0)
|
self.horizontalHeader().setMinimumSectionSize(0)
|
||||||
|
|
||||||
self._set_column_widths()
|
self._set_column_widths(session)
|
||||||
self.setHorizontalHeaderLabels([
|
self.setHorizontalHeaderLabels([
|
||||||
Config.COLUMN_NAME_AUTOPLAY,
|
Config.COLUMN_NAME_AUTOPLAY,
|
||||||
Config.COLUMN_NAME_LEADING_SILENCE,
|
Config.COLUMN_NAME_LEADING_SILENCE,
|
||||||
@ -1368,7 +1368,7 @@ class PlaylistTab(QTableWidget):
|
|||||||
ms: int = 0
|
ms: int = 0
|
||||||
with Session() as session:
|
with Session() as session:
|
||||||
for row in (sel_rows - notes_rows):
|
for row in (sel_rows - notes_rows):
|
||||||
ms += self._get_row_track_object(row, session).duration
|
ms += self._get_row_track_object(row, session).duration or 0
|
||||||
|
|
||||||
# Only paint message if there are selected track rows
|
# Only paint message if there are selected track rows
|
||||||
if ms > 0:
|
if ms > 0:
|
||||||
@ -1398,17 +1398,16 @@ class PlaylistTab(QTableWidget):
|
|||||||
# Reset extended selection
|
# Reset extended selection
|
||||||
self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||||
|
|
||||||
def _set_column_widths(self) -> None:
|
def _set_column_widths(self, session: Session) -> None:
|
||||||
"""Column widths from settings"""
|
"""Column widths from settings"""
|
||||||
|
|
||||||
with Session() as session:
|
for column in range(self.columnCount()):
|
||||||
for column in range(self.columnCount()):
|
name: str = f"playlist_col_{str(column)}_width"
|
||||||
name: str = f"playlist_col_{str(column)}_width"
|
record: Settings = Settings.get_int_settings(session, name)
|
||||||
record: Settings = Settings.get_int_settings(session, name)
|
if record and record.f_int is not None:
|
||||||
if record and record.f_int is not None:
|
self.setColumnWidth(column, record.f_int)
|
||||||
self.setColumnWidth(column, record.f_int)
|
else:
|
||||||
else:
|
self.setColumnWidth(column, Config.DEFAULT_COLUMN_WIDTH)
|
||||||
self.setColumnWidth(column, Config.DEFAULT_COLUMN_WIDTH)
|
|
||||||
|
|
||||||
def _set_next(self, row: int, session: Session) -> None:
|
def _set_next(self, row: int, session: Session) -> None:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -53,7 +53,7 @@ def main():
|
|||||||
DEBUG("Finished")
|
DEBUG("Finished")
|
||||||
|
|
||||||
|
|
||||||
def create_track_from_file(session, path, interactive=False):
|
def create_track_from_file(session, path, normalise=None, interactive=False):
|
||||||
"""
|
"""
|
||||||
Create track in database from passed path, or update database entry
|
Create track in database from passed path, or update database entry
|
||||||
if path already in database.
|
if path already in database.
|
||||||
@ -100,7 +100,7 @@ def create_track_from_file(session, path, interactive=False):
|
|||||||
track.mtime = os.path.getmtime(path)
|
track.mtime = os.path.getmtime(path)
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
if Config.NORMALISE_ON_IMPORT:
|
if normalise or normalise is None and Config.NORMALISE_ON_IMPORT:
|
||||||
if interactive:
|
if interactive:
|
||||||
INFO("Normalise...")
|
INFO("Normalise...")
|
||||||
# Check type
|
# Check type
|
||||||
|
|||||||
20
conftest.py
20
conftest.py
@ -2,11 +2,12 @@
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import sys
|
import sys
|
||||||
|
sys.path.append("app")
|
||||||
|
import models
|
||||||
|
|
||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
from sqlalchemy.orm import scoped_session, sessionmaker
|
from sqlalchemy.orm import scoped_session, sessionmaker
|
||||||
|
|
||||||
sys.path.append("app")
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="session")
|
@pytest.fixture(scope="session")
|
||||||
@ -18,23 +19,6 @@ def connection():
|
|||||||
return engine.connect()
|
return engine.connect()
|
||||||
|
|
||||||
|
|
||||||
def seed_database():
|
|
||||||
pass
|
|
||||||
|
|
||||||
# users = [
|
|
||||||
# {
|
|
||||||
# "id": 1,
|
|
||||||
# "name": "John Doe",
|
|
||||||
# },
|
|
||||||
# # ...
|
|
||||||
# ]
|
|
||||||
|
|
||||||
# for user in users:
|
|
||||||
# db_user = User(**user)
|
|
||||||
# db_session.add(db_user)
|
|
||||||
# db_session.commit()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="session")
|
@pytest.fixture(scope="session")
|
||||||
def setup_database(connection):
|
def setup_database(connection):
|
||||||
from app.models import Base # noqa E402
|
from app.models import Base # noqa E402
|
||||||
|
|||||||
6
poetry.lock
generated
6
poetry.lock
generated
@ -943,6 +943,12 @@ pytest = [
|
|||||||
{file = "pytest-7.0.1-py3-none-any.whl", hash = "sha256:9ce3ff477af913ecf6321fe337b93a2c0dcf2a0a1439c43f5452112c1e4280db"},
|
{file = "pytest-7.0.1-py3-none-any.whl", hash = "sha256:9ce3ff477af913ecf6321fe337b93a2c0dcf2a0a1439c43f5452112c1e4280db"},
|
||||||
{file = "pytest-7.0.1.tar.gz", hash = "sha256:e30905a0c131d3d94b89624a1cc5afec3e0ba2fbdb151867d8e0ebd49850f171"},
|
{file = "pytest-7.0.1.tar.gz", hash = "sha256:e30905a0c131d3d94b89624a1cc5afec3e0ba2fbdb151867d8e0ebd49850f171"},
|
||||||
]
|
]
|
||||||
|
pytest-profiling = [
|
||||||
|
{file = "pytest-profiling-1.7.0.tar.gz", hash = "sha256:93938f147662225d2b8bd5af89587b979652426a8a6ffd7e73ec4a23e24b7f29"},
|
||||||
|
{file = "pytest_profiling-1.7.0-py2.7.egg", hash = "sha256:3b255f9db36cb2dd7536a8e7e294c612c0be7f7850a7d30754878e4315d56600"},
|
||||||
|
{file = "pytest_profiling-1.7.0-py2.py3-none-any.whl", hash = "sha256:999cc9ac94f2e528e3f5d43465da277429984a1c237ae9818f8cfd0b06acb019"},
|
||||||
|
{file = "pytest_profiling-1.7.0-py3.6.egg", hash = "sha256:6bce4e2edc04409d2f3158c16750fab8074f62d404cc38eeb075dff7fcbb996c"},
|
||||||
|
]
|
||||||
pytest-qt = [
|
pytest-qt = [
|
||||||
{file = "pytest-qt-4.0.2.tar.gz", hash = "sha256:dfc5240dec7eb43b76bcb5f9a87eecae6ef83592af49f3af5f1d5d093acaa93e"},
|
{file = "pytest-qt-4.0.2.tar.gz", hash = "sha256:dfc5240dec7eb43b76bcb5f9a87eecae6ef83592af49f3af5f1d5d093acaa93e"},
|
||||||
{file = "pytest_qt-4.0.2-py2.py3-none-any.whl", hash = "sha256:e03847ac02a890ccaac0fde1748855b9dce425aceba62005c6cfced6cf7d5456"},
|
{file = "pytest_qt-4.0.2-py2.py3-none-any.whl", hash = "sha256:e03847ac02a890ccaac0fde1748855b9dce425aceba62005c6cfced6cf7d5456"},
|
||||||
|
|||||||
@ -126,7 +126,7 @@ def test_playdates_add_playdate(session):
|
|||||||
assert playdate
|
assert playdate
|
||||||
|
|
||||||
last_played = Playdates.last_played(session, track.id)
|
last_played = Playdates.last_played(session, track.id)
|
||||||
assert playdate.lastplayed == last_played
|
assert abs((playdate.lastplayed - last_played).total_seconds()) < 2
|
||||||
|
|
||||||
|
|
||||||
def test_playdates_remove_track(session):
|
def test_playdates_remove_track(session):
|
||||||
@ -274,6 +274,9 @@ def test_playlist_remove_tracks(session):
|
|||||||
|
|
||||||
playlist1.remove_track(session, 1)
|
playlist1.remove_track(session, 1)
|
||||||
assert len(playlist1.tracks) == 2
|
assert len(playlist1.tracks) == 2
|
||||||
|
# Check the track itself still exists
|
||||||
|
original_track = Tracks.get_by_id(session, track1.id)
|
||||||
|
assert original_track
|
||||||
|
|
||||||
playlist1.remove_all_tracks(session)
|
playlist1.remove_all_tracks(session)
|
||||||
assert len(playlist1.tracks) == 0
|
assert len(playlist1.tracks) == 0
|
||||||
@ -330,8 +333,7 @@ def test_playlisttracks_move_track(session):
|
|||||||
assert tracks[track2_row] == track2
|
assert tracks[track2_row] == track2
|
||||||
|
|
||||||
# Move track2 to playlist2 and check
|
# Move track2 to playlist2 and check
|
||||||
PlaylistTracks.move_track(
|
playlist1.move_track(session, [track2_row], playlist2)
|
||||||
session, playlist1.id, track2_row, playlist2.id)
|
|
||||||
|
|
||||||
tracks1 = playlist1.tracks
|
tracks1 = playlist1.tracks
|
||||||
tracks2 = playlist2.tracks
|
tracks2 = playlist2.tracks
|
||||||
|
|||||||
@ -1,15 +1,47 @@
|
|||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
||||||
|
|
||||||
from app.playlists import Notes, PlaylistTab, Tracks
|
from app import playlists
|
||||||
from app.models import Playlists
|
from app import models
|
||||||
import musicmuster
|
from app import musicmuster
|
||||||
|
from app import dbconfig
|
||||||
|
|
||||||
|
|
||||||
|
def seed2tracks(session):
|
||||||
|
tracks = [
|
||||||
|
{
|
||||||
|
"path": "testdata/isa.mp3",
|
||||||
|
"title": "I'm so afraid",
|
||||||
|
"artist": "Fleetwood Mac",
|
||||||
|
"duration": 263000,
|
||||||
|
"start_gap": 60,
|
||||||
|
"fade_at": 236263,
|
||||||
|
"silence_at": 260343,
|
||||||
|
"mtime": 371900000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "testdata/mom.mp3",
|
||||||
|
"title": "Man of Mystery",
|
||||||
|
"artist": "The Shadows",
|
||||||
|
"duration": 120000,
|
||||||
|
"start_gap": 70,
|
||||||
|
"fade_at": 115000,
|
||||||
|
"silence_at": 118000,
|
||||||
|
"mtime": 1642760000,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
for track in tracks:
|
||||||
|
db_track = models.Tracks(session=session, **track)
|
||||||
|
session.add(db_track)
|
||||||
|
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
|
||||||
def test_init(qtbot, session):
|
def test_init(qtbot, session):
|
||||||
"""Just check we can create a playlist_tab"""
|
"""Just check we can create a playlist_tab"""
|
||||||
|
|
||||||
playlist = Playlists(session, "my playlist")
|
playlist = models.Playlists(session, "my playlist")
|
||||||
playlist_tab = PlaylistTab(None, session, playlist.id)
|
playlist_tab = playlists.PlaylistTab(None, session, playlist.id)
|
||||||
assert playlist_tab
|
assert playlist_tab
|
||||||
|
|
||||||
|
|
||||||
@ -17,46 +49,51 @@ def test_save_and_restore(qtbot, session):
|
|||||||
"""Playlist with one track, one note, save and restore"""
|
"""Playlist with one track, one note, save and restore"""
|
||||||
|
|
||||||
# Create playlist
|
# Create playlist
|
||||||
playlist = Playlists(session, "my playlist")
|
playlist = models.Playlists(session, "my playlist")
|
||||||
playlist_tab = PlaylistTab(None, session, playlist.id)
|
playlist_tab = playlists.PlaylistTab(None, session, playlist.id)
|
||||||
|
|
||||||
# Insert a note
|
# Insert a note
|
||||||
note_text = "my note"
|
note_text = "my note"
|
||||||
note_row = 7
|
note_row = 7
|
||||||
note = Notes(session, playlist.id, note_row, note_text)
|
note = models.Notes(session, playlist.id, note_row, note_text)
|
||||||
playlist_tab._insert_note(session, note)
|
playlist_tab._insert_note(session, note)
|
||||||
|
|
||||||
# Add a track
|
# Add a track
|
||||||
track_path = "/a/b/c"
|
track_path = "/a/b/c"
|
||||||
track = Tracks(session, track_path)
|
track = models.Tracks(session, track_path)
|
||||||
playlist_tab.insert_track(session, track)
|
playlist_tab.insert_track(session, track)
|
||||||
|
|
||||||
# Save playlist
|
# Save playlist
|
||||||
playlist_tab.save_playlist(session)
|
playlist_tab.save_playlist(session)
|
||||||
|
|
||||||
|
# We need to commit the session before re-querying
|
||||||
|
session.commit()
|
||||||
|
|
||||||
# Retrieve playlist
|
# Retrieve playlist
|
||||||
playlists = Playlists.get_open(session)
|
all_playlists = playlists.Playlists.get_open(session)
|
||||||
assert len(playlists) == 1
|
assert len(all_playlists) == 1
|
||||||
retrieved_playlist = playlists[0]
|
retrieved_playlist = all_playlists[0]
|
||||||
assert track_path in [a.path for a in retrieved_playlist.tracks.values()]
|
paths = [a.path for a in retrieved_playlist.tracks.values()]
|
||||||
assert note_text in [a.note for a in retrieved_playlist.notes]
|
assert track_path in paths
|
||||||
|
notes = [a.note for a in retrieved_playlist.notes]
|
||||||
|
assert note_text in notes
|
||||||
|
|
||||||
|
|
||||||
def test_meta_all_clear(qtbot, session):
|
def test_meta_all_clear(qtbot, session):
|
||||||
|
|
||||||
# Create playlist
|
# Create playlist
|
||||||
playlist = Playlists(session, "my playlist")
|
playlist = models.Playlists(session, "my playlist")
|
||||||
playlist_tab = PlaylistTab(None, session, playlist.id)
|
playlist_tab = playlists.PlaylistTab(None, session, playlist.id)
|
||||||
|
|
||||||
# Add some tracks
|
# Add some tracks
|
||||||
track1_path = "/a/b/c"
|
track1_path = "/a/b/c"
|
||||||
track1 = Tracks(session, track1_path)
|
track1 = models.Tracks(session, track1_path)
|
||||||
playlist_tab.insert_track(session, track1)
|
playlist_tab.insert_track(session, track1)
|
||||||
track2_path = "/d/e/f"
|
track2_path = "/d/e/f"
|
||||||
track2 = Tracks(session, track2_path)
|
track2 = models.Tracks(session, track2_path)
|
||||||
playlist_tab.insert_track(session, track2)
|
playlist_tab.insert_track(session, track2)
|
||||||
track3_path = "/h/i/j"
|
track3_path = "/h/i/j"
|
||||||
track3 = Tracks(session, track3_path)
|
track3 = models.Tracks(session, track3_path)
|
||||||
playlist_tab.insert_track(session, track3)
|
playlist_tab.insert_track(session, track3)
|
||||||
|
|
||||||
assert playlist_tab._get_current_track_row() is None
|
assert playlist_tab._get_current_track_row() is None
|
||||||
@ -69,18 +106,18 @@ def test_meta_all_clear(qtbot, session):
|
|||||||
def test_meta(qtbot, session):
|
def test_meta(qtbot, session):
|
||||||
|
|
||||||
# Create playlist
|
# Create playlist
|
||||||
playlist = Playlists(session, "my playlist")
|
playlist = playlists.Playlists(session, "my playlist")
|
||||||
playlist_tab = PlaylistTab(None, session, playlist.id)
|
playlist_tab = playlists.PlaylistTab(None, session, playlist.id)
|
||||||
|
|
||||||
# Add some tracks
|
# Add some tracks
|
||||||
track1_path = "/a/b/c"
|
track1_path = "/a/b/c"
|
||||||
track1 = Tracks(session, track1_path)
|
track1 = models.Tracks(session, track1_path)
|
||||||
playlist_tab.insert_track(session, track1)
|
playlist_tab.insert_track(session, track1)
|
||||||
track2_path = "/d/e/f"
|
track2_path = "/d/e/f"
|
||||||
track2 = Tracks(session, track2_path)
|
track2 = models.Tracks(session, track2_path)
|
||||||
playlist_tab.insert_track(session, track2)
|
playlist_tab.insert_track(session, track2)
|
||||||
track3_path = "/h/i/j"
|
track3_path = "/h/i/j"
|
||||||
track3 = Tracks(session, track3_path)
|
track3 = models.Tracks(session, track3_path)
|
||||||
playlist_tab.insert_track(session, track3)
|
playlist_tab.insert_track(session, track3)
|
||||||
|
|
||||||
assert len(playlist_tab._get_unreadable_track_rows()) == 3
|
assert len(playlist_tab._get_unreadable_track_rows()) == 3
|
||||||
@ -99,7 +136,7 @@ def test_meta(qtbot, session):
|
|||||||
# Add a note
|
# Add a note
|
||||||
note_text = "my note"
|
note_text = "my note"
|
||||||
note_row = 7 # will be added as row 3
|
note_row = 7 # will be added as row 3
|
||||||
note = Notes(session, playlist.id, note_row, note_text)
|
note = models.Notes(session, playlist.id, note_row, note_text)
|
||||||
playlist_tab._insert_note(session, note)
|
playlist_tab._insert_note(session, note)
|
||||||
|
|
||||||
assert playlist_tab._get_played_track_rows() == [0]
|
assert playlist_tab._get_played_track_rows() == [0]
|
||||||
@ -147,15 +184,15 @@ def test_meta(qtbot, session):
|
|||||||
|
|
||||||
def test_clear_next(qtbot, session):
|
def test_clear_next(qtbot, session):
|
||||||
# Create playlist
|
# Create playlist
|
||||||
playlist = Playlists(session, "my playlist")
|
playlist = models.Playlists(session, "my playlist")
|
||||||
playlist_tab = PlaylistTab(None, session, playlist.id)
|
playlist_tab = playlists.PlaylistTab(None, session, playlist.id)
|
||||||
|
|
||||||
# Add some tracks
|
# Add some tracks
|
||||||
track1_path = "/a/b/c"
|
track1_path = "/a/b/c"
|
||||||
track1 = Tracks(session, track1_path)
|
track1 = models.Tracks(session, track1_path)
|
||||||
playlist_tab.insert_track(session, track1)
|
playlist_tab.insert_track(session, track1)
|
||||||
track2_path = "/d/e/f"
|
track2_path = "/d/e/f"
|
||||||
track2 = Tracks(session, track2_path)
|
track2 = models.Tracks(session, track2_path)
|
||||||
playlist_tab.insert_track(session, track2)
|
playlist_tab.insert_track(session, track2)
|
||||||
|
|
||||||
playlist_tab._set_next_track_row(1)
|
playlist_tab._set_next_track_row(1)
|
||||||
@ -165,21 +202,24 @@ def test_clear_next(qtbot, session):
|
|||||||
assert playlist_tab._get_next_track_row() is None
|
assert playlist_tab._get_next_track_row() is None
|
||||||
|
|
||||||
|
|
||||||
def test_get_selected_row(qtbot, session):
|
def test_get_selected_row(qtbot, monkeypatch, session):
|
||||||
|
|
||||||
# Create playlist
|
monkeypatch.setattr(musicmuster, "Session", session)
|
||||||
playlist = Playlists(session, "test playlist")
|
monkeypatch.setattr(playlists, "Session", session)
|
||||||
playlist_tab = PlaylistTab(None, session, playlist.id)
|
|
||||||
|
# Create playlist and playlist_tab
|
||||||
|
window = musicmuster.Window()
|
||||||
|
playlist = models.Playlists(session, "test playlist")
|
||||||
|
playlist_tab = playlists.PlaylistTab(window, session, playlist.id)
|
||||||
|
|
||||||
# Add some tracks
|
# Add some tracks
|
||||||
track1_path = "/a/b/c"
|
track1_path = "/a/b/c"
|
||||||
track1 = Tracks(session, track1_path)
|
track1 = models.Tracks(session, track1_path)
|
||||||
playlist_tab.insert_track(session, track1)
|
playlist_tab.insert_track(session, track1)
|
||||||
track2_path = "/d/e/f"
|
track2_path = "/d/e/f"
|
||||||
track2 = Tracks(session, track2_path)
|
track2 = models.Tracks(session, track2_path)
|
||||||
playlist_tab.insert_track(session, track2)
|
playlist_tab.insert_track(session, track2)
|
||||||
|
|
||||||
window = Window()
|
|
||||||
qtbot.addWidget(playlist_tab)
|
qtbot.addWidget(playlist_tab)
|
||||||
with qtbot.waitExposed(window):
|
with qtbot.waitExposed(window):
|
||||||
window.show()
|
window.show()
|
||||||
@ -191,31 +231,37 @@ def test_get_selected_row(qtbot, session):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_set_next(qtbot, session):
|
def test_set_next(qtbot, monkeypatch, session):
|
||||||
|
|
||||||
|
monkeypatch.setattr(musicmuster, "Session", session)
|
||||||
|
monkeypatch.setattr(playlists, "Session", session)
|
||||||
|
seed2tracks(session)
|
||||||
|
|
||||||
|
playlist_name = "test playlist"
|
||||||
# Create testing playlist
|
# Create testing playlist
|
||||||
playlist = Playlists(session, "test playlist")
|
window = musicmuster.Window()
|
||||||
playlist_tab = PlaylistTab(None, session, playlist.id)
|
playlist = models.Playlists(session, playlist_name)
|
||||||
|
playlist_tab = playlists.PlaylistTab(window, session, playlist.id)
|
||||||
|
idx = window.tabPlaylist.addTab(playlist_tab, playlist_name)
|
||||||
|
window.tabPlaylist.setCurrentIndex(idx)
|
||||||
|
qtbot.addWidget(playlist_tab)
|
||||||
|
|
||||||
# Add some tracks
|
# Add some tracks
|
||||||
track1_path = "testdata/isa.mp3"
|
track1 = models.Tracks.get_from_filename(session, "isa.mp3")
|
||||||
track1 = Tracks(session, track1_path)
|
|
||||||
playlist_tab.insert_track(session, track1)
|
playlist_tab.insert_track(session, track1)
|
||||||
track2_path = "mom.mp3"
|
track2 = models.Tracks.get_from_filename(session, "mom.mp3")
|
||||||
track2 = Tracks(session, track2_path)
|
|
||||||
playlist_tab.insert_track(session, track2)
|
playlist_tab.insert_track(session, track2)
|
||||||
|
|
||||||
window = Window()
|
|
||||||
qtbot.addWidget(playlist_tab)
|
|
||||||
with qtbot.waitExposed(window):
|
with qtbot.waitExposed(window):
|
||||||
window.show()
|
window.show()
|
||||||
|
|
||||||
row0_item2 = playlist_tab.item(0, 2)
|
row0_item2 = playlist_tab.item(0, 2)
|
||||||
assert row0_item2 is not None
|
assert row0_item2 is not None
|
||||||
rect = playlist_tab.visualItemRect(row0_item2)
|
rect = playlist_tab.visualItemRect(row0_item2)
|
||||||
qtbot.mouseClick(
|
qtbot.mouseClick(
|
||||||
playlist_tab.viewport(), Qt.LeftButton, pos=rect.center()
|
playlist_tab.viewport(), Qt.LeftButton, pos=rect.center()
|
||||||
)
|
)
|
||||||
qtbot.wait(10000)
|
# qtbot.wait(10000)
|
||||||
qtbot.keyPress(playlist_tab.viewport(), "N",
|
qtbot.keyPress(playlist_tab.viewport(), "N",
|
||||||
modifier=Qt.ControlModifier)
|
modifier=Qt.ControlModifier)
|
||||||
qtbot.wait(2000)
|
qtbot.wait(2000)
|
||||||
@ -223,6 +269,12 @@ def test_set_next(qtbot, session):
|
|||||||
|
|
||||||
|
|
||||||
def test_kae(monkeypatch, session):
|
def test_kae(monkeypatch, session):
|
||||||
|
# monkeypatch.setattr(dbconfig, "Session", session)
|
||||||
monkeypatch.setattr(musicmuster, "Session", session)
|
monkeypatch.setattr(musicmuster, "Session", session)
|
||||||
|
|
||||||
musicmuster.Window.kae()
|
musicmuster.Window.kae()
|
||||||
|
# monkeypatch.setattr(musicmuster, "Session", session)
|
||||||
|
# monkeypatch.setattr(dbconfig, "Session", session)
|
||||||
|
# monkeypatch.setattr(models, "Session", session)
|
||||||
|
# monkeypatch.setattr(playlists, "Session", session)
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user