[codex] Make Windows mpv shortcut self-contained (#40)

This commit is contained in:
2026-04-03 21:35:18 -07:00
committed by GitHub
parent d6c72806bb
commit 7514985feb
131 changed files with 3367 additions and 716 deletions

View File

@@ -38,6 +38,7 @@ export function createKeyboardHandlers(
let pendingSelectionAnchorAfterSubtitleSeek: 'start' | 'end' | null = null;
let pendingLookupRefreshAfterSubtitleSeek = false;
let resetSelectionToStartOnNextSubtitleSync = false;
let lookupScanFallbackTimer: ReturnType<typeof setTimeout> | null = null;
const CHORD_MAP = new Map<
string,
@@ -358,12 +359,10 @@ export function createKeyboardHandlers(
});
}
function isSubtitleSeekCommand(command: (string | number)[] | undefined): command is [string, number] {
return (
Array.isArray(command) &&
command[0] === 'sub-seek' &&
typeof command[1] === 'number'
);
function isSubtitleSeekCommand(
command: (string | number)[] | undefined,
): command is [string, number] {
return Array.isArray(command) && command[0] === 'sub-seek' && typeof command[1] === 'number';
}
function dispatchConfiguredMpvCommand(command: (string | number)[]): void {
@@ -485,7 +484,9 @@ export function createKeyboardHandlers(
});
}
// Fallback only if the explicit scan path did not open popup quickly.
setTimeout(() => {
if (lookupScanFallbackTimer !== null) clearTimeout(lookupScanFallbackTimer);
lookupScanFallbackTimer = setTimeout(() => {
lookupScanFallbackTimer = null;
if (ctx.state.yomitanPopupVisible || isYomitanPopupVisible(document)) {
return;
}
@@ -525,6 +526,10 @@ export function createKeyboardHandlers(
return false;
}
if (lookupScanFallbackTimer !== null) {
clearTimeout(lookupScanFallbackTimer);
lookupScanFallbackTimer = null;
}
dispatchYomitanPopupVisibility(false);
dispatchYomitanFrontendClearActiveTextSource();
clearNativeSubtitleSelection();

View File

@@ -1,7 +1,4 @@
import type {
PlaylistBrowserDirectoryItem,
PlaylistBrowserQueueItem,
} from '../../types';
import type { PlaylistBrowserDirectoryItem, PlaylistBrowserQueueItem } from '../../types';
import type { RendererContext } from '../context';
type PlaylistBrowserRowRenderActions = {
@@ -55,7 +52,7 @@ export function renderPlaylistBrowserDirectoryRow(
? item.episodeLabel
? `${item.episodeLabel} · Current file`
: 'Current file'
: item.episodeLabel ?? 'Video file';
: (item.episodeLabel ?? 'Video file');
main.append(label, meta);
const trailing = document.createElement('div');

View File

@@ -236,9 +236,17 @@ function createPlaylistBrowserElectronApi(overrides?: Partial<ElectronAPI>): Ele
notifyOverlayModalClosed: () => {},
focusMainWindow: async () => {},
setIgnoreMouseEvents: () => {},
appendPlaylistBrowserFile: async () => ({ ok: true, message: 'ok', snapshot: createSnapshot() }),
appendPlaylistBrowserFile: async () => ({
ok: true,
message: 'ok',
snapshot: createSnapshot(),
}),
playPlaylistBrowserIndex: async () => ({ ok: true, message: 'ok', snapshot: createSnapshot() }),
removePlaylistBrowserIndex: async () => ({ ok: true, message: 'ok', snapshot: createSnapshot() }),
removePlaylistBrowserIndex: async () => ({
ok: true,
message: 'ok',
snapshot: createSnapshot(),
}),
movePlaylistBrowserIndex: async () => ({ ok: true, message: 'ok', snapshot: createSnapshot() }),
...overrides,
} as ElectronAPI;
@@ -348,15 +356,13 @@ test('playlist browser modal action buttons stop double-click propagation', asyn
await modal.openPlaylistBrowserModal();
const row =
env.dom.playlistBrowserDirectoryList.children[0] as
| ReturnType<typeof createPlaylistRow>
| undefined;
const row = env.dom.playlistBrowserDirectoryList.children[0] as
| ReturnType<typeof createPlaylistRow>
| undefined;
const trailing = row?.children?.[1] as ReturnType<typeof createPlaylistRow> | undefined;
const button =
trailing?.children?.at(-1) as
| { listeners?: Map<string, Array<(event?: unknown) => void>> }
| undefined;
const button = trailing?.children?.at(-1) as
| { listeners?: Map<string, Array<(event?: unknown) => void>> }
| undefined;
const dblclickHandler = button?.listeners?.get('dblclick')?.[0];
assert.equal(typeof dblclickHandler, 'function');

View File

@@ -31,7 +31,8 @@ function getDefaultDirectorySelectionIndex(snapshot: PlaylistBrowserSnapshot): n
function getDefaultPlaylistSelectionIndex(snapshot: PlaylistBrowserSnapshot): number {
const playlistIndex =
snapshot.playingIndex ?? snapshot.playlistItems.findIndex((item) => item.current || item.playing);
snapshot.playingIndex ??
snapshot.playlistItems.findIndex((item) => item.current || item.playing);
return clampIndex(playlistIndex >= 0 ? playlistIndex : 0, snapshot.playlistItems.length);
}
@@ -225,7 +226,10 @@ export function createPlaylistBrowserModal(
}
async function removePlaylistItem(index: number): Promise<void> {
await handleMutation(window.electronAPI.removePlaylistBrowserIndex(index), 'Removed queue item');
await handleMutation(
window.electronAPI.removePlaylistBrowserIndex(index),
'Removed queue item',
);
}
async function movePlaylistItem(index: number, direction: 1 | -1): Promise<void> {

View File

@@ -453,8 +453,7 @@ body {
padding: 14px;
border-radius: 16px;
border: 1px solid rgba(110, 115, 141, 0.16);
background:
linear-gradient(180deg, rgba(54, 58, 79, 0.55), rgba(36, 39, 58, 0.6));
background: linear-gradient(180deg, rgba(54, 58, 79, 0.55), rgba(36, 39, 58, 0.6));
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
}
@@ -496,8 +495,12 @@ body {
}
.playlist-browser-row.current {
background:
linear-gradient(90deg, rgba(138, 173, 244, 0.12), rgba(138, 173, 244, 0.03) 28%, transparent);
background: linear-gradient(
90deg,
rgba(138, 173, 244, 0.12),
rgba(138, 173, 244, 0.03) 28%,
transparent
);
box-shadow: inset 3px 0 0 #8aadf4;
}

View File

@@ -222,8 +222,12 @@ export function resolveRendererDom(): RendererDom {
playlistBrowserModal: getRequiredElement<HTMLDivElement>('playlistBrowserModal'),
playlistBrowserTitle: getRequiredElement<HTMLDivElement>('playlistBrowserTitle'),
playlistBrowserStatus: getRequiredElement<HTMLDivElement>('playlistBrowserStatus'),
playlistBrowserDirectoryList: getRequiredElement<HTMLUListElement>('playlistBrowserDirectoryList'),
playlistBrowserPlaylistList: getRequiredElement<HTMLUListElement>('playlistBrowserPlaylistList'),
playlistBrowserDirectoryList: getRequiredElement<HTMLUListElement>(
'playlistBrowserDirectoryList',
),
playlistBrowserPlaylistList: getRequiredElement<HTMLUListElement>(
'playlistBrowserPlaylistList',
),
playlistBrowserClose: getRequiredElement<HTMLButtonElement>('playlistBrowserClose'),
};
}