Compare commits
4 Commits
0e4de857d4
...
89d49f3e34
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89d49f3e34 | ||
|
|
e813a01e14 | ||
|
|
72e3ef69ff | ||
|
|
94e7508a24 |
@ -36,7 +36,7 @@ class Config(object):
|
|||||||
ROOT = os.environ.get('ROOT') or "/home/kae/music"
|
ROOT = os.environ.get('ROOT') or "/home/kae/music"
|
||||||
TESTMODE = True
|
TESTMODE = True
|
||||||
TIMER_MS = 500
|
TIMER_MS = 500
|
||||||
VOLUME_VLC_DEFAULT = 81
|
VOLUME_VLC_DEFAULT = 75
|
||||||
|
|
||||||
|
|
||||||
config = Config
|
config = Config
|
||||||
|
|||||||
68
app/model.py
68
app/model.py
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime, time
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
from sqlalchemy import (
|
from sqlalchemy import (
|
||||||
Boolean,
|
Boolean,
|
||||||
@ -119,6 +119,35 @@ class Playdates(Base):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def remove_track(session, track_id):
|
||||||
|
"""
|
||||||
|
Remove all records of track_id
|
||||||
|
"""
|
||||||
|
|
||||||
|
session.query(Playdates).filter(
|
||||||
|
Playdates.track_id == track_id,
|
||||||
|
).delete()
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def last_show(session, track):
|
||||||
|
"""
|
||||||
|
Return datetime track last played during show time or None
|
||||||
|
|
||||||
|
FIXME: hard coded times in here
|
||||||
|
"""
|
||||||
|
|
||||||
|
# dayofweek: 1 = Sunday, 2 = Monday, ..., 7 = Saturday.
|
||||||
|
friday = 6
|
||||||
|
after = time(20, 0)
|
||||||
|
|
||||||
|
return session.query(Playdates).filter(
|
||||||
|
(Playdates.track_id == track.id),
|
||||||
|
(func.dayofweek(Playdates.lastplayed) == friday),
|
||||||
|
(func.time(Playdates.lastplayed) > after),
|
||||||
|
).order_by(Playdates.lastplayed.desc()).first()
|
||||||
|
|
||||||
|
|
||||||
class Playlists(Base):
|
class Playlists(Base):
|
||||||
"""
|
"""
|
||||||
@ -293,18 +322,11 @@ class PlaylistTracks(Base):
|
|||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_playlists_containing_track_id(session, track_id):
|
def get_track_playlists(session, track_id):
|
||||||
|
"Return all PlaylistTracks objects with this track_id"
|
||||||
|
|
||||||
playlists = []
|
return session.query(PlaylistTracks).filter(
|
||||||
playlist_ids = session.query(PlaylistTracks.playlist_id).filter(
|
|
||||||
PlaylistTracks.track_id == track_id).all()
|
PlaylistTracks.track_id == track_id).all()
|
||||||
for p in playlist_ids:
|
|
||||||
playlist = session.query(Playlists).filter(
|
|
||||||
Playlists.id == p[0]).first()
|
|
||||||
if playlist:
|
|
||||||
playlists.append(playlist)
|
|
||||||
|
|
||||||
return playlists
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def move_track(session, from_playlist_id, row, to_playlist_id):
|
def move_track(session, from_playlist_id, row, to_playlist_id):
|
||||||
@ -492,6 +514,29 @@ class Tracks(Base):
|
|||||||
ERROR(f"get_track({id}): not found")
|
ERROR(f"get_track({id}): not found")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def search(session, title=None, artist=None, duration=None):
|
||||||
|
"""
|
||||||
|
Return any tracks matching passed criteria
|
||||||
|
"""
|
||||||
|
|
||||||
|
DEBUG(
|
||||||
|
f"Tracks.search({title=}, {artist=}), {duration=})"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not title and not artist and not duration:
|
||||||
|
return None
|
||||||
|
|
||||||
|
q = session.query(Tracks).filter(False)
|
||||||
|
if title:
|
||||||
|
q = q.filter(Tracks.title == title)
|
||||||
|
if artist:
|
||||||
|
q = q.filter(Tracks.artist == artist)
|
||||||
|
if duration:
|
||||||
|
q = q.filter(Tracks.duration == duration)
|
||||||
|
|
||||||
|
return q.all()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_track_from_filename(session, filename):
|
def get_track_from_filename(session, filename):
|
||||||
"""
|
"""
|
||||||
@ -527,6 +572,7 @@ class Tracks(Base):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
session.query(Tracks).filter(Tracks.path == path).delete()
|
session.query(Tracks).filter(Tracks.path == path).delete()
|
||||||
|
session.commit()
|
||||||
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=})")
|
||||||
|
|
||||||
|
|||||||
@ -530,6 +530,11 @@ class PlaylistTab(QTableWidget):
|
|||||||
duration = Tracks.get_duration(session, self._get_row_id(row))
|
duration = Tracks.get_duration(session, self._get_row_id(row))
|
||||||
return start + timedelta(milliseconds=duration)
|
return start + timedelta(milliseconds=duration)
|
||||||
|
|
||||||
|
def _can_read_track(self, track):
|
||||||
|
"Check track file is readable"
|
||||||
|
|
||||||
|
return os.access(track.path, os.R_OK)
|
||||||
|
|
||||||
def _context_menu(self, pos):
|
def _context_menu(self, pos):
|
||||||
|
|
||||||
self.menu.exec_(self.mapToGlobal(pos))
|
self.menu.exec_(self.mapToGlobal(pos))
|
||||||
@ -617,12 +622,12 @@ class PlaylistTab(QTableWidget):
|
|||||||
if not track:
|
if not track:
|
||||||
txt = f"Track not found (track.id={id})"
|
txt = f"Track not found (track.id={id})"
|
||||||
else:
|
else:
|
||||||
txt = f"""
|
txt = (
|
||||||
Title: {track.title}
|
f"Title: {track.title}\n"
|
||||||
Artist: {track.artist}
|
f"Artist: {track.artist}\n"
|
||||||
Path: {track.path}
|
f"Path: {track.path}\n"
|
||||||
Track ID: {track.id}
|
f"Track ID: {track.id}"
|
||||||
"""
|
)
|
||||||
info = QMessageBox(self)
|
info = QMessageBox(self)
|
||||||
info.setIcon(QMessageBox.Information)
|
info.setIcon(QMessageBox.Information)
|
||||||
info.setText(txt)
|
info.setText(txt)
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import tempfile
|
|||||||
|
|
||||||
from config import Config
|
from config import Config
|
||||||
from log import DEBUG, INFO
|
from log import DEBUG, INFO
|
||||||
from model import Tracks, Playdates, PlaylistTracks, Session
|
from model import Notes, Playdates, PlaylistTracks, Session, Tracks
|
||||||
from mutagen.flac import FLAC
|
from mutagen.flac import FLAC
|
||||||
from mutagen.mp3 import MP3
|
from mutagen.mp3 import MP3
|
||||||
from pydub import AudioSegment, effects
|
from pydub import AudioSegment, effects
|
||||||
@ -255,22 +255,25 @@ def update_db(session):
|
|||||||
db_paths = set(Tracks.get_all_paths(session))
|
db_paths = set(Tracks.get_all_paths(session))
|
||||||
# Remote any tracks from database whose paths don't exist
|
# Remote any tracks from database whose paths don't exist
|
||||||
for path in list(db_paths - os_paths):
|
for path in list(db_paths - os_paths):
|
||||||
|
# Manage tracks listed in database but where path is invalid
|
||||||
track = Tracks.get_track_from_path(session, path)
|
track = Tracks.get_track_from_path(session, path)
|
||||||
DEBUG(f"songdb.update_db(): remove from database: {path=} {track=}")
|
DEBUG(f"songdb.update_db(): remove from database: {path=} {track=}")
|
||||||
played = Playdates.last_played(session, track)
|
|
||||||
playlists = PlaylistTracks.get_playlists_containing_track_id(
|
# Remove references from Playdates
|
||||||
session, track.id)
|
Playdates.remove_track(session, track.id)
|
||||||
if played:
|
|
||||||
INFO(
|
# Replace playlist entries with a note
|
||||||
f"songdb.update_db: Can't remove {track.id=} ({track.path=}) "
|
note_txt = (
|
||||||
f"as it's in playdates.id={played.id}"
|
f"File removed: {track.title=}, {track.artist=}, "
|
||||||
|
f"{track.path=}"
|
||||||
)
|
)
|
||||||
elif playlists:
|
for pt in PlaylistTracks.get_track_playlists(session, track.id):
|
||||||
INFO(
|
# Create note
|
||||||
f"songdb.update_db: Can't remove {track.id=} ({track.path=} "
|
Notes.add_note(session, pt.playlist_id, pt.row, note_txt)
|
||||||
f"as it's in playlists {[p.name for p in playlists]}"
|
# Remove playlist entry
|
||||||
)
|
PlaylistTracks.remove_track(session, pt.playlist_id, pt.row)
|
||||||
else:
|
|
||||||
|
# Remove Track entry pointing to invalid path
|
||||||
Tracks.remove_path(session, path)
|
Tracks.remove_path(session, path)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user