auto export playlist works!!!
This commit is contained in:
parent
3a9f7a27d3
commit
dc4f7a4cbc
85
components/EditPlaylistOptionsWindow.py
Normal file
85
components/EditPlaylistOptionsWindow.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import DBA
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QDialog,
|
||||||
|
QLineEdit,
|
||||||
|
QLabel,
|
||||||
|
QPushButton,
|
||||||
|
QVBoxLayout,
|
||||||
|
)
|
||||||
|
from PyQt5.QtGui import QFont
|
||||||
|
|
||||||
|
|
||||||
|
class EditPlaylistOptionsWindow(QDialog):
|
||||||
|
def __init__(self, playlist_id):
|
||||||
|
super(EditPlaylistOptionsWindow, self).__init__()
|
||||||
|
self.setWindowTitle("Playlist options")
|
||||||
|
self.setMinimumSize(600, 400)
|
||||||
|
self.playlist_id = playlist_id
|
||||||
|
# self.playlist_path_prefix: str = self.config.get(
|
||||||
|
# "settings", "playlist_path_prefix"
|
||||||
|
# )
|
||||||
|
# self.export_path: str = self.config.get("settings", "playlist_export_path")
|
||||||
|
# self.selected_playlist_name: str = "my-playlist.m3u"
|
||||||
|
# self.chosen_list_widget_item: QListWidgetItem | None = None
|
||||||
|
layout = self.setup_ui()
|
||||||
|
self.setLayout(layout)
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
def setup_ui(self):
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
|
||||||
|
# Header label
|
||||||
|
label = QLabel("Options")
|
||||||
|
label.setFont(QFont("Sans", weight=QFont.Bold))
|
||||||
|
layout.addWidget(label)
|
||||||
|
|
||||||
|
# Get options from db
|
||||||
|
with DBA.DBAccess() as db:
|
||||||
|
data = db.query("SELECT auto_export_path, path_prefix from playlist WHERE id = ?;", (self.playlist_id,))
|
||||||
|
auto_export_path = data[0][0]
|
||||||
|
path_prefix = data[0][1]
|
||||||
|
|
||||||
|
# Relative export path label
|
||||||
|
label = QLabel("Auto export path (../music/playlists/my_playlist.m3u)")
|
||||||
|
label.setFont(QFont("Sans", weight=QFont.Bold)) # bold category
|
||||||
|
label.setStyleSheet("text-transform:lowercase;") # uppercase category
|
||||||
|
layout.addWidget(label)
|
||||||
|
|
||||||
|
# Relative export path line edit widget
|
||||||
|
self.auto_export_path = QLineEdit(auto_export_path)
|
||||||
|
layout.addWidget(self.auto_export_path)
|
||||||
|
|
||||||
|
# Playlist file save path label
|
||||||
|
label = QLabel("Path prefix (/prefix/song.mp3, /prefix/song2.mp3)")
|
||||||
|
label.setFont(QFont("Sans", weight=QFont.Bold))
|
||||||
|
label.setStyleSheet("text-transform:lowercase;")
|
||||||
|
layout.addWidget(label)
|
||||||
|
|
||||||
|
# Playlist file save path line edit widget
|
||||||
|
self.path_prefix = QLineEdit(path_prefix)
|
||||||
|
layout.addWidget(self.path_prefix)
|
||||||
|
|
||||||
|
# Save button
|
||||||
|
self.save_button = QPushButton("Save")
|
||||||
|
layout.addWidget(self.save_button)
|
||||||
|
|
||||||
|
# Signals
|
||||||
|
self.save_button.clicked.connect(self.save)
|
||||||
|
return layout
|
||||||
|
|
||||||
|
def save(self) -> None:
|
||||||
|
"""
|
||||||
|
Updates the options in the db
|
||||||
|
"""
|
||||||
|
with DBA.DBAccess() as db:
|
||||||
|
db.execute('''
|
||||||
|
UPDATE playlist SET auto_export_path = ?, path_prefix = ? WHERE id = ?
|
||||||
|
''', (self.auto_export_path.text(), self.path_prefix.text(), self.playlist_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.close()
|
||||||
|
return
|
||||||
|
|
||||||
|
def cancel(self) -> None:
|
||||||
|
self.close()
|
||||||
|
return
|
||||||
@ -4,7 +4,6 @@ import os
|
|||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QCheckBox,
|
QCheckBox,
|
||||||
QDialog,
|
QDialog,
|
||||||
QHBoxLayout,
|
|
||||||
QLineEdit,
|
QLineEdit,
|
||||||
QLabel,
|
QLabel,
|
||||||
QPushButton,
|
QPushButton,
|
||||||
@ -26,8 +25,8 @@ class ExportPlaylistWindow(QDialog):
|
|||||||
self.setWindowTitle("Export playlist")
|
self.setWindowTitle("Export playlist")
|
||||||
self.setMinimumSize(600, 400)
|
self.setMinimumSize(600, 400)
|
||||||
self.load_config()
|
self.load_config()
|
||||||
self.relative_path: str = self.config.get(
|
self.playlist_path_prefix: str = self.config.get(
|
||||||
"settings", "playlist_content_relative_path"
|
"settings", "playlist_path_prefix"
|
||||||
)
|
)
|
||||||
self.export_path: str = self.config.get("settings", "playlist_export_path")
|
self.export_path: str = self.config.get("settings", "playlist_export_path")
|
||||||
self.selected_playlist_name: str = "my-playlist.m3u"
|
self.selected_playlist_name: str = "my-playlist.m3u"
|
||||||
@ -74,7 +73,7 @@ class ExportPlaylistWindow(QDialog):
|
|||||||
layout.addWidget(label)
|
layout.addWidget(label)
|
||||||
|
|
||||||
# Relative export path line edit widget
|
# Relative export path line edit widget
|
||||||
self.input_relative_path = QLineEdit(self.relative_path) # not needed
|
self.input_relative_path = QLineEdit(self.playlist_path_prefix) # not needed
|
||||||
layout.addWidget(self.input_relative_path)
|
layout.addWidget(self.input_relative_path)
|
||||||
|
|
||||||
# Playlist file save path label
|
# Playlist file save path label
|
||||||
@ -112,9 +111,7 @@ class ExportPlaylistWindow(QDialog):
|
|||||||
Sets the current playlist name, then edits the playlist export path
|
Sets the current playlist name, then edits the playlist export path
|
||||||
"""
|
"""
|
||||||
# Get the current chosen list item
|
# Get the current chosen list item
|
||||||
self.chosen_list_widget_item: QListWidgetItem | None = (
|
self.chosen_list_widget_item = self.playlist_listWidget.currentItem()
|
||||||
self.playlist_listWidget.currentItem()
|
|
||||||
)
|
|
||||||
# We don't care if nothing is chosen
|
# We don't care if nothing is chosen
|
||||||
if self.chosen_list_widget_item is None:
|
if self.chosen_list_widget_item is None:
|
||||||
return
|
return
|
||||||
@ -129,13 +126,13 @@ class ExportPlaylistWindow(QDialog):
|
|||||||
|
|
||||||
# alter line edit text for playlist path
|
# alter line edit text for playlist path
|
||||||
# Make the thing react and show the correct thing or whatever
|
# Make the thing react and show the correct thing or whatever
|
||||||
current_text: list = self.input_m3u_path.text().split("/")
|
current_text: list = self.export_m3u_path.text().split("/")
|
||||||
if "." in current_text[-1]:
|
if "." in current_text[-1]:
|
||||||
current_text = current_text[:-1]
|
current_text = current_text[:-1]
|
||||||
else:
|
else:
|
||||||
current_text = current_text
|
current_text = current_text
|
||||||
m3u_text = os.path.join("/", *current_text, self.selected_playlist_name)
|
m3u_text = os.path.join("/", *current_text, self.selected_playlist_name)
|
||||||
self.input_m3u_path.setText(m3u_text)
|
self.export_m3u_path.setText(m3u_text)
|
||||||
|
|
||||||
def save(self) -> None:
|
def save(self) -> None:
|
||||||
"""
|
"""
|
||||||
@ -145,7 +142,7 @@ class ExportPlaylistWindow(QDialog):
|
|||||||
if self.chosen_list_widget_item is None:
|
if self.chosen_list_widget_item is None:
|
||||||
return
|
return
|
||||||
relative_path = self.input_relative_path.text()
|
relative_path = self.input_relative_path.text()
|
||||||
output_filename = self.input_m3u_path.text()
|
output_filename = self.export_m3u_path.text()
|
||||||
|
|
||||||
# If no output path is provided, just close the window...
|
# If no output path is provided, just close the window...
|
||||||
if output_filename == "" or output_filename is None:
|
if output_filename == "" or output_filename is None:
|
||||||
|
|||||||
@ -6,13 +6,12 @@ from PyQt5.QtWidgets import (
|
|||||||
QTreeWidget,
|
QTreeWidget,
|
||||||
QTreeWidgetItem,
|
QTreeWidgetItem,
|
||||||
)
|
)
|
||||||
from PyQt5.QtCore import QThreadPool, pyqtSignal, Qt, QPoint
|
from PyQt5.QtCore import pyqtSignal, Qt, QPoint
|
||||||
import DBA
|
import DBA
|
||||||
from logging import debug
|
|
||||||
from components.ErrorDialog import ErrorDialog
|
from components.ErrorDialog import ErrorDialog
|
||||||
from utils import Worker
|
from utils import Worker
|
||||||
|
|
||||||
from components import CreatePlaylistWindow
|
from components import CreatePlaylistWindow, EditPlaylistOptionsWindow
|
||||||
|
|
||||||
|
|
||||||
class PlaylistWidgetItem(QTreeWidgetItem):
|
class PlaylistWidgetItem(QTreeWidgetItem):
|
||||||
@ -70,10 +69,13 @@ class PlaylistsPane(QTreeWidget):
|
|||||||
# only allow delete/rename non-root nodes
|
# only allow delete/rename non-root nodes
|
||||||
rename_action = QAction("Rename", self)
|
rename_action = QAction("Rename", self)
|
||||||
delete_action = QAction("Delete", self)
|
delete_action = QAction("Delete", self)
|
||||||
|
options_action = QAction("Options", self)
|
||||||
rename_action.triggered.connect(self.rename_playlist)
|
rename_action.triggered.connect(self.rename_playlist)
|
||||||
delete_action.triggered.connect(self.delete_playlist)
|
delete_action.triggered.connect(self.delete_playlist)
|
||||||
|
options_action.triggered.connect(self.options)
|
||||||
menu.addAction(rename_action)
|
menu.addAction(rename_action)
|
||||||
menu.addAction(delete_action)
|
menu.addAction(delete_action)
|
||||||
|
menu.addAction(options_action)
|
||||||
create_action = QAction("New playlist", self)
|
create_action = QAction("New playlist", self)
|
||||||
create_action.triggered.connect(self.create_playlist)
|
create_action.triggered.connect(self.create_playlist)
|
||||||
menu.addAction(create_action)
|
menu.addAction(create_action)
|
||||||
@ -85,6 +87,10 @@ class PlaylistsPane(QTreeWidget):
|
|||||||
window.playlistCreatedSignal.connect(self.reload_playlists)
|
window.playlistCreatedSignal.connect(self.reload_playlists)
|
||||||
window.exec_()
|
window.exec_()
|
||||||
|
|
||||||
|
def options(self):
|
||||||
|
window = EditPlaylistOptionsWindow(self.playlist_db_id_choice)
|
||||||
|
window.exec_()
|
||||||
|
|
||||||
def rename_playlist(self, *args):
|
def rename_playlist(self, *args):
|
||||||
"""
|
"""
|
||||||
Asks user for input
|
Asks user for input
|
||||||
|
|||||||
@ -6,6 +6,7 @@ from .ErrorDialog import ErrorDialog
|
|||||||
from .LyricsWindow import LyricsWindow
|
from .LyricsWindow import LyricsWindow
|
||||||
from .DebugWindow import DebugWindow
|
from .DebugWindow import DebugWindow
|
||||||
from .AddToPlaylistWindow import AddToPlaylistWindow
|
from .AddToPlaylistWindow import AddToPlaylistWindow
|
||||||
|
from .EditPlaylistOptionsWindow import EditPlaylistOptionsWindow
|
||||||
from .CreatePlaylistWindow import CreatePlaylistWindow
|
from .CreatePlaylistWindow import CreatePlaylistWindow
|
||||||
from .PlaylistsPane import PlaylistsPane
|
from .PlaylistsPane import PlaylistsPane
|
||||||
from .ExportPlaylistWindow import ExportPlaylistWindow
|
from .ExportPlaylistWindow import ExportPlaylistWindow
|
||||||
|
|||||||
14
main.py
14
main.py
@ -4,7 +4,7 @@ import logging
|
|||||||
from PyQt5 import QtCore
|
from PyQt5 import QtCore
|
||||||
import qdarktheme
|
import qdarktheme
|
||||||
import typing
|
import typing
|
||||||
# import DBA
|
import DBA
|
||||||
from subprocess import run
|
from subprocess import run
|
||||||
# from pyqtgraph import mkBrush
|
# from pyqtgraph import mkBrush
|
||||||
from mutagen.id3 import ID3
|
from mutagen.id3 import ID3
|
||||||
@ -60,6 +60,7 @@ from components import (
|
|||||||
CreatePlaylistWindow,
|
CreatePlaylistWindow,
|
||||||
ExportPlaylistWindow,
|
ExportPlaylistWindow,
|
||||||
)
|
)
|
||||||
|
from utils.export_playlist_by_id import export_playlist_by_id
|
||||||
|
|
||||||
# good help with signals slots in threads
|
# good help with signals slots in threads
|
||||||
# https://stackoverflow.com/questions/52993677/how-do-i-setup-signals-and-slots-in-pyqt-with-qthreads-in-both-directions
|
# https://stackoverflow.com/questions/52993677/how-do-i-setup-signals-and-slots-in-pyqt-with-qthreads-in-both-directions
|
||||||
@ -246,13 +247,22 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
self.config["settings"]["window_size"] = (
|
self.config["settings"]["window_size"] = (
|
||||||
str(self.width()) + "," + str(self.height())
|
str(self.width()) + "," + str(self.height())
|
||||||
)
|
)
|
||||||
|
|
||||||
# Save the config
|
# Save the config
|
||||||
try:
|
try:
|
||||||
with open(self.cfg_file, "w") as configfile:
|
with open(self.cfg_file, "w") as configfile:
|
||||||
self.config.write(configfile)
|
self.config.write(configfile)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
debug(f"wtf man {e}")
|
debug(f"wtf man {e}")
|
||||||
|
|
||||||
|
# auto export any playlists that want it
|
||||||
|
try:
|
||||||
|
with DBA.DBAccess() as db:
|
||||||
|
result = db.query('SELECT id FROM playlist WHERE auto_export_path IS NOT NULL;', ())
|
||||||
|
ids = [id[0] for id in result]
|
||||||
|
for id in ids:
|
||||||
|
export_playlist_by_id(id)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
if a0 is not None:
|
if a0 is not None:
|
||||||
super().closeEvent(a0)
|
super().closeEvent(a0)
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ library = /path/to/music
|
|||||||
reorganize_destination = /where/to/reorganize/to
|
reorganize_destination = /where/to/reorganize/to
|
||||||
playlist_auto_export_enabled = 0
|
playlist_auto_export_enabled = 0
|
||||||
playlist_export_path = /where/to/export/to
|
playlist_export_path = /where/to/export/to
|
||||||
playlist_relative_path = /relative/prefix
|
playlist_path_prefix = /relative/prefix
|
||||||
extensions = mp3,wav,ogg,flac
|
extensions = mp3,wav,ogg,flac
|
||||||
volume = 100
|
volume = 100
|
||||||
window_size=1152,894
|
window_size=1152,894
|
||||||
|
|||||||
@ -17,3 +17,4 @@ from .convert_date_str_to_tyer_tdat_id3_tag import convert_date_str_to_tyer_tdat
|
|||||||
from .set_album_art import set_album_art
|
from .set_album_art import set_album_art
|
||||||
from .delete_album_art import delete_album_art
|
from .delete_album_art import delete_album_art
|
||||||
from .Worker import Worker
|
from .Worker import Worker
|
||||||
|
from .export_playlist_by_id import export_playlist_by_id
|
||||||
|
|||||||
69
utils/export_playlist_by_id.py
Normal file
69
utils/export_playlist_by_id.py
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import os
|
||||||
|
from PyQt5.QtCore import QThreadPool
|
||||||
|
import DBA
|
||||||
|
import logging
|
||||||
|
from utils import get_reorganize_vars, Worker
|
||||||
|
|
||||||
|
def export_playlist_by_id(playlist_db_id: int) -> bool:
|
||||||
|
"""
|
||||||
|
Exports a playlist to its defined auto_export_path, by database ID
|
||||||
|
"""
|
||||||
|
threadpool = QThreadPool()
|
||||||
|
try:
|
||||||
|
with DBA.DBAccess() as db:
|
||||||
|
result = db.query('''
|
||||||
|
SELECT auto_export_path, path_prefix FROM playlist WHERE id = ?
|
||||||
|
''', (playlist_db_id,)
|
||||||
|
)
|
||||||
|
auto_export_path = result[0][0]
|
||||||
|
path_prefix = result[0][1]
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(
|
||||||
|
f"export_playlist_by_id.py | Could not contact database: {e}"
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# If the prefix is null, then use an empty string
|
||||||
|
if not path_prefix:
|
||||||
|
path_prefix = ""
|
||||||
|
|
||||||
|
# Get filepaths for selected playlist from the database
|
||||||
|
try:
|
||||||
|
with DBA.DBAccess() as db:
|
||||||
|
data = db.query(
|
||||||
|
"""SELECT s.filepath FROM song_playlist as sp
|
||||||
|
JOIN song as s ON s.id = sp.song_id
|
||||||
|
WHERE sp.playlist_id = ?;""",
|
||||||
|
(playlist_db_id,),
|
||||||
|
)
|
||||||
|
db_paths = [path[0] for path in data]
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(
|
||||||
|
f"export_playlist_by_id.py | Could not retrieve records from playlist: {e}"
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Gather playlist song paths
|
||||||
|
write_paths = []
|
||||||
|
# Relative paths
|
||||||
|
for song in db_paths:
|
||||||
|
artist, album = get_reorganize_vars(song)
|
||||||
|
write_path = os.path.join(
|
||||||
|
path_prefix, artist, album, song.split("/")[-1] + "\n"
|
||||||
|
)
|
||||||
|
write_paths.append(str(write_path))
|
||||||
|
|
||||||
|
|
||||||
|
worker = Worker(write_to_playlist_file, write_paths, auto_export_path)
|
||||||
|
# worker.signals.signal_finished.connect(None)
|
||||||
|
# worker.signals.signal_progress.connect()
|
||||||
|
threadpool.start(worker)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def write_to_playlist_file(paths: list[str], outfile: str, progress_callback=None) -> None:
|
||||||
|
"""
|
||||||
|
Writes a list of strings to a m3u file
|
||||||
|
"""
|
||||||
|
os.makedirs(os.path.dirname(outfile), exist_ok=True)
|
||||||
|
with open(outfile, "w") as f:
|
||||||
|
f.writelines(paths)
|
||||||
@ -22,7 +22,9 @@ CREATE TABLE song(
|
|||||||
CREATE TABLE playlist(
|
CREATE TABLE playlist(
|
||||||
id integer primary key,
|
id integer primary key,
|
||||||
name varchar(64),
|
name varchar(64),
|
||||||
date_created TIMESTAMP default CURRENT_TIMESTAMP
|
date_created TIMESTAMP default CURRENT_TIMESTAMP,
|
||||||
|
auto_export_path varchar(512),
|
||||||
|
path_prefix varchar(255)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE song_playlist(
|
CREATE TABLE song_playlist(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user