mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Merge pull request #2672 from PR0M3TH3AN/agents/daily/prompt-curator-agent-2026-02-22-2018433635480124911
docs(agents): prompt curation run 2026-02-22
This commit is contained in:
14 files changed
+161
-100
No files matched your search
@@ -1,26 +1,33 @@
|
||||
# Prompt Library Status
|
||||
|
||||
Last updated: 2026-02-18
|
||||
Last updated: 2026-02-22
|
||||
Run type: Daily
|
||||
|
||||
## Summary
|
||||
|
||||
- **Total prompts**: 36 (21 daily, 15 weekly) + 2 schedulers
|
||||
- **Health**: Good. All prompts follow the canonical structure.
|
||||
Verified `test-audit-agent` update is consistent with repo policy.
|
||||
- **Health**: Good. Fixed broken path references in multiple prompts.
|
||||
|
||||
## Changes This Run
|
||||
|
||||
### Verified Fixes
|
||||
|
||||
None.
|
||||
- **`weekly/bitvid-smoke-agent.md`**: Fixed missing `.js` extension in `js/nostrClientFacade.js` reference.
|
||||
- **`weekly/bitvid-test-coverage-agent.md`**: Updated examples to reference existing files (`js/nostr/utils.js`, `js/services/storageService.js`) instead of placeholders.
|
||||
- **`daily/bitvid-content-audit-agent.md`**:
|
||||
- Removed reference to non-existent `content/docs/upload.md`.
|
||||
- Updated `js/services/uploadService.js` to `js/services/s3UploadService.js`.
|
||||
- Updated `js/ui/uploadModal.js` to `js/ui/components/UploadModal.js`.
|
||||
- **`daily/bitvid-deps-security-agent.md`**: Updated `scripts/deps-audit.sh` to `scripts/generate-deps-report.cjs`.
|
||||
- **`daily/bitvid-const-refactor-agent.md`**:
|
||||
- Updated regex/grep instructions to be generic.
|
||||
- Updated target file examples to existing files (`js/nostr/watchHistory.js`, `js/nostr/relayBatchFetcher.js`).
|
||||
- **`daily/bitvid-nip-research-agent.md`**: Updated test file reference to `tests/dm-decryptor.test.mjs`.
|
||||
- **`daily/bitvid-test-audit-agent.md`**: Clarified wildcard `js/webtorrent*` to explicit `js/webtorrent.js`.
|
||||
|
||||
### Audited Prompts (Sample)
|
||||
|
||||
- `daily/bitvid-test-audit-agent.md` (Verified recent update)
|
||||
- `daily/bitvid-docs-alignment-agent.md` (Verified valid)
|
||||
- `daily/bitvid-docs-agent.md` (Verified valid)
|
||||
- `daily/bitvid-known-issues-agent.md` (Verified valid)
|
||||
- `daily/bitvid-prompt-curator-agent.md` (Self)
|
||||
|
||||
## Known Remaining Issues
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ DETAILED WORKFLOW (step-by-step)
|
||||
- Generic app-level: `js/constants.js`
|
||||
- Nostr/relay-level: `js/nostr/relayConstants.js`
|
||||
- Cache TTLs: `js/nostr/cachePolicies.js`
|
||||
- If a more specific domain exists (e.g., `js/services/watchHistoryConstants.js`), prefer creating in that domain.
|
||||
- If a more specific domain exists (e.g., `js/nostr/watchHistory.js`), prefer creating in that domain.
|
||||
- Choose a clear semantic name. Naming guidelines:
|
||||
- Use all-caps snake-case with domain and unit: e.g., `FAST_RELAY_TIMEOUT_MS`, `DM_DECRYPT_WORKER_MAX_PENDING`, `WATCH_HISTORY_REPUBLISH_MAX_DELAY_MS`, `DEFAULT_RETRY_ATTEMPTS`.
|
||||
- Suffix with `_MS` for millisecond timeouts, `_S` for seconds, `_COUNT`, `_TTL_MS`.
|
||||
@@ -210,7 +210,7 @@ PR / REVIEW CHECKLIST (what maintainers expect)
|
||||
|
||||
===============================================================================
|
||||
EXAMPLE: end-to-end flow for 5000ms duplicates
|
||||
- Discover `5000` appears in `js/relayManager.js`, `js/nostr/watchHistory.js`, `js/nostr/relayClient.js`.
|
||||
- Discover `5000` appears in `js/relayManager.js`, `js/nostr/watchHistory.js`, `js/nostr/relayBatchFetcher.js`.
|
||||
- Determine these uses are all "fast relay timeout" semantics.
|
||||
- Check `js/nostr/relayConstants.js` — no `FAST_RELAY_TIMEOUT_MS`. Decide to add:
|
||||
```js
|
||||
|
||||
@@ -49,7 +49,7 @@ Each phase below includes concrete steps and deliverables.
|
||||
Goal: build a complete mapping: `/content` page → concrete claims → code locations that implement the claim.
|
||||
|
||||
Steps:
|
||||
- List every page in `/content` related to uploading, contributing, or media (e.g., `content/docs/upload.md`, `content/contribute/*`, `content/guides/*`). Use:
|
||||
- List every page in `/content` related to uploading, contributing, or media (e.g., `content/contribute/*`, `content/guides/*`). Use:
|
||||
```
|
||||
|
||||
rg --hidden --files --glob 'content/**' | rg '/content/' -n
|
||||
@@ -67,7 +67,7 @@ rg --hidden --files --glob 'content/**' | rg '/content/' -n
|
||||
- Licensing & attribution templates and policies
|
||||
- How to edit/delete content and check status
|
||||
- For each claim, find the authoritative code location(s) — the file(s) and function(s) implementing it:
|
||||
- Upload UI: look under `js/` for upload modal/upload service controllers (e.g., `js/services/uploadService.js`, `js/ui/uploadModal.js`).
|
||||
- Upload UI: look under `js/` for upload modal/upload service controllers (e.g., `js/services/s3UploadService.js`, `js/ui/components/UploadModal.js`).
|
||||
- API endpoints: search backend server for upload handlers (e.g., `server/` or `api/`).
|
||||
- Storage/processing: check any `torrent/`, `storage/`, or `cloud` integration code.
|
||||
- Moderation code: e.g., `js/userBlocks.js`, moderation service.
|
||||
@@ -77,7 +77,7 @@ rg --hidden --files --glob 'content/**' | rg '/content/' -n
|
||||
- Produce a deliverable CSV or markdown table:
|
||||
```
|
||||
|
||||
/content/path.md | Claim: "Max file size 100MB" | Code: js/services/uploadService.js#L123-L160 | Verified? (unknown)
|
||||
/content/path.md | Claim: "Max file size 100MB" | Code: js/services/s3UploadService.js#L123-L160 | Verified? (unknown)
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ Create/update these files/folders (commit them in the branch when PRing):
|
||||
- `todo/TODO_<timestamp>.md` — upgrade tasks and statuses.
|
||||
- `decisions/DECISIONS_<timestamp>.md` — rationale for upgrade choices and tradeoffs.
|
||||
- `test_logs/TEST_LOG_<timestamp>.md` — exact commands run and their outputs (timestamped).
|
||||
- Optionally: `scripts/deps-audit.sh` for reproducible automation.
|
||||
- Optionally: `scripts/generate-deps-report.cjs` for reproducible automation.
|
||||
|
||||
Also read `AGENTS.md` and `KNOWN_ISSUES.md` for project-specific caveats (e.g., the repo uses `nostr-tools`, `webtorrent`, `Playwright`, `Tailwind`). Tag these libraries for special handling.
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ SEARCH PATTERNS & REPO COMMANDS
|
||||
- Example validation commands:
|
||||
- Fetch NIP markdown: `curl -sSL https://raw.githubusercontent.com/nostr-protocol/nips/master/text/0000-nip.md > artifacts/nips/nip-0000.md`
|
||||
- Run a local node test harness: `node test/nostr-specs/validate-serialization.js`
|
||||
- Run unit tests for nostr helpers: `npm test -- js/nostr/dmDecryptWorker.test.js --runInBand`
|
||||
- Run unit tests for nostr helpers: `npm test -- tests/dm-decryptor.test.mjs --runInBand`
|
||||
|
||||
===============================================================================
|
||||
TESTS & AUTOMATION (what to add)
|
||||
|
||||
@@ -106,7 +106,7 @@ DAILY WORKFLOW (run every day or as scheduled)
|
||||
- `js/nostr/watchHistory.js` — normalization, payload limits, republish backoff/jitter.
|
||||
- `js/userBlocks.js` — block list parsing/sanitation.
|
||||
- `js/ui/ambientBackground.js` — RAF and visibility gating.
|
||||
- `js/webtorrent*` / `torrent/app.js` — lazy initialization.
|
||||
- `js/webtorrent.js` / `torrent/app.js` — lazy initialization.
|
||||
- Parse coverage data (LCOV/coverage-summary) and map production files to coverage percentages.
|
||||
- Flag critical files with coverage < X% (configurable threshold, default 70%) and record in `test-audit/coverage-gaps.json`.
|
||||
|
||||
@@ -199,7 +199,7 @@ Focus on tests that exercise real behavior for these critical modules (examples
|
||||
- Tests: normalization, payload size limits, republish backoff/jitter handling, serialization.
|
||||
- **Block lists & moderation**: `js/userBlocks.js`
|
||||
- Tests: tag sanitation, self-target filtering, parsing, and dumping behavior.
|
||||
- **Playback & WebTorrent**: `js/webtorrent*`, `torrent/app.js`, `js/ui/ambientBackground.js`
|
||||
- **Playback & WebTorrent**: `js/webtorrent.js`, `torrent/app.js`, `js/ui/ambientBackground.js`
|
||||
- Tests: lazy webtorrent init, visibility gating, ensure heavy loops paused when hidden.
|
||||
|
||||
(If you need file paths to scan, search the `js/` tree for the filenames above).
|
||||
|
||||
@@ -93,7 +93,7 @@ WORKFLOW (implementation & run steps)
|
||||
- If Playwright is available:
|
||||
- Launch `chromium` headless and open `http://localhost:8000`
|
||||
- Optionally use Playwright page APIs to interact with the UI to trigger login/publish flows
|
||||
- Alternatively implement a headless Node client using `js/nostrClientFacade` directly to simulate flows without UI.
|
||||
- Alternatively implement a headless Node client using `js/nostrClientFacade.js` directly to simulate flows without UI.
|
||||
|
||||
4) Login with ephemeral keys
|
||||
- Generate ephemeral keypair in memory (do not persist)
|
||||
|
||||
@@ -146,8 +146,8 @@ PR & COMMIT CONVENTIONS
|
||||
|
||||
- Branch: `ai/tests-<module>-YYYYMMDD`
|
||||
- Commit message examples:
|
||||
- `test(ai): add unit tests for js/nostr/parseEvent.js (agent)`
|
||||
- `test(ai): add fake-indexeddb tests for js/state/kvStore.js (agent)`
|
||||
- `test(ai): add unit tests for js/nostr/utils.js (agent)`
|
||||
- `test(ai): add fake-indexeddb tests for js/services/storageService.js (agent)`
|
||||
- PR title: `test(ai): add unit tests for <module>`
|
||||
- PR body must include:
|
||||
- Baseline test/coverage run summary
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# prompt-curator-agent - Daily Run
|
||||
|
||||
Date: 2026-02-22
|
||||
Status: Completed
|
||||
|
||||
## Summary
|
||||
|
||||
Executed daily prompt curation. Verified paths in all prompt files against the codebase.
|
||||
|
||||
## Changes
|
||||
|
||||
- **Verified Paths**: Scanned all prompts for broken file references.
|
||||
- **Fixed Issues**:
|
||||
- `weekly/bitvid-smoke-agent.md`: Fixed missing `.js` extension.
|
||||
- `weekly/bitvid-test-coverage-agent.md`: Updated examples to real files.
|
||||
- `daily/bitvid-content-audit-agent.md`: Fixed `docs/upload.md` reference and `js/services/s3UploadService.js`.
|
||||
- `daily/bitvid-deps-security-agent.md`: Updated `scripts/deps-audit.sh` to `scripts/generate-deps-report.cjs`.
|
||||
- `daily/bitvid-const-refactor-agent.md`: Updated target file examples.
|
||||
- `daily/bitvid-nip-research-agent.md`: Updated test file reference.
|
||||
- `daily/bitvid-test-audit-agent.md`: Clarified wildcard usage.
|
||||
- **Updated Status**: Updated `docs/agents/PROMPT_LIBRARY_STATUS.md`.
|
||||
@@ -197,6 +197,31 @@ function resolveEntryInput(entry) {
|
||||
return { url, mode: deriveMode(mode) };
|
||||
}
|
||||
|
||||
function getTestRelayOverrides() {
|
||||
if (typeof window === "undefined" || !window.location) return null;
|
||||
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const paramRelays = params.get("__testRelays__");
|
||||
if (paramRelays) {
|
||||
return paramRelays
|
||||
.split(",")
|
||||
.map((r) => r.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
try {
|
||||
const stored = localStorage.getItem("__bitvidTestRelays__");
|
||||
if (stored) {
|
||||
const parsed = JSON.parse(stored);
|
||||
if (Array.isArray(parsed)) return parsed;
|
||||
}
|
||||
} catch {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
class RelayPreferencesManager {
|
||||
constructor() {
|
||||
this.entries = [];
|
||||
@@ -228,6 +253,16 @@ class RelayPreferencesManager {
|
||||
return createEntry(normalized, "both");
|
||||
});
|
||||
|
||||
const testOverrides = getTestRelayOverrides();
|
||||
if (testOverrides && testOverrides.length) {
|
||||
this.defaultEntries = testOverrides
|
||||
.map((url) => {
|
||||
const normalized = normalizeRelayUrl(url) || url;
|
||||
return createEntry(normalized, "both");
|
||||
})
|
||||
.filter((e) => e.url);
|
||||
}
|
||||
|
||||
// Attempt to load from storage if policy allows
|
||||
const loaded = this.loadFromStorage();
|
||||
if (loaded && loaded.length) {
|
||||
|
||||
@@ -197,8 +197,8 @@ const formatDateInputValue = (timestampSeconds) => {
|
||||
|
||||
function handleDateChip(days) {
|
||||
if (days === "all") {
|
||||
dateStartInput.value = "";
|
||||
dateEndInput.value = "";
|
||||
if (dateStartInput) dateStartInput.value = "";
|
||||
if (dateEndInput) dateEndInput.value = "";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -209,8 +209,8 @@ function handleDateChip(days) {
|
||||
const start = new Date();
|
||||
start.setDate(now.getDate() - numDays);
|
||||
|
||||
dateStartInput.value = formatDateInputValue(Math.floor(start.getTime() / 1000));
|
||||
dateEndInput.value = formatDateInputValue(Math.floor(now.getTime() / 1000));
|
||||
if (dateStartInput) dateStartInput.value = formatDateInputValue(Math.floor(start.getTime() / 1000));
|
||||
if (dateEndInput) dateEndInput.value = formatDateInputValue(Math.floor(now.getTime() / 1000));
|
||||
}
|
||||
|
||||
// Helpers for Chips
|
||||
@@ -240,18 +240,20 @@ function syncStateToControls(filters) {
|
||||
// Logic to highlight correct date chip if it matches
|
||||
// (Simplified: just highlight 'All Time' if no dates, otherwise clear chips)
|
||||
const hasDateRange = Number.isFinite(safeFilters.dateRange?.after) || Number.isFinite(safeFilters.dateRange?.before);
|
||||
const dateBtns = dateChipsContainer.querySelectorAll("button");
|
||||
dateBtns.forEach(btn => {
|
||||
if (btn.dataset.days === "all") {
|
||||
const isActive = !hasDateRange;
|
||||
btn.setAttribute("aria-pressed", isActive);
|
||||
btn.dataset.state = isActive ? "on" : "off";
|
||||
} else {
|
||||
// We could try to calculate if range matches 24h/7d etc, but for now just clear them if custom dates are set
|
||||
btn.setAttribute("aria-pressed", "false");
|
||||
btn.dataset.state = "off";
|
||||
}
|
||||
});
|
||||
if (dateChipsContainer) {
|
||||
const dateBtns = dateChipsContainer.querySelectorAll("button");
|
||||
dateBtns.forEach(btn => {
|
||||
if (btn.dataset.days === "all") {
|
||||
const isActive = !hasDateRange;
|
||||
btn.setAttribute("aria-pressed", isActive);
|
||||
btn.dataset.state = isActive ? "on" : "off";
|
||||
} else {
|
||||
// We could try to calculate if range matches 24h/7d etc, but for now just clear them if custom dates are set
|
||||
btn.setAttribute("aria-pressed", "false");
|
||||
btn.dataset.state = "off";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Sort
|
||||
if (sortSelect) sortSelect.value = safeFilters.sort || "relevance";
|
||||
@@ -263,20 +265,22 @@ function syncStateToControls(filters) {
|
||||
if (tagsInput) tagsInput.value = "";
|
||||
// We separate tags that are in chips vs typed
|
||||
const activeTags = new Set(safeFilters.tags || []);
|
||||
const tagBtns = tagChipsContainer.querySelectorAll("button");
|
||||
const chippedTags = new Set();
|
||||
|
||||
tagBtns.forEach(btn => {
|
||||
const tag = btn.dataset.tag;
|
||||
chippedTags.add(tag);
|
||||
const isActive = activeTags.has(tag);
|
||||
btn.setAttribute("aria-pressed", isActive);
|
||||
btn.dataset.state = isActive ? "on" : "off";
|
||||
});
|
||||
if (tagChipsContainer) {
|
||||
const tagBtns = tagChipsContainer.querySelectorAll("button");
|
||||
tagBtns.forEach(btn => {
|
||||
const tag = btn.dataset.tag;
|
||||
chippedTags.add(tag);
|
||||
const isActive = activeTags.has(tag);
|
||||
btn.setAttribute("aria-pressed", isActive);
|
||||
btn.dataset.state = isActive ? "on" : "off";
|
||||
});
|
||||
}
|
||||
|
||||
// Remaining tags go to input
|
||||
const otherTags = (safeFilters.tags || []).filter(t => !chippedTags.has(t));
|
||||
if (otherTags.length) {
|
||||
if (otherTags.length && tagsInput) {
|
||||
tagsInput.value = otherTags.join(", ");
|
||||
}
|
||||
|
||||
@@ -284,34 +288,38 @@ function syncStateToControls(filters) {
|
||||
const minSec = safeFilters.duration?.minSeconds;
|
||||
const maxSec = safeFilters.duration?.maxSeconds;
|
||||
|
||||
durationShortCheckbox.checked = false;
|
||||
durationMediumCheckbox.checked = false;
|
||||
durationLongCheckbox.checked = false;
|
||||
if (durationShortCheckbox) durationShortCheckbox.checked = false;
|
||||
if (durationMediumCheckbox) durationMediumCheckbox.checked = false;
|
||||
if (durationLongCheckbox) durationLongCheckbox.checked = false;
|
||||
|
||||
if (minSec === null && maxSec === 300) durationShortCheckbox.checked = true;
|
||||
if (minSec === 300 && maxSec === 1200) durationMediumCheckbox.checked = true;
|
||||
if (minSec === 1200 && maxSec === null) durationLongCheckbox.checked = true;
|
||||
if (minSec === null && maxSec === 300 && durationShortCheckbox) durationShortCheckbox.checked = true;
|
||||
if (minSec === 300 && maxSec === 1200 && durationMediumCheckbox) durationMediumCheckbox.checked = true;
|
||||
if (minSec === 1200 && maxSec === null && durationLongCheckbox) durationLongCheckbox.checked = true;
|
||||
|
||||
// Has
|
||||
const hasBtns = hasChipsContainer.querySelectorAll("button");
|
||||
hasBtns.forEach(btn => {
|
||||
const type = btn.dataset.has;
|
||||
let isActive = false;
|
||||
if (type === "magnet") isActive = safeFilters.hasMagnet === true;
|
||||
if (type === "url") isActive = safeFilters.hasUrl === true;
|
||||
if (hasChipsContainer) {
|
||||
const hasBtns = hasChipsContainer.querySelectorAll("button");
|
||||
hasBtns.forEach(btn => {
|
||||
const type = btn.dataset.has;
|
||||
let isActive = false;
|
||||
if (type === "magnet") isActive = safeFilters.hasMagnet === true;
|
||||
if (type === "url") isActive = safeFilters.hasUrl === true;
|
||||
|
||||
btn.setAttribute("aria-pressed", isActive);
|
||||
btn.dataset.state = isActive ? "on" : "off";
|
||||
});
|
||||
btn.setAttribute("aria-pressed", isActive);
|
||||
btn.dataset.state = isActive ? "on" : "off";
|
||||
});
|
||||
}
|
||||
|
||||
// NSFW
|
||||
if (ALLOW_NSFW_CONTENT) {
|
||||
const nsfwIsOn = safeFilters.nsfw === "true" || safeFilters.nsfw === "only";
|
||||
nsfwToggle.setAttribute("aria-checked", nsfwIsOn);
|
||||
nsfwToggle.classList.toggle("is-on", nsfwIsOn);
|
||||
} else {
|
||||
nsfwToggle.setAttribute("aria-checked", "false");
|
||||
nsfwToggle.classList.remove("is-on");
|
||||
if (nsfwToggle) {
|
||||
if (ALLOW_NSFW_CONTENT) {
|
||||
const nsfwIsOn = safeFilters.nsfw === "true" || safeFilters.nsfw === "only";
|
||||
nsfwToggle.setAttribute("aria-checked", nsfwIsOn);
|
||||
nsfwToggle.classList.toggle("is-on", nsfwIsOn);
|
||||
} else {
|
||||
nsfwToggle.setAttribute("aria-checked", "false");
|
||||
nsfwToggle.classList.remove("is-on");
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-expand Advanced if needed
|
||||
|
||||
@@ -517,9 +517,9 @@ export class UploadModal {
|
||||
// Show UI
|
||||
this.sourceSections.progress.classList.remove("hidden");
|
||||
this.sourceSections.results.classList.remove("hidden");
|
||||
this.results.videoUrl.value = "Uploading...";
|
||||
this.results.magnet.value = "Pending...";
|
||||
this.results.torrentUrl.value = "Pending...";
|
||||
if (this.results.videoUrl) this.results.videoUrl.value = "Uploading...";
|
||||
if (this.results.magnet) this.results.magnet.value = "Pending...";
|
||||
if (this.results.torrentUrl) this.results.torrentUrl.value = "Pending...";
|
||||
|
||||
this.updateVideoProgress(0, "Preparing upload...");
|
||||
|
||||
@@ -615,7 +615,7 @@ export class UploadModal {
|
||||
provider: providerLabel,
|
||||
prefix: storagePrefix,
|
||||
});
|
||||
this.results.videoUrl.value = videoPublicUrl;
|
||||
if (this.results.videoUrl) this.results.videoUrl.value = videoPublicUrl;
|
||||
this.updateVideoProgress(1, "Video uploaded.");
|
||||
|
||||
// 5. Handle Torrent Result & Upload .torrent file
|
||||
@@ -670,15 +670,15 @@ export class UploadModal {
|
||||
|
||||
this.torrentState.magnet = magnet;
|
||||
|
||||
this.results.magnet.value = magnet;
|
||||
this.results.torrentUrl.value = torrentPublicUrl;
|
||||
if (this.results.magnet) this.results.magnet.value = magnet;
|
||||
if (this.results.torrentUrl) this.results.torrentUrl.value = torrentPublicUrl;
|
||||
|
||||
this.updateVideoProgress(1, "Ready to publish!");
|
||||
} else {
|
||||
this.torrentState.status = 'skipped'; // Failed hash or invalid
|
||||
this.updateVideoProgress(1, "Upload complete (No torrent fallback).");
|
||||
this.results.magnet.value = "Not available (Info Hash failed)";
|
||||
this.results.torrentUrl.value = "Not available";
|
||||
if (this.results.magnet) this.results.magnet.value = "Not available (Info Hash failed)";
|
||||
if (this.results.torrentUrl) this.results.torrentUrl.value = "Not available";
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
@@ -699,7 +699,7 @@ export class UploadModal {
|
||||
|
||||
alert(`Upload failed: ${err.message}`);
|
||||
|
||||
this.inputs.file.value = ""; // Reset
|
||||
if (this.inputs.file) this.inputs.file.value = ""; // Reset
|
||||
}
|
||||
}
|
||||
|
||||
@@ -782,7 +782,7 @@ export class UploadModal {
|
||||
|
||||
this.thumbnailUploadState.status = 'complete';
|
||||
this.thumbnailUploadState.url = publicUrl;
|
||||
this.inputs.thumbnail.value = publicUrl;
|
||||
if (this.inputs.thumbnail) this.inputs.thumbnail.value = publicUrl;
|
||||
|
||||
this.updateThumbnailProgress(1, "Thumbnail uploaded.");
|
||||
|
||||
@@ -815,28 +815,18 @@ export class UploadModal {
|
||||
}
|
||||
|
||||
const pct = Math.round(fraction * 100);
|
||||
if (this.inputs?.progress) {
|
||||
this.inputs.progress.value = pct;
|
||||
}
|
||||
if (this.statusText?.uploadPercent) {
|
||||
this.statusText.uploadPercent.textContent = `${pct}%`;
|
||||
}
|
||||
if (this.inputs.progress) this.inputs.progress.value = pct;
|
||||
if (this.statusText.uploadPercent) this.statusText.uploadPercent.textContent = `${pct}%`;
|
||||
}
|
||||
|
||||
updateThumbnailProgress(fraction, text) {
|
||||
if (text && this.statusText?.thumbnailMain) {
|
||||
this.statusText.thumbnailMain.textContent = text;
|
||||
}
|
||||
if (text && this.statusText.thumbnailMain) this.statusText.thumbnailMain.textContent = text;
|
||||
|
||||
if (fraction === null) return;
|
||||
|
||||
const pct = Math.round(fraction * 100);
|
||||
if (this.inputs?.thumbnailProgress) {
|
||||
this.inputs.thumbnailProgress.value = pct;
|
||||
}
|
||||
if (this.statusText?.thumbnailPercent) {
|
||||
this.statusText.thumbnailPercent.textContent = `${pct}%`;
|
||||
}
|
||||
if (this.inputs.thumbnailProgress) this.inputs.thumbnailProgress.value = pct;
|
||||
if (this.statusText.thumbnailPercent) this.statusText.thumbnailPercent.textContent = `${pct}%`;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -27,8 +27,8 @@
|
||||
"lint:tailwind-brackets": "node scripts/check-design-tokens.mjs --check=brackets",
|
||||
"lint:tailwind-colors": "node scripts/check-tailwind-colors.mjs",
|
||||
"check:css": "npm run build:css",
|
||||
"test:visual": "npm run build && npx playwright test",
|
||||
"test:visual:update": "npm run build && cross-env UPDATE_VISUAL_BASELINES=1 npx playwright test",
|
||||
"test:visual": "npm run build && npx playwright test --project=visual",
|
||||
"test:visual:update": "npm run build && cross-env UPDATE_VISUAL_BASELINES=1 npx playwright test --project=visual",
|
||||
"test:e2e": "npm run build && npx playwright test tests/e2e --project=e2e --project=e2e-firefox",
|
||||
"test:e2e:chromium": "npm run build && npx playwright test tests/e2e --project=e2e",
|
||||
"test:e2e:firefox": "npm run build && npx playwright test tests/e2e --project=e2e-firefox",
|
||||
|
||||
@@ -8,17 +8,17 @@ if (!global.WebSocket) {
|
||||
global.WebSocket = WebSocket;
|
||||
}
|
||||
|
||||
const RELAY_PORT = 8899;
|
||||
const RELAY_URL = `ws://127.0.0.1:${RELAY_PORT}`;
|
||||
|
||||
test.describe('Embed Player', () => {
|
||||
let relayServer;
|
||||
let RELAY_URL;
|
||||
|
||||
test.beforeAll(async () => {
|
||||
relayServer = startRelay(RELAY_PORT);
|
||||
test.beforeEach(async ({}, testInfo) => {
|
||||
const port = 8900 + (testInfo.workerIndex * 10);
|
||||
RELAY_URL = `ws://127.0.0.1:${port}`;
|
||||
relayServer = startRelay(port);
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
test.afterEach(async () => {
|
||||
if (relayServer) {
|
||||
await relayServer.close();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user