mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-05-26 12:55:16 -07:00
migrate ankiConnect.knownWords.color to subtitleStyle.knownWordColor
- Add knownWords.color → subtitleStyle.knownWordColor migration path - Fix discordPresence.updateIntervalMs label/description to say ms not seconds - Add changelog frontmatter (type/area) to settings-modal-layout fragment
This commit is contained in:
@@ -1 +1,4 @@
|
|||||||
|
type: changed
|
||||||
|
area: config
|
||||||
|
|
||||||
- Settings: reorganized playback, shortcut, WebSocket, tracking, Jellyfin, character dictionary, and Discord presence controls in the settings modal.
|
- Settings: reorganized playback, shortcut, WebSocket, tracking, Jellyfin, character dictionary, and Discord presence controls in the settings modal.
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ const LEGACY_N_PLUS_ONE_PATH_MAP = {
|
|||||||
nPlusOne: 'subtitleStyle.nPlusOneColor',
|
nPlusOne: 'subtitleStyle.nPlusOneColor',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
const hexColorPattern = /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
||||||
|
|
||||||
function propertyKey(propertyNode: JsoncNode): string | undefined {
|
function propertyKey(propertyNode: JsoncNode): string | undefined {
|
||||||
return propertyNode.children?.[0]?.value;
|
return propertyNode.children?.[0]?.value;
|
||||||
}
|
}
|
||||||
@@ -82,6 +84,12 @@ function normalizeLegacyDecks(value: unknown): unknown {
|
|||||||
return normalized;
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function asLegacyColor(value: unknown): string | undefined {
|
||||||
|
if (typeof value !== 'string') return undefined;
|
||||||
|
const text = value.trim();
|
||||||
|
return hexColorPattern.test(text) ? text : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
function buildLegacyNPlusOneMigrationOperations(root: JsoncNode | undefined): {
|
function buildLegacyNPlusOneMigrationOperations(root: JsoncNode | undefined): {
|
||||||
operations: ConfigSettingsPatchOperation[];
|
operations: ConfigSettingsPatchOperation[];
|
||||||
hasLegacy: boolean;
|
hasLegacy: boolean;
|
||||||
@@ -90,9 +98,9 @@ function buildLegacyNPlusOneMigrationOperations(root: JsoncNode | undefined): {
|
|||||||
const ankiConnect = propertyValue(findLastProperty(root, 'ankiConnect'));
|
const ankiConnect = propertyValue(findLastProperty(root, 'ankiConnect'));
|
||||||
const nPlusOneProperties = findProperties(ankiConnect, 'nPlusOne');
|
const nPlusOneProperties = findProperties(ankiConnect, 'nPlusOne');
|
||||||
const nPlusOneObjects = nPlusOneProperties.map(propertyValue).filter(Boolean) as JsoncNode[];
|
const nPlusOneObjects = nPlusOneProperties.map(propertyValue).filter(Boolean) as JsoncNode[];
|
||||||
if (nPlusOneObjects.length === 0) {
|
const knownWords = propertyValue(findLastProperty(ankiConnect, 'knownWords'));
|
||||||
return { operations, hasLegacy: false };
|
const knownWordsColorNode = propertyValue(findLastProperty(knownWords, 'color'));
|
||||||
}
|
const knownWordsColor = knownWordsColorNode ? getNodeValue(knownWordsColorNode) : undefined;
|
||||||
|
|
||||||
const canonicalNPlusOneValues = new Map<string, unknown>();
|
const canonicalNPlusOneValues = new Map<string, unknown>();
|
||||||
const legacyValues = new Map<keyof typeof LEGACY_N_PLUS_ONE_PATH_MAP, unknown>();
|
const legacyValues = new Map<keyof typeof LEGACY_N_PLUS_ONE_PATH_MAP, unknown>();
|
||||||
@@ -144,6 +152,22 @@ function buildLegacyNPlusOneMigrationOperations(root: JsoncNode | undefined): {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const legacyKnownWordsColor = asLegacyColor(knownWordsColor);
|
||||||
|
if (legacyKnownWordsColor !== undefined) {
|
||||||
|
hasLegacy = true;
|
||||||
|
if (!hasPath(root, 'subtitleStyle.knownWordColor')) {
|
||||||
|
operations.push({
|
||||||
|
op: 'set',
|
||||||
|
path: 'subtitleStyle.knownWordColor',
|
||||||
|
value: legacyKnownWordsColor,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
operations.push({
|
||||||
|
op: 'reset',
|
||||||
|
path: 'ankiConnect.knownWords.color',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return { operations, hasLegacy };
|
return { operations, hasLegacy };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2096,6 +2096,7 @@ test('migrates legacy ankiConnect n+1 color value to subtitleStyle', () => {
|
|||||||
subtitleStyle: { nPlusOneColor?: string; knownWordColor?: string };
|
subtitleStyle: { nPlusOneColor?: string; knownWordColor?: string };
|
||||||
};
|
};
|
||||||
assert.equal(parsed.subtitleStyle.nPlusOneColor, '#c6a0f6');
|
assert.equal(parsed.subtitleStyle.nPlusOneColor, '#c6a0f6');
|
||||||
|
assert.equal(parsed.subtitleStyle.knownWordColor, '#a6da95');
|
||||||
assert.equal(Object.hasOwn(parsed.ankiConnect.nPlusOne ?? {}, 'nPlusOne'), false);
|
assert.equal(Object.hasOwn(parsed.ankiConnect.nPlusOne ?? {}, 'nPlusOne'), false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ const LABEL_OVERRIDES: Record<string, string> = {
|
|||||||
'mpv.pauseUntilOverlayReady': 'Pause Until Overlay Ready',
|
'mpv.pauseUntilOverlayReady': 'Pause Until Overlay Ready',
|
||||||
'mpv.aniskipEnabled': 'Enable AniSkip',
|
'mpv.aniskipEnabled': 'Enable AniSkip',
|
||||||
'mpv.aniskipButtonKey': 'AniSkip Button Key',
|
'mpv.aniskipButtonKey': 'AniSkip Button Key',
|
||||||
'discordPresence.updateIntervalMs': 'Update Interval Seconds',
|
'discordPresence.updateIntervalMs': 'Update Interval (ms)',
|
||||||
};
|
};
|
||||||
|
|
||||||
const DESCRIPTION_OVERRIDES: Record<string, string> = {
|
const DESCRIPTION_OVERRIDES: Record<string, string> = {
|
||||||
@@ -248,7 +248,7 @@ const DESCRIPTION_OVERRIDES: Record<string, string> = {
|
|||||||
'subtitleSidebar.css':
|
'subtitleSidebar.css':
|
||||||
'CSS declarations applied to the subtitle sidebar. Includes color, background-color, all font properties, and sidebar CSS variables.',
|
'CSS declarations applied to the subtitle sidebar. Includes color, background-color, all font properties, and sidebar CSS variables.',
|
||||||
'discordPresence.updateIntervalMs':
|
'discordPresence.updateIntervalMs':
|
||||||
'Minimum interval between presence payload updates, in seconds.',
|
'Minimum interval between presence payload updates, in milliseconds.',
|
||||||
};
|
};
|
||||||
|
|
||||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||||
|
|||||||
Reference in New Issue
Block a user