Store playlist in db
This commit is contained in:
parent
ddce8f2391
commit
af895ef577
94
app/model.py
94
app/model.py
@ -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()
|
||||||
|
|||||||
@ -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}"
|
||||||
|
|
||||||
|
|||||||
@ -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 ###
|
||||||
@ -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
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user