Commit Graph
81 Commits
Author SHA1 Message Date
thePR0M3TH3ANandClaude Opus 4.8 cf6a830183 [upload] Derive a webseed torrent for external-URL posts (P2P for external links)
Posting an external URL used to skip the torrent/webseed benefit entirely. Now the
upload modal's external tab auto-derives a WebTorrent webseed from the URL at
publish time: fetch the remote file (CORS-permitting), stream it under a hard size
cap, compute the infoHash, and publish a magnet with the URL as the webseed (ws=).
Best-effort — CORS failure / over the cap / any error silently degrades to
URL-only. Only runs when the user didn't paste their own magnet.

- js/utils/externalUrlTorrent.js: fetchBlobWithCap (streams with a 500 MB cap,
  aborts past it, short-circuits on content-length), buildWebseedMagnet, and
  deriveExternalUrlTorrent (reuses createTorrentMetadata). Pure + injectable → unit
  tested without network/WebTorrent.
- mediaUploader.deriveTorrentForExternalUrl: derives the ws= magnet and, when
  storage is unlocked, also hosts the tiny .torrent so the webseed can actually
  bootstrap P2P (xs=) — best-effort, falls back to ws=-only.
- UploadModal.handleExternalFlow calls it; deriveExternalWebseed only hosts the
  .torrent when storage is unlocked, shows progress on the submit button, and
  never throws.

Tests: tests/external-url-torrent.test.mjs (9 — magnet assembly, name parsing,
streamed size-cap enforcement + short-circuit, fetch-failed, derive-with-injected-
hash, failure propagation). Lint + build green.

Next: the same for editing a URL in the Edit modal.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-02 09:08:32 -04:00
thePR0M3TH3ANandClaude Opus 4.8 3df398d7ad [upload] Suggest one-tap hashtag chips from the user's past videos (#45)
The upload modal's Hashtags section now shows chips of the user's most-used past
hashtags ("Reuse a tag from your videos:"). Clicking one adds it to the NIP-71 't'
repeater; already-added chips dim + disable; the row is hidden for users with no
past tags.

- js/utils/hashtagSuggestions.js: pure rankHashtagsByFrequency(videos) — count =
  number of the user's videos using each tag, normalized (case + '#') and deduped
  per video, ranked by count then alphabetically. Reads video.nip71.hashtags, falls
  back to raw event 't' tags minus bitvid's fixed t=video marker.
- app.getUserHashtagSuggestions() sources the user's own videos via
  nostrService.getActiveVideosByAuthors([pubkey]) and ranks them (top 12), injected
  into the modal as getHashtagSuggestions.
- UploadModal renders the chips on open and wires clicks through the existing
  Nip71FormManager (addRepeaterEntry + setFieldValue, dedup via collectRepeaterValues).

Tests: tests/hashtag-suggestions.test.mjs (5 — per-video counting, normalization,
marker exclusion, tie-break + limit, empty input). Lint + build green.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-01 20:59:56 -04:00
thePR0M3TH3ANandClaude Opus 4.8 a1ed04b22c [dm] Fix NIP-17 send failing with nip17-keygen-failed (missing bytesToHex import)
Sending a NIP-17 DM builds a kind-1059 gift wrap, which needs a fresh ephemeral
keypair. generateEphemeralKeypair() hex-encodes the generated secret with
bytesToHex — but bytesToHex was never imported in client.js, so the call threw
ReferenceError. The try/catch swallowed it into privateKey="", keygen returned
null, and every NIP-17 send failed with "We couldn't create secure wrapper keys
for NIP-17 delivery." (nip17-keygen-failed). The seal (kind 13) signed fine
because it uses the active signer; only the ephemeral keygen was broken. Build
and lint don't parse JS, so the missing import wasn't caught.

- Add bytesToHex to the canonical js/utils/hex.js and import it in client.js.
- Add tests/nip17-send-gift-wrap.test.mjs: forces the NIP-17 path (useNip17 +
  relay hints, nip44-capable signer) and asserts a kind-1059 gift wrap is
  published. Reverting the import reproduces the exact nip17-keygen-failed error;
  the existing DM tests only covered the legacy kind-4/NIP-04 path (they delete
  nip44Encrypt), so this path had no coverage.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-01 09:29:43 -04:00
thePR0M3TH3ANandClaude Opus 4.8 2e510b2330 fix(liveness): don't bury WebTorrent-only content under hide-until-verified
A WebTorrent-only card's sole liveness signal is the swarm probe (20s timeout,
5min cache), and P2P liveness is slow + intermittent — a live-but-slow video is
indistinguishable from a dead one until that probe finishes. Hiding such a card
until the swarm verifies could bury perfectly good P2P content for minutes.

hide-until-verified now only suppresses a card while the FAST, reliable CDN probe
is still running. Once the CDN resolves dead (or is absent, i.e. P2P-only), it
falls back to show-pending for the WebTorrent part: shown while the swarm is
checked, hidden only once it too is confirmed dead. Burying live content is worse
than a brief flash of a dead one, and only the slow P2P probe is at issue.
cardNeedsEagerLivenessProbe likewise skips P2P-only cards (they start visible).

Tests: hide-foreign does-not-bury-WebTorrent-only coverage in
tests/video-card-source-visibility.test.mjs.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-25 09:48:55 -04:00
thePR0M3TH3ANandClaude Opus 4.8 129d877d38 fix(liveness): eager-probe hide-until-verified cards (fixes vanished foreign feed)
Setting CARD_LIVENESS_POLICY=hide-foreign made all foreign/NIP-71 content
disappear: a hide-until-verified card starts display:none, which has no layout
box, so the IntersectionObserver never fires for it — its liveness probe never
runs, it never gets a healthy verdict, and it stays hidden forever (deadlock).

Fix: cardNeedsEagerLivenessProbe() identifies cards governed by a
hide-until-verified policy (foreign under hide-foreign; all non-owner under
hide-all). Both health observers now kick the probe for those cards from
onCardRegister — which fires for every card regardless of visibility — instead of
waiting for an intersection that a hidden card can never produce. The URL probe is
deferred one microtask so attachUrlHealthBadges has wired state.onCheck after
observe(). Probes stay concurrency-capped + priority-ordered; show-pending is
unchanged (no eager probing).

Tests: cardNeedsEagerLivenessProbe predicate coverage in
tests/video-card-source-visibility.test.mjs.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-25 09:33:41 -04:00
thePR0M3TH3ANandClaude Opus 4.8 ccbe8d9bb2 feat(liveness): config-driven card visibility policy + probe prefetch (#5)
Makes the card liveness-visibility behavior switchable so it can be A/B
feel-tested, and probes ahead of the scroll for a snappier result.

- CARD_LIVENESS_POLICY (config/instance-config.js): "show-pending" (default,
  unchanged) | "hide-foreign" (foreign/ingested cards hidden until a source
  verifies; native cards stay show-pending) | "hide-all". Owner's own cards are
  always visible. Flip live for testing without a rebuild:
  window.__BITVID_CARD_LIVENESS_POLICY__ = "hide-foreign" then refresh/scroll.
  Implemented via a data-foreign provenance flag on the card +
  getCardLivenessPolicy() in cardSourceVisibility.js.
- LIVENESS_PROBE_PREFETCH_MARGIN (default 600px): both liveness probes were
  already viewport-gated (IntersectionObserver, on-screen-first, WebTorrent
  priority-queued + concurrency-capped); this expands their rootMargin so cards
  just below the fold verify before the user reaches them.
- Tests: three policy scenarios in tests/video-card-source-visibility.test.mjs;
  also un-broke 3 pre-existing VideoCard tests by adding the missing
  IntersectionObserver JSDOM stub.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-25 09:13:52 -04:00
thePR0M3TH3ANandClaude Opus 4.8 e4e5c552c7 feat(forms): validate submitter npub on submission forms (#22)
The embed submission forms accepted any free-text identifier and published it,
so they were an easy spam vector. Add a shared, testable NIP-19 validator and
require a well-formed npub before a submission is sent.

- js/utils/validateNpub.js: validateNpubHex() decodes via nostr-tools nip19 and
  returns the 64-char hex pubkey, or null for anything that isn't a real npub
  (free text, wrong prefix, bad checksum, wrong NIP-19 entity). Also exposed as
  window.validateNpubHex for the classic iframe form scripts.
- Application form (required npub): submit is blocked unless valid; the decoded
  hex is written into the application body for canonical storage/matching.
- Feature-request / bug-fix / feedback (optional npub): stays optional, but a
  non-empty value must be a valid npub or submit is blocked with an inline error.
- Tests: tests/validate-npub.test.mjs (real nostr-tools, no implementation mirror).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-25 08:31:45 -04:00
thePR0M3TH3ANandClaude Opus 4.8 065706a3cf videos: cross-ecosystem dedup (prefer bitvid, show one) across all grids
Phase 1 of the on-boarding plan, and the shared layer for unified grid
loading. A video that exists as both a bitvid kind-30078 note and a NIP-71
mirror/original previously could appear twice (e.g. independent dual-posts).

js/utils/videoDeduper.js: collapseCrossEcosystem() groups events by a
per-author identity (fileSha256 / originalFileSha256 / infoHash, plus an
`eid` namespace that links an on-boarded note's `importedFrom` to the
original foreign event) via union-find, and keeps the bitvid-native version
(else newest). dedupeVideos() = root-dedup THEN cross-ecosystem collapse.

Routed through the shared chokepoint app.dedupeVideosByRoot (playback
coordinator), so the feed stage, channel profile, and search all collapse
duplicates identically — "show one, prefer bitvid" everywhere. Channel
fallback path updated too.

Limitation (documented): hash-less independent dual-posts can't be matched
until the bitvid side carries on-board provenance (Phase 2).

Tests + mutation-verified (prefer-bitvid, per-author identity, infohash,
provenance link, root+cross composition). 1262/1263 unit (known flake).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 19:51:43 -04:00
thePR0M3TH3ANandClaude Opus 4.8 115521928c feat(video): capture & persist dimensions/duration at upload (enables shorts)
Auto-captures a video's width/height/duration at file-select and persists them on
the 30078 — the durable foundation for a future "shorts" vertical feed (filter on
height > width) and for the NIP-71 mirror's short-kind selection.

- js/utils/videoProbe.js: probeVideoMetadata(src) loads metadata into a hidden
  <video> (element injectable for tests); resolves {width,height,duration} or null.
- UploadModal: probes the selected file (objectURL) in the background and threads
  width/height/duration into the publish payload.
- videoPayloadBuilder: persists width/height/duration in content (publish) and
  preserves them across edits; normalizers exported.
- convertEventToVideo: exposes video.width/height/duration → the mirror builder
  already uses them (portrait ⇒ 34236 short + imeta dim).

tests: probe resolution (incl portrait + error/timeout → null); content persist +
parse; portrait⇒34236 / landscape⇒34235 mirror selection; edit preserves dims.
Mutation-verified earlier on the mirror short-selection.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 11:44:02 -04:00
thePR0M3TH3ANandClaude Opus 4.8 fdebf05e1a feat(s3): bring generic S3 to parity with R2 (cleanup + CORS guidance)
Two gaps where generic S3 trailed Cloudflare R2:

1. Object cleanup on delete/edit didn't work for generic S3. deleteVideoStorage
   built its client via makeR2Client, which hard-forces path-style and ignores
   the connection's forcePathStyle -- so vhost-style S3 deletes were misaddressed
   and cleanup silently failed (S3 users' deleted/edited files orphaned). It is
   now provider-aware (mirrors uploadFile): R2 -> makeR2Client (path-style),
   generic S3 -> makeS3Client honoring forcePathStyle. makeS3Client is now
   injectable for testing.

2. CORS guidance on upload failure was R2-only. Extracted isLikelyCorsError +
   a generic-S3 guidance builder into js/utils/uploadErrorHints.js (re-exported
   from r2Service for back-compat); s3UploadService now appends actionable CORS
   guidance on an opaque "Failed to fetch" too.

Generic S3 is now at functional parity with R2 for upload -> publish -> cleanup.

Tests: r2-delete-video-storage (adds generic-S3 forcePathStyle routing),
s3-upload-cors-guidance (new). Full suite green.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-17 06:13:38 -04:00
thePR0M3TH3ANandClaude Opus 4.8 95b51b6e61 feat(r2): delete the underlying storage objects when a video is deleted
Deleting a video removed the Nostr note but left the actual file (plus its
thumbnail and .torrent) publicly downloadable at its R2/S3 URL forever — a
privacy gap and ongoing storage cost. Now the delete flow also removes the
backing objects, best-effort.

- collectVideoStorageKeys() (storagePointer.js): pure helper that derives the
  object keys (video + sibling .torrent + thumbnail) from a note, ONLY for URLs
  under the owner's bucket base — external/3rd-party URLs are never returned.
- R2Service.deleteVideoStorage(): resolves the owner's connection, and deletes
  those keys. Skips cleanly when storage is locked / no creds / no owned
  objects, and never throws (failures are recorded, not propagated) so storage
  cleanup can't block note deletion. R2Service class now exported for testing.
- app.handleDeleteModalConfirm: calls it after handleFullDeleteVideo succeeds.

Tests: tests/storage-key-collection.test.mjs (4),
tests/services/r2-delete-video-storage.test.mjs (4). Full suite green.

Note: superseded versions orphaned by past edits aren't retroactively cleaned;
edit-time cleanup (next) prevents new orphans going forward.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-16 22:09:57 -04:00
thePR0M3TH3ANandClaude Opus 4.8 8f39b2c479 feat(signer): surface an actionable notice when the signer goes unresponsive
A raw window.nostr probe in the user's browser (getPublicKey → nip04.encrypt
→ nip04.decrypt, bypassing ALL of bitvid) HUNG forever, with the extension's
own console showing `ObjectMultiplex - orphaned data for "background-liveness"`
+ `malformed chunk` + listener-leak warnings. That is the NIP-07 extension's
content-script ↔ background-service-worker channel being dead (classic MV3
worker death) — an extension/environment failure, not a bitvid bug. No client
change can force an unresponsive signer to answer; the fix is to reload/unlock
the extension.

What bitvid CAN do is stop failing silently. Add js/utils/signerHealthNotice.js:
after a few consecutive list-decrypt timeouts while the signer reports itself
present, emit ONE rate-limited, actionable user notice ("your signer isn't
responding to decryption — unlock/reload the extension and refresh") instead of
the silent 15-minute retry loop. Reset on any decrypt success so a transient
blip doesn't warn. Wired into blocks, hashtags, and subscriptions.

Also documents the definitive root-cause + all resilience increments in
KNOWN_BUGS #0. Test: tests/signer-health-notice.test.mjs (threshold, rate-limit,
success-reset). Full unit suite green.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-16 14:18:46 -04:00
google-labs-jules[bot]andPR0M3TH3AN 0fcfc6009f Refactor qrcode.js to use DOM methods instead of innerHTML
- Replaces unsafe innerHTML usage with document.createElement and appendChild in the table drawing fallback.
- Adds a unit test `tests/qrcode_table_fallback.test.mjs` to verify the table generation logic using JSDOM.
- Addresses a potential security vulnerability where HTML injection could occur (though unlikely in this specific context, it is best practice).
- Updates package.json to include jsdom in devDependencies (if not already present).

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-02-26 17:42:28 +00:00
google-labs-jules[bot]andPR0M3TH3AN 004c0bed83 fix(ci): reduce channelProfile.js size and bound relay concurrency
- Refactored `js/channelProfile.js` to use `pMapSettled` from `js/utils/asyncUtils.js`, fixing both the concurrency issue (P1) and the file size lint failure.
- `pMapSettled` replaces a bulky inline `pMap` wrapper, reducing code volume.
- Ensures `js/channelProfile.js` stays within its grandfathered line count limit (5579 lines).

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-02-17 10:55:28 +00:00
google-labs-jules[bot]andPR0M3TH3AN f148653c39 Refactor AuthService login logic
Extracted complex logic from `AuthService.login` into private helper methods (`_validateAndNormalizeLoginInputs`, `_checkAccessControl`, `_updateGlobalState`, `_updateSavedProfiles`, `_initiatePostLogin`) to improve readability and maintainability.

Moved `SimpleEventEmitter` to `js/utils/simpleEventEmitter.js` and auth constants/normalization helpers to `js/services/authUtils.js` to reduce file size and coupling.

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-02-10 13:53:10 +00:00
google-labs-jules[bot]andPR0M3TH3AN e4e07ad7e8 fix(qrcode): calculate margins using real size instead of DOM offset
Replaces the dependency on `offsetWidth` and `offsetHeight` with a deterministic calculation based on module count and cell size. This prevents incorrect (huge) margins when the QR code is generated inside a hidden container where offset dimensions are 0.

Fixes: Margin values calculation in QRCode drawing logic.

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-02-10 04:27:16 +00:00
google-labs-jules[bot]andPR0M3TH3AN b246e431e5 Refactor publishVideo method in NostrClient
Co-authored-by: PR0M3TH3AN <[email protected]>
2026-02-09 01:54:07 +00:00
google-labs-jules[bot]andPR0M3TH3AN 6a74b3ddfc Refactor fetchListIncrementally into RelayBatchFetcher and genericize timeout logic
Extracted `fetchListIncrementally` from `js/nostr/client.js` into a new `RelayBatchFetcher` class in `js/nostr/relayBatchFetcher.js` to reduce complexity in `NostrClient`.
Moved `withRequestTimeout` to `js/utils/asyncUtils.js` to make it reusable and remove duplication.
Updated `js/nostr/client.js` to use these new components while preserving existing behavior and specific logging for COUNT diagnostics.

- Created `js/nostr/relayBatchFetcher.js`
- Updated `js/utils/asyncUtils.js`
- Refactored `js/nostr/client.js`
- Verified with existing tests

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-02-08 19:09:11 +00:00
thePR0M3TH3AN ec50db8645 Merge pull request #2243 from PR0M3TH3AN/refactor-application-monolith-3243348981324014635
Refactor Application class into Router and UI Coordinators
2026-02-08 10:57:44 -05:00
thePR0M3TH3AN 6f765cc647 Merge pull request #2240 from PR0M3TH3AN/refactor-revert-video-2176939372137755635
🧹 Refactor revertVideo to use helper function
2026-02-08 10:56:57 -05:00
google-labs-jules[bot]andPR0M3TH3AN 44e9f42ac0 Refactor Application class into smaller coordinators
Co-authored-by: PR0M3TH3AN <[email protected]>
2026-02-08 03:51:43 +00:00
google-labs-jules[bot]andPR0M3TH3AN e16eecb4e3 Refactor revertVideo to use helper function for payload construction
- Extracted payload construction logic from `revertVideo` in `js/nostr/client.js` to `buildRevertVideoPayload` in `js/nostr/publishHelpers.js`.
- Moved `resolveStoragePointerValue` from `js/nostr/client.js` to `js/utils/storagePointer.js` to fix circular dependencies and improve code organization.
- Updated imports in `js/nostr/client.js` and `js/nostr/publishHelpers.js`.
- Verified with existing tests.

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-02-08 03:44:15 +00:00
google-labs-jules[bot]andPR0M3TH3AN 5fb7299850 test: add unit tests for sanitizeProfileMediaUrl and fix bugs
- Add `tests/utils/profileMedia.test.mjs` with comprehensive test cases.
- Fix `sanitizeProfileMediaUrl` to correctly trim whitespace after removing quotes.
- Fix `sanitizeProfileMediaUrl` to correctly detect and normalize `ipfs/` paths (without protocol).

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-02-08 03:36:59 +00:00
google-labs-jules[bot]andPR0M3TH3AN aae2ea7d16 perf: use batch fetch for profile refresh
Replaces the sequential loop in `forceRefreshAllProfiles` with `batchFetchProfiles` to reduce network requests.
Updates `batchFetchProfilesFromRelays` to support `forceRefresh`, ensuring fresh data is requested while maintaining optimistic UI updates.
Adds unit tests for `forceRefresh` behavior.

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-02-07 23:15:13 +00:00
google-labs-jules[bot]andPR0M3TH3AN a084bb59de refactor: deduplicate HEX64_REGEX to js/utils/hex.js
Moves the repeatedly defined HEX64_REGEX constant to a shared utility
module to improve maintainability and consistency. Updates all consumers
to import from the new location.

Signed-off-by: Jules <[email protected]>

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-02-07 21:52:51 +00:00
google-labs-jules[bot]andPR0M3TH3AN ab441ce0c4 ⚡ Optimize watch history publishing with parallel execution
- Implemented `pMap` utility for concurrent async mapping with a limit.
- Refactored `publishRecords` in `js/nostr/watchHistory.js` to use `pMap` instead of serial `for...of` loop.
- Added `tests/benchmark_watch_history_publish.mjs` to verify performance.

Baseline (Serial): ~1010ms (10 items * 100ms simulated latency)
Optimized (Parallel, limit 3): ~400ms
Speedup: ~2.5x faster.

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-02-05 19:38:13 +00:00
google-labs-jules[bot]andPR0M3TH3AN fac5e00297 feat(perf): offload explore data computation to web worker
- Moved heavy tag counting and IDF calculation to `js/workers/exploreData.worker.js`.
- Extracted `collectVideoTags` to `js/utils/videoTags.js` (preserved original behavior).
- Extracted pointer normalization logic to `js/utils/pointerNormalization.js`.
- Refactored `js/services/exploreDataService.js` to use the worker.
- Added benchmark test `tests/benchmark-explore-data.spec.mjs`.

Measured Improvement:
- `buildTagIdf` execution time on main thread reduced from ~130ms blocking to ~0ms blocking (141ms total async time).
- Unblocks UI during periodic data refreshes.

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-02-05 17:00:13 +00:00
google-labs-jules[bot]andPR0M3TH3AN 2f33992192 Fix dependencies (jsdom/nostr-tools conflict) and WebTorrent regression
Co-authored-by: PR0M3TH3AN <[email protected]>
2026-02-01 13:32:00 +00:00
google-labs-jules[bot]andPR0M3TH3AN ffd8f0e23c fix: Sync package-lock.json and fix tests for nostr-tools v2
- Synced `package-lock.json` with `package.json` to resolve `npm ci` failures.
- Updated `nostr-tools` dependencies to resolve conflicts.
- Fixed `SyntaxError` in `tests/nostr-login-permissions.test.mjs` caused by duplicate code.
- Updated `js/nostr/client.js`, `js/nostr/publishHelpers.js`, `js/nostr/adapters/nsecAdapter.js`, `js/nostr/nip46Client.js` to use `hexToBytes` helper when calling `nostr-tools` functions, as v2+ expects `Uint8Array` instead of hex strings.
- Added `hexToBytes` helper in `js/utils/hex.js`.
- Updated tests (`tests/nostr/dm-direct-message-flow.test.mjs`, `tests/nostr-send-direct-message.test.mjs`, `tests/nostr-private-key-signer.test.mjs`, `tests/nostr/nip46Client.test.js`) to use `Uint8Array` for keys where required.

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-01-31 19:56:44 +00:00
thePR0M3TH3AN ceccd34681 Revert "Dead Code Cleanup" 2026-01-30 16:51:01 -05:00
google-labs-jules[bot]andPR0M3TH3AN 60fa6c4282 chore(ai): remove dead code (agent)
Co-authored-by: PR0M3TH3AN <[email protected]>
2026-01-30 20:54:52 +00:00
thePR0M3TH3AN cc7fe64e90 Merge pull request #1946 from PR0M3TH3AN/ai/dead-code-20240123-13702536329573366933
chore(ai): remove dead code (agent)
2026-01-30 10:05:35 -05:00
google-labs-jules[bot]andPR0M3TH3AN 40e809245a chore(ai): remove dead code (agent)
Removed unused exports and functions identified as dead code.
- Removed unused exports from `js/utils/storage.js`, `js/utils/storagePointer.js`, `js/utils/videoTags.js`, `js/ui/moderationCopy.js`.
- Removed unused function `updateTagPillStrip` from `js/ui/components/tagPillList.js` and associated tests.
- Updated `tests/utils/video-tags.test.mjs` to remove test for private function.
- Added `artifacts/depcheck.json` showing dependency analysis.

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-01-29 20:29:42 +00:00
thePR0M3TH3AN 89b8d124fa Consolidate profile metadata fetches 2026-01-29 15:25:08 -05:00
google-labs-jules[bot]andPR0M3TH3AN bf7988226d Fix WebTorrent client race condition and silence legacy avatar warning
- Added a null check for `this.client` in `js/webtorrent.js` after `await this.init()` to prevent `TypeError` when cleanup occurs during initialization.
- Updated `js/utils/profileMedia.js` to silently ignore the legacy `images/robot.png` path, preventing "Unsupported media URL" warnings.

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-01-29 14:14:30 +00:00
thePR0M3TH3AN 419a3f419c Add storage pointer tags to video posts 2026-01-26 22:07:32 -05:00
google-labs-jules[bot] 4a0b81ad98 chore(ai): remove dead code (unused exports & deps) 2026-01-24 20:28:53 +00:00
thePR0M3TH3AN 0eacbd1063 Add cached link previews with privacy toggle 2026-01-19 13:06:50 -05:00
thePR0M3TH3AN 0ac64867da Add shared hashtag normalization helper 2026-01-18 13:35:34 -05:00
google-labs-jules[bot] f06b2c7b1d feat: persist webtorrent probes and tracker health checks to localstorage
- Add storage helpers for torrent probes and tracker health in `js/utils/storage.js`
- Update `js/gridHealth.js` to read/write torrent probes from localStorage
- Update `js/healthService.js` to read/write tracker health from localStorage
- Ensure TTLs (5m for probes, 2m for trackers) are respected across sessions
- Add verification test `tests/verify-storage-persistence.mjs` (removed before completion)
2026-01-18 18:13:37 +00:00
google-labs-jules[bot] 083f0c9ecc feat: implement shared LRU cache for video comments and reactions
- Added `js/utils/lruCache.js` with hit/miss tracking.
- Updated `js/nostr/cachePolicies.js` to set 5-minute TTL for comments/reactions.
- Integrated caching and incremental fetching in `js/nostr/commentEvents.js`.
- Implemented `listVideoReactions` in `js/nostr/reactionEvents.js` with caching logic.
2026-01-17 22:15:46 +00:00
google-labs-jules[bot] 4e840c6159 feat: improve magnet link reliability with webseeds
- Update `UploadModal.js` to pre-calculate R2 keys and public URLs before upload.
- Update `torrentHash.js` to embed the calculated video URL as a webseed (`url-list`) in the `.torrent` file.
- Update `r2Service.js` to accept forced keys/URLs and append `&xs=` (pointing to the .torrent file) to the magnet link.
- Ensures magnet links work for peerless downloads via WebSeed (BEP19) and HTTP Seeding (BEP17).
2026-01-15 13:26:27 +00:00
thePR0M3TH3AN 6262a3cb37 Add torrent metadata upload for R2 videos 2026-01-14 21:28:57 -05:00
thePR0M3TH3AN b48edbb055 Refactor inline styles to CSS rules 2026-01-13 21:13:32 -05:00
thePR0M3TH3AN 4c4f57c6e5 Replace inline styles with classes 2026-01-13 20:29:38 -05:00
google-labs-jules[bot] 7dc2977cf2 Update Cloudflare R2 upload to use minimal permissions and add progress bar
- Removed requirement for Cloudflare API Token, Zone ID, and Worker Token from Upload Modal and R2Service.
- Simplified R2 configuration to require only Account ID, S3 Access Keys, and a user-provided Public Bucket URL.
- Added a read-only field in Upload Modal displaying the derived target bucket name (npub-based) for user reference.
- Implemented client-side torrent info hash calculation using `WebTorrent` (via `js/utils/torrentHash.js`) to generate magnet links before upload.
- Added a visual upload progress bar to the Upload Modal.
- Updated `js/r2.js` to ensure the Public Bucket URL always includes the `https://` protocol.
2026-01-12 18:53:22 +00:00
google-labs-jules[bot] 1d3c827f62 Fix: prevent published date reset when editing videos and show edited status
Prioritize `published_at` metadata over event `created_at` timestamp.
Backfill `published_at` during edit if missing to preserve original date.
Add "(edited)" label to video cards for modified content.
Display "Last Edited: [Date]" on video player modal.
2026-01-12 15:35:23 +00:00
thePR0M3TH3AN 3996986e63 Remove nostr shim and retarget imports 2026-01-06 15:32:21 -05:00
google-labs-jules[bot] f9ce798332 Prioritize d tag in video pointer resolution
When creating address pointers (`a` tags) for watch history, `resolveVideoPointer` was incorrectly prioritizing `videoRootId` over the actual NIP-33 `d` tag. If these values differed (common in newly published videos), the resulting pointer would reference a non-existent identifier, causing subsequent hydration to fail.

This change swaps the order to prioritize the `d` tag, ensuring watch history entries use the correct addressable identifier.
2026-01-06 14:27:26 +00:00
google-labs-jules[bot] e6a6ea6f78 Fix watch history hydration by preserving relay hints
Ensures that the relay hint is preserved when recording a video view, allowing the hydration logic to fetch the video details from the correct relay.
- Updated `resolveVideoPointer` in `js/utils/videoPointer.js` to accept a `relay` argument.
- Updated `playVideoByEventId`, `checkUrlParams`, and `deriveVideoPointerInfo` in `js/app.js` to pass the relay hint when resolving the video pointer.
2026-01-06 14:12:59 +00:00