Compare commits
No commits in common. "436f6b4fa948da572742e4434d97e7b7c1bcb9e5" and "f1796451ae97c6406ef0b1fbb2a32a6e4710fae4" have entirely different histories.
436f6b4fa9
...
f1796451ae
@ -249,20 +249,13 @@ class Playdates(Base):
|
|||||||
return last_played[0]
|
return last_played[0]
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
#
|
||||||
@staticmethod
|
# @staticmethod
|
||||||
def played_after(session: Session, since: datetime) -> List["Playdates"]:
|
# def played_after(session: Session, since: datetime) -> List["Playdates"]:
|
||||||
"""Return a list of Playdates objects since passed time"""
|
# """Return a list of Playdates objects since passed time"""
|
||||||
|
#
|
||||||
return (
|
# return session.query(Playdates).filter(
|
||||||
session.execute(
|
# Playdates.lastplayed >= since).all()
|
||||||
select(Playdates)
|
|
||||||
.where(Playdates.lastplayed >= since)
|
|
||||||
.order_by(Playdates.lastplayed)
|
|
||||||
)
|
|
||||||
.scalars()
|
|
||||||
.all()
|
|
||||||
)
|
|
||||||
#
|
#
|
||||||
# @staticmethod
|
# @staticmethod
|
||||||
# def remove_track(session: Session, track_id: int) -> None:
|
# def remove_track(session: Session, track_id: int) -> None:
|
||||||
@ -296,6 +289,7 @@ class Playlists(Base):
|
|||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"<Playlists(id={self.id}, name={self.name}>"
|
return f"<Playlists(id={self.id}, name={self.name}>"
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# def __init__(self, session: Session, name: str) -> None:
|
# def __init__(self, session: Session, name: str) -> None:
|
||||||
# self.name = name
|
# self.name = name
|
||||||
@ -314,11 +308,13 @@ class Playlists(Base):
|
|||||||
# row = self.next_free_row(session, self.id)
|
# row = self.next_free_row(session, self.id)
|
||||||
#
|
#
|
||||||
# xPlaylistTracks(session, self.id, track_id, row)
|
# xPlaylistTracks(session, self.id, track_id, row)
|
||||||
|
#
|
||||||
def close(self, session: Session) -> None:
|
# def close(self, session: Session) -> None:
|
||||||
"""Mark playlist as unloaded"""
|
# """Record playlist as no longer loaded"""
|
||||||
|
#
|
||||||
self.loaded = False
|
# self.loaded = False
|
||||||
|
# session.add(self)
|
||||||
|
# session.flush()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_all(cls, session: Session) -> List["Playlists"]:
|
def get_all(cls, session: Session) -> List["Playlists"]:
|
||||||
@ -510,40 +506,40 @@ class PlaylistRows(Base):
|
|||||||
# Ensure new row numbers are available to the caller
|
# Ensure new row numbers are available to the caller
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
@classmethod
|
@staticmethod
|
||||||
def get_played_rows(cls, session: Session,
|
def get_played_rows(session: Session,
|
||||||
playlist_id: int) -> List[int]:
|
playlist_id: int) -> List[int]:
|
||||||
"""
|
"""
|
||||||
For passed playlist, return a list of rows that
|
For passed playlist, return a list of row numbers that
|
||||||
have been played.
|
have been played.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
plrs = session.execute(
|
plrs = session.execute(
|
||||||
select(cls)
|
select(PlaylistRows.row_number)
|
||||||
.where(
|
.where(
|
||||||
cls.playlist_id == playlist_id,
|
PlaylistRows.playlist_id == playlist_id,
|
||||||
cls.played.is_(True)
|
PlaylistRows.played.is_(True)
|
||||||
)
|
)
|
||||||
.order_by(cls.row_number)
|
.order_by(PlaylistRows.row_number)
|
||||||
).scalars().all()
|
).scalars().all()
|
||||||
|
|
||||||
return plrs
|
return plrs
|
||||||
|
|
||||||
@classmethod
|
@staticmethod
|
||||||
def get_rows_with_tracks(cls, session: Session,
|
def get_rows_with_tracks(session: Session,
|
||||||
playlist_id: int) -> List[int]:
|
playlist_id: int) -> List[int]:
|
||||||
"""
|
"""
|
||||||
For passed playlist, return a list of rows that
|
For passed playlist, return a list of all row numbers that
|
||||||
contain tracks
|
contain tracks
|
||||||
"""
|
"""
|
||||||
|
|
||||||
plrs = session.execute(
|
plrs = session.execute(
|
||||||
select(cls)
|
select(PlaylistRows.row_number)
|
||||||
.where(
|
.where(
|
||||||
cls.playlist_id == playlist_id,
|
PlaylistRows.playlist_id == playlist_id,
|
||||||
cls.track_id.is_not(None)
|
PlaylistRows.track_id.is_not(None)
|
||||||
)
|
)
|
||||||
.order_by(cls.row_number)
|
.order_by(PlaylistRows.row_number)
|
||||||
).scalars().all()
|
).scalars().all()
|
||||||
|
|
||||||
return plrs
|
return plrs
|
||||||
|
|||||||
@ -7,13 +7,14 @@ import sys
|
|||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
# from typing import Callable, Dict, List, Optional, Tuple
|
# from typing import Callable, Dict, List, Optional, Tuple
|
||||||
|
#
|
||||||
from PyQt5.QtCore import QDate, QEvent, Qt, QTime, QTimer
|
# from PyQt5.QtCore import QDate, QProcess, Qt, QTime, QTimer, QUrl
|
||||||
|
from PyQt5.QtCore import QEvent, Qt, QTimer
|
||||||
from PyQt5.QtGui import QColor
|
from PyQt5.QtGui import QColor
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QApplication,
|
QApplication,
|
||||||
QDialog,
|
QDialog,
|
||||||
QFileDialog,
|
# QFileDialog,
|
||||||
# QInputDialog,
|
# QInputDialog,
|
||||||
QLabel,
|
QLabel,
|
||||||
# QLineEdit,
|
# QLineEdit,
|
||||||
@ -38,7 +39,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 # type: ignore
|
from ui.dlg_SelectPlaylist_ui import Ui_dlgSelectPlaylist # type: ignore
|
||||||
from ui.downloadcsv_ui import Ui_DateSelect # type: ignore
|
# from ui.downloadcsv_ui import Ui_DateSelect
|
||||||
from config import Config
|
from config import Config
|
||||||
from ui.main_window_ui import Ui_MainWindow # type: ignore
|
from ui.main_window_ui import Ui_MainWindow # type: ignore
|
||||||
# from utilities import create_track_from_file, update_db
|
# from utilities import create_track_from_file, update_db
|
||||||
@ -169,13 +170,12 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
def connect_signals_slots(self) -> None:
|
def connect_signals_slots(self) -> None:
|
||||||
# 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.actionDownload_CSV_of_played_tracks.triggered.connect(
|
||||||
self.download_played_tracks)
|
# 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)
|
||||||
# ***kae
|
|
||||||
# self.actionImport.triggered.connect(self.import_track)
|
# self.actionImport.triggered.connect(self.import_track)
|
||||||
self.actionFade.triggered.connect(self.fade)
|
self.actionFade.triggered.connect(self.fade)
|
||||||
# self.actionMoveSelected.triggered.connect(self.move_selected)
|
# self.actionMoveSelected.triggered.connect(self.move_selected)
|
||||||
@ -198,7 +198,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
# self.btnHidePlayed.clicked.connect(self.hide_played)
|
# self.btnHidePlayed.clicked.connect(self.hide_played)
|
||||||
self.btnFade.clicked.connect(self.fade)
|
self.btnFade.clicked.connect(self.fade)
|
||||||
self.btnStop.clicked.connect(self.stop)
|
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.returnPressed.connect(self.search_playlist_return)
|
||||||
# self.txtSearch.textChanged.connect(self.search_playlist_update)
|
# self.txtSearch.textChanged.connect(self.search_playlist_update)
|
||||||
#
|
#
|
||||||
@ -216,36 +216,32 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
# with Session() as session:
|
# with Session() as session:
|
||||||
# playlist = Playlists(session, dlg.textValue())
|
# playlist = Playlists(session, dlg.textValue())
|
||||||
# self.create_playlist_tab(session, playlist)
|
# self.create_playlist_tab(session, playlist)
|
||||||
|
#
|
||||||
def close_playlist_tab(self) -> None:
|
# def close_playlist_tab(self) -> None:
|
||||||
"""
|
# """Close active playlist tab"""
|
||||||
Close active playlist tab, called by menu item
|
#
|
||||||
"""
|
# self.close_tab(self.tabPlaylist.currentIndex())
|
||||||
|
#
|
||||||
self.close_tab(self.tabPlaylist.currentIndex())
|
# def close_tab(self, index: int) -> None:
|
||||||
|
# """
|
||||||
def close_tab(self, tab_index: int) -> None:
|
# Close tab unless it holds the curren or next track
|
||||||
"""
|
# """
|
||||||
Close active playlist tab unless it holds the curren or next track.
|
#
|
||||||
Called from close_playlist_tab() or by clicking close button on tab.
|
# if hasattr(self.tabPlaylist.widget(index), 'playlist_id'):
|
||||||
"""
|
# if self.tabPlaylist.widget(index) == (
|
||||||
|
# self.current_track_playlist_tab):
|
||||||
# Don't close current track playlist
|
# self.statusbar.showMessage(
|
||||||
if self.tabPlaylist.widget(tab_index) == (
|
# "Can't close current track playlist", 5000)
|
||||||
self.current_track_playlist_tab):
|
# return
|
||||||
self.statusbar.showMessage(
|
# if self.tabPlaylist.widget(index) == self.next_track_playlist_tab:
|
||||||
"Can't close current track playlist", 5000)
|
# self.statusbar.showMessage(
|
||||||
return
|
# "Can't close next track playlist", 5000)
|
||||||
|
# return
|
||||||
# Don't close next track playlist
|
# # It's OK to close this playlist so remove from open playlist list
|
||||||
if self.tabPlaylist.widget(tab_index) == self.next_track_playlist_tab:
|
# self.tabPlaylist.widget(index).close()
|
||||||
self.statusbar.showMessage(
|
#
|
||||||
"Can't close next track playlist", 5000)
|
# # Close regardless of tab type
|
||||||
return
|
# self.tabPlaylist.removeTab(index)
|
||||||
|
|
||||||
# Close playlist and remove tab
|
|
||||||
self.tabPlaylist.widget(tab_index).close()
|
|
||||||
self.tabPlaylist.removeTab(tab_index)
|
|
||||||
#
|
#
|
||||||
# def create_note(self) -> None:
|
# def create_note(self) -> None:
|
||||||
# """Call playlist to create note"""
|
# """Call playlist to create note"""
|
||||||
@ -275,32 +271,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:
|
# def download_played_tracks(self) -> None:
|
||||||
"""Download a CSV of played tracks"""
|
# """Download a CSV of played tracks"""
|
||||||
|
#
|
||||||
dlg = DownloadCSV(self)
|
# dlg = DownloadCSV(self)
|
||||||
if dlg.exec():
|
# if dlg.exec():
|
||||||
start_dt = dlg.ui.dateTimeEdit.dateTime().toPyDateTime()
|
# start_dt = dlg.ui.dateTimeEdit.dateTime().toPyDateTime()
|
||||||
# Get output filename
|
# # Get output filename
|
||||||
pathspec = QFileDialog.getSaveFileName(
|
# pathspec: Tuple[str, str] = QFileDialog.getSaveFileName(
|
||||||
self, 'Save CSV of tracks played',
|
# self, 'Save CSV of tracks played',
|
||||||
directory="/tmp/playlist.csv",
|
# directory="/tmp/playlist.csv",
|
||||||
filter="CSV files (*.csv)"
|
# filter="CSV files (*.csv)"
|
||||||
)
|
# )
|
||||||
if not pathspec:
|
# if not pathspec:
|
||||||
return
|
# return
|
||||||
|
#
|
||||||
path = pathspec[0]
|
# path: str = pathspec[0]
|
||||||
if not path.endswith(".csv"):
|
# if not path.endswith(".csv"):
|
||||||
path += ".csv"
|
# path += ".csv"
|
||||||
|
#
|
||||||
with open(path, "w") as f:
|
# with open(path, "w") as f:
|
||||||
with Session() as session:
|
# with Session() as session:
|
||||||
for playdate in Playdates.played_after(session, start_dt):
|
# for playdate in Playdates.played_after(session, start_dt):
|
||||||
f.write(
|
# f.write(
|
||||||
f"{playdate.track.artist},{playdate.track.title}\n"
|
# f"{playdate.track.artist},{playdate.track.title}\n"
|
||||||
)
|
# )
|
||||||
#
|
#
|
||||||
# def drop3db(self) -> None:
|
# def drop3db(self) -> None:
|
||||||
# """Drop music level by 3db if button checked"""
|
# """Drop music level by 3db if button checked"""
|
||||||
@ -364,45 +360,42 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
# Enable controls
|
# Enable controls
|
||||||
self.enable_play_next_controls()
|
self.enable_play_next_controls()
|
||||||
|
#
|
||||||
def export_playlist_tab(self) -> None:
|
# def export_playlist_tab(self) -> None:
|
||||||
"""Export the current playlist to an m3u file"""
|
# """Export the current playlist to an m3u file"""
|
||||||
|
#
|
||||||
if not self.visible_playlist_tab():
|
# if not self.visible_playlist_tab():
|
||||||
return
|
# return
|
||||||
|
#
|
||||||
playlist_id = self.visible_playlist_tab().playlist_id
|
# with Session() as session:
|
||||||
|
# playlist = Playlists.get_by_id(
|
||||||
with Session() as session:
|
# session, self.visible_playlist_tab().playlist_id)
|
||||||
|
# # Get output filename
|
||||||
# Get output filename
|
# pathspec: Tuple[str, str] = QFileDialog.getSaveFileName(
|
||||||
playlist = session.get(Playlists, playlist_id)
|
# self, 'Save Playlist',
|
||||||
pathspec = QFileDialog.getSaveFileName(
|
# directory=f"{playlist.name}.m3u",
|
||||||
self, 'Save Playlist',
|
# filter="M3U files (*.m3u);;All files (*.*)"
|
||||||
directory=f"{playlist.name}.m3u",
|
# )
|
||||||
filter="M3U files (*.m3u);;All files (*.*)"
|
# if not pathspec:
|
||||||
)
|
# return
|
||||||
if not pathspec:
|
#
|
||||||
return
|
# path: str = pathspec[0]
|
||||||
path = pathspec[0]
|
# if not path.endswith(".m3u"):
|
||||||
if not path.endswith(".m3u"):
|
# path += ".m3u"
|
||||||
path += ".m3u"
|
#
|
||||||
|
# with open(path, "w") as f:
|
||||||
# Get list of track rows for this playlist
|
# # Required directive on first line
|
||||||
plrs = PlaylistRows.get_rows_with_tracks(session, playlist_id)
|
# f.write("#EXTM3U\n")
|
||||||
with open(path, "w") as f:
|
# for _, track in playlist.tracks.items():
|
||||||
# Required directive on first line
|
# f.write(
|
||||||
f.write("#EXTM3U\n")
|
# "#EXTINF:"
|
||||||
for track in [a.track for a in plrs]:
|
# f"{int(track.duration / 1000)},"
|
||||||
f.write(
|
# f"{track.title} - "
|
||||||
"#EXTINF:"
|
# f"{track.artist}"
|
||||||
f"{int(track.duration / 1000)},"
|
# "\n"
|
||||||
f"{track.title} - "
|
# f"{track.path}"
|
||||||
f"{track.artist}"
|
# "\n"
|
||||||
"\n"
|
# )
|
||||||
f"{track.path}"
|
|
||||||
"\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
def fade(self) -> None:
|
def fade(self) -> None:
|
||||||
"""Fade currently playing track"""
|
"""Fade currently playing track"""
|
||||||
@ -977,18 +970,18 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
# item = self.ui.matchList.currentItem()
|
# item = self.ui.matchList.currentItem()
|
||||||
# track = item.data(Qt.UserRole)
|
# track = item.data(Qt.UserRole)
|
||||||
# self.ui.dbPath.setText(track.path)
|
# self.ui.dbPath.setText(track.path)
|
||||||
|
#
|
||||||
|
#
|
||||||
class DownloadCSV(QDialog):
|
# class DownloadCSV(QDialog):
|
||||||
def __init__(self, parent=None):
|
# def __init__(self, parent=None):
|
||||||
super().__init__(parent)
|
# super().__init__(parent)
|
||||||
|
#
|
||||||
self.ui = Ui_DateSelect()
|
# self.ui = Ui_DateSelect()
|
||||||
self.ui.setupUi(self)
|
# self.ui.setupUi(self)
|
||||||
self.ui.dateTimeEdit.setDate(QDate.currentDate())
|
# self.ui.dateTimeEdit.setDate(QDate.currentDate())
|
||||||
self.ui.dateTimeEdit.setTime(QTime(19, 59, 0))
|
# self.ui.dateTimeEdit.setTime(QTime(19, 59, 0))
|
||||||
self.ui.buttonBox.accepted.connect(self.accept)
|
# self.ui.buttonBox.accepted.connect(self.accept)
|
||||||
self.ui.buttonBox.rejected.connect(self.reject)
|
# self.ui.buttonBox.rejected.connect(self.reject)
|
||||||
|
|
||||||
|
|
||||||
class SelectPlaylistDialog(QDialog):
|
class SelectPlaylistDialog(QDialog):
|
||||||
|
|||||||
@ -349,15 +349,23 @@ class PlaylistTab(QTableWidget):
|
|||||||
|
|
||||||
return [self._get_playlistrow_id(a) for a in self._selected_rows()]
|
return [self._get_playlistrow_id(a) for a in self._selected_rows()]
|
||||||
|
|
||||||
def closeEvent(self, event) -> None:
|
# def closeEvent(self, event) -> None:
|
||||||
"""Handle closing playist tab"""
|
# """Save column widths"""
|
||||||
|
#
|
||||||
with Session() as session:
|
# log.debug(f"playlists.closeEvent()")
|
||||||
# Record playlist as closed
|
# with Session() as session:
|
||||||
playlist = session.get(Playlists, self.playlist_id)
|
# for column in range(self.columnCount()):
|
||||||
playlist.close(session)
|
# width = self.columnWidth(column)
|
||||||
|
# name = f"playlist_col_{str(column)}_width"
|
||||||
event.accept()
|
# 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 clear_next(self, session) -> None:
|
def clear_next(self, session) -> None:
|
||||||
"""Clear next track marker"""
|
"""Clear next track marker"""
|
||||||
@ -922,10 +930,7 @@ class PlaylistTab(QTableWidget):
|
|||||||
|
|
||||||
current_row: Optional[int] = self._get_current_track_row()
|
current_row: Optional[int] = self._get_current_track_row()
|
||||||
next_row: Optional[int] = self._get_next_track_row()
|
next_row: Optional[int] = self._get_next_track_row()
|
||||||
played = [
|
played = PlaylistRows.get_played_rows(session, self.playlist_id)
|
||||||
p.row_number for p in PlaylistRows.get_played_rows(
|
|
||||||
session, self.playlist_id)
|
|
||||||
]
|
|
||||||
unreadable: List[int] = self._get_unreadable_track_rows()
|
unreadable: List[int] = self._get_unreadable_track_rows()
|
||||||
|
|
||||||
if self.row_filter:
|
if self.row_filter:
|
||||||
@ -1339,14 +1344,9 @@ class PlaylistTab(QTableWidget):
|
|||||||
if starting_row is None:
|
if starting_row is None:
|
||||||
starting_row = 0
|
starting_row = 0
|
||||||
|
|
||||||
track_rows = [
|
track_rows = PlaylistRows.get_rows_with_tracks(session,
|
||||||
p.row_number for p in PlaylistRows.get_rows_with_tracks(
|
self.playlist_id)
|
||||||
session, self.playlist_id)
|
played_rows = PlaylistRows.get_played_rows(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()):
|
for row in range(starting_row, self.rowCount()):
|
||||||
if row not in track_rows or row in played_rows:
|
if row not in track_rows or row in played_rows:
|
||||||
continue
|
continue
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user