Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1d49ce7cee | |||
| 109bc658c3 |
@@ -1757,7 +1757,12 @@ class WaveformWorker(QThread):
|
|||||||
"-vn", "-ac", "1", "-ar", "8000",
|
"-vn", "-ac", "1", "-ar", "8000",
|
||||||
"-f", "f32le", "-loglevel", "error", "pipe:1",
|
"-f", "f32le", "-loglevel", "error", "pipe:1",
|
||||||
]
|
]
|
||||||
proc = subprocess.run(cmd, capture_output=True, timeout=60)
|
# Run at low priority so it yields disk/CPU to mpv during the
|
||||||
|
# initial load instead of competing for the same file.
|
||||||
|
kwargs = {}
|
||||||
|
if sys.platform != "win32":
|
||||||
|
kwargs["preexec_fn"] = lambda: os.nice(15)
|
||||||
|
proc = subprocess.run(cmd, capture_output=True, timeout=60, **kwargs)
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
return
|
return
|
||||||
samples = np.frombuffer(proc.stdout, dtype=np.float32)
|
samples = np.frombuffer(proc.stdout, dtype=np.float32)
|
||||||
@@ -3184,6 +3189,7 @@ class PlaylistWidget(QListWidget):
|
|||||||
self._folder_counts: dict[str, dict[str, int]] = {} # path → {folder: count}
|
self._folder_counts: dict[str, dict[str, int]] = {} # path → {folder: count}
|
||||||
self._all_subcat_counts: dict[str, int] = {} # profile-wide folder → count
|
self._all_subcat_counts: dict[str, int] = {} # profile-wide folder → count
|
||||||
self._separators_before: set[str] = set() # paths that show a separator row above
|
self._separators_before: set[str] = set() # paths that show a separator row above
|
||||||
|
self._missing: set[str] = set() # paths not present on disk
|
||||||
self._visible: list[str | None] = [] # rows shown; None = separator row
|
self._visible: list[str | None] = [] # rows shown; None = separator row
|
||||||
self._selected_path: str | None = None
|
self._selected_path: str | None = None
|
||||||
self.itemClicked.connect(self._on_item_clicked)
|
self.itemClicked.connect(self._on_item_clicked)
|
||||||
@@ -3238,6 +3244,7 @@ class PlaylistWidget(QListWidget):
|
|||||||
# Drop separator anchors for paths no longer present (keep end sentinel).
|
# Drop separator anchors for paths no longer present (keep end sentinel).
|
||||||
self._separators_before &= set(self._paths) | {self._SEP_END}
|
self._separators_before &= set(self._paths) | {self._SEP_END}
|
||||||
visible_paths = [p for p in self._paths if self._is_visible(p)]
|
visible_paths = [p for p in self._paths if self._is_visible(p)]
|
||||||
|
self._missing = {p for p in visible_paths if not os.path.isfile(p)}
|
||||||
self._visible = []
|
self._visible = []
|
||||||
for path in visible_paths:
|
for path in visible_paths:
|
||||||
if path in self._separators_before:
|
if path in self._separators_before:
|
||||||
@@ -3265,15 +3272,26 @@ class PlaylistWidget(QListWidget):
|
|||||||
return item
|
return item
|
||||||
|
|
||||||
def _style_item(self, item: "QListWidgetItem", path: str) -> None:
|
def _style_item(self, item: "QListWidgetItem", path: str) -> None:
|
||||||
"""Set an item's text and color based on hidden/done/disabled state."""
|
"""Set an item's text and color based on hidden/done/disabled/missing state."""
|
||||||
name = os.path.basename(path)
|
name = os.path.basename(path)
|
||||||
|
font = item.font()
|
||||||
|
font.setItalic(False)
|
||||||
|
font.setStrikeOut(False)
|
||||||
if name in self._hidden_basenames:
|
if name in self._hidden_basenames:
|
||||||
item.setText(f"[hidden] {name}")
|
item.setText(f"[hidden] {name}")
|
||||||
item.setForeground(QColor(120, 120, 120))
|
item.setForeground(QColor(120, 120, 120))
|
||||||
font = item.font()
|
|
||||||
font.setItalic(True)
|
font.setItalic(True)
|
||||||
item.setFont(font)
|
item.setFont(font)
|
||||||
return
|
return
|
||||||
|
if path in self._missing:
|
||||||
|
item.setText(f"⚠ {name}")
|
||||||
|
item.setForeground(QColor(230, 120, 60)) # orange — missing on disk
|
||||||
|
font.setStrikeOut(True)
|
||||||
|
item.setFont(font)
|
||||||
|
item.setToolTip("File missing from disk")
|
||||||
|
return
|
||||||
|
item.setFont(font)
|
||||||
|
item.setToolTip("")
|
||||||
n = self._done_counts.get(path, 0)
|
n = self._done_counts.get(path, 0)
|
||||||
if path in self._done_set:
|
if path in self._done_set:
|
||||||
tag = f"[{n}]" if n else "✓"
|
tag = f"[{n}]" if n else "✓"
|
||||||
@@ -3296,10 +3314,13 @@ class PlaylistWidget(QListWidget):
|
|||||||
self._selected_path = None
|
self._selected_path = None
|
||||||
self._rebuild()
|
self._rebuild()
|
||||||
|
|
||||||
def add_files(self, paths: list[str]) -> None:
|
def add_files(self, paths: list[str], allow_missing: bool = False) -> None:
|
||||||
was_empty = len(self._paths) == 0
|
was_empty = len(self._paths) == 0
|
||||||
for path in paths:
|
for path in paths:
|
||||||
if path not in self._path_set and os.path.isfile(path):
|
if path in self._path_set:
|
||||||
|
continue
|
||||||
|
if not allow_missing and not os.path.isfile(path):
|
||||||
|
continue
|
||||||
self._paths.append(path)
|
self._paths.append(path)
|
||||||
self._path_set.add(path)
|
self._path_set.add(path)
|
||||||
self._rebuild()
|
self._rebuild()
|
||||||
@@ -3379,13 +3400,8 @@ class PlaylistWidget(QListWidget):
|
|||||||
path = self._visible[row]
|
path = self._visible[row]
|
||||||
if path is None:
|
if path is None:
|
||||||
return
|
return
|
||||||
name = os.path.basename(path)
|
self._style_item(item, path)
|
||||||
if path in self._done_set:
|
item.setText(f"▶ {item.text()}")
|
||||||
n = self._done_counts.get(path, 0)
|
|
||||||
tag = f"[{n}] " if n else "✓ "
|
|
||||||
else:
|
|
||||||
tag = ""
|
|
||||||
item.setText(f"▶ {tag}{name}")
|
|
||||||
|
|
||||||
def _decorate_prev(self, row: int) -> None:
|
def _decorate_prev(self, row: int) -> None:
|
||||||
item = self.item(row)
|
item = self.item(row)
|
||||||
@@ -3394,13 +3410,7 @@ class PlaylistWidget(QListWidget):
|
|||||||
path = self._visible[row]
|
path = self._visible[row]
|
||||||
if path is None:
|
if path is None:
|
||||||
return
|
return
|
||||||
name = os.path.basename(path)
|
self._style_item(item, path)
|
||||||
if path in self._done_set:
|
|
||||||
n = self._done_counts.get(path, 0)
|
|
||||||
tag = f"[{n}] " if n else "✓ "
|
|
||||||
item.setText(f"{tag}{name}")
|
|
||||||
else:
|
|
||||||
item.setText(name)
|
|
||||||
|
|
||||||
def _on_item_clicked(self, item: QListWidgetItem) -> None:
|
def _on_item_clicked(self, item: QListWidgetItem) -> None:
|
||||||
# Only load file when it's a plain click (no Ctrl/Shift for multi-select).
|
# Only load file when it's a plain click (no Ctrl/Shift for multi-select).
|
||||||
@@ -4401,7 +4411,8 @@ class MainWindow(QMainWindow):
|
|||||||
if separators:
|
if separators:
|
||||||
pw._separators_before = set(separators)
|
pw._separators_before = set(separators)
|
||||||
if files:
|
if files:
|
||||||
pw.add_files([p for p in files if os.path.isfile(p)])
|
# Keep missing files so they're flagged in the list, not silently dropped.
|
||||||
|
pw.add_files(files, allow_missing=True)
|
||||||
if select:
|
if select:
|
||||||
self._playlist_tabs.setCurrentIndex(idx)
|
self._playlist_tabs.setCurrentIndex(idx)
|
||||||
if not self._loading_tabs:
|
if not self._loading_tabs:
|
||||||
@@ -4474,14 +4485,13 @@ class MainWindow(QMainWindow):
|
|||||||
if isinstance(seps, str):
|
if isinstance(seps, str):
|
||||||
seps = [seps] if seps else []
|
seps = [seps] if seps else []
|
||||||
self._add_playlist_tab(
|
self._add_playlist_tab(
|
||||||
"List 1",
|
"List 1", files=list(files),
|
||||||
files=[f for f in files if os.path.isfile(f)],
|
|
||||||
separators=seps, select=True)
|
separators=seps, select=True)
|
||||||
else:
|
else:
|
||||||
for t in data["tabs"]:
|
for t in data["tabs"]:
|
||||||
self._add_playlist_tab(
|
self._add_playlist_tab(
|
||||||
t.get("label", "List"),
|
t.get("label", "List"),
|
||||||
files=[f for f in t.get("files", []) if os.path.isfile(f)],
|
files=list(t.get("files", [])),
|
||||||
separators=t.get("separators", []), select=False)
|
separators=t.get("separators", []), select=False)
|
||||||
cur = min(max(0, data.get("current", 0)),
|
cur = min(max(0, data.get("current", 0)),
|
||||||
self._playlist_tabs.count() - 1)
|
self._playlist_tabs.count() - 1)
|
||||||
|
|||||||
Reference in New Issue
Block a user