Completes end-to-end multi-webseed support: the editor can now see, add, and
remove every web seed a video carries.
- magnetShared: promote normalizeWebSeedList to a shared export (videoNotePayload
now imports it) and add setMagnetWebSeeds(), which replaces a magnet's COMPLETE
ws= set with exactly the requested list. ensureWebSeeds is append-only, so
without set-semantics a webseed a user deleted would linger in the magnet;
setMagnetWebSeeds strips the existing ws= params first, making removal stick.
- edit-video-modal.html: the single "Web seed (ws=)" input becomes a "Web seeds
(one per line)" textarea with backup-origin help text.
- EditModal: open() populates the field from extractAllWebSeeds() (every seed,
not just the first). On save, when the field was manually edited the magnet's
ws set is rebuilt from the field via setMagnetWebSeeds (true add/remove);
otherwise existing seeds are preserved untouched. The content `ws` field still
stores the primary (first) seed while the magnet carries the full set.
Mutation-verified (no-strip and no-add both fail the removal/add tests); build,
relevant lints (inline-styles, tokens, innerHTML), and full unit suite green.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Let uploaders declare a backup origin at creation time so the swarm can keep
streaming when the primary CDN is overloaded.
- upload-modal.html: the single "Web Seed (ws)" input becomes a "Web seeds
(one per line)" textarea with help text explaining the backup-origin use
case and the byte-identical-file requirement.
- UploadModal: in upload mode the R2/CDN url stays the primary webseed and any
textarea entries follow it (passed as [primaryUrl, textarea]); external mode
already flowed the field through. All parsing stays in the payload layer.
- videoNotePayload.normalizeWebSeedList now splits every entry (array OR
string) on newlines/commas, so the upload-modal's [url, "a\nb"] shape and a
plain multi-line string both expand + dedupe correctly.
Mutation-verified (array entries no longer split fails the upload-shape test);
build + full unit suite green. Lints relevant to the change (inline-styles,
tokens, innerHTML) pass.
Note: npm run lint also reports pre-existing file-size violations in unrelated
files (SignerManager, watchHistory, playbackService, webtorrent, etc.) that
grew in earlier commits — none are touched here. Flagging separately.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Foundation for declaring more than one web seed per video so the WebTorrent
swarm can pull pieces from an independent backup origin when the primary CDN
is overloaded — multiple `ws=` params are the standard BEP19 carrier and the
playback path already attaches every webseed it finds in the magnet.
- magnetShared: add extractAllWebSeeds(), which returns every `ws=` URL
(deduped, in order) instead of only the first like extractMagnetHints —
so a magnet with several webseeds can be round-tripped without dropping the
extras.
- videoNotePayload: normalizeWebSeedList() accepts the ws field as an array OR
a newline/comma-delimited string and feeds the full, deduped set into the
magnet (plus the hosted CDN url, as before). A single ws string still works
unchanged; the content `ws` field still reflects the primary seed.
Upload/Edit UI to author and manage the list lands in slices 2 and 3.
Mutation-verified (array-drop, split-drop, first-only, dedupe-loss all fail
the new tests); build + full unit suite green.
Co-Authored-By: Claude Opus 4.8 <[email protected]>