Compare commits

..

4 Commits

Author SHA1 Message Date
Keith Edmunds
436f6b4fa9 Export playlist working 2022-08-13 13:32:25 +01:00
Keith Edmunds
9485b244f5 Export played tracks csv works 2022-08-13 12:57:37 +01:00
Keith Edmunds
63acc025f9 Close tab works 2022-08-13 12:27:38 +01:00
Keith Edmunds
066b20a571 Close playlist from menubar 2022-08-13 12:03:35 +01:00
3 changed files with 172 additions and 161 deletions

View File

@ -249,13 +249,20 @@ class Playdates(Base):
return last_played[0]
else:
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
def played_after(session: Session, since: datetime) -> List["Playdates"]:
"""Return a list of Playdates objects since passed time"""
return (
session.execute(
select(Playdates)
.where(Playdates.lastplayed >= since)
.order_by(Playdates.lastplayed)
)
.scalars()
.all()
)
#
# @staticmethod
# def remove_track(session: Session, track_id: int) -> None:
@ -289,7 +296,6 @@ class Playlists(Base):
def __repr__(self) -> str:
return f"<Playlists(id={self.id}, name={self.name}>"
#
# def __init__(self, session: Session, name: str) -> None:
# self.name = name
@ -308,13 +314,11 @@ class Playlists(Base):
# row = self.next_free_row(session, self.id)
#
# xPlaylistTracks(session, self.id, track_id, row)
#
# def close(self, session: Session) -> None:
# """Record playlist as no longer loaded"""
#
# self.loaded = False
# session.add(self)
# session.flush()
def close(self, session: Session) -> None:
"""Mark playlist as unloaded"""
self.loaded = False
@classmethod
def get_all(cls, session: Session) -> List["Playlists"]:
@ -506,40 +510,40 @@ class PlaylistRows(Base):
# Ensure new row numbers are available to the caller
session.commit()
@staticmethod
def get_played_rows(session: Session,
@classmethod
def get_played_rows(cls, session: Session,
playlist_id: int) -> List[int]:
"""
For passed playlist, return a list of row numbers that
For passed playlist, return a list of rows that
have been played.
"""
plrs = session.execute(
select(PlaylistRows.row_number)
select(cls)
.where(
PlaylistRows.playlist_id == playlist_id,
PlaylistRows.played.is_(True)
cls.playlist_id == playlist_id,
cls.played.is_(True)
)
.order_by(PlaylistRows.row_number)
.order_by(cls.row_number)
).scalars().all()
return plrs
@staticmethod
def get_rows_with_tracks(session: Session,
playlist_id: int) -> List[int]:
@classmethod
def get_rows_with_tracks(cls, session: Session,
playlist_id: int) -> List[int]:
"""
For passed playlist, return a list of all row numbers that
For passed playlist, return a list of rows that
contain tracks
"""
plrs = session.execute(
select(PlaylistRows.row_number)
select(cls)
.where(
PlaylistRows.playlist_id == playlist_id,
PlaylistRows.track_id.is_not(None)
cls.playlist_id == playlist_id,
cls.track_id.is_not(None)
)
.order_by(PlaylistRows.row_number)
.order_by(cls.row_number)
).scalars().all()
return plrs

View File

@ -7,14 +7,13 @@ import sys
from datetime import datetime, timedelta
# from typing import Callable, Dict, List, Optional, Tuple
#
# from PyQt5.QtCore import QDate, QProcess, Qt, QTime, QTimer, QUrl
from PyQt5.QtCore import QEvent, Qt, QTimer
from PyQt5.QtCore import QDate, QEvent, Qt, QTime, QTimer
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import (
QApplication,
QDialog,
# QFileDialog,
QFileDialog,
# QInputDialog,
QLabel,
# QLineEdit,
@ -39,7 +38,7 @@ from playlists import PlaylistTab
from sqlalchemy.orm.exc import DetachedInstanceError
# from ui.dlg_search_database_ui import Ui_Dialog
from ui.dlg_SelectPlaylist_ui import Ui_dlgSelectPlaylist # type: ignore
# from ui.downloadcsv_ui import Ui_DateSelect
from ui.downloadcsv_ui import Ui_DateSelect # type: ignore
from config import Config
from ui.main_window_ui import Ui_MainWindow # type: ignore
# from utilities import create_track_from_file, update_db
@ -170,12 +169,13 @@ class Window(QMainWindow, Ui_MainWindow):
def connect_signals_slots(self) -> None:
# self.actionAdd_note.triggered.connect(self.create_note)
self.action_Clear_selection.triggered.connect(self.clear_selection)
# self.actionClosePlaylist.triggered.connect(self.close_playlist_tab)
# self.actionDownload_CSV_of_played_tracks.triggered.connect(
# self.download_played_tracks)
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.enable_play_next_controls)
# self.actionExport_playlist.triggered.connect(self.export_playlist_tab)
self.actionExport_playlist.triggered.connect(self.export_playlist_tab)
# ***kae
# self.actionImport.triggered.connect(self.import_track)
self.actionFade.triggered.connect(self.fade)
# self.actionMoveSelected.triggered.connect(self.move_selected)
@ -198,7 +198,7 @@ class Window(QMainWindow, Ui_MainWindow):
# self.btnHidePlayed.clicked.connect(self.hide_played)
self.btnFade.clicked.connect(self.fade)
self.btnStop.clicked.connect(self.stop)
# self.tabPlaylist.tabCloseRequested.connect(self.close_tab)
self.tabPlaylist.tabCloseRequested.connect(self.close_tab)
# self.txtSearch.returnPressed.connect(self.search_playlist_return)
# self.txtSearch.textChanged.connect(self.search_playlist_update)
#
@ -216,32 +216,36 @@ class Window(QMainWindow, Ui_MainWindow):
# with Session() as session:
# playlist = Playlists(session, dlg.textValue())
# self.create_playlist_tab(session, playlist)
#
# def close_playlist_tab(self) -> None:
# """Close active playlist tab"""
#
# self.close_tab(self.tabPlaylist.currentIndex())
#
# def close_tab(self, index: int) -> None:
# """
# Close tab unless it holds the curren or next track
# """
#
# if hasattr(self.tabPlaylist.widget(index), 'playlist_id'):
# if self.tabPlaylist.widget(index) == (
# self.current_track_playlist_tab):
# self.statusbar.showMessage(
# "Can't close current track playlist", 5000)
# return
# if self.tabPlaylist.widget(index) == self.next_track_playlist_tab:
# self.statusbar.showMessage(
# "Can't close next track playlist", 5000)
# return
# # It's OK to close this playlist so remove from open playlist list
# self.tabPlaylist.widget(index).close()
#
# # Close regardless of tab type
# self.tabPlaylist.removeTab(index)
def close_playlist_tab(self) -> None:
"""
Close active playlist tab, called by menu item
"""
self.close_tab(self.tabPlaylist.currentIndex())
def close_tab(self, tab_index: int) -> None:
"""
Close active playlist tab unless it holds the curren or next track.
Called from close_playlist_tab() or by clicking close button on tab.
"""
# Don't close current track playlist
if self.tabPlaylist.widget(tab_index) == (
self.current_track_playlist_tab):
self.statusbar.showMessage(
"Can't close current track playlist", 5000)
return
# Don't close next track playlist
if self.tabPlaylist.widget(tab_index) == self.next_track_playlist_tab:
self.statusbar.showMessage(
"Can't close next track playlist", 5000)
return
# Close playlist and remove tab
self.tabPlaylist.widget(tab_index).close()
self.tabPlaylist.removeTab(tab_index)
#
# def create_note(self) -> None:
# """Call playlist to create note"""
@ -271,32 +275,32 @@ class Window(QMainWindow, Ui_MainWindow):
self.actionPlay_next.setEnabled(False)
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 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 = QFileDialog.getSaveFileName(
self, 'Save CSV of tracks played',
directory="/tmp/playlist.csv",
filter="CSV files (*.csv)"
)
if not pathspec:
return
path = 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 drop3db(self) -> None:
# """Drop music level by 3db if button checked"""
@ -360,42 +364,45 @@ class Window(QMainWindow, Ui_MainWindow):
# Enable controls
self.enable_play_next_controls()
#
# def export_playlist_tab(self) -> None:
# """Export the current playlist to an m3u file"""
#
# if not self.visible_playlist_tab():
# return
#
# with Session() as session:
# playlist = Playlists.get_by_id(
# session, self.visible_playlist_tab().playlist_id)
# # Get output filename
# pathspec: Tuple[str, str] = QFileDialog.getSaveFileName(
# self, 'Save Playlist',
# directory=f"{playlist.name}.m3u",
# filter="M3U files (*.m3u);;All files (*.*)"
# )
# if not pathspec:
# return
#
# path: str = pathspec[0]
# if not path.endswith(".m3u"):
# path += ".m3u"
#
# with open(path, "w") as f:
# # Required directive on first line
# f.write("#EXTM3U\n")
# for _, track in playlist.tracks.items():
# f.write(
# "#EXTINF:"
# f"{int(track.duration / 1000)},"
# f"{track.title} - "
# f"{track.artist}"
# "\n"
# f"{track.path}"
# "\n"
# )
def export_playlist_tab(self) -> None:
"""Export the current playlist to an m3u file"""
if not self.visible_playlist_tab():
return
playlist_id = self.visible_playlist_tab().playlist_id
with Session() as session:
# Get output filename
playlist = session.get(Playlists, playlist_id)
pathspec = QFileDialog.getSaveFileName(
self, 'Save Playlist',
directory=f"{playlist.name}.m3u",
filter="M3U files (*.m3u);;All files (*.*)"
)
if not pathspec:
return
path = pathspec[0]
if not path.endswith(".m3u"):
path += ".m3u"
# Get list of track rows for this playlist
plrs = PlaylistRows.get_rows_with_tracks(session, playlist_id)
with open(path, "w") as f:
# Required directive on first line
f.write("#EXTM3U\n")
for track in [a.track for a in plrs]:
f.write(
"#EXTINF:"
f"{int(track.duration / 1000)},"
f"{track.title} - "
f"{track.artist}"
"\n"
f"{track.path}"
"\n"
)
def fade(self) -> None:
"""Fade currently playing track"""
@ -970,18 +977,18 @@ class Window(QMainWindow, Ui_MainWindow):
# item = self.ui.matchList.currentItem()
# track = item.data(Qt.UserRole)
# 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 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):

View File

@ -349,23 +349,15 @@ class PlaylistTab(QTableWidget):
return [self._get_playlistrow_id(a) for a in self._selected_rows()]
# def closeEvent(self, event) -> None:
# """Save column widths"""
#
# log.debug(f"playlists.closeEvent()")
# with Session() as session:
# for column in range(self.columnCount()):
# width = self.columnWidth(column)
# name = f"playlist_col_{str(column)}_width"
# record = Settings.get_int_settings(session, name)
# if record.f_int != self.columnWidth(column):
# record.update(session, {'f_int': width})
#
# # Record playlist as closed
# playlist = Playlists.get_by_id(session, self.playlist_id)
# playlist.close(session)
#
# event.accept()
def closeEvent(self, event) -> None:
"""Handle closing playist tab"""
with Session() as session:
# Record playlist as closed
playlist = session.get(Playlists, self.playlist_id)
playlist.close(session)
event.accept()
def clear_next(self, session) -> None:
"""Clear next track marker"""
@ -930,7 +922,10 @@ class PlaylistTab(QTableWidget):
current_row: Optional[int] = self._get_current_track_row()
next_row: Optional[int] = self._get_next_track_row()
played = PlaylistRows.get_played_rows(session, self.playlist_id)
played = [
p.row_number for p in PlaylistRows.get_played_rows(
session, self.playlist_id)
]
unreadable: List[int] = self._get_unreadable_track_rows()
if self.row_filter:
@ -1344,9 +1339,14 @@ class PlaylistTab(QTableWidget):
if starting_row is None:
starting_row = 0
track_rows = PlaylistRows.get_rows_with_tracks(session,
self.playlist_id)
played_rows = PlaylistRows.get_played_rows(session, self.playlist_id)
track_rows = [
p.row_number for p in PlaylistRows.get_rows_with_tracks(
session, self.playlist_id)
]
played_rows = [
p.row_number for p in PlaylistRows.get_played_rows(
session, self.playlist_id)
]
for row in range(starting_row, self.rowCount()):
if row not in track_rows or row in played_rows:
continue