diff --git a/README.md b/README.md index 562b1ca..425cde5 100644 --- a/README.md +++ b/README.md @@ -29,12 +29,25 @@ I have been a mac user for ~34 years. I gave up daily driving mac os in 2021. Af `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`. +- **Identify Track…** listens to a song (Chromaprint + AcoustID) and proposes + its real title, artist, album and *original* release year — and when the + internet has never heard of it, reads the answer out of the filename. +- **Import from URL…** (File menu) — paste a link and the song is downloaded + (yt-dlp), filed, and handed straight to Identify Track. +- Album art is searched on both iTunes and **Deezer**, can be pasted onto a + whole album's worth of tracks at once, and clicking the blank cover in the + sidebar goes looking for it. +- Right-click any song to **look it up on YouTube**. +- Every song you add is stamped with the day you added it. **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. +- Click a selected playlist's name to rename it. +- New libraries start with a **New Tracks** smart playlist (everything added in + the last 3 months). **Playing** - mp3, m4a, flac, aac, wav, aiff. @@ -43,18 +56,34 @@ I have been a mac user for ~34 years. I gave up daily driving mac os in 2021. Af - Live **spectrum visualizer** — click it to cycle bright / dim / off. - last.fm scrobbling - Theming: highlight color, UI scale, and custom colors +- A soft emboss on every button that follows your 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. +- **andTunes**, a small music player for the Rabbit R1 that LinTunes installs + and fills from the Connections menu — and the plays you rack up on the Rabbit + come back into your library. **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. +- Play counts can never conflict (each machine keeps its own tally), a song you + remove on one machine stays removed, and the merge report only speaks up when + something you'd care about happened. + +**Sharing with friends (Cassette)** +- Share parts of your library with a friend — one pasted code connects you, + over [Syncthing](https://syncthing.net), with no server anywhere. +- You choose exactly what each friend can see: the whole library, or just + certain artists, albums, songs and playlists. +- Browse a friend's library and press the little cassette buttons on anything + you'd like; those songs arrive in your library by themselves. +- Follow a friend's playlist and play it right from your own sidebar. @@ -248,3 +277,177 @@ python3 -m pytest tests/ ``` `spec.md` is the original design brief; `tasks*.md` track what's built. + +## Sharing music with friends (Cassette) + +Cassette lets you and a friend peek at each other's libraries and ask for +songs. There's no server and no account: your two computers talk directly +through a free program called **Syncthing**, and LinTunes just tells Syncthing +what to do. Neither of you can change or delete anything on the other's +computer. + +You'll both need LinTunes and Syncthing. You **don't** need to be online at the +same time — things simply finish the next time both computers are on. + +### 1. Install and start Syncthing (once) + +Open a terminal (see *Never used a terminal?* above) and paste the line for +your distro: + +```sh +sudo apt install syncthing # Debian / Ubuntu / Mint +sudo dnf install syncthing # Fedora +``` + +Then start it, and have it start by itself every time you log in: + +```sh +systemctl --user enable --now syncthing +``` + +To check it's running, open in your web browser — +you should see Syncthing's page. You don't have to do anything there; the +default settings (including "global discovery" and "relaying", which let two +computers find each other across the internet) are exactly right. + +> **Already using Syncthing to keep your library on two of your own +> computers?** Great — nothing changes. Only one of your computers handles +> friends; LinTunes asks which the first time (see below), and songs it brings +> in reach your other computers the usual way. + +### 2. Connect with a friend + +One of you **invites**, the other **pastes**. It doesn't matter who. + +**If you're inviting:** in LinTunes choose **Connections ▸ Share Library with a +Friend…**. The very first time, LinTunes asks *"Use this computer for sharing +with friends?"* — say **Yes**. You'll get an **invite code**: a long line +starting with `LTC1.` Press **Copy Code** and send it to your friend however you +like (text, email, chat). Each code works for **one** friend, once. + +**If you were sent a code:** choose **Connections ▸ Add Friend Library…**, +paste the whole code into the box, and press **Connect**. + +That's it. When the two computers have found each other, you'll see +**"*Name* is now connected."** at the bottom of the window. This can take a +minute — or, if the other computer is off, however long until it's back on. + +You can see how it's going any time in **Connections ▸ Sync Settings…**: pick +your friend in the list on the left. Invites nobody has used yet are listed on +the **General** page, with a **Cancel Invite** button each. + +### 3. Choose what your friend can see + +**Nothing is shared until you say so.** In **Connections ▸ Sync Settings…**, +click your friend's name on the left. Below their connection status are two +sections: + +- **Library** — tick the artists, albums or songs your friend may ask for, or + tick **Share whole library** for everything (including songs you add later). +- **Playlists** — tick the playlists to share, or **Share all playlists**. + A shared playlist brings its songs along: they show up ticked and greyed in + the Library section (hover one to see which playlist is holding it there). + +**Select All** and **Select None** do what they say — and if you click one by +accident, just press **Cancel**: nothing is saved until you press **OK**. + +Want everyone to see the same thing? On the **General** page, tick **Share the +same selection with all friends** and choose there instead. + +Sharing something doesn't send it. Your friend only receives what they ask +for. + +### 4. Browse a friend's library and ask for songs + +Once you have a friend, a small **▾** appears on the right end of the +**Library** button: + +The Library button with the ▾ friend selector on its right + +Click the **▾** and pick your friend. The button turns light purple and shows +their library's name — you're now looking at what they've shared with you: + +The Library button in friend mode, purple, reading Sam's Library + +![Browsing a friend's library](docs/cassette/friend-mode.png) + +It works just like your own library, except nothing plays (the songs aren't on +your computer yet). Instead, every artist, album and song has a little +**cassette button**: + +| Button | What it means | +|---|---| +| cassette button, not pressed | Not asked for. Click it to ask your friend for this. | +| cassette button, pressed | Asked for — this song is on its way to you. Click again to change your mind. | +| cassette button, partly pressed | Some of this artist's or album's songs are asked for. Click to ask for all of them. | + +Pressing the button on an **artist** or **album** asks for every song under it. + +Along the bottom of the window: + +- **Hide tracks I have** hides songs you already own. Songs that are *probably* + the same as one of yours (same artist and title, different album or length) + stay visible in light grey so you can decide. +- The **size** of what you've asked for, next to your free space. It turns + **orange** if it would leave so little space that Syncthing pauses, and + **red** if it won't fit at all. +- **Save and Close** sends your list to your friend and takes you back to your + own library. **Cancel** forgets the changes. (Leaving any other way with + changes asks *"Save changes?"* first.) + +The songs you asked for arrive in your library **by themselves**, filed by +artist and album like anything you'd add yourself, with *"3 songs arrived from +Sam."* at the bottom of the window. They come with their names, album info and +artwork — but not your friend's play counts or ratings. + +### 5. Follow a friend's playlist + +In a friend's library, their shared playlists are listed on the left, each +with a UFO. Click a playlist's **UFO** to follow it: + +| Icon | What it means | +|---|---| +| grey outline UFO | Not following. Click the UFO to follow this playlist. | +| purple UFO | Following. Click again to stop. | + +Press **Save and Close**, and the playlist appears in **your** sidebar with a +purple UFO, and plays like any other playlist: + +![A followed playlist in the sidebar](docs/cassette/followed-playlist.png) + +- Songs that are still on their way show in grey; they become playable as they + arrive. The bottom of the window says when your friend's folder last synced. +- A followed playlist's songs are **kept separate from your library** — you get + to listen without them filling up your collection. Like one? Right-click the + column headings, turn on **Cassette**, and press its cassette button to add + it to your library. +- Right-click a followed playlist in the sidebar and choose **Unfollow** to let + it go (its songs are cleaned up afterwards). + +Two choices per friend, in **Sync Settings** on their page: + +- Show followed playlists **mixed in with yours**, or grouped **in a folder + with their name**. +- **Keep their songs separate** (the default), or **add them to your library** + automatically. + +### If something isn't working + +Sync Settings always says what's going on in plain words and what to do next. +The common ones: + +- **"Syncthing isn't running"** — run `systemctl --user start syncthing`, then + press **Retry** on the General page. +- **"Can't reach Syncthing's API"** — press **Read from Syncthing** on the + General page. (Or copy the key from Syncthing's page at + : **Actions ▸ Settings ▸ General ▸ API Key**.) +- **"Waiting for *Name*'s computer"** for a long time — both computers need to + be on with Syncthing running, and your friend needs to have opened LinTunes + once since you pasted the code. If it never connects, the code may already + have been used: ask for a new one. +- **"That code isn't valid"** — part of the code got lost when it was copied. + It's one long line starting with `LTC1.`; ask your friend to send it again. +- **"This invite has already been used"** — codes work once. Ask for a new one. + +To stop sharing with someone, open their page in Sync Settings and press +**Remove Friend…**. Songs you already brought into your library stay. diff --git a/docs/cassette/cassette-off.png b/docs/cassette/cassette-off.png new file mode 100644 index 0000000..7e22c13 Binary files /dev/null and b/docs/cassette/cassette-off.png differ diff --git a/docs/cassette/cassette-on-hover.png b/docs/cassette/cassette-on-hover.png new file mode 100644 index 0000000..c3680cb Binary files /dev/null and b/docs/cassette/cassette-on-hover.png differ diff --git a/docs/cassette/cassette-on.png b/docs/cassette/cassette-on.png new file mode 100644 index 0000000..0116e90 Binary files /dev/null and b/docs/cassette/cassette-on.png differ diff --git a/docs/cassette/cassette-partial.png b/docs/cassette/cassette-partial.png new file mode 100644 index 0000000..dcf993f Binary files /dev/null and b/docs/cassette/cassette-partial.png differ diff --git a/docs/cassette/followed-playlist.png b/docs/cassette/followed-playlist.png new file mode 100644 index 0000000..9cc3e0c Binary files /dev/null and b/docs/cassette/followed-playlist.png differ diff --git a/docs/cassette/friend-library-button.png b/docs/cassette/friend-library-button.png new file mode 100644 index 0000000..7578cb1 Binary files /dev/null and b/docs/cassette/friend-library-button.png differ diff --git a/docs/cassette/friend-mode.png b/docs/cassette/friend-mode.png new file mode 100644 index 0000000..3c27a5d Binary files /dev/null and b/docs/cassette/friend-mode.png differ diff --git a/docs/cassette/library-selector.png b/docs/cassette/library-selector.png new file mode 100644 index 0000000..a9bafa3 Binary files /dev/null and b/docs/cassette/library-selector.png differ diff --git a/docs/cassette/ufo-followed.png b/docs/cassette/ufo-followed.png new file mode 100644 index 0000000..bdc0038 Binary files /dev/null and b/docs/cassette/ufo-followed.png differ diff --git a/docs/cassette/ufo-not-followed.png b/docs/cassette/ufo-not-followed.png new file mode 100644 index 0000000..955866e Binary files /dev/null and b/docs/cassette/ufo-not-followed.png differ