travandClaude Opus 5 211cb50a9e v0.7.0: startup speed — the 21k-track library stops freezing
Three reported symptoms, one shape: every operation was whole-library,
whole-file, on the Qt main thread. Measured on the real library (21,482
tracks, 506 playlists, 15 MB library.json).

The track table sorted through a QSortFilterProxyModel, which asks data()
for a value on every comparison — 580k Python round trips, 8.5 s per table
load, paid again on every reload. TrackTableModel now keeps _tracks in
canonical (playlist) order plus an _order index list and sorts a key list
computed once per track. Nothing used the proxy's filtering. Sorting by #
is the identity order, so "source row" still means "playlist position" for
drag-reorder. 8.5 s -> 0.13 s; MainWindow() 18.1 s -> 0.79 s.

Smart rules compile to closures once per evaluate() instead of being
re-dispatched per track — the operator lookup, casefolding the query and
parsing the rule's own date constants all leave the 21k-iteration loop
(_match_date was re-parsing its own constant 21,482 times per rule).
Verified identical membership against the old evaluator on all 20 real
smart playlists. 2.54 s -> 0.72 s, and it now runs after the first paint.

Also: _reconcile_track skips two to_dict() round trips per unchanged track
(MERGEABLE_FIELDS in the resolver is the single source of truth for what a
merge touches); no git subprocess on the startup path (Updater.enabled is
probed lazily on the background thread, version-button tooltip deferred);
and .resolved/ is pruned to the newest 10 snapshots — it had reached 1.7 GB
across 73 snapshots inside the Syncthing share.

Time to interactive window ~15 s -> 3.2 s. The mid-session freeze when
Syncthing delivers a change — a full reload + recompute + table rebuild
with the window already on screen, which is what GNOME was offering to
force-quit — ~16 s -> 3.8 s.

The merge rework itself (playlist ordering, per-machine play journal,
quieting the dialog) is queued in TASKS.md as Round 36.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 17:09:07 -04:00
2026-06-26 21:12:01 -04:00
2026-06-26 21:12:01 -04:00
2026-06-26 21:12:01 -04:00

LinTunes

LinTunes

an mp3 library manager and player for linux. Absolutely no guarantees, if it wrecks your itunes library or wipes your harddrive that's on you (maybe just have your LLM of choice review the software for bugs and vulns?).

Features

  • can import an iTunes 12 (untested on other versions) library, including smart playlists (auto-updating, editable, marked with a ❧)
  • runs on several machines off one Syncthing-synced library (see below)

How it works

  • Your music files are never moved or rewritten (except when you edit tags).
  • The library lives as plain JSON files (library.json + one file per playlist) in a directory you choose — designed to be synced with Syncthing; sync conflicts are merged automatically on startup (play counts take the max, edits take the newest, playlists take the union).
  • Playback via Qt Multimedia/FFmpeg (mp3, m4a, flac). Media keys work through MPRIS. Scrobbling to last.fm is optional (Edit → Preferences).

Why

I have been a mac user for ~34 years. I gave up daily driving mac os in 2020. I figured Apple

but my music library even some tracks I got from napster all the way back in 2000 (I have since paid for!!)

Installing

LinTunes needs four Python packages — PyQt6 (with its QtMultimedia module), mutagen, numpy, requests — plus the FFmpeg codecs for Qt Multimedia so audio actually plays. Nothing compiles; get the deps whichever way fits your distro:

  • pip — simplest where your distro allows it; also puts a lintunes command in ~/.local/bin:
    pip install -e .
    
  • Debian/Ubuntu — system pip is locked down (the externally-managed-environment / PEP 668 error), so install the deps from apt and skip pip entirely:
    sudo apt install python3-pyqt6 python3-pyqt6.qtmultimedia \
                     python3-mutagen python3-numpy python3-requests
    
    (If python3-pyqt6.qtmultimedia isn't found, apt search python3-pyqt6 and grab the multimedia one.) There's no lintunes command this way — run it with python3 -m lintunes.main.
  • venv — isolated:
    python3 -m venv .venv && .venv/bin/pip install -e .
    
    Run with .venv/bin/lintunes. One caveat: the dock launcher (see App icon) uses the system python, which can't see a venv's packages — so for the icon to work, edit the installed lintunes.desktop's Exec= line to the absolute venv path (…/lintunes/.venv/bin/lintunes %F).

You never strictly need pip or the lintunes command. As long as those four deps import, python3 -m lintunes.main from the checkout runs the app — which is exactly what the desktop launcher does. The FFmpeg codecs come from qt6-qtmultimedia built with ffmpeg (Fedora: RPM Fusion; Debian/Ubuntu: pulled in by python3-pyqt6.qtmultimedia). Without them the UI runs but tracks won't play.

Running it

# one-time import from iTunes (XML: File ▸ Library ▸ Export Library in iTunes 12.x)
python3 -m lintunes.main --import-xml "iTunes Library.xml" \
    --music-root "/path/to/iTunes Media" \
    --data-dir /path/to/library-data --save-config
python3 -m lintunes.main            # run the app (uses the saved config)

(Installed with pip? Type lintunes instead of python3 -m lintunes.main.)

LinTunes looks best with Century Gothic installed (~/.local/share/fonts/); if it's missing, you'll be asked to pick a font on first run.

The desktop launcher runs LinTunes with no --data-dir, so it always uses whatever is saved in ~/.config/lintunes/config.json — point that config wherever you want and the dock icon follows.

Running on a second machine (Syncthing)

Keep the data dir (which holds library.json, the playlists, and preferences.json) inside your Syncthing-shared music folder, so the music and the library travel together. Track paths are stored relative to the data dir, so the library resolves correctly no matter where each machine mounts the shared folder — you never edit anything inside the library to move it.

~/.config/lintunes/config.json is per-machine (it is not synced), so on a new machine you just tell LinTunes where the synced folder landed:

# 1. get the code, then install the deps (see "Installing" above: pip / apt / venv)
git clone ssh://git@git.autonomic.zone:2222/trav/lintunes.git
cd lintunes

# 2. let Syncthing finish replicating the music folder, then point the config at
#    THIS machine's paths and launch — no re-import, the data is already synced:
python3 -m lintunes.main --data-dir  "/path/to/synced/music/lintunes" \
                         --music-root "/path/to/synced/music/iTunes Media" \
                         --save-config

# 3. install the launcher + icon, then pin it (see "App icon" below)
bash packaging/install-desktop.sh

(Step 2 just writes data_dir + music_root into ~/.config/lintunes/config.json — you can also create that file by hand. After it's saved, every launch, including the dock icon, uses the synced library automatically.)

Keys

Space play/pause · ←/→ previous/next · Ctrl+B column browser · Ctrl+I get info · Ctrl+, preferences · Ctrl+C/Ctrl+X/Ctrl+V copy/cut/paste tracks · double-click sidebar art for a big art window

App icon

packaging/install-desktop.sh installs the launcher entry and icon for your user (lets you pin LinTunes to the GNOME dash). The icon is just a file — replace packaging/lintunes.png (256×256 PNG) and re-run the script to use your own. GNOME caches icons, so if the old one lingers, log out and back in.

Unpinning from the dash does not uninstall LinTunes — it's still in the GNOME app grid (open Activities and search "LinTunes"). Right-click it there → Pin to Dash to get it back.

Development

python3 -m pytest tests/

spec.md is the original design brief; tasks*.md track what's built.

S
Description
No description provided
Readme
2.2 MiB
Languages
Python 98.4%
JavaScript 0.7%
CSS 0.5%
Go Template 0.2%
Shell 0.2%