mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-03-26 00:26:05 -07:00
Refine YouTube playback launch preparation
This commit is contained in:
@@ -18,7 +18,12 @@ test('prepare youtube playback skips load when current path already matches exac
|
|||||||
const ok = await prepare({ url: 'https://www.youtube.com/watch?v=abc123' });
|
const ok = await prepare({ url: 'https://www.youtube.com/watch?v=abc123' });
|
||||||
|
|
||||||
assert.equal(ok, true);
|
assert.equal(ok, true);
|
||||||
assert.deepEqual(commands, []);
|
assert.deepEqual(commands, [
|
||||||
|
['set_property', 'pause', 'yes'],
|
||||||
|
['set_property', 'sub-auto', 'no'],
|
||||||
|
['set_property', 'sid', 'no'],
|
||||||
|
['set_property', 'secondary-sid', 'no'],
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('prepare youtube playback treats matching video IDs as already loaded', async () => {
|
test('prepare youtube playback treats matching video IDs as already loaded', async () => {
|
||||||
@@ -33,7 +38,12 @@ test('prepare youtube playback treats matching video IDs as already loaded', asy
|
|||||||
const ok = await prepare({ url: 'https://www.youtube.com/watch?v=abc123' });
|
const ok = await prepare({ url: 'https://www.youtube.com/watch?v=abc123' });
|
||||||
|
|
||||||
assert.equal(ok, true);
|
assert.equal(ok, true);
|
||||||
assert.deepEqual(commands, []);
|
assert.deepEqual(commands, [
|
||||||
|
['set_property', 'pause', 'yes'],
|
||||||
|
['set_property', 'sub-auto', 'no'],
|
||||||
|
['set_property', 'sid', 'no'],
|
||||||
|
['set_property', 'secondary-sid', 'no'],
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('prepare youtube playback does not mark matching target ready until tracks exist', async () => {
|
test('prepare youtube playback does not mark matching target ready until tracks exist', async () => {
|
||||||
@@ -59,7 +69,12 @@ test('prepare youtube playback does not mark matching target ready until tracks
|
|||||||
});
|
});
|
||||||
|
|
||||||
assert.equal(ok, true);
|
assert.equal(ok, true);
|
||||||
assert.deepEqual(commands, []);
|
assert.deepEqual(commands, [
|
||||||
|
['set_property', 'pause', 'yes'],
|
||||||
|
['set_property', 'sub-auto', 'no'],
|
||||||
|
['set_property', 'sid', 'no'],
|
||||||
|
['set_property', 'secondary-sid', 'no'],
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('prepare youtube playback replaces media and waits for path switch', async () => {
|
test('prepare youtube playback replaces media and waits for path switch', async () => {
|
||||||
@@ -185,13 +200,17 @@ test('prepare youtube playback accepts a non-youtube resolved path once playable
|
|||||||
});
|
});
|
||||||
|
|
||||||
const ok = await prepare({
|
const ok = await prepare({
|
||||||
url: 'https://www.youtube.com/watch?v=newvid',
|
url: 'https://rr16---sn.example.googlevideo.com/videoplayback?id=abc',
|
||||||
timeoutMs: 1500,
|
timeoutMs: 1500,
|
||||||
pollIntervalMs: 1,
|
pollIntervalMs: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.equal(ok, true);
|
assert.equal(ok, true);
|
||||||
assert.deepEqual(commands[4], ['loadfile', 'https://www.youtube.com/watch?v=newvid', 'replace']);
|
assert.deepEqual(commands[4], [
|
||||||
|
'loadfile',
|
||||||
|
'https://rr16---sn.example.googlevideo.com/videoplayback?id=abc',
|
||||||
|
'replace',
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('prepare youtube playback does not accept a different youtube video after path change', async () => {
|
test('prepare youtube playback does not accept a different youtube video after path change', async () => {
|
||||||
@@ -234,3 +253,39 @@ test('prepare youtube playback does not accept a different youtube video after p
|
|||||||
'replace',
|
'replace',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('prepare youtube playback accepts a fresh-start path change when the direct target matches exactly', async () => {
|
||||||
|
const commands: Array<Array<string>> = [];
|
||||||
|
const observedPaths = [
|
||||||
|
'',
|
||||||
|
'https://rr16---sn.example.googlevideo.com/videoplayback?id=abc',
|
||||||
|
];
|
||||||
|
const observedTrackLists = [[], [{ type: 'video', id: 1 }, { type: 'audio', id: 2 }]];
|
||||||
|
let requestCount = 0;
|
||||||
|
const prepare = createPrepareYoutubePlaybackInMpvHandler({
|
||||||
|
requestPath: async () => {
|
||||||
|
const value = observedPaths[Math.min(requestCount, observedPaths.length - 1)] ?? null;
|
||||||
|
requestCount += 1;
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
requestProperty: async (name) => {
|
||||||
|
if (name !== 'track-list') return null;
|
||||||
|
return observedTrackLists[Math.min(requestCount - 1, observedTrackLists.length - 1)] ?? [];
|
||||||
|
},
|
||||||
|
sendMpvCommand: (command) => commands.push(command),
|
||||||
|
wait: createWaitStub(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const ok = await prepare({
|
||||||
|
url: 'https://rr16---sn.example.googlevideo.com/videoplayback?id=abc',
|
||||||
|
timeoutMs: 1500,
|
||||||
|
pollIntervalMs: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(ok, true);
|
||||||
|
assert.deepEqual(commands[4], [
|
||||||
|
'loadfile',
|
||||||
|
'https://rr16---sn.example.googlevideo.com/videoplayback?id=abc',
|
||||||
|
'replace',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|||||||
@@ -79,6 +79,13 @@ function hasPlayableMediaTracks(trackListRaw: unknown): boolean {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sendPlaybackPrepCommands(sendMpvCommand: (command: Array<string>) => void): void {
|
||||||
|
sendMpvCommand(['set_property', 'pause', 'yes']);
|
||||||
|
sendMpvCommand(['set_property', 'sub-auto', 'no']);
|
||||||
|
sendMpvCommand(['set_property', 'sid', 'no']);
|
||||||
|
sendMpvCommand(['set_property', 'secondary-sid', 'no']);
|
||||||
|
}
|
||||||
|
|
||||||
export function createPrepareYoutubePlaybackInMpvHandler(deps: YoutubePlaybackLaunchDeps) {
|
export function createPrepareYoutubePlaybackInMpvHandler(deps: YoutubePlaybackLaunchDeps) {
|
||||||
const now = deps.now ?? (() => Date.now());
|
const now = deps.now ?? (() => Date.now());
|
||||||
return async (input: YoutubePlaybackLaunchInput): Promise<boolean> => {
|
return async (input: YoutubePlaybackLaunchInput): Promise<boolean> => {
|
||||||
@@ -95,6 +102,8 @@ export function createPrepareYoutubePlaybackInMpvHandler(deps: YoutubePlaybackLa
|
|||||||
// Ignore transient path request failures and continue with bootstrap commands.
|
// Ignore transient path request failures and continue with bootstrap commands.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendPlaybackPrepCommands(deps.sendMpvCommand);
|
||||||
|
|
||||||
const alreadyTarget = pathMatchesYoutubeTarget(previousPath, targetUrl);
|
const alreadyTarget = pathMatchesYoutubeTarget(previousPath, targetUrl);
|
||||||
if (alreadyTarget) {
|
if (alreadyTarget) {
|
||||||
if (!deps.requestProperty) {
|
if (!deps.requestProperty) {
|
||||||
@@ -109,10 +118,6 @@ export function createPrepareYoutubePlaybackInMpvHandler(deps: YoutubePlaybackLa
|
|||||||
// Keep polling; mpv can report the target path before tracks are ready.
|
// Keep polling; mpv can report the target path before tracks are ready.
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
deps.sendMpvCommand(['set_property', 'pause', 'yes']);
|
|
||||||
deps.sendMpvCommand(['set_property', 'sub-auto', 'no']);
|
|
||||||
deps.sendMpvCommand(['set_property', 'sid', 'no']);
|
|
||||||
deps.sendMpvCommand(['set_property', 'secondary-sid', 'no']);
|
|
||||||
deps.sendMpvCommand(['loadfile', targetUrl, 'replace']);
|
deps.sendMpvCommand(['loadfile', targetUrl, 'replace']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,12 +144,13 @@ export function createPrepareYoutubePlaybackInMpvHandler(deps: YoutubePlaybackLa
|
|||||||
// Continue polling until media tracks are actually available.
|
// Continue polling until media tracks are actually available.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (previousPath && currentPath !== previousPath) {
|
const pathChanged = currentPath !== previousPath;
|
||||||
if (isYoutubeMediaPath(currentPath) && isYoutubeMediaPath(targetUrl)) {
|
const matchesChangedTarget =
|
||||||
if (!pathMatchesYoutubeTarget(currentPath, targetUrl)) {
|
currentPath === targetUrl ||
|
||||||
continue;
|
(isYoutubeMediaPath(currentPath) &&
|
||||||
}
|
isYoutubeMediaPath(targetUrl) &&
|
||||||
}
|
pathMatchesYoutubeTarget(currentPath, targetUrl));
|
||||||
|
if (pathChanged && matchesChangedTarget) {
|
||||||
if (deps.requestProperty) {
|
if (deps.requestProperty) {
|
||||||
try {
|
try {
|
||||||
const trackList = await deps.requestProperty('track-list');
|
const trackList = await deps.requestProperty('track-list');
|
||||||
|
|||||||
Reference in New Issue
Block a user