mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-10-27 11:35:23 -07:00
refactor: remove dead code and enable noUnusedLocals (#292)
* refactor: remove dead code and enable noUnusedLocals
- delete launcher/jimaku.ts and the launcher Args/config jimaku* fields
that only fed it (the SUBMINER_JIMAKU_* env vars had no effect)
- delete plugin/subminer/hover.lua; nothing has sent subminer-hover-token
since Overlay 2.0
- drop never-read anilist.characterDictionary.refreshTtlHours and
evictionPolicy (still hidden in the settings UI for old configs)
- drop unused root deps: eslint, @fontsource-variable/geist{,-mono}
(stats/ declares its own)
- delete the committed draft renderer-performance plan doc
- turn on noUnusedLocals for typecheck and remove what it surfaced,
including Windows focus-handoff values computed but never consumed
* docs(changes): add docs fragment and note retired hover messages
This commit is contained in:
1 parent
ea2b3a9507
commit
8fc20b2499
52 files changed
+20
-1683
No files matched your search
@@ -41,7 +41,6 @@ import type { NPlusOneMatchMode, SubtitleMiningContext } from './types/subtitle'
|
||||
import { DEFAULT_ANKI_CONNECT_CONFIG } from './config';
|
||||
import {
|
||||
getConfiguredWordFieldCandidates,
|
||||
getConfiguredWordFieldName,
|
||||
getPreferredWordValueFromExtractedFields,
|
||||
} from './anki-field-config';
|
||||
import { createLogger } from './logger';
|
||||
@@ -1632,10 +1631,6 @@ export class AnkiIntegration {
|
||||
return sentenceCardConfig.audioField || 'SentenceAudio';
|
||||
}
|
||||
|
||||
private getConfiguredWordFieldName(): string {
|
||||
return getConfiguredWordFieldName(this.config);
|
||||
}
|
||||
|
||||
private getConfiguredWordFieldCandidates(): string[] {
|
||||
return getConfiguredWordFieldCandidates(this.config);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { DEFAULT_ANKI_CONNECT_CONFIG } from '../config';
|
||||
import type { AnkiConnectConfig } from '../types/anki';
|
||||
import {
|
||||
getKnownWordCacheLifecycleConfig,
|
||||
getKnownWordCacheRefreshIntervalMinutes,
|
||||
getKnownWordCacheScopeForConfig,
|
||||
} from './known-word-cache';
|
||||
import { getKnownWordCacheLifecycleConfig } from './known-word-cache';
|
||||
|
||||
export interface AnkiIntegrationRuntimeProxyServer {
|
||||
start(options: { host: string; port: number; upstreamUrl: string }): void;
|
||||
@@ -255,14 +251,6 @@ export class AnkiIntegrationRuntime {
|
||||
return getKnownWordCacheLifecycleConfig(config);
|
||||
}
|
||||
|
||||
private getKnownWordRefreshIntervalMinutes(config: AnkiConnectConfig): number {
|
||||
return getKnownWordCacheRefreshIntervalMinutes(config);
|
||||
}
|
||||
|
||||
private getKnownWordCacheScopeForConfig(config: AnkiConnectConfig): string {
|
||||
return getKnownWordCacheScopeForConfig(config);
|
||||
}
|
||||
|
||||
getOrCreateProxyServer(): AnkiIntegrationRuntimeProxyServer {
|
||||
if (!this.proxyServer) {
|
||||
this.proxyServer = this.deps.proxyServerFactory();
|
||||
|
||||
@@ -133,9 +133,7 @@ export const INTEGRATIONS_DEFAULT_CONFIG: Pick<
|
||||
enabled: false,
|
||||
accessToken: '',
|
||||
characterDictionary: {
|
||||
refreshTtlHours: 168,
|
||||
maxLoaded: 3,
|
||||
evictionPolicy: 'delete',
|
||||
profileScope: 'all',
|
||||
collapsibleSections: {
|
||||
description: false,
|
||||
|
||||
@@ -37,8 +37,6 @@ function collectConfigLeafPaths(config: ResolvedConfig): string[] {
|
||||
// an allowlist entry. Only allowlist a path when the registry is genuinely
|
||||
// the wrong surface for it.
|
||||
const UNDOCUMENTED_LEAVES: ReadonlySet<string> = new Set([
|
||||
'anilist.characterDictionary.evictionPolicy',
|
||||
'anilist.characterDictionary.refreshTtlHours',
|
||||
'keybindings',
|
||||
'subtitleStyle.backdropFilter',
|
||||
'subtitleStyle.backgroundColor',
|
||||
|
||||
@@ -94,27 +94,6 @@ export function applyIntegrationConfig(context: ResolveContext): void {
|
||||
if (isObject(src.anilist.characterDictionary)) {
|
||||
const characterDictionary = src.anilist.characterDictionary;
|
||||
|
||||
const refreshTtlHours = asNumber(characterDictionary.refreshTtlHours);
|
||||
if (refreshTtlHours !== undefined) {
|
||||
const normalized = Math.min(24 * 365, Math.max(1, Math.floor(refreshTtlHours)));
|
||||
if (normalized !== refreshTtlHours) {
|
||||
warn(
|
||||
'anilist.characterDictionary.refreshTtlHours',
|
||||
characterDictionary.refreshTtlHours,
|
||||
normalized,
|
||||
'Out of range; clamped to 1..8760 hours.',
|
||||
);
|
||||
}
|
||||
resolved.anilist.characterDictionary.refreshTtlHours = normalized;
|
||||
} else if (characterDictionary.refreshTtlHours !== undefined) {
|
||||
warn(
|
||||
'anilist.characterDictionary.refreshTtlHours',
|
||||
characterDictionary.refreshTtlHours,
|
||||
resolved.anilist.characterDictionary.refreshTtlHours,
|
||||
'Expected number.',
|
||||
);
|
||||
}
|
||||
|
||||
const maxLoaded = asNumber(characterDictionary.maxLoaded);
|
||||
if (maxLoaded !== undefined) {
|
||||
const normalized = Math.min(20, Math.max(1, Math.floor(maxLoaded)));
|
||||
@@ -136,28 +115,6 @@ export function applyIntegrationConfig(context: ResolveContext): void {
|
||||
);
|
||||
}
|
||||
|
||||
const evictionPolicyRaw = asString(characterDictionary.evictionPolicy);
|
||||
if (evictionPolicyRaw !== undefined) {
|
||||
const evictionPolicy = evictionPolicyRaw.trim().toLowerCase();
|
||||
if (evictionPolicy === 'disable' || evictionPolicy === 'delete') {
|
||||
resolved.anilist.characterDictionary.evictionPolicy = evictionPolicy;
|
||||
} else {
|
||||
warn(
|
||||
'anilist.characterDictionary.evictionPolicy',
|
||||
characterDictionary.evictionPolicy,
|
||||
resolved.anilist.characterDictionary.evictionPolicy,
|
||||
"Expected one of: 'disable', 'delete'.",
|
||||
);
|
||||
}
|
||||
} else if (characterDictionary.evictionPolicy !== undefined) {
|
||||
warn(
|
||||
'anilist.characterDictionary.evictionPolicy',
|
||||
characterDictionary.evictionPolicy,
|
||||
resolved.anilist.characterDictionary.evictionPolicy,
|
||||
'Expected string.',
|
||||
);
|
||||
}
|
||||
|
||||
const profileScopeRaw = asString(characterDictionary.profileScope);
|
||||
if (profileScopeRaw !== undefined) {
|
||||
const profileScope = profileScopeRaw.trim().toLowerCase();
|
||||
|
||||
@@ -97,9 +97,7 @@ test('anilist character dictionary fields are parsed, clamped, and enum-validate
|
||||
const { context, warnings } = createResolveContext({
|
||||
anilist: {
|
||||
characterDictionary: {
|
||||
refreshTtlHours: 0,
|
||||
maxLoaded: 99,
|
||||
evictionPolicy: 'purge' as never,
|
||||
profileScope: 'global' as never,
|
||||
collapsibleSections: {
|
||||
description: true,
|
||||
@@ -112,9 +110,7 @@ test('anilist character dictionary fields are parsed, clamped, and enum-validate
|
||||
|
||||
applyIntegrationConfig(context);
|
||||
|
||||
assert.equal(context.resolved.anilist.characterDictionary.refreshTtlHours, 1);
|
||||
assert.equal(context.resolved.anilist.characterDictionary.maxLoaded, 20);
|
||||
assert.equal(context.resolved.anilist.characterDictionary.evictionPolicy, 'delete');
|
||||
assert.equal(context.resolved.anilist.characterDictionary.profileScope, 'all');
|
||||
assert.equal(context.resolved.anilist.characterDictionary.collapsibleSections.description, true);
|
||||
assert.equal(
|
||||
@@ -124,9 +120,7 @@ test('anilist character dictionary fields are parsed, clamped, and enum-validate
|
||||
assert.equal(context.resolved.anilist.characterDictionary.collapsibleSections.voicedBy, true);
|
||||
|
||||
const warnedPaths = warnings.map((warning) => warning.path);
|
||||
assert.ok(warnedPaths.includes('anilist.characterDictionary.refreshTtlHours'));
|
||||
assert.ok(warnedPaths.includes('anilist.characterDictionary.maxLoaded'));
|
||||
assert.ok(warnedPaths.includes('anilist.characterDictionary.evictionPolicy'));
|
||||
assert.ok(warnedPaths.includes('anilist.characterDictionary.profileScope'));
|
||||
assert.ok(
|
||||
warnedPaths.includes('anilist.characterDictionary.collapsibleSections.characterInformation'),
|
||||
@@ -134,7 +128,7 @@ test('anilist character dictionary fields are parsed, clamped, and enum-validate
|
||||
});
|
||||
|
||||
test('yomitan externalProfilePath is trimmed and invalid values warn', () => {
|
||||
const { context, warnings } = createResolveContext({
|
||||
const { context } = createResolveContext({
|
||||
yomitan: {
|
||||
externalProfilePath: ' /tmp/gsm-profile ',
|
||||
},
|
||||
|
||||
@@ -18,10 +18,6 @@ const TOP_LEVEL_SECTION_DESCRIPTION_BY_KEY = new Map(
|
||||
CONFIG_TEMPLATE_SECTIONS.map((section) => [String(section.key), section.description[0] ?? '']),
|
||||
);
|
||||
const SUBTITLE_CSS_SCOPES: SubtitleCssScope[] = ['primary', 'secondary', 'sidebar'];
|
||||
const HIDDEN_TEMPLATE_PATHS = [
|
||||
'anilist.characterDictionary.evictionPolicy',
|
||||
'anilist.characterDictionary.refreshTtlHours',
|
||||
];
|
||||
|
||||
function normalizeCommentText(value: string): string {
|
||||
return value.replace(/\s+/g, ' ').replace(/\*\//g, '*\\/').trim();
|
||||
@@ -176,9 +172,6 @@ function renderSection(
|
||||
function createTemplateConfig(config: ResolvedConfig): ResolvedConfig {
|
||||
const templateConfig = deepCloneConfig(config);
|
||||
foldSubtitleCssManagedDefaults(templateConfig);
|
||||
for (const hiddenPath of HIDDEN_TEMPLATE_PATHS) {
|
||||
deleteValueAtPath(templateConfig, hiddenPath);
|
||||
}
|
||||
if (templateConfig.keybindings.length === 0) {
|
||||
templateConfig.keybindings = DEFAULT_KEYBINDINGS.map((binding) => ({
|
||||
key: binding.key,
|
||||
|
||||
@@ -87,20 +87,6 @@ export interface GuessAnilistMediaInfoDeps {
|
||||
runGuessit: (target: string) => Promise<string>;
|
||||
}
|
||||
|
||||
function firstString(value: unknown): string | null {
|
||||
if (typeof value === 'string') {
|
||||
const trimmed = value.trim();
|
||||
return trimmed.length > 0 ? trimmed : null;
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
for (const item of value) {
|
||||
const candidate = firstString(item);
|
||||
if (candidate) return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function normalizeGuessitTitlePart(value: string): string {
|
||||
return value.replace(/[._]+/g, ' ').replace(/-/g, ' ').replace(/\s+/g, ' ').trim();
|
||||
}
|
||||
|
||||
@@ -147,16 +147,10 @@ import { enqueueWrite } from './immersion-tracker/queue';
|
||||
import { nowMs } from './immersion-tracker/time';
|
||||
import {
|
||||
DEFAULT_BATCH_SIZE,
|
||||
DEFAULT_DAILY_ROLLUP_RETENTION_MS,
|
||||
DEFAULT_EVENTS_RETENTION_MS,
|
||||
DEFAULT_FLUSH_INTERVAL_MS,
|
||||
DEFAULT_MAINTENANCE_INTERVAL_MS,
|
||||
DEFAULT_MAX_PAYLOAD_BYTES,
|
||||
DEFAULT_MONTHLY_ROLLUP_RETENTION_MS,
|
||||
DEFAULT_QUEUE_CAP,
|
||||
DEFAULT_SESSIONS_RETENTION_MS,
|
||||
DEFAULT_TELEMETRY_RETENTION_MS,
|
||||
DEFAULT_VACUUM_INTERVAL_MS,
|
||||
EVENT_CARD_MINED,
|
||||
EVENT_LOOKUP,
|
||||
EVENT_MEDIA_BUFFER,
|
||||
|
||||
@@ -2769,7 +2769,6 @@ test('getSessionWordsByLine joins word occurrences through imm_words.id', () =>
|
||||
|
||||
try {
|
||||
ensureSchema(db);
|
||||
const stmts = createTrackerPreparedStatements(db);
|
||||
const startedAtMs = 1_735_732_800_000;
|
||||
const videoId = getOrCreateVideoRecord(db, '/tmp/session-words-by-line.mkv', {
|
||||
canonicalTitle: 'Episode',
|
||||
|
||||
@@ -18,7 +18,6 @@ import type {
|
||||
} from './types';
|
||||
import {
|
||||
ACTIVE_SESSION_METRICS_CTE,
|
||||
SESSION_WORD_COUNTS_CTE,
|
||||
SESSION_WORD_COUNTS_SELECT,
|
||||
fromDbTimestamp,
|
||||
resolvedCoverBlobExpr,
|
||||
|
||||
@@ -16,7 +16,6 @@ import { deriveStoredPartOfSpeech } from '../tokenizer/part-of-speech';
|
||||
import {
|
||||
cleanupUnusedCoverArtBlobHash,
|
||||
findSharedCoverBlobHash,
|
||||
toDbMs,
|
||||
toDbTimestamp,
|
||||
} from './query-shared';
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { ensureLexicalDailyRollupTables, markLexicalDailyRollupsReady } from './
|
||||
import { isVocabularyStatsRowVisible, type VocabularyVisibilityRow } from './vocabulary-visibility';
|
||||
import { SCHEMA_VERSION } from './types';
|
||||
import type { QueuedWrite, VideoMetadata, YoutubeVideoMetadata } from './types';
|
||||
import { toDbMs, toDbTimestamp } from './query-shared';
|
||||
import { toDbTimestamp } from './query-shared';
|
||||
|
||||
export interface TrackerPreparedStatements {
|
||||
telemetryInsertStmt: ReturnType<DatabaseSync['prepare']>;
|
||||
|
||||
@@ -74,9 +74,6 @@ export function updateVisibleOverlayVisibility(args: {
|
||||
overlayInteractionActive?: boolean;
|
||||
mainWindow: BrowserWindow | null;
|
||||
windowTracker: BaseWindowTracker | null;
|
||||
lastKnownWindowsForegroundProcessName?: string | null;
|
||||
windowsOverlayProcessName?: string | null;
|
||||
windowsFocusHandoffGraceActive?: boolean;
|
||||
macOSForegroundProbeActive?: boolean;
|
||||
trackerNotReadyWarningShown: boolean;
|
||||
setTrackerNotReadyWarningShown: (shown: boolean) => void;
|
||||
@@ -168,26 +165,6 @@ export function updateVisibleOverlayVisibility(args: {
|
||||
const shouldUseMacOSMousePassthrough = args.isMacOSPlatform && !overlayInteractionActive;
|
||||
const shouldDefaultToPassthrough =
|
||||
args.isWindowsPlatform || forceMousePassthrough || shouldReleaseMacOSOverlayLevel;
|
||||
const windowsForegroundProcessName =
|
||||
args.lastKnownWindowsForegroundProcessName?.trim().toLowerCase() ?? null;
|
||||
const windowsOverlayProcessName = args.windowsOverlayProcessName?.trim().toLowerCase() ?? null;
|
||||
const hasWindowsForegroundProcessSignal =
|
||||
args.isWindowsPlatform && windowsForegroundProcessName !== null;
|
||||
const isTrackedWindowsTargetFocused = args.windowTracker?.isTargetWindowFocused?.() ?? true;
|
||||
const isTrackedWindowsTargetMinimized =
|
||||
args.isWindowsPlatform &&
|
||||
typeof args.windowTracker?.isTargetWindowMinimized === 'function' &&
|
||||
args.windowTracker.isTargetWindowMinimized();
|
||||
const shouldPreserveWindowsOverlayDuringFocusHandoff =
|
||||
args.isWindowsPlatform &&
|
||||
args.windowsFocusHandoffGraceActive === true &&
|
||||
!!args.windowTracker &&
|
||||
(!hasWindowsForegroundProcessSignal ||
|
||||
windowsForegroundProcessName === 'mpv' ||
|
||||
(windowsOverlayProcessName !== null &&
|
||||
windowsForegroundProcessName === windowsOverlayProcessName)) &&
|
||||
!isTrackedWindowsTargetMinimized &&
|
||||
(args.windowTracker.isTracking() || args.windowTracker.getGeometry() !== null);
|
||||
const shouldForcePassiveReshow = args.isWindowsPlatform && !wasVisible;
|
||||
const isNonNativeOverlay = !args.isWindowsPlatform && !args.isMacOSPlatform;
|
||||
const isNonNativePassiveOverlay = isNonNativeOverlay && !overlayInteractionActive;
|
||||
@@ -208,13 +185,6 @@ export function updateVisibleOverlayVisibility(args: {
|
||||
(isNonNativePassiveOverlay && !hasNonNativeInputRegion) ||
|
||||
(shouldDefaultToPassthrough && (!isVisibleOverlayFocused || shouldForcePassiveReshow));
|
||||
const shouldBindTrackedWindowsOverlay = args.isWindowsPlatform && !!args.windowTracker;
|
||||
const shouldKeepTrackedWindowsOverlayTopmost =
|
||||
!args.isWindowsPlatform ||
|
||||
!args.windowTracker ||
|
||||
isVisibleOverlayFocused ||
|
||||
isTrackedWindowsTargetFocused ||
|
||||
shouldPreserveWindowsOverlayDuringFocusHandoff ||
|
||||
(hasWindowsForegroundProcessSignal && windowsForegroundProcessName === 'mpv');
|
||||
if (shouldIgnoreMouseEvents) {
|
||||
applyOverlayClickThrough(mainWindow, args.isWindowsPlatform);
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { RuntimeOptionApplyResult, RuntimeOptionId } from '../../types';
|
||||
import type { SessionActionId } from '../../types/session-bindings';
|
||||
import type { SessionActionDispatchRequest } from '../../types/runtime';
|
||||
|
||||
export interface SessionActionExecutorDeps {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { selectAll, type SqlRow, type SyncDb } from './libsql-driver';
|
||||
import { selectAll, type SyncDb } from './libsql-driver';
|
||||
import { nowDbTimestamp, tableExists, type SyncMergeSummary } from './shared';
|
||||
|
||||
const LOCAL_DAY_EXPR = `CAST(julianday(CAST(started_at_ms AS REAL) / 1000, 'unixepoch', 'localtime') - 2440587.5 AS INTEGER)`;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { parseSrtCues, parseAssCues, parseSubtitleCues } from './subtitle-cue-parser';
|
||||
import type { SubtitleCue } from '../../types';
|
||||
|
||||
test('parseSrtCues parses basic SRT content', () => {
|
||||
const content = [
|
||||
|
||||
@@ -608,14 +608,6 @@ function getYomitanFrequencyRank(
|
||||
return null;
|
||||
}
|
||||
|
||||
const normalizedHeadword = token.headword.trim();
|
||||
const normalizedSurface = token.surface.trim();
|
||||
const isInflectedHeadwordFallback =
|
||||
matchMode === 'headword' &&
|
||||
normalizedCandidateText === normalizedHeadword &&
|
||||
normalizedSurface.length > 0 &&
|
||||
normalizedSurface !== normalizedHeadword;
|
||||
|
||||
return selectBestYomitanFrequencyRank(candidateEntries);
|
||||
}
|
||||
|
||||
|
||||
@@ -390,23 +390,6 @@ function isReduplicatedKanaSfx(text: string): boolean {
|
||||
return chars.slice(0, half).join('') === chars.slice(half).join('');
|
||||
}
|
||||
|
||||
function isReduplicatedKanaSfxWithOptionalTrailingTo(text: string): boolean {
|
||||
const normalized = normalizeKana(text);
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isReduplicatedKanaSfx(normalized)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (normalized.length <= 1 || !normalized.endsWith('と')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isReduplicatedKanaSfx(normalized.slice(0, -1));
|
||||
}
|
||||
|
||||
function hasAdjacentKanaRepeat(text: string): boolean {
|
||||
const normalized = normalizeKana(text);
|
||||
if (!normalized) {
|
||||
|
||||
-15
@@ -193,14 +193,9 @@ import {
|
||||
createBuildSetOverlayDebugVisualizationEnabledMainDepsHandler,
|
||||
createTrayRuntimeHandlers,
|
||||
createOverlayVisibilityRuntime,
|
||||
createBroadcastRuntimeOptionsChangedHandler,
|
||||
createGetRuntimeOptionsStateHandler,
|
||||
createGetFieldGroupingResolverHandler,
|
||||
createSetFieldGroupingResolverHandler,
|
||||
createOpenRuntimeOptionsPaletteHandler,
|
||||
createRestorePreviousSecondarySubVisibilityHandler,
|
||||
createSendToActiveOverlayWindowHandler,
|
||||
createSetOverlayDebugVisualizationEnabledHandler,
|
||||
createLoadSubtitlePositionHandler,
|
||||
createSaveSubtitlePositionHandler,
|
||||
createAppendClipboardVideoToQueueHandler,
|
||||
@@ -297,7 +292,6 @@ import {
|
||||
handleMultiCopyDigit as handleMultiCopyDigitCore,
|
||||
hasMpvWebsocketPlugin,
|
||||
importYomitanDictionaryFromZip,
|
||||
initializeOverlayAnkiIntegration as initializeOverlayAnkiIntegrationCore,
|
||||
initializeOverlayRuntime as initializeOverlayRuntimeCore,
|
||||
isSubtitleAnnotationUpgrade,
|
||||
isOverlayWindowContentReady,
|
||||
@@ -603,7 +597,6 @@ import {
|
||||
} from './main/anilist-url-guard';
|
||||
import {
|
||||
ConfigService,
|
||||
ConfigStartupParseError,
|
||||
DEFAULT_CONFIG,
|
||||
DEFAULT_KEYBINDINGS,
|
||||
generateConfigTemplate,
|
||||
@@ -615,7 +608,6 @@ import {
|
||||
createSubtitlePrefetchService,
|
||||
type SubtitlePrefetchService,
|
||||
} from './core/services/subtitle-prefetch';
|
||||
import { buildSubtitleSidebarSourceKey } from './main/runtime/subtitle-prefetch-source';
|
||||
import { createSubtitlePrefetchInitController } from './main/runtime/subtitle-prefetch-init';
|
||||
import {
|
||||
createCachedInternalSubtitleTrackExtractor,
|
||||
@@ -623,7 +615,6 @@ import {
|
||||
} from './main/runtime/internal-subtitle-extraction';
|
||||
import { createRemoteMediaPathDetector } from './main/runtime/network-media-path';
|
||||
import { applyCharacterDictionarySelection } from './main/character-dictionary-selection';
|
||||
import { getSubsyncConfig } from './subsync/utils';
|
||||
|
||||
if (process.platform === 'linux') {
|
||||
app.commandLine.appendSwitch('enable-features', 'GlobalShortcutsPortal');
|
||||
@@ -2798,11 +2789,6 @@ const overlayVisibilityRuntime = createOverlayVisibilityRuntimeService(
|
||||
getOverlayInteractionActive: () =>
|
||||
visibleOverlayInteractionRuntime.getVisibleOverlayInteractionActive(),
|
||||
getWindowTracker: () => appState.windowTracker,
|
||||
getLastKnownWindowsForegroundProcessName: () =>
|
||||
visibleOverlayInteractionRuntime.getLastWindowsVisibleOverlayForegroundProcessName(),
|
||||
getWindowsOverlayProcessName: () => path.parse(process.execPath).name.toLowerCase(),
|
||||
getWindowsFocusHandoffGraceActive: () =>
|
||||
visibleOverlayInteractionRuntime.hasWindowsVisibleOverlayFocusHandoffGrace(),
|
||||
getMacOSForegroundProbeActive: () =>
|
||||
visibleOverlayInteractionRuntime.getMacOSVisibleOverlayForegroundProbeActive(),
|
||||
getTrackerNotReadyWarningShown: () => appState.trackerNotReadyWarningShown,
|
||||
@@ -3233,7 +3219,6 @@ const {
|
||||
cleanupJellyfinSubtitleCache,
|
||||
runJellyfinCommand,
|
||||
openJellyfinSetupWindow,
|
||||
getJellyfinClientInfo,
|
||||
ensureMpvConnectedForPlayback,
|
||||
} = composeJellyfinRuntimeHandlers({
|
||||
getResolvedJellyfinConfigMainDeps: {
|
||||
|
||||
@@ -49,7 +49,6 @@ import type {
|
||||
CharacterDictionaryRuntimeDeps,
|
||||
CharacterDictionarySnapshot,
|
||||
CharacterDictionarySnapshotImage,
|
||||
CharacterDictionarySnapshotProgress,
|
||||
CharacterDictionarySnapshotProgressCallbacks,
|
||||
CharacterDictionarySnapshotResult,
|
||||
MergedCharacterDictionaryBuildResult,
|
||||
|
||||
@@ -15,9 +15,6 @@ export interface OverlayVisibilityRuntimeDeps {
|
||||
getSuspendVisibleOverlay?: () => boolean;
|
||||
getOverlayInteractionActive?: () => boolean;
|
||||
getWindowTracker: () => BaseWindowTracker | null;
|
||||
getLastKnownWindowsForegroundProcessName?: () => string | null;
|
||||
getWindowsOverlayProcessName?: () => string | null;
|
||||
getWindowsFocusHandoffGraceActive?: () => boolean;
|
||||
getMacOSForegroundProbeActive?: () => boolean;
|
||||
getTrackerNotReadyWarningShown: () => boolean;
|
||||
setTrackerNotReadyWarningShown: (shown: boolean) => void;
|
||||
@@ -61,9 +58,6 @@ export function createOverlayVisibilityRuntimeService(
|
||||
overlayInteractionActive: deps.getOverlayInteractionActive?.() ?? false,
|
||||
mainWindow,
|
||||
windowTracker,
|
||||
lastKnownWindowsForegroundProcessName: deps.getLastKnownWindowsForegroundProcessName?.(),
|
||||
windowsOverlayProcessName: deps.getWindowsOverlayProcessName?.() ?? null,
|
||||
windowsFocusHandoffGraceActive: deps.getWindowsFocusHandoffGraceActive?.() ?? false,
|
||||
macOSForegroundProbeActive: deps.getMacOSForegroundProbeActive?.() ?? false,
|
||||
trackerNotReadyWarningShown: deps.getTrackerNotReadyWarningShown(),
|
||||
setTrackerNotReadyWarningShown: (shown: boolean) => {
|
||||
|
||||
@@ -14,10 +14,6 @@ export function createBuildOverlayVisibilityRuntimeMainDepsHandler(
|
||||
getSuspendVisibleOverlay: () => deps.getSuspendVisibleOverlay?.() ?? false,
|
||||
getOverlayInteractionActive: () => deps.getOverlayInteractionActive?.() ?? false,
|
||||
getWindowTracker: () => deps.getWindowTracker(),
|
||||
getLastKnownWindowsForegroundProcessName: () =>
|
||||
deps.getLastKnownWindowsForegroundProcessName?.() ?? null,
|
||||
getWindowsOverlayProcessName: () => deps.getWindowsOverlayProcessName?.() ?? null,
|
||||
getWindowsFocusHandoffGraceActive: () => deps.getWindowsFocusHandoffGraceActive?.() ?? false,
|
||||
getMacOSForegroundProbeActive: () => deps.getMacOSForegroundProbeActive?.() ?? false,
|
||||
getTrackerNotReadyWarningShown: () => deps.getTrackerNotReadyWarningShown(),
|
||||
setTrackerNotReadyWarningShown: (shown: boolean) => deps.setTrackerNotReadyWarningShown(shown),
|
||||
|
||||
@@ -78,7 +78,6 @@ export function createVisibleOverlayInteractionRuntime(deps: VisibleOverlayInter
|
||||
const VISIBLE_OVERLAY_BLUR_REFRESH_DELAYS_MS = [0, 25, 100, 250] as const;
|
||||
const WINDOWS_VISIBLE_OVERLAY_Z_ORDER_RETRY_DELAYS_MS = [0, 48, 120, 240, 480] as const;
|
||||
const WINDOWS_VISIBLE_OVERLAY_FOREGROUND_POLL_INTERVAL_MS = 75;
|
||||
const WINDOWS_VISIBLE_OVERLAY_FOCUS_HANDOFF_GRACE_MS = 200;
|
||||
const LINUX_VISIBLE_OVERLAY_FOCUS_HANDOFF_GRACE_MS = 1_500;
|
||||
// Ignore transient "neither mpv nor overlay is the active window" blips before suppressing
|
||||
// subtitle pointer interaction. Right after playback starts the overlay can briefly become the
|
||||
@@ -93,7 +92,6 @@ export function createVisibleOverlayInteractionRuntime(deps: VisibleOverlayInter
|
||||
let windowsVisibleOverlayForegroundPollInterval: ReturnType<typeof setInterval> | null = null;
|
||||
let windowsOverlayPointerInteractionActive = false;
|
||||
let lastWindowsVisibleOverlayForegroundProcessName: string | null = null;
|
||||
let lastWindowsVisibleOverlayBlurredAtMs = 0;
|
||||
let lastLinuxVisibleOverlayFollowedMpvAtMs = 0;
|
||||
const linuxPointerForegroundSuppressionGrace: ForegroundSuppressionGraceState = {
|
||||
lossSinceMs: null,
|
||||
@@ -482,15 +480,6 @@ export function createVisibleOverlayInteractionRuntime(deps: VisibleOverlayInter
|
||||
}
|
||||
}
|
||||
|
||||
function hasWindowsVisibleOverlayFocusHandoffGrace(): boolean {
|
||||
return (
|
||||
process.platform === 'win32' &&
|
||||
lastWindowsVisibleOverlayBlurredAtMs > 0 &&
|
||||
Date.now() - lastWindowsVisibleOverlayBlurredAtMs <=
|
||||
WINDOWS_VISIBLE_OVERLAY_FOCUS_HANDOFF_GRACE_MS
|
||||
);
|
||||
}
|
||||
|
||||
function shouldPollWindowsVisibleOverlayForegroundProcess(): boolean {
|
||||
if (process.platform !== 'win32' || !overlayManager.getVisibleOverlayVisible()) {
|
||||
return false;
|
||||
@@ -562,9 +551,6 @@ export function createVisibleOverlayInteractionRuntime(deps: VisibleOverlayInter
|
||||
return;
|
||||
}
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
lastWindowsVisibleOverlayBlurredAtMs = Date.now();
|
||||
}
|
||||
startMacOSVisibleOverlayForegroundProbe();
|
||||
clearVisibleOverlayBlurRefreshTimeouts();
|
||||
for (const delayMs of VISIBLE_OVERLAY_BLUR_REFRESH_DELAYS_MS) {
|
||||
@@ -860,7 +846,6 @@ export function createVisibleOverlayInteractionRuntime(deps: VisibleOverlayInter
|
||||
retargetOverlayWindowTrackerForMpvSocket,
|
||||
requestWindowsVisibleOverlayZOrderSync,
|
||||
scheduleWindowsVisibleOverlayZOrderSyncBurst,
|
||||
hasWindowsVisibleOverlayFocusHandoffGrace,
|
||||
ensureWindowsVisibleOverlayForegroundPollLoop,
|
||||
clearWindowsVisibleOverlayForegroundPollLoop,
|
||||
scheduleVisibleOverlayBlurRefresh,
|
||||
@@ -881,8 +866,6 @@ export function createVisibleOverlayInteractionRuntime(deps: VisibleOverlayInter
|
||||
windowsOverlayPointerInteractionActive = false;
|
||||
},
|
||||
getLinuxOverlayInputShapeActive: () => linuxOverlayInputShapeActive,
|
||||
getLastWindowsVisibleOverlayForegroundProcessName: () =>
|
||||
lastWindowsVisibleOverlayForegroundProcessName,
|
||||
getMacOSVisibleOverlayForegroundProbeActive: () => macOSVisibleOverlayForegroundProbeActive,
|
||||
setLinuxOverlayInteractiveHint: (interactive: boolean) => {
|
||||
linuxOverlayInteractiveHint = interactive;
|
||||
|
||||
@@ -1464,7 +1464,7 @@ test('keyboard mode: an open modal receives h/l/arrows instead of lookup control
|
||||
});
|
||||
|
||||
test('keyboard mode: h/l/arrows typed into a text field are not consumed by lookup controls', async () => {
|
||||
const { ctx, testGlobals, handlers, setWordCount } = createKeyboardHandlerHarness();
|
||||
const { testGlobals, handlers, setWordCount } = createKeyboardHandlerHarness();
|
||||
|
||||
try {
|
||||
await handlers.setupMpvInputForwarding();
|
||||
|
||||
@@ -31,12 +31,6 @@ export function createYoutubeTrackPickerModal(
|
||||
ctx.dom.youtubePickerStatus.style.color = isError ? '#ed8796' : '#a5adcb';
|
||||
}
|
||||
|
||||
function getTrackLabel(trackId: string): string {
|
||||
return (
|
||||
ctx.state.youtubePickerPayload?.tracks.find((track) => track.id === trackId)?.label ?? ''
|
||||
);
|
||||
}
|
||||
|
||||
function renderTrackList(): void {
|
||||
ctx.dom.youtubePickerTracks.replaceChildren();
|
||||
const payload = ctx.state.youtubePickerPayload;
|
||||
|
||||
@@ -4,7 +4,6 @@ import type {
|
||||
AiConfig,
|
||||
AiFeatureConfig,
|
||||
AnilistCharacterDictionaryCollapsibleSectionsConfig,
|
||||
AnilistCharacterDictionaryEvictionPolicy,
|
||||
AnilistCharacterDictionaryProfileScope,
|
||||
AnilistConfig,
|
||||
DiscordPresenceConfig,
|
||||
@@ -345,9 +344,7 @@ export interface ResolvedConfig {
|
||||
enabled: boolean;
|
||||
accessToken: string;
|
||||
characterDictionary: {
|
||||
refreshTtlHours: number;
|
||||
maxLoaded: number;
|
||||
evictionPolicy: AnilistCharacterDictionaryEvictionPolicy;
|
||||
profileScope: AnilistCharacterDictionaryProfileScope;
|
||||
collapsibleSections: Required<AnilistCharacterDictionaryCollapsibleSectionsConfig>;
|
||||
};
|
||||
|
||||
@@ -50,7 +50,6 @@ export interface JimakuConfig {
|
||||
maxEntryResults?: number;
|
||||
}
|
||||
|
||||
export type AnilistCharacterDictionaryEvictionPolicy = 'disable' | 'delete';
|
||||
export type AnilistCharacterDictionaryProfileScope = 'all' | 'active';
|
||||
export type AnilistCharacterDictionaryCollapsibleSectionKey =
|
||||
| 'description'
|
||||
@@ -64,9 +63,7 @@ export interface AnilistCharacterDictionaryCollapsibleSectionsConfig {
|
||||
}
|
||||
|
||||
export interface AnilistCharacterDictionaryConfig {
|
||||
refreshTtlHours?: number;
|
||||
maxLoaded?: number;
|
||||
evictionPolicy?: AnilistCharacterDictionaryEvictionPolicy;
|
||||
profileScope?: AnilistCharacterDictionaryProfileScope;
|
||||
collapsibleSections?: AnilistCharacterDictionaryCollapsibleSectionsConfig;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,6 @@ import type {
|
||||
SubtitleSidebarPlaybackState,
|
||||
SubtitleSidebarSnapshot,
|
||||
SubtitleRendererStyleConfig,
|
||||
SubtitleStyleConfig,
|
||||
} from './subtitle';
|
||||
import type {
|
||||
RuntimeOptionApplyResult,
|
||||
|
||||
@@ -13,7 +13,8 @@ const RECT = koffi.struct('RECT', {
|
||||
Bottom: 'int',
|
||||
});
|
||||
|
||||
const MARGINS = koffi.struct('MARGINS', {
|
||||
// Registered by name for the DwmExtendFrameIntoClientArea prototype below.
|
||||
koffi.struct('MARGINS', {
|
||||
cxLeftWidth: 'int',
|
||||
cxRightWidth: 'int',
|
||||
cyTopHeight: 'int',
|
||||
|
||||
Reference in new issue
Block a user