Add startup, search and play timing marks plus yt-dlp duration logs
This commit is contained in:
@@ -23,6 +23,18 @@ const ZERO = window.zero && typeof window.zero.invoke === 'function' ? window.ze
|
|||||||
const WEB = !TAURI && !ZERO;
|
const WEB = !TAURI && !ZERO;
|
||||||
const APP_VERSION = '1.0.0';
|
const APP_VERSION = '1.0.0';
|
||||||
|
|
||||||
|
// Timing marks for the speed work (plans/). performance.measure entries are
|
||||||
|
// visible in DevTools → Performance; __ytpPerf() prints the latest ones.
|
||||||
|
function perfMark(name) { try { performance.mark(name); } catch { /* old browser */ } }
|
||||||
|
function perfMeasure(name, start) {
|
||||||
|
try { performance.measure(name, start); } catch { /* start mark missing */ }
|
||||||
|
}
|
||||||
|
window.__ytpPerf = () => {
|
||||||
|
const out = {};
|
||||||
|
try { for (const m of performance.getEntriesByType('measure')) if (m.name.startsWith('ytp:')) out[m.name] = Math.round(m.duration); } catch { /* none */ }
|
||||||
|
return out;
|
||||||
|
};
|
||||||
|
|
||||||
// call(zeroName, tauriName, payload) — routes to whichever native shell is present.
|
// call(zeroName, tauriName, payload) — routes to whichever native shell is present.
|
||||||
async function call(zeroName, tauriName, payload = {}) {
|
async function call(zeroName, tauriName, payload = {}) {
|
||||||
if (TAURI) return await TAURI.invoke(tauriName, payload);
|
if (TAURI) return await TAURI.invoke(tauriName, payload);
|
||||||
@@ -1649,6 +1661,7 @@ const Player = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async loadVideo(videoObj, { preferStream = false, resume = true, reveal = true, nocache = false } = {}) {
|
async loadVideo(videoObj, { preferStream = false, resume = true, reveal = true, nocache = false } = {}) {
|
||||||
|
perfMark('ytp:tap');
|
||||||
if (!this._handoff) Transition.cancel();
|
if (!this._handoff) Transition.cancel();
|
||||||
// When false (auto-advance / prev), skip resuming the saved timestamp and
|
// When false (auto-advance / prev), skip resuming the saved timestamp and
|
||||||
// start from the beginning (or the A marker, if an A-B loop is set).
|
// start from the beginning (or the A marker, if an A-B loop is set).
|
||||||
@@ -2286,6 +2299,10 @@ function wirePlayerEvents() {
|
|||||||
});
|
});
|
||||||
el.addEventListener('playing', () => {
|
el.addEventListener('playing', () => {
|
||||||
if (!masterIs(el)) return;
|
if (!masterIs(el)) return;
|
||||||
|
if (performance.getEntriesByName('ytp:tap').length) {
|
||||||
|
perfMeasure('ytp:tap-to-play', 'ytp:tap');
|
||||||
|
try { performance.clearMarks('ytp:tap'); } catch { /* ignore */ }
|
||||||
|
}
|
||||||
showSpinner(false);
|
showSpinner(false);
|
||||||
Player.clearBufferGrace();
|
Player.clearBufferGrace();
|
||||||
if (Player.secondary && !el.paused && Player.secondary.paused) {
|
if (Player.secondary && !el.paused && Player.secondary.paused) {
|
||||||
@@ -8584,6 +8601,7 @@ function wireUI() {
|
|||||||
q = (q || '').trim();
|
q = (q || '').trim();
|
||||||
if (!q) return;
|
if (!q) return;
|
||||||
const mySeq = ++searchSeq;
|
const mySeq = ++searchSeq;
|
||||||
|
perfMark('ytp:search-start');
|
||||||
RecentSearches.add(q);
|
RecentSearches.add(q);
|
||||||
hideRecentSearches();
|
hideRecentSearches();
|
||||||
view = { type: 'search' };
|
view = { type: 'search' };
|
||||||
@@ -8607,6 +8625,7 @@ function wireUI() {
|
|||||||
searchAttempted = true;
|
searchAttempted = true;
|
||||||
renderList();
|
renderList();
|
||||||
RecentSearches.cacheResults(q, results);
|
RecentSearches.cacheResults(q, results);
|
||||||
|
perfMeasure('ytp:search', 'ytp:search-start');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (mySeq !== searchSeq) return;
|
if (mySeq !== searchSeq) return;
|
||||||
if (instant) return; // keep showing the cached results; fail silently
|
if (instant) return; // keep showing the cached results; fail silently
|
||||||
@@ -9747,6 +9766,7 @@ function bootSearchFromUrl() {
|
|||||||
// Boot
|
// Boot
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
async function boot() {
|
async function boot() {
|
||||||
|
perfMark('ytp:boot-start');
|
||||||
wirePlayerEvents();
|
wirePlayerEvents();
|
||||||
wireUI();
|
wireUI();
|
||||||
wireShortcutHelp();
|
wireShortcutHelp();
|
||||||
@@ -9795,6 +9815,7 @@ async function boot() {
|
|||||||
// first, which left the sidebar empty for as long as the network took.
|
// first, which left the sidebar empty for as long as the network took.
|
||||||
renderSmartSidebar();
|
renderSmartSidebar();
|
||||||
render();
|
render();
|
||||||
|
perfMeasure('ytp:boot', 'ytp:boot-start');
|
||||||
|
|
||||||
// …then reconcile with the server in the background, with the spinner up,
|
// …then reconcile with the server in the background, with the spinner up,
|
||||||
// and re-render only if something actually changed.
|
// and re-render only if something actually changed.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ green, app boots with no JS errors, P2P on by default, offline boot works).
|
|||||||
|
|
||||||
| Seq | ID | Title | Status | Commit | Notes |
|
| Seq | ID | Title | Status | Commit | Notes |
|
||||||
|-----|----|-------|--------|--------|-------|
|
|-----|----|-------|--------|--------|-------|
|
||||||
| 001 | 001-perf-timing-marks-105acc | Add startup, search and play timing marks plus yt-dlp duration logs | in-progress | | baseline numbers for the rest |
|
| 001 | 001-perf-timing-marks-105acc | Add startup, search and play timing marks plus yt-dlp duration logs | done | Add startup, search and play timing marks plus yt-dlp duration logs | baseline numbers for the rest |
|
||||||
| 002 | 002-compress-and-etag-shell-bd459c | Serve the app shell gzip/brotli-compressed with ETags | queued | | app.js 426 KB → 94 KB (br) |
|
| 002 | 002-compress-and-etag-shell-bd459c | Serve the app shell gzip/brotli-compressed with ETags | queued | | app.js 426 KB → 94 KB (br) |
|
||||||
| 003 | 003-self-host-fonts-89466b | Self-host the three web fonts and drop the render-blocking Google Fonts CSS | queued | | needs network once; CSP font-src fix |
|
| 003 | 003-self-host-fonts-89466b | Self-host the three web fonts and drop the render-blocking Google Fonts CSS | queued | | needs network once; CSP font-src fix |
|
||||||
| 004 | 004-coalesce-stream-resolves-a92d40 | Coalesce concurrent resolveStreams calls for the same video | queued | | |
|
| 004 | 004-coalesce-stream-resolves-a92d40 | Coalesce concurrent resolveStreams calls for the same video | queued | | |
|
||||||
|
|||||||
@@ -121,3 +121,9 @@ Output ONLY the following, no other prose:
|
|||||||
skipped and why.
|
skipped and why.
|
||||||
|
|
||||||
Do not commit. Do not push. Do not touch files outside the Steps.
|
Do not commit. Do not push. Do not touch files outside the Steps.
|
||||||
|
|
||||||
|
## Execution log
|
||||||
|
|
||||||
|
- Executor: in-session Agent (haiku), gateway `delegate.sh` not installed. Attempts: 1. Fix rounds: 0.
|
||||||
|
- Orchestrator re-ran Verification: syntax OK, `SERVER_OK`, `node --test frontend/*.test.js` 52 pass / 0 fail, mark count 8.
|
||||||
|
- Executor Findings (verbatim): All 6 plan steps applied successfully. Frontend timing marks added for boot (start->first paint), search (start->cached), tap-to-play (tap->playing event). Server logs yt-dlp duration on every invocation. Verification: syntax OK, server builds, unit tests pass (0 failures), 8 perfMark/perfMeasure occurrences (exceeds required 8). No deviations or skips.
|
||||||
@@ -143,6 +143,9 @@ const CHANNEL_LIMIT = 60;
|
|||||||
function runYtdlp(args, { signal } = {}) {
|
function runYtdlp(args, { signal } = {}) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const child = spawn(YTDLP, args, { stdio: ['ignore', 'pipe', 'pipe'] });
|
const child = spawn(YTDLP, args, { stdio: ['ignore', 'pipe', 'pipe'] });
|
||||||
|
const t0 = Date.now();
|
||||||
|
const kind = String(args.find((a) => /^ytsearch|^https?:/.test(String(a))) || args[0] || '')
|
||||||
|
.replace(/^ytsearch\d*:.*/, 'search').replace(/^https?:\/\/[^/]+\/watch.*/, 'video').slice(0, 40);
|
||||||
// Kill the download when the requesting client goes away — otherwise an
|
// Kill the download when the requesting client goes away — otherwise an
|
||||||
// aborted/retried save leaves yt-dlp running to completion (8 copies of
|
// aborted/retried save leaves yt-dlp running to completion (8 copies of
|
||||||
// one video were found pulling in parallel after the client retried).
|
// one video were found pulling in parallel after the client retried).
|
||||||
@@ -158,6 +161,7 @@ function runYtdlp(args, { signal } = {}) {
|
|||||||
child.stderr.on('data', (d) => { err += d; });
|
child.stderr.on('data', (d) => { err += d; });
|
||||||
child.on('error', (e) => reject(new Error('yt-dlp not found: ' + e.message)));
|
child.on('error', (e) => reject(new Error('yt-dlp not found: ' + e.message)));
|
||||||
child.on('close', (code) => {
|
child.on('close', (code) => {
|
||||||
|
console.log(`[ytdlp] ${kind} ${Date.now() - t0}ms ${code === 0 ? 'ok' : 'fail'}`);
|
||||||
if (code !== 0) reject(new Error(err.trim() || 'yt-dlp exited with code ' + code));
|
if (code !== 0) reject(new Error(err.trim() || 'yt-dlp exited with code ' + code));
|
||||||
else resolve(out);
|
else resolve(out);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user