task 50: one-button publish the local recording (creator ruling 2026-09-28)
This commit is contained in:
@@ -65,6 +65,7 @@
|
||||
| 47 | Alert box video: built-in/custom alert clip (+ six-animation fallback) with read-time fade in/out + ticker (now in the preview too, 3 display methods) + alert volume in the live mix | ✅ Done (2026-09-26) | [`TASKS/task-47-alert-videos.md`](TASKS/task-47-alert-videos.md) |
|
||||
| 48 | Distribution & packaging: **MSIX + Store IAP** | 🔶 In progress — **✅ route decided 2026-09-27 (Store MSIX + Store IAP)**; **item 1 (bundle ffmpeg) SHIPPED 2026-09-28** | [`TASKS/task-48-distribution-msix.md`](TASKS/task-48-distribution-msix.md) |
|
||||
| 49 | Chat profanity filter (local, opt-in, non-persistent, user word list) | ☐ Queued (2026-09-27) | [`TASKS/task-49-chat-profanity-filter.md`](TASKS/task-49-chat-profanity-filter.md) |
|
||||
| 50 | One-button "Publish this video" (resumable upload of the local recording) | ☐ Queued (2026-09-28) | [`TASKS/task-50-publish-recording.md`](TASKS/task-50-publish-recording.md) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
# TASK 50 — One-button "Publish this video" (resumable upload of the local recording)
|
||||
|
||||
> Catalog: [`TASKS.md`](../TASKS.md) — status and requirements live here.
|
||||
> Carved 2026-09-28 from a creator ruling: *"For me, as a creator, I'd love a one-button
|
||||
> publish this video feature. Who wouldn't?"*
|
||||
|
||||
**Status:** ☐ Queued — creator-ruled, not yet scoped in detail
|
||||
|
||||
**Goal:** turn the local REC-side MP4 into a channel video with one button, and stop relying on
|
||||
YouTube's silent automatic archiving to get a recording onto the channel at all.
|
||||
|
||||
**Size:** S–M. Media already exists; the work is a resumable-transfer lifecycle. **Not a quarter.**
|
||||
|
||||
---
|
||||
|
||||
## Why
|
||||
|
||||
Two reasons, and the second is the one that actually justifies it.
|
||||
|
||||
**1. It fixes a defect the creator already reported as broken.** On 2026-09-26 the creator could
|
||||
not get private test recordings saved to YouTube, and used the local recording as the proof of
|
||||
concept instead. The mechanism is now understood (§ Mechanism below): the archive *is* created,
|
||||
the app just offers no way to see or reach it. A deliberate upload is the actual fix; the current
|
||||
behaviour is a side-effect nobody designed.
|
||||
|
||||
**2. It is not the heavy feature it looks like.** The instinct is to call upload a big risky
|
||||
addition because it moves bytes. It doesn't: ffmpeg already moves the media, and the recording
|
||||
already exists as a finished local MP4. The genuine new work is a **discrete long-running job
|
||||
with a lifecycle** — resumable, with progress, retry, cancel and quota. RTMP has none of that
|
||||
because the connection belongs to the encoder process and simply reconnects. Different protocol,
|
||||
different failure model. That is the whole cost.
|
||||
|
||||
**Creator ruling, verbatim:** one button. Not a media manager, not a playlist tool.
|
||||
|
||||
---
|
||||
|
||||
## Mechanism — why recordings already reach YouTube, and why that's a problem
|
||||
|
||||
Verified 2026-09-28 against the code:
|
||||
|
||||
- `enableAutomaticArchiving` is **never set** by the app. YouTube's default for
|
||||
`liveBroadcasts.insert` is `true`, so **every** broadcast the app creates is archived as a VOD
|
||||
when it ends.
|
||||
- Broadcasts are inserted with `privacyStatus = "private"`
|
||||
(`Services/YouTubeStreamService.cs:49`), so those orphans are not public. That is correct and
|
||||
must stay.
|
||||
- The app has **no delete path** — nothing in `Services/` deletes a broadcast or a video. The
|
||||
creator clears each orphan by hand in Studio.
|
||||
|
||||
So "dev mode deletes the video immediately" is a **manual Studio step today**, not app behaviour.
|
||||
|
||||
### Sequencing constraint — do not flip the flag early
|
||||
|
||||
`enableAutomaticArchiving: false` is the correct end state: the app uploads the local file
|
||||
deliberately, on demand, instead of YouTube archiving silently. **But automatic archiving is
|
||||
currently the only route a recording takes to YouTube.** Setting it to `false` before publish
|
||||
ships would leave test streams with nothing on the channel at all and re-create the 2026-09-26
|
||||
complaint in a worse form.
|
||||
|
||||
**Therefore: ship the upload first, flip the flag as part of the same task, never before.**
|
||||
|
||||
---
|
||||
|
||||
## Design notes
|
||||
|
||||
- **Source is the local MP4**, not the YouTube archive. The app already has it (REC side,
|
||||
`EncoderOptions.RecordPath`); the archived VOD is a duplicate and an orphan.
|
||||
- **Resumable upload is mandatory, not optional.** Stream-length recordings are large (hours of
|
||||
4–8 Mbps video); a plain single POST is not viable. YouTube's `videos.insert` supports
|
||||
resumable sessions, and the failure mode that matters is a drop at 80%.
|
||||
- **Default visibility must be `private` or `unlisted`, never `public`.** A bad take going public
|
||||
is unrecoverable, and this app is used for test streams by definition. The creator picks, and
|
||||
the default is the safe one.
|
||||
- **A title still has to come from somewhere.** One button, not zero decisions: default to the
|
||||
recording's filename, allow an edit, do not block on it.
|
||||
- **Quota:** `videos.insert` costs 1600 units against a 10,000/day project allowance — roughly
|
||||
six uploads per day. Fine for a creator, but it is a real ceiling and the app should surface a
|
||||
quota error rather than retrying into it.
|
||||
- Scope already permits it: the single `auth/youtube` scope covers upload. No scope change needed.
|
||||
|
||||
---
|
||||
|
||||
## Open question to settle before coding
|
||||
|
||||
**Microsoft Store 11.12 (User-Generated Content).** The standing answer is that the app hosts no
|
||||
user content and does not interact with third-party UGC — chat is read-only and never persisted,
|
||||
which is load-bearing for that answer. A publish feature makes the app *push* creator content to
|
||||
a third-party platform, which touches the same area. It does not obviously break the answer (the
|
||||
destination is YouTube, which has its own mature moderation, and the app stores nothing), but it
|
||||
**must be re-checked against
|
||||
[`research-store-certification.md`](research-store-certification.md) §11.12 and the IARC answers
|
||||
in [`task-48`](task-48-distribution-msix.md) before submission** — do not let the IARC answers go
|
||||
to certification describing an app that cannot publish.
|
||||
|
||||
---
|
||||
|
||||
## Precedence
|
||||
|
||||
Belongs to **TASK 48** (MSIX/Store), but does **not** block the Store submission: the app is
|
||||
fully shippable without it. Recommend MSIX submission first, publish second — unless the creator
|
||||
reverses that, in which case it moves ahead of the remaining TASK 48 items.
|
||||
Reference in New Issue
Block a user