Skip to content

UI UX improvements#19

Merged
QuantumFF merged 12 commits into
mainfrom
ui-ux-improvements
Jun 7, 2026
Merged

UI UX improvements#19
QuantumFF merged 12 commits into
mainfrom
ui-ux-improvements

Conversation

@QuantumFF

Copy link
Copy Markdown
Owner

No description provided.

QuantumFF and others added 12 commits June 7, 2026 14:49
…#11)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mirror build_rip_command in the Search slice: pull the rip search
argv assembly out of search_music() into a side-effect-free
build_search_command(source, type, query, output_file, config_path).
Config-path inclusion now reuses the same exists-check semantics.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move rip search output parsing out of search_music() into a pure
parse_search_results(content, source, search_type). It owns the JSON
decode, the desc -> title/artist split, and the construct_url wiring,
and returns a ParsedSearch(results, error) the endpoint maps to its
response. The endpoint keeps the temp-file lifecycle and logging.

Returns ([], "empty") for blank output and ([], JSONDecodeError) for
malformed JSON without raising. Adds direct unit tests for well-formed,
by-split, missing-fields, empty, and malformed inputs. /api/search
response shape unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an injectable http_get seam (mirroring run_rip / read_audio_tags) and a
Source interface (url / album_art / metadata). Migrate Qobuz fully behind a
QobuzSource adapter: URL construction both directions, art, metadata, and
credential/app_id reading, collapsing the duplicate app_id regex into one
place. The album-art, metadata-extraction, and search paths dispatch to the
adapter for Qobuz; other sources keep their inline code until later slices.
Add unit tests exercising the adapter through a fake http_get with canned JSON
(no network), a route-level album-art test, and a Source glossary entry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a DeezerSource adapter mirroring QobuzSource (#15): URL construction both
directions, art, and metadata, all reaching the network only through the shared
http_get seam. Deezer's art is asymmetric — album/track art is a pure URL
template (no HTTP), while artist art is a real Deezer API call via http_get.
Move Deezer metadata fetch into the adapter (dropping the inline
fetch_deezer_metadata + its requests.get) and dispatch the album-art,
construct_url, and metadata-extraction paths to it for Deezer URLs. Add unit
tests covering artist-API vs album/track-template art and metadata through a
fake http_get, plus route-level album-art tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…and per-source branches (#17)

Add TidalSource (template url/art, art-only metadata), SoundCloudSource
(empty art, owns the id-mangling), and SpotifySource (no-op metadata, no
art) behind the existing Source interface. Introduce a SOURCES registry
plus resolve_source/GenericSource so URL construction, album-art, and
metadata extraction dispatch over adapters instead of per-source if/elif
chains; construct_url is removed. Qobuz/Deezer gain a domain attr for the
URL->source map. Unit tests cover each new adapter (incl. SoundCloud
id-mangling) and the registry dispatch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move active_downloads, download_history, and their two locks behind a
single DownloadStore class (ADR-0002 seam). All five former call sites —
register, worker, finalize, status, redownload — go through the store via
add_queued / mark_downloading / finalize / snapshot / find_history. Id
generation now allocates under the Active lock through next_id() instead
of reading len(active_downloads) unlocked. No persistence added; in-memory
stays the only adapter.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…oggle

Add a per-album DELETE control to the Files-tab tree, backed by a new
DELETE /api/library/album endpoint that confines the target to DOWNLOAD_DIR
(rejecting traversal and refusing DOWNLOAD_DIR itself), removes the folder,
and evicts its cached completeness assessment. This is the first write path
into the otherwise read-only Library (ADR-0003).

Add a COMPACT toggle to the search-controls bar that switches the results
list to a denser layout (tighter rows, no album art / ID / service chip).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ialog

Fix the INFO box jumping on tab switch: give every .tab-content pane a fixed
height (min(520px, 65vh)) with internal scroll, so ACTIVE/HISTORY/FILES/CONFIG
all occupy the same height. Let the in-pane library tree grow instead of
opening a nested scrollbar.

Add a REDUCE SIZE / EXPAND SIZE toggle below the search results that shrinks
the results scroll window.

Replace window.confirm in the album delete flow with a reusable confirmDialog()
modal (Promise-based; cancel via button, Escape, or backdrop) styled to match
the app, with a red danger confirm button.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Active/History state, the SSE subscriber list, and the download worker
threads all live in-process (ADR-0002). With --workers 2 each gunicorn
worker is a separate process with its own copy of all three, so the
browser's SSE stream and the request that starts a download can land on
different workers — the download runs but never appears in Active/History.
Drop to one gevent worker, which serves many concurrent SSE clients via
greenlets while download concurrency stays handled by MAX_CONCURRENT_DOWNLOADS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@QuantumFF QuantumFF merged commit 0c72924 into main Jun 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant