Compare commits

...

2 Commits

Author SHA1 Message Date
Keith Edmunds
1749f0a0b8 Actually add tracks chosen from query 2025-03-13 10:41:56 +00:00
Keith Edmunds
c9ff1aa668 Improver performance loading playlists 2025-03-09 19:23:55 +00:00
8 changed files with 100 additions and 11 deletions

View File

@ -5,7 +5,7 @@ from dataclasses import dataclass
from enum import auto, Enum from enum import auto, Enum
import functools import functools
import threading import threading
from typing import NamedTuple, Optional from typing import NamedTuple
# Third party imports # Third party imports
@ -97,10 +97,7 @@ class MusicMusterSignals(QObject):
""" """
Class for all MusicMuster signals. See: Class for all MusicMuster signals. See:
- https://zetcode.com/gui/pyqt5/eventssignals/ - https://zetcode.com/gui/pyqt5/eventssignals/
- https://stackoverflow.com/questions/62654525/ - https://stackoverflow.com/questions/62654525/emit-a-signal-from-another-class-to-main-class
emit-a-signal-from-another-class-to-main-class
and Singleton class at
https://refactoring.guru/design-patterns/singleton/python/example#example-0
""" """
begin_reset_model_signal = pyqtSignal(int) begin_reset_model_signal = pyqtSignal(int)

View File

@ -22,7 +22,7 @@ from sqlalchemy import (
) )
from sqlalchemy.exc import IntegrityError, ProgrammingError from sqlalchemy.exc import IntegrityError, ProgrammingError
from sqlalchemy.orm.exc import NoResultFound from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.orm import joinedload from sqlalchemy.orm import joinedload, selectinload
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
from sqlalchemy.engine.row import RowMapping from sqlalchemy.engine.row import RowMapping
@ -48,6 +48,7 @@ cache_region = make_region().configure(
expiration_time=600 # Cache expires after 10 minutes expiration_time=600 # Cache expires after 10 minutes
) )
def run_sql(session: Session, sql: str) -> Sequence[RowMapping]: def run_sql(session: Session, sql: str) -> Sequence[RowMapping]:
""" """
Run a sql string and return results Run a sql string and return results
@ -519,9 +520,13 @@ class PlaylistRows(dbtables.PlaylistRowsTable):
For passed playlist, return a list of rows. For passed playlist, return a list of rows.
""" """
plrs = session.scalars( stmt = (
select(cls).where(cls.playlist_id == playlist_id).order_by(cls.row_number) select(cls)
).all() .where(cls.playlist_id == playlist_id)
.options(selectinload(cls.track))
.order_by(cls.row_number)
)
plrs = session.execute(stmt).scalars().all()
return plrs return plrs

View File

@ -6,6 +6,7 @@ from time import sleep
from typing import Optional from typing import Optional
# Third party imports # Third party imports
# import line_profiler
import numpy as np import numpy as np
import pyqtgraph as pg # type: ignore import pyqtgraph as pg # type: ignore
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session

View File

@ -57,6 +57,7 @@ from PyQt6.QtWidgets import (
) )
# Third party imports # Third party imports
# import line_profiler
from pygame import mixer from pygame import mixer
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
import stackprinter # type: ignore import stackprinter # type: ignore
@ -71,7 +72,7 @@ from classes import (
from config import Config from config import Config
from dialogs import TrackSelectDialog from dialogs import TrackSelectDialog
from file_importer import FileImporter from file_importer import FileImporter
from helpers import file_is_unreadable, get_name from helpers import ask_yes_no, file_is_unreadable, get_name
from log import log from log import log
from models import db, Playdates, PlaylistRows, Playlists, Queries, Settings, Tracks from models import db, Playdates, PlaylistRows, Playlists, Queries, Settings, Tracks
from music_manager import RowAndTrack, track_sequence from music_manager import RowAndTrack, track_sequence
@ -1430,7 +1431,27 @@ class Window(QMainWindow):
# Keep a reference else it will be gc'd # Keep a reference else it will be gc'd
self.query_dialog = QueryDialog(session, query_id) self.query_dialog = QueryDialog(session, query_id)
self.query_dialog.exec() if self.query_dialog.exec():
new_row_number = self.current_row_or_end()
base_model = self.current.base_model
for track_id in self.query_dialog.selected_tracks:
# Check whether track is already in playlist
move_existing = False
existing_prd = base_model.is_track_in_playlist(track_id)
if existing_prd is not None:
if ask_yes_no(
"Duplicate row",
"Track already in playlist. " "Move to new location?",
default_yes=True,
):
move_existing = True
if move_existing and existing_prd:
base_model.move_track_add_note(new_row_number, existing_prd, note="")
else:
base_model.insert_row(new_row_number, track_id)
new_row_number += 1
# # # # # # # # # # Playlist management functions # # # # # # # # # # # # # # # # # # # # Playlist management functions # # # # # # # # # #

View File

@ -24,6 +24,7 @@ from PyQt6.QtGui import (
) )
# Third party imports # Third party imports
# import line_profiler
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
import obswebsocket # type: ignore import obswebsocket # type: ignore

View File

@ -31,6 +31,7 @@ from PyQt6.QtWidgets import (
) )
# Third party imports # Third party imports
# import line_profiler
# App imports # App imports
from audacity_controller import AudacityController from audacity_controller import AudacityController

View File

@ -32,6 +32,7 @@ dependencies = [
"audioop-lts>=0.2.1", "audioop-lts>=0.2.1",
"types-pyyaml>=6.0.12.20241230", "types-pyyaml>=6.0.12.20241230",
"dogpile-cache>=1.3.4", "dogpile-cache>=1.3.4",
"pdbpp>=0.10.3",
] ]
[dependency-groups] [dependency-groups]

62
uv.lock
View File

@ -37,6 +37,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918 }, { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918 },
] ]
[[package]]
name = "attrs"
version = "25.1.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/49/7c/fdf464bcc51d23881d110abd74b512a42b3d5d376a55a831b44c603ae17f/attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e", size = 810562 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a", size = 63152 },
]
[[package]] [[package]]
name = "audioop-lts" name = "audioop-lts"
version = "0.2.1" version = "0.2.1"
@ -199,6 +208,19 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa", size = 26702 }, { url = "https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa", size = 26702 },
] ]
[[package]]
name = "fancycompleter"
version = "0.9.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pyreadline", marker = "sys_platform == 'win32'" },
{ name = "pyrepl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a9/95/649d135442d8ecf8af5c7e235550c628056423c96c4bc6787348bdae9248/fancycompleter-0.9.1.tar.gz", hash = "sha256:09e0feb8ae242abdfd7ef2ba55069a46f011814a80fe5476be48f51b00247272", size = 10866 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/38/ef/c08926112034d017633f693d3afc8343393a035134a29dfc12dcd71b0375/fancycompleter-0.9.1-py3-none-any.whl", hash = "sha256:dd076bca7d9d524cc7f25ec8f35ef95388ffef9ef46def4d3d25e9b044ad7080", size = 9681 },
]
[[package]] [[package]]
name = "flake8" name = "flake8"
version = "7.1.2" version = "7.1.2"
@ -467,6 +489,7 @@ dependencies = [
{ name = "mutagen" }, { name = "mutagen" },
{ name = "mysqlclient" }, { name = "mysqlclient" },
{ name = "obs-websocket-py" }, { name = "obs-websocket-py" },
{ name = "pdbpp" },
{ name = "psutil" }, { name = "psutil" },
{ name = "pydub" }, { name = "pydub" },
{ name = "pydymenu" }, { name = "pydymenu" },
@ -511,6 +534,7 @@ requires-dist = [
{ name = "mutagen", specifier = ">=1.47.0" }, { name = "mutagen", specifier = ">=1.47.0" },
{ name = "mysqlclient", specifier = ">=2.2.5" }, { name = "mysqlclient", specifier = ">=2.2.5" },
{ name = "obs-websocket-py", specifier = ">=1.0" }, { name = "obs-websocket-py", specifier = ">=1.0" },
{ name = "pdbpp", specifier = ">=0.10.3" },
{ name = "psutil", specifier = ">=6.1.0" }, { name = "psutil", specifier = ">=6.1.0" },
{ name = "pydub", specifier = ">=0.25.1" }, { name = "pydub", specifier = ">=0.25.1" },
{ name = "pydymenu", specifier = ">=0.5.2" }, { name = "pydymenu", specifier = ">=0.5.2" },
@ -668,6 +692,20 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/47/ac/684d71315abc7b1214d59304e23a982472967f6bf4bde5a98f1503f648dc/pbr-6.1.1-py2.py3-none-any.whl", hash = "sha256:38d4daea5d9fa63b3f626131b9d34947fd0c8be9b05a29276870580050a25a76", size = 108997 }, { url = "https://files.pythonhosted.org/packages/47/ac/684d71315abc7b1214d59304e23a982472967f6bf4bde5a98f1503f648dc/pbr-6.1.1-py2.py3-none-any.whl", hash = "sha256:38d4daea5d9fa63b3f626131b9d34947fd0c8be9b05a29276870580050a25a76", size = 108997 },
] ]
[[package]]
name = "pdbpp"
version = "0.10.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "fancycompleter" },
{ name = "pygments" },
{ name = "wmctrl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1f/a3/c4bd048256fd4b7d28767ca669c505e156f24d16355505c62e6fce3314df/pdbpp-0.10.3.tar.gz", hash = "sha256:d9e43f4fda388eeb365f2887f4e7b66ac09dce9b6236b76f63616530e2f669f5", size = 68116 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/93/ee/491e63a57fffa78b9de1c337b06c97d0cd0753e88c00571c7b011680332a/pdbpp-0.10.3-py2.py3-none-any.whl", hash = "sha256:79580568e33eb3d6f6b462b1187f53e10cd8e4538f7d31495c9181e2cf9665d1", size = 23961 },
]
[[package]] [[package]]
name = "pexpect" name = "pexpect"
version = "4.9.0" version = "4.9.0"
@ -928,6 +966,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/7b/34/5702b3b7cafe99be1d94b42f100e8cc5e6957b761fcb1cf5f72d492851da/pyqtgraph-0.13.7-py3-none-any.whl", hash = "sha256:7754edbefb6c367fa0dfb176e2d0610da3ada20aa7a5318516c74af5fb72bf7a", size = 1925473 }, { url = "https://files.pythonhosted.org/packages/7b/34/5702b3b7cafe99be1d94b42f100e8cc5e6957b761fcb1cf5f72d492851da/pyqtgraph-0.13.7-py3-none-any.whl", hash = "sha256:7754edbefb6c367fa0dfb176e2d0610da3ada20aa7a5318516c74af5fb72bf7a", size = 1925473 },
] ]
[[package]]
name = "pyreadline"
version = "2.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/bc/7c/d724ef1ec3ab2125f38a1d53285745445ec4a8f19b9bb0761b4064316679/pyreadline-2.1.zip", hash = "sha256:4530592fc2e85b25b1a9f79664433da09237c1a270e4d78ea5aa3a2c7229e2d1", size = 109189 }
[[package]]
name = "pyrepl"
version = "0.9.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/05/1b/ea40363be0056080454cdbabe880773c3c5bd66d7b13f0c8b8b8c8da1e0c/pyrepl-0.9.0.tar.gz", hash = "sha256:292570f34b5502e871bbb966d639474f2b57fbfcd3373c2d6a2f3d56e681a775", size = 48744 }
[[package]] [[package]]
name = "pytest" name = "pytest"
version = "8.3.5" version = "8.3.5"
@ -1231,3 +1281,15 @@ sdist = { url = "https://files.pythonhosted.org/packages/e6/30/fba0d96b4b5fbf594
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826 }, { url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826 },
] ]
[[package]]
name = "wmctrl"
version = "0.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "attrs" },
]
sdist = { url = "https://files.pythonhosted.org/packages/60/d9/6625ead93412c5ce86db1f8b4f2a70b8043e0a7c1d30099ba3c6a81641ff/wmctrl-0.5.tar.gz", hash = "sha256:7839a36b6fe9e2d6fd22304e5dc372dbced2116ba41283ea938b2da57f53e962", size = 5202 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/13/ca/723e3f8185738d7947f14ee7dc663b59415c6dee43bd71575f8c7f5cd6be/wmctrl-0.5-py2.py3-none-any.whl", hash = "sha256:ae695c1863a314c899e7cf113f07c0da02a394b968c4772e1936219d9234ddd7", size = 4268 },
]