Næster version

This commit is contained in:
2026-04-14 14:05:11 +02:00
parent 9257f198eb
commit 66804681da
11 changed files with 647 additions and 364 deletions

View File

@@ -5,6 +5,7 @@ library_panel.py — Musikbibliotek med søgning og drag-and-drop til danseliste
from PyQt6.QtWidgets import (
QWidget, QVBoxLayout, QListWidget, QListWidgetItem,
QLineEdit, QLabel, QHBoxLayout, QPushButton,
QFrame, QSlider, QCheckBox,
QAbstractItemView, QStyledItemDelegate,
)
from PyQt6.QtCore import Qt, pyqtSignal, QTimer, QMimeData, QByteArray, QRect
@@ -175,6 +176,73 @@ class LibraryPanel(QWidget):
self._list.setItemDelegate(DanseButtonDelegate(self._list))
layout.addWidget(self._list)
# Preview-afspiller bar
self._preview_bar = self._build_preview_bar()
self._preview_bar.setVisible(False)
layout.addWidget(self._preview_bar)
# Timer til preview progress opdatering
self._preview_timer = QTimer(self)
self._preview_timer.setInterval(200)
self._preview_timer.timeout.connect(self._update_preview_progress)
def _build_preview_bar(self) -> QWidget:
bar = QFrame()
bar.setObjectName("track_display")
bar.setFixedHeight(62)
row = QHBoxLayout(bar)
row.setContentsMargins(10, 8, 10, 8)
row.setSpacing(10)
# Play/pause knap — orange som hoved-afspiller
self._btn_preview_play = QPushButton("")
self._btn_preview_play.setFixedSize(36, 36)
self._btn_preview_play.setObjectName("btn_play_small")
self._btn_preview_play.setToolTip("Afspil / Pause")
self._btn_preview_play.clicked.connect(self._toggle_preview_playback)
row.addWidget(self._btn_preview_play)
# Stop knap
self._btn_preview_stop = QPushButton("")
self._btn_preview_stop.setFixedSize(30, 30)
self._btn_preview_stop.setObjectName("btn_stop_small")
self._btn_preview_stop.setToolTip("Stop preview")
self._btn_preview_stop.clicked.connect(self._stop_preview)
row.addWidget(self._btn_preview_stop)
# Titel + progress i midten
info = QVBoxLayout()
info.setSpacing(4)
info.setContentsMargins(0, 0, 0, 0)
self._lbl_preview_title = QLabel("")
self._lbl_preview_title.setObjectName("track_meta")
info.addWidget(self._lbl_preview_title)
self._preview_progress = QSlider(Qt.Orientation.Horizontal)
self._preview_progress.setRange(0, 1000)
self._preview_progress.sliderMoved.connect(self._seek_preview)
info.addWidget(self._preview_progress)
row.addLayout(info, stretch=1)
# Tid
self._lbl_preview_time = QLabel("0:00")
self._lbl_preview_time.setObjectName("track_meta")
self._lbl_preview_time.setFixedWidth(70)
self._lbl_preview_time.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
row.addWidget(self._lbl_preview_time)
# Volumen
self._preview_vol = QSlider(Qt.Orientation.Horizontal)
self._preview_vol.setRange(0, 100)
self._preview_vol.setValue(78)
self._preview_vol.setFixedWidth(70)
self._preview_vol.setToolTip("Volumen preview")
self._preview_vol.valueChanged.connect(self._on_preview_volume)
row.addWidget(self._preview_vol)
return bar
# ── Scanning ──────────────────────────────────────────────────────────────
def _on_scan_clicked(self):
@@ -312,11 +380,6 @@ class LibraryPanel(QWidget):
# ── Handlinger ────────────────────────────────────────────────────────────
def _on_double_click(self, item: QListWidgetItem):
song = item.data(Qt.ItemDataRole.UserRole)
if song:
self.song_selected.emit(song)
def _show_context_menu(self, pos):
from PyQt6.QtWidgets import QMenu
item = self._list.itemAt(pos)
@@ -326,8 +389,17 @@ class LibraryPanel(QWidget):
if not song:
return
menu = QMenu(self)
act_add = menu.addAction("Tilføj til danseliste")
act_play = menu.addAction("Afspil")
act_add = menu.addAction("Tilføj til danseliste")
act_play = menu.addAction("Afspil")
# Preview kun hvis preview player er sat op
is_previewing = (
hasattr(self, "_preview_player") and
self._preview_player and
self._preview_player.is_playing()
)
act_preview = menu.addAction(
"⏹ Stop preview" if is_previewing else "▶ Preview (høretelefoner)"
)
menu.addSeparator()
act_tags = menu.addAction("✎ Rediger dans-tags...")
act_info = menu.addAction(" Dans-info...")
@@ -340,6 +412,8 @@ class LibraryPanel(QWidget):
self.add_to_playlist.emit(song)
elif action == act_play:
self.song_selected.emit(song)
elif action == act_preview:
self._toggle_preview(song)
elif action == act_tags:
self.edit_tags_requested.emit(song)
elif action == act_info:
@@ -351,6 +425,78 @@ class LibraryPanel(QWidget):
elif action == act_mail:
self.send_mail_requested.emit(song)
def set_preview_player(self, preview_player):
"""Sæt preview-afspilleren fra main_window."""
self._preview_player = preview_player
def _on_double_click(self, item: QListWidgetItem):
song = item.data(Qt.ItemDataRole.UserRole)
if song:
self._start_preview(song)
def _start_preview(self, song: dict):
if not hasattr(self, "_preview_player") or not self._preview_player:
self.song_selected.emit(song)
return
path = song.get("local_path", "")
if not path:
return
self._preview_song = song
self._preview_player.play(path)
title = song.get("title", "")
artist = song.get("artist", "")
self._lbl_preview_title.setText(f"{title} · {artist}")
self._btn_preview_play.setText("")
self._preview_bar.setVisible(True)
self._preview_timer.start()
def _toggle_preview_playback(self):
if not hasattr(self, "_preview_player") or not self._preview_player:
return
if self._preview_player.is_playing():
self._preview_player.pause()
self._btn_preview_play.setText("")
else:
self._preview_player.resume()
self._btn_preview_play.setText("")
def _stop_preview(self):
if hasattr(self, "_preview_player") and self._preview_player:
self._preview_player.stop()
self._preview_timer.stop()
self._preview_bar.setVisible(False)
self._btn_preview_play.setText("")
def _seek_preview(self, value: int):
if hasattr(self, "_preview_player") and self._preview_player:
self._preview_player.seek(value / 1000.0)
def _on_preview_volume(self, value: int):
if hasattr(self, "_preview_player") and self._preview_player:
self._preview_player.set_volume(value)
def _update_preview_progress(self):
if not hasattr(self, "_preview_player") or not self._preview_player:
return
if not self._preview_player.is_playing():
self._btn_preview_play.setText("")
return
pos = self._preview_player.get_position()
cur = self._preview_player.get_time()
dur = self._preview_player.get_duration()
self._preview_progress.setValue(int(pos * 1000))
def fmt(s): return f"{s//60}:{s%60:02d}"
self._lbl_preview_time.setText(f"{fmt(cur)} / {fmt(dur)}")
def _toggle_preview(self, song: dict):
"""Start/stop preview af en sang."""
if not hasattr(self, "_preview_player") or not self._preview_player:
return
if self._preview_player.is_playing():
self._stop_preview()
else:
self._start_preview(song)
def _analyze_bpm(self, song: dict):
"""Analysér BPM i baggrundstråd og opdater biblioteket."""
path = song.get("local_path", "")