From 45917d6e2b6cf5754cb86f2e3c0636b8f5d8264e Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 18:45:20 +0000 Subject: [PATCH] run daily perf-agent and add analysis scripts - Added scripts/agent/perf-search.mjs to scan for performance anti-patterns. - Added scripts/agent/generate-perf-report.mjs to summarize findings. - Generated perf/hits-2026-02-18.json and perf/daily-perf-report-2026-02-18.md. - Created completion log. Co-authored-by: PR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> --- ...026-02-18_18-39-21_perf-agent_completed.md | 10 + perf/daily-perf-report-2026-02-18.md | 42 + perf/hits-2026-02-18.json | 9123 +++++++++++++++++ scripts/agent/generate-perf-report.mjs | 63 + scripts/agent/perf-search.mjs | 70 + 5 files changed, 9308 insertions(+) create mode 100644 docs/agents/task-logs/daily/2026-02-18_18-39-21_perf-agent_completed.md create mode 100644 perf/daily-perf-report-2026-02-18.md create mode 100644 perf/hits-2026-02-18.json create mode 100644 scripts/agent/generate-perf-report.mjs create mode 100644 scripts/agent/perf-search.mjs diff --git a/docs/agents/task-logs/daily/2026-02-18_18-39-21_perf-agent_completed.md b/docs/agents/task-logs/daily/2026-02-18_18-39-21_perf-agent_completed.md new file mode 100644 index 00000000..68095251 --- /dev/null +++ b/docs/agents/task-logs/daily/2026-02-18_18-39-21_perf-agent_completed.md @@ -0,0 +1,10 @@ +# perf-agent completed + +- **Date**: 2026-02-18 +- **Agent**: perf-agent +- **Summary**: Ran search patterns, generated `perf/hits-2026-02-18.json` and `perf/daily-perf-report-2026-02-18.md`. +- **Files Created**: + - `scripts/agent/perf-search.mjs` + - `scripts/agent/generate-perf-report.mjs` + - `perf/hits-2026-02-18.json` + - `perf/daily-perf-report-2026-02-18.md` diff --git a/perf/daily-perf-report-2026-02-18.md b/perf/daily-perf-report-2026-02-18.md new file mode 100644 index 00000000..d47bb366 --- /dev/null +++ b/perf/daily-perf-report-2026-02-18.md @@ -0,0 +1,42 @@ +# Daily Performance Report - 2026-02-18 + +## Summary +Total Hits: 1303 + +### Hits by Pattern +- Nostr/Relay/Auth: 257 +- Promise Concurrency: 66 +- WebTorrent: 771 +- Timeouts/Intervals: 153 +- Visibility: 19 +- Workers: 37 + +## Top Files by Activity +- js/webtorrent.js: 100 hits +- js/services/playbackService.js: 76 hits +- js/app.js: 72 hits +- js/app/playbackCoordinator.js: 71 hits +- js/ui/components/UploadModal.js: 64 hits +- js/app/authSessionCoordinator.js: 47 hits +- js/ui/components/VideoCard.js: 34 hits +- js/ui/applicationBootstrap.js: 31 hits +- js/ui/components/EditModal.js: 30 hits +- js/nostr/client.js: 28 hits + +## Potential P0/P1 Candidates (Sample) +These locations involve concurrency or heavy relay operations: + +- **js/adminListStore.js:567** (Nostr/Relay/Auth): `events = await nostrClient.pool.list(relays, [normalizedFilter]);` +- **js/app.js:2828** (Nostr/Relay/Auth): `if (!nostrClient?.pool || typeof nostrClient.pool.list !== "function") {` +- **js/app.js:2833** (Nostr/Relay/Auth): `const events = await nostrClient.pool.list(relayList, [` +- **js/channelProfile.js:5402** (Nostr/Relay/Auth): `const fallbackEvents = await nostrClient.pool.list(` +- **js/channelProfile.js:5415** (Nostr/Relay/Auth): `(url) => nostrClient.pool.list([url], [filter]),` +- **js/dmDecryptor.js:456** (Promise Concurrency): `return await Promise.any(decryptors.map(attemptUnwrap));` +- **js/embed.js:274** (Nostr/Relay/Auth): `const events = await pool.list(relayList, [filter]);` +- **js/embed.js:282** (Nostr/Relay/Auth): `devLogger.warn("[embed] Failed to fetch naddr via pool.list:", error);` +- **js/feedEngine/watchHistoryFeed.js:406** (Nostr/Relay/Auth): `const events = await nostrClient.pool.list(mergedRelays, filters);` +- **js/feedEngine/watchHistoryFeed.js:514** (Nostr/Relay/Auth): `const events = await nostrClient.pool.list(relays, [filter]);` + +## Actions Taken +- Ran search patterns and generated inventory. +- No automatic fixes applied in this run. diff --git a/perf/hits-2026-02-18.json b/perf/hits-2026-02-18.json new file mode 100644 index 00000000..f4d400df --- /dev/null +++ b/perf/hits-2026-02-18.json @@ -0,0 +1,9123 @@ +[ + { + "file": "js/adminListStore.js", + "line": 297, + "content": "if (!nostrClient.pool) {", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/adminListStore.js", + "line": 567, + "content": "events = await nostrClient.pool.list(relays, [normalizedFilter]);", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/adminListStore.js", + "line": 607, + "content": "const [editors, whitelist, blacklist] = await Promise.all([", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/adminListStore.js", + "line": 653, + "content": "const results = await Promise.all(", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/adminListStore.js", + "line": 802, + "content": "return Promise.any(acceptancePromises).catch((aggregateError) => {", + "pattern": "Promise Concurrency", + "match": "Promise.any" + }, + { + "file": "js/adminListStore.js", + "line": 808, + "content": "const allResults = Promise.allSettled(relayPromises).then((entries) => {", + "pattern": "Promise Concurrency", + "match": "Promise.allSettled" + }, + { + "file": "js/adminListStore.js", + "line": 911, + "content": "nostrClient.pool,", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 29, + "content": "relayManager,", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 30, + "content": "torrentClient,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 37, + "content": "publishEventToRelays,", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 39, + "content": "queueSignEvent,", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 268, + "content": "// 1. Relays and Profile are now loaded (sequentially or efficiently by authService)", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 363, + "content": "const listStatePromise = Promise.all([", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 423, + "content": "typeof this.authService.loadBlocksForPubkey === \"function\"", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 429, + "content": "const loaded = await this.authService.loadBlocksForPubkey(activePubkey, {", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 491, + "content": "const taskOutcomes = await Promise.all(parallelListTasks);", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 521, + "content": "Promise.all([", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 522, + "content": "this.authService?.loadBlocksForPubkey?.(activePubkey, {", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 709, + "content": "const feedSyncPromise = Promise.race([", + "pattern": "Promise Concurrency", + "match": "Promise.race" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 710, + "content": "Promise.allSettled([", + "pattern": "Promise Concurrency", + "match": "Promise.allSettled" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 714, + "content": "new Promise((resolve) => setTimeout(resolve, FEED_SYNC_TIMEOUT_MS)),", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 792, + "content": "typeof window !== \"undefined\" && typeof window.setTimeout === \"function\"", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 793, + "content": "? window.setTimeout.bind(window)", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 794, + "content": ": setTimeout;", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 827, + "content": "const detail = await this.authService.logout();", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1152, + "content": "// Tell webtorrent to cleanup", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1153, + "content": "await torrentClient.cleanup();", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1154, + "content": "this.log(\"[cleanup] WebTorrent cleanup resolved.\");", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1158, + "content": "await fetch(\"/webtorrent/cancel/\", { mode: \"no-cors\" });", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1201, + "content": "this.torrentStatusIntervalId = null;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1209, + "content": "this.torrentStatusNodes = null;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1212, + "content": "this.torrentStatusNodes = {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1222, + "content": "this.torrentStatusNodes = null;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1257, + "content": "this.torrentStatusVisibilityHandler = handleVisibilityChange;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1258, + "content": "this.torrentStatusPageHideHandler = handlePageHide;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1259, + "content": "document.addEventListener(\"visibilitychange\", handleVisibilityChange);", + "pattern": "Visibility", + "match": "visibilitychange" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1264, + "content": "if (this.torrentStatusVisibilityHandler) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1265, + "content": "document.removeEventListener(\"visibilitychange\", this.torrentStatusVisibilityHandler);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1265, + "content": "document.removeEventListener(\"visibilitychange\", this.torrentStatusVisibilityHandler);", + "pattern": "Visibility", + "match": "visibilitychange" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1266, + "content": "this.torrentStatusVisibilityHandler = null;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1268, + "content": "if (this.torrentStatusPageHideHandler) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1269, + "content": "window.removeEventListener(\"pagehide\", this.torrentStatusPageHideHandler);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1270, + "content": "this.torrentStatusPageHideHandler = null;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1279, + "content": "const result = await this.authService.switchProfile(pubkey, { providerId });", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1357, + "content": "} else if (typeof setTimeout === \"function\") {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1358, + "content": "setTimeout(resolve, 0);", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1451, + "content": "removalResult = this.authService.removeSavedProfile(candidatePubkey);", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1513, + "content": "const previous = relayManager.snapshot();", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1519, + "content": "operationResult = relayManager.addRelay(url);", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1522, + "content": "operationResult = relayManager.removeRelay(url);", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1525, + "content": "operationResult = relayManager.restoreDefaults();", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1528, + "content": "operationResult = relayManager.cycleRelayMode(url);", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1552, + "content": "const publishResult = await relayManager.publishRelayList(activePubkey);", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/app/authSessionCoordinator.js", + "line": 1577, + "content": "relayManager.setEntries(previous, { allowEmpty: false });", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/app/feedCoordinator.js", + "line": 1130, + "content": "const classes = [\"badge\", \"torrent-health-badge\"];", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/feedCoordinator.js", + "line": 1148, + "content": "isMagnetUriSupported(magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/feedCoordinator.js", + "line": 1149, + "content": "return isValidMagnetUri(magnet);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/modalCoordinator.js", + "line": 21, + "content": "torrentClient,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/modalCoordinator.js", + "line": 252, + "content": "await fetch(\"/webtorrent/cancel/\", { mode: \"no-cors\" });", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/modalCoordinator.js", + "line": 255, + "content": "devLogger.warn(\"[hideModal] webtorrent cancel fetch failed:\", err);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 4, + "content": "* URL-first + magnet fallback playback pipeline.", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 21, + "content": "torrentClient,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 140, + "content": "magnet: pending.magnet || \"\",", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 212, + "content": "startTorrentStatusMirrors(torrentInstance) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 213, + "content": "if (!torrentInstance) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 225, + "content": "this.updateTorrentStatus(torrentInstance);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 226, + "content": "const { status, progress, peers, speed, downloaded } = this.torrentStatusNodes || {};", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 267, + "content": "if (this.torrentStatusIntervalId) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 273, + "content": "const intervalId = setInterval(callback, 3000);", + "pattern": "Timeouts/Intervals", + "match": "setInterval" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 274, + "content": "this.torrentStatusIntervalId = intervalId;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 279, + "content": "if (!this.torrentStatusIntervalId) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 282, + "content": "clearInterval(this.torrentStatusIntervalId);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 283, + "content": "this.removeActiveInterval(this.torrentStatusIntervalId);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 284, + "content": "this.torrentStatusIntervalId = null;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 333, + "content": "async playViaWebTorrent(", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 334, + "content": "magnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 349, + "content": "throw new Error(\"No magnet URI provided for torrent playback.\");", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 359, + "content": "\"No modal video element available for torrent playback.\"", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 364, + "content": "const [magnetPrefix, magnetQuery = \"\"] = trimmedCandidate.split(\"?\", 2);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 365, + "content": "let normalizedMagnet = magnetPrefix;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 366, + "content": "let queryParts = magnetQuery", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 372, + "content": "normalizedMagnet = `${magnetPrefix}?${queryParts.join(\"&\")}`;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 378, + "content": "await torrentClient.cleanup();", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 382, + "content": "this.videoModal.updateStatus(\"Streaming via WebTorrent\");", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 386, + "content": "const torrentInstance = await torrentClient.streamVideo(", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 392, + "content": "if (torrentClient.isServiceWorkerUnavailable()) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 393, + "content": "const swError = torrentClient.getServiceWorkerInitError();", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 396, + "content": "\"[playViaWebTorrent] Service worker unavailable; streaming directly via WebTorrent.\",", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 401, + "content": "\"[playViaWebTorrent] Service worker unavailable; direct streaming engaged.\",", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 409, + "content": "if (torrentInstance && torrentInstance.ready) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 410, + "content": "// Some browsers delay `playing` events for MediaSource-backed torrents.", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 412, + "content": "// video\" regression when WebTorrent is already feeding data.", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 413, + "content": "this.forceRemoveModalPoster(\"webtorrent-ready\");", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 415, + "content": "this.startTorrentStatusMirrors(torrentInstance);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 416, + "content": "return torrentInstance;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 420, + "content": "typeof magnet === \"string\" ? magnet.trim() : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 433, + "content": "`[playViaWebTorrent] Normalized magnet failed: ${primaryError.message}`", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 436, + "content": "\"[playViaWebTorrent] Primary magnet failed, retrying original string.\"", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 448, + "content": "* and falls back to WebTorrent when needed.", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 492, + "content": "playViaWebTorrent: (magnetUri, opts) =>", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 493, + "content": "this.playViaWebTorrent(magnetUri, opts),", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 514, + "content": "this.currentVideo.magnet = metadata.magnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 521, + "content": "this.currentVideo.torrentSupported = metadata.torrentSupported;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 523, + "content": "this.currentMagnetUri = metadata.magnet || null;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 558, + "content": "typeof hint.magnet === \"string\" ? hint.magnet.trim() : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 589, + "content": "magnet: fallbackMagnetCandidate,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 626, + "content": "typeof video.magnet === \"string\" ? video.magnet.trim() : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 637, + "content": "let magnetCandidate = rawMagnet || legacyInfoHash || \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 638, + "content": "let decodedMagnetCandidate = safeDecodeMagnet(magnetCandidate);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 639, + "content": "let usableMagnetCandidate = decodedMagnetCandidate || magnetCandidate;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 640, + "content": "let magnetSupported = isValidMagnetUri(usableMagnetCandidate);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 642, + "content": "if (!magnetSupported && fallbackMagnetForCandidate) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 643, + "content": "magnetCandidate = fallbackMagnetForCandidate;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 644, + "content": "decodedMagnetCandidate = safeDecodeMagnet(magnetCandidate);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 645, + "content": "usableMagnetCandidate = decodedMagnetCandidate || magnetCandidate;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 646, + "content": "magnetSupported = isValidMagnetUri(usableMagnetCandidate);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 649, + "content": "const sanitizedMagnet = magnetSupported ? usableMagnetCandidate : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 675, + "content": "magnet: sanitizedMagnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 677, + "content": "magnetCandidate || fallbackMagnetForCandidate || legacyInfoHash || \"\",", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 678, + "content": "torrentSupported: magnetSupported,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 782, + "content": "const magnetInput =", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 785, + "content": "magnetCandidate ||", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 798, + "content": "magnet: magnetInput,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 1117, + "content": "magnet = \"\",", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 1138, + "content": "const trimmedMagnet = typeof magnet === \"string\" ? magnet.trim() : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 1141, + "content": "const magnetSupported = isValidMagnetUri(usableMagnet);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 1142, + "content": "const sanitizedMagnet = magnetSupported ? usableMagnet : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 1152, + "content": "const message = trimmedMagnet && !magnetSupported", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 1164, + "content": "magnet: sanitizedMagnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 1166, + "content": "torrentSupported: magnetSupported,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app/playbackCoordinator.js", + "line": 1211, + "content": "magnet: usableMagnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app.js", + "line": 5, + "content": "import { torrentClient } from \"./webtorrent.js\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app.js", + "line": 16, + "content": "import { extractBtihFromMagnet, safeDecodeMagnet } from \"./magnetUtils.js\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app.js", + "line": 34, + "content": "import { relayManager } from \"./relayManager.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/app.js", + "line": 84, + "content": "publishEventToRelays,", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/app.js", + "line": 91, + "content": "import { queueSignEvent } from \"./nostr/signRequestQueue.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/app.js", + "line": 129, + "content": "import { isValidMagnetUri } from \"./utils/magnetValidators.js\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app.js", + "line": 169, + "content": "import TorrentStatusController from \"./ui/torrentStatusController.js\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app.js", + "line": 192, + "content": "\"This magnet link is missing a compatible BitTorrent v1 info hash.\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app.js", + "line": 210, + "content": "return this.authService.pubkey;", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 214, + "content": "this.authService.pubkey = value;", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 218, + "content": "return this.authService.currentUserNpub;", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 222, + "content": "this.authService.currentUserNpub = value;", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 234, + "content": "return this.authService.activeProfilePubkey;", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 238, + "content": "this.authService.setActiveProfilePubkey(value, { persist: false });", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 242, + "content": "return this.authService.savedProfiles;", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 246, + "content": "this.authService.setSavedProfiles(value, { persist: false, persistActive: false });", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 263, + "content": "torrentClient,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app.js", + "line": 338, + "content": "this.torrentStatusIntervalId = null;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app.js", + "line": 339, + "content": "this.torrentStatusNodes = null;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app.js", + "line": 340, + "content": "this.torrentStatusVisibilityHandler = null;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app.js", + "line": 341, + "content": "this.torrentStatusPageHideHandler = null;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app.js", + "line": 347, + "content": "this.torrentStatusController = new TorrentStatusController({", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app.js", + "line": 602, + "content": "torrentClient,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app.js", + "line": 638, + "content": "relayManager,", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/app.js", + "line": 639, + "content": "torrentClient,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app.js", + "line": 646, + "content": "publishEventToRelays,", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/app.js", + "line": 648, + "content": "queueSignEvent,", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/app.js", + "line": 651, + "content": "getActiveProfilePubkey: () => this.authService.activeProfilePubkey,", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 662, + "content": "torrentClient,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app.js", + "line": 720, + "content": "const result = this.authService.loadSavedProfilesFromStorage();", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 726, + "content": "const updated = this.authService.syncSavedProfileFromCache(pubkey, {", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 736, + "content": "this.authService.loadProfileCacheFromStorage();", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 740, + "content": "this.authService.persistProfileCache();", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 744, + "content": "return this.authService.getProfileCacheEntry(pubkey);", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 748, + "content": "return this.authService.setProfileCacheEntry(pubkey, profile);", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 752, + "content": "this.authService.setActiveProfilePubkey(pubkey, { persist });", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 831, + "content": "_initServiceWorker() {", + "pattern": "Workers", + "match": "Worker(" + }, + { + "file": "js/app.js", + "line": 841, + "content": "this.authService.hydrateFromStorage();", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 907, + "content": "return Promise.all([", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/app.js", + "line": 1114, + "content": "const savedProfiles = this.authService.cloneSavedProfiles();", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 1129, + "content": "await this.authService.login(savedPubKey, loginOptions);", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 1158, + "content": "this._initServiceWorker();", + "pattern": "Workers", + "match": "Worker(" + }, + { + "file": "js/app.js", + "line": 1442, + "content": "this.authService?.requestLogin?.(options) ?? Promise.resolve(false),", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 1668, + "content": "return this.authService.requestLogin({", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 1756, + "content": "authService: this.authService,", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 2471, + "content": "await Promise.allSettled(refreshTasks);", + "pattern": "Promise Concurrency", + "match": "Promise.allSettled" + }, + { + "file": "js/app.js", + "line": 2625, + "content": "return this.authService.loadOwnProfile(pubkey);", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 2629, + "content": "return this.authService.fetchAndRenderProfile(pubkey, forceRefresh);", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 2749, + "content": "const publishResults = await publishEventToRelays(", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/app.js", + "line": 2750, + "content": "nostrClient.pool,", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/app.js", + "line": 2828, + "content": "if (!nostrClient?.pool || typeof nostrClient.pool.list !== \"function\") {", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/app.js", + "line": 2833, + "content": "const events = await nostrClient.pool.list(relayList, [", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/app.js", + "line": 3077, + "content": "const publishResult = await this.authService.handleUploadSubmit(payload, {", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 3425, + "content": "await Promise.allSettled(tasks);", + "pattern": "Promise Concurrency", + "match": "Promise.allSettled" + }, + { + "file": "js/app.js", + "line": 3443, + "content": "const taskResults = await Promise.allSettled([", + "pattern": "Promise Concurrency", + "match": "Promise.allSettled" + }, + { + "file": "js/app.js", + "line": 3445, + "content": ".then(() => this.authService?.loadBlocksForPubkey?.(activePubkey, {", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/app.js", + "line": 4311, + "content": "* Updates the modal to reflect current torrent stats.", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app.js", + "line": 4312, + "content": "* We remove the unused torrent.status references,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app.js", + "line": 4313, + "content": "* and do not re-trigger recursion here (no setTimeout).", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/app.js", + "line": 4315, + "content": "updateTorrentStatus(torrent) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app.js", + "line": 4316, + "content": "if (this.torrentStatusController) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app.js", + "line": 4317, + "content": "this.torrentStatusController.update(torrent);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app.js", + "line": 4645, + "content": "async playViaWebTorrent(...args) {", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/app.js", + "line": 4647, + "content": "return this._playback.playViaWebTorrent(...args);", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/app.js", + "line": 4652, + "content": "* and falls back to WebTorrent when needed.", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/app.js", + "line": 5098, + "content": "* Copies the current video's magnet link to the clipboard.", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app.js", + "line": 5101, + "content": "if (!this.currentVideo || !this.currentVideo.magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app.js", + "line": 5105, + "content": "!this.currentVideo.torrentSupported", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/app.js", + "line": 5111, + "content": "this.showError(\"No magnet link to copy.\");", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app.js", + "line": 5115, + "content": "navigator.clipboard.writeText(this.currentVideo.magnet);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app.js", + "line": 5118, + "content": "devLogger.error(\"Failed to copy magnet link:\", err);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/app.js", + "line": 5119, + "content": "this.showError(\"Could not copy magnet link. Please copy it manually.\");", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/channelProfile.js", + "line": 3835, + "content": "await Promise.allSettled(pendingTasks);", + "pattern": "Promise Concurrency", + "match": "Promise.allSettled" + }, + { + "file": "js/channelProfile.js", + "line": 4122, + "content": "typeof window.requestIdleCallback === \"function\"", + "pattern": "Timeouts/Intervals", + "match": "requestIdleCallback" + }, + { + "file": "js/channelProfile.js", + "line": 4124, + "content": "window.requestIdleCallback(() => warmZapPopover(), { timeout: 250 });", + "pattern": "Timeouts/Intervals", + "match": "requestIdleCallback" + }, + { + "file": "js/channelProfile.js", + "line": 4126, + "content": "setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/channelProfile.js", + "line": 4611, + "content": ": \"This magnet link is missing a compatible BitTorrent v1 info hash.\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/channelProfile.js", + "line": 4633, + "content": "element?.closest(\"[data-play-url],[data-play-magnet]\") || element;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/channelProfile.js", + "line": 4645, + "content": "target?.getAttribute?.(\"data-play-magnet\") ??", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/channelProfile.js", + "line": 4657, + "content": "const magnet = typeof rawMagnetValue === \"string\" ? rawMagnetValue : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/channelProfile.js", + "line": 4664, + "content": "return { videoId, url, magnet, video };", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/channelProfile.js", + "line": 4682, + "content": "magnet: detail.magnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/channelProfile.js", + "line": 4691, + "content": "magnet: detail.magnet", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/channelProfile.js", + "line": 4700, + "content": "app.playVideoWithFallback({ url: detail.url, magnet: detail.magnet })", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/channelProfile.js", + "line": 4819, + "content": "isMagnetSupported: (magnet) => app?.isMagnetUriSupported?.(magnet),", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/channelProfile.js", + "line": 5402, + "content": "const fallbackEvents = await nostrClient.pool.list(", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/channelProfile.js", + "line": 5415, + "content": "(url) => nostrClient.pool.list([url], [filter]),", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/constants.js", + "line": 139, + "content": "\"wss://tracker.openwebtorrent.com\",", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/constants.js", + "line": 141, + "content": "\"wss://tracker.btorrent.xyz\",", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/constants.js", + "line": 143, + "content": "\"wss://tracker.webtorrent.dev\",", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/constants.js", + "line": 183, + "content": "URL_FIRST_ENABLED: DEFAULT_PLAYBACK_SOURCE !== \"torrent\", // try URL before magnet in the player", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/dmDecryptor.js", + "line": 456, + "content": "return await Promise.any(decryptors.map(attemptUnwrap));", + "pattern": "Promise Concurrency", + "match": "Promise.any" + }, + { + "file": "js/dmDecryptor.js", + "line": 567, + "content": "return await Promise.any(attempts);", + "pattern": "Promise Concurrency", + "match": "Promise.any" + }, + { + "file": "js/docsView.js", + "line": 385, + "content": "scrollSpyState.rafId = requestAnimationFrame(updateActiveFromScroll);", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/docsView.js", + "line": 463, + "content": "typeof requestIdleCallback === \"function\"", + "pattern": "Timeouts/Intervals", + "match": "requestIdleCallback" + }, + { + "file": "js/docsView.js", + "line": 464, + "content": "? requestIdleCallback", + "pattern": "Timeouts/Intervals", + "match": "requestIdleCallback" + }, + { + "file": "js/docsView.js", + "line": 465, + "content": ": (callback) => requestAnimationFrame(callback);", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/docsView.js", + "line": 580, + "content": "typeof requestAnimationFrame === \"function\"", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/docsView.js", + "line": 581, + "content": "? requestAnimationFrame", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/docsView.js", + "line": 582, + "content": ": (callback) => setTimeout(callback, 0);", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/embed.js", + "line": 38, + "content": "window.parent.postMessage(", + "pattern": "Workers", + "match": "postMessage(" + }, + { + "file": "js/embed.js", + "line": 112, + "content": "if (normalized === \"url\" || normalized === \"torrent\") {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/embed.js", + "line": 255, + "content": "const pool = nostrClient.pool;", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/embed.js", + "line": 274, + "content": "const events = await pool.list(relayList, [filter]);", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/embed.js", + "line": 282, + "content": "devLogger.warn(\"[embed] Failed to fetch naddr via pool.list:\", error);", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/embed.js", + "line": 379, + "content": "app.authService?.hydrateFromStorage?.();", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/embed.js", + "line": 411, + "content": "const magnet = typeof video.magnet === \"string\" ? video.magnet.trim() : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/embed.js", + "line": 413, + "content": "if (!url && !magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/embed.js", + "line": 425, + "content": "magnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/embedDiagnostics.js", + "line": 14, + "content": "window.parent.postMessage({ __bitvid_debug: true, type, payload }, \"*\");", + "pattern": "Workers", + "match": "postMessage(" + }, + { + "file": "js/feedEngine/stages.js", + "line": 196, + "content": "return await Promise.any(promises);", + "pattern": "Promise Concurrency", + "match": "Promise.any" + }, + { + "file": "js/feedEngine/watchHistoryFeed.js", + "line": 406, + "content": "const events = await nostrClient.pool.list(mergedRelays, filters);", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/feedEngine/watchHistoryFeed.js", + "line": 514, + "content": "const events = await nostrClient.pool.list(relays, [filter]);", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/gridHealth.js", + "line": 2, + "content": "import { infoHashFromMagnet } from \"./magnets.js\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/gridHealth.js", + "line": 4, + "content": "import { TorrentClient, torrentClient } from \"./webtorrent.js\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/gridHealth.js", + "line": 113, + "content": "normalizedReason = \"Invalid magnet\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/gridHealth.js", + "line": 120, + "content": "return \"WebTorrent status unknown\";", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/gridHealth.js", + "line": 122, + "content": "return `WebTorrent • ${parts.join(\" • \")}`;", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/gridHealth.js", + "line": 177, + "content": "function queueProbe(magnet, cacheKey, priority = 0, webSeeds = []) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/gridHealth.js", + "line": 178, + "content": "if (!magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/gridHealth.js", + "line": 194, + "content": "torrentClient", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/gridHealth.js", + "line": 195, + "content": ".probePeers(magnet, {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/gridHealth.js", + "line": 346, + "content": "const badge = card.querySelector(\".torrent-health-badge\");", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/gridHealth.js", + "line": 354, + "content": "const classes = [\"badge\", \"torrent-health-badge\"];", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/gridHealth.js", + "line": 363, + "content": "aria: \"WebTorrent peers available\",", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/gridHealth.js", + "line": 369, + "content": "aria: \"WebTorrent peers unavailable\",", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/gridHealth.js", + "line": 375, + "content": "aria: \"Checking WebTorrent peers\",", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/gridHealth.js", + "line": 381, + "content": "aria: \"WebTorrent status unknown\",", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/gridHealth.js", + "line": 395, + "content": "badge.textContent = `${iconPrefix}WebTorrent`;", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/gridHealth.js", + "line": 437, + "content": "const magnet = card.dataset.magnet || \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/gridHealth.js", + "line": 438, + "content": "if (!magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/gridHealth.js", + "line": 443, + "content": "const infoHash = infoHashFromMagnet(magnet);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/gridHealth.js", + "line": 474, + "content": "const probePromise = queueProbe(magnet, infoHash, priority, webSeeds);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/gridHealth.js", + "line": 525, + "content": "if (!card.dataset.magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/historyView.js", + "line": 1153, + "content": "return { url: \"\", magnet: \"\" };", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/historyView.js", + "line": 1156, + "content": "const magnetRaw =", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/historyView.js", + "line": 1157, + "content": "typeof video.magnet === \"string\"", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/historyView.js", + "line": 1158, + "content": "? video.magnet.trim()", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/historyView.js", + "line": 1162, + "content": "return { url, magnet: magnetRaw };", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/historyView.js", + "line": 1178, + "content": "if (playbackData.magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/historyView.js", + "line": 1179, + "content": "thumbnailLink.dataset.playMagnet = playbackData.magnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/historyView.js", + "line": 1214, + "content": "if (playbackData.magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/historyView.js", + "line": 1215, + "content": "titleLink.dataset.playMagnet = playbackData.magnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/historyView.js", + "line": 1327, + "content": "if (playbackData.magnet)", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/historyView.js", + "line": 1328, + "content": "btn.dataset.playMagnet = playbackData.magnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/historyView.js", + "line": 2077, + "content": "const magnetAttr = trigger.dataset.playMagnet || \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/historyView.js", + "line": 2089, + "content": "app.playVideoByEventId(videoId, { url, magnet: magnetAttr });", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/historyView.js", + "line": 2096, + "content": "magnet: magnetAttr", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/index.js", + "line": 46, + "content": "import AuthService from \"./services/authService.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/index.js", + "line": 53, + "content": "import { relayManager } from \"./relayManager.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/index.js", + "line": 131, + "content": "relayManager,", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/index.js", + "line": 139, + "content": "service.hydrateFromStorage();", + "pattern": "Nostr/Relay/Auth", + "match": "hydrateFromStorage" + }, + { + "file": "js/index.js", + "line": 200, + "content": "const authService = getLockdownAuthService();", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/index.js", + "line": 201, + "content": "if (!authService || typeof authService.getActivePubkey !== \"function\") {", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/index.js", + "line": 205, + "content": "const savedPubkey = authService.getActivePubkey();", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/index.js", + "line": 216, + "content": "await authService.login(savedPubkey, { persistActive: false });", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/index.js", + "line": 285, + "content": "const authService = getLockdownAuthService();", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/index.js", + "line": 286, + "content": "const result = await authService.requestLogin({ allowAccountSelection: true });", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/index.js", + "line": 373, + "content": "window.requestAnimationFrame(() => {", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/index.js", + "line": 608, + "content": "await Promise.all([", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/index.js", + "line": 807, + "content": "timeoutId = window.setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/magnetShared.js", + "line": 10, + "content": "const MAGNET_SCHEME = \"magnet:\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/magnetShared.js", + "line": 201, + "content": "if (!/^magnet:/i.test(working)) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/magnetUtils.js", + "line": 1, + "content": "// js/magnetUtils.js", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/magnetUtils.js", + "line": 14, + "content": "} from \"./magnetShared.js\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/magnetUtils.js", + "line": 27, + "content": "torrentUrl,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/magnetUtils.js", + "line": 47, + "content": "return { magnet: \"\", didChange: false };", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/magnetUtils.js", + "line": 51, + "content": "const magnet = canonicalValue;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/magnetUtils.js", + "line": 53, + "content": "magnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/magnetUtils.js", + "line": 54, + "content": "didChange: didMutate || magnet !== initial,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/magnetUtils.js", + "line": 93, + "content": "const torrentHint = typeof torrentUrl === \"string\" && torrentUrl.trim()", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/magnetUtils.js", + "line": 94, + "content": "? torrentUrl", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/magnetUtils.js", + "line": 99, + "content": "if (torrentHint) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/magnetUtils.js", + "line": 100, + "content": "if (ensureTorrentHint(params, torrentHint, { requireHttp: true })) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/magnetUtils.js", + "line": 126, + "content": "magnet: finalMagnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/magnets.js", + "line": 1, + "content": "import { extractBtihFromMagnet, normalizeInfoHash } from \"./magnetShared.js\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/magnets.js", + "line": 22, + "content": "export function infoHashFromMagnet(magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/magnets.js", + "line": 23, + "content": "if (typeof magnet !== \"string\") {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/magnets.js", + "line": 26, + "content": "const extracted = extractBtihFromMagnet(magnet);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/magnets.js", + "line": 30, + "content": "export function trackersFromMagnet(magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/magnets.js", + "line": 31, + "content": "if (typeof magnet !== \"string\") {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/magnets.js", + "line": 34, + "content": "const parsed = parseMagnetLite(magnet);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/magnets.js", + "line": 52, + "content": "function parseMagnetLite(magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/magnets.js", + "line": 53, + "content": "if (typeof magnet !== \"string\") {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/magnets.js", + "line": 57, + "content": "const trimmed = magnet.trim();", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/adapters/nip07Adapter.js", + "line": 31, + "content": "await new Promise((resolve) => setTimeout(resolve, delay));", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/client.js", + "line": 21, + "content": "import { infoHashFromMagnet } from \"../magnets.js\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/client.js", + "line": 106, + "content": "publishEventToRelays,", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/nostr/client.js", + "line": 130, + "content": "decryptDmInWorker,", + "pattern": "Workers", + "match": "decryptDmInWorker" + }, + { + "file": "js/nostr/client.js", + "line": 213, + "content": "import { queueSignEvent } from \"./signRequestQueue.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/nostr/client.js", + "line": 802, + "content": "* @param {function} [params.fetchFn] - Custom fetch function (mocks or specialized logic). Defaults to `pool.list`.", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/client.js", + "line": 1282, + "content": "decryptDmInWorker({", + "pattern": "Workers", + "match": "decryptDmInWorker" + }, + { + "file": "js/nostr/client.js", + "line": 1299, + "content": "decryptDmInWorker({", + "pattern": "Workers", + "match": "decryptDmInWorker" + }, + { + "file": "js/nostr/client.js", + "line": 1440, + "content": "timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/client.js", + "line": 1974, + "content": "ciphertext = await encryptNip04InWorker({", + "pattern": "Workers", + "match": "Worker(" + }, + { + "file": "js/nostr/client.js", + "line": 2103, + "content": "const events = await this.pool.list(relayListCandidates, [", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/client.js", + "line": 2438, + "content": "* - It includes both a WebTorrent `magnet` and a direct `url` (if hosted).", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/nostr/client.js", + "line": 2449, + "content": "* @param {object} videoPayload - The normalized form data (title, magnet, thumbnail, etc.).", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/client.js", + "line": 2491, + "content": "* 3. **Content Update**: The new payload (title, magnet, etc.) replaces the old content.", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/client.js", + "line": 2706, + "content": "magnet: fetched.magnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/client.js", + "line": 2756, + "content": "const signedEvent = await queueSignEvent(signer, event);", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/nostr/client.js", + "line": 2757, + "content": "const publishResults = await publishEventToRelays(", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/nostr/client.js", + "line": 2892, + "content": "await Promise.all(", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/nostr/client.js", + "line": 2911, + "content": "magnet: typeof vid.magnet === \"string\" ? vid.magnet : \"\",", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/client.js", + "line": 2951, + "content": "cached.magnet = \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/client.js", + "line": 3081, + "content": "const signedDelete = await queueSignEvent(signer, deleteEvent);", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/nostr/client.js", + "line": 3082, + "content": "const publishResults = await publishEventToRelays(", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/nostr/client.js", + "line": 3425, + "content": "const events = await this.pool.list([url], [filter]);", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/client.js", + "line": 3571, + "content": "if (typeof this.pool.list === \"function\") {", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/client.js", + "line": 3573, + "content": "const events = await this.pool.list(relays, [makeFilter()]);", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/client.js", + "line": 3586, + "content": "devLogger.warn(\"fetchRawEventById pool.list error:\", error);", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/client.js", + "line": 3797, + "content": "const events = await this.pool.list(relays, [{ ids: Array.from(missingRoots) }]);", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/client.js", + "line": 3819, + "content": "const events = await this.pool.list(relays, [filter]);", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/client.js", + "line": 3943, + "content": "const events = await this.pool.list([url], [filter]);", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/commentEvents.js", + "line": 13, + "content": "import { queueSignEvent } from \"./signRequestQueue.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/nostr/commentEvents.js", + "line": 302, + "content": "signedEvent = await queueSignEvent(signer, event, {", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/nostr/commentEvents.js", + "line": 352, + "content": "if (!pool || typeof pool.list !== \"function\") {", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/commentEvents.js", + "line": 366, + "content": "if (!pool || typeof pool.list !== \"function\") {", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/commentEvents.js", + "line": 426, + "content": "const events = await pool.list([url], relayFilters);", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/dmDecryptWorker.js", + "line": 12, + "content": "workerScope.postMessage(payload);", + "pattern": "Workers", + "match": "postMessage(" + }, + { + "file": "js/nostr/dmDecryptWorkerClient.js", + "line": 51, + "content": "function ensureWorker() {", + "pattern": "Workers", + "match": "Worker(" + }, + { + "file": "js/nostr/dmDecryptWorkerClient.js", + "line": 61, + "content": "workerInstance = new Worker(", + "pattern": "Workers", + "match": "new Worker" + }, + { + "file": "js/nostr/dmDecryptWorkerClient.js", + "line": 80, + "content": "export function getDmDecryptWorkerQueueSize() {", + "pattern": "Workers", + "match": "getDmDecryptWorkerQueueSize" + }, + { + "file": "js/nostr/dmDecryptWorkerClient.js", + "line": 84, + "content": "export function decryptDmInWorker({", + "pattern": "Workers", + "match": "decryptDmInWorker" + }, + { + "file": "js/nostr/dmDecryptWorkerClient.js", + "line": 92, + "content": "const worker = ensureWorker();", + "pattern": "Workers", + "match": "Worker(" + }, + { + "file": "js/nostr/dmDecryptWorkerClient.js", + "line": 112, + "content": "const timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/dmDecryptWorkerClient.js", + "line": 118, + "content": "worker.postMessage({", + "pattern": "Workers", + "match": "postMessage(" + }, + { + "file": "js/nostr/dmSignalEvents.js", + "line": 9, + "content": "import { queueSignEvent } from \"./signRequestQueue.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/nostr/dmSignalEvents.js", + "line": 128, + "content": "signedEvent = await queueSignEvent(signer, event, {", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/nostr/dmSignalEvents.js", + "line": 271, + "content": "signedEvent = await queueSignEvent(signer, event, {", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/nostr/managers/ConnectionManager.js", + "line": 42, + "content": "timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/managers/ConnectionManager.js", + "line": 189, + "content": "const results = await Promise.all(", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/nostr/managers/ConnectionManager.js", + "line": 194, + "content": "const timeout = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/managers/ConnectionManager.js", + "line": 269, + "content": "this.relayReconnectTimer = setTimeout(async () => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/managers/ConnectionManager.js", + "line": 863, + "content": "const activeResults = await Promise.all(", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/nostr/managers/EventsCacheStore.js", + "line": 11, + "content": "if (typeof requestIdleCallback === \"function\") {", + "pattern": "Timeouts/Intervals", + "match": "requestIdleCallback" + }, + { + "file": "js/nostr/managers/EventsCacheStore.js", + "line": 12, + "content": "return requestIdleCallback(callback, { timeout });", + "pattern": "Timeouts/Intervals", + "match": "requestIdleCallback" + }, + { + "file": "js/nostr/managers/EventsCacheStore.js", + "line": 14, + "content": "return setTimeout(callback, timeout);", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/managers/EventsCacheStore.js", + "line": 154, + "content": "const [events, tombstones] = await Promise.all([", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/nostr/managers/EventsCacheStore.js", + "line": 221, + "content": "const [events, tombstones] = await Promise.all([", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/nostr/managers/PersistenceManager.js", + "line": 13, + "content": "if (typeof requestIdleCallback === \"function\") {", + "pattern": "Timeouts/Intervals", + "match": "requestIdleCallback" + }, + { + "file": "js/nostr/managers/PersistenceManager.js", + "line": 14, + "content": "return requestIdleCallback(callback, { timeout });", + "pattern": "Timeouts/Intervals", + "match": "requestIdleCallback" + }, + { + "file": "js/nostr/managers/PersistenceManager.js", + "line": 16, + "content": "return setTimeout(callback, timeout);", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/managers/PersistenceManager.js", + "line": 223, + "content": "* - Coordinates with `requestIdleCallback` to avoid blocking the main thread.", + "pattern": "Timeouts/Intervals", + "match": "requestIdleCallback" + }, + { + "file": "js/nostr/managers/PersistenceManager.js", + "line": 249, + "content": "this.cachePersistTimerId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/managers/SignerManager.js", + "line": 54, + "content": "import { queueSignEvent } from \"../signRequestQueue.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/nostr/managers/SignerManager.js", + "line": 542, + "content": "await new Promise((resolve) => setTimeout(resolve, 500));", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/nip04Worker.js", + "line": 10, + "content": "workerScope.postMessage(payload);", + "pattern": "Workers", + "match": "postMessage(" + }, + { + "file": "js/nostr/nip04WorkerClient.js", + "line": 49, + "content": "function ensureWorker() {", + "pattern": "Workers", + "match": "Worker(" + }, + { + "file": "js/nostr/nip04WorkerClient.js", + "line": 59, + "content": "workerInstance = new Worker(new URL(\"./nip04Worker.js\", import.meta.url), {", + "pattern": "Workers", + "match": "new Worker" + }, + { + "file": "js/nostr/nip04WorkerClient.js", + "line": 71, + "content": "export function encryptNip04InWorker({", + "pattern": "Workers", + "match": "Worker(" + }, + { + "file": "js/nostr/nip04WorkerClient.js", + "line": 77, + "content": "const worker = ensureWorker();", + "pattern": "Workers", + "match": "Worker(" + }, + { + "file": "js/nostr/nip04WorkerClient.js", + "line": 95, + "content": "const timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/nip04WorkerClient.js", + "line": 101, + "content": "worker.postMessage({", + "pattern": "Workers", + "match": "postMessage(" + }, + { + "file": "js/nostr/nip07Permissions.js", + "line": 237, + "content": "timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/nip07Permissions.js", + "line": 254, + "content": "return Promise.race([operationPromise, timeoutPromise]).finally(() => {", + "pattern": "Promise Concurrency", + "match": "Promise.race" + }, + { + "file": "js/nostr/nip07Permissions.js", + "line": 422, + "content": "const interval = setInterval(() => {", + "pattern": "Timeouts/Intervals", + "match": "setInterval" + }, + { + "file": "js/nostr/nip46Client.js", + "line": 29, + "content": "publishEventToRelays as defaultPublishEventToRelays,", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/nostr/nip46Client.js", + "line": 1292, + "content": "publishEventToRelays = defaultPublishEventToRelays,", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/nostr/nip46Client.js", + "line": 1308, + "content": "this.publishEventToRelays =", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/nostr/nip46Client.js", + "line": 1309, + "content": "typeof publishEventToRelays === \"function\"", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/nostr/nip46Client.js", + "line": 1310, + "content": "? publishEventToRelays", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/nostr/nip46Client.js", + "line": 1692, + "content": "const timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/nip46Client.js", + "line": 1721, + "content": "const publishResults = await this.publishEventToRelays(", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/nostr/nip46Client.js", + "line": 1759, + "content": "await new Promise((r) => setTimeout(r, backoffMs));", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/nip46Connector.js", + "line": 323, + "content": "const timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/nip46Queue.js", + "line": 49, + "content": "await new Promise((r) => setTimeout(r, waitMs));", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/nip71.js", + "line": 17, + "content": "import { extractBtihFromMagnet, extractMagnetHints } from \"../magnetShared.js\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/nip71.js", + "line": 1424, + "content": "* Handles parsing of `content` JSON, extraction of magnet links, info hashes,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/nip71.js", + "line": 1451, + "content": "const directMagnetRaw = safeTrim(parsedContent.magnet);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/nip71.js", + "line": 1461, + "content": "if (trimmed.toLowerCase().startsWith(\"magnet:?\")) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/nip71.js", + "line": 1467, + "content": "let magnet = normalizeMagnetCandidate(directMagnetRaw);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/nip71.js", + "line": 1468, + "content": "let rawMagnet = magnet ? directMagnetRaw : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/nip71.js", + "line": 1472, + "content": "if (!url && !magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/nip71.js", + "line": 1518, + "content": "if (!infoHash && magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/nip71.js", + "line": 1519, + "content": "const extracted = extractBtihFromMagnet(magnet);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/nip71.js", + "line": 1558, + "content": "const magnetHints = magnet", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/nip71.js", + "line": 1559, + "content": "? extractMagnetHints(magnet)", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/nip71.js", + "line": 1561, + "content": "const ws = wsField || magnetHints.ws || \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/nip71.js", + "line": 1562, + "content": "const xs = xsField || magnetHints.xs || \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/nip71.js", + "line": 1578, + "content": "magnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/publishHelpers.js", + "line": 3, + "content": "publishEventToRelays,", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/nostr/publishHelpers.js", + "line": 27, + "content": "import { queueSignEvent } from \"./signRequestQueue.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/nostr/publishHelpers.js", + "line": 383, + "content": "signedEvent = await queueSignEvent(signer, event, {", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/nostr/publishHelpers.js", + "line": 464, + "content": "const publishResults = await publishEventToRelays(", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/nostr/publishHelpers.js", + "line": 1032, + "content": "let magnet = sanitize(options.magnet);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/publishHelpers.js", + "line": 1033, + "content": "if (!magnet && cachedVideo?.magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/publishHelpers.js", + "line": 1034, + "content": "magnet = sanitize(cachedVideo.magnet);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/publishHelpers.js", + "line": 1036, + "content": "if (!magnet && cachedVideo?.rawMagnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/publishHelpers.js", + "line": 1037, + "content": "magnet = sanitize(cachedVideo.rawMagnet);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/publishHelpers.js", + "line": 1039, + "content": "if (!magnet && cachedVideo?.originalMagnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/publishHelpers.js", + "line": 1040, + "content": "magnet = sanitize(cachedVideo.originalMagnet);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/publishHelpers.js", + "line": 1100, + "content": "if (!isPrivate && magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/publishHelpers.js", + "line": 1101, + "content": "tags.push([\"magnet\", magnet]);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/publishHelpers.js", + "line": 1331, + "content": "const publishResults = await publishEventToRelays(client?.pool, relays, rawEvent);", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/nostr/publishHelpers.js", + "line": 1391, + "content": "magnet: \"\",", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/reactionEvents.js", + "line": 11, + "content": "import { queueSignEvent } from \"./signRequestQueue.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/nostr/reactionEvents.js", + "line": 149, + "content": "if (!pool || typeof pool.list !== \"function\") {", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/reactionEvents.js", + "line": 163, + "content": "if (!pool || typeof pool.list !== \"function\") {", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/reactionEvents.js", + "line": 225, + "content": "const events = await pool.list([url], relayFilters);", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/reactionEvents.js", + "line": 452, + "content": "signedEvent = await queueSignEvent(signer, event, {", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/nostr/relayBatchFetcher.js", + "line": 83, + "content": ": (r, f, timeout) => pool.list([r], [f], { timeout });", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/relayBatchFetcher.js", + "line": 206, + "content": "const chunkResults = await Promise.all(promises);", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/nostr/signRequestQueue.js", + "line": 88, + "content": "timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/signRequestQueue.js", + "line": 96, + "content": "return Promise.race([signPromise, timeoutPromise]).finally(() => {", + "pattern": "Promise Concurrency", + "match": "Promise.race" + }, + { + "file": "js/nostr/signRequestQueue.js", + "line": 108, + "content": "export async function queueSignEvent(signer, event, options = {}) {", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/nostr/toolkit.js", + "line": 539, + "content": "if (typeof pool.list !== \"function\") {", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/toolkit.js", + "line": 540, + "content": "pool.list = async function legacyList(relays, filters, opts = {}) {", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/toolkit.js", + "line": 586, + "content": "timer = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/toolkit.js", + "line": 587, + "content": "devLogger.warn(`[toolkit] pool.list timed out after ${timeoutMs}ms.`);", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/videoEventBuffer.js", + "line": 29, + "content": "document.addEventListener(\"visibilitychange\", this.handleVisibilityChange);", + "pattern": "Visibility", + "match": "visibilitychange" + }, + { + "file": "js/nostr/videoEventBuffer.js", + "line": 62, + "content": "this.flushTimerId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/videoEventBuffer.js", + "line": 150, + "content": "if (typeof document !== \"undefined\" && document.hidden) {", + "pattern": "Visibility", + "match": "document.hidden" + }, + { + "file": "js/nostr/videoEventBuffer.js", + "line": 177, + "content": "if (typeof document !== \"undefined\" && !document.hidden) {", + "pattern": "Visibility", + "match": "document.hidden" + }, + { + "file": "js/nostr/videoEventBuffer.js", + "line": 213, + "content": "document.removeEventListener(\"visibilitychange\", this.handleVisibilityChange);", + "pattern": "Visibility", + "match": "visibilitychange" + }, + { + "file": "js/nostr/videoPayloadBuilder.js", + "line": 2, + "content": "import { infoHashFromMagnet } from \"../magnets.js\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/videoPayloadBuilder.js", + "line": 56, + "content": "const rawMagnet = typeof videoData.magnet === \"string\" ? videoData.magnet : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/videoPayloadBuilder.js", + "line": 132, + "content": "magnet: finalMagnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/videoPayloadBuilder.js", + "line": 286, + "content": "magnet: finalMagnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/videoPayloadBuilder.js", + "line": 324, + "content": ": typeof baseEvent.magnet === \"string\"", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/videoPayloadBuilder.js", + "line": 325, + "content": "? baseEvent.magnet.trim()", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/videoPayloadBuilder.js", + "line": 336, + "content": "// Use the new magnet if provided; otherwise, fall back to the decrypted old magnet", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/videoPayloadBuilder.js", + "line": 337, + "content": "const magnetEdited = updatedData.magnetEdited === true;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/videoPayloadBuilder.js", + "line": 339, + "content": "typeof updatedData.magnet === \"string\" ? updatedData.magnet.trim() : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/videoPayloadBuilder.js", + "line": 340, + "content": "const finalMagnet = magnetEdited ? newMagnetValue : oldMagnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/videoPayloadBuilder.js", + "line": 414, + "content": "magnet: finalMagnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/videoPublisher.js", + "line": 116, + "content": "magnet: contentObject.magnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostr/viewEvents.js", + "line": 16, + "content": "import { queueSignEvent } from \"./signRequestQueue.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/nostr/viewEvents.js", + "line": 357, + "content": "const canQueryPool = pool && typeof pool.list === \"function\";", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/viewEvents.js", + "line": 394, + "content": "rawResults = await pool.list(relayList, filters);", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/viewEvents.js", + "line": 641, + "content": "? await Promise.race([listPromise, abortPromise])", + "pattern": "Promise Concurrency", + "match": "Promise.race" + }, + { + "file": "js/nostr/viewEvents.js", + "line": 811, + "content": "signedEvent = await queueSignEvent(signer, event, {", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/nostr/viewEvents.js", + "line": 847, + "content": "const publishResults = await Promise.all(", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/nostr/watchHistory.js", + "line": 17, + "content": "import { publishEventToRelays } from \"../nostrPublish.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/nostr/watchHistory.js", + "line": 26, + "content": "import { queueSignEvent } from \"./signRequestQueue.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/nostr/watchHistory.js", + "line": 983, + "content": "const timer = setTimeout(async () => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostr/watchHistory.js", + "line": 1324, + "content": "return queueSignEvent(activeSigner, event, {", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/nostr/watchHistory.js", + "line": 1463, + "content": "const publishResults = await publishEventToRelays(", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/nostr/watchHistory.js", + "line": 1847, + "content": "const results = await pool.list(readRelays, filters);", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostr/watchHistory.js", + "line": 1906, + "content": "const results = await pool.list(readRelays, [", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/nostrEventSchemas.js", + "line": 286, + "content": "{ key: \"magnet\", type: \"string\", required: false },", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/nostrPublish.js", + "line": 79, + "content": "const timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostrPublish.js", + "line": 157, + "content": "export function publishEventToRelays(pool, urls, event, options = {}) {", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/nostrPublish.js", + "line": 169, + "content": "return Promise.all(promises);", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/nostrToolsBootstrap.js", + "line": 133, + "content": "timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/nostrToolsBootstrap.js", + "line": 397, + "content": "const dynamicResults = await Promise.allSettled([", + "pattern": "Promise Concurrency", + "match": "Promise.allSettled" + }, + { + "file": "js/payments/nwcClient.js", + "line": 807, + "content": "timeoutId: setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/payments/nwcClient.js", + "line": 1323, + "content": "entry.timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/payments/platformAddress.js", + "line": 256, + "content": "const events = await pool.list(relayUrls, [", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/payments/zapNotifications.js", + "line": 231, + "content": "doc?.defaultView?.setTimeout ||", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/payments/zapNotifications.js", + "line": 232, + "content": "(typeof setTimeout === \"function\" ? setTimeout : null);", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/payments/zapReceiptValidator.js", + "line": 345, + "content": "if (!pool || typeof pool.list !== \"function\") {", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/payments/zapReceiptValidator.js", + "line": 366, + "content": "events = await pool.list(relayUrls, filters);", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/payments/zapRequests.js", + "line": 11, + "content": "import { publishEventToRelays, assertAnyRelayAccepted } from \"../nostrPublish.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/payments/zapRequests.js", + "line": 12, + "content": "import { queueSignEvent } from \"../nostr/signRequestQueue.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/payments/zapRequests.js", + "line": 108, + "content": "return queueSignEvent(signer, event, { timeoutMs });", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/payments/zapRequests.js", + "line": 114, + "content": "const publishResults = await publishEventToRelays(pool, publishTargets, signedEvent);", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/playbackUtils.js", + "line": 6, + "content": "} from \"./magnetUtils.js\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 9, + "content": "const MAGNET_URI = /^magnet:\\?/i;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 12, + "content": "* Normalizes torrent related playback inputs into a canonical magnet payload.", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/playbackUtils.js", + "line": 14, + "content": "* The function first trims and safely decodes the incoming `magnet` string so", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 15, + "content": "* that URL encoded magnets become plain text before processing. Bare info hash", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 17, + "content": "* the `infoHash` field or a magnet that looks like one) it gets promoted to a", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 18, + "content": "* full magnet URI so downstream WebTorrent code can consume it directly.", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 20, + "content": "* When the normalized output differs from the original magnet input (for", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 23, + "content": "* that value if a later refactor breaks magnet normalization.", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 26, + "content": "* torrent-related input was supplied, while `usedInfoHash` is only `true` when", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/playbackUtils.js", + "line": 27, + "content": "* the normalized magnet was derived from an info hash instead of an already", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 28, + "content": "* well-formed magnet URI.", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 36, + "content": "magnet = \"\",", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 42, + "content": "const trimmedMagnet = typeof magnet === \"string\" ? magnet.trim() : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 44, + "content": "const magnetCandidate = decodedMagnet || trimmedMagnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 49, + "content": "const magnetIsUri = MAGNET_URI.test(magnetCandidate);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 50, + "content": "const magnetLooksLikeInfoHash = HEX_INFO_HASH.test(magnetCandidate);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 51, + "content": "const resolvedInfoHash = trimmedInfoHash || (magnetLooksLikeInfoHash", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 52, + "content": "? magnetCandidate.toLowerCase()", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 55, + "content": "const normalizationInput = magnetIsUri ? magnetCandidate : resolvedInfoHash;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 57, + "content": "const decodeChanged = magnetCandidate !== trimmedMagnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 61, + "content": "magnet: \"\",", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 77, + "content": "let normalizedMagnet = normalization.magnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 79, + "content": "if (magnetIsUri) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 82, + "content": "normalizedMagnet = `magnet:?xt=urn:btih:${resolvedInfoHash}`;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 88, + "content": "const usedInfoHash = !magnetIsUri && Boolean(resolvedInfoHash);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 89, + "content": "const fallbackMagnet = magnetIsUri && normalization.didChange", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/playbackUtils.js", + "line": 94, + "content": "magnet: normalizedMagnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/reactionCounter.js", + "line": 485, + "content": "if (!pool || typeof pool.list !== \"function\") {", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/reactionCounter.js", + "line": 510, + "content": "events = await query.pool.list(query.relays, query.filters);", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/relayManager.js", + "line": 11, + "content": "publishEventToRelays,", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/relayManager.js", + "line": 523, + "content": "const timer = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/relayManager.js", + "line": 538, + "content": ".then(() => nostrClient.pool.list([relayUrl], [filter]))", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/relayManager.js", + "line": 583, + "content": "const background = Promise.allSettled([", + "pattern": "Promise Concurrency", + "match": "Promise.allSettled" + }, + { + "file": "js/relayManager.js", + "line": 601, + "content": "`[relayManager] Relay ${reason.relay} timed out while loading relay list (${reason.timeoutMs}ms)`", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/relayManager.js", + "line": 604, + "content": "`[relayManager] Relay ${reason?.relay || \"unknown\"} failed while loading relay list:`,", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/relayManager.js", + "line": 617, + "content": "devLogger.warn(\"[relayManager] Background relay refresh failed\", error);", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/relayManager.js", + "line": 623, + "content": "fastResult = await Promise.any(fastPromises);", + "pattern": "Promise Concurrency", + "match": "Promise.any" + }, + { + "file": "js/relayManager.js", + "line": 629, + "content": "`[relayManager] Relay ${err.relay} timed out while loading relay list (${err.timeoutMs}ms)`", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/relayManager.js", + "line": 633, + "content": "} else devLogger.warn(\"[relayManager] Fast relay fetch failed\", error);", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/relayManager.js", + "line": 713, + "content": "const publishResults = await publishEventToRelays(", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/relayManager.js", + "line": 714, + "content": "nostrClient.pool,", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/relayManager.js", + "line": 770, + "content": "export const relayManager = new RelayPreferencesManager();", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/search/searchFilterMatchers.js", + "line": 55, + "content": "if (hasMagnet && !video.magnet) return false;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/search/searchFilters.js", + "line": 243, + "content": "if (normalizedValue === \"magnet\") {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/search/searchFilters.js", + "line": 248, + "content": "errors.push({ token, message: \"Has filter supports magnet or url.\" });", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/search/searchFilters.js", + "line": 319, + "content": "tokens.push(\"has:magnet\");", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/searchView.js", + "line": 180, + "content": "\"Results matching your search query. Use tokens like author:, tag:, kind:, relay:, after:, before:, duration:<, and has:magnet/url.\"", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/searchView.js", + "line": 374, + "content": "label: \"Has magnet\",", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/searchView.js", + "line": 495, + "content": "isMagnetSupported: (magnet) => magnet && magnet.startsWith(\"magnet:\"),", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/searchView.js", + "line": 500, + "content": "unsupportedBtihMessage: \"Unsupported magnet link\"", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/searchView.js", + "line": 514, + "content": "magnet: video.magnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/searchView.js", + "line": 520, + "content": "magnet: video.magnet", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/searchView.js", + "line": 590, + "content": "if (nostrClient && nostrClient.pool) {", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/searchView.js", + "line": 600, + "content": "const events = await nostrClient.pool.list(relays, [filter]);", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/searchView.js", + "line": 686, + "content": "if (relays.length > 0 && nostrClient.pool) {", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/searchView.js", + "line": 699, + "content": "const events = await nostrClient.pool.list(relays, [filter]);", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/services/authService.js", + "line": 1, + "content": "// js/services/authService.js", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/services/authService.js", + "line": 53, + "content": "relayManager,", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/services/authService.js", + "line": 61, + "content": "this.relayManager = relayManager || null;", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/services/authService.js", + "line": 129, + "content": "hydrateFromStorage() {", + "pattern": "Nostr/Relay/Auth", + "match": "hydrateFromStorage" + }, + { + "file": "js/services/authService.js", + "line": 751, + "content": "if (this.relayManager && typeof this.relayManager.loadRelayList === \"function\") {", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/services/authService.js", + "line": 754, + "content": "promise: schedule(() => this.relayManager.loadRelayList(activePubkey)),", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/services/authService.js", + "line": 803, + "content": "await Promise.allSettled(concurrentOps.map(runOperation));", + "pattern": "Promise Concurrency", + "match": "Promise.allSettled" + }, + { + "file": "js/services/authService.js", + "line": 902, + "content": "if (this.relayManager && typeof this.relayManager.reset === \"function\") {", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/services/authService.js", + "line": 904, + "content": "this.relayManager.reset();", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/services/authService.js", + "line": 906, + "content": "this.log(\"[AuthService] relayManager.reset threw\", error);", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/services/authService.js", + "line": 1026, + "content": "const fetchPromise = this.nostrClient.pool.list([relayUrl], filter);", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/services/authService.js", + "line": 1030, + "content": "timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/services/authService.js", + "line": 1042, + "content": "const result = await Promise.race([fetchPromise, timeoutPromise]);", + "pattern": "Promise Concurrency", + "match": "Promise.race" + }, + { + "file": "js/services/authService.js", + "line": 1152, + "content": "const background = Promise.all([", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/services/authService.js", + "line": 1153, + "content": "Promise.allSettled(fastPromises),", + "pattern": "Promise Concurrency", + "match": "Promise.allSettled" + }, + { + "file": "js/services/authService.js", + "line": 1211, + "content": "fastResult = await Promise.any(fastPromises);", + "pattern": "Promise Concurrency", + "match": "Promise.any" + }, + { + "file": "js/services/commentThreadService.js", + "line": 882, + "content": "this.profileHydrationTimer = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/services/commentThreadService.js", + "line": 930, + "content": "await new Promise((resolve) => setTimeout(resolve, backoffMs));", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/services/dmNostrService.js", + "line": 74, + "content": "timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/services/dmNostrService.js", + "line": 83, + "content": "return Promise.race([promise, timeoutPromise]).finally(() => {", + "pattern": "Promise Concurrency", + "match": "Promise.race" + }, + { + "file": "js/services/dmNostrService.js", + "line": 121, + "content": "typeof pool.list === \"function\" &&", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/services/dmNostrService.js", + "line": 126, + "content": "pool.list(discoveryList, [", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/services/dmNostrService.js", + "line": 398, + "content": "const timer = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/services/exploreDataService.js", + "line": 9, + "content": "function getWorker() {", + "pattern": "Workers", + "match": "Worker(" + }, + { + "file": "js/services/exploreDataService.js", + "line": 11, + "content": "workerInstance = new Worker(new URL(\"../workers/exploreData.worker.js\", import.meta.url), { type: \"module\" });", + "pattern": "Workers", + "match": "new Worker" + }, + { + "file": "js/services/exploreDataService.js", + "line": 18, + "content": "const worker = getWorker();", + "pattern": "Workers", + "match": "Worker(" + }, + { + "file": "js/services/exploreDataService.js", + "line": 31, + "content": "worker.postMessage({ type, id, payload });", + "pattern": "Workers", + "match": "postMessage(" + }, + { + "file": "js/services/exploreDataService.js", + "line": 154, + "content": "document.addEventListener(\"visibilitychange\", this.handleVisibility);", + "pattern": "Visibility", + "match": "visibilitychange" + }, + { + "file": "js/services/exploreDataService.js", + "line": 161, + "content": "if (document.hidden) {", + "pattern": "Visibility", + "match": "document.hidden" + }, + { + "file": "js/services/exploreDataService.js", + "line": 173, + "content": "this.watchHistoryInterval = setInterval(() => {", + "pattern": "Timeouts/Intervals", + "match": "setInterval" + }, + { + "file": "js/services/exploreDataService.js", + "line": 178, + "content": "this.tagIdfInterval = setInterval(() => {", + "pattern": "Timeouts/Intervals", + "match": "setInterval" + }, + { + "file": "js/services/exploreDataService.js", + "line": 232, + "content": "this.watchHistoryRefreshHandle = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/services/exploreDataService.js", + "line": 242, + "content": "this.tagIdfRefreshHandle = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/services/exploreDataService.js", + "line": 324, + "content": "document.removeEventListener(\"visibilitychange\", this.handleVisibility);", + "pattern": "Visibility", + "match": "visibilitychange" + }, + { + "file": "js/services/hashtagPreferencesService.js", + "line": 14, + "content": "publishEventToRelays,", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/services/hashtagPreferencesService.js", + "line": 22, + "content": "import { relayManager } from \"../relayManager.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/services/hashtagPreferencesService.js", + "line": 342, + "content": "pool: nostrClient.pool,", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/services/hashtagPreferencesService.js", + "line": 528, + "content": "this.decryptRetryTimeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/services/hashtagPreferencesService.js", + "line": 623, + "content": "!nostrClient.pool ||", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/services/hashtagPreferencesService.js", + "line": 624, + "content": "typeof nostrClient.pool.list !== \"function\"", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/services/hashtagPreferencesService.js", + "line": 627, + "content": "`${LOG_PREFIX} nostrClient.pool.list unavailable; treating preferences as empty.`,", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/services/hashtagPreferencesService.js", + "line": 648, + "content": "const readRelays = relayManager.getReadRelayUrls();", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/services/hashtagPreferencesService.js", + "line": 713, + "content": "const results = await Promise.all(promises);", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/services/hashtagPreferencesService.js", + "line": 845, + "content": "timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/services/hashtagPreferencesService.js", + "line": 854, + "content": "decryptResult = await Promise.race([decryptPromise, timeoutPromise]);", + "pattern": "Promise Concurrency", + "match": "Promise.race" + }, + { + "file": "js/services/hashtagPreferencesService.js", + "line": 1198, + "content": "// PERF: Try all decryption schemes in parallel via Promise.any().", + "pattern": "Promise Concurrency", + "match": "Promise.any" + }, + { + "file": "js/services/hashtagPreferencesService.js", + "line": 1231, + "content": "const result = await Promise.any(attempts);", + "pattern": "Promise Concurrency", + "match": "Promise.any" + }, + { + "file": "js/services/hashtagPreferencesService.js", + "line": 1403, + "content": "const publishResults = await publishEventToRelays(", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/services/hashtagPreferencesService.js", + "line": 1404, + "content": "nostrClient.pool,", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/services/moderationService.js", + "line": 22, + "content": "import { publishEventToRelays, assertAnyRelayAccepted } from \"../nostrPublish.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/services/moderationService.js", + "line": 1145, + "content": "this.muteRefreshTimer = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/services/moderationService.js", + "line": 1198, + "content": "const sub = this.nostrClient.pool.sub(relays, [filter]);", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/services/moderationService.js", + "line": 1874, + "content": "events = await this.nostrClient.pool.list(relays, [filter]);", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/services/moderationService.js", + "line": 1970, + "content": "const sub = this.nostrClient.pool.sub(relays, [filter]);", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/services/moderationService.js", + "line": 2018, + "content": "await Promise.all(tasks);", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/services/moderationService.js", + "line": 2080, + "content": "events = await this.nostrClient.pool.list(relays, [filter]);", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/services/moderationService.js", + "line": 2093, + "content": "const sub = this.nostrClient.pool.sub(relays, [filter]);", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/services/moderationService.js", + "line": 2523, + "content": "results = await publishEventToRelays(this.nostrClient.pool, relays, signedEvent);", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/services/nostrService.js", + "line": 20, + "content": "import { getDmDecryptWorkerQueueSize } from \"../nostr/dmDecryptWorkerClient.js\";", + "pattern": "Workers", + "match": "getDmDecryptWorkerQueueSize" + }, + { + "file": "js/services/nostrService.js", + "line": 713, + "content": "workerQueueSize: getDmDecryptWorkerQueueSize(),", + "pattern": "Workers", + "match": "getDmDecryptWorkerQueueSize" + }, + { + "file": "js/services/nostrService.js", + "line": 1802, + "content": "await Promise.all(", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/services/nostrService.js", + "line": 1806, + "content": "const events = await this.nostrClient.pool.list([url], [filter]);", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/services/nostrService.js", + "line": 1946, + "content": "const events = await this.nostrClient.pool.list(this.nostrClient.relays, [filter]);", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/services/playbackService.js", + "line": 11, + "content": "* falling back to a WebTorrent (P2P) stream if the URL is unreachable or stalls.", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/services/playbackService.js", + "line": 18, + "content": "* stalls, it seamlessly triggers the P2P engine (WebTorrent).", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/services/playbackService.js", + "line": 66, + "content": "\"This magnet link is missing a compatible BitTorrent v1 info hash.\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 73, + "content": "const extractWebSeedsFromMagnet = (magnetUri) => {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 74, + "content": "if (typeof magnetUri !== \"string\") {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 77, + "content": "const trimmed = magnetUri.trim();", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 121, + "content": "\"Hosted URL timed out. We’ll try WebTorrent if available.\",", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/services/playbackService.js", + "line": 173, + "content": "\"Hosted URL blocked by browser security (CORS/SSL). We’ll try WebTorrent if available.\",", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/services/playbackService.js", + "line": 192, + "content": "\"Hosted URL blocked by CORS. We’ll try WebTorrent if available.\",", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/services/playbackService.js", + "line": 244, + "content": "return \"WebTorrent could not start. Please try again.\";", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/services/playbackService.js", + "line": 251, + "content": "return \"WebTorrent could not reach any peers or trackers.\";", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/services/playbackService.js", + "line": 254, + "content": "return \"WebTorrent was blocked by the browser or network.\";", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/services/playbackService.js", + "line": 256, + "content": "return \"WebTorrent could not start. Please try again.\";", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/services/playbackService.js", + "line": 262, + "content": "torrentClient,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 277, + "content": "this.torrentClient = torrentClient;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 324, + "content": "getProbeCacheKey({ url, magnet }) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 326, + "content": "const trimmedMagnet = typeof magnet === \"string\" ? magnet.trim() : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 355, + "content": "async probeHostedUrl({ url, magnet, probeUrl } = {}) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 362, + "content": "magnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 493, + "content": "stallTimerId = setTimeout(() => triggerFallback(\"stall\"), normalizedStallMs);", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/services/playbackService.js", + "line": 556, + "content": "* 4. Falling back to WebTorrent if needed.", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/services/playbackService.js", + "line": 558, + "content": "* It uses a `requestSignature` (JSON of url+magnet) to uniquely identify the request.", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 576, + "content": "typeof options.magnet === \"string\" ? options.magnet.trim() : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 585, + "content": "magnet: this.trimmedMagnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 590, + "content": "magnet: this.trimmedMagnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 597, + "content": "magnet: this.trimmedMagnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 607, + "content": "const magnetIsUsable =", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 609, + "content": "? service.isValidMagnetUri(this.playbackConfig.magnet)", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 612, + "content": "this.magnetForPlayback = magnetIsUsable", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 613, + "content": "? this.playbackConfig.magnet", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 615, + "content": "this.fallbackMagnet = magnetIsUsable", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 618, + "content": "this.magnetProvided = !!this.playbackConfig.provided;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 644, + "content": "return this.magnetForPlayback;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 652, + "content": "return this.magnetProvided;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 759, + "content": "playViaWebTorrent,", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/services/playbackService.js", + "line": 771, + "content": "magnetProvided: this.magnetProvided,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 772, + "content": "magnetUsable: !!this.magnetForPlayback,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 802, + "content": "this.service.torrentClient &&", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 803, + "content": "typeof this.service.torrentClient.cleanup === \"function\"", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 805, + "content": "await this.service.torrentClient.cleanup();", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 848, + "content": "const magnetWebSeeds = extractWebSeedsFromMagnet(this.magnetForPlayback);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 849, + "content": "if (magnetWebSeeds.length > 0) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 850, + "content": "magnetWebSeeds.forEach((seed) => addWebSeedCandidate(seed));", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 882, + "content": "let torrentAttempted = false;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 884, + "content": "if (torrentAttempted) return null;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 885, + "content": "torrentAttempted = true;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 892, + "content": "if (!this.magnetForPlayback) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 893, + "content": "// No magnet available to try", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 897, + "content": "this.emit(\"status\", { message: \"Switching to WebTorrent...\" });", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/services/playbackService.js", + "line": 901, + "content": "if (typeof playViaWebTorrent !== \"function\") {", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/services/playbackService.js", + "line": 902, + "content": "throw new Error(\"No torrent playback handler provided.\");", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 905, + "content": "let torrentInstance;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 907, + "content": "torrentInstance = await playViaWebTorrent(this.magnetForPlayback, {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 919, + "content": "this.service.handleAnalyticsEvent(\"sourcechange\", { source: \"torrent\" });", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 920, + "content": "this.emit(\"sourcechange\", { source: \"torrent\" });", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 925, + "content": "const result = { source: \"torrent\", torrentInstance };", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 994, + "content": "magnet: this.trimmedMagnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 1136, + "content": "const timer = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/services/playbackService.js", + "line": 1157, + "content": "if (forcedSource === \"torrent\") tryUrlFirst = false;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 1189, + "content": "if (this.magnetForPlayback && forcedSource !== \"url\") {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 1192, + "content": "} else if (this.magnetForPlayback && forcedSource !== \"url\") {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 1197, + "content": "if (this.magnetForPlayback) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackService.js", + "line": 1201, + "content": "const torrentTimeout = httpsUrl ? effectiveTimeout : 0;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 1204, + "content": "const torrentResult = await withTimeout(", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 1206, + "content": "torrentTimeout,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 1210, + "content": "if (torrentResult && torrentResult.source === \"torrent\") {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 1211, + "content": "return torrentResult;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 1214, + "content": "if (torrentResult?.reason === \"timeout\") {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 1219, + "content": "this.service.torrentClient &&", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 1220, + "content": "typeof this.service.torrentClient.cleanup === \"function\"", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 1222, + "content": "await this.service.torrentClient.cleanup();", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 1232, + "content": "this.service.torrentClient &&", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 1233, + "content": "typeof this.service.torrentClient.cleanup === \"function\"", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 1235, + "content": "await this.service.torrentClient.cleanup();", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 1242, + "content": "if (httpsUrl && forcedSource !== \"torrent\") {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackService.js", + "line": 1256, + "content": "(this.magnetProvided && !this.magnetForPlayback", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 32, + "content": "* @param {object} options - Playback options (url, magnet, trigger, forcedSource).", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 37, + "content": "const { url = \"\", magnet = \"\", trigger, forcedSource } = options || {};", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 40, + "content": "method: forcedSource || (magnet ? \"webtorrent\" : \"url\"), // heuristic", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 43, + "content": "magnet: Boolean(magnet),", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 54, + "content": "const trimmedMagnet = typeof magnet === \"string\" ? magnet.trim() : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 58, + "content": "magnet: trimmedMagnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 107, + "content": "previousSource === \"torrent\" &&", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 110, + "content": "this.playbackService.torrentClient &&", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 111, + "content": "typeof this.playbackService.torrentClient.cleanup === \"function\"", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 114, + "content": "this.log(\"Previous playback used WebTorrent; cleaning up before preparing hosted session.\");", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 115, + "content": "await this.playbackService.torrentClient.cleanup();", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 117, + "content": "this.log(\"Pre-playback torrent cleanup threw:\", error);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 199, + "content": "magnet: trimmedMagnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 208, + "content": "playViaWebTorrent: context.playViaWebTorrent,", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 232, + "content": "const magnetForPlayback = session.getMagnetForPlayback();", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 234, + "content": "// const magnetProvided = session.getMagnetProvided();", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 238, + "content": "magnet: magnetForPlayback,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 239, + "content": "normalizedMagnet: magnetForPlayback,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 242, + "content": "torrentSupported: !!magnetForPlayback", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 246, + "content": "// this.currentMagnetUri = magnetForPlayback || null; // Logic is in context if needed", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/playbackStrategyService.js", + "line": 285, + "content": "const usingTorrent = source === \"torrent\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/profileMetadataService.js", + "line": 90, + "content": "if (!nostr?.pool || typeof nostr.pool.list !== \"function\") {", + "pattern": "Nostr/Relay/Auth", + "match": "pool.list" + }, + { + "file": "js/services/profileMetadataService.js", + "line": 109, + "content": "const results = await Promise.allSettled(", + "pattern": "Promise Concurrency", + "match": "Promise.allSettled" + }, + { + "file": "js/services/profileMetadataService.js", + "line": 235, + "content": "await Promise.all([...waiters, batchPromise].filter(Boolean));", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/services/r2Service.js", + "line": 11, + "content": "* 2. A `.torrent` file is generated and uploaded alongside the video.", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/r2Service.js", + "line": 13, + "content": "* torrent file as a metadata source (`xs=`).", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/r2Service.js", + "line": 51, + "content": "import { calculateTorrentInfoHash } from \"../utils/torrentHash.js\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/r2Service.js", + "line": 675, + "content": "await new Promise((r) => setTimeout(r, 500));", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/services/r2Service.js", + "line": 788, + "content": "* - `xs`: The Exact Source URL (link to the .torrent file on R2).", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/r2Service.js", + "line": 799, + "content": "torrentFile = null,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/r2Service.js", + "line": 919, + "content": "return `${baseKey}.torrent`;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/r2Service.js", + "line": 921, + "content": "return `${key}.torrent`;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/r2Service.js", + "line": 973, + "content": "let torrentUrl = forcedTorrentUrl || \"\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/r2Service.js", + "line": 975, + "content": "if (torrentFile) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/r2Service.js", + "line": 976, + "content": "this.setCloudflareUploadStatus(\"Uploading torrent metadata...\", \"info\");", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/r2Service.js", + "line": 977, + "content": "const torrentKey = buildTorrentKey();", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/r2Service.js", + "line": 982, + "content": "key: torrentKey,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/r2Service.js", + "line": 983, + "content": "file: torrentFile,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/r2Service.js", + "line": 984, + "content": "contentType: \"application/x-bittorrent\",", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/r2Service.js", + "line": 988, + "content": "if (!torrentUrl) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/r2Service.js", + "line": 989, + "content": "torrentUrl = buildPublicUrl(bucketEntry.publicBaseUrl, torrentKey);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/r2Service.js", + "line": 1005, + "content": "// - `ws` (WebSeed): The direct R2 URL. WebTorrent clients use this to \"seed\"", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/services/r2Service.js", + "line": 1007, + "content": "// - `xs` (eXact Source): The URL to the .torrent file on R2. This allows", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/r2Service.js", + "line": 1016, + "content": "let magnet = `magnet:?xt=urn:btih:${normalizedInfoHash}&dn=${encodedDn}&ws=${encodedWs}`;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/r2Service.js", + "line": 1020, + "content": "if (torrentUrl) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/r2Service.js", + "line": 1021, + "content": "const encodedXs = encodeURIComponent(torrentUrl);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/r2Service.js", + "line": 1022, + "content": "magnet += `&xs=${encodedXs}`;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/r2Service.js", + "line": 1025, + "content": "generatedMagnet = magnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/r2Service.js", + "line": 1030, + "content": "\"Invalid info hash provided. Skipping magnet and webseed generation.\",", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/r2Service.js", + "line": 1035, + "content": "\"Info hash missing or invalid. Publishing URL-first without WebTorrent fallback.\",", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/services/r2Service.js", + "line": 1052, + "content": "magnet: generatedMagnet || (metadata?.magnet ?? \"\"),", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/r2Service.js", + "line": 1057, + "content": "xs: torrentUrl || (metadata?.xs ?? \"\"),", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/relayHealthService.js", + "line": 58, + "content": "constructor({ relayManager, nostrClient, logger, telemetryEmitter } = {}) {", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/services/relayHealthService.js", + "line": 59, + "content": "this.relayManager = relayManager || null;", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/services/relayHealthService.js", + "line": 81, + "content": "if (!this.relayManager || typeof this.relayManager.getEntries !== \"function\") {", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/services/relayHealthService.js", + "line": 84, + "content": "const entries = this.relayManager.getEntries();", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/services/relayHealthService.js", + "line": 200, + "content": "if (!this.nostrClient.pool || typeof this.nostrClient.pool.ensureRelay !== \"function\") {", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/services/relayHealthService.js", + "line": 207, + "content": "const relay = await Promise.race([", + "pattern": "Promise Concurrency", + "match": "Promise.race" + }, + { + "file": "js/services/relayHealthService.js", + "line": 208, + "content": "this.nostrClient.pool.ensureRelay(relayUrl),", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/services/relayHealthService.js", + "line": 210, + "content": "setTimeout(", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/services/relayHealthService.js", + "line": 239, + "content": "await Promise.allSettled(urls.map((url) => this.checkRelay(url)));", + "pattern": "Promise Concurrency", + "match": "Promise.allSettled" + }, + { + "file": "js/services/s3UploadService.js", + "line": 20, + "content": "import { calculateTorrentInfoHash } from \"../utils/torrentHash.js\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/s3UploadService.js", + "line": 222, + "content": "torrentFile = null,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/s3UploadService.js", + "line": 351, + "content": "let torrentUrl = forcedTorrentUrl || \"\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/s3UploadService.js", + "line": 352, + "content": "if (torrentFile) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/s3UploadService.js", + "line": 353, + "content": "this.setUploadStatus(\"Uploading torrent metadata...\", \"info\");", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/s3UploadService.js", + "line": 354, + "content": "const torrentKey =", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/s3UploadService.js", + "line": 359, + "content": "return `${baseKey}.torrent`;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/s3UploadService.js", + "line": 361, + "content": "return `${key}.torrent`;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/s3UploadService.js", + "line": 367, + "content": "key: torrentKey,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/s3UploadService.js", + "line": 368, + "content": "file: torrentFile,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/s3UploadService.js", + "line": 369, + "content": "contentType: \"application/x-bittorrent\",", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/s3UploadService.js", + "line": 373, + "content": "if (!torrentUrl) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/s3UploadService.js", + "line": 374, + "content": "torrentUrl = this.deps.buildS3ObjectUrl({", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/s3UploadService.js", + "line": 378, + "content": "key: torrentKey,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/s3UploadService.js", + "line": 403, + "content": "let magnet = `magnet:?xt=urn:btih:${normalizedInfoHash}&dn=${encodedDn}&ws=${encodedWs}`;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/s3UploadService.js", + "line": 404, + "content": "if (torrentUrl) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/s3UploadService.js", + "line": 405, + "content": "const encodedXs = encodeURIComponent(torrentUrl);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/s3UploadService.js", + "line": 406, + "content": "magnet += `&xs=${encodedXs}`;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/s3UploadService.js", + "line": 408, + "content": "generatedMagnet = magnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/s3UploadService.js", + "line": 413, + "content": "\"Invalid info hash provided. Skipping magnet generation.\",", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/s3UploadService.js", + "line": 418, + "content": "\"Info hash missing or invalid. Publishing URL-first without WebTorrent fallback.\",", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/services/s3UploadService.js", + "line": 435, + "content": "magnet: generatedMagnet || (metadata?.magnet ?? \"\"),", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/s3UploadService.js", + "line": 440, + "content": "xs: torrentUrl || (metadata?.xs ?? \"\"),", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/services/trustBootstrap.js", + "line": 47, + "content": "return new Promise((resolve) => setTimeout(resolve, ms));", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/services/trustBootstrap.js", + "line": 73, + "content": "setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/services/trustBootstrap.js", + "line": 80, + "content": "await Promise.race([accessControl.waitForReady(), timeoutPromise]);", + "pattern": "Promise Concurrency", + "match": "Promise.race" + }, + { + "file": "js/services/videoNotePayload.js", + "line": 1, + "content": "import { extractMagnetHints } from \"../magnetShared.js\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/videoNotePayload.js", + "line": 2, + "content": "import { normalizeAndAugmentMagnet } from \"../magnetUtils.js\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/videoNotePayload.js", + "line": 3, + "content": "import { infoHashFromMagnet } from \"../magnets.js\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/videoNotePayload.js", + "line": 18, + "content": "\"Provide a hosted URL, magnet link, or an imeta variant before publishing.\",", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/videoNotePayload.js", + "line": 342, + "content": "const magnet = normalizeString(legacyPayload?.magnet || \"\");", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/videoNotePayload.js", + "line": 371, + "content": "magnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/videoNotePayload.js", + "line": 386, + "content": "const hasLegacySource = Boolean(legacyFormData.url || legacyFormData.magnet);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/videoNotePayload.js", + "line": 417, + "content": "if (legacyFormData.magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/videoNotePayload.js", + "line": 426, + "content": "const result = normalizeAndAugmentMagnet(legacyFormData.magnet, {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/videoNotePayload.js", + "line": 430, + "content": "legacyFormData.magnet = result.magnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/videoNotePayload.js", + "line": 431, + "content": "const hints = extractMagnetHints(result.magnet);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/videoNotePayload.js", + "line": 450, + "content": "infoHash || normalizeInfoHash(legacyFormData.magnet) || \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/watchHistoryTelemetry.js", + "line": 19, + "content": "// Transport identifiers (URL, magnet, hashes) are intentionally omitted so", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/services/watchHistoryTelemetry.js", + "line": 323, + "content": "state[idKey] = this._getTimerHost().setTimeout(callback, remainingMs);", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/state/profileCache.js", + "line": 21, + "content": "if (typeof requestIdleCallback !== \"undefined\") {", + "pattern": "Timeouts/Intervals", + "match": "requestIdleCallback" + }, + { + "file": "js/state/profileCache.js", + "line": 22, + "content": "requestIdleCallback(callback);", + "pattern": "Timeouts/Intervals", + "match": "requestIdleCallback" + }, + { + "file": "js/state/profileCache.js", + "line": 24, + "content": "setTimeout(callback, 1);", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/storage/r2-mgmt.js", + "line": 226, + "content": "await new Promise((resolve) => setTimeout(resolve, pollInterval));", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/subscriptions.js", + "line": 14, + "content": "import { relayManager } from \"./relayManager.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/subscriptions.js", + "line": 23, + "content": "publishEventToRelays,", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/subscriptions.js", + "line": 460, + "content": "this.decryptRetryTimeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/subscriptions.js", + "line": 495, + "content": "const readRelays = relayManager.getReadRelayUrls();", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/subscriptions.js", + "line": 569, + "content": "const fetchResults = await Promise.all(fetchPromises);", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/subscriptions.js", + "line": 649, + "content": "setTimeout(", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/subscriptions.js", + "line": 660, + "content": "decryptResult = await Promise.race([decryptPromise, timeoutPromise]);", + "pattern": "Promise Concurrency", + "match": "Promise.race" + }, + { + "file": "js/subscriptions.js", + "line": 851, + "content": "pool: nostrClient.pool,", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/subscriptions.js", + "line": 916, + "content": "await Promise.race([", + "pattern": "Promise Concurrency", + "match": "Promise.race" + }, + { + "file": "js/subscriptions.js", + "line": 919, + "content": "timeoutId = setTimeout(", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/subscriptions.js", + "line": 1215, + "content": "// PERF: Try all decryption schemes in parallel via Promise.any().", + "pattern": "Promise Concurrency", + "match": "Promise.any" + }, + { + "file": "js/subscriptions.js", + "line": 1236, + "content": "// Promise.any() from trying the remaining schemes.", + "pattern": "Promise Concurrency", + "match": "Promise.any" + }, + { + "file": "js/subscriptions.js", + "line": 1250, + "content": "const result = await Promise.any(attempts);", + "pattern": "Promise Concurrency", + "match": "Promise.any" + }, + { + "file": "js/subscriptions.js", + "line": 1489, + "content": "const publishResults = await publishEventToRelays(", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/subscriptions.js", + "line": 1490, + "content": "nostrClient.pool,", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/subscriptions.js", + "line": 2001, + "content": "\"This magnet link is missing a compatible BitTorrent v1 info hash.\"", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/subscriptions.js", + "line": 2043, + "content": "isMagnetSupported: (magnet) =>", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/subscriptions.js", + "line": 2044, + "content": "app?.isMagnetUriSupported?.(magnet) ?? false,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/subscriptions.js", + "line": 2144, + "content": "magnet: detail.magnet", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/subscriptions.js", + "line": 2155, + "content": "app?.playVideoWithFallback?.({ url: detail.url, magnet: detail.magnet })", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/subscriptions.js", + "line": 2352, + "content": "await publishEventToRelays(", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/subscriptions.js", + "line": 2353, + "content": "nostrClient.pool,", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/testHarness.js", + "line": 177, + "content": "hasMagnet: Boolean(card.getAttribute(\"data-play-magnet\")),", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/testHarness.js", + "line": 202, + "content": "requestAnimationFrame(check);", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/testHarness.js", + "line": 228, + "content": "requestAnimationFrame(check);", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/ui/ModalManager.js", + "line": 71, + "content": "authService: app.authService,", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/ModalManager.js", + "line": 109, + "content": "magnet: (value) => (typeof value === \"string\" ? value.trim() : \"\"),", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/ModalManager.js", + "line": 283, + "content": "\"video:copy-magnet\",", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/ModalManager.js", + "line": 494, + "content": "typeof selectedVideo.magnet === \"string\"", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/ModalManager.js", + "line": 495, + "content": "? selectedVideo.magnet.trim()", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/ModalManager.js", + "line": 498, + "content": "playbackOptions.magnet = rawMagnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/ModalManager.js", + "line": 853, + "content": "eventName = \"video:copy-magnet\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/ambientBackground.js", + "line": 130, + "content": "const requestFrame = win?.requestAnimationFrame?.bind(win) || ((cb) => setTimeout(() => cb(Date.now()), throttleMs));", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/ui/ambientBackground.js", + "line": 295, + "content": "doc.addEventListener(\"visibilitychange\", handleVisibility);", + "pattern": "Visibility", + "match": "visibilitychange" + }, + { + "file": "js/ui/ambientBackground.js", + "line": 315, + "content": "doc.removeEventListener(\"visibilitychange\", handleVisibility);", + "pattern": "Visibility", + "match": "visibilitychange" + }, + { + "file": "js/ui/appChromeController.js", + "line": 319, + "content": "this.document.addEventListener(\"visibilitychange\", this.handleVisibilityChange);", + "pattern": "Visibility", + "match": "visibilitychange" + }, + { + "file": "js/ui/appChromeController.js", + "line": 356, + "content": ".then(() => this.callbacks.flushWatchHistory(\"session-end\", \"visibilitychange\"))", + "pattern": "Visibility", + "match": "visibilitychange" + }, + { + "file": "js/ui/appChromeController.js", + "line": 359, + "content": "this.logger.warn(\"[visibilitychange] Watch history flush failed:\", error);", + "pattern": "Visibility", + "match": "visibilitychange" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 10, + "content": "import AuthService from \"../services/authService.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 27, + "content": "import { relayManager } from \"../relayManager.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 66, + "content": "import { isValidMagnetUri } from \"../utils/magnetValidators.js\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 67, + "content": "import { torrentClient } from \"../webtorrent.js\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 138, + "content": "app.relayManager = relayManager;", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 316, + "content": "torrentClient: this.services.torrentClient || torrentClient,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 327, + "content": "torrentClient: playbackDependencies.torrentClient,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 334, + "content": "const magnetProvided = detail?.magnetProvided ? \"true\" : \"false\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 335, + "content": "const magnetUsable = detail?.magnetUsable ? \"true\" : \"false\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 337, + "content": "`[playVideoWithFallback] Session start urlProvided=${urlProvided} magnetProvided=${magnetProvided} magnetUsable=${magnetUsable}`,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 343, + "content": "`[playVideoWithFallback] Falling back to WebTorrent (${detail.reason}).`,", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 361, + "content": "app.authService =", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 362, + "content": "this.services.authService ||", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 366, + "content": "relayManager,", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 373, + "content": "app.authService.on(\"auth:login\", (detail) => {", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 383, + "content": "app.authService.on(\"auth:logout\", (detail) => {", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 407, + "content": "app.authService.on(\"profile:updated\", (detail) => {", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 419, + "content": "app.authService.on(\"blocksLoaded\", (detail) => {", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 431, + "content": "app.authService.on(\"relaysLoaded\", (detail) => {", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 482, + "content": "relayManager,", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 496, + "content": "switchProfile: (pubkey) => app.authService.switchProfile(pubkey),", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 498, + "content": "app.authService.removeSavedProfile(pubkey),", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 499, + "content": "relayManager,", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 530, + "content": "authService: app.authService,", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 899, + "content": "if (this.window && typeof this.window.setTimeout === \"function\") {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 900, + "content": "this.window.setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 911, + "content": "const magnetValidator = playbackDependencies.isValidMagnetUri;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 927, + "content": "isMagnetSupported: (magnet) => magnetValidator(magnet),", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 1006, + "content": "magnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 1014, + "content": "app.playVideoByEventId(videoId, { url, magnet, trigger }),", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/applicationBootstrap.js", + "line": 1021, + "content": "app.playVideoWithFallback({ url, magnet, trigger }),", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 1, + "content": "import { extractMagnetHints } from \"../../magnetShared.js\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 2, + "content": "import { normalizeAndAugmentMagnet } from \"../../magnetUtils.js\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 39, + "content": "magnet:", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 40, + "content": "typeof sanitizers.magnet === \"function\"", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 41, + "content": "? sanitizers.magnet", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 168, + "content": "magnet: context.querySelector(\"#editVideoMagnet\") || null,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 414, + "content": "const magnetSource = video.magnet || video.rawMagnet || \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 415, + "content": "const magnetHints = extractMagnetHints(magnetSource);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 416, + "content": "const effectiveWs = video.ws || magnetHints.ws || \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 417, + "content": "const effectiveXs = video.xs || magnetHints.xs || \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 489, + "content": "window.requestAnimationFrame(() => {", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 517, + "content": "magnet: editContext.magnet || \"\",", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 613, + "content": "case \"magnet\":", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 877, + "content": "if (key === \"magnet\") {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 878, + "content": "return this.sanitizers.magnet(input.value);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 887, + "content": "const magnetInput = this.fields.magnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 899, + "content": "const newMagnet = fieldValue(\"magnet\");", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 920, + "content": "const magnetWasEdited = isEditing(magnetInput);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 925, + "content": "typeof original.magnet === \"string\" ? original.magnet.trim() : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 934, + "content": "let finalMagnet = magnetWasEdited ? newMagnet : originalMagnetValue;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 938, + "content": "if (magnetWasEdited) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 939, + "content": "const magnetHintCandidates = extractMagnetHints(finalMagnet);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 941, + "content": "finalWs = magnetHintCandidates.ws || \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 944, + "content": "finalXs = magnetHintCandidates.xs || \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 1046, + "content": "finalMagnet = result.magnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 1055, + "content": "const magnetChanged = magnetWasEdited && finalMagnet !== originalMagnetValue;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 1056, + "content": "const wsEditedFlag = wsWasManuallyEdited || magnetChanged;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 1057, + "content": "const xsEditedFlag = xsWasManuallyEdited || magnetChanged;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 1062, + "content": "magnet: finalMagnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EditModal.js", + "line": 1072, + "content": "magnetEdited: magnetWasEdited,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EmbedPlayerModal.js", + "line": 53, + "content": "// no-op for embed view (torrent stats)", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/EmbedPlayerModal.js", + "line": 96, + "content": "this.root.dataset.torrentStats = isVisible ? \"true\" : \"false\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/EmbedVideoModal.js", + "line": 179, + "content": "const hasMagnet = isNonEmptyString(this.activeVideo.magnet);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/EmbedVideoModal.js", + "line": 204, + "content": "return \"torrent\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/EventDetailsModal.js", + "line": 374, + "content": "magnet: video.magnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/RevertModal.js", + "line": 601, + "content": "const magnet =", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/RevertModal.js", + "line": 602, + "content": "typeof version.magnet === \"string\" ? version.magnet.trim() : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/RevertModal.js", + "line": 605, + "content": "const displayMagnet = magnet || rawMagnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/RevertModal.js", + "line": 617, + "content": "const magnetNode = displayMagnet", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/RevertModal.js", + "line": 948, + "content": "headerDl.appendChild(createDtDd(\"Magnet\", magnetNode));", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/SearchFilterModal.js", + "line": 300, + "content": "if (type === \"magnet\") isActive = safeFilters.hasMagnet === true;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/SearchFilterModal.js", + "line": 395, + "content": "if (btn.dataset.has === \"magnet\") filters.hasMagnet = true;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/ShareNostrModal.js", + "line": 4, + "content": "import { relayManager } from \"../../relayManager.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/ui/components/ShareNostrModal.js", + "line": 246, + "content": "relayManager && typeof relayManager.getWriteRelayUrls === \"function\"", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/ui/components/ShareNostrModal.js", + "line": 247, + "content": "? relayManager.getWriteRelayUrls()", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 12, + "content": "} from \"../../utils/torrentHash.js\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 40, + "content": "authService,", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 55, + "content": "this.authService = authService || null;", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 106, + "content": "this.torrentState = {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 109, + "content": "magnet: '',", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 110, + "content": "url: '', // xs (torrent file url)", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 233, + "content": "magnet: $(\"#input-magnet\"),", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 250, + "content": "magnet: $(\"#result-magnet\"),", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 251, + "content": "torrentUrl: $(\"#result-torrent-url\"),", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 368, + "content": "if (this.videoUploadState.url || this.torrentState.magnet) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 509, + "content": "this.torrentState = {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 512, + "content": "magnet: '',", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 521, + "content": "this.results.magnet.value = \"Pending...\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 522, + "content": "this.results.torrentUrl.value = \"Pending...\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 596, + "content": "const torrentPromise = this.generateTorrentMetadata({ file, videoPublicUrl });", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 598, + "content": "const [uploadResult, torrentResult] = await Promise.all([uploadPromise, torrentPromise]);", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 598, + "content": "const [uploadResult, torrentResult] = await Promise.all([uploadPromise, torrentPromise]);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 621, + "content": "// 5. Handle Torrent Result & Upload .torrent file", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 622, + "content": "if (torrentResult.hasValidInfoHash && torrentResult.torrentFile) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 624, + "content": "const torrentKey = (baseKey && baseKey !== videoKey) ? `${baseKey}.torrent` : `${videoKey}.torrent`;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 626, + "content": "let torrentPublicUrl = \"\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 628, + "content": "torrentPublicUrl = buildPublicUrl(baseDomain, torrentKey);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 630, + "content": "torrentPublicUrl = buildS3ObjectUrl({ publicBaseUrl: baseDomain, key: torrentKey });", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 633, + "content": "this.updateVideoProgress(1, \"Uploading torrent metadata...\");", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 645, + "content": "file: torrentResult.torrentFile,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 647, + "content": "key: torrentKey,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 660, + "content": "this.torrentState.status = 'complete';", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 661, + "content": "this.torrentState.infoHash = torrentResult.infoHash;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 662, + "content": "this.torrentState.url = torrentPublicUrl;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 663, + "content": "this.torrentState.file = torrentResult.torrentFile;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 668, + "content": "const encodedXs = encodeURIComponent(torrentPublicUrl);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 669, + "content": "const magnet = `magnet:?xt=urn:btih:${torrentResult.infoHash}&dn=${encodedDn}&ws=${encodedWs}&xs=${encodedXs}`;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 671, + "content": "this.torrentState.magnet = magnet;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 673, + "content": "this.results.magnet.value = magnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 674, + "content": "this.results.torrentUrl.value = torrentPublicUrl;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 678, + "content": "this.torrentState.status = 'skipped'; // Failed hash or invalid", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 679, + "content": "this.updateVideoProgress(1, \"Upload complete (No torrent fallback).\");", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 680, + "content": "this.results.magnet.value = \"Not available (Info Hash failed)\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 681, + "content": "this.results.torrentUrl.value = \"Not available\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 697, + "content": "if (this.results.magnet) this.results.magnet.value = \"Upload Failed\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 698, + "content": "if (this.results.torrentUrl) this.results.torrentUrl.value = \"Upload Failed\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 790, + "content": "setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 928, + "content": "// We need a signer. Try active signer or authService", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 930, + "content": "if (!signer && this.authService?.signer) {", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 931, + "content": "signer = this.authService.signer;", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 1046, + "content": "magnet: \"\",", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 1050, + "content": "infoHash: this.torrentState.infoHash || \"\",", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 1063, + "content": "metadata.magnet = this.torrentState.magnet || \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 1072, + "content": "metadata.xs = this.torrentState.url || \"\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 1079, + "content": "x: this.torrentState.infoHash || \"\",", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 1101, + "content": "let torrentFile = null;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 1105, + "content": "const torrentMetadata = await createTorrentMetadata(file, urlList);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 1107, + "content": "infoHash = torrentMetadata?.infoHash || \"\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 1108, + "content": "if (torrentMetadata?.torrentFile) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 1110, + "content": "torrentFile = new File([torrentMetadata.torrentFile], `${baseName}.torrent`, {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 1111, + "content": "type: \"application/x-bittorrent\",", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 1123, + "content": "torrentFile,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 1143, + "content": "metadata.magnet = this.inputs.magnet?.value?.trim() || \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 1148, + "content": "const hasMagnet = metadata.magnet.length > 0;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 1206, + "content": "this.torrentState = {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 1209, + "content": "magnet: '',", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 1210, + "content": "url: '', // xs (torrent file url)", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 1227, + "content": "if (this.results.magnet) this.results.magnet.value = \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/UploadModal.js", + "line": 1228, + "content": "if (this.results.torrentUrl) this.results.torrentUrl.value = \"\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 163, + "content": "this.torrentHealthBadgeEl = null;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 172, + "content": "typeof video.magnet === \"string\" ? video.magnet.trim() : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 176, + "content": "magnet: rawMagnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 180, + "content": "this.playbackMagnet = playbackConfig.magnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 183, + "content": "this.magnetProvided = playbackConfig.provided;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 184, + "content": "this.magnetSupported = this.helpers.isMagnetSupported", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 188, + "content": "!this.playbackUrl && this.magnetProvided && !this.magnetSupported;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 283, + "content": "return this.torrentHealthBadgeEl;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 506, + "content": "\"WebTorrent fallback unavailable (magnet missing btih info hash)\"", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 508, + "content": "warning.dataset.torrentStatus = \"unsupported\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 1131, + "content": "if (!isCompact && this.magnetSupported && this.magnetProvided) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 1133, + "content": "classNames: [\"badge\", \"torrent-health-badge\"]", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 1141, + "content": "this.torrentHealthBadgeEl = badge;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2243, + "content": "normalizedReason = \"Invalid magnet\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2250, + "content": "return \"WebTorrent status unknown\";", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2252, + "content": "return `WebTorrent • ${parts.join(\" • \")}`;", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2328, + "content": "badge.className = [\"badge\", \"torrent-health-badge\"].join(\" \");", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2333, + "content": "aria: \"WebTorrent peers available\",", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2339, + "content": "aria: \"WebTorrent peers unavailable\",", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2345, + "content": "aria: \"Checking WebTorrent peers\",", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2351, + "content": "aria: \"WebTorrent status unknown\",", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2364, + "content": "const computedText = `${iconPrefix}WebTorrent`;", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2642, + "content": "if (this.magnetProvided && this.magnetSupported) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2663, + "content": "this.root.dataset.streamHealthReason = this.magnetProvided", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2671, + "content": "if (this.magnetProvided) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2672, + "content": "this.root.dataset.magnet = this.playbackMagnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2674, + "content": "delete this.root.dataset.magnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2678, + "content": "this.root.dataset.torrentSupported = \"false\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2679, + "content": "} else if (this.magnetProvided && this.magnetSupported) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2680, + "content": "this.root.dataset.torrentSupported = \"true\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2708, + "content": "if (this.magnetProvided) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2709, + "content": "el.dataset.torrentSupported = this.magnetSupported ? \"true\" : \"false\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2710, + "content": "} else if (el.dataset.torrentSupported) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/VideoCard.js", + "line": 2711, + "content": "delete el.dataset.torrentSupported;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/VideoModal.js", + "line": 1565, + "content": "if (!this.window || typeof this.window.setTimeout !== \"function\") {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/components/VideoModal.js", + "line": 1573, + "content": "const nextId = this.window.setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/components/VideoModal.js", + "line": 2715, + "content": "(typeof this.activeVideo?.magnet === \"string\" &&", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoModal.js", + "line": 2716, + "content": "this.activeVideo.magnet.trim()) ||", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoModal.js", + "line": 2717, + "content": "this.activeVideo?.torrentSupported", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/VideoModal.js", + "line": 2759, + "content": "} else if (action === \"copy-magnet\") {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoModal.js", + "line": 2760, + "content": "this.dispatch(\"video:copy-magnet\", { video: this.activeVideo });", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoModal.js", + "line": 2911, + "content": "this.dispatch(\"video:copy-magnet\", { video: this.activeVideo });", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoModal.js", + "line": 2915, + "content": "if (!this.activeVideo || (mode !== \"url\" && mode !== \"torrent\")) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/VideoModal.js", + "line": 2930, + "content": "(typeof video?.magnet === \"string\" && video.magnet.trim()) ||", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoModal.js", + "line": 2931, + "content": "video?.torrentSupported", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/VideoModal.js", + "line": 2954, + "content": "} else if (mode === \"torrent\") {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/VideoModal.js", + "line": 2971, + "content": "const current = activeSource === \"torrent\" ? \"torrent\" : \"url\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/VideoModal.js", + "line": 3721, + "content": "this.updateSourceToggleState(visible ? \"torrent\" : \"url\");", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/components/VideoModal.js", + "line": 6022, + "content": "const magnetCandidate = (() => {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoModal.js", + "line": 6023, + "content": "if (typeof currentVideo?.magnet === \"string\" && currentVideo.magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoModal.js", + "line": 6024, + "content": "return currentVideo.magnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/VideoModal.js", + "line": 6038, + "content": "this.modalMoreMenuContext.playbackMagnet = magnetCandidate;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/hashtagStripHelper.js", + "line": 231, + "content": "typeof this.window.requestAnimationFrame === \"function\" &&", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/ui/components/hashtagStripHelper.js", + "line": 234, + "content": "this.window.requestAnimationFrame(() => {", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/ui/components/hashtagStripHelper.js", + "line": 240, + "content": "if (this.window && typeof this.window.setTimeout === \"function\") {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/components/hashtagStripHelper.js", + "line": 241, + "content": "this.window.setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/components/hashtagStripHelper.js", + "line": 248, + "content": "this.window.setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/components/hashtagStripHelper.js", + "line": 332, + "content": "if (typeof this.window.requestAnimationFrame === \"function\") {", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/ui/components/hashtagStripHelper.js", + "line": 333, + "content": "const frameId = this.window.requestAnimationFrame(() => {", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/ui/components/hashtagStripHelper.js", + "line": 344, + "content": "const timeoutId = this.window.setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/components/videoMenuRenderers.js", + "line": 226, + "content": "magnet: playbackMagnet || \"\",", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/videoMenuRenderers.js", + "line": 351, + "content": "const magnetBtn = appendMenuAction(doc, list, {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/videoMenuRenderers.js", + "line": 353, + "content": "action: \"copy-magnet\",", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/videoMenuRenderers.js", + "line": 357, + "content": "magnetBtn.disabled = true;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/videoMenuRenderers.js", + "line": 358, + "content": "magnetBtn.classList.add(\"opacity-50\", \"cursor-not-allowed\");", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/components/videoMenuRenderers.js", + "line": 359, + "content": "magnetBtn.title = \"No magnet link available\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/dm/ConversationList.js", + "line": 105, + "content": "setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/dm/ConversationList.js", + "line": 108, + "content": "setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/dm/ConversationList.js", + "line": 119, + "content": "setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/dm/ConversationList.js", + "line": 122, + "content": "setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/dm/MessageThread.js", + "line": 154, + "content": "setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/dm/MessageThread.js", + "line": 158, + "content": "setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/dm/MessageThread.js", + "line": 180, + "content": "setTimeout(initializeScroll, 300);", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/dm/MessageThread.js", + "line": 185, + "content": "setTimeout(initializeScroll, 0);", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/engagementController.js", + "line": 208, + "content": "typeof dataset.magnet === \"string\" && dataset.magnet.trim()", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/engagementController.js", + "line": 209, + "content": "? dataset.magnet.trim()", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/engagementController.js", + "line": 213, + "content": "? currentVideo?.magnet || currentVideo?.originalMagnet || \"\"", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/engagementController.js", + "line": 215, + "content": "const magnet = rawMagnet || fallbackMagnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/engagementController.js", + "line": 251, + "content": "magnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/engagementController.js", + "line": 382, + "content": "typeof window.setTimeout === \"function\"", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/engagementController.js", + "line": 384, + "content": "window.setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/initUploadModal.js", + "line": 15, + "content": "authService = null,", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/initUploadModal.js", + "line": 40, + "content": "authService,", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/loginModalController.js", + "line": 227, + "content": "authService:", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/loginModalController.js", + "line": 228, + "content": "services.authService && typeof services.authService === \"object\"", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/loginModalController.js", + "line": 229, + "content": "? services.authService", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/loginModalController.js", + "line": 325, + "content": "document.addEventListener(\"visibilitychange\", this.handleVisibility);", + "pattern": "Visibility", + "match": "visibilitychange" + }, + { + "file": "js/ui/loginModalController.js", + "line": 338, + "content": "if (document.hidden) {", + "pattern": "Visibility", + "match": "document.hidden" + }, + { + "file": "js/ui/loginModalController.js", + "line": 389, + "content": "typeof this.window.setInterval !== \"function\"", + "pattern": "Timeouts/Intervals", + "match": "setInterval" + }, + { + "file": "js/ui/loginModalController.js", + "line": 395, + "content": "this.modalCloseIntervalId = this.window.setInterval(handleClose, 500);", + "pattern": "Timeouts/Intervals", + "match": "setInterval" + }, + { + "file": "js/ui/loginModalController.js", + "line": 537, + "content": "typeof this.window.setInterval === \"function\" &&", + "pattern": "Timeouts/Intervals", + "match": "setInterval" + }, + { + "file": "js/ui/loginModalController.js", + "line": 540, + "content": "const timerId = this.window.setInterval(() => {", + "pattern": "Timeouts/Intervals", + "match": "setInterval" + }, + { + "file": "js/ui/loginModalController.js", + "line": 714, + "content": "const service = this.services?.authService;", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/loginModalController.js", + "line": 1562, + "content": "setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/loginModalController.js", + "line": 1609, + "content": "if (this.window && typeof this.window.setTimeout === \"function\") {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/loginModalController.js", + "line": 1610, + "content": "this.nip46AutoStartTimer = this.window.setTimeout(autoStart, 0);", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/loginModalController.js", + "line": 1788, + "content": "const accessControl = this.services?.authService?.accessControl;", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/loginModalController.js", + "line": 2211, + "content": "if (!this.window || typeof this.window.setTimeout !== \"function\") {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/loginModalController.js", + "line": 2215, + "content": "const timerId = this.window.setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/loginModalController.js", + "line": 2267, + "content": "if (!this.services.authService) {", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/loginModalController.js", + "line": 2364, + "content": "await this.services.authService.requestLogin(requestOptions);", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/loginModalController.js", + "line": 2509, + "content": "document.removeEventListener(\"visibilitychange\", this.handleVisibility);", + "pattern": "Visibility", + "match": "visibilitychange" + }, + { + "file": "js/ui/moreMenuController.js", + "line": 1035, + "content": "if (typeof video?.magnet === \"string\" && video.magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/moreMenuController.js", + "line": 1036, + "content": "return video.magnet;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/notificationController.js", + "line": 93, + "content": "if (this.window && typeof this.window.setTimeout === \"function\") {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/notificationController.js", + "line": 94, + "content": "this.errorAutoHideHandle = this.window.setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/notificationController.js", + "line": 117, + "content": "defaultView?.setTimeout || (typeof setTimeout === \"function\" ? setTimeout : null);", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/notificationController.js", + "line": 231, + "content": "if (this.window && typeof this.window.setTimeout === \"function\") {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/notificationController.js", + "line": 232, + "content": "this.successAutoHideHandle = this.window.setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/overlay/popoverEngine.js", + "line": 364, + "content": "if (typeof view.requestAnimationFrame === \"function\") {", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/ui/overlay/popoverEngine.js", + "line": 365, + "content": "view.requestAnimationFrame(restoreScroll);", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/ui/overlay/popoverEngine.js", + "line": 369, + "content": "if (typeof view.setTimeout === \"function\") {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/overlay/popoverEngine.js", + "line": 370, + "content": "view.setTimeout(restoreScroll, 0);", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/overlay/popoverEngine.js", + "line": 385, + "content": "if (!view || typeof view.setTimeout !== \"function\") {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/overlay/popoverEngine.js", + "line": 391, + "content": "menuState.typeaheadTimeout = view.setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/profileModal/ProfileDirectMessageRenderer.js", + "line": 268, + "content": "if (typeof window !== \"undefined\" && window && window.setTimeout) {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/profileModal/ProfileDirectMessageRenderer.js", + "line": 272, + "content": "this.messagesStatusClearTimeout = window.setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/profileModal/ProfileDirectMessageRenderer.js", + "line": 819, + "content": "typeof window !== \"undefined\" && typeof window.setTimeout === \"function\"", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/profileModal/ProfileDirectMessageRenderer.js", + "line": 820, + "content": "? window.setTimeout.bind(window)", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/profileModal/ProfileDirectMessageRenderer.js", + "line": 821, + "content": ": setTimeout;", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/profileModal/ProfileRelayController.js", + "line": 39, + "content": ": this.mainController.services.relayManager.getEntries();", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/ui/profileModalContract.js", + "line": 275, + "content": "key: \"relayManager\",", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/ui/profileModalController.js", + "line": 98, + "content": "* @param {object} [options.services] - Service instances (nostrService, relayManager, etc.).", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/ui/profileModalController.js", + "line": 1670, + "content": "const service = this.services.relayManager;", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/ui/profileModalController.js", + "line": 2324, + "content": "await this.services.authService.loadOwnProfile(normalizedPubkey);", + "pattern": "Nostr/Relay/Auth", + "match": "authService" + }, + { + "file": "js/ui/profileModalController.js", + "line": 3166, + "content": "window.requestAnimationFrame(() => {", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/ui/profileModalController.js", + "line": 3333, + "content": "setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/profileModalController.js", + "line": 4944, + "content": "\"visibilitychange\",", + "pattern": "Visibility", + "match": "visibilitychange" + }, + { + "file": "js/ui/profileModalController.js", + "line": 5033, + "content": "const previous = this.services.relayManager.snapshot();", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/ui/profileModalController.js", + "line": 5038, + "content": "return this.services.relayManager.addRelay(url);", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/ui/profileModalController.js", + "line": 5040, + "content": "return this.services.relayManager.removeRelay(url);", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/ui/profileModalController.js", + "line": 5042, + "content": "return this.services.relayManager.restoreDefaults();", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/ui/profileModalController.js", + "line": 5044, + "content": "return this.services.relayManager.cycleRelayMode(url);", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/ui/profileModalController.js", + "line": 5069, + "content": "const publishResult = await this.services.relayManager.publishRelayList(", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/ui/profileModalController.js", + "line": 5079, + "content": "this.services.relayManager.setEntries(previous, { allowEmpty: false });", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/ui/profileModalController.js", + "line": 5557, + "content": "requestAnimationFrame(() => {", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/ui/profileModalController.js", + "line": 5631, + "content": "void Promise.allSettled(backgroundTasks);", + "pattern": "Promise Concurrency", + "match": "Promise.allSettled" + }, + { + "file": "js/ui/profileModalController.js", + "line": 5673, + "content": "window.requestAnimationFrame(() => {", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/ui/profileModalController.js", + "line": 5743, + "content": "\"visibilitychange\",", + "pattern": "Visibility", + "match": "visibilitychange" + }, + { + "file": "js/ui/profileModalController.js", + "line": 5778, + "content": "window.requestAnimationFrame(() => {", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/ui/profileModalController.js", + "line": 5869, + "content": "Promise.all([walletPromise, adminPromise, postLoginPromise])", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/ui/shareNostrController.js", + "line": 4, + "content": "publishEventToRelays as defaultPublishEventToRelays,", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/ui/shareNostrController.js", + "line": 10, + "content": "import { queueSignEvent as defaultQueueSignEvent } from \"../nostr/signRequestQueue.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/ui/shareNostrController.js", + "line": 22, + "content": "publishEventToRelays: services.publishEventToRelays || defaultPublishEventToRelays,", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/ui/shareNostrController.js", + "line": 25, + "content": "queueSignEvent: services.queueSignEvent || defaultQueueSignEvent,", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/ui/shareNostrController.js", + "line": 176, + "content": "signedEvent = await this.services.queueSignEvent(signer, event);", + "pattern": "Nostr/Relay/Auth", + "match": "queueSignEvent" + }, + { + "file": "js/ui/shareNostrController.js", + "line": 183, + "content": "const publishResults = await this.services.publishEventToRelays(", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/ui/shareNostrController.js", + "line": 184, + "content": "this.services.nostrClient.pool,", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 23, + "content": "update(torrent) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 24, + "content": "if (!torrent) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 34, + "content": "progress: torrent.progress,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 35, + "content": "numPeers: torrent.numPeers,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 36, + "content": "downloadSpeed: torrent.downloadSpeed,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 37, + "content": "downloaded: torrent.downloaded,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 38, + "content": "length: torrent.length,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 39, + "content": "ready: torrent.ready,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 43, + "content": "if (torrent.ready || (typeof torrent.progress === \"number\" && torrent.progress > 0)) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 44, + "content": "// Belt-and-suspenders: if WebTorrent reports progress but the DOM events", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 48, + "content": "torrent.ready ? \"torrent-ready-flag\" : \"torrent-progress\"", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 56, + "content": "const fullyDownloaded = Number(torrent.progress) >= 1;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 57, + "content": "const status = torrent.ready", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 68, + "content": "const progressValue = Number.isFinite(torrent.progress)", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 69, + "content": "? `${(torrent.progress * 100).toFixed(2)}%`", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 77, + "content": "const peersValue = `Peers: ${Number.isFinite(torrent.numPeers) ? torrent.numPeers : 0}`;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 84, + "content": "const speedValue = Number.isFinite(torrent.downloadSpeed)", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 85, + "content": "? `${(torrent.downloadSpeed / 1024).toFixed(2)} KB/s`", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 93, + "content": "const downloadedMb = Number.isFinite(torrent.downloaded)", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 94, + "content": "? (torrent.downloaded / (1024 * 1024)).toFixed(2)", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 96, + "content": "const lengthMb = Number.isFinite(torrent.length)", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/torrentStatusController.js", + "line": 97, + "content": "? (torrent.length / (1024 * 1024)).toFixed(2)", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/urlHealthController.js", + "line": 56, + "content": "if (typeof requestAnimationFrame === \"function\") {", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/ui/urlHealthController.js", + "line": 57, + "content": "requestAnimationFrame(() => {", + "pattern": "Timeouts/Intervals", + "match": "requestAnimationFrame" + }, + { + "file": "js/ui/urlHealthController.js", + "line": 315, + "content": "timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/urlHealthController.js", + "line": 418, + "content": "timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/ui/urlHealthController.js", + "line": 434, + "content": "responseOrTimeout = await Promise.race(racers);", + "pattern": "Promise Concurrency", + "match": "Promise.race" + }, + { + "file": "js/ui/videoModalController.js", + "line": 72, + "content": "this.videoModal.addEventListener(\"video:copy-magnet\", () => {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/videoModalController.js", + "line": 133, + "content": "const magnetCandidate =", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/videoModalController.js", + "line": 134, + "content": "typeof video.magnet === \"string\" ? video.magnet.trim() : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/videoModalController.js", + "line": 143, + "content": "const magnetAvailable = Boolean(magnetCandidate);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/videoModalController.js", + "line": 165, + "content": "if (source === \"torrent\" && !magnetAvailable) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/videoModalController.js", + "line": 167, + "content": "\"[VideoModalController] Unable to switch to torrent playback: missing magnet.\",", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/videoModalController.js", + "line": 171, + "content": "\"Torrent playback is unavailable for this video. No magnet was provided.\",", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/videoModalController.js", + "line": 177, + "content": "if (source === \"torrent\" && hasActivePeers === false) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/videoModalController.js", + "line": 179, + "content": "\"[VideoModalController] Switching to torrent playback despite 0 active peers detected.\",", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/videoModalController.js", + "line": 196, + "content": "\"CDN playback is unavailable right now, staying on the torrent stream.\",", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/ui/videoModalController.js", + "line": 210, + "content": "magnet: magnetCandidate,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/views/VideoListView.js", + "line": 407, + "content": "magnet: typeof video?.magnet === \"string\" ? video.magnet : \"\",", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/views/VideoListView.js", + "line": 1067, + "content": "const target = element?.closest(\"[data-play-url],[data-play-magnet]\") || element;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/views/VideoListView.js", + "line": 1076, + "content": ": null) ?? target?.getAttribute?.(\"data-play-magnet\") ?? \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/views/VideoListView.js", + "line": 1091, + "content": "const magnet = typeof rawMagnetValue === \"string\" ? rawMagnetValue : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/views/VideoListView.js", + "line": 1103, + "content": "return { videoId, url, magnet, infoJsonUrl, video, trigger: element };", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/ui/views/VideoListView.js", + "line": 1326, + "content": "const trigger = target.closest(\"[data-play-magnet],[data-play-url]\");", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/userBlocks.js", + "line": 17, + "content": "publishEventToRelays,", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/userBlocks.js", + "line": 22, + "content": "import { relayManager } from \"./relayManager.js\";", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/userBlocks.js", + "line": 763, + "content": "pool: nostrClient.pool,", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/userBlocks.js", + "line": 810, + "content": "this.decryptRetryTimeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/userBlocks.js", + "line": 939, + "content": "const readRelays = relayManager.getReadRelayUrls();", + "pattern": "Nostr/Relay/Auth", + "match": "relayManager" + }, + { + "file": "js/userBlocks.js", + "line": 1335, + "content": "// PERF: Try all decryption schemes in parallel via Promise.any().", + "pattern": "Promise Concurrency", + "match": "Promise.any" + }, + { + "file": "js/userBlocks.js", + "line": 1361, + "content": "const result = await Promise.any(attempts);", + "pattern": "Promise Concurrency", + "match": "Promise.any" + }, + { + "file": "js/userBlocks.js", + "line": 1402, + "content": "const decryptPromise = Promise.all([", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/userBlocks.js", + "line": 1407, + "content": "setTimeout(", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/userBlocks.js", + "line": 1420, + "content": "const [standardDecrypted, legacyDecrypted] = await Promise.race([", + "pattern": "Promise Concurrency", + "match": "Promise.race" + }, + { + "file": "js/userBlocks.js", + "line": 1564, + "content": "const legacyFetchPromise = Promise.all([", + "pattern": "Promise Concurrency", + "match": "Promise.all" + }, + { + "file": "js/userBlocks.js", + "line": 2232, + "content": "const publishResults = await publishEventToRelays(", + "pattern": "Nostr/Relay/Auth", + "match": "publishEventToRelays" + }, + { + "file": "js/userBlocks.js", + "line": 2233, + "content": "nostrClient.pool,", + "pattern": "Nostr/Relay/Auth", + "match": "nostrClient.pool" + }, + { + "file": "js/utils/asyncUtils.js", + "line": 59, + "content": "* for each item, ensuring all items are processed (like Promise.allSettled).", + "pattern": "Promise Concurrency", + "match": "Promise.allSettled" + }, + { + "file": "js/utils/asyncUtils.js", + "line": 93, + "content": "timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/utils/magnetValidators.js", + "line": 1, + "content": "// js/utils/magnetValidators.js", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/utils/magnetValidators.js", + "line": 3, + "content": "import { safeDecodeMagnet } from \"../magnetUtils.js\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/utils/magnetValidators.js", + "line": 6, + "content": "* Basic validation for BitTorrent magnet URIs.", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/utils/magnetValidators.js", + "line": 8, + "content": "* Returns `true` only when the value looks like a magnet link that WebTorrent", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/utils/magnetValidators.js", + "line": 9, + "content": "* understands (`magnet:` scheme with at least one `xt=urn:btih:`", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/utils/magnetValidators.js", + "line": 14, + "content": "export function isValidMagnetUri(magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/utils/magnetValidators.js", + "line": 15, + "content": "const trimmed = typeof magnet === \"string\" ? magnet.trim() : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/utils/magnetValidators.js", + "line": 29, + "content": "if (parsed.protocol.toLowerCase() !== \"magnet:\") {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/utils/serviceWorkerFallbackMessages.js", + "line": 3, + "content": "const BASE_STATUS_MESSAGE = \"Streaming via WebTorrent\";", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/utils/storage.js", + "line": 5, + "content": "const TORRENT_PROBE_STORAGE_PREFIX = \"bitvid:torrentProbe:\";", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/utils/storage.js", + "line": 80, + "content": "`Failed to parse stored torrent probe for ${infoHash}:`,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/utils/storage.js", + "line": 100, + "content": "userLogger.warn(`Failed to persist torrent probe for ${infoHash}:`, err);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/utils/storage.js", + "line": 112, + "content": "userLogger.warn(`Failed to remove torrent probe for ${infoHash}:`, err);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/utils/torrentHash.js", + "line": 1, + "content": "import WebTorrent from \"../webtorrent.min.js\";", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/utils/torrentHash.js", + "line": 14, + "content": "const client = new WebTorrent({", + "pattern": "WebTorrent", + "match": "new WebTorrent" + }, + { + "file": "js/utils/torrentHash.js", + "line": 30, + "content": "(torrent) => {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/utils/torrentHash.js", + "line": 31, + "content": "const infoHash = torrent.infoHash;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/utils/torrentHash.js", + "line": 32, + "content": "const torrentFile = torrent.torrentFile || torrent.torrentFileBuffer || null;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/utils/torrentHash.js", + "line": 38, + "content": "resolve({ infoHash, torrentFile });", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/utils/torrentHash.js", + "line": 47, + "content": "userLogger.error(\"WebTorrent client error during hashing:\", err);", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/utils/torrentHash.js", + "line": 59, + "content": "* Calculates the torrent infoHash for a given file client-side.", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/videoEventUtils.js", + "line": 7, + "content": "const MAGNET_URI_PATTERN = /^magnet:\\?/i;", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/viewCounter.js", + "line": 75, + "content": "persistTimer = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/webtorrent-global.js", + "line": 1, + "content": "import WebTorrent from \"./webtorrent.min.js\";", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent-global.js", + "line": 10, + "content": "typeof globalScope.WebTorrent !== \"function\" &&", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent-global.js", + "line": 11, + "content": "typeof WebTorrent === \"function\"", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent-global.js", + "line": 13, + "content": "globalScope.WebTorrent = WebTorrent;", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent.js", + "line": 1, + "content": "//js/webtorrent.js", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 4, + "content": "* js/webtorrent.js", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 6, + "content": "* This module wraps the WebTorrent client and manages the Service Worker integration.", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent.js", + "line": 10, + "content": "* - Singleton WebTorrent client: It ensures we reuse a single client instance to", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent.js", + "line": 13, + "content": "* because WebTorrent in the browser streams data via a Service Worker \"proxy\" that", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent.js", + "line": 21, + "content": "import WebTorrent from \"./webtorrent.min.js\";", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent.js", + "line": 69, + "content": "function appendProbeTrackers(magnetURI, trackers) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/webtorrent.js", + "line": 70, + "content": "if (typeof magnetURI !== \"string\") {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/webtorrent.js", + "line": 71, + "content": "return { magnet: \"\", appended: false, hasProbeTrackers: false };", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/webtorrent.js", + "line": 74, + "content": "const trimmedMagnet = magnetURI.trim();", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/webtorrent.js", + "line": 76, + "content": "return { magnet: \"\", appended: false, hasProbeTrackers: false };", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/webtorrent.js", + "line": 82, + "content": "magnet: trimmedMagnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/webtorrent.js", + "line": 124, + "content": "magnet: trimmedMagnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/webtorrent.js", + "line": 137, + "content": "magnet: finalMagnet,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/webtorrent.js", + "line": 164, + "content": "this.WebTorrentClass =", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent.js", + "line": 165, + "content": "typeof webTorrentClass === \"function\" ? webTorrentClass : WebTorrent;", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent.js", + "line": 185, + "content": "this.probeClient = new this.WebTorrentClass();", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent.js", + "line": 194, + "content": "* Helper to check if a magnet link has active peers without starting a full", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/webtorrent.js", + "line": 198, + "content": "magnetURI,", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/webtorrent.js", + "line": 201, + "content": "const magnet = typeof magnetURI === \"string\" ? magnetURI.trim() : \"\";", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/webtorrent.js", + "line": 202, + "content": "if (!magnet) {", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/webtorrent.js", + "line": 215, + "content": "const { magnet: augmentedMagnet, appended, hasProbeTrackers } =", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/webtorrent.js", + "line": 216, + "content": "appendProbeTrackers(magnet, trackers);", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/webtorrent.js", + "line": 218, + "content": "const hasMagnetWebSeed = magnet.includes(\"ws=\") || magnet.includes(\"webSeed=\");", + "pattern": "WebTorrent", + "match": "magnet" + }, + { + "file": "js/webtorrent.js", + "line": 248, + "content": "emit(\"torrent-probe-start\", { magnet: augmentedMagnet });", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 252, + "content": "let torrent = null;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 269, + "content": "if (torrent) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 271, + "content": "torrent.destroy({ destroyStore: true });", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 295, + "content": "emit(\"torrent-probe-result\", result);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 309, + "content": "* That was a mistake. WebTorrent counts a connected webseed as a peer.", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent.js", + "line": 320, + "content": "torrent = client.add(augmentedMagnet, addOptions);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 332, + "content": "const peers = Math.max(1, Math.floor(normalizeNumber(torrent?.numPeers, 1)));", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 336, + "content": "torrent.once(\"wire\", settleHealthy);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 338, + "content": "torrent.once(\"error\", (err) => {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 339, + "content": "const peers = Math.max(0, Math.floor(normalizeNumber(torrent?.numPeers, 0)));", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 350, + "content": "timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/webtorrent.js", + "line": 351, + "content": "const peers = Math.max(0, Math.floor(normalizeNumber(torrent?.numPeers, 0)));", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 361, + "content": "pollId = setInterval(() => {", + "pattern": "Timeouts/Intervals", + "match": "setInterval" + }, + { + "file": "js/webtorrent.js", + "line": 362, + "content": "if (!torrent || settled) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 365, + "content": "const peers = Math.max(0, Math.floor(normalizeNumber(torrent.numPeers, 0)));", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 396, + "content": "* Makes sure we have exactly one WebTorrent client instance and one SW registration.", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent.js", + "line": 401, + "content": "this.client = new this.WebTorrentClass();", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent.js", + "line": 417, + "content": "this.swRegistration = await this.setupServiceWorker();", + "pattern": "Workers", + "match": "Worker(" + }, + { + "file": "js/webtorrent.js", + "line": 434, + "content": "\"[WebTorrent] Service worker setup failed; continuing without it:\",", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent.js", + "line": 438, + "content": "\"[WebTorrent] Service worker unavailable; falling back to direct streaming.\",", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent.js", + "line": 454, + "content": "const timeout = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/webtorrent.js", + "line": 478, + "content": "registration.waiting.postMessage({ type: \"SKIP_WAITING\" });", + "pattern": "Workers", + "match": "postMessage(" + }, + { + "file": "js/webtorrent.js", + "line": 502, + "content": "this.log(\"[WebTorrent] Service worker lifecycle:\", payload);", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent.js", + "line": 507, + "content": "async activateWaitingWorker(registration) {", + "pattern": "Workers", + "match": "Worker(" + }, + { + "file": "js/webtorrent.js", + "line": 522, + "content": "waitingWorker.postMessage({ type: \"SKIP_WAITING\" });", + "pattern": "Workers", + "match": "postMessage(" + }, + { + "file": "js/webtorrent.js", + "line": 529, + "content": "* start WebTorrent streaming.", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent.js", + "line": 533, + "content": "* had finished installing but never claimed the page yet. WebTorrent's", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent.js", + "line": 557, + "content": "activeWorker.postMessage({ type: \"ENSURE_CLIENTS_CLAIM\" });", + "pattern": "Workers", + "match": "postMessage(" + }, + { + "file": "js/webtorrent.js", + "line": 613, + "content": "timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/webtorrent.js", + "line": 618, + "content": "pollId = setInterval(() => {", + "pattern": "Timeouts/Intervals", + "match": "setInterval" + }, + { + "file": "js/webtorrent.js", + "line": 638, + "content": "async setupServiceWorker() {", + "pattern": "Workers", + "match": "Worker(" + }, + { + "file": "js/webtorrent.js", + "line": 654, + "content": "// and WebTorrent fails to spin up, leaving playback broken until the", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent.js", + "line": 676, + "content": "await new Promise((resolve) => setTimeout(resolve, 1000));", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/webtorrent.js", + "line": 693, + "content": "const timeout = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/webtorrent.js", + "line": 711, + "content": "await this.activateWaitingWorker(registration);", + "pattern": "Workers", + "match": "Worker(" + }, + { + "file": "js/webtorrent.js", + "line": 716, + "content": "const readyRegistration = await Promise.race([", + "pattern": "Promise Concurrency", + "match": "Promise.race" + }, + { + "file": "js/webtorrent.js", + "line": 719, + "content": "setTimeout(", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/webtorrent.js", + "line": 737, + "content": "// newly installed worker claims the page before WebTorrent spins up.", + "pattern": "WebTorrent", + "match": "WebTorrent" + }, + { + "file": "js/webtorrent.js", + "line": 743, + "content": "await this.activateWaitingWorker(registration);", + "pattern": "Workers", + "match": "Worker(" + }, + { + "file": "js/webtorrent.js", + "line": 753, + "content": "attemptAutoplay(videoElement, context = \"webtorrent\") {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 774, + "content": "torrent,", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 784, + "content": "// and deliberately mutate `torrent._opts` as a sanctioned WebTorrent workaround.", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 786, + "content": "torrent.on(\"warning\", (err) => {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 795, + "content": "if (torrent._opts?.urlList?.length) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 796, + "content": "torrent._opts.urlList = torrent._opts.urlList.filter((url) => {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 799, + "content": "userLogger.warn(\"Cleaned up webseeds =>\", torrent._opts.urlList);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 801, + "content": "if (torrent._opts?.announce?.length) {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 802, + "content": "torrent._opts.announce = torrent._opts.announce.filter((url) => {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 805, + "content": "userLogger.warn(\"Cleaned up trackers =>\", torrent._opts.announce);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 812, + "content": "const file = torrent.files.find((f) => /\\.(mp4|webm|mkv)$/i.test(f.name));", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 814, + "content": "return reject(new Error(\"No compatible video file found in torrent\"));", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 842, + "content": "this.currentTorrent = torrent;", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 843, + "content": "resolve(torrent);", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 849, + "content": "torrent.on(\"error\", (err) => {", + "pattern": "WebTorrent", + "match": "torrent" + }, + { + "file": "js/webtorrent.js", + "line": 889, + "content": "const timeoutId = setTimeout(() => {", + "pattern": "Timeouts/Intervals", + "match": "setTimeout" + }, + { + "file": "js/webtorrent.js", + "line": 924, + "content": "* Initiates streaming of a torrent magnet to a