v0.2 - drop fingerprinting, add LUFS cart normalisation, playlist save/load, editable history with TXT+CSV export
This commit is contained in:
+102
-3
@@ -8,6 +8,7 @@ from PySide6.QtWidgets import (
|
||||
)
|
||||
from PySide6.QtCore import Qt, QTimer
|
||||
from PySide6.QtGui import QFont, QColor, QAction
|
||||
import json
|
||||
import os
|
||||
|
||||
|
||||
@@ -264,6 +265,17 @@ class BasePlaylistPanel(QWidget):
|
||||
else:
|
||||
item.setForeground(QColor("#cccccc"))
|
||||
|
||||
def get_filepaths(self, lst: QListWidget) -> list:
|
||||
paths = []
|
||||
for i in range(lst.count()):
|
||||
item = lst.item(i)
|
||||
if isinstance(item, PlaylistItem):
|
||||
paths.append(item.filepath)
|
||||
return paths
|
||||
|
||||
def clear_list(self, lst: QListWidget):
|
||||
lst.clear()
|
||||
|
||||
|
||||
# ─────────────────────────────────────────
|
||||
# TRACK PLAYLIST PANEL
|
||||
@@ -574,18 +586,58 @@ class CartPlaylistPanel(BasePlaylistPanel):
|
||||
# ─────────────────────────────────────────
|
||||
|
||||
class PlaylistWidget(QWidget):
|
||||
PLAYLIST_JSON_FILTER = "JSON Files (*.json)"
|
||||
|
||||
def __init__(self, engine, deck_widgets: dict,
|
||||
cart_slots: list, parent=None):
|
||||
super().__init__(parent)
|
||||
self.engine = engine
|
||||
|
||||
# Expandable - no fixed width
|
||||
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
self.setMinimumWidth(200)
|
||||
|
||||
root = QVBoxLayout(self)
|
||||
root.setContentsMargins(0, 0, 0, 0)
|
||||
root.setSpacing(0)
|
||||
root.setSpacing(4)
|
||||
|
||||
# Toolbar
|
||||
bar = QHBoxLayout()
|
||||
bar.setSpacing(4)
|
||||
|
||||
self._save_btn = QPushButton("SAVE")
|
||||
self._save_btn.setFixedHeight(28)
|
||||
self._save_btn.setFont(QFont("Arial", 9, QFont.Bold))
|
||||
self._save_btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #2a4a2a;
|
||||
color: #aaaaaa;
|
||||
border: 1px solid #444;
|
||||
border-radius: 3px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
QPushButton:hover { background-color: #3a5a3a; }
|
||||
""")
|
||||
self._save_btn.clicked.connect(self._save_playlist)
|
||||
|
||||
self._load_btn = QPushButton("LOAD")
|
||||
self._load_btn.setFixedHeight(28)
|
||||
self._load_btn.setFont(QFont("Arial", 9, QFont.Bold))
|
||||
self._load_btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #3a2a2a;
|
||||
color: #aaaaaa;
|
||||
border: 1px solid #444;
|
||||
border-radius: 3px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
QPushButton:hover { background-color: #4a3a3a; }
|
||||
""")
|
||||
self._load_btn.clicked.connect(self._load_playlist)
|
||||
|
||||
bar.addWidget(self._save_btn)
|
||||
bar.addWidget(self._load_btn)
|
||||
bar.addStretch()
|
||||
root.addLayout(bar)
|
||||
|
||||
splitter = QSplitter(Qt.Vertical)
|
||||
splitter.setStyleSheet("""
|
||||
@@ -602,4 +654,51 @@ class PlaylistWidget(QWidget):
|
||||
splitter.addWidget(self.cart_panel)
|
||||
splitter.setSizes([600, 400])
|
||||
|
||||
root.addWidget(splitter)
|
||||
root.addWidget(splitter)
|
||||
|
||||
def _save_playlist(self):
|
||||
path, _ = QFileDialog.getSaveFileName(
|
||||
self, "Save Playlist",
|
||||
os.path.expanduser("~/playlist.json"),
|
||||
self.PLAYLIST_JSON_FILTER
|
||||
)
|
||||
if not path:
|
||||
return
|
||||
data = {
|
||||
"version": 1,
|
||||
"tracks": self.track_panel.get_filepaths(self.track_panel.playlist),
|
||||
"cart_tracks": self.cart_panel.get_filepaths(self.cart_panel.playlist),
|
||||
}
|
||||
with open(path, 'w') as f:
|
||||
json.dump(data, f, indent=2)
|
||||
|
||||
def _load_playlist(self):
|
||||
path, _ = QFileDialog.getOpenFileName(
|
||||
self, "Load Playlist",
|
||||
os.path.expanduser("~"),
|
||||
self.PLAYLIST_JSON_FILTER
|
||||
)
|
||||
if not path:
|
||||
return
|
||||
try:
|
||||
with open(path) as f:
|
||||
data = json.load(f)
|
||||
except Exception:
|
||||
return
|
||||
|
||||
tracks = data.get("tracks", [])
|
||||
cart = data.get("cart_tracks", [])
|
||||
|
||||
self.track_panel.playlist.clear()
|
||||
for fp in tracks:
|
||||
if os.path.exists(fp):
|
||||
self.track_panel._add_item_to(self.track_panel.playlist, fp)
|
||||
self.track_panel._update_count(self.track_panel.playlist,
|
||||
self.track_panel.count_label)
|
||||
|
||||
self.cart_panel.playlist.clear()
|
||||
for fp in cart:
|
||||
if os.path.exists(fp):
|
||||
self.cart_panel._add_item_to(self.cart_panel.playlist, fp)
|
||||
self.cart_panel._update_count(self.cart_panel.playlist,
|
||||
self.cart_panel.count_label)
|
||||
Reference in New Issue
Block a user