v0.18.0: paste a link, get the song
File > Import from URL... runs trav's `song` helper (yt-dlp --extract-audio --audio-format mp3) from inside the app. Everything at the link downloads to a private temp dir and is imported as each song lands. "and add to current playlist?" puts the batch above the selected song, else at the end of the playing playlist, else at the end of the shown one, in the link's order. Each song goes straight into Identify Track. With no AcoustID key, the proposal comes from the filename alone. Album art now opens on a single click, in a window shaped like the cover and as big as the screen allows. Also fixed the dev fixture's play journal, which crashed startup (wrong shape) and would have been ignored anyway (wrong keys). The loader now skips a journal it can't read instead of aborting. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R5m9mXFPHNro78BdD69mG2
This commit is contained in:
@@ -1,5 +1,47 @@
|
||||
## Done
|
||||
|
||||
### Round 49 (2026-09-10) — Import from URL (v0.18.0)
|
||||
|
||||
trav's `song` shell helper is `yt-dlp --extract-audio --audio-format mp3`,
|
||||
followed by a drag into LinTunes. Now it's one menu item.
|
||||
|
||||
- [x] **File ▸ Import from URL…** sits under Add Files to Library. You paste a
|
||||
link (it's prefilled from the clipboard). Everything at the link
|
||||
downloads, whether one song or a playlist, with the `song` flags
|
||||
verbatim (`lintunes/url_import.py`). Output is read from `--print`
|
||||
markers, not scraped. Downloads go to a private temp dir, each song is
|
||||
imported the moment it lands, and the temp dir is removed at the end.
|
||||
Progress and cancel use the status-bar transfer widgets.
|
||||
- [x] **"and add to current playlist?"** puts the songs above the selected
|
||||
song in the shown playlist, else at the end of the playing one, else at
|
||||
the end of the shown one. With none of those the checkbox is grayed. A
|
||||
hint under the checkbox names the actual target, so the rule is never a
|
||||
surprise. A batch keeps the link's order, and smart and folder
|
||||
playlists are never targets.
|
||||
- [x] **Every imported song goes through Identify Track** with the usual
|
||||
checkbox dialog, song 1 while the rest still download (the Identify
|
||||
queue can now grow mid-run). With no AcoustID key the proposal comes
|
||||
from the filename alone, with no fpcalc and no network. yt-dlp's
|
||||
`Title [id].mp3` is exactly what the filename parser was built for.
|
||||
- [x] **Album art opens on a single click**, in a window shaped like the
|
||||
cover and as big as the screen allows (`art_window.fit_size`): square
|
||||
for a square cover, no black bars, and a small cover scales up.
|
||||
- [x] **Found while verifying: the dev fixture's play journal crashed
|
||||
startup.** `make_dev_library.py` got it wrong twice. First, it wrapped
|
||||
the journal as `{"machine", "tracks"}`, but `PlayJournal` reads a flat
|
||||
`{track id: totals}` map, and `int("tracks")` raised straight through
|
||||
a loader whose own comment says a bad journal must never abort
|
||||
startup. Second, even unwrapped, its entries used the `library.json`
|
||||
names (`play_count`/`play_date_utc`) instead of `record_play()`'s
|
||||
(`plays`/`last_played`), so the fixture's plays would have been
|
||||
silently ignored. The generator now writes the real shape and keys
|
||||
(checked: base + journal = the effective count on every journaled
|
||||
track), and the loader skips shapes it doesn't know.
|
||||
- [x] Verified end to end against a copy of the dev library, with real
|
||||
yt-dlp on a 19-second video. The song landed above the selected row in
|
||||
“Inside B”, the Identify dialog proposed a name from the filename, and
|
||||
the temp dir was gone afterwards.
|
||||
|
||||
### Round 48 (2026-09-10) — A library to break (v0.17.1)
|
||||
|
||||
Round 47 was verified by loading trav's real 21,531-track library. Nothing was
|
||||
|
||||
Reference in New Issue
Block a user