Merge pull request #67 from PR0M3TH3AN/codex/update-agents.md-and-readme.md-documentation

Update contributor docs for URL-first playback
This commit is contained in:
thePR0M3TH3AN authored and GitHub committed 2025-09-24 21:54:16 -04:00
commit d6a34571a9
3 files changed
+88 -240

No files matched your search

+41 -238
View File
@@ -1,263 +1,66 @@
# Bitvid — AI Agent Guide (AGENTS.md)
# Bitvid — AI Agent Guide
This document tells AI agents how Bitvid works **now** and how to extend it going forward. It focuses on the newly adopted **URL‑first playback with WebTorrent fallback** strategy, minimal code touchpoints, and reliable interop with the Nostr ecosystem.
As you work in the repo, please add detailed comments to help others understand what and why your code is doing.
This guide tells AI agents how to keep Bitvid aligned with the current product direction. Follow it whenever you touch code, content, or documentation inside this repository.
---
## 1) Mission & Product Direction
## 1. Mission: URL‑First Playback with WebTorrent Fallback
**Goal:** Stream videos reliably and cheaply.
* **Primary transport:** a **hosted video URL** (MP4/WebM/HLS/DASH) that plays directly in the browser.
* **Secondary transport (fallback & cost control):** a **WebTorrent magnet** enhanced with **`ws=` (web seed)** and **`xs=` (.torrent URL)**.
* **Behavior:** Try `url` first. If it’s missing or unreachable, **fallback to WebTorrent** using the same post’s magnet. If the magnet includes `ws`/`xs`, WebTorrent can bootstrap via HTTP and/or peers.
* **Nostr interop:** Keep existing kind `30078` events for Bitvid’s app data; optionally **mirror a NIP‑94 kind `1063`** event so other clients can discover the same hosted video URL.
* **Resilience:** Light link‑health probing to hide/flag dead URLs and avoid broken playback.
* **Goal:** Always deliver smooth playback while keeping hosting costs low.
* **Primary transport:** A hosted video URL (MP4/WebM/HLS/DASH) that the `<video>` element can stream directly.
* **Fallback transport:** A WebTorrent magnet that includes browser‑safe trackers plus optional HTTP hints.
* **Runtime behavior:** Call `playVideoWithFallback({ url, magnet })` (see `js/playbackUtils.js`). It probes the URL first; only when that fails should WebTorrent start.
* **Content contract:** Bitvid posts (Nostr kind `30078`) must include a `title` and at least one of `url` or `magnet`. Prefer to publish both along with optional `thumbnail`, `description`, and `mode` fields. When mirroring to NIP‑94 (`kind 1063`), copy the hosted URL and (optionally) the magnet so other clients can discover the same asset.
---
## 2) High‑Level Architecture
## 2. Magnet Handling — Do’s & Don’ts
* **Frontend app** (vanilla JS + HTML/CSS)
* **Upload modal** accepts: Title (required), **URL or Magnet** (at least one required), Thumbnail, Description. Optional fields for **`ws`** and **`xs`** help P2P bootstrap.
* **Feed / Cards** render video posts, each carrying both `data-play-url` and `data-play-magnet` attributes.
* **Player** uses `playVideoWithFallback({ url, magnet })`: probe `url`; if OK, play via `<video>`; else call `torrentClient.streamVideo(magnet, videoEl)`.
* **Nostr client**
* Publishes Bitvid’s **kind `30078`** events with content `{ version, title, url?, magnet?, thumbnail?, description?, mode }`.
* Subscribes to Bitvid video events and (optionally) **NIP‑94 `kind 1063`** to interop with external clients.
* **Optional Upload API** (future): If adding server‑side upload (NIP‑96/98), the client would POST to an uploader, receive an HTTPS URL, then publish events.
* **Use the helpers:** Always pass inbound values through `safeDecodeMagnet()` before playback, and use `normalizeAndAugmentMagnet()` (see `js/magnetUtils.js`) to append `ws=` or `xs=` hints.
* **Do keep magnets raw:** Store and reuse the literal `magnet:?xt=urn:btih:...` string. Decode once, then feed that exact value to WebTorrent.
* **Don’t call `new URL()` on magnets:** URL constructors/`URLSearchParams` percent‑encode the `xt` payload and can break legacy hashes. Manipulate magnets via the helper utilities or string concatenation.
* **Do encourage HTTP hints:** `ws=` (web seed) should point to an HTTPS file root; `xs=` points to a `.torrent`. They help the fallback path warm up quickly.
* **Don’t ship insecure trackers:** Stick to the WSS tracker list exported from `js/constants.js`. Avoid UDP or plaintext HTTP trackers in browser code.
---
## 3) Data Contracts
## 3. Upload Modal Troubleshooting
### 3.1 Bitvid app event (kind `30078`)
**Content JSON** (superset; some fields optional):
```json
{
"version": 2,
"title": "<string>",
"url": "https://cdn.example.com/video.mp4", // optional but recommended
"magnet": "magnet:?xt=urn:btih:...&tr=...", // optional but recommended
"thumbnail": "https://.../thumb.jpg", // optional
"description": "<string>", // optional
"mode": "live" | "dev" // optional
}
```
**Validation:**
* `title` **required**; **at least one** of `url` **or** `magnet` **required**.
* If `magnet` present and uploader supplied `ws` and/or `xs`, append them to the magnet before publish.
### 3.2 NIP‑94 mirror (kind `1063`, optional but encouraged)
**Tags (typical):**
* `["url", "https://cdn.example.com/video.mp4"]`
* `["m", "video/mp4"]` (or `video/webm`, `application/x-mpegURL`, etc.)
* `["thumb", "https://.../thumb.jpg"]` (optional)
* `["alt", "<title or description>"]` (optional)
* `["size", "<bytes>"]` (optional)
* `["x", "<sha256-of-file>"]` (optional integrity)
* `["magnet", "magnet:?xt=...&ws=...&xs=..."]` (optional for P2P aware clients)
> Agents SHOULD keep Bitvid’s 30078 as the source of truth, and publish a **lossless mirror** into 1063 when possible.
1. **Required fields:** Validation must ensure a title exists and that either a hosted URL or a magnet (or both) is supplied. Optional `ws` / `xs` inputs should be appended only when a magnet is present.
2. **Magnet parsing errors:** When a user pastes encoded magnets, run `safeDecodeMagnet()` before normalizing. Show inline errors if decoding fails.
3. **URL-first promise:** After submission, confirm the resulting feed item carries `data-play-url` and `data-play-magnet` attributes so playback utilities can attempt the URL first.
4. **Mixed-content warnings:** If the page is served over HTTPS, reject `ws=` or `xs=` hints that begin with `http://` and show guidance to upgrade to HTTPS.
5. **Telemetry hooks:** Keep existing analytics/logging untouched unless instructed. If you add new modal states, annotate them clearly in code comments.
---
## 4) UI & UX Flows
## 4. Manual QA Checklist
### 4.1 Upload Flow (author)
Run this script before shipping notable UI changes, especially around upload/playback flows. Automate when possible, but manual verification is required for releases.
1. Author opens **Upload modal**.
2. Inputs **Title**, plus **either** Hosted URL **or** Magnet (or both). Optionally adds **Web seed base (ws)** and **.torrent URL (xs)**.
3. Client **augments magnet** with `ws`/`xs` and publishes a kind `30078` event (and optionally a NIP‑94 `1063`).
1. **Smoke test the modal**
* Launch the site, open the Upload modal, and confirm required-field validation (title + one of URL/magnet).
* Submit with URL only, magnet only, and both; ensure success states are clear.
2. **URL-first playback**
* Publish a post with both URL and magnet. Load the card and verify the player fetches the hosted URL first (check network tab or logs).
* Temporarily block the URL (e.g., devtools throttling or offline). Confirm playback seamlessly falls back to the magnet.
3. **Magnet hygiene**
* Paste an encoded magnet; ensure `safeDecodeMagnet()` returns the raw value and the final string still includes the original `xt` hash.
* Confirm `normalizeAndAugmentMagnet()` appends `ws=`/`xs=` hints without corrupting parameters.
4. **P2P hints**
* Verify magnets authored through the modal include HTTPS `ws=` and optional `xs=` values when provided.
* Ensure tracker lists come from `js/constants.js` and remain WSS-only.
5. **Cross-browser sanity**
* Spot-check playback in Chromium and Firefox (desktop) to ensure no console errors related to CORS, Range requests, or tracker connections.
### 4.2 Consumption Flow (viewer)
1. Feed renders cards with `data-play-url` + `data-play-magnet`.
2. On click: `playVideoWithFallback()`
* `probeUrl(url)` → If reachable, set `<video>.src = url` and play.
* Else: `torrentClient.streamVideo(magnet, videoEl)`.
3. UI hides or badges items whose `probeUrl()` fails consistently (cached temporarily).
Document the run in PR descriptions so QA can cross-reference results.
---
## 5) Key Client Functions (reference)
## 5. Additional Notes for Agents
### 5.1 `normalizeAndAugmentMagnet(raw, { webSeed?, torrentUrl?, xs?, extraTrackers? })`
* Accepts a magnet URI or bare hex info hash and returns a **sanitized magnet**.
* Fixes accidentally encoded `xt=urn%3Abtih:` segments and tolerates bare hashes by
promoting them to `magnet:?xt=urn:btih:<hash>`.
* Appends only **browser-safe WSS trackers** plus optional extras, avoiding mixed
content.
* Adds HTTPS web seeds (`ws=`) and torrent hints (`xs=`) when provided, skipping
insecure `http://` web seeds unless the app itself is served via HTTP.
* Preserves existing parameters in their original form—no `new URL()` usage and no
percent re-encoding of the `xt` payload.
### 5.2 `probeUrl(url)`
* `HEAD` request to check availability; expects `2xx` and (ideally) `Accept-Ranges: bytes`.
* Fallback small `GET` with `Range: bytes=0-1023` can be used if certain hosts block `HEAD`.
* Returns boolean `ok`.
### 5.3 `playVideoWithFallback({ url, magnet })`
* Try `playHttp(url)` if `probeUrl(url)` passes.
* Else try `playViaWebTorrent(magnet)`.
* Show UI error if neither source available.
### 5.4 `playViaWebTorrent(magnet)`
* Uses existing `torrentClient.streamVideo(magnet, videoEl)` under the hood.
* Benefits if magnet contains `ws`/`xs` for bootstrap.
---
## 6) Markup Contracts
* **Cards:** add both attributes where applicable:
* `data-play-url="<encoded URL or empty>"`
* `data-play-magnet="<raw magnet or empty>"`
* **Click delegate:** look for a closest element bearing either attribute; decode
both `data-play-url` and `data-play-magnet` (if encoded upstream) **before** passing
them to playback logic. Never double-encode magnets when writing them into the DOM.
---
## 7) Main vs Unstable — legacy WebTorrent compatibility lessons
Legacy Bitvid posts (v1 / magnet-only) still play on **Main**. They broke on
**Unstable** because of double-encoded magnets, URL constructors, and strict
filters. Apply these rules to stay compatible:
* **Raw magnets end-to-end.** Store the literal `magnet:?xt=urn:btih:...` in the DOM
and feed that same string into WebTorrent. If you must encode for transport, be
sure to decode once when handling clicks.
* **No `new URL()` for magnets.** Appending params with `URLSearchParams` or `new URL`
percent-encodes the `xt` value and can corrupt legacy hashes. When you need to add
trackers or cache-busting params, concatenate plain text (or use
`normalizeAndAugmentMagnet`, which already preserves the payload).
* **Converters should allow magnet-only posts.** A note is playable when it exposes
either a usable `magnet` **or** a direct `url`. Don’t require `version >= 2` to keep
legacy uploads alive.
* **Browser-safe announce list.** Ship WSS trackers for browser playback. Skip UDP
trackers in the client path and only add `ws=` hints when they’re HTTPS on HTTPS
pages (mixed content gets blocked anyway).
---
## 8) Server Requirements for Hosted URLs
* **CORS:** allow the app origin (or `*`).
* **Range requests:** ensure `Accept-Ranges: bytes`.
* **Correct MIME:** `video/mp4`, `video/webm`, `application/x-mpegURL`, etc.
* **Optional:** expose `Content-Length` for better UX/progress.
---
## 9) P2P Notes for Agents
* **`ws=` (web seed):** HTTP(S) base path where the file is fetchable; enables WebTorrent to download pieces even with zero peers.
* **`xs=`:** HTTP(S) URL of the `.torrent` metadata so the client can start promptly without DHT/peer discovery.
* **Trackers:** Keep WSS trackers for peer discovery; they reduce CDN load when peers exist.
---
## 10) Interop & Extensions
* **Live streams:** future option via HLS URLs (MIME `application/x-mpegURL`). For Nostr live presence, consider **NIP‑53** events alongside VOD 1063 entries.
* **Adaptive Bitrate + P2P:** if ABR is needed with P2P, consider a segment‑sharing overlay (e.g., p2p segment loaders) rather than WebTorrent.
* **Uploads (optional):** NIP‑96/NIP‑98 flow to obtain a hosted URL, then publish Bitvid/NIP‑94 events.
---
## 11) Testing Checklist (agents)
* **Form validation:** title present; ensure `(url || magnet)` is true; `ws` and `xs` appended only for magnet.
* **Probe:** healthy URL returns `ok=true`; dead URL hides/badges card; cache prevents re‑probing every render.
* **Playback:** URL path plays successfully; disconnect network to force WebTorrent path; verify video plays via magnet.
* **CORS & Range:** verify no console CORS errors; confirm seeking works.
* **Events:** verify kind `30078` contains `url` and/or `magnet`; optional 1063 mirror created correctly.
* **Cards:** both `data-play-url` and `data-play-magnet` present; click handler calls fallback player.
---
## 12) Guardrails & Do/Don’t
**Do**
* Fail soft: when URL fails, fall back to magnet without blocking UI.
* Prefer standards: URL + NIP‑94 mirror when possible.
* Degrade gracefully when `ws`/`xs` missing; torrent should still work with peers.
**Don’t**
* Don’t require magnet if URL is provided (and vice versa).
* Don’t assume CORS/Range are configured—probe and message helpfully.
* Don’t block the main thread with large HEAD/GETs; keep probes lightweight with timeouts.
---
## 13) Quick Reference (snippets)
**Bitvid content object (30078)**
```js
const content = {
version: 2,
title,
url, // optional but preferred
magnet, // optional but preferred
thumbnail, // optional
description, // optional
mode // "live" | "dev"
};
```
**Magnet normalization & augmentation**
```js
import { normalizeAndAugmentMagnet } from "./js/magnetUtils.js";
const { magnet } = normalizeAndAugmentMagnet(inputMagnetOrInfoHash, {
webSeed: hostedUrl ? [hostedUrl] : [],
torrentUrl: xsHint,
extraTrackers: ["wss://tracker.openwebtorrent.com"],
});
// Feed `magnet` directly to playVideoWithFallback / WebTorrent.
```
**Playback with fallback**
```js
async function playVideoWithFallback({ url, magnet }) {
if (url && await probeUrl(url)) return playHttp(url);
if (magnet) return playViaWebTorrent(magnet);
throw new Error("No playable source");
}
```
---
## 14) Roadmap Hooks (where to extend)
* **Analytics:** Keep using your existing 30078 analytics/logging. Add fields for `play_source: "url"|"torrent"` to measure cost savings.
* **Integrity:** Optionally compute SHA‑256 of the hosted file (off‑thread) and publish as NIP‑94 `["x", hash]` tag.
* **Moderation:** Add a background task to periodically probe and mark dead links; publish a lightweight status event so other Bitvid clients learn from each other.
---
* **Nostr interoperability:** Keep kind `30078` events as the source of truth and optionally mirror to kind `1063` so external clients see the hosted URL.
* **Probing:** Lightweight `HEAD`/`GET` requests should back `probeUrl()` so dead URLs can be hidden or flagged without blocking the UI.
* **Extensibility:** Future work (live streams, NIP-96 uploads, analytics) should preserve the URL-first strategy and magnet safety rules above.
**End of AGENTS.md**
+26 -2
View File
@@ -27,10 +27,15 @@
2. **Login with Nostr**:
- Use a compatible Nostr browser extension or manually input your public key.
3. **Upload Videos**:
- Provide a title, magnet link, and optional thumbnail or description.
- Provide a title plus a hosted URL (recommended) and optionally a magnet link. Bitvid plays the URL first and falls back to WebTorrent.
- Toggle "Private" for encrypted listings.
4. **Stream Videos**:
- Play videos directly in the browser using WebTorrent technology.
- The player attempts the hosted URL first and uses WebTorrent as a fallback when a magnet is available.
#### P2P Hints
- Append `ws=` parameters to magnets to expose HTTPS web seeds that help the fallback warm up quickly.
- Append `xs=` parameters when you have an HTTPS `.torrent` URL so WebTorrent can bootstrap without waiting on peer discovery.
---
@@ -67,6 +72,10 @@ To run **bitvid** locally:
- **`config.js`**:
- Toggle `isDevMode` for development (`true`) or production (`false`).
- **`js/constants.js`**:
- Source for browser-safe tracker lists and feature flags that govern WebTorrent behavior.
- **Magnet helpers**:
- Use `safeDecodeMagnet()` and `normalizeAndAugmentMagnet()` from `js/magnetUtils.js` to preserve hashes and add `ws=` / `xs=` hints safely.
### Adding Features
@@ -101,6 +110,21 @@ To run **bitvid** locally:
- Follow the [MIT License](https://opensource.org/licenses/MIT).
- Use clear, concise commit messages.
- Respect the existing coding style and architecture.
- Run the manual QA script (see below) and note results in PR descriptions for changes that affect upload or playback.
---
## Testing
Use the manual QA checklist before releases or when altering upload/playback flows:
1. Open the Upload modal, confirm validation (title plus URL or magnet), and test submissions for URL-only, magnet-only, and combined entries.
2. Publish a post with both URL and magnet, verify the player streams the hosted URL, then simulate a URL failure and confirm WebTorrent playback.
3. Paste encoded magnets to ensure `safeDecodeMagnet()` returns the raw string and `normalizeAndAugmentMagnet()` adds `ws=` / `xs=` hints without corruption.
4. Confirm magnets include HTTPS `ws=` / optional `xs=` hints and use the WSS tracker list from `js/constants.js`.
5. Spot-check Chromium and Firefox for console warnings (CORS, Range requests, tracker connectivity).
See [`docs/qa.md`](docs/qa.md) for the copy/paste-friendly checklist we share with QA.
---
+21
View File
@@ -0,0 +1,21 @@
# Bitvid Manual QA Script
Run this checklist before publishing releases or merging changes that touch upload or playback flows. Copy/paste the steps into QA tickets when requesting validation.
1. **Upload Modal Smoke Test**
- Open the Upload modal, verify title is required, and ensure either a hosted URL or a magnet (or both) must be supplied.
- Submit three variants: URL-only, magnet-only, and both URL + magnet. Confirm success messaging or event publication in each case.
2. **URL-First Playback**
- For a post with both URL and magnet, play the video and confirm the hosted URL loads first (inspect network requests or logs).
- Simulate a dead URL (offline mode or request blocker) and confirm playback falls back to WebTorrent without breaking the UI.
3. **Magnet Safety**
- Paste an encoded magnet and confirm `safeDecodeMagnet()` outputs the raw string before playback.
- Ensure `normalizeAndAugmentMagnet()` adds provided `ws=` / `xs=` hints while keeping the original `xt` hash intact.
4. **P2P Hints & Trackers**
- Confirm magnets generated through the modal include HTTPS `ws=` seeds and optional HTTPS `xs=` torrent URLs when supplied.
- Check that tracker arrays originate from `js/constants.js` and only include WSS endpoints.
5. **Cross-Browser Verification**
- Spot-check Chromium and Firefox (desktop) for console warnings about CORS, Range requests, or tracker connectivity.
- Optionally validate on mobile Safari/Chrome if the change targets mobile UX.
Document findings (pass/fail notes plus relevant screenshots or logs) so they can be attached to release or PR notes.