From f6e48b3bd66b1ac1377347e4e31c9dac8ba77cad Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 5 Feb 2026 03:00:29 +0000 Subject: [PATCH] docs: align upload guides with code and add consistency test - Updates `content/docs/guides/upload-content.md` and `getting-started.md` to accurately reflect supported file types, S3-compatible storage options, and metadata requirements. - Clarifies CORS configuration steps for R2 vs. generic S3. - Adds `tests/docs/verify-upload-claims.test.mjs` to programmatically ensure documentation claims match frontend code attributes. Co-authored-by: PR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> --- content/docs/getting-started.md | 35 +++++----- content/docs/guides/upload-content.md | 87 +++++++++++++----------- tests/docs/verify-upload-claims.test.mjs | 65 ++++++++++++++++++ 3 files changed, 131 insertions(+), 56 deletions(-) create mode 100644 tests/docs/verify-upload-claims.test.mjs diff --git a/content/docs/getting-started.md b/content/docs/getting-started.md index 9c08a284..0a34cff9 100644 --- a/content/docs/getting-started.md +++ b/content/docs/getting-started.md @@ -6,8 +6,8 @@ Ready to jump in? Here's everything you need to know to start watching and shari 2. **(Optional) Install as an App:** - **Desktop:** On Chrome-based browsers, click the "Install" icon in the address bar to run bitvid as a standalone app. - **Mobile:** Tap "Share" (iOS) or the menu (Android) and select "Add to Home Screen". -3. Browse the videos on the homepage -4. Click any video to start watching +3. Browse the videos on the homepage. +4. Click any video to start watching. That's it! No account needed to watch. ## Sharing Your Videos @@ -16,37 +16,36 @@ Ready to jump in? Here's everything you need to know to start watching and shari > ⚠️ **Note:** We are currently invite-only. [Submit an application](https://bitvid.network/?modal=application) to request approval for posting content. -1. Install a [Nostr extension](https://nostrapps.com/#signers#all) (like Alby or Nos2x) in your browser -2. The extension creates your secure login key automatically -3. Click "Login" on bitvid to connect +1. Install a [Nostr extension](https://nostrapps.com/#signers#all) (like Alby or Nos2x) in your browser. +2. The extension creates your secure login key automatically. +3. Click "Login" on bitvid to connect. ### Step 2: Prepare Your Video -1. Host your video at an HTTPS URL that browsers can stream directly. If you are uploading a file directly via bitvid, we accept **MP4, WebM, MOV, MKV, TS, M3U8, MPG, and MPEG** (Max 2GB recommended). For external hosting, ensure the format is streamable (MP4/WebM/HLS/DASH). You can use your own CDN, Cloudflare Stream, an R2 bucket, or any static site host—as long as the link begins with `https://`. -2. (Optional but recommended) Generate a WebTorrent magnet so viewers can fall back to peer-to-peer delivery. Desktop apps like [WebTorrent Desktop](https://webtorrent.io/desktop/) or command-line tools can create the magnet for you. -3. Double-check that either the hosted URL or the magnet (or both) is ready before you open the Upload modal. +1. **Format:** We accept **.mp4, .webm, .mov, .mkv, .ts, .m3u8, .mpg, .mpeg** (Max 2GB recommended). +2. **Hosting:** You can upload directly via bitvid (requires your own Cloudflare R2 or S3 bucket) or host your video elsewhere (CDN, Cloudflare Stream, etc.) and provide the HTTPS URL. For external hosting, ensure the format is streamable (MP4/WebM/HLS/DASH). +3. **(Optional) WebTorrent:** If hosting externally, you can generate a WebTorrent magnet so viewers can fall back to peer-to-peer delivery. ### Step 3: Share on bitvid 1. Click "Share a Video" on bitvid to open the upload modal. 2. Choose your upload mode: - - **Upload Video**: Select a file from your device to upload directly to your Cloudflare R2 bucket. If you haven't configured storage yet, click **"Configure Storage"** to enter your R2 credentials (Account ID, Access Key ID, Secret Access Key, Bucket Name, Public Access URL) in your Profile settings. + - **Upload Video**: Select a file from your device to upload directly to your Cloudflare R2 or S3-compatible bucket. If you haven't configured storage yet, click **"Configure Storage"** to enter your credentials (Account ID/Endpoint, Access Keys, Bucket Name, Public URL) in your Profile settings. - **External URL**: If you already host your video elsewhere, paste the HTTPS URL and (optionally) a WebTorrent magnet link. -3. Review the rest of the form: add a description and thumbnail, decide whether to allow comments, and set the NSFW or "For Kids" toggles to match your content. Explore the metadata section to fill in captions, duration, publish time, hashtags, participants, and other fields so first-time viewers have all the context they need. +3. Review the rest of the form: add a description and thumbnail, decide whether to allow comments, and set the NSFW or "For Kids" toggles to match your content. Explore the metadata section to fill in captions, duration, hashtags, and other fields. 4. Click "Publish Video" to post your content. ## Tips for Success -- Keep WebTorrent Desktop running while sharing videos -- Add eye-catching thumbnails to attract viewers -- Write clear descriptions to help people find your content -- After posting, open a card’s **More → Edit** action and use the [visibility toggle in the Edit Video modal](../components/edit-video-modal.html) to keep it private until you’re ready to share -- Encrypted watch-history sync lives in the [Watch History view](history.html), where you can clear devices or pause tracking whenever you need. +- **Thumbnails:** Add eye-catching thumbnails to attract viewers. +- **Descriptions:** Write clear descriptions to help people find your content. +- **Visibility:** After posting, you can use the **More → Edit** action to toggle visibility or delete content. +- **Watch History:** Encrypted watch-history sync lives in the [Watch History view](history.html), where you can clear devices or pause tracking whenever you need. ## Need Help? -- Visit our [GitHub](https://github.com/PR0M3TH3AN/bitvid) page for technical support -- Join our [community](https://primal.net/p/npub13yarr7j6vjqjjkahd63dmr27curypehx45ucue286ac7sft27y0srnpmpe) to connect with other users -- Report bugs to help us improve +- Visit our [GitHub](https://github.com/PR0M3TH3AN/bitvid) page for technical support. +- Join our [community](https://primal.net/p/npub13yarr7j6vjqjjkahd63dmr27curypehx45ucue286ac7sft27y0srnpmpe) to connect with other users. +- Report bugs to help us improve. Welcome to bitvid – let's start sharing! diff --git a/content/docs/guides/upload-content.md b/content/docs/guides/upload-content.md index 94af0bea..823417fe 100644 --- a/content/docs/guides/upload-content.md +++ b/content/docs/guides/upload-content.md @@ -1,11 +1,11 @@ # How to Upload Content -bitvid is a decentralized platform, but for larger video files, we currently support **Cloudflare R2** as a storage backend. This allows you to upload files directly from your browser to a high-performance, affordable storage bucket. +bitvid is a decentralized platform, but for larger video files, we support **Cloudflare R2** and **S3-compatible** storage backends. This allows you to upload files directly from your browser to a high-performance storage bucket. ## Prerequisites -- A **Cloudflare Account** (free to create). -- An activated **R2 Plan** (there is a generous free tier, but you may need to add a payment method). +- A **Cloudflare Account** (free to create) or an **S3-compatible provider**. +- An activated **R2 Plan** (if using Cloudflare). ## Supported Media & Limits @@ -20,29 +20,30 @@ Before you start, ensure your content meets the following requirements: - **Why?** Browser-based uploads rely on your device's memory for hashing and chunk management. Files larger than 2GB may cause browser instability or crashes. ### Metadata -- **Title:** Required. -- **Description, Thumbnail, Tags:** Optional but highly recommended for discoverability. +- **Title:** **Required**. +- **Description:** Optional. +- **Thumbnail:** Optional. +- **Tags (Hashtags):** Optional but highly recommended for discoverability. ## Step-by-Step Guide ### 1. Create a Bucket & Enable Public Access -1. Log in to your [Cloudflare Dashboard](https://dash.cloudflare.com/). -2. Navigate to **R2** in the sidebar. -3. Click **"Create Bucket"**. -4. Give it a name (e.g., `my-bitvid-videos`) and click **"Create Bucket"**. -5. Go to the **Settings** tab of your new bucket. -6. Scroll down to **"Public Access"** and click **"Enable"** under "R2.dev subdomain". -7. **Copy the Public Bucket URL** (it looks like `https://pub-xxxxxx.r2.dev`). You will need this later. +1. Log in to your provider's dashboard (e.g., Cloudflare). +2. Create a new bucket (e.g., `my-bitvid-videos`). +3. **Enable Public Access**: + - **Cloudflare R2**: Go to **Settings** > **Public Access** and enable "R2.dev subdomain" or connect a custom domain. + - **S3 Compatible**: Ensure the bucket policy allows public read access for objects. +4. **Copy the Public Bucket URL** (e.g., `https://pub-xxxxxx.r2.dev`). You will need this later. ### 2. Configure CORS -To allow your browser to upload files directly to Cloudflare, you must allow Cross-Origin Resource Sharing (CORS). +To allow your browser to upload files directly to the storage bucket, you must allow Cross-Origin Resource Sharing (CORS). -1. Still in your bucket's **Settings** tab, scroll down to **"CORS Policy"**. +**Cloudflare R2 (Manual Configuration Required):** +1. In your bucket's **Settings** tab, scroll down to **"CORS Policy"**. 2. Click **"Add CORS Policy"** (or Edit). -3. **Important:** Browser uploads use the **AWS JavaScript SDK v3**, which automatically adds headers like `amz-sdk-invocation-id`, `amz-sdk-request`, and `x-amz-user-agent`. You **must** allow these headers. The simplest and most robust setup is to set `AllowedHeaders: ["*"]`. -4. Paste the following JSON configuration and **explicitly list every allowed app origin** (the scheme, host, and port must match exactly): +3. Paste the following JSON configuration. You **must** allow headers used by the AWS SDK (`amz-sdk-*`). ```json [ @@ -55,35 +56,45 @@ To allow your browser to upload files directly to Cloudflare, you must allow Cro } ] ``` -> **Note:** Replace the `AllowedOrigins` values with the exact origins you use in development and production. Uploads go through the **S3 API endpoint** (`.r2.cloudflarestorage.com`), and browser-based uploads require `OPTIONS` for preflight requests. The `ExposeHeaders` list ensures the SDK can correctly track multipart upload progress. +> **Note:** Replace `AllowedOrigins` with your actual development or production origins. -5. Click **"Save"**. +**S3 Compatible Providers:** +bitvid will attempt to configure CORS automatically for generic S3 providers if your credentials have sufficient permissions. However, if uploads fail with CORS errors, apply a similar policy manually in your provider's console. -### 3. Create an API Token (S3 Credentials) +### 3. Create API Credentials -1. Go back to the **R2 Overview** page. -2. Click **"Manage R2 API Tokens"** (right sidebar). -3. Click **"Create API Token"**. -4. **Configure the token:** - - **Token name**: e.g., "bitvid-upload". - - **Permissions**: Select **"Object Read & Write"**. This is the minimal permission needed to upload and delete files. - - **Specific Bucket(s)**: Select the bucket you created in Step 1. - - **TTL**: "Forever". -5. Click **"Create API Token"**. -6. **Copy the credentials**: You will need the **Access Key ID** and **Secret Access Key**. +1. Create an API Token or Access Key pair. +2. **Permissions**: Ensure **"Object Read & Write"** access (or `s3:PutObject`, `s3:DeleteObject`). +3. **Copy the credentials**: You will need the **Access Key ID** and **Secret Access Key**. ### 4. Configure bitvid -1. Copy the **Access Key ID**, **Secret Access Key**, and your **Account ID** (found on the R2 Overview page). -2. In bitvid, open your **Profile** (click your avatar). -3. Navigate to the **Storage** tab (or click **"Configure R2 Storage"** in the Upload Modal to be redirected there). -4. Click **"Add Connection"** and select **Cloudflare R2**. -5. Enter your: - - **Account ID** +1. In bitvid, open your **Profile** (click your avatar). +2. Navigate to the **Storage** tab (or click **"Configure Storage"** in the Upload Modal). +3. Click **"Add Connection"** (or use the default form). +4. Select **Cloudflare R2** or **S3 Compatible**. +5. Enter your credentials: + - **Account ID** (R2 only) - **Access Key ID** - **Secret Access Key** - - **Bucket Name** (from Step 1) - - **Public Access URL** (from Step 1) + - **Bucket Name** + - **Public Access URL** (The URL from Step 1) + - **Endpoint** (S3 Compatible only) 6. Click **"Save Connection"**. -bitvid will verify your credentials by uploading a small test file. Once verified, return to the Upload Modal to start sharing! +bitvid will verify your credentials by attempting to list or upload a test file. Once verified, return to the Upload Modal to start sharing! + +## Upload Lifecycle & Moderation + +### How Uploads Work +1. **Direct Upload**: Your browser uploads the file directly to your storage bucket. No video data passes through a bitvid server. +2. **Client-Side Hashing**: Your browser calculates a cryptographic hash (info hash) of the file to enable WebTorrent support. +3. **Publication**: The video metadata (title, URL, hash, tags) is signed by your Nostr key and published to relays. + +### Moderation & Visibility +While publication is decentralized and permissionless, the bitvid.network instance may enforce moderation policies: +- **Whitelists**: If the instance is in "whitelist mode", you may need approval before your videos appear in public feeds. +- **Blacklists**: Violating community guidelines may result in your account being hidden from this instance. +- **User Blocks**: Viewers can mute or block your content individually. + +Check the [Community Guidelines](../community/community-guidelines.md) for more details. diff --git a/tests/docs/verify-upload-claims.test.mjs b/tests/docs/verify-upload-claims.test.mjs new file mode 100644 index 00000000..1a2f7dee --- /dev/null +++ b/tests/docs/verify-upload-claims.test.mjs @@ -0,0 +1,65 @@ +import { test, describe, it } from 'node:test'; +import assert from 'node:assert/strict'; +import fs from 'node:fs/promises'; + +const DOC_PATH = 'content/docs/guides/upload-content.md'; +const HTML_PATH = 'components/upload-modal.html'; + +describe('Documentation Accuracy Verification', () => { + let docContent; + let htmlContent; + + test('setup', async () => { + docContent = await fs.readFile(DOC_PATH, 'utf8'); + htmlContent = await fs.readFile(HTML_PATH, 'utf8'); + }); + + it('should list accepted video file extensions in docs matching the HTML accept attribute', () => { + // Extract extensions from HTML + // accept="video/*,.m3u8,.ts,.mp4,.webm,.mov,.mkv,.mpg,.mpeg" + const htmlMatch = htmlContent.match(/accept="([^"]*)"/); + assert.ok(htmlMatch, 'Upload modal should have an accept attribute'); + + const htmlAccepts = htmlMatch[1].split(',') + .map(s => s.trim()) + .filter(s => s.startsWith('.')) // Only care about extensions + .map(s => s.toLowerCase()); + + // Extract extensions from Docs + // - **Video:** `.mp4`, `.webm`, `.mov`, `.mkv`, `.ts`, `.m3u8`, `.mpg`, `.mpeg` + const docMatch = docContent.match(/- \*\*Video:\*\* (.*)/); + assert.ok(docMatch, 'Docs should list video types'); + + const docAccepts = docMatch[1].match(/\.(\w+)/g) + .map(s => s.toLowerCase()); + + // Check if every HTML extension is in Docs + for (const ext of htmlAccepts) { + assert.ok(docAccepts.includes(ext), `Extension ${ext} from HTML not found in Docs`); + } + + // Check if every Doc extension is in HTML (ignoring sort order) + for (const ext of docAccepts) { + assert.ok(htmlAccepts.includes(ext), `Extension ${ext} from Docs not found in HTML`); + } + }); + + it('should state Title is required in docs and be required in HTML', () => { + // Docs: - **Title:** **Required**. + assert.match(docContent, /- \*\*Title:\*\* \*\*Required\*\*/i, 'Docs should state Title is required'); + + // HTML: + // Simple check for id and required in close proximity or regex + const titleInputMatch = htmlContent.match(/]*id="input-title"[^>]*>/); + assert.ok(titleInputMatch, 'Title input not found in HTML'); + assert.match(titleInputMatch[0], /required/, 'Title input in HTML should have "required" attribute'); + }); + + it('should mention 2GB limit recommendation in docs and HTML', () => { + // Docs: Up to **2GB** per file + assert.match(docContent, /2GB/i, 'Docs should mention 2GB limit'); + + // HTML: (Max 2GB recommended) + assert.match(htmlContent, /2GB recommended/i, 'HTML should mention 2GB recommended limit'); + }); +});