251 lines
11 KiB
Markdown
251 lines
11 KiB
Markdown
# LinTunes
|
||
|
||

|
||
|
||
|
||
## trave notes
|
||
|
||
|
||
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?).
|
||
|
||
I have been a mac user for ~34 years. I gave up daily driving mac os in 2021. After 5 years I got tired of my music being solely on my desktop so I vibe-coded this replacement with all the features I wanted from iTunes.
|
||
|
||
|
||
# docs written by llms and cleaned up by me:
|
||
|
||
## Features
|
||
|
||
**Library**
|
||
- Sortable track list with 24 optional columns (plays, skips, rating, BPM,
|
||
bit rate, date added…) — column choice, sort and widths are remembered
|
||
*per playlist*.
|
||
- Keeps track of date song was last played
|
||
- **Column browser** (Ctrl+B) — filter by genre / artist / album.
|
||
- Instant **search** over name, artist, album, composer and more.
|
||
- **Get Info** (Ctrl+I) edits tags on one track or a whole selection at once,
|
||
writing them back to the file. Artwork can be pasted, dragged in, or fetched
|
||
automatically (**Download Album Art…**, via the iTunes Search API).
|
||
- Rename an artist or album and the files **move themselves** into a tidy
|
||
`Artist/Album/` tree.
|
||
- **Undo/redo everything** (Ctrl+Z / Ctrl+Shift+Z) — edits, deletes, reorders.
|
||
- Deleting a track sends the file to your desktop **Trash**, never `rm`.
|
||
|
||
**Playlists**
|
||
- Regular playlists, **folders**, and **smart playlists** (auto-updating, with a
|
||
full rule editor).
|
||
- Drag and drop to reorder or insert at a spot; duplicate-aware adds;
|
||
copy/cut/paste tracks between playlists.
|
||
|
||
**Playing**
|
||
- mp3, m4a, flac, aac, wav, aiff.
|
||
- Shuffle, per-track start/stop times, play counts, skip counts and ratings.
|
||
- Media keys work, plus Space and ←/→ anywhere in the app.
|
||
- Live **spectrum visualizer** — click it to cycle bright / dim / off.
|
||
- last.fm scrobbling
|
||
- Theming: highlight color, UI scale, and custom colors
|
||
|
||
**Sending music elsewhere**
|
||
- **Chromecast**
|
||
- **Export a playlist** (File ▸ Export Playlist…) — either a folder of
|
||
`Artist - Title.mp3` files plus an `.m3u`, or a self-contained `index.html` you can upload anywhere.
|
||
- **Sync a playlist to a Rabbit R1** over MTP, `.m3u` included.
|
||
|
||
**Living on more than one machine**
|
||
- The whole library is **plain JSON**, designed to be synced with
|
||
[Syncthing](https://syncthing.net). Sync conflicts merge themselves on
|
||
startup.
|
||
- The version number in the status bar checks for updates (via git) and you can click it to update to the latest version.
|
||
|
||
|
||
|
||
## Never used a terminal? Start here
|
||
|
||
If the commands below look intimidating, they're friendlier than they look.
|
||
|
||
The **terminal** is a window where you type commands instead of clicking. On
|
||
most Linux desktops you open it by pressing the Super key (the one with the
|
||
Windows/Command logo) and typing "terminal". (On a Mac it's Terminal, from
|
||
Spotlight; on Windows it's PowerShell, from the Start menu — but read the
|
||
Mac/Windows note under *What you need* first.) Everything in a grey box below is
|
||
meant to be **copied and pasted** into that window — paste it, press Enter,
|
||
done. You don't need to understand a command to run it.
|
||
|
||
Two bits of shorthand that show up everywhere:
|
||
|
||
- **`~`** means your home folder. `~/Music` is just the Music folder inside your
|
||
home folder — the same one your file manager shows you.
|
||
- **Your "distro"** is which flavour of Linux you're running (Ubuntu, Fedora,
|
||
Debian, Mint…). If you don't know, it's almost certainly Ubuntu or Mint, and
|
||
you want the **Debian/Ubuntu** instructions below.
|
||
|
||
If a command fails, nothing is broken — copy the error into a search engine, or
|
||
ask whoever pointed you here. You cannot damage your music by running these.
|
||
|
||
## What you need
|
||
|
||
Linux, Python, and a handful of free add-ons. **Nothing to compile, no account
|
||
to make, no database to set up, nothing that phones home.** LinTunes keeps your
|
||
library as ordinary files on your own computer.
|
||
|
||
In detail:
|
||
|
||
- **Linux** with Python **3.11 or newer** (already installed on essentially
|
||
every Linux machine — check with `python3 --version`)
|
||
- **PyQt6** (including its QtMultimedia part), **mutagen**, **numpy**, **requests**
|
||
- The **FFmpeg codecs for Qt Multimedia**. Without these the window opens fine
|
||
but nothing plays — so if you get a silent LinTunes, this is the thing that's
|
||
missing. They come from `qt6-qtmultimedia` built with ffmpeg (Fedora: enable
|
||
RPM Fusion; Debian/Ubuntu: it comes along with `python3-pyqt6.qtmultimedia`).
|
||
|
||
**On a Mac or on Windows?** LinTunes is only built and tested on Linux and
|
||
that's not changing — but very little of it is actually Linux-specific: Python,
|
||
PyQt6, mutagen and the rest run everywhere, and your library is just JSON files.
|
||
On **macOS** it will most likely run as-is — clone the repo, `pip install -e .`,
|
||
then `python3 -m lintunes.main` — with three things quietly missing: media keys
|
||
and the now-playing widget, the keep-the-machine-awake-while-playing bit (both
|
||
of those go through a Linux-only service), and Rabbit R1 sync. Deleting a track
|
||
would also drop the file in a Linux-style `.Trash` folder rather than Finder's
|
||
Trash — recoverable, but not where you'd look — and there's no `.app` or dock
|
||
icon, so you'd launch it from Terminal. **Windows** needs a little real work
|
||
first: a couple of places call a POSIX-only function (`os.getuid()`, in
|
||
`lintunes/trash.py` and `lintunes/device_sync.py`), so deleting a track would
|
||
error out until someone routes that through the Recycle Bin instead — a small
|
||
patch, not a rewrite. If you get either one going, lmk!!
|
||
|
||
## Installing
|
||
|
||
Pick whichever fits your distro:
|
||
|
||
- **pip** — simplest where your distro allows it; also puts a `lintunes` command
|
||
in `~/.local/bin`:
|
||
```sh
|
||
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:
|
||
```sh
|
||
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:
|
||
```sh
|
||
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.
|
||
|
||
Below, `lintunes` and `python3 -m lintunes.main` are interchangeable — use
|
||
whichever your install gave you.
|
||
|
||
## Starting from scratch (no iTunes needed)
|
||
|
||
Tell it where to keep the library, once:
|
||
|
||
```sh
|
||
mkdir -p ~/Music/lintunes # the library lives here
|
||
lintunes --data-dir ~/Music/lintunes --save-config # remembers it from now on
|
||
```
|
||
|
||
Then just run `lintunes`. The first time it opens, it asks one question — where
|
||
to keep your music — and suggests `~/Music`. Pick a folder, or click **Not
|
||
Now** and set it later in **Edit ▸ Preferences**.
|
||
|
||
Now add music: **File ▸ Add Files to Library** (Ctrl+O), or drag files and
|
||
folders straight onto the window. Whole folders are fine.
|
||
|
||
Your songs are **copied** into the folder you chose and filed by artist and
|
||
album.
|
||
|
||
|
||
## Importing an existing iTunes library
|
||
|
||
In iTunes 12.x: **File ▸ Library ▸ Export Library** to get the XML, then:
|
||
|
||
```sh
|
||
lintunes --import-xml "iTunes Library.xml" \
|
||
--music-root "/path/to/iTunes Media" \
|
||
--data-dir /path/to/library-data --save-config
|
||
lintunes # from now on, just run it
|
||
```
|
||
|
||
This brings across your tracks, playlists, playlist folders and smart playlists
|
||
(auto-updating and still editable), along with play counts, ratings and dates.
|
||
Mac paths are remapped to `--music-root` automatically, including
|
||
case/accent differences. Anything it couldn't find is written to
|
||
`import_missing_files.txt` in your data dir. Untested on iTunes versions other
|
||
than 12.
|
||
|
||
## Running it
|
||
|
||
```sh
|
||
lintunes # uses the saved config
|
||
```
|
||
|
||
The desktop launcher runs LinTunes with no arguments, so it always uses whatever
|
||
is saved in `~/.config/lintunes/config.json`
|
||
|
||
|
||
## Keys
|
||
|
||
Space play/pause · ←/→ previous/next · Ctrl+B column browser ·
|
||
Ctrl+I get info · Ctrl+L go to current song · Ctrl+O add files ·
|
||
Ctrl+N new playlist (Ctrl+Alt+N smart, Ctrl+Shift+N folder) ·
|
||
Ctrl+Z undo · Ctrl+, preferences · Ctrl+C/Ctrl+X/Ctrl+V copy/cut/paste tracks ·
|
||
double-click sidebar art for a big art window
|
||
|
||
## 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:
|
||
|
||
```sh
|
||
# 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" --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` 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.)
|
||
|
||
## 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
|
||
|
||
```sh
|
||
python3 -m pytest tests/
|
||
```
|
||
|
||
`spec.md` is the original design brief; `tasks*.md` track what's built.
|