mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-07-27 04:49:49 -07:00
refactor(tsukihime): rename tabs from English/Japanese to secondary/prim
- Tab identifiers and DOM IDs now reflect role (secondary/primary) not language - State type `tsukihimeActiveTab` updated from `'en' | 'ja'` to `'secondary' | 'primary'` - Docs and config comments updated to match
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
type: added
|
||||
area: overlay
|
||||
|
||||
- Added a TsukiHime integration for downloading English (and Japanese) subtitles, mirroring the Jimaku flow: `Ctrl+Shift+T` (configurable via `shortcuts.openTsukihime`) opens an in-overlay modal with two language tabs (the first follows `secondarySub.secondarySubLanguages`, defaulting to English; the second is Japanese) that parses the current video filename, searches TsukiHime releases, lists extracted text subtitle tracks filtered by the active tab, then downloads the chosen track, decompresses it (requires the `xz` binary), saves it next to the video with a language suffix (`<video>.en.<ext>`, `.ja` for Japanese tracks, etc.), and loads it into mpv immediately - Japanese tracks as the primary subtitle, other languages as the secondary subtitle. No API key is required; also reachable via `subminer --open-tsukihime`, the `__tsukihime-open` keybinding command, and configurable under a new `tsukihime` config section. TsukiHime is the successor to Animetosho, which stops processing new releases in May 2026; it imported the Animetosho index and mirrors its attachment storage, so older releases stay reachable. Existing `animetosho`, `shortcuts.openAnimetosho`, `--open-animetosho`, and `__animetosho-open` inputs remain accepted as deprecated aliases.
|
||||
- Added a TsukiHime integration for downloading primary and secondary subtitles, mirroring the Jimaku flow: `Ctrl+Shift+T` (configurable via `shortcuts.openTsukihime`) opens an in-overlay modal with a Japanese primary tab and a secondary tab that follows `secondarySub.secondarySubLanguages`. It parses the current video filename, searches TsukiHime releases, lists extracted text subtitle tracks filtered by the active tab, then downloads the chosen track, decompresses it (requires the `xz` binary), saves it next to the video with a language suffix (`<video>.en.<ext>`, `.ja` for Japanese tracks, etc.), and loads Japanese into mpv's primary slot or configured secondary tracks into its secondary slot. No API key is required; also reachable via `subminer --open-tsukihime`, the `__tsukihime-open` keybinding command, and configurable under a new `tsukihime` config section. TsukiHime is the successor to Animetosho, which stops processing new releases in May 2026; it imported the Animetosho index and mirrors its attachment storage, so older releases stay reachable. Existing `animetosho`, `shortcuts.openAnimetosho`, `--open-animetosho`, and `__animetosho-open` inputs remain accepted as deprecated aliases.
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
"openCharacterDictionaryManager": "CommandOrControl+D", // Accelerator that opens the character dictionary manager modal.
|
||||
"openRuntimeOptions": "CommandOrControl+Shift+O", // Accelerator that opens the runtime options modal.
|
||||
"openJimaku": "Ctrl+Shift+J", // Accelerator that opens the Jimaku subtitle search modal.
|
||||
"openTsukihime": "Ctrl+Shift+T", // Accelerator that opens the TsukiHime subtitle search modal (English/Japanese tabs).
|
||||
"openTsukihime": "Ctrl+Shift+T", // Accelerator that opens the TsukiHime subtitle search modal (configured secondary/Japanese primary tabs).
|
||||
"openSessionHelp": "CommandOrControl+Slash", // Accelerator that opens the session help / keybinding cheatsheet.
|
||||
"openControllerSelect": "Alt+C", // Accelerator that opens the controller selection and learn-mode modal.
|
||||
"openControllerDebug": "Alt+Shift+C", // Accelerator that opens the controller debug modal with live axis/button readouts.
|
||||
@@ -615,13 +615,13 @@
|
||||
|
||||
// ==========================================
|
||||
// TsukiHime
|
||||
// TsukiHime subtitle search configuration (English and Japanese). No API key required.
|
||||
// TsukiHime subtitle search configuration for Japanese primary and configured secondary subtitles. No API key required.
|
||||
// Hot-reload: TsukiHime changes apply to the next TsukiHime request.
|
||||
// ==========================================
|
||||
"tsukihime": {
|
||||
"apiBaseUrl": "https://api.tsukihime.org/v1", // Base URL of the TsukiHime API (Animetosho successor). No API key required.
|
||||
"maxSearchResults": 10 // Maximum TsukiHime search results returned.
|
||||
}, // TsukiHime subtitle search configuration (English and Japanese). No API key required.
|
||||
}, // TsukiHime subtitle search configuration for Japanese primary and configured secondary subtitles. No API key required.
|
||||
|
||||
// ==========================================
|
||||
// YouTube Playback Settings
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
"openCharacterDictionaryManager": "CommandOrControl+D", // Accelerator that opens the character dictionary manager modal.
|
||||
"openRuntimeOptions": "CommandOrControl+Shift+O", // Accelerator that opens the runtime options modal.
|
||||
"openJimaku": "Ctrl+Shift+J", // Accelerator that opens the Jimaku subtitle search modal.
|
||||
"openTsukihime": "Ctrl+Shift+T", // Accelerator that opens the TsukiHime subtitle search modal (English/Japanese tabs).
|
||||
"openTsukihime": "Ctrl+Shift+T", // Accelerator that opens the TsukiHime subtitle search modal (configured secondary/Japanese primary tabs).
|
||||
"openSessionHelp": "CommandOrControl+Slash", // Accelerator that opens the session help / keybinding cheatsheet.
|
||||
"openControllerSelect": "Alt+C", // Accelerator that opens the controller selection and learn-mode modal.
|
||||
"openControllerDebug": "Alt+Shift+C", // Accelerator that opens the controller debug modal with live axis/button readouts.
|
||||
@@ -615,13 +615,13 @@
|
||||
|
||||
// ==========================================
|
||||
// TsukiHime
|
||||
// TsukiHime subtitle search configuration (English and Japanese). No API key required.
|
||||
// TsukiHime subtitle search configuration for Japanese primary and configured secondary subtitles. No API key required.
|
||||
// Hot-reload: TsukiHime changes apply to the next TsukiHime request.
|
||||
// ==========================================
|
||||
"tsukihime": {
|
||||
"apiBaseUrl": "https://api.tsukihime.org/v1", // Base URL of the TsukiHime API (Animetosho successor). No API key required.
|
||||
"maxSearchResults": 10 // Maximum TsukiHime search results returned.
|
||||
}, // TsukiHime subtitle search configuration (English and Japanese). No API key required.
|
||||
}, // TsukiHime subtitle search configuration for Japanese primary and configured secondary subtitles. No API key required.
|
||||
|
||||
// ==========================================
|
||||
// YouTube Playback Settings
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[TsukiHime](https://tsukihime.org) tracks anime torrent releases and extracts every attachment - including embedded subtitle tracks - from the release files, hosting them for direct download. SubMiner integrates with the TsukiHime API so you can pull English subtitles for the currently playing episode straight from the overlay, no torrent client involved. Downloaded subtitles are decompressed, saved next to the video, and loaded into mpv immediately.
|
||||
|
||||
This is the English-side companion to the [Jimaku integration](/jimaku-integration): Jimaku covers Japanese subtitles, TsukiHime covers your secondary language (English by default). Releases that ship multiple languages (e.g. Netflix `[MultiSub]` rips) expose them all; the modal's tabs pick which ones you see, and each download is saved with its own language suffix.
|
||||
This is the multi-language companion to the [Jimaku integration](/jimaku-integration). Releases that ship multiple languages (e.g. Netflix `[MultiSub]` rips) expose them all; the modal's tabs pick which ones you see, and each download is saved with its own language suffix.
|
||||
|
||||
::: tip Successor to Animetosho
|
||||
TsukiHime replaces [Animetosho](https://animetosho.org), which stops processing new releases in May 2026. TsukiHime imported the Animetosho index and mirrors its attachment storage, so older releases stay reachable alongside new ones.
|
||||
@@ -14,7 +14,7 @@ Unlike Jimaku, TsukiHime needs no account or API key. The only requirement is th
|
||||
|
||||
## How It Works
|
||||
|
||||
The integration runs through an in-overlay modal opened with `Ctrl+Shift+T` by default. The modal has two tabs that filter the subtitle tracks of the selected release by language: the first tab follows your `secondarySub.secondarySubLanguages` config (defaults to English when unset, and the tab is labeled accordingly - e.g. "German" if you configure `["de"]`), and the second tab is always **Japanese**. Tracks with no language tag stay visible on the first tab.
|
||||
The integration runs through an in-overlay modal opened with `Ctrl+Shift+T` by default. The modal has two tabs that filter the subtitle tracks of the selected release by role: the first follows `secondarySub.secondarySubLanguages` (English when unset), and the second is always **Japanese**, the currently supported primary subtitle language. Tracks with no language tag stay visible on the secondary tab.
|
||||
|
||||
When you open the modal, SubMiner parses the current video filename to extract a title and episode number (same parser as Jimaku - `S01E03`, `1x03`, `E03`, and dash-separated numbers all work). If the filename yields a high-confidence match, SubMiner auto-searches immediately.
|
||||
|
||||
@@ -22,7 +22,7 @@ From there:
|
||||
|
||||
1. **Search** - SubMiner queries TsukiHime with `<title> <episode>`. Results appear as a list of releases (e.g. `[SubsPlease] ... - 28 (1080p)`), each showing size, file count, and the subtitle languages the release carries.
|
||||
2. **Browse releases** - Select a release to list the text subtitle tracks extracted from its files. English tracks sort first; image-based tracks (PGS/VobSub) are filtered out.
|
||||
3. **Download** - Selecting a track downloads the xz-compressed subtitle from TsukiHime's storage, decompresses it, saves it next to the video (or a temp directory for remote/streamed media), and loads it into mpv. Japanese tracks are selected as the **primary** subtitle; any other language loads as the **secondary** subtitle, so your Japanese primary track stays in place. The filename carries the track's language - `<video basename>.en.<ext>` for English, `.ja` for Japanese, and so on - so mpv and media servers detect the language correctly.
|
||||
3. **Download** - Selecting a track downloads the xz-compressed subtitle from TsukiHime's storage, decompresses it, saves it next to the video (or a temp directory for remote/streamed media), and loads it into mpv. Japanese tracks are selected as mpv's **primary** subtitle. Tracks from the configured secondary tab are assigned to mpv's **secondary** subtitle slot without replacing the primary. The filename carries the track's language - `<video basename>.en.<ext>` for English, `.ja` for Japanese, and so on - so mpv and media servers detect the language correctly.
|
||||
|
||||
Because releases on TsukiHime are the same files circulating as torrents, picking the release that matches your local file (same group, same version) gives you subtitles with exact timing - no resync needed. If your file is a raw or from a different group, pick any release of the same episode and adjust timing with the [subtitle sync tools](/troubleshooting#subtitle-sync-subsync) (`Ctrl+Alt+S`) if necessary.
|
||||
|
||||
|
||||
@@ -620,7 +620,7 @@ export function buildCoreConfigOptionRegistry(
|
||||
kind: 'string',
|
||||
defaultValue: defaultConfig.shortcuts.openTsukihime,
|
||||
description:
|
||||
'Accelerator that opens the TsukiHime subtitle search modal (English/Japanese tabs).',
|
||||
'Accelerator that opens the TsukiHime subtitle search modal (configured secondary/Japanese primary tabs).',
|
||||
},
|
||||
{
|
||||
path: 'shortcuts.openSessionHelp',
|
||||
|
||||
@@ -150,7 +150,7 @@ const INTEGRATION_TEMPLATE_SECTIONS: ConfigTemplateSection[] = [
|
||||
{
|
||||
title: 'TsukiHime',
|
||||
description: [
|
||||
'TsukiHime subtitle search configuration (English and Japanese). No API key required.',
|
||||
'TsukiHime subtitle search configuration for Japanese primary and configured secondary subtitles. No API key required.',
|
||||
],
|
||||
notes: ['Hot-reload: TsukiHime changes apply to the next TsukiHime request.'],
|
||||
key: 'tsukihime',
|
||||
|
||||
@@ -132,7 +132,7 @@ test('anki/jimaku IPC handlers reject malformed invoke payloads', async () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('tsukihime downloads route by language: secondary for eng, primary for jpn', async () => {
|
||||
test('tsukihime downloads always route Japanese as primary', async () => {
|
||||
const { registrar, handleHandlers } = createFakeRegistrar();
|
||||
const primaryLoads: string[] = [];
|
||||
const secondaryLoads: string[] = [];
|
||||
@@ -163,7 +163,7 @@ test('tsukihime downloads route by language: secondary for eng, primary for jpn'
|
||||
searchTsukihimeEntries: async () => ({ ok: true, data: [] }),
|
||||
listTsukihimeFiles: async () => ({ ok: true, data: [] }),
|
||||
downloadTsukihimeSubtitle: async (_url, destPath) => ({ ok: true, path: destPath }),
|
||||
getTsukihimeSecondaryLanguages: () => ['en'],
|
||||
getTsukihimeSecondaryLanguages: () => ['ja'],
|
||||
onDownloadedSecondarySubtitle: (path) => {
|
||||
secondaryLoads.push(path);
|
||||
},
|
||||
|
||||
@@ -124,12 +124,10 @@
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="tsukihime-tabs">
|
||||
<button id="tsukihimeTabEnglish" class="tsukihime-tab active" type="button">
|
||||
<button id="tsukihimeTabSecondary" class="tsukihime-tab active" type="button">
|
||||
English
|
||||
</button>
|
||||
<button id="tsukihimeTabJapanese" class="tsukihime-tab" type="button">
|
||||
Japanese
|
||||
</button>
|
||||
<button id="tsukihimeTabPrimary" class="tsukihime-tab" type="button">Japanese</button>
|
||||
</div>
|
||||
<div class="jimaku-form">
|
||||
<label class="jimaku-field">
|
||||
|
||||
@@ -168,12 +168,12 @@ function createModalHarness(
|
||||
tsukihimeEpisodeInput: { value: '' },
|
||||
tsukihimeSearchButton: { addEventListener: () => {} },
|
||||
tsukihimeCloseButton: { addEventListener: () => {} },
|
||||
tsukihimeTabEnglishButton: {
|
||||
tsukihimeTabSecondaryButton: {
|
||||
textContent: 'English',
|
||||
classList: createClassList(['active']),
|
||||
addEventListener: () => {},
|
||||
},
|
||||
tsukihimeTabJapaneseButton: {
|
||||
tsukihimeTabPrimaryButton: {
|
||||
textContent: 'Japanese',
|
||||
classList: createClassList(),
|
||||
addEventListener: () => {},
|
||||
@@ -257,7 +257,7 @@ test('successful Tsukihime subtitle selection closes modal', async () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('English tab hides non-English languages, not just Japanese', async () => {
|
||||
test('secondary tab hides languages outside its configured defaults', async () => {
|
||||
const harness = createModalHarness([GERMAN_TRACK, ENGLISH_TRACK, JAPANESE_TRACK]);
|
||||
try {
|
||||
// With German visible this would move selection onto it; English-only
|
||||
@@ -279,12 +279,12 @@ test('English tab hides non-English languages, not just Japanese', async () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('Japanese tab filters tracks so Enter downloads the Japanese one', async () => {
|
||||
test('primary tab defaults to Japanese tracks', async () => {
|
||||
const harness = createModalHarness([ENGLISH_TRACK, JAPANESE_TRACK]);
|
||||
try {
|
||||
assert.equal(harness.state.tsukihimeActiveTab, 'en');
|
||||
assert.equal(harness.state.tsukihimeActiveTab, 'secondary');
|
||||
pressKey(harness, 'ArrowRight');
|
||||
assert.equal(harness.state.tsukihimeActiveTab, 'ja');
|
||||
assert.equal(harness.state.tsukihimeActiveTab, 'primary');
|
||||
|
||||
pressKey(harness, 'Enter');
|
||||
await flushAsyncWork();
|
||||
@@ -331,6 +331,35 @@ test('secondary tab follows configured secondarySub languages', async () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('primary tab remains Japanese when the release includes other languages', async () => {
|
||||
const harness = createModalHarness([GERMAN_TRACK, ENGLISH_TRACK, JAPANESE_TRACK], {
|
||||
secondaryLanguages: ['en'],
|
||||
});
|
||||
try {
|
||||
harness.state.tsukihimeModalOpen = false;
|
||||
harness.modal.openTsukihimeModal();
|
||||
await flushAsyncWork();
|
||||
|
||||
harness.state.tsukihimeFiles = [GERMAN_TRACK, ENGLISH_TRACK, JAPANESE_TRACK];
|
||||
harness.state.currentTsukihimeEntryId = 606713;
|
||||
|
||||
pressKey(harness, 'ArrowRight');
|
||||
pressKey(harness, 'Enter');
|
||||
await flushAsyncWork();
|
||||
|
||||
assert.deepEqual(harness.downloadQueries, [
|
||||
{
|
||||
entryId: 606713,
|
||||
url: JAPANESE_TRACK.url,
|
||||
name: JAPANESE_TRACK.filename,
|
||||
lang: 'jpn',
|
||||
},
|
||||
]);
|
||||
} finally {
|
||||
harness.restoreGlobals();
|
||||
}
|
||||
});
|
||||
|
||||
test('a slow release response does not overwrite the newly selected release', async () => {
|
||||
const STALE_TRACK: TsukihimeSubtitleFile = {
|
||||
...ENGLISH_TRACK,
|
||||
@@ -386,13 +415,13 @@ test('a slow release response does not overwrite the newly selected release', as
|
||||
}
|
||||
});
|
||||
|
||||
test('ArrowLeft switches back to the English tab', () => {
|
||||
test('ArrowLeft switches back to the secondary-language tab', () => {
|
||||
const harness = createModalHarness([ENGLISH_TRACK, JAPANESE_TRACK]);
|
||||
try {
|
||||
pressKey(harness, 'ArrowRight');
|
||||
assert.equal(harness.state.tsukihimeActiveTab, 'ja');
|
||||
assert.equal(harness.state.tsukihimeActiveTab, 'primary');
|
||||
pressKey(harness, 'ArrowLeft');
|
||||
assert.equal(harness.state.tsukihimeActiveTab, 'en');
|
||||
assert.equal(harness.state.tsukihimeActiveTab, 'secondary');
|
||||
} finally {
|
||||
harness.restoreGlobals();
|
||||
}
|
||||
|
||||
@@ -39,40 +39,40 @@ export function createTsukihimeModal(
|
||||
ctx.dom.tsukihimeFilesSection.classList.add('hidden');
|
||||
}
|
||||
|
||||
// Defaults to English until the configured secondarySub languages arrive.
|
||||
// Defaults to English until the configured secondary languages arrive.
|
||||
let secondaryLanguages: string[] = ['en'];
|
||||
|
||||
function secondaryTabLabel(): string {
|
||||
return describeTsukihimeTabLanguages(secondaryLanguages);
|
||||
}
|
||||
|
||||
function isJapaneseTrack(file: TsukihimeSubtitleFile): boolean {
|
||||
function isPrimaryTrack(file: TsukihimeSubtitleFile): boolean {
|
||||
return normalizeTsukihimeLangCode(file.lang) === 'ja';
|
||||
}
|
||||
|
||||
function getVisibleFiles(): TsukihimeSubtitleFile[] {
|
||||
if (ctx.state.tsukihimeActiveTab === 'ja') {
|
||||
return ctx.state.tsukihimeFiles.filter(isJapaneseTrack);
|
||||
if (ctx.state.tsukihimeActiveTab === 'primary') {
|
||||
return ctx.state.tsukihimeFiles.filter(isPrimaryTrack);
|
||||
}
|
||||
return ctx.state.tsukihimeFiles.filter(
|
||||
(file) =>
|
||||
!isJapaneseTrack(file) && tsukihimeTrackMatchesLanguages(file.lang, secondaryLanguages),
|
||||
!isPrimaryTrack(file) && tsukihimeTrackMatchesLanguages(file.lang, secondaryLanguages),
|
||||
);
|
||||
}
|
||||
|
||||
function renderTabs(): void {
|
||||
if (ctx.state.tsukihimeActiveTab === 'ja') {
|
||||
ctx.dom.tsukihimeTabEnglishButton.classList.remove('active');
|
||||
ctx.dom.tsukihimeTabJapaneseButton.classList.add('active');
|
||||
if (ctx.state.tsukihimeActiveTab === 'primary') {
|
||||
ctx.dom.tsukihimeTabSecondaryButton.classList.remove('active');
|
||||
ctx.dom.tsukihimeTabPrimaryButton.classList.add('active');
|
||||
} else {
|
||||
ctx.dom.tsukihimeTabEnglishButton.classList.add('active');
|
||||
ctx.dom.tsukihimeTabJapaneseButton.classList.remove('active');
|
||||
ctx.dom.tsukihimeTabSecondaryButton.classList.add('active');
|
||||
ctx.dom.tsukihimeTabPrimaryButton.classList.remove('active');
|
||||
}
|
||||
}
|
||||
|
||||
function describeEmptyTab(): string {
|
||||
const hiddenCount = ctx.state.tsukihimeFiles.length;
|
||||
if (ctx.state.tsukihimeActiveTab === 'ja') {
|
||||
if (ctx.state.tsukihimeActiveTab === 'primary') {
|
||||
return hiddenCount > 0
|
||||
? `No Japanese tracks in this release. Switch to the ${secondaryTabLabel()} tab.`
|
||||
: 'No Japanese tracks in this release.';
|
||||
@@ -82,7 +82,7 @@ export function createTsukihimeModal(
|
||||
: `No ${secondaryTabLabel()} tracks in this release.`;
|
||||
}
|
||||
|
||||
function setActiveTab(tab: 'en' | 'ja'): void {
|
||||
function setActiveTab(tab: 'secondary' | 'primary'): void {
|
||||
if (ctx.state.tsukihimeActiveTab === tab) return;
|
||||
ctx.state.tsukihimeActiveTab = tab;
|
||||
ctx.state.selectedTsukihimeFileIndex = 0;
|
||||
@@ -321,12 +321,13 @@ export function createTsukihimeModal(
|
||||
|
||||
async function loadSecondaryLanguages(): Promise<void> {
|
||||
try {
|
||||
const languages = await window.electronAPI.tsukihimeGetSecondaryLanguages();
|
||||
secondaryLanguages = languages.length > 0 ? languages : ['en'];
|
||||
const configuredSecondary = await window.electronAPI.tsukihimeGetSecondaryLanguages();
|
||||
secondaryLanguages = configuredSecondary.length > 0 ? configuredSecondary : ['en'];
|
||||
} catch {
|
||||
secondaryLanguages = ['en'];
|
||||
}
|
||||
ctx.dom.tsukihimeTabEnglishButton.textContent = secondaryTabLabel();
|
||||
ctx.dom.tsukihimeTabSecondaryButton.textContent = secondaryTabLabel();
|
||||
ctx.dom.tsukihimeTabPrimaryButton.textContent = 'Japanese';
|
||||
// Tracks may already be on screen if the languages arrived late.
|
||||
if (ctx.state.tsukihimeFiles.length > 0) {
|
||||
renderFiles();
|
||||
@@ -337,7 +338,7 @@ export function createTsukihimeModal(
|
||||
if (ctx.state.tsukihimeModalOpen) return;
|
||||
|
||||
ctx.state.tsukihimeModalOpen = true;
|
||||
ctx.state.tsukihimeActiveTab = 'en';
|
||||
ctx.state.tsukihimeActiveTab = 'secondary';
|
||||
options.syncSettingsModalSubtitleSuppression();
|
||||
ctx.dom.overlay.classList.add('interactive');
|
||||
ctx.dom.tsukihimeModal.classList.remove('hidden');
|
||||
@@ -402,13 +403,13 @@ export function createTsukihimeModal(
|
||||
|
||||
if (e.key === 'ArrowLeft') {
|
||||
e.preventDefault();
|
||||
setActiveTab('en');
|
||||
setActiveTab('secondary');
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.key === 'ArrowRight') {
|
||||
e.preventDefault();
|
||||
setActiveTab('ja');
|
||||
setActiveTab('primary');
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -471,11 +472,11 @@ export function createTsukihimeModal(
|
||||
ctx.dom.tsukihimeCloseButton.addEventListener('click', () => {
|
||||
closeTsukihimeModal();
|
||||
});
|
||||
ctx.dom.tsukihimeTabEnglishButton.addEventListener('click', () => {
|
||||
setActiveTab('en');
|
||||
ctx.dom.tsukihimeTabSecondaryButton.addEventListener('click', () => {
|
||||
setActiveTab('secondary');
|
||||
});
|
||||
ctx.dom.tsukihimeTabJapaneseButton.addEventListener('click', () => {
|
||||
setActiveTab('ja');
|
||||
ctx.dom.tsukihimeTabPrimaryButton.addEventListener('click', () => {
|
||||
setActiveTab('primary');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ export type RendererState = {
|
||||
currentEntryId: number | null;
|
||||
|
||||
tsukihimeModalOpen: boolean;
|
||||
tsukihimeActiveTab: 'en' | 'ja';
|
||||
tsukihimeActiveTab: 'secondary' | 'primary';
|
||||
tsukihimeEntries: TsukihimeEntry[];
|
||||
tsukihimeFiles: TsukihimeSubtitleFile[];
|
||||
selectedTsukihimeEntryIndex: number;
|
||||
@@ -175,7 +175,7 @@ export function createRendererState(): RendererState {
|
||||
currentEntryId: null,
|
||||
|
||||
tsukihimeModalOpen: false,
|
||||
tsukihimeActiveTab: 'en',
|
||||
tsukihimeActiveTab: 'secondary',
|
||||
tsukihimeEntries: [],
|
||||
tsukihimeFiles: [],
|
||||
selectedTsukihimeEntryIndex: 0,
|
||||
|
||||
@@ -27,8 +27,8 @@ export type RendererDom = {
|
||||
tsukihimeEpisodeInput: HTMLInputElement;
|
||||
tsukihimeSearchButton: HTMLButtonElement;
|
||||
tsukihimeCloseButton: HTMLButtonElement;
|
||||
tsukihimeTabEnglishButton: HTMLButtonElement;
|
||||
tsukihimeTabJapaneseButton: HTMLButtonElement;
|
||||
tsukihimeTabSecondaryButton: HTMLButtonElement;
|
||||
tsukihimeTabPrimaryButton: HTMLButtonElement;
|
||||
tsukihimeStatus: HTMLDivElement;
|
||||
tsukihimeEntriesSection: HTMLDivElement;
|
||||
tsukihimeEntriesList: HTMLUListElement;
|
||||
@@ -172,8 +172,8 @@ export function resolveRendererDom(): RendererDom {
|
||||
tsukihimeEpisodeInput: getRequiredElement<HTMLInputElement>('tsukihimeEpisode'),
|
||||
tsukihimeSearchButton: getRequiredElement<HTMLButtonElement>('tsukihimeSearch'),
|
||||
tsukihimeCloseButton: getRequiredElement<HTMLButtonElement>('tsukihimeClose'),
|
||||
tsukihimeTabEnglishButton: getRequiredElement<HTMLButtonElement>('tsukihimeTabEnglish'),
|
||||
tsukihimeTabJapaneseButton: getRequiredElement<HTMLButtonElement>('tsukihimeTabJapanese'),
|
||||
tsukihimeTabSecondaryButton: getRequiredElement<HTMLButtonElement>('tsukihimeTabSecondary'),
|
||||
tsukihimeTabPrimaryButton: getRequiredElement<HTMLButtonElement>('tsukihimeTabPrimary'),
|
||||
tsukihimeStatus: getRequiredElement<HTMLDivElement>('tsukihimeStatus'),
|
||||
tsukihimeEntriesSection: getRequiredElement<HTMLDivElement>('tsukihimeEntriesSection'),
|
||||
tsukihimeEntriesList: getRequiredElement<HTMLUListElement>('tsukihimeEntries'),
|
||||
|
||||
Reference in New Issue
Block a user