Add ability to download CSV of played tracks.

Fixes #60
This commit is contained in:
Keith Edmunds 2022-04-09 22:08:08 +01:00
parent e1800328fd
commit cf7930190e
6 changed files with 212 additions and 3 deletions

View File

@ -186,7 +186,7 @@ class Playdates(Base):
id: int = Column(Integer, primary_key=True, autoincrement=True) id: int = Column(Integer, primary_key=True, autoincrement=True)
lastplayed: datetime = Column(DateTime, index=True, default=None) lastplayed: datetime = Column(DateTime, index=True, default=None)
track_id: int = Column(Integer, ForeignKey('tracks.id')) track_id: int = Column(Integer, ForeignKey('tracks.id'))
tracks: RelationshipProperty = relationship( track: RelationshipProperty = relationship(
"Tracks", back_populates="playdates", lazy="joined") "Tracks", back_populates="playdates", lazy="joined")
def __init__(self, session: Session, track_id: int) -> None: def __init__(self, session: Session, track_id: int) -> None:
@ -212,6 +212,13 @@ class Playdates(Base):
else: else:
return None return None
@staticmethod
def played_after(session: Session, since: datetime) -> List["Playdates"]:
"""Return a list of Playdates objects since passed time"""
return session.query(Playdates).filter(
Playdates.lastplayed >= since).all()
@staticmethod @staticmethod
def remove_track(session: Session, track_id: int) -> None: def remove_track(session: Session, track_id: int) -> None:
""" """
@ -478,7 +485,8 @@ class Tracks(Base):
back_populates="tracks", back_populates="tracks",
lazy="joined") lazy="joined")
playdates: RelationshipProperty = relationship("Playdates", playdates: RelationshipProperty = relationship("Playdates",
back_populates="tracks", back_populates="track"
"",
lazy="joined") lazy="joined")
def __init__( def __init__(

View File

@ -11,7 +11,7 @@ from datetime import datetime
from log import DEBUG, EXCEPTION from log import DEBUG, EXCEPTION
from typing import Callable, Dict, List, Optional, Tuple from typing import Callable, Dict, List, Optional, Tuple
from PyQt5.QtCore import QEvent, QProcess, Qt, QTimer, QUrl from PyQt5.QtCore import QDate, QEvent, QProcess, Qt, QTime, QTimer, QUrl
from PyQt5.QtGui import QColor from PyQt5.QtGui import QColor
from PyQt5.QtWebEngineWidgets import QWebEngineView as QWebView from PyQt5.QtWebEngineWidgets import QWebEngineView as QWebView
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
@ -36,6 +36,7 @@ from playlists import PlaylistTab
from sqlalchemy.orm.exc import DetachedInstanceError from sqlalchemy.orm.exc import DetachedInstanceError
from ui.dlg_search_database_ui import Ui_Dialog from ui.dlg_search_database_ui import Ui_Dialog
from ui.dlg_SelectPlaylist_ui import Ui_dlgSelectPlaylist from ui.dlg_SelectPlaylist_ui import Ui_dlgSelectPlaylist
from ui.downloadcsv_ui import Ui_DateSelect
from ui.main_window_ui import Ui_MainWindow from ui.main_window_ui import Ui_MainWindow
from utilities import create_track_from_file from utilities import create_track_from_file
@ -170,6 +171,8 @@ class Window(QMainWindow, Ui_MainWindow):
self.actionAdd_note.triggered.connect(self.create_note) self.actionAdd_note.triggered.connect(self.create_note)
self.action_Clear_selection.triggered.connect(self.clear_selection) self.action_Clear_selection.triggered.connect(self.clear_selection)
self.actionClosePlaylist.triggered.connect(self.close_playlist_tab) self.actionClosePlaylist.triggered.connect(self.close_playlist_tab)
self.actionDownload_CSV_of_played_tracks.triggered.connect(
self.download_played_tracks)
self.actionEnable_controls.triggered.connect( self.actionEnable_controls.triggered.connect(
self.enable_play_next_controls) self.enable_play_next_controls)
self.actionExport_playlist.triggered.connect(self.export_playlist_tab) self.actionExport_playlist.triggered.connect(self.export_playlist_tab)
@ -279,6 +282,32 @@ class Window(QMainWindow, Ui_MainWindow):
self.actionPlay_next.setEnabled(False) self.actionPlay_next.setEnabled(False)
self.statusbar.showMessage("Play controls: Disabled", 0) self.statusbar.showMessage("Play controls: Disabled", 0)
def download_played_tracks(self) -> None:
"""Download a CSV of played tracks"""
dlg = DownloadCSV(self)
if dlg.exec():
start_dt = dlg.ui.dateTimeEdit.dateTime().toPyDateTime()
# Get output filename
pathspec: Tuple[str, str] = QFileDialog.getSaveFileName(
self, 'Save CSV of tracks played',
directory="/tmp/playlist.csv",
filter="CSV files (*.csv)"
)
if not pathspec:
return
path: str = pathspec[0]
if not path.endswith(".csv"):
path += ".csv"
with open(path, "w") as f:
with Session() as session:
for playdate in Playdates.played_after(session, start_dt):
f.write(
f"{playdate.track.artist},{playdate.track.title}\n"
)
def enable_play_next_controls(self) -> None: def enable_play_next_controls(self) -> None:
""" """
Enable "play next" keyboard controls Enable "play next" keyboard controls
@ -957,6 +986,18 @@ class DbDialog(QDialog):
self.ui.dbPath.setText(track.path) self.ui.dbPath.setText(track.path)
class DownloadCSV(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = Ui_DateSelect()
self.ui.setupUi(self)
self.ui.dateTimeEdit.setDate(QDate.currentDate())
self.ui.dateTimeEdit.setTime(QTime(19, 59, 0))
self.ui.buttonBox.accepted.connect(self.accept)
self.ui.buttonBox.rejected.connect(self.reject)
class SelectPlaylistDialog(QDialog): class SelectPlaylistDialog(QDialog):
def __init__(self, parent=None, playlists=None, session=None): def __init__(self, parent=None, playlists=None, session=None):
super().__init__(parent) super().__init__(parent)

107
app/ui/downloadcsv.ui Normal file
View File

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DateSelect</class>
<widget class="QDialog" name="DateSelect">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>280</width>
<height>166</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>70</x>
<y>110</y>
<width>191</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<widget class="QDateTimeEdit" name="dateTimeEdit">
<property name="geometry">
<rect>
<x>70</x>
<y>60</y>
<width>194</width>
<height>28</height>
</rect>
</property>
<property name="calendarPopup">
<bool>true</bool>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>261</width>
<height>19</height>
</rect>
</property>
<property name="text">
<string>Download CSV of tracks played</string>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>15</x>
<y>66</y>
<width>51</width>
<height>19</height>
</rect>
</property>
<property name="text">
<string>Since:</string>
</property>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DateSelect</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DateSelect</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

43
app/ui/downloadcsv_ui.py Normal file
View File

@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/downloadcsv.ui'
#
# Created by: PyQt5 UI code generator 5.15.6
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_DateSelect(object):
def setupUi(self, DateSelect):
DateSelect.setObjectName("DateSelect")
DateSelect.resize(280, 166)
self.buttonBox = QtWidgets.QDialogButtonBox(DateSelect)
self.buttonBox.setGeometry(QtCore.QRect(70, 110, 191, 32))
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.dateTimeEdit = QtWidgets.QDateTimeEdit(DateSelect)
self.dateTimeEdit.setGeometry(QtCore.QRect(70, 60, 194, 28))
self.dateTimeEdit.setCalendarPopup(True)
self.dateTimeEdit.setObjectName("dateTimeEdit")
self.label = QtWidgets.QLabel(DateSelect)
self.label.setGeometry(QtCore.QRect(10, 20, 261, 19))
self.label.setObjectName("label")
self.label_2 = QtWidgets.QLabel(DateSelect)
self.label_2.setGeometry(QtCore.QRect(15, 66, 51, 19))
self.label_2.setObjectName("label_2")
self.retranslateUi(DateSelect)
self.buttonBox.accepted.connect(DateSelect.accept) # type: ignore
self.buttonBox.rejected.connect(DateSelect.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(DateSelect)
def retranslateUi(self, DateSelect):
_translate = QtCore.QCoreApplication.translate
DateSelect.setWindowTitle(_translate("DateSelect", "Dialog"))
self.label.setText(_translate("DateSelect", "Download CSV of tracks played"))
self.label_2.setText(_translate("DateSelect", "Since:"))

View File

@ -786,6 +786,7 @@ border: 1px solid rgb(85, 87, 83);</string>
<addaction name="actionSelect_played_tracks"/> <addaction name="actionSelect_played_tracks"/>
<addaction name="actionMoveSelected"/> <addaction name="actionMoveSelected"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionDownload_CSV_of_played_tracks"/>
<addaction name="actionExport_playlist"/> <addaction name="actionExport_playlist"/>
</widget> </widget>
<widget class="QMenu" name="menu_Music"> <widget class="QMenu" name="menu_Music">
@ -1022,6 +1023,11 @@ border: 1px solid rgb(85, 87, 83);</string>
<string>Ctrl+Shift+I</string> <string>Ctrl+Shift+I</string>
</property> </property>
</action> </action>
<action name="actionDownload_CSV_of_played_tracks">
<property name="text">
<string>Download CSV of played tracks...</string>
</property>
</action>
</widget> </widget>
<resources> <resources>
<include location="icons.qrc"/> <include location="icons.qrc"/>

View File

@ -443,6 +443,8 @@ class Ui_MainWindow(object):
self.actionEnable_controls.setObjectName("actionEnable_controls") self.actionEnable_controls.setObjectName("actionEnable_controls")
self.actionImport = QtWidgets.QAction(MainWindow) self.actionImport = QtWidgets.QAction(MainWindow)
self.actionImport.setObjectName("actionImport") self.actionImport.setObjectName("actionImport")
self.actionDownload_CSV_of_played_tracks = QtWidgets.QAction(MainWindow)
self.actionDownload_CSV_of_played_tracks.setObjectName("actionDownload_CSV_of_played_tracks")
self.menuFile.addAction(self.actionImport) self.menuFile.addAction(self.actionImport)
self.menuFile.addSeparator() self.menuFile.addSeparator()
self.menuFile.addAction(self.actionE_xit) self.menuFile.addAction(self.actionE_xit)
@ -465,6 +467,7 @@ class Ui_MainWindow(object):
self.menuPlaylist.addAction(self.actionSelect_played_tracks) self.menuPlaylist.addAction(self.actionSelect_played_tracks)
self.menuPlaylist.addAction(self.actionMoveSelected) self.menuPlaylist.addAction(self.actionMoveSelected)
self.menuPlaylist.addSeparator() self.menuPlaylist.addSeparator()
self.menuPlaylist.addAction(self.actionDownload_CSV_of_played_tracks)
self.menuPlaylist.addAction(self.actionExport_playlist) self.menuPlaylist.addAction(self.actionExport_playlist)
self.menu_Music.addAction(self.actionPlay_next) self.menu_Music.addAction(self.actionPlay_next)
self.menu_Music.addAction(self.actionSkip_next) self.menu_Music.addAction(self.actionSkip_next)
@ -553,4 +556,5 @@ class Ui_MainWindow(object):
self.actionEnable_controls.setText(_translate("MainWindow", "Enable controls")) self.actionEnable_controls.setText(_translate("MainWindow", "Enable controls"))
self.actionImport.setText(_translate("MainWindow", "Import...")) self.actionImport.setText(_translate("MainWindow", "Import..."))
self.actionImport.setShortcut(_translate("MainWindow", "Ctrl+Shift+I")) self.actionImport.setShortcut(_translate("MainWindow", "Ctrl+Shift+I"))
self.actionDownload_CSV_of_played_tracks.setText(_translate("MainWindow", "Download CSV of played tracks..."))
import icons_rc import icons_rc