This commit is contained in:
2026-04-12 19:19:01 +02:00
parent 1ea5cad01f
commit 45dcedaed4
4 changed files with 75 additions and 50 deletions

View File

@@ -104,26 +104,25 @@ pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
[], # ← onedir: ingen binaries/datas her
exclude_binaries=True, # ← onedir: binaries samles i COLLECT
name='LineDancePlayer',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[
'vcruntime140.dll',
'msvcp140.dll',
'python3*.dll',
'Qt6*.dll',
],
upx_exclude=['Qt6*.dll', 'python3*.dll', 'vcruntime140.dll'],
console=False,
disable_windowed_traceback=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=None,
onefile=True,
)
coll = COLLECT(
exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=['Qt6*.dll', 'python3*.dll', 'vcruntime140.dll'],
name='LineDancePlayer',
)

View File

@@ -138,11 +138,20 @@ class LibraryPanel(QWidget):
header.addWidget(btn_manage)
layout.addLayout(header)
# Søgefelt
# Søgefelt + checkbox
search_row = QHBoxLayout()
search_row.setSpacing(6)
self._search = QLineEdit()
self._search.setPlaceholderText("Søg i titel, artist, album, dans...")
self._search.textChanged.connect(self._on_search_changed)
layout.addWidget(self._search)
search_row.addWidget(self._search)
from PyQt6.QtWidgets import QCheckBox
self._chk_alt = QCheckBox("Inkl. alt.")
self._chk_alt.setToolTip("Søg også i alternativ-danse")
self._chk_alt.setChecked(False)
self._chk_alt.toggled.connect(self._on_search_changed)
search_row.addWidget(self._chk_alt)
layout.addLayout(search_row)
# Resultat-tæller + drag-hint
hint_row = QHBoxLayout()
@@ -190,7 +199,10 @@ class LibraryPanel(QWidget):
def _do_search(self):
q = self._search.text().strip().lower()
self._filtered = [s for s in self._all_songs if self._matches(s, q)] if q else list(self._all_songs)
incl_alt = self._chk_alt.isChecked()
self._filtered = [
s for s in self._all_songs if self._matches(s, q, incl_alt)
] if q else list(self._all_songs)
total = len(self._all_songs)
found = len(self._filtered)
q_text = self._search.text().strip()
@@ -200,25 +212,14 @@ class LibraryPanel(QWidget):
)
self._render()
def _matches(self, song: dict, q: str) -> bool:
return any(q in f.lower() for f in [
def _matches(self, song: dict, q: str, incl_alt: bool = False) -> bool:
fields = [
song.get("title", ""), song.get("artist", ""),
song.get("album", ""), song.get("file_format", ""),
] + song.get("dances", []))
def _render(self):
self._list.clear()
q = self._search.text().strip().lower()
for song in self._filtered:
dances = song.get("dances", [])
dance_levels = song.get("dance_levels", [])
missing = song.get("file_missing", False)
dance_parts = []
for i, d in enumerate(dances):
lvl = dance_levels[i] if i < len(dance_levels) else ""
dance_parts.append(f"{d} / {lvl}" if lvl else d)
dance_str = " · " + " | ".join(dance_parts) if dance_parts else ""
] + song.get("dances", [])
if incl_alt:
fields += song.get("alt_dances", [])
return any(q in f.lower() for f in fields)
def _render(self):
self._list.clear()

View File

@@ -287,10 +287,10 @@ class MainWindow(QMainWindow):
b.setCheckable(True)
return b
self._btn_prev = btn("", size=52)
self._btn_prev = btn("|◀◀", size=52)
self._btn_play = btn("", "btn_play", size=72)
self._btn_stop = btn("", "btn_stop", size=52)
self._btn_next = btn("", size=52)
self._btn_stop = btn("", "btn_stop", size=52)
self._btn_next = btn("▶▶|", size=52)
self._btn_demo = btn(f"\n{self._demo_seconds} SEK", "btn_demo", size=64, checkable=True)
self._btn_prev.clicked.connect(self._prev_song)
@@ -453,12 +453,15 @@ class MainWindow(QMainWindow):
SELECT s.id, s.title, s.artist, s.album, s.bpm,
s.duration_sec, s.local_path, s.file_format,
s.file_missing,
GROUP_CONCAT(d.name, '||') AS dance_names,
GROUP_CONCAT(COALESCE(dl.name,''), '||') AS dance_levels
GROUP_CONCAT(DISTINCT d.name) AS dance_names,
GROUP_CONCAT(DISTINCT COALESCE(dl.name,'')) AS dance_levels,
GROUP_CONCAT(DISTINCT ad.name) AS alt_dance_names
FROM songs s
LEFT JOIN song_dances sd ON sd.song_id = s.id
LEFT JOIN dances d ON d.id = sd.dance_id
LEFT JOIN dance_levels dl ON dl.id = d.level_id
LEFT JOIN song_dances sd ON sd.song_id = s.id
LEFT JOIN dances d ON d.id = sd.dance_id
LEFT JOIN dance_levels dl ON dl.id = d.level_id
LEFT JOIN song_alt_dances sad ON sad.song_id = s.id
LEFT JOIN dances ad ON ad.id = sad.dance_id
WHERE s.file_missing = 0
GROUP BY s.id
ORDER BY s.artist, s.title
@@ -467,8 +470,9 @@ class MainWindow(QMainWindow):
songs = []
for row in rows:
dances = row["dance_names"].split("||") if row["dance_names"] else []
levels = row["dance_levels"].split("||") if row["dance_levels"] else []
dances = row["dance_names"].split(",") if row["dance_names"] else []
levels = row["dance_levels"].split(",") if row["dance_levels"] else []
alt_dances = row["alt_dance_names"].split(",") if row["alt_dance_names"] else []
songs.append({
"id": row["id"],
"title": row["title"],
@@ -481,6 +485,7 @@ class MainWindow(QMainWindow):
"file_missing": bool(row["file_missing"]),
"dances": dances,
"dance_levels": levels,
"alt_dances": alt_dances,
})
self._library_loaded.emit(songs)
except Exception:

View File

@@ -29,6 +29,16 @@ class DanceLineEdit(QLineEdit):
class TagEditorDialog(QDialog):
def keyPressEvent(self, event):
"""Forhindre Enter i at lukke dialogen — bruges til at tilføje danse."""
from PyQt6.QtCore import Qt as _Qt
if event.key() in (_Qt.Key.Key_Return, _Qt.Key.Key_Enter):
# Send Enter videre til det fokuserede widget i stedet for at lukke
focused = self.focusWidget()
if focused and focused is not self:
focused.event(event)
return
super().keyPressEvent(event)
def __init__(self, song: dict, parent=None):
super().__init__(parent)
self._song = song
@@ -134,6 +144,7 @@ class TagEditorDialog(QDialog):
# Forslags-liste
self._dance_suggestions = QListWidget()
self._dance_suggestions.setMaximumHeight(120)
self._dance_suggestions.setFocusPolicy(Qt.FocusPolicy.NoFocus)
self._dance_suggestions.itemClicked.connect(
lambda item: self._add_from_suggestion(item, "dance")
)
@@ -152,7 +163,11 @@ class TagEditorDialog(QDialog):
return grp
def _add_dance_row(self, name="", level_id=None):
from translations import _
try:
from translations import _, translate_level
except Exception:
def _(key, **kw): return key.split(".")[-1]
def translate_level(n): return n
row_widget = QWidget()
row_layout = QHBoxLayout(row_widget)
row_layout.setContentsMargins(0, 0, 0, 0)
@@ -166,7 +181,6 @@ class TagEditorDialog(QDialog):
level_cb = QComboBox()
level_cb.addItem(_("tags.no_level"), None)
for lvl in self._levels:
from translations import translate_level
level_cb.addItem(translate_level(lvl["name"]), lvl["id"])
# Sæt til det rigtige niveau
if level_id is not None:
@@ -221,16 +235,18 @@ class TagEditorDialog(QDialog):
pass
def _add_from_suggestion(self, item, panel: str):
"""Tilføj dans fra forslags-listen ved dobbeltklik."""
"""Tilføj dans fra forslags-listen ved klik."""
name = item.data(Qt.ItemDataRole.UserRole + 1) or item.text().split(" / ")[0]
level_id = item.data(Qt.ItemDataRole.UserRole)
if panel == "dance":
self._add_dance_row(name, level_id)
self._new_dance.clear()
self._new_dance.setFocus()
self._load_dance_suggestions("", self._dance_suggestions)
else:
self._add_alt_row(name, level_id)
self._new_alt.clear()
self._new_alt.setFocus()
self._load_dance_suggestions("", self._alt_suggestions)
def _on_add_dance(self):
@@ -278,6 +294,7 @@ class TagEditorDialog(QDialog):
self._alt_suggestions = QListWidget()
self._alt_suggestions.setMaximumHeight(120)
self._alt_suggestions.setFocusPolicy(Qt.FocusPolicy.NoFocus)
self._alt_suggestions.itemClicked.connect(
lambda item: self._add_from_suggestion(item, "alt")
)
@@ -295,7 +312,11 @@ class TagEditorDialog(QDialog):
return grp
def _add_alt_row(self, name="", level_id=None, note=""):
from translations import _
try:
from translations import _, translate_level
except Exception:
def _(key, **kw): return key.split(".")[-1]
def translate_level(n): return n
row_widget = QWidget()
row_layout = QHBoxLayout(row_widget)
row_layout.setContentsMargins(0, 0, 0, 0)
@@ -313,7 +334,6 @@ class TagEditorDialog(QDialog):
level_cb = QComboBox()
level_cb.addItem(_("tags.no_level"), None)
for lvl in self._levels:
from translations import translate_level
level_cb.addItem(translate_level(lvl["name"]), lvl["id"])
if level_id is not None:
for i in range(level_cb.count()):