mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-01 10:22:25 +00:00
update
This commit is contained in:
1 parent
7cf334de8b
commit
000127f88c
8 files changed
+92
-25
No files matched your search
@@ -10,12 +10,15 @@
|
||||
|
||||
## Features
|
||||
|
||||
- **Decentralized Sharing**: Video sharing without central servers.
|
||||
- **Cloudflare R2 Uploads**: Publish directly from the Upload modal's Cloudflare flow with progress tracking and credential helpers.
|
||||
- **Decentralized Sharing**: Publish and browse videos without a centralized server.
|
||||
- **Channel profile pages**: The [channel view](views/channel-profile.html) and `js/channelProfile.js` render banners, playlists, links, and follow stats so every creator has a branded landing page.
|
||||
- **Audience flags**: The [Upload](components/upload-modal.html) and [Edit Video](components/edit-video-modal.html) modals expose **NSFW** and **For Kids** toggles that map straight to note metadata for safer discovery.
|
||||
- **Richer metadata repeaters**: Configure variants, captions, segments, participants, references, and hashtags directly in the Upload modal so posts ship with structured context.
|
||||
- **Cloudflare R2 Uploads**: Publish through the modal’s Cloudflare flow with progress tracking and credential helpers.
|
||||
- **Encrypted Watch History**: Sync viewing activity privately through the NIP-04 encrypted pipeline with local fallbacks.
|
||||
- **Live View Counters**: Subscribe to view events and see totals update in real time on video cards and the video modal.
|
||||
- **Lightning Zaps**: Tip creators with Lightning payments via the Zap controls in the video modal.
|
||||
- **Private Video Listings**: Hide cards from shared grids by flipping the visibility switch in the [Edit Video modal](components/edit-video-modal.html) after publishing.
|
||||
- **Private Video Listings**: Hide cards from shared grids by flipping the visibility switch in the Edit Video modal after publishing.
|
||||
- **Nostr Integration**: Use Nostr keys for login and interaction.
|
||||
- **WebTorrent Streaming**: Stream videos directly through torrent technology.
|
||||
- **Developer-Friendly**: Open source and customizable for your needs.
|
||||
@@ -120,9 +123,10 @@ Tailwind utilities are generated from `css/tailwind.source.css` and themed via
|
||||
the shared tokens in `css/tokens.css`. Install dependencies once and lean on the
|
||||
package scripts to keep formatting, linting, and generated output consistent:
|
||||
|
||||
- **Token imports:** `css/tokens.css` feeds `css/style.css`, which in turn seeds
|
||||
`tailwind.config.cjs` so utilities inherit the same palette, spacing, and
|
||||
typography primitives across the stack.
|
||||
- **Token imports:** `css/tailwind.source.css` imports `css/tokens.css`, and
|
||||
Tailwind consumes that source file directly so utilities inherit the same
|
||||
palette, spacing, and typography primitives across the stack—no
|
||||
`css/style.css` intermediary.
|
||||
- **Core scripts:**
|
||||
|
||||
```bash
|
||||
@@ -140,7 +144,7 @@ package scripts to keep formatting, linting, and generated output consistent:
|
||||
```bash
|
||||
npm install # install Prettier, Stylelint, and Tailwind toolchain
|
||||
npm run format # format CSS/HTML/JS/MD with Prettier + tailwindcss plugin
|
||||
npm run lint # run CSS, hex color, and inline-style guards in one pass
|
||||
npm run lint # run CSS, hex color, inline-style, design-token, and Tailwind color/bracket guards in one pass
|
||||
npm run lint:css # enforce token usage and forbid raw hex colors
|
||||
npm run lint:inline-styles # fail CI if inline style attributes or element.style usage slip in
|
||||
npm run build:css # rebuild css/tailwind.generated.css from tailwind.source.css
|
||||
@@ -313,7 +317,7 @@ placeholder at “—” and development builds log a warning—so mixed deploym
|
||||
|
||||
### Contribution Guidelines
|
||||
|
||||
- Follow the [MIT License](https://opensource.org/licenses/MIT).
|
||||
- Follow the [GPL-3.0-or-later License](LICENSE).
|
||||
- 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.
|
||||
|
||||
+11
-4
@@ -7,13 +7,16 @@
|
||||
- **Zap controls** – Channel profiles manage zap visibility, login gating, retry flows, and receipt rendering via the Lightning controller on the page.
|
||||
- **Source visibility filtering** – Lists now hide cards whose hosted URLs are offline unless their WebTorrent fallback is healthy, reusing the shared guard in `js/utils/cardSourceVisibility.js`.
|
||||
- **Video modal comments** – The video modal now surfaces in-context comment threads so viewers can follow discussions without leaving the player.
|
||||
- **Channel profile views** – `views/channel-profile.html` and `js/channelProfile.js` render dedicated channel landing pages with banners, follow stats, playlists, and contact links.
|
||||
- **Audience targeting toggles** – The [Upload modal](components/upload-modal.html) and [Edit Video modal](components/edit-video-modal.html) ship **NSFW** and **For Kids** toggles that map to the note’s moderation flags.
|
||||
- **Hashtag metadata repeater** – Upload metadata repeaters now support hashtag sets so creators can publish discovery tags alongside variants, captions, and participants.
|
||||
- **Dev/Live publishing fix** – Publishing honors the selected mode, preventing Dev-mode uploads from leaking into Live feeds.
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
> ⚠️ **Note:** If you find a new bug thats not listed here. Please submit a [Bug Report](https://bitvid.network/?modal=bug).
|
||||
|
||||
- Speed up loading in subscriptions. Save to local cache?
|
||||
- Fix "Dev Mode" publishing "Live Mode" notes—add a flag for dev mode posts.
|
||||
- Fix slow back button issues on Firefox.
|
||||
- Add Amber login support for mobile.
|
||||
- Add support for "Playlist" lists and other custom lists (named whatever) and also a "Watch Later" list.
|
||||
@@ -21,6 +24,8 @@
|
||||
- Add "add to watch later" option to edit button.
|
||||
- Fix autoplay broken on iPhone chrome.
|
||||
- Fix playback broken on Safari on iPhone.
|
||||
- **[14]** Get Watch History working reliably so the view stays in sync across devices and sessions.
|
||||
- **[15]** Fix Watch History bugs for various login methods to keep timelines aligned regardless of how users authenticate.
|
||||
- Update note spec v3 transition to include new fields that have been added like "has previous" or "videoRootID" or enentID if null.
|
||||
- Change "explore" view to "kids" view and add flag to all notes to see if they are for kids.
|
||||
- Add "seed" lists.
|
||||
@@ -33,12 +38,11 @@
|
||||
|
||||
- Allow users to set custom relay settings, stored in local cache.
|
||||
- Add a "Publish" step in the video editing process.
|
||||
- Add Profile/Channel Views. [Click for more details](https://github.com/PR0M3TH3AN/bitvid/blob/main/content/roadmap/04_bitvid_Enhanced_Profile_Channel_Views_Specification.md)
|
||||
- Add a relay note search surface with filters for post date, hashtags, title keywords, view counts, and the publishing account.
|
||||
- Add a mobile search control with a floating icon that expands into a full search field on small screens.
|
||||
- Improve event spec for migration to new versions. [Click for more details](https://github.com/PR0M3TH3AN/bitvid/blob/main/content/roadmap/02_bitvid_Enhanced_Migration_of_Note_Spec_Logic.md)
|
||||
- Migrate event spec to v3 and add support for Audio/Podcast content. [Click for more details](https://github.com/PR0M3TH3AN/bitvid/blob/main/content/roadmap/03_bitvid_Enhanced_Nostr_Video_%26_Audio_Note_Specification_Version%203.md)
|
||||
- Add Block List, Subscription List, Playlist, and Reporting Specification. [Click for more details](https://github.com/PR0M3TH3AN/bitvid/blob/main/content/roadmap/05_bitvid_Enhanced_Block_Subscription_%26_Reporting_Specification.md)
|
||||
- Implement an "Adult Content" flag for note submissions.
|
||||
- Enable custom hashtags in the submission spec and form. (Use with future search system)
|
||||
- Allow multiple video resolutions with a selector in the video player. (v3 event spec needed)
|
||||
- Introduce a subscription mechanism with notifications.
|
||||
- Add zaps to videos, profiles, and comments.
|
||||
@@ -48,5 +52,8 @@
|
||||
- Add multi-language support for content and filtration. (v4?)
|
||||
- Create a settings menu for local account preferences, including relay, adult content, theme, and language.
|
||||
- Better integrate with other Nostr/torrent ecosystem. (NIP-35 + WebRTC Check Integration) [Click for more details](https://github.com/PR0M3TH3AN/bitvid/blob/main/content/roadmap/09_bitvid_Enhanced_NIP-35_%2B_WebRTC_Check_Integration.md)
|
||||
- **[16]** Add ability to write and send DMs so creators and viewers can coordinate privately.
|
||||
- **[17]** Add a "Live" live stream view (view only for now) that imports Zapstream notes and displays the live streams within the bitvid environment.
|
||||
- **[18]** Add ability to create and post livestreams to R2 storage so streamers can broadcast directly from bitvid.
|
||||
|
||||
> ⚠️ **Note:** Your feedback helps us improve bitvid! Whether it’s a suggestion, a concern, or general thoughts on the platform, we’d love to hear from you. Please tell us what you think [with this form](https://bitvid.network/?modal=feedback).
|
||||
@@ -326,6 +326,13 @@ Tailwind now exposes matching utilities for layouts that opt into the design sys
|
||||
|
||||
Iconography and motion helpers rely on fresh tokens as well: `--icon-size-sm`, `--icon-size-md`, and `--icon-size-lg` standardise glyph sizing across nav links, collapse toggles, and dropup triggers, while `--space-sidebar-nav-translate` powers the translate offsets used when collapsing the rail. Thin overlays inherit `--scrollbar-thin-width` so modal and sidebar scroll containers feel identical.
|
||||
|
||||
### Search surfaces backlog
|
||||
|
||||
Discovery work is queued behind two search affordances that will need close coordination with the navigation shell tokens:
|
||||
|
||||
- **Relay note search filters** — Stand up a dedicated search surface that can index relay-published notes and expose filter chips for posted date ranges, hashtags, title keywords, view-count ranges, and the publishing account. Reuse `.menu`, `.input`, and `.chip` primitives for the filter controls so the surface stays aligned with existing command panels, and plan on routing results through the popover/filter pipeline described above.
|
||||
- **Mobile floating search** — Introduce a floating search icon on small breakpoints that expands into a full-width search field when tapped. The trigger should inherit the circular icon tokens used by sidebar toggles, snap to the `z-overlay-nav` layer, and collapse back to the icon state once the user blurs or submits the field.
|
||||
|
||||
### Menus
|
||||
|
||||
`.menu` normalises list-based command menus with consistent padding. Pair it with `.menu__heading` for optional section labels, `.menu__separator` for dividers, and `.menu__item` for actionable rows. Each item supports hover, active (`data-state="active"`), and critical (`data-variant="critical"`) palettes plus disabled fallbacks through either `disabled` or `aria-disabled="true"`.
|
||||
|
||||
+5
-4
@@ -50,10 +50,11 @@ Notes:
|
||||
|
||||
`authType` describes how the profile authenticated:
|
||||
|
||||
- `"nip07"` – Browser extension flow (current default).
|
||||
- `"nsec"` – Reserved for future direct key import or signer integrations. New
|
||||
auth strategies should pick a distinct string and document how migration works
|
||||
alongside any recovery tooling.
|
||||
1. `"nip07"` – Browser extension flow that delegates signing to a NIP-07 compatible provider embedded in the browser.
|
||||
2. `"nsec"` – Direct key import where the private key stays in the client and bitvid signs locally without an external signer.
|
||||
3. `"nip46"` – Remote signer flow that relies on a NIP-46 capable relay or service to authorize requests on behalf of the user.
|
||||
|
||||
When introducing additional providers, choose a unique string value and extend this section (plus any related migration notes) to explain how the new strategy authenticates and how existing data should transition.
|
||||
|
||||
When the app reads stored entries it normalises unknown values back to
|
||||
`"nip07"` but keeps recognised alternatives intact.
|
||||
|
||||
@@ -16,6 +16,9 @@ function sanitizeVideoMetadata(video) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Transport identifiers (URL, magnet, hashes) are intentionally omitted so
|
||||
// watch history storage never persists playback endpoints. Only surface the
|
||||
// minimal fields needed to render the saved entry.
|
||||
const createdAtCandidates = [
|
||||
video.rootCreatedAt,
|
||||
video.created_at,
|
||||
@@ -37,11 +40,6 @@ function sanitizeVideoMetadata(video) {
|
||||
thumbnail: typeof video.thumbnail === "string" ? video.thumbnail : "",
|
||||
pubkey: typeof video.pubkey === "string" ? video.pubkey : "",
|
||||
created_at: createdAt,
|
||||
url: typeof video.url === "string" ? video.url : "",
|
||||
magnet: typeof video.magnet === "string" ? video.magnet : "",
|
||||
infoHash: typeof video.infoHash === "string" ? video.infoHash : "",
|
||||
legacyInfoHash:
|
||||
typeof video.legacyInfoHash === "string" ? video.legacyInfoHash : "",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -192,6 +190,8 @@ export default class WatchHistoryTelemetry {
|
||||
}
|
||||
|
||||
const metadata = {
|
||||
// Persist only sanitized metadata so local history never stores playback
|
||||
// transports or magnet fingerprints.
|
||||
video: sanitizeVideoMetadata(video),
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// js/ui/ambientBackground.js
|
||||
|
||||
import { devLogger as defaultLogger } from "../utils/logger.js";
|
||||
|
||||
const DEFAULT_THROTTLE_MS = 66;
|
||||
|
||||
function getGlobalFromCanvas(canvas) {
|
||||
@@ -100,14 +102,29 @@ export function attachAmbientBackground(videoElement, canvasElement, options = {
|
||||
return () => {};
|
||||
}
|
||||
|
||||
const ctx = canvasElement.getContext("2d", { alpha: false });
|
||||
const normalizedOptions =
|
||||
options && typeof options === "object" ? options : {};
|
||||
const logger = normalizedOptions.logger || defaultLogger;
|
||||
|
||||
let ctx = null;
|
||||
try {
|
||||
ctx = canvasElement.getContext("2d", { alpha: false });
|
||||
} catch (error) {
|
||||
if (logger && typeof logger.warn === "function") {
|
||||
logger.warn("[ambientBackground] Canvas context unavailable:", error);
|
||||
}
|
||||
return () => {};
|
||||
}
|
||||
if (!ctx) {
|
||||
if (logger && typeof logger.warn === "function") {
|
||||
logger.warn("[ambientBackground] Canvas context unavailable.");
|
||||
}
|
||||
return () => {};
|
||||
}
|
||||
|
||||
const { doc, win } = getGlobalFromCanvas(canvasElement);
|
||||
const throttleMs = Number.isFinite(options.throttleMs)
|
||||
? Math.max(0, options.throttleMs)
|
||||
const throttleMs = Number.isFinite(normalizedOptions.throttleMs)
|
||||
? Math.max(0, normalizedOptions.throttleMs)
|
||||
: DEFAULT_THROTTLE_MS;
|
||||
|
||||
const requestFrame = win?.requestAnimationFrame?.bind(win) || ((cb) => setTimeout(() => cb(Date.now()), throttleMs));
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
export function dedupeToNewestByRoot(videos) {
|
||||
const map = new Map();
|
||||
|
||||
const normalizeTimestamp = (value) => {
|
||||
const numeric = Number(value);
|
||||
return Number.isFinite(numeric) ? numeric : -Infinity;
|
||||
};
|
||||
|
||||
for (const vid of videos || []) {
|
||||
if (!vid) {
|
||||
continue;
|
||||
@@ -18,7 +23,10 @@ export function dedupeToNewestByRoot(videos) {
|
||||
}
|
||||
|
||||
const existing = map.get(rootId);
|
||||
if (!existing || vid.created_at > existing.created_at) {
|
||||
if (
|
||||
!existing ||
|
||||
normalizeTimestamp(vid.created_at) > normalizeTimestamp(existing.created_at)
|
||||
) {
|
||||
map.set(rootId, vid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import { dedupeToNewestByRoot } from "../../js/utils/videoDeduper.js";
|
||||
|
||||
test("dedupeToNewestByRoot replaces entries with missing timestamps", () => {
|
||||
const original = { id: "abc", created_at: undefined };
|
||||
const newer = { id: "abc", created_at: 123 };
|
||||
|
||||
const [result] = dedupeToNewestByRoot([original, newer]);
|
||||
|
||||
assert.equal(result, newer);
|
||||
});
|
||||
|
||||
test("dedupeToNewestByRoot replaces entries with non-numeric timestamps", () => {
|
||||
const rootId = "root-1";
|
||||
const invalid = { id: "old", videoRootId: rootId, created_at: "not-a-number" };
|
||||
const newer = { id: "new", videoRootId: rootId, created_at: "456" };
|
||||
|
||||
const [result] = dedupeToNewestByRoot([invalid, newer]);
|
||||
|
||||
assert.equal(result, newer);
|
||||
});
|
||||
Reference in new issue
Block a user