diff --git a/config/defaults.js b/config/defaults.js index eaefcc24..91bddf24 100644 --- a/config/defaults.js +++ b/config/defaults.js @@ -91,6 +91,10 @@ const defaultConfig = { "saveSize": false, "hotkey": "P" }, + "captions-selector": { + enabled: false, + disableCaptions: false + }, "skip-silences": { onlySkipBeginning: false, }, diff --git a/plugins/captions-selector/back.js b/plugins/captions-selector/back.js new file mode 100644 index 00000000..de53d85a --- /dev/null +++ b/plugins/captions-selector/back.js @@ -0,0 +1,15 @@ +const { ipcMain, dialog } = require("electron"); + +module.exports = () => { + ipcMain.handle('captionsSelector', async (_, captionLabels, currentIndex) => { + return await dialog.showMessageBox({ + type: "question", + buttons: captionLabels, + defaultId: currentIndex, + title: "Choose Caption", + message: "Choose Caption:", + detail: `Current Caption: ${captionLabels[currentIndex]}`, + cancelId: -1 + }) + }) +}; diff --git a/plugins/captions-selector/front.js b/plugins/captions-selector/front.js new file mode 100644 index 00000000..9ae9dbde --- /dev/null +++ b/plugins/captions-selector/front.js @@ -0,0 +1,60 @@ +const { ElementFromFile, templatePath } = require("../utils"); +const { ipcRenderer } = require("electron"); + +function $(selector) { return document.querySelector(selector); } + +const captionsSettingsButton = ElementFromFile( + templatePath(__dirname, "captionsSettingsTemplate.html") +); + +module.exports = (options) => { + document.addEventListener('apiLoaded', (event) => setup(event, options), { once: true, passive: true }); +} + +/** + * If captions are disabled by default, + * unload "captions" module when video changes. + */ +const videoChanged = (api, options) => { + if (options.disableCaptions) { + setTimeout(() => api.unloadModule("captions"), 100); + } +} + +function setup(event, options) { + const api = event.detail; + + $("video").addEventListener("srcChanged", () => videoChanged(api, options)); + + $(".right-controls-buttons").append(captionsSettingsButton); + + captionsSettingsButton.onclick = function chooseQuality() { + api.loadModule("captions"); + + const captionTrackList = api.getOption("captions", "tracklist"); + + if (captionTrackList?.length) { + const currentCaptionTrack = api.getOption("captions", "track"); + const currentIndex = captionTrackList.indexOf(captionTrackList.find(track => track.languageCode === currentCaptionTrack.languageCode)); + + const captionLabels = [ + ...captionTrackList.map(track => track.displayName), + 'None' + ]; + + ipcRenderer.invoke('captionsSelector', captionLabels, currentIndex).then(promise => { + if (promise.response === -1) return; + + const newCaptions = captionTrackList[promise.response]; + if (newCaptions) { + api.loadModule("captions"); + api.setOption("captions", "track", { languageCode: newCaptions.languageCode }); + } else { + api.unloadModule("captions"); + } + + setTimeout(() => api.playVideo()); + }); + } + } +} diff --git a/plugins/captions-selector/menu.js b/plugins/captions-selector/menu.js new file mode 100644 index 00000000..439ff8b4 --- /dev/null +++ b/plugins/captions-selector/menu.js @@ -0,0 +1,12 @@ +const { setOptions } = require('../../config/plugins'); + +module.exports = (_win, options) => [ + { + label: "No captions by default", + type: "checkbox", + checked: options.disabledCaptions, + click: (item) => { + setOptions("captions-selector", { disableCaptions: item.checked }); + }, + } +]; diff --git a/plugins/captions-selector/templates/captionsSettingsTemplate.html b/plugins/captions-selector/templates/captionsSettingsTemplate.html new file mode 100644 index 00000000..16c1b2b6 --- /dev/null +++ b/plugins/captions-selector/templates/captionsSettingsTemplate.html @@ -0,0 +1,13 @@ + + + + + + + +