Store playlist in db

This commit is contained in:
Keith Edmunds 2021-03-27 22:41:29 +00:00
parent ddce8f2391
commit af895ef577
4 changed files with 159 additions and 6 deletions

View File

@ -3,10 +3,19 @@
import os import os
import sqlalchemy import sqlalchemy
from datetime import datetime
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Float, DateTime, Integer, String from sqlalchemy import (
Column,
DateTime,
Float,
ForeignKey,
Integer,
String,
Table
)
from sqlalchemy.orm.exc import NoResultFound from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import relationship, sessionmaker
from config import Config from config import Config
@ -60,6 +69,63 @@ class Settings(Base):
session.commit() session.commit()
playlist_tracks = Table(
'playlistracks',
Base.metadata,
Column('playlist_id', Integer, ForeignKey('playlists.id')),
Column('track_id', Integer, ForeignKey('tracks.id'))
)
class Playlists(Base):
"""
Usage:
In [3]: pl = session.query(Playlists).filter(Playlists.id == 1).one()
In [4]: pl
Out[4]: <Playlist(id=1, name=Default>
In [5]: tr = session.query(Tracks).filter(Tracks.id == 3837).one()
In [6]: tr
Out[6]: <Track(id=3837, title=Babe, artist=Various, path=/home/[...]
In [7]: pl.tracks.append(tr)
...: session.commit()
In [8]: tr.playlists
Out[8]: [<Playlist(id=1, name=Default>]
In [9]: pl.tracks
Out[9]: [<Track(id=3837, title=Babe, artist=Various, path=/home/[...]
"""
__tablename__ = "playlists"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(32), nullable=False, unique=True)
tracks = relationship(
"Tracks",
secondary=playlist_tracks,
back_populates="playlists")
def __repr__(self):
return (f"<Playlist(id={self.id}, name={self.name}>")
# Currently we only support one playlist, so make that obvious from
# function name
@classmethod
def get_only_playlist(cls):
return session.query(Playlists).filter(Playlists.id == 1).one()
def add_track(self, track):
self.tracks.append(track)
def get_tracks(self):
return self.tracks
class Tracks(Base): class Tracks(Base):
__tablename__ = 'tracks' __tablename__ = 'tracks'
@ -71,9 +137,14 @@ class Tracks(Base):
fade_at = Column(Integer, index=False) fade_at = Column(Integer, index=False)
silence_at = Column(Integer, index=False) silence_at = Column(Integer, index=False)
path = Column(String(2048), index=False, nullable=False) path = Column(String(2048), index=False, nullable=False)
mtime = Column(Float, index=True) mtime = Column(Float, index=True)
lastplayed = Column(DateTime, index=True, default=None) lastplayed = Column(DateTime, index=True, default=None)
playlists = relationship(
"Playlists",
secondary=playlist_tracks,
back_populates="tracks")
playdates_id = Column(Integer, ForeignKey('playdates.id'))
playdates = relationship("Playdates", back_populates="tracks")
def __repr__(self): def __repr__(self):
return ( return (
@ -123,3 +194,20 @@ class Tracks(Base):
def track_from_id(id): def track_from_id(id):
return session.query(Tracks).filter( return session.query(Tracks).filter(
Tracks.id == id).one() Tracks.id == id).one()
class Playdates(Base):
__tablename__ = 'playdates'
id = Column(Integer, primary_key=True, autoincrement=True)
lastplayed = Column(DateTime, index=True, default=None)
tracks = relationship("Tracks", back_populates="playdates")
@staticmethod
def add_playdate(track):
DEBUG(f"add_playdate({track})")
pd = Playdates()
pd.lastplayed = datetime.now()
pd.tracks.append(track)
session.add(pd)
session.commit()

View File

@ -14,7 +14,7 @@ from ui.main_window_ui import Ui_MainWindow
from ui.dlg_search_database_ui import Ui_Dialog from ui.dlg_search_database_ui import Ui_Dialog
from config import Config from config import Config
from model import Settings, Tracks from model import Playdates, Playlists, Settings, Tracks
class Music: class Music:
@ -106,6 +106,7 @@ class Music:
self.previous_track = self.current_track self.previous_track = self.current_track
self.current_track = self.next_track self.current_track = self.next_track
self.current_track['player'].play() self.current_track['player'].play()
Playdates.add_playdate(self.current_track['meta'])
# Tidy up # Tidy up
self.next_track = { self.next_track = {
@ -158,6 +159,11 @@ class Window(QMainWindow, Ui_MainWindow):
if record.f_int is not None: if record.f_int is not None:
self.playlist.setColumnWidth(column, record.f_int) self.playlist.setColumnWidth(column, record.f_int)
# Load playlist
db_playlist = Playlists.get_only_playlist()
for track in db_playlist.get_tracks():
self.add_to_playlist(track)
self.timer.start(Config.TIMER_MS) self.timer.start(Config.TIMER_MS)
def __del__(self): def __del__(self):
@ -369,6 +375,12 @@ class DbDialog(QDialog):
def listdclick(self, entry): def listdclick(self, entry):
track_id = entry.data(Qt.UserRole) track_id = entry.data(Qt.UserRole)
track = Tracks.track_from_id(track_id) track = Tracks.track_from_id(track_id)
# Store in current playlist in database
db_playlist = Playlists.get_only_playlist()
db_playlist.add_track(track)
# Add to on-screen playlist
self.parent().add_to_playlist(track) self.parent().add_to_playlist(track)
@ -384,8 +396,8 @@ def ms_to_mmss(ms, decimals=0, negative=False):
minutes, remainder = divmod(ms, 60 * 1000) minutes, remainder = divmod(ms, 60 * 1000)
seconds = remainder / 1000 seconds = remainder / 1000
if seconds == 60: if int(seconds) == 60:
print(f"ms_to_mmss({ms}) gave 60 seconds") DEBUG(f"ms_to_mmss({ms}) gave 60 seconds")
return f"{sign}{minutes:.0f}:{seconds:02.{decimals}f}" return f"{sign}{minutes:.0f}:{seconds:02.{decimals}f}"

View File

@ -0,0 +1,52 @@
"""Add playlist and playtimes
Revision ID: f07b96a5e60f
Revises: b0983648595e
Create Date: 2021-03-27 19:53:09.524989
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'f07b96a5e60f'
down_revision = 'b0983648595e'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('playdates',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('lastplayed', sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_playdates_lastplayed'), 'playdates', ['lastplayed'], unique=False)
op.create_table('playlists',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('name', sa.String(length=32), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name')
)
op.create_table('playlistracks',
sa.Column('playlist_id', sa.Integer(), nullable=True),
sa.Column('track_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['playlist_id'], ['playlists.id'], ),
sa.ForeignKeyConstraint(['track_id'], ['tracks.id'], )
)
op.add_column('tracks', sa.Column('playdates_id', sa.Integer(), nullable=True))
op.create_foreign_key(None, 'tracks', 'playdates', ['playdates_id'], ['id'])
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'tracks', type_='foreignkey')
op.drop_column('tracks', 'playdates_id')
op.drop_table('playlistracks')
op.drop_table('playlists')
op.drop_index(op.f('ix_playdates_lastplayed'), table_name='playdates')
op.drop_table('playdates')
# ### end Alembic commands ###

View File

@ -54,6 +54,7 @@ First release
Status bar Status bar
Timer colour warnings Timer colour warnings
Non-track playlist entries Non-track playlist entries
Fade entry for some tracks is zero
Later releases Later releases
Autoplay next track Autoplay next track
Track properties Track properties