mirror of
https://github.com/narrrl/proton-stream.git
synced 2026-11-03 16:41:26 +01:00
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.
This commit is contained in:
1 parent
6cdab2fde1
commit
0b2813cd42
37 files changed
+4111
-159
No files matched your search
+11
-1
@@ -104,6 +104,13 @@ an edge case.
|
||||
holds only the id, display name and token.
|
||||
- Nothing this app holds can write to the share: a viewer link grants
|
||||
`MemberRole::Viewer`, and the SDK's public-link write side is unported anyway.
|
||||
- Signing in to a Proton account is optional (`pstr-core::account`). The
|
||||
session — tokens, the mailbox password that unlocks the key chain, and the
|
||||
key salts a refreshed token can no longer fetch — is one blob in the same
|
||||
credential store, under `proton-account`. Refresh tokens are single-use, so
|
||||
every refresh is written back. The account writes exactly one thing: the
|
||||
watch-history files on its own `proton-stream` device (`pstr-core::sync`).
|
||||
Folders of the account added as shares are only ever read.
|
||||
- Signature verification is absent on the visitor path by design — an anonymous
|
||||
visitor cannot read `core/v4/keys/all` to resolve a signer. Decryption still
|
||||
proves the bytes were encrypted to the node key. Nodes come back with nothing
|
||||
@@ -118,7 +125,10 @@ an edge case.
|
||||
| Share list | config dir, `shares.json` | **No** — atomic writes, never overwritten when unparseable |
|
||||
| Share secrets | OS credential store | **No** |
|
||||
| Catalog | data dir, `catalog.db` | Yes — recrawl |
|
||||
| Watch state | same DB, own table | **No** — deliberately survives a recrawl |
|
||||
| Watch state | same DB, own table | **No** — deliberately survives a recrawl; with an account, mirrored to its Drive |
|
||||
| Proton session | OS credential store, `proton-account` | No — sign in again |
|
||||
| Sync identity | config dir, `sync.json` | A new id if missing — the old history file is still read |
|
||||
| Watch history in Drive | device `proton-stream`, `watch-history/<id>.json` | One file per installation; merged per episode, newer wins |
|
||||
| Block cache | cache dir, `blocks/` | Yes — must work correctly after deletion |
|
||||
| Poster thumbnails | cache dir, `thumbs/` | Yes — refetched per file, one small decrypt each; stored scaled to 640 px |
|
||||
| Provider artwork | cache dir, `posters/` | Yes — refetched by URL; stored scaled to 640 px |
|
||||
|
||||
@@ -146,6 +146,32 @@ and [B44](#b44--r8-broke-the-app-under-instrumentation-in-five-places).
|
||||
|
||||
## Fixed
|
||||
|
||||
### B64 — Android offline downloads looked stuck
|
||||
|
||||
**Symptom.** A queued episode, and more so a queued season, sat at a progress
|
||||
bar that did not move for long stretches, then jumped.
|
||||
|
||||
**Cause.** Three, compounding. WorkManager starts every queued worker whose
|
||||
constraints are met, so "Download season" was a dozen transfers at once, each
|
||||
with a share of the link. Each read through the *playback* stream, so behind
|
||||
every block it read sat twelve blocks of read-ahead competing for the same
|
||||
bandwidth — and filling the shared memory ring and the disk block cache, a
|
||||
second copy of every byte. And progress was reported once per completed
|
||||
in-order block, so the first report waited on all of that. The desktop had none
|
||||
of these: three downloads at most, a copy stream with no read-ahead, four
|
||||
blocks in flight.
|
||||
|
||||
**Fix.** The Android engine allows two downloads to transfer at once; the rest
|
||||
wait for a slot, reported as queued (the worker no longer marks itself running
|
||||
before its first progress report, and its notification says "Waiting to
|
||||
download"). Downloads open through `StreamSource::open_for_copy` and read with
|
||||
`VideoStream::blocks_in_order` at `COPY_BLOCKS_IN_FLIGHT`, now shared with the
|
||||
desktop engine. The rows show a smoothed transfer rate beside the bytes, so a
|
||||
slow download reads as slow rather than stuck.
|
||||
|
||||
**Verified.** Workspace gate and the Android host check pass, with
|
||||
`TransferRateTest` covering the rate. Not yet observed on a device.
|
||||
|
||||
### B63 — a taskbar pin on Windows lost its icon
|
||||
|
||||
**Symptom.** Proton Stream pinned to the Windows taskbar showed its icon at
|
||||
|
||||
+4
-1
@@ -161,7 +161,10 @@ reads an external subtitle through the same protocol); the work is in
|
||||
## Design decisions already taken
|
||||
|
||||
- **Fat client, no server.** Each viewer's app talks to Proton directly.
|
||||
- **Public links only**, but several, merged into one catalog. No account login.
|
||||
- **Public links first**, several, merged into one catalog. A Proton account
|
||||
is optional: it adds folders of the viewer's own Drive as shares, and watch
|
||||
history synced through a `proton-stream` device in that Drive — one file per
|
||||
installation, so no two devices ever write the same file.
|
||||
- **Embedded libmpv**, not a bundled decoder stack. HEVC 10-bit, HDR and ASS
|
||||
subtitles with hardware decode, for free.
|
||||
- **No transcoding.** mpv demuxes and decodes natively; there is no remux or
|
||||
|
||||
Reference in new issue
Block a user