Truncate Provider, Bucket, and URL Style fields to prevent layout overflow.
Add `title` attribute for native tooltips on hover.
Add `tabindex="0"` for keyboard accessibility.
When saving an R2 storage connection, the "Prefix" input (which holds the Public Bucket URL) was not being mapped to `meta.baseDomain` or `meta.publicBaseUrl`. This caused `R2Service.ensureBucketConfigForNpub` to throw "Public Bucket URL is missing" during upload preparation, as it relies on these properties.
This commit updates `ProfileModalController.handleSaveStorage` to correctly assign the prefix value to `baseDomain` and `publicBaseUrl` for the `cloudflare_r2` provider, aligning it with the behavior for generic S3 providers and resolving the upload error.
- Refactored `UploadModal.js` to trigger uploads immediately on file selection.
- Added progress bars and result fields (Video URL, Magnet, Torrent) to the UI.
- Fixed a crash in `r2Service.js` caused by `userLogger.debug` usage.
- Exposed `prepareUpload` and `uploadFile` methods in `r2Service` and `s3UploadService` for granular control.
- Updated `upload-modal.html` with new UI elements.
Simplified the Upload Modal by removing inline storage configuration forms.
The modal now displays the active storage provider (read-only) or prompts the user
to configure storage via the Profile Modal if missing.
Changes:
- Refactored `js/ui/components/UploadModal.js` to consume stored credentials directly.
- Updated `components/upload-modal.html` to remove complex forms.
- Updated `tests/ui/uploadModal-integration.test.mjs` to match new UI structure.
- Removed race-prone logic for saving credentials within the upload flow.
This change ensures that cloud storage credentials are not leaked between Nostr profiles when switching accounts in the UI.
Changes:
- Imported `storageService` in `js/app.js` to enable the `bitvid:auth-changed` event listener to correctly lock the previous profile's storage session.
- Updated `ProfileModalController.populateStoragePane` to explicitly clear the storage form before loading new data.
- Enhanced `ProfileModalController.handleClearStorage` to fully reset the form state, including the provider selection and visibility toggles.
Verified with a reproduction script (`reproduce_storage_isolation.mjs`) that `StorageService` correctly isolates data by pubkey at the backend level. The UI fixes address the frontend persistence issue.
Prevents storage unlock failures and security risks when switching profiles by verifying that the active signer's public key matches the target profile. This ensures users are prompted to switch accounts in their NIP-07 extension if a mismatch occurs.
Fixes an issue where switching profiles caused the storage tab to break due to using the wrong decryption key.
This commit addresses an issue where thumbnail images would "drop" (disappear/flicker) upon login or re-initialization of the video list.
Changes:
- Modified `js/ui/views/VideoListView.js` to add a guard clause in `cleanupThumbnailCache`.
- The function now returns early if the provided `videos` list is empty, preserving the existing `loadedThumbnails` cache during transient loading states.
Verification:
- Created a reproduction script (`reproduce_issue.mjs`) that confirmed the cache was being cleared on empty input.
- Verified the fix with the same script, ensuring the cache is preserved.
- Verified no regression in `npm run lint:hex` and `npm run lint:inline-styles`.
Previously, `StorageService.saveConnection` allowed multiple connections to be marked as `defaultForUploads: true` because it did not unset the flag on existing connections. This caused `loadFromStorage` (which uses `find`) to potentially pick up an old, invalid connection instead of the newly configured one, leading to a loop where the user is asked to configure credentials again.
This change modifies `saveConnection` to iterate through existing connections and unset `defaultForUploads` if the new connection is being saved as the default. This ensures the "default" invariant is maintained.
Added a unit test case to verify this behavior.
Increases the default wait time for NIP-07 extension injection from 1.5s to 5s.
This resolves timeout errors for users on slower connections or devices where
the extension takes longer to inject `window.nostr`.
Verified with a reproduction script that simulates delayed injection.
Implemented `waitForNip07Extension` polling in `js/nostr/client.js` to address race conditions where `window.nostr` is not immediately available.
Updated `js/nostr/nip07Permissions.js` with the polling logic and added unit tests.
- Created `scripts/agent/validate-events.mjs` to validate all event builders.
- Fixed `buildViewEvent` to generate a fallback `d` tag for kind 30079 compliance.
- Relaxed `REPOST` schema validation to allow empty content (blind reposts), per NIP-18.
- Updated `docs/nostr-event-schemas.md` to reflect schema changes.
- Updated `js/s3-quick.js` to support new manifest structure: `{ bucket, key, uploadId, parts: [{partNumber, url}] }`.
- Added logic to sort parts, upload chunks, collect ETags, and call `completeUrl` if present.
- Updated `js/ui/components/UploadModal.js` to handle manifest flow, validate new structure, and alert user if completion is manual (missing `completeUrl`).
- Updated `components/upload-modal.html` with new placeholder example and documentation note.
- Verified logic with reproduction script and UI with Playwright.
When running the application locally (e.g., `127.0.0.1:5500`) but using a production configuration (`BITVID_WEBSITE_URL` pointing to `bitvid.network`), `playVideoByEventId` would attempt to `pushState` with the production URL. This triggers a browser `SecurityError` due to the origin mismatch, preventing the video modal from opening.
This change adds a check to normalize the `pushUrl`. If the target URL's origin differs from the current window's origin, it falls back to a relative path using `window.location.pathname` combined with the target's search parameters and hash. This ensures `pushState` always receives a safe, same-origin URL regardless of the environment configuration.
- Add `js/s3-quick.js` with `uploadWithManifest` and `uploadWithKeys`.
- Update `components/upload-modal.html` to add "Use presigned manifest" toggle and warning.
- Update `js/ui/components/UploadModal.js` to wire up the manifest upload flow.
- Add local persistence for quick S3 settings (though mainly handled by existing storage settings).
- Ensure keys are only used for client-side uploads or replaced by manifest flow.
Import `PROVIDERS` from `../services/storageService.js` in `js/ui/profileModalController.js`.
This fixes a `ReferenceError` when testing or saving generic S3 storage configurations.
The error was caused by using `PROVIDERS.GENERIC` without importing the constant.
Enforce full-width/height video display and dynamic object-fit logic to prevent letterboxing and layout gaps.
- Add robust CSS overrides to 'css/tailwind.source.css' to ensure video fills the stage.
- Update 'VideoModal.js' to dynamically switch between 'cover' and 'contain' based on aspect ratio match.
- Handle ambient canvas positioning to prevent layout shifts.
- Changed embed video sizing to `object-fit: cover` and `width: 100%` to eliminate black bars/letterboxing.
- Updated `embed.html` and `css/tailwind.source.css` to enforce these styles on `.video-modal__media`, `.video-modal__video`, and `#embedVideo`.
- Wired the embed logo accent color to use the instance configuration (`THEME_ACCENT_OVERRIDES` from `config/instance-config.js`) via a `--bitvid-accent` CSS variable injected in `js/embed.js`.
- Added unit and visual tests to verify styling and configuration logic.
- Remove black background from embed video to allow transparency
- Update "Watch on Bitvid" button to "Watch on" + white logo
- Fix share URL generation to point to main site instead of embed
- Ensure view counts and reactions are subscribed in embed mode
- Removed background colors from `embed.html` for transparency.
- Added a hover-triggered overlay with "Watch on BitVid" button and stats (views, likes, dislikes).
- Updated `js/ui/components/EmbedPlayerModal.js` to implement stats update methods and handle the overlay elements.
- Updated `js/embed.js` to set the share URL on the overlay after video resolution.
- Verified visual changes with Playwright.
This commit instruments the embed runtime to forward structured logs and lifecycle events
(Nostr, relay, pointer resolution, playback decision, WebTorrent) to the parent window
via `postMessage` when the `embed_debug=1` query parameter is present.
It also adds a defensive guard to `resetTorrentStats` in `js/app.js` to prevent TypeErrors.
Changes:
- Added `js/embedDiagnostics.js` module.
- Modified `js/embed.js` to initialize diagnostics and instrument startup.
- Modified `js/app.js` to instrument playback fallback and patch `resetTorrentStats`.
- Modified `js/webtorrent.js` to instrument peer probing and streaming.
- Add `js/ui/components/EmbedPlayerModal.js` to implement the `VideoModal` interface for embed contexts (including `resetStats`).
- Update `js/ui/ModalManager.js` to detect embed mode and use `EmbedPlayerModal`.
- Clean up `js/embed.js` to remove local modal definition and add `postMessage` diagnostic logging.
- Update `js/app.js` `resetTorrentStats` log message and verify guard.
- Add unit tests for `EmbedPlayerModal` and `resetTorrentStats` logic.
- Add E2E reproduction script `tests/e2e/repro_issue.spec.ts`.
- Fix `TypeError: this.videoModal.resetStats is not a function` by implementing `resetStats` (no-op) in `EmbedVideoModal` and adding a safety guard in `Application.resetTorrentStats`.
- Prevent duplicate `NostrClient` initialization within the same frame by adding idempotent guards in `js/embed.js` and `js/nostr/client.js`.
- Add documentation (`docs/embed-notes.md`) on embed architecture and recommendations for multi-frame resource sharing (SharedWorker).
- Add regression test `tests/embed_playback_check.spec.mjs`.
Refactored `EmbedVideoModal.js` to unwrap the fetched HTML content using a `DocumentFragment` before appending it to the DOM. This removes an unnecessary wrapper `div` that was causing stacking context issues, preventing the modal's buttons (Exit, Close, Copy) from being clickable when layered over other UI elements. This change aligns the implementation with `VideoModal.js`.
- Adds --z-modal-always-top: 200 token in css/tokens.css
- Adds .modal-always-on-top utility class in css/tailwind.source.css
- Applies class to EventDetailsModal, EmbedVideoModal, and ShareNostrModal