Commit Graph
25 Commits
Author SHA1 Message Date
nvrl 0b2813cd42 feat(core,stream,meta,app,android,cli): sign in to Proton and sync watch history
A Proton account is now optional alongside public links. Signing in (password,
then a second-factor code and a mailbox password where the account has them;
a CAPTCHA gate is solved in the Android app) stores one session blob in the OS
credential store under `proton-account`, writing back every refreshed token
since refresh tokens are single-use. With an account, folders of the viewer's
own Drive — My Files, other devices, shared with me — can be added as shares
through the same `ShareClient` surface as a public link.

Watch history syncs through a `proton-stream` device in that Drive: one
`watch-history/<installation>.json` per installation, so no two devices ever
write the same file. Each sync reads the others and merges per episode, newer
`updated_at` wins, with a deterministic tie-break. It runs at launch, after
sign-in, whenever the player closes and every five minutes. A session that can
no longer refresh signs the app out instead of failing on every launch.

The CLI gains `login`, `logout`, `account`, `browse` and `sync`.

Also in this change:
- Android offline downloads no longer look stuck (B64): two transfer at once,
  through a copy stream with no read-ahead, with a smoothed transfer rate.
- Choosing a metadata match by hand now enriches the title too, instead of
  keeping the old match's episodes and artwork.

The catalog schema is unchanged.
2026-10-06 13:06:54 +02:00
nvrl 6239780978 fix(app,packaging): keep libmpv and the taskbar icon across Windows upgrades
An MSI upgrade left the app without libmpv-2.dll until it was installed a
second time (B62). Costing runs before RemoveExistingProducts, saw the old
DLL at the same version and skipped the copy, and removing the old product
then deleted it. Both installer definitions now set REINSTALLMODE=amus;
every file is private to the install directory.

A taskbar pin lost its icon after a while (B63). The exe carried no icon
resource, and the Start Menu shortcut's icon lived in the per-ProductCode
installer cache that each upgrade deletes. build.rs now compiles the .ico
into proton-stream.exe, and the shortcut has no Icon of its own (and in the
WiX build is no longer advertised), so both show the exe's icon.
2026-10-06 03:04:07 +02:00
nvrl 99abc8f205 build(android): move to NDK r30 and mpv-android 687c7fd
Upstream mpv-android moved its build to NDK r30 (30.0.16248370), and each
mpv-android revision pins its own NDK, so the two move together. The new
revision also updates harfbuzz to 14.5.0, unibreak to 8.0, fribidi to
1.0.17, libxml2 to 2.15.4, fontconfig to 2.18.3 and curl to 8.22.0, and
builds libass with assembly on x86_64 (nasm, already installed in CI).

r30 brings an LLVM update with codegen and LTO fixes and sysroots up to
API 37. It is also the NDK current SDK managers install, so a fresh setup
no longer needs r29 installed beside it.

The script change invalidates the cached libmpv tree, so CI rebuilds it
once. The staged libraries are the same set as before, all 16 KiB aligned.
2026-10-04 02:42:53 +02:00
nvrl 3638e0e5df feat(core,app,android): sort, fold and shelve the Android library
Bring the phase 2 library to Android. Search, sorting and franchise folding
move from the desktop app into pstr_core::browse, so both clients find,
fold and order the same titles the same way.

The bridge gains AndroidEngine::arrangement, which returns the grid's tiles
and up to three shelves as keys into the library's titles. Each TitleRecord
now carries its display name, wide art, format, season, studios, directors,
tags, airing state and franchise. The library bar has a sort menu with the
franchise toggle, folded tiles show a +N badge, and shelves sit above the
grid. The title page shows the same facts, tags and franchise row as the
desktop. Settings -> Appearance gains Title names.

The default title name is now English, which is what Android always showed.
A folded franchise now sorts by its lead's displayed name rather than by its
alphabetically first member.
2026-10-04 02:04:15 +02:00
nvrl 6853725ca0 feat(core,meta,app,android,cli): sort, group and shelve the library
The AniList query now keeps the start date, season, banner, popularity,
status, next airing episode, tags, main studios, director and story
relations, as TitleDetails in one JSON column (schema v10). Matches
stored without them are fetched again by id, never searched, so
hand-picked matches stay; refreshing the same entry keeps its episodes
and fanart. Enrichment records the entries it walked. node_first_seen
remembers when each file appeared, across recrawls.

pstr_core::franchise groups titles that share a provider id. The grid
folds each franchise into its lead with a +N badge, and the title page
lists the whole franchise in release order. pstr_core::shelves picks
rows by airing status, director, studio and genre. A row needs three
franchises, so one franchise's titles never make a row on their own.

Desktop:
- Covers are the default grid (Settings > Appearance > Library tiles).
- The hero and title band use fanart or banner decoded at 1920 px.
- New sorts: recently added, newest, highest rated, most popular.
- Titles can show the share's, English or romaji name; search matches
  all of them.

Android carries TitleDetails through a hand-picked match; its screens
are unchanged.
2026-10-04 01:26:21 +02:00
nvrl 4c80076762 fix(core,meta,app,android,cli): number episodes the way releases do
AniList's per-season lookup searched for "<title> 2nd Season" and the
scorer picked the base entry again, so Attack on Titan seasons 2-4 and
Jigokuraku season 2 were captioned with season one's names. Episode
names came from streamingEpisodes, which is partial and numbered however
a streaming site counted. Bleach S17 and Mushishi S02/S03 had none.

AniList now walks SEQUEL relations from the match and takes each
entry's episodes from ani.zip, which carries TVDB's season, number and
absolute number. An episode row keeps all three plus its place in the
AniList entry. EpisodeGuide::get matches whichever numbering a file
uses and never answers from another season.

Episodes and fanart are stored as one enrichment. The episode list is
replaced even when empty, and the enrichment is recorded as asked, so a
film is not re-asked every run. Storing a different match drops the old
entry's episode rows. AniList's 4.75:1 bannerImage is no longer stored
as the 16:9 backdrop; ani.zip's 1920x1080 fanart is used instead.

Schema v9 adds the columns and deletes the AniList episode rows and
banners. Matches are kept. Desktop, Android and the CLI now share
service::plan and MetadataService::work. The settings text names
ani.zip. Audit and roadmap in docs/METADATA.md; bug entry B61.
2026-10-04 00:47:41 +02:00
nvrl 39a7f3cc38 docs: PLAN.md status and the screenshot list after the second Android pass 2026-10-03 13:34:28 +02:00
nvrl 1c61aadb22 feat(android): a history page
History sits second in the navigation, as on the desktop: every played
episode, newest first, under Today, Yesterday, a weekday or a date. The
still plays the episode, the text opens its title, and the cross takes
it off the page — forgetting its position and watched mark — with Undo.

The list is the desktop's Library::history rule over the records the
library already holds, so no bridge call is added; HistoryTest pins the
rule and the day headings.
2026-10-03 05:23:26 +02:00
nvrl c63f08ac91 test(android): screenshot tests for every screen
Roborazzi draws Library (phone, tablet, font scale 1.5, empty), a title,
Shares, Settings and Downloads from fixed records under Robolectric, and
build-android.sh check compares them with the committed images in
app/src/test/screenshots. The redesign changes every screen; a layout
regression now fails the gate and shows up in review as a changed image.
2026-10-03 04:34:46 +02:00
nvrl 2275df40a8 ci(android,release): publish the signed APK with each release 2026-10-03 02:45:13 +02:00
nvrl 4d44db0949 feat(app): desktop notifications on Windows
Toasts through WinRT, under the app id io.narl.proton-stream. The id is
registered for the current user under HKCU\Software\Classes\AppUserModelId
with a display name and icon on the first notification of a session, which
is what lets an app with no package or installer-made shortcut show one. If
that write fails, the toast goes out under PowerShell's id rather than not
at all.
2026-10-02 23:27:25 +02:00
nvrl 4a54af3245 feat(app): one window at a time, share link as an argument
A second launch hands its request to the open window and exits: over a
Unix socket in the user's runtime directory, or a named pipe on Windows
whose name carries a random key from the user's config directory, so
another account cannot take the name first. The open window comes forward,
and a share link given as the first such argument opens the Add form with
it filled in. Setup failures are logged and the app runs without the lock.
2026-10-02 23:24:28 +02:00
nvrl 85092fa893 refactor(app): spacing, radius and motion tokens
theme::space, theme::radius and theme::motion name the steps the UI is
drawn with. Literal gaps, corner radii and animation durations across ui/
now come from them, which folds a few near-misses onto the scale (10 and 14
point gaps onto 12, 10 point radii onto 12, 0.10 s hovers onto 0.12 s).
Page fades and toasts share one ease_out curve.
2026-10-02 23:10:39 +02:00
nvrl 558446b9e4 feat(app): bundled Inter and Phosphor icons, window icon
Headings are set in Inter SemiBold, everything else in Inter Regular, so a
title sets the same on every desktop. Media and navigation glyphs (⏭, 🔊, ⛶,
★) come from the Phosphor icon font instead of whichever fallback font had
them. The CJK fallback still loads on its own thread and now joins the
bundled fonts instead of replacing them. The window carries the app icon
on X11 and Windows.
2026-10-02 23:07:05 +02:00
nvrl 6518aef5ee docs: new config files, scaled art caches, media widget privacy 2026-10-02 20:16:27 +02:00
nvrl 4027ab5fb3 feat(app): polish pass - toasts, shortcuts, redesigned pages, cheaper frames
- toasts replace the status line; keyboard shortcuts with a ? overlay
- library: filters, sort, row virtualisation, cached search, skeleton
  tiles until the catalog loads, gradient placeholder art
- title page: season pills, episode rows with stills and one download
  glyph, portrait poster, clamped overview, resume time in the button
- player: fading chrome, smooth scrims, subtitles lifted over the
  controls, drag-following seek knob, OSD, speed menu, auto-skip
- settings as grouped cards with toggles and palette previews
- shares: confirm before removing, inline link validation, form kept
  until the add succeeds; downloads scroll and show rate and ETA
- downloads pipeline four blocks; the next episode is warmed near the end
- a film behind another page repaints at 4 Hz, not its frame rate

Fixes B55-B60.
2026-10-02 19:27:28 +02:00
nvrl d3c5f071fb feat(player,core): remember the audio/subtitle track by name across episodes
A track picked on one episode now carries over to the next by its title as
well as its language, so e.g. "Signs & Songs" vs "Full" subtitles in the same
language stick. Catalog migration V8 adds the title columns; the Android
bridge keeps a stored title only while its language is unchanged.
2026-09-15 13:54:07 +02:00
nvrl ad24557588 feature(gui) themes + chore(deps) version bump 2026-08-15 14:49:04 +02:00
nvrl dc85890a9f docs: android review ledger, design tokens, test notes
B14-B42 record the Android review the theme and lifecycle work came out of.
DESIGN-TOKENS.md states what both clients agree on and where each keeps its
copy.
2026-08-10 01:10:13 +02:00
nvrl 46bb68e3a5 improved android ui 2026-08-09 19:12:41 +02:00
nvrl f1b3ad9637 improved android client, feature parity with desktop 2026-08-09 16:40:37 +02:00
nvrl 6db6909824 added android client 2026-08-05 13:07:56 +02:00
nvrl 4c842402a6 fixed ci, release, docs 2026-08-03 09:38:01 +02:00
nvrl 14c48428a3 bug fixes, windows build 2026-08-03 09:09:40 +02:00
nvrl a1b345a029 init 2026-08-02 19:37:03 +02:00