mirror of
https://github.com/darkzoul5/YoutubePlaylistSync.git
synced 2026-11-03 23:38:14 +02:00
fix: resolve all current lint errors
This commit is contained in:
1 parent
972c8e1dbf
commit
8904e07597
11 files changed
+64
-51
No files matched your search
@@ -1,10 +1,13 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _default_ffmpeg_path() -> str:
|
||||
if os.name == "nt":
|
||||
@@ -40,9 +43,9 @@ class Settings:
|
||||
def _load_from_path(self, path: Path) -> None:
|
||||
try:
|
||||
self.data.update(json.loads(path.read_text(encoding="utf-8")))
|
||||
except Exception:
|
||||
except (OSError, TypeError, UnicodeError, ValueError) as exc:
|
||||
# Leave defaults if invalid JSON; validation can be added later.
|
||||
pass
|
||||
logger.debug("Failed to load config %s: %s", path, exc)
|
||||
|
||||
def _write_default_config(self, path: Path) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from PySide6 import QtGui, QtWidgets
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _resource_base() -> Path:
|
||||
# PyInstaller sets sys._MEIPASS to the temp extraction dir.
|
||||
@@ -31,16 +34,16 @@ def load_app_icon() -> QtGui.QIcon:
|
||||
icon = QtGui.QIcon(str(p))
|
||||
if not icon.isNull():
|
||||
return icon
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001 - icon loading is best effort
|
||||
logger.debug("Failed to load app icon from %s: %s", p, exc)
|
||||
|
||||
# Fallback to a platform theme icon (Linux) or a generic icon.
|
||||
try:
|
||||
themed = QtGui.QIcon.fromTheme("applications-multimedia")
|
||||
if not themed.isNull():
|
||||
return themed
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001 - themed icon loading is best effort
|
||||
logger.debug("Failed to load themed app icon: %s", exc)
|
||||
|
||||
return QtWidgets.QApplication.style().standardIcon(QtWidgets.QStyle.StandardPixmap.SP_ComputerIcon)
|
||||
|
||||
@@ -15,7 +15,7 @@ class AppConfig:
|
||||
def load_config(path: Path) -> AppConfig:
|
||||
raw = json.loads(path.read_text(encoding="utf-8"))
|
||||
if not isinstance(raw, dict):
|
||||
raise ValueError("config root must be a JSON object")
|
||||
raise TypeError("config root must be a JSON object")
|
||||
return AppConfig(data=raw, path=path)
|
||||
|
||||
|
||||
|
||||
+34
-26
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import sys
|
||||
import threading
|
||||
|
||||
@@ -17,6 +18,8 @@ from .pages.queue import QueuePage
|
||||
from .pages.settings import SettingsPage
|
||||
from .runner import SyncRequest, SyncRunner
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MainWindow(QtWidgets.QMainWindow):
|
||||
def __init__(self) -> None:
|
||||
@@ -90,8 +93,8 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
if cfg_path is not None:
|
||||
try:
|
||||
self._settings_page.set_config_path(cfg_path)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001 - optional settings-page wiring
|
||||
logger.debug("Failed to set settings config path: %s", exc)
|
||||
|
||||
self._playlists_page.cancel_requested.connect(self._cancel_sync)
|
||||
self._queue_page.cancel_sync_requested.connect(self._cancel_sync)
|
||||
@@ -138,7 +141,8 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
tray = ui.get("tray")
|
||||
tray = tray if isinstance(tray, dict) else {}
|
||||
return dict(tray)
|
||||
except Exception:
|
||||
except Exception as exc: # noqa: BLE001 - config fallback keeps the UI usable
|
||||
logger.debug("Failed to load tray configuration: %s", exc)
|
||||
return {}
|
||||
|
||||
def _close_to_tray_enabled(self) -> bool:
|
||||
@@ -158,7 +162,8 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
try:
|
||||
if not QtWidgets.QSystemTrayIcon.isSystemTrayAvailable():
|
||||
return
|
||||
except Exception:
|
||||
except Exception as exc: # noqa: BLE001 - tray support is optional
|
||||
logger.debug("Failed to check system tray availability: %s", exc)
|
||||
return
|
||||
|
||||
icon = load_app_icon()
|
||||
@@ -211,27 +216,30 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
QtWidgets.QSystemTrayIcon.MessageIcon.Information,
|
||||
3000,
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001 - tray notification is best effort
|
||||
logger.debug("Failed to show tray notification: %s", exc)
|
||||
return
|
||||
if self._tray is not None and not self._close_to_tray_enabled():
|
||||
# Explicitly quit, because the app may be configured to keep running without windows.
|
||||
try:
|
||||
event.accept()
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001 - close event acceptance is best effort
|
||||
logger.debug("Failed to accept close event: %s", exc)
|
||||
QtWidgets.QApplication.quit()
|
||||
return
|
||||
super().closeEvent(event)
|
||||
|
||||
def changeEvent(self, event: QtCore.QEvent) -> None: # type: ignore[override]
|
||||
try:
|
||||
if event.type() == QtCore.QEvent.Type.WindowStateChange:
|
||||
if self._tray is not None and self._minimize_to_tray_enabled():
|
||||
if bool(self.windowState() & QtCore.Qt.WindowState.WindowMinimized):
|
||||
QtCore.QTimer.singleShot(0, self.hide)
|
||||
except Exception:
|
||||
pass
|
||||
if (
|
||||
event.type() == QtCore.QEvent.Type.WindowStateChange
|
||||
and self._tray is not None
|
||||
and self._minimize_to_tray_enabled()
|
||||
and bool(self.windowState() & QtCore.Qt.WindowState.WindowMinimized)
|
||||
):
|
||||
QtCore.QTimer.singleShot(0, self.hide)
|
||||
except Exception as exc: # noqa: BLE001 - window state handling is best effort
|
||||
logger.debug("Failed to handle window state change: %s", exc)
|
||||
super().changeEvent(event)
|
||||
|
||||
def _refresh_queue_labels(self) -> None:
|
||||
@@ -244,24 +252,24 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
pid = extract_playlist_id(url) or url
|
||||
labels[pid] = str(pl.get("name") or f"Playlist {idx}")
|
||||
self._queue_page.set_playlist_labels(labels)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001 - queue labels are best effort
|
||||
logger.debug("Failed to refresh queue labels: %s", exc)
|
||||
|
||||
@QtCore.Slot(str, dict)
|
||||
def _on_bus_event(self, name: str, payload: dict) -> None:
|
||||
# Fan out to interested pages.
|
||||
try:
|
||||
self._queue_page.on_event(name, payload)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001 - page event fan-out is isolated
|
||||
logger.debug("Queue page event handler failed: %s", exc)
|
||||
try:
|
||||
self._logs_page.on_event(name, payload)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001 - page event fan-out is isolated
|
||||
logger.debug("Logs page event handler failed: %s", exc)
|
||||
try:
|
||||
self._playlists_page.on_event(name, payload)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001 - page event fan-out is isolated
|
||||
logger.debug("Playlists page event handler failed: %s", exc)
|
||||
|
||||
# Auto-pause on YouTube bot-check/rate-limit surface.
|
||||
if name == "SyncPaused":
|
||||
@@ -315,8 +323,8 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
try:
|
||||
self._thread.quit()
|
||||
self._thread.wait(2000)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001 - thread shutdown is best effort
|
||||
logger.debug("Failed to stop sync thread: %s", exc)
|
||||
self._runner = None
|
||||
self._cancel_flag = None
|
||||
self._pause_flag = None
|
||||
@@ -330,8 +338,8 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
if cfg_path is not None:
|
||||
self._settings_page.set_config_path(cfg_path)
|
||||
self._refresh_queue_labels()
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001 - config refresh is best effort
|
||||
logger.debug("Failed to refresh configuration after sync: %s", exc)
|
||||
|
||||
# Continue "sync all" chain if active.
|
||||
if hasattr(self, "_sync_queue") and self._sync_queue:
|
||||
|
||||
@@ -38,7 +38,7 @@ class LogsPage(QtWidgets.QWidget):
|
||||
# Keep this lightweight: append a single-line JSON entry.
|
||||
try:
|
||||
line = json.dumps({"event": name, **payload}, ensure_ascii=False)
|
||||
except Exception:
|
||||
except Exception: # noqa: BLE001 - fall back to a readable representation
|
||||
line = f"{name}: {payload}"
|
||||
self._text.appendPlainText(line)
|
||||
self._text.moveCursor(self._text.textCursor().End)
|
||||
@@ -137,7 +137,7 @@ class PlaylistManagerPage(QtWidgets.QWidget):
|
||||
raise RuntimeError("Config path not available")
|
||||
self._config = normalize_config(load_config(self._config_path).data)
|
||||
rows = self._rows_from_settings()
|
||||
except Exception as exc:
|
||||
except Exception as exc: # noqa: BLE001 - show config load failures in the UI
|
||||
self._status.setText(f"Failed to load config: {exc}")
|
||||
return
|
||||
finally:
|
||||
@@ -152,7 +152,7 @@ class PlaylistManagerPage(QtWidgets.QWidget):
|
||||
ls = db.get_playlist_last_sync(pid)
|
||||
if ls:
|
||||
last_sync_by_id[pid] = str(ls)
|
||||
except Exception:
|
||||
except Exception: # noqa: BLE001 - database metadata is optional
|
||||
last_sync_by_id = {}
|
||||
|
||||
self._list.clear()
|
||||
@@ -256,7 +256,7 @@ class PlaylistManagerPage(QtWidgets.QWidget):
|
||||
self._status.setText(f"Saved {len(data['playlists'])} playlists to {self._config_path}.")
|
||||
# Reload settings to reflect merged defaults
|
||||
self.reload_from_config()
|
||||
except Exception as exc:
|
||||
except Exception as exc: # noqa: BLE001 - show config save failures in the UI
|
||||
self._status.setText(f"Failed to save config: {exc}")
|
||||
|
||||
def _reindex_cards(self) -> None:
|
||||
@@ -302,7 +302,7 @@ class PlaylistManagerPage(QtWidgets.QWidget):
|
||||
data["playlists"] = self._table_to_playlists()
|
||||
save_config(self._config_path, data)
|
||||
self._status.setText(f"Autosaved to {self._config_path}.")
|
||||
except Exception as exc:
|
||||
except Exception as exc: # noqa: BLE001 - show autosave failures in the UI
|
||||
self._status.setText(f"Autosave failed: {exc}")
|
||||
|
||||
def on_event(self, name: str, payload: dict) -> None:
|
||||
@@ -355,7 +355,7 @@ class PlaylistManagerPage(QtWidgets.QWidget):
|
||||
self._download_state_by_pid[pid]["video_id"] = vid
|
||||
self._download_state_by_pid[pid]["status"] = str(payload.get("status") or "downloading")
|
||||
self._set_card_progress(pid, p)
|
||||
pct = int(round(max(0.0, min(1.0, p)) * 100))
|
||||
pct = round(max(0.0, min(1.0, p)) * 100)
|
||||
st = str(payload.get("status") or "downloading")
|
||||
tail = f"{vid} {pct}%" if vid else f"{pct}%"
|
||||
self._set_card_status(pid, f"{st} {tail}".strip())
|
||||
@@ -392,9 +392,8 @@ class PlaylistManagerPage(QtWidgets.QWidget):
|
||||
for i in range(self._list.count()):
|
||||
item = self._list.item(i)
|
||||
w = self._list.itemWidget(item)
|
||||
if isinstance(w, _PlaylistCard):
|
||||
if w.playlist_id() == playlist_id:
|
||||
w.set_status(text)
|
||||
if isinstance(w, _PlaylistCard) and w.playlist_id() == playlist_id:
|
||||
w.set_status(text)
|
||||
|
||||
def _set_card_last_sync(self, playlist_id: str, last_sync: str) -> None:
|
||||
for i in range(self._list.count()):
|
||||
@@ -604,7 +603,7 @@ class _PlaylistCard(QtWidgets.QFrame):
|
||||
return extract_playlist_id(url) or url
|
||||
|
||||
def set_progress(self, progress: float) -> None:
|
||||
pct = max(0, min(100, int(round(progress * 100))))
|
||||
pct = max(0, min(100, round(progress * 100)))
|
||||
self._progress.setValue(pct)
|
||||
|
||||
def set_last_sync(self, last_sync: str) -> None:
|
||||
@@ -613,7 +612,7 @@ class _PlaylistCard(QtWidgets.QFrame):
|
||||
def validate(self) -> list[str]:
|
||||
errs: list[str] = []
|
||||
url = self._url.text().strip()
|
||||
if not url or not (url.startswith("http://") or url.startswith("https://")):
|
||||
if not url or not url.startswith(("http://", "https://")):
|
||||
errs.append("URL required")
|
||||
mode = self._mode.currentText().strip()
|
||||
if mode not in {"video", "audio", "both"}:
|
||||
|
||||
@@ -141,7 +141,7 @@ class QueuePage(QtWidgets.QWidget):
|
||||
status_item.setText(str(payload.get("status") or "downloading"))
|
||||
prog = payload.get("progress")
|
||||
if isinstance(prog, (int, float)):
|
||||
pct = max(0, min(100, int(round(prog * 100))))
|
||||
pct = max(0, min(100, round(prog * 100)))
|
||||
bar = self._table.cellWidget(row, 3)
|
||||
if bar is None:
|
||||
bar = QtWidgets.QProgressBar()
|
||||
|
||||
@@ -126,7 +126,7 @@ class SettingsPage(QtWidgets.QWidget):
|
||||
self._start_minimized_to_tray.setChecked(bool(tray.get("start_minimized_to_tray", False)))
|
||||
|
||||
self._status.setText(f"Loaded settings from {self._config_path}.")
|
||||
except Exception as exc:
|
||||
except Exception as exc: # noqa: BLE001 - show load failures in the UI
|
||||
self._status.setText(f"Failed to load settings: {exc}")
|
||||
finally:
|
||||
self._suppress_autosave = False
|
||||
@@ -161,5 +161,5 @@ class SettingsPage(QtWidgets.QWidget):
|
||||
|
||||
save_config(self._config_path, data)
|
||||
self._status.setText(f"Saved settings to {self._config_path}.")
|
||||
except Exception as exc:
|
||||
except Exception as exc: # noqa: BLE001 - show save failures in the UI
|
||||
self._status.setText(f"Failed to save settings: {exc}")
|
||||
@@ -70,5 +70,5 @@ class SyncRunner(QtCore.QObject):
|
||||
self.finished.emit(False, "cancelled")
|
||||
else:
|
||||
self.finished.emit(True, "done")
|
||||
except Exception as exc:
|
||||
except Exception as exc: # noqa: BLE001 - report worker failures through the UI signal
|
||||
self.finished.emit(False, str(exc))
|
||||
@@ -19,7 +19,7 @@ class _SmoothWheelFilter(QtCore.QObject):
|
||||
try:
|
||||
angle_y = wheel.angleDelta().y()
|
||||
pixel_y = wheel.pixelDelta().y()
|
||||
except Exception:
|
||||
except Exception: # noqa: BLE001 - fall back to native scrolling for unknown event types
|
||||
return super().eventFilter(obj, event)
|
||||
|
||||
dy = pixel_y if pixel_y else angle_y
|
||||
@@ -34,7 +34,7 @@ class _SmoothWheelFilter(QtCore.QObject):
|
||||
if pixel_y:
|
||||
delta = -dy
|
||||
else:
|
||||
delta = int(round(-dy / 120.0 * base_step))
|
||||
delta = round(-dy / 120.0 * base_step)
|
||||
|
||||
target = max(sb.minimum(), min(sb.maximum(), start + delta))
|
||||
if target == start:
|
||||
|
||||
@@ -37,7 +37,7 @@ def test_executor_emits_sync_events(tmp_path):
|
||||
assert "SyncSummary" in names
|
||||
assert "SyncFinished" in names
|
||||
|
||||
summary = [p for n, p in published if n == "SyncSummary"][0]
|
||||
summary = next(p for n, p in published if n == "SyncSummary")
|
||||
assert summary["playlist_id"] == "p"
|
||||
assert "duration_s" in summary
|
||||
assert isinstance(summary["counts"], dict)
|
||||
|
||||
Reference in new issue
Block a user