Commit graph

132 commits

Author SHA1 Message Date
363cf44ebe Merge pull request 'Fix CI: flaky mtime test on master + PR checkout always failing' (#29) from fix/static-store-test-mtime-precision into master
All checks were successful
Publier l'image Docker / test (push) Successful in 24s
Publier l'image Docker / publish (push) Successful in 13s
Reviewed-on: #29
2026-09-24 19:42:48 +02:00
56f969ba78 Fix CI source checkout on pull requests
All checks were successful
Publier l'image Docker / test (pull_request) Successful in 24s
Publier l'image Docker / publish (pull_request) Has been skipped
On a pull_request event github.ref_name is the PR number (e.g. "29"),
not a fetchable ref, so the test job failed at "Récupérer les sources"
on every PR ("couldn't find remote ref 29"). Fetch the PR's head branch
(github.head_ref) instead, falling back to ref_name for pushes/tags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 19:37:15 +02:00
b0d2100210 Fix flaky mtime assertion in the static party store test on Linux
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 3s
Publier l'image Docker / publish (pull_request) Has been skipped
The "only rewrites the party that changed" test compared a file's
mtimeMs against the exact millisecond passed to utimesSync. Linux
reports mtimeMs as a float that can land a hair off it (...780.999 for
...781), failing CI on master. Compare against the mtime the filesystem
reports right after setting it instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 19:36:21 +02:00
db3cf68843 Merge pull request 'Lounge parties: own tab, one file per party, watch/listen/lounge naming' (#28) from feat/static-parties-tab-and-per-file-storage into master
Some checks failed
Publier l'image Docker / test (push) Failing after 20s
Publier l'image Docker / publish (push) Has been skipped
2026-09-24 19:31:54 +02:00
58d51f5f74 Name the three party kinds: watch, listen and lounge party
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
- UI wording: "Watch party" = classic video, "Listen party" = classic
  audio, "Lounge party" = static party (tab, page, create buttons,
  toasts/confirms, server error messages); code names are unchanged
- home: "Parties en cours" with a Watch party / Listen party badge on
  each card
- music launch buttons say "Lancer une listen party"; a failed tile
  launch now restores its own label instead of always "watch party"

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 19:22:15 +02:00
1e437e4a91 Give static watch parties their own tab and one file per party
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
- new "Parties permanentes" tab (/static, sidebar + mobile sheet),
  highlighted on a party's own page too; the home page no longer lists
  static parties, and its live "Watch parties en cours" list leaves
  their sessions out
- StaticPartyStore now writes data/static-parties/<id>.json - one file
  per party, debounced per party, so a write only touches the party that
  changed and a corrupt file only costs that party (moved aside to
  .corrupt, the rest still load); leftover .tmp files are cleaned up;
  deleting a party removes its file and cancels any pending save
- the first release's single static-parties.json is migrated once on
  load, then kept as .migrated

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 19:16:55 +02:00
2de375ac62 Merge pull request 'Add static (persistent) watch parties' (#27) from feat/static-watch-party into master
All checks were successful
Publier l'image Docker / test (push) Successful in 24s
Publier l'image Docker / publish (push) Successful in 17s
2026-09-24 19:07:38 +02:00
5182def5c9 Add static (persistent) watch parties
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
A watch party built from a whole series or video playlist that remembers
the group's progress and each member's, so someone coming back or joining
late sees the items they missed and can catch up (solo, as a catch-up
watch party, or by marking items watched).

- StaticPartyService + StaticPartyStore: first on-disk state (JSON file
  under DATA_DIR, atomic debounced writes, flushed on SIGTERM)
- each session is an ordinary Party linked via party.staticLink; group
  position is saved by the 20s sweep and resumed on the next session
- PartyService.completeCurrentItem centralizes "item done" (Emby Played +
  static progress); new host-only "itemEnded" socket event covers the
  last queued item, which was never marked Played before
- missed = group-completed minus watched in-app minus Emby Played
- /static/:id view, create buttons on series/playlist pages, home section
- Docker volume for /data, spec/static-watch-party.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 18:54:47 +02:00
04a9116f68 Merge pull request 'Fix host stream freeze when a guest joins an in-progress party' (#26) from fix/guest-join-freezes-host-stream into master
All checks were successful
Publier l'image Docker / test (push) Successful in 24s
Publier l'image Docker / publish (push) Successful in 8s
2026-09-23 20:34:12 +02:00
7fbf22419d Fix host stream freeze when a guest joins an in-progress party
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
A joining member's player always called loadVideo(itemId, 0, false),
hardcoding a resume position of 0. Since a party's Emby stream is one
shared transcode session (PartyStreamService, keyed by partyId alone),
a newcomer's hls.js requesting segments from position 0 against a
session that already progressed well past that forces Emby to
seek/restart the shared transcode - stalling playback for every
member, host included, right as the newcomer joins.

Seed the initial resume position from the host's last-reported
position (already available in party.members) instead, so the first
segment request lands near where the shared session already is.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-23 18:53:57 +02:00
076cd7a624 Merge pull request 'Fix the music bar mobile now-playing screen not fitting landscape' (#25) from fix/music-bar-landscape-mobile into master
All checks were successful
Publier l'image Docker / test (push) Successful in 24s
Publier l'image Docker / publish (push) Successful in 7s
2026-09-18 15:54:02 +02:00
83592f1ee9 Fix the music bar mobile now-playing screen not fitting landscape
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
The album art was sized off min(220px, 60vw) - the viewport dimension
a phone in landscape has plenty of - and stayed pinned near that cap
regardless of how little vertical room was actually left once
everything stacked vertically (art, text, transport, side), running
well past a typical landscape height and needing to scroll to reach
the controls.

Added a dedicated media query for max-width 720px and orientation
landscape rather than chasing every fixed value in the portrait rules:
the art now sits beside the title/artist instead of above them
(flex-direction: row), freeing most of the vertical space the
portrait layout spends stacking them, and its size is capped by vh
instead of vw - the dimension landscape actually constrains. A few
margins shrink alongside it in the same block for the same reason.
Deliberately left the transport buttons fixed-size - a touch target
answers to a finger, not the screen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 11:43:36 +02:00
310dcd422e Merge pull request 'Fix a track started directly never falling back to its album's artwork' (#24) from fix/track-image-albumid-fallback into master
All checks were successful
Publier l'image Docker / test (push) Successful in 24s
Publier l'image Docker / publish (push) Successful in 17s
2026-09-18 11:36:34 +02:00
6bec09ae20 Merge remote-tracking branch 'origin/master' into fix/track-image-albumid-fallback
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
# Conflicts:
#	README.md
#	docs/architecture.md
2026-09-18 11:36:09 +02:00
b31377c1e9 Merge pull request 'Fix device takeover leaving both devices on the session with no working controls' (#23) from fix/device-takeover-stale-connection into master
All checks were successful
Publier l'image Docker / test (push) Successful in 25s
Publier l'image Docker / publish (push) Successful in 13s
2026-09-18 11:33:24 +02:00
5b2b832be7 Fix a track started directly never falling back to its albums artwork
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
imageUrlFors own Audio -> AlbumId fallback was silently never
triggering for a track played directly (not via its album/artist),
because the raw item that decision runs against - CatalogService
getRawItem - never requested AlbumId from Emby. Its default field set
for a single-item GET omits it entirely, so item.AlbumId read
undefined regardless of whether the tracks actual album had one -
falling through to the tracks own id every time, which essentially
never has a Primary image of its own. Every other path that resolves a
tracks image already asks for AlbumId correctly (getAlbumTracks/
getPlaylistItemsRaw), which is why launching a whole album/artist/
playlist was never affected. Fixed the one gap: getRawItem now
requests Fields=AlbumId too.

Flagged directly as probably not the whole images-are-hard-to-find
story - a real Emby library can also legitimately have no Primary
image at all for a given artist/album, which is not a bug this app can
fix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 10:26:33 +02:00
3ae1fce806 Fix device takeover leaving both devices on the session with no working controls
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
Two gaps around an already-correct takeover mechanism, not the
mechanism itself. First: Player.ts/MusicBar.ts both wired onClose to a
no-op, so the moment a takeover force-disconnected the old device its
video/hls.js instance (or the persistent music bar) just kept running
forever on a dead connection - both devices looked fully active, since
nothing ever told the old one to stop or navigate away. Second: the
obvious fix (call the same leave path Quitter uses) ran into a worse
bug - POST /leave removes a member by userId alone with no staleness
guard, so the old devices own leave call would have ended the NEW
devices membership too. Fixed both: onClose now tears down local
playback and leaves whenever this routes own explicit teardown has not
already run, and the leave route (plus the client, which now sends its
own deviceId) gained the same staleness guard the socket handlers
already had, via a new PartyService.isStaleDevice.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 10:23:22 +02:00
071184e3c6 Merge pull request 'Link video/music playback to the OS's own media controls (Windows SMTC, macOS Now Playing, ...)' (#22) from feature/media-session-integration into master
All checks were successful
Publier l'image Docker / test (push) Successful in 27s
Publier l'image Docker / publish (push) Successful in 8s
2026-09-17 23:43:32 +02:00
6582ad855b Link video/music playback to the OS own media controls (Windows SMTC, macOS Now Playing, ...)
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
New mediaSession.ts wraps the standard Media Session API - shared by
Player.ts and MusicBar.ts, which can never both be active at once so
there is no risk of them fighting over this one global. Metadata/
position/playback-state hook into each players own existing single
source of truth (updatePlayPauseBtn/updateProgressBar, setPlayIcon/
updatePositionDisplay) instead of adding parallel call sites. Play/
pause/seek are wired once and read isHost/conn fresh on every
OS-triggered call, so they keep working through a live host handoff;
a non-host play/pause routes through the same requestPause/
requestResume the request toolbar already uses, and seek is gated on
isHost the same way the in-page seek bar already is. Next is handled
separately since a registered nexttrack handler is what makes the OS
show that control at all - its presence tracks whatever the in-page
equivalent already tracks (isHost && hasNextQueued for video, a vote
skip for music). Cleared entirely on leaving a party/page, or just to
idle (metadata/state only) when a listen partys queue runs empty but
the party itself is still open.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 23:41:39 +02:00
9cb25f4dc0 Merge pull request 'Add a mobile banner nudging an install of the PWA' (#21) from feature/pwa-install-prompt into master
All checks were successful
Publier l'image Docker / test (push) Successful in 25s
Publier l'image Docker / publish (push) Successful in 7s
2026-09-17 21:22:35 +02:00
d79b49f34d Merge remote-tracking branch 'origin/master' into feature/pwa-install-prompt
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
# Conflicts:
#	README.md
#	docs/architecture.md
2026-09-17 21:22:16 +02:00
e9e288c93c Merge pull request 'Fix album track rows collapsing to 3 lines on mobile' (#20) from fix/album-track-row-mobile-width into master
All checks were successful
Publier l'image Docker / test (push) Successful in 26s
Publier l'image Docker / publish (push) Successful in 9s
2026-09-16 23:40:26 +02:00
7f0dbc28e3 Add a mobile banner nudging an install of the PWA
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
The PWA already existed but nothing told a mobile visitor it could be
installed - Chrome own default mini-infobar is easy to miss, and
Safari has no browser-driven prompt at all. New pwaInstall.ts (self-
mounting like toast.ts) captures beforeinstallprompt as early as
possible (a top-level side effect of importing the module from
Shell.ts, live before boot() even starts its async login check, since
that event never replays for a listener that attached too late) and
shows a banner with a real Installer button on Chrome/Edge/Android, or
manual Share-then-home-screen instructions on iOS Safari where no such
event exists at all. Mobile-only, suppressed once already running
standalone, and a close click remembers not to ask again.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 23:29:27 +02:00
c12e34e1e7 Fix album track rows collapsing to 3 lines on mobile
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
trackList.css forced .trackRow down to 2 columns under 600px and
pinned duration + the icon button both to column 2 - auto-placement
then stacked them into their own rows under the track name instead of
staying on one line. The fixed overhead (index/gaps/padding/an
auto-sized duration and button) comes to roughly 155-165px, and even a
320px-wide phone leaves comfortably more than that for the flexible
name column - .trackName already ellipsizes, so the breakpoint was
solving a problem that did not exist. Removed outright.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 23:18:12 +02:00
021f272a7d Merge pull request 'Fix the music bar progress bar not spanning full width on desktop' (#19) from fix/music-bar-progress-full-width into master
All checks were successful
Publier l'image Docker / test (push) Successful in 24s
Publier l'image Docker / publish (push) Successful in 8s
Reviewed-on: #19
2026-09-16 22:58:14 +02:00
5ceceb262d Fix the music bar progress bar not spanning full width on desktop
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
trackProgress is musicBarPanel own first child inside a 3-column grid
(track/transport/side), with no grid-column of its own - auto-placement
dropped it into column 1 of row 1 like any other item, squeezing it to
that columns width and wrapping musicBarPanelSide onto a second row
underneath instead of spanning the full bar with everything else in
one row below, as its own comment already said it should. Fixed with
grid-column: 1 / -1, which pushes every sibling after it into row 2
across the full width with no changes needed to any of them.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 22:55:51 +02:00
fa9d87b130 Merge pull request 'Fix library tile buttons rendering above the sticky header while scrolling' (#18) from fix/library-header-zindex into master
All checks were successful
Publier l'image Docker / test (push) Successful in 25s
Publier l'image Docker / publish (push) Successful in 8s
2026-09-16 22:41:28 +02:00
f923fa24e7 Merge remote-tracking branch 'origin/master' into fix/library-header-zindex
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
# Conflicts:
#	README.md
#	docs/architecture.md
2026-09-16 22:41:13 +02:00
658ad1d01d Merge pull request 'Fix the music bar queue popup: broken layout on desktop, unclosable on mobile' (#17) from fix/music-bar-queue-popup into master
All checks were successful
Publier l'image Docker / test (push) Successful in 26s
Publier l'image Docker / publish (push) Successful in 8s
2026-09-16 22:39:09 +02:00
d23fcc028b Fix library tile buttons rendering above the sticky header while scrolling
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
.libraryHeader and the alphabet index's .letterHeading copied their
z-index: 2 from tiles.css's own pre-existing sticky .searchBar - which
never showed the problem in practice, since a single slim input has
little room to actually overlap a scrolling tile. A tile's own
.tileOverlay action buttons are also z-index: 2 though, and an equal
z-index ties toward whichever renders later in the DOM - a tile, always
after the header. Wrapping the header into a much taller block gave a
scrolling tile far more room to pass underneath before fully clearing
it, which is what actually surfaced the tie. Raised both to z-index: 3,
matching shell/Shell.css's own mobileTopBar.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 22:37:11 +02:00
fc2c4e551f Fix the music bar queue popup: broken layout on desktop, unclosable on mobile
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
.musicBarQueue never actually had a position set on desktop despite its
own comment saying it should float above the bar - toggling it visible
just pushed the real controls out of the way instead, growing the
fixed bottom bar upward. Mobile had position: relative with a high
z-index to at least show above the full-screen now-playing panel, but
that left it sized/placed by normal flow, overlapping the very toggle
button used to open it with no other way to close it.

Now: musicBar gets position: relative, desktop musicBarQueue floats
via position: absolute; bottom: 100% without touching the bar's own
layout, and mobile gets a proper position: fixed; inset: 0 overlay.
Also added a dedicated close button plus a click-outside-closes
listener, so closing it never again depends on where the toggle button
happens to render underneath.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 22:32:32 +02:00
292fec9c19 Merge pull request 'Fix the alphabet index bucketing by display name instead of Emby SortName' (#16) from fix/alphabet-index-sort-order into master
All checks were successful
Publier l'image Docker / test (push) Successful in 25s
Publier l'image Docker / publish (push) Successful in 14s
Reviewed-on: #16
2026-09-16 21:44:44 +02:00
6b6a57a5f7 Fix the alphabet index bucketing by display name instead of Emby SortName
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
Emby orders (and this app already asked it to) by SortName, which
strips leading articles - an item like The Bunker sorts among the Bs
there, but the index was bucketing by the raw display name, throwing a
spurious T heading into the middle of that run. getLibraryItems/
getArtists now also fetch SortName, ItemDto carries it through, and the
index buckets by that instead - the same key Emby actually used to
order the array, not a guess that usually matches it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 21:36:37 +02:00
b34e1ce8ff Merge pull request 'Add an alphabet index to the library page' (#15) from feature/library-alphabet-index into master
All checks were successful
Publier l'image Docker / test (push) Successful in 24s
Publier l'image Docker / publish (push) Successful in 6s
2026-09-16 21:24:32 +02:00
3ba0de341e Merge pull request 'Make the library page header (title + search bar) fully sticky' (#14) from feature/library-sticky-header into master
Some checks failed
Publier l'image Docker / publish (push) Blocked by required conditions
Publier l'image Docker / test (push) Has been cancelled
2026-09-16 21:24:14 +02:00
0bd95b03b9 Add an alphabet index to the library page: sticky letter headings + a right-edge A-Z rail
Groups an already-alphabetical library into per-letter sections (accents
folded, so an item is bucketed under its base letter) with a sticky
heading before each - still one chunked-rendered grid, not a big
synchronous write, so a 1000+-item library stays smooth. The right-edge
rail jumps to a letter on tap or drag (pointer-capture, same shape as
the mobile nav sheet's own drag handle), dims letters with nothing in
them, and tracks the header/music-bar's real height instead of a
guessed offset so it never sits under either.

Stacked on feature/library-sticky-header (Library.css's .libraryHeader,
not yet merged) rather than master, per CLAUDE.md's sequential-PRs rule.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 20:31:03 +02:00
3fda483688 Make the library page header (title + search bar) fully sticky
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
The search bar was already sticky on its own; the title above it
still scrolled away. Wraps both in one sticky .libraryHeader block,
scoped to views/library only, and stacks it below the mobile shell's
own sticky top bar instead of racing it for the same spot.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 19:20:01 +02:00
0a9b3fb498 Merge pull request 'Replace every blocking alert() with a light toast, fix a mobile grid bug' (#12) from feature/toast-notifications into master
All checks were successful
Publier l'image Docker / test (push) Successful in 24s
Publier l'image Docker / publish (push) Successful in 7s
2026-09-16 18:33:01 +02:00
acb45c8a1a Merge remote-tracking branch 'origin/master' into feature/toast-notifications
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
# Conflicts:
#	README.md
#	docs/architecture.md
2026-09-16 18:32:22 +02:00
d10a35e541 Merge pull request 'Make the mobile nav sheet swipe-to-close instead of fighting pull-to-refresh' (#13) from fix/mobile-nav-swipe-close into master
All checks were successful
Publier l'image Docker / test (push) Successful in 24s
Publier l'image Docker / publish (push) Successful in 7s
Reviewed-on: #13
2026-09-16 18:29:19 +02:00
afae977b49 Make the mobile nav sheet swipe-to-close instead of fighting pull-to-refresh
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
Reported directly: the only way to close the bottom sheet was tapping
the scrim, and the instinctive swipe-it-down gesture fell straight
through to the browser's own pull-to-refresh instead - nothing was
telling the browser this app's own code owned that gesture.

touch-action: none on the scrim and the (now real, not just visual)
grabber handle stops the browser's default touch handling from
kicking in there at all; overscroll-behavior: contain on the sheet
itself stops a drag that hits its own scroll boundary (the library
grid can run taller than the sheet's 75vh cap) from chaining to the
page underneath. The grabber's small 36x4px pill now sits inside a
much bigger invisible touch target that actually drags the sheet
(pointerdown/move/up, 1:1 tracking, snap back under 90px or close past
it) - scoped to the grabber alone, not the whole sheet, so the
library grid's own taps/scroll keep working untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 17:58:56 +02:00
ff664f2c2b Replace every blocking alert() with a light toast, fix a mobile grid bug
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
Every message this app ever showed the client - the host-handoff
notice, every "couldn't start/join a party" error - went through a
blocking alert(), freezing the tab for what's usually just a heads-up.
New toast.ts is a self-mounting singleton (no per-party state, so it
doesn't need Shell.ts wiring like musicBar/MusicBar does) styled after
Player.css's own .requestBanner, with an 'error' variant that's still
just a plain left accent, not a red banner - even a failed click
doesn't need this app to suddenly shout. All ten alert() call sites
across Player/MusicBar/tiles/Home/Series/Playlist/Artist/Album now go
through it.

Also fixes a real reported bug while in the area: the library/artist
grid's minmax(160px, 1fr) floor left no room for a second column once
a real phone's padding was subtracted, unlike everything else mobile
in this app (the sidebar, the music bar) which already got a
narrow-screen treatment. Switched to a fluid clamp(100px, 28vw, 160px)
floor instead of a fixed breakpoint, confirmed at seven real widths via
an iframe (its own independent viewport for vw units, sidestepping
this sandbox's own unreliable viewport-resize emulation).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 17:34:10 +02:00
2772cc70d6 Merge pull request 'Rework the music UI: circles/squares instead of movie posters, a real now-playing screen' (#11) from feature/music-ui into master
All checks were successful
Publier l'image Docker / test (push) Successful in 24s
Publier l'image Docker / publish (push) Successful in 7s
2026-09-16 15:59:34 +02:00
617a3d0d49 Merge remote-tracking branch 'origin/master' into feature/music-ui
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
# Conflicts:
#	README.md
#	docs/architecture.md
2026-09-16 15:58:43 +02:00
e9b6a2541c Merge pull request 'Replace the mobile sidebar with a bottom sheet, grouped by data shape' (#10) from feature/mobile-nav into master
All checks were successful
Publier l'image Docker / test (push) Successful in 24s
Publier l'image Docker / publish (push) Successful in 7s
2026-09-16 15:55:57 +02:00
2f10a46664 Merge remote-tracking branch 'origin/master' into feature/mobile-nav
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
# Conflicts:
#	README.md
#	docs/architecture.md
2026-09-16 15:55:14 +02:00
b5a9a0bc7d Merge pull request 'Make the app installable as a PWA' (#9) from feature/pwa into master
All checks were successful
Publier l'image Docker / test (push) Successful in 24s
Publier l'image Docker / publish (push) Successful in 7s
2026-09-16 15:52:12 +02:00
c8655fc7c3 Merge remote-tracking branch 'origin/master' into feature/pwa
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 3s
Publier l'image Docker / publish (pull_request) Has been skipped
# Conflicts:
#	README.md
2026-09-16 15:51:34 +02:00
e65ba271fd Merge pull request 'Add picture-in-picture to the video player' (#8) from feature/picture-in-picture into master
All checks were successful
Publier l'image Docker / test (push) Successful in 23s
Publier l'image Docker / publish (push) Successful in 7s
2026-09-16 15:50:05 +02:00
098f447e57 Rework the music UI: circles/squares instead of movie posters, a real now-playing screen
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
The music library reused the movie-poster tile (2:3, hover-revealed
actions) for artists and albums too, since it was already there for
video - functional, but never reads as "this is music" the way real
apps do. Explored as mockups first, then implemented without touching
any of MusicBar's existing sync/cast/HLS logic:

- tiles.ts's tileHtml() now dispatches on Emby type: artists get a
  circle with no hover overlay, albums a square - same "whole tile is
  the one link" idea, since there's only ever one action either way.
- Artist/album pages gain a real hero header (circular/square art, a
  pill-shaped play button) instead of a plain title + text button.
  Album's per-track buttons shrink from a wide text button repeated on
  every row to a small icon that swaps play/plus with the same two
  states as before.
- MusicBar gains a real mobile "now playing" full-screen view (tap the
  collapsed mini bar to expand it) instead of only ever being a thin
  strip - the screen every music app has that this one was missing.
  The existing thin top-edge progress bar didn't change shape at all,
  on either breakpoint.

Nothing here invents a feature without a real data source behind it -
no popular tracks, no previous-track, no favorites, none of that
exists server-side.

Caught and fixed one real bug via computed-style verification, not
just reading the CSS back: the new circular play button was silently
losing to .iconBtn's own background/radius at equal specificity,
outcome depending on esbuild's bundle order rather than either rule's
own declared intent.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 15:44:14 +02:00