Compare commits
4 Commits
b4f5d92f5d
...
8e48d63ebb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e48d63ebb | ||
|
|
aa6ab03555 | ||
|
|
90d72464cb | ||
|
|
82e707a6f6 |
@ -80,6 +80,7 @@ class FileErrors(NamedTuple):
|
||||
|
||||
@dataclass
|
||||
class Filter:
|
||||
version: int = 1
|
||||
path_type: str = "contains"
|
||||
path: Optional[str] = None
|
||||
last_played_number: Optional[int] = None
|
||||
|
||||
@ -49,6 +49,18 @@ class Config(object):
|
||||
FADEOUT_DB = -10
|
||||
FADEOUT_SECONDS = 5
|
||||
FADEOUT_STEPS_PER_SECOND = 5
|
||||
FILTER_DURATION_LONGER = "longer than"
|
||||
FILTER_DURATION_MINUTES = "minutes"
|
||||
FILTER_DURATION_SECONDS = "seconds"
|
||||
FILTER_DURATION_SHORTER = "shorter than"
|
||||
FILTER_PATH_CONTAINS = "contains"
|
||||
FILTER_PATH_EXCLUDING = "excluding"
|
||||
FILTER_PLAYED_BEFORE = "before"
|
||||
FILTER_PLAYED_DAYS = "days"
|
||||
FILTER_PLAYED_MONTHS = "months"
|
||||
FILTER_PLAYED_NEVER = "never"
|
||||
FILTER_PLAYED_WEEKS = "weeks"
|
||||
FILTER_PLAYED_YEARS = "years"
|
||||
FUZZYMATCH_MINIMUM_LIST = 60.0
|
||||
FUZZYMATCH_MINIMUM_SELECT_ARTIST = 80.0
|
||||
FUZZYMATCH_MINIMUM_SELECT_TITLE = 80.0
|
||||
|
||||
@ -154,7 +154,7 @@ class QueriesTable(Model):
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
||||
_filter_data: Mapped[dict | None] = mapped_column("filter_data", JSONEncodedDict, nullable=True)
|
||||
_filter_data: Mapped[dict | None] = mapped_column("filter_data", JSONEncodedDict, nullable=False)
|
||||
favourite: Mapped[bool] = mapped_column(Boolean, nullable=False, index=False, default=False)
|
||||
|
||||
def _get_filter(self) -> Filter:
|
||||
|
||||
@ -10,7 +10,7 @@ import ssl
|
||||
import tempfile
|
||||
|
||||
# PyQt imports
|
||||
from PyQt6.QtWidgets import QMainWindow, QMessageBox, QWidget
|
||||
from PyQt6.QtWidgets import QInputDialog, QMainWindow, QMessageBox, QWidget
|
||||
|
||||
# Third party imports
|
||||
from mutagen.flac import FLAC # type: ignore
|
||||
@ -150,6 +150,23 @@ def get_audio_metadata(filepath: str) -> AudioMetadata:
|
||||
)
|
||||
|
||||
|
||||
def get_name(prompt: str, default: str = "") -> str | None:
|
||||
"""Get a name from the user"""
|
||||
|
||||
dlg = QInputDialog()
|
||||
dlg.setInputMode(QInputDialog.InputMode.TextInput)
|
||||
dlg.setLabelText(prompt)
|
||||
while True:
|
||||
if default:
|
||||
dlg.setTextValue(default)
|
||||
dlg.resize(500, 100)
|
||||
ok = dlg.exec()
|
||||
if ok:
|
||||
return dlg.textValue()
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def get_relative_date(
|
||||
past_date: Optional[dt.datetime], reference_date: Optional[dt.datetime] = None
|
||||
) -> str:
|
||||
|
||||
@ -4,10 +4,10 @@ menus:
|
||||
- text: "Save as Template"
|
||||
handler: "save_as_template"
|
||||
- text: "Manage Templates"
|
||||
handler: "manage_templates"
|
||||
handler: "manage_templates_wrapper"
|
||||
- separator: true
|
||||
- text: "Manage Queries"
|
||||
handler: "manage_queries"
|
||||
handler: "manage_queries_wrapper"
|
||||
- separator: true
|
||||
- text: "Exit"
|
||||
handler: "close"
|
||||
|
||||
@ -25,7 +25,7 @@ from sqlalchemy.orm.session import Session
|
||||
from sqlalchemy.engine.row import RowMapping
|
||||
|
||||
# App imports
|
||||
from classes import ApplicationError
|
||||
from classes import ApplicationError, Filter
|
||||
from config import Config
|
||||
from dbmanager import DatabaseManager
|
||||
import dbtables
|
||||
@ -610,11 +610,21 @@ class Queries(dbtables.QueriesTable):
|
||||
session.commit()
|
||||
|
||||
@classmethod
|
||||
def get_all_queries(cls, session: Session) -> Sequence["Queries"]:
|
||||
def get_all(cls, session: Session) -> Sequence["Queries"]:
|
||||
"""Returns a list of all queries ordered by name"""
|
||||
|
||||
return session.scalars(select(cls).order_by(cls.name)).all()
|
||||
|
||||
@classmethod
|
||||
def get_favourites(cls, session: Session) -> Sequence["Queries"]:
|
||||
"""Returns a list of favourite queries ordered by name"""
|
||||
|
||||
return session.scalars(
|
||||
select(cls)
|
||||
.where(cls.favourite.is_(True))
|
||||
.order_by(cls.name)
|
||||
).all()
|
||||
|
||||
|
||||
class Settings(dbtables.SettingsTable):
|
||||
def __init__(self, session: Session, name: str) -> None:
|
||||
@ -700,6 +710,40 @@ class Tracks(dbtables.TracksTable):
|
||||
.all()
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_filtered_tracks(cls, session: Session, filter: Filter) -> Sequence["Tracks"]:
|
||||
"""
|
||||
Return tracks matching filter
|
||||
"""
|
||||
|
||||
query = select(cls)
|
||||
if filter.path:
|
||||
if filter.path_type == "contains":
|
||||
query = query.where(cls.path.ilike(f"%{filter.path}%"))
|
||||
elif filter.path_type == "excluding":
|
||||
query = query.where(cls.path.notilike(f"%{filter.path}%"))
|
||||
else:
|
||||
raise ApplicationError(f"Can't process filter path ({filter=})")
|
||||
# TODO
|
||||
# if last_played_number:
|
||||
# need group_by track_id and having max/min lastplayed gt/lt, etc
|
||||
seconds_duration = filter.duration_number
|
||||
if filter.duration_unit == Config.FILTER_DURATION_MINUTES:
|
||||
seconds_duration *= 60
|
||||
elif filter.duration_unit != Config.FILTER_DURATION_SECONDS:
|
||||
raise ApplicationError(f"Can't process filter duration ({filter=})")
|
||||
if filter.duration_type == Config.FILTER_DURATION_LONGER:
|
||||
query = query.where(cls.duration >= seconds_duration)
|
||||
elif filter.duration_unit == Config.FILTER_DURATION_SHORTER:
|
||||
query = query.where(cls.duration <= seconds_duration)
|
||||
else:
|
||||
raise ApplicationError(f"Can't process filter duration type ({filter=})")
|
||||
|
||||
records = session.scalars(
|
||||
query).unique().all()
|
||||
|
||||
return records
|
||||
|
||||
@classmethod
|
||||
def get_by_path(cls, session: Session, path: str) -> Optional["Tracks"]:
|
||||
"""
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -38,7 +38,7 @@ from helpers import (
|
||||
show_warning,
|
||||
)
|
||||
from log import log
|
||||
from models import db, Playdates
|
||||
from models import db, Playdates, Tracks
|
||||
from music_manager import RowAndTrack
|
||||
|
||||
|
||||
@ -228,20 +228,20 @@ class QuerylistModel(QAbstractTableModel):
|
||||
row = 0
|
||||
|
||||
try:
|
||||
results = Tracks.get_filtered(self.session, self.filter)
|
||||
results = Tracks.get_filtered_tracks(self.session, self.filter)
|
||||
for result in results:
|
||||
if hasattr(result, "lastplayed"):
|
||||
lastplayed = result["lastplayed"]
|
||||
else:
|
||||
lastplayed = None
|
||||
queryrow = QueryRow(
|
||||
artist=result["artist"],
|
||||
bitrate=result["bitrate"],
|
||||
duration=result["duration"],
|
||||
artist=result.artist,
|
||||
bitrate=result.bitrate or 0,
|
||||
duration=result.duration,
|
||||
lastplayed=lastplayed,
|
||||
path=result["path"],
|
||||
title=result["title"],
|
||||
track_id=result["id"],
|
||||
path=result.path,
|
||||
title=result.title,
|
||||
track_id=result.id,
|
||||
)
|
||||
|
||||
self.querylist_rows[row] = queryrow
|
||||
|
||||
@ -33,7 +33,7 @@ def upgrade_() -> None:
|
||||
op.create_table('queries',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('name', sa.String(length=128), nullable=False),
|
||||
sa.Column('filter_data', dbtables.JSONEncodedDict(), nullable=True),
|
||||
sa.Column('filter_data', dbtables.JSONEncodedDict(), nullable=False),
|
||||
sa.Column('favourite', sa.Boolean(), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user