import { ElementFromHtml } from '@/plugins/utils/renderer';
import { createRenderer } from '@/utils';
import CaptionsSettingsButtonHTML from './templates/captions-settings-template.html?raw';
import { YoutubePlayer } from '@/types/youtube-player';
export interface LanguageOptions {
displayName: string;
id: string | null;
is_default: boolean;
is_servable: boolean;
is_translateable: boolean;
kind: string;
languageCode: string; // 2 length
languageName: string;
name: string | null;
vss_id: string;
}
export interface CaptionsSelectorConfig {
enabled: boolean;
disableCaptions: boolean;
autoload: boolean;
lastCaptionsCode: string;
}
export default createRenderer<
{
captionsSettingsButton: HTMLElement;
captionTrackList: LanguageOptions[] | null;
api: YoutubePlayer | null;
config: CaptionsSelectorConfig | null;
setConfig: (config: Partial) => void;
videoChangeListener: () => void;
captionsButtonClickListener: () => void;
},
CaptionsSelectorConfig
>({
captionsSettingsButton: ElementFromHtml(CaptionsSettingsButtonHTML),
captionTrackList: null,
api: null,
config: null,
setConfig: () => {},
async captionsButtonClickListener() {
if (this.captionTrackList?.length) {
const currentCaptionTrack = this.api!.getOption(
'captions',
'track',
);
let currentIndex = currentCaptionTrack
? this.captionTrackList.indexOf(
this.captionTrackList.find(
(track) =>
track.languageCode === currentCaptionTrack.languageCode,
)!,
)
: null;
const captionLabels = [
...this.captionTrackList.map((track) => track.displayName),
'None',
];
currentIndex = (await window.ipcRenderer.invoke(
'captionsSelector',
captionLabels,
currentIndex,
)) as number;
if (currentIndex === null) {
return;
}
const newCaptions = this.captionTrackList[currentIndex];
this.setConfig({ lastCaptionsCode: newCaptions?.languageCode });
if (newCaptions) {
this.api?.setOption('captions', 'track', {
languageCode: newCaptions.languageCode,
});
} else {
this.api?.setOption('captions', 'track', {});
}
setTimeout(() => this.api?.playVideo());
}
},
videoChangeListener() {
if (this.config?.disableCaptions) {
setTimeout(() => this.api!.unloadModule('captions'), 100);
this.captionsSettingsButton.style.display = 'none';
return;
}
this.api!.loadModule('captions');
setTimeout(() => {
this.captionTrackList =
this.api!.getOption('captions', 'tracklist') ?? [];
if (this.config!.autoload && this.config!.lastCaptionsCode) {
this.api?.setOption('captions', 'track', {
languageCode: this.config!.lastCaptionsCode,
});
}
this.captionsSettingsButton.style.display = this.captionTrackList?.length
? 'inline-block'
: 'none';
}, 250);
},
async start({ getConfig, setConfig }) {
this.config = await getConfig();
this.setConfig = setConfig;
},
stop() {
document
.querySelector('.right-controls-buttons')
?.removeChild(this.captionsSettingsButton);
document
.querySelector('#movie_player')
?.unloadModule('captions');
document
.querySelector('video')
?.removeEventListener('ytmd:src-changed', this.videoChangeListener);
this.captionsSettingsButton.removeEventListener(
'click',
this.captionsButtonClickListener,
);
},
onPlayerApiReady(playerApi) {
this.api = playerApi;
document
.querySelector('.right-controls-buttons')
?.append(this.captionsSettingsButton);
this.captionTrackList =
this.api.getOption('captions', 'tracklist') ?? [];
document
.querySelector('video')
?.addEventListener('ytmd:src-changed', this.videoChangeListener);
this.captionsSettingsButton.addEventListener(
'click',
this.captionsButtonClickListener,
);
},
onConfigChange(newConfig) {
this.config = newConfig;
},
});