PySide6 desktop app for organizing mpv .m3u8 playlists
Find a file
Isaac be22837d26 Force UTF-8 for ffmpeg/ffprobe subprocess output
ffmpeg's stderr contains bytes (special symbols, math chars, codec
names) that aren't valid in cp932 — the default code page on
Japanese Windows. With text=True and no explicit encoding,
subprocess.run tried to decode the captured output as cp932 and
crashed with:
  UnicodeDecodeError: 'cp932' codec can't decode byte 0x90

Same issue in get_midpoint_seconds for ffprobe.

Fix: pass encoding='utf-8' and errors='replace' to both
subprocess.run calls. UTF-8 covers the ffmpeg/ffprobe output
universally, and errors='replace' is a belt-and-suspenders safety
net so we never crash while constructing an error message from
stderr.

Also added:
- MainWindow.closeEvent that calls worker.quit() + wait(5000)
  on any running thumbnail workers, so a QThread is never
  destroyed while still running (was producing 'QThread: Destroyed
  while thread is still running' warnings and intermittent
  segfaults on app close / test teardown).
- tests/conftest.py: new qt_window fixture that tracks QWidgets
  and closes them at test teardown, so the closeEvent cleanup
  actually runs in tests.

Tests: 2 new in test_thumbnails verifying encoding='utf-8' and
errors='replace' are passed to subprocess.run for both ffprobe
and ffmpeg. All 86 tests pass; suite exits cleanly with no
segfaults.
2026-07-07 17:18:28 -04:00
tests Force UTF-8 for ffmpeg/ffprobe subprocess output 2026-07-07 17:18:28 -04:00
.env.example Add MPV_BIN env var to override the mpv binary 2026-07-07 16:46:53 -04:00
.gitignore feat: initial implementation 2026-06-24 18:40:20 -04:00
config.py Add MPV_BIN env var to override the mpv binary 2026-07-07 16:46:53 -04:00
db.py Add Delete Selected button with confirmation 2026-07-07 16:31:04 -04:00
DESIGN.md design: lock implementation decisions 2026-06-24 18:32:55 -04:00
main.py feat: initial implementation 2026-06-24 18:40:20 -04:00
playlists.py Add 'New Playlist' button and drag-and-drop 2026-07-07 17:11:45 -04:00
README.md feat: initial implementation 2026-06-24 18:40:20 -04:00
requirements.txt feat: initial implementation 2026-06-24 18:40:20 -04:00
thumbnails.py Force UTF-8 for ffmpeg/ffprobe subprocess output 2026-07-07 17:18:28 -04:00
window.py Force UTF-8 for ffmpeg/ffprobe subprocess output 2026-07-07 17:18:28 -04:00

mpv-playlist-dashboard

A small PySide6 desktop app for organizing and launching mpv .m3u8 playlists.

See DESIGN.md for the design document.

Setup

pip install --break-system-packages -r requirements.txt
pip install --break-system-packages pytest  # for tests

Configuration

Create a .env file in the repo root:

MPV_PLAYLIST_DIR=/path/to/playlists

Optional:

MPV_PLAYLIST_DB=/path/to/state.db   # default: XDG_DATA_HOME/mpv-playlist-dashboard/state.db

The MPV_PLAYLIST_DIR directory should hold .m3u8 playlist files.

Run

python main.py

Tests

pytest tests/ -v

Status

Implementation complete for v1. See DESIGN.md for scope and out-of-scope items.