mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-15 20:31:46 +00:00
Merge branch 'local-upstream/master' into add-crossfade-menu-options
This commit is contained in:
139
config/dynamic.js
Normal file
139
config/dynamic.js
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
const { ipcRenderer, ipcMain } = require("electron");
|
||||||
|
|
||||||
|
const defaultConfig = require("./defaults");
|
||||||
|
const { getOptions, setOptions, setMenuOptions } = require("./plugins");
|
||||||
|
|
||||||
|
const activePlugins = {};
|
||||||
|
/**
|
||||||
|
* [!IMPORTANT!]
|
||||||
|
* The method is **sync** in the main process and **async** in the renderer process.
|
||||||
|
*/
|
||||||
|
module.exports.getActivePlugins =
|
||||||
|
process.type === "renderer"
|
||||||
|
? async () => ipcRenderer.invoke("get-active-plugins")
|
||||||
|
: () => activePlugins;
|
||||||
|
|
||||||
|
if (process.type === "browser") {
|
||||||
|
ipcMain.handle("get-active-plugins", this.getActivePlugins);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [!IMPORTANT!]
|
||||||
|
* The method is **sync** in the main process and **async** in the renderer process.
|
||||||
|
*/
|
||||||
|
module.exports.isActive =
|
||||||
|
process.type === "renderer"
|
||||||
|
? async (plugin) =>
|
||||||
|
plugin in (await ipcRenderer.invoke("get-active-plugins"))
|
||||||
|
: (plugin) => plugin in activePlugins;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to create a dynamic synced config for plugins.
|
||||||
|
*
|
||||||
|
* [!IMPORTANT!]
|
||||||
|
* The methods are **sync** in the main process and **async** in the renderer process.
|
||||||
|
*
|
||||||
|
* @param {string} name - The name of the plugin.
|
||||||
|
* @param {boolean} [options.enableFront] - Whether the config should be available in front.js. Default: false.
|
||||||
|
* @param {object} [options.initialOptions] - The initial options for the plugin. Default: loaded from store.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const { PluginConfig } = require("../../config/dynamic");
|
||||||
|
* const config = new PluginConfig("plugin-name", { enableFront: true });
|
||||||
|
* module.exports = { ...config };
|
||||||
|
*
|
||||||
|
* // or
|
||||||
|
*
|
||||||
|
* module.exports = (win, options) => {
|
||||||
|
* const config = new PluginConfig("plugin-name", {
|
||||||
|
* enableFront: true,
|
||||||
|
* initialOptions: options,
|
||||||
|
* });
|
||||||
|
* setupMyPlugin(win, config);
|
||||||
|
* };
|
||||||
|
*/
|
||||||
|
module.exports.PluginConfig = class PluginConfig {
|
||||||
|
#name;
|
||||||
|
#config;
|
||||||
|
#defaultConfig;
|
||||||
|
#enableFront;
|
||||||
|
|
||||||
|
constructor(name, { enableFront = false, initialOptions = undefined } = {}) {
|
||||||
|
const pluginDefaultConfig = defaultConfig.plugins[name] || {};
|
||||||
|
const pluginConfig = initialOptions || getOptions(name) || {};
|
||||||
|
|
||||||
|
this.#name = name;
|
||||||
|
this.#enableFront = enableFront;
|
||||||
|
this.#defaultConfig = pluginDefaultConfig;
|
||||||
|
this.#config = { ...pluginDefaultConfig, ...pluginConfig };
|
||||||
|
|
||||||
|
if (this.#enableFront) {
|
||||||
|
this.#setupFront();
|
||||||
|
}
|
||||||
|
|
||||||
|
activePlugins[name] = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
get = (option) => {
|
||||||
|
return this.#config[option];
|
||||||
|
};
|
||||||
|
|
||||||
|
set = (option, value) => {
|
||||||
|
this.#config[option] = value;
|
||||||
|
this.#save();
|
||||||
|
};
|
||||||
|
|
||||||
|
toggle = (option) => {
|
||||||
|
this.#config[option] = !this.#config[option];
|
||||||
|
this.#save();
|
||||||
|
};
|
||||||
|
|
||||||
|
getAll = () => {
|
||||||
|
return { ...this.#config };
|
||||||
|
};
|
||||||
|
|
||||||
|
setAll = (options) => {
|
||||||
|
this.#config = { ...this.#config, ...options };
|
||||||
|
this.#save();
|
||||||
|
};
|
||||||
|
|
||||||
|
getDefaultConfig = () => {
|
||||||
|
return this.#defaultConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this method to set an option and restart the app if `appConfig.restartOnConfigChange === true`
|
||||||
|
*
|
||||||
|
* Used for options that require a restart to take effect.
|
||||||
|
*/
|
||||||
|
setAndMaybeRestart = (option, value) => {
|
||||||
|
this.#config[option] = value;
|
||||||
|
setMenuOptions(this.#name, this.#config);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Called only from back */
|
||||||
|
#save() {
|
||||||
|
setOptions(this.#name, this.#config);
|
||||||
|
}
|
||||||
|
|
||||||
|
#setupFront() {
|
||||||
|
if (process.type === "renderer") {
|
||||||
|
for (const [fnName, fn] of Object.entries(this)) {
|
||||||
|
if (typeof fn !== "function") return;
|
||||||
|
this[fnName] = async (...args) => {
|
||||||
|
return await ipcRenderer.invoke(
|
||||||
|
`${this.name}-config-${fnName}`,
|
||||||
|
...args,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else if (process.type === "browser") {
|
||||||
|
for (const [fnName, fn] of Object.entries(this)) {
|
||||||
|
if (typeof fn !== "function") return;
|
||||||
|
ipcMain.handle(`${this.name}-config-${fnName}`, (_, ...args) => {
|
||||||
|
return fn(...args);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -11,28 +11,32 @@ module.exports = (options) => {
|
|||||||
document.addEventListener('apiLoaded', (event) => setup(event, options), { once: true, passive: true });
|
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) {
|
function setup(event, options) {
|
||||||
const api = event.detail;
|
const api = event.detail;
|
||||||
|
|
||||||
$("video").addEventListener("srcChanged", () => videoChanged(api, options));
|
|
||||||
|
|
||||||
$(".right-controls-buttons").append(captionsSettingsButton);
|
$(".right-controls-buttons").append(captionsSettingsButton);
|
||||||
|
|
||||||
|
let captionTrackList = api.getOption("captions", "tracklist");
|
||||||
|
|
||||||
|
$("video").addEventListener("srcChanged", () => {
|
||||||
|
if (options.disableCaptions) {
|
||||||
|
setTimeout(() => api.unloadModule("captions"), 100);
|
||||||
|
captionsSettingsButton.style.display = "none";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
api.loadModule("captions");
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
captionTrackList = api.getOption("captions", "tracklist");
|
||||||
|
|
||||||
|
captionsSettingsButton.style.display = captionTrackList?.length
|
||||||
|
? "inline-block"
|
||||||
|
: "none";
|
||||||
|
}, 250);
|
||||||
|
});
|
||||||
|
|
||||||
captionsSettingsButton.onclick = async () => {
|
captionsSettingsButton.onclick = async () => {
|
||||||
api.loadModule("captions");
|
|
||||||
|
|
||||||
const captionTrackList = api.getOption("captions", "tracklist");
|
|
||||||
|
|
||||||
if (captionTrackList?.length) {
|
if (captionTrackList?.length) {
|
||||||
const currentCaptionTrack = api.getOption("captions", "track");
|
const currentCaptionTrack = api.getOption("captions", "track");
|
||||||
let currentIndex = !currentCaptionTrack ?
|
let currentIndex = !currentCaptionTrack ?
|
||||||
|
|||||||
@ -7,7 +7,7 @@ const fetch = require("node-fetch");
|
|||||||
|
|
||||||
const { cleanupName } = require("../../providers/song-info");
|
const { cleanupName } = require("../../providers/song-info");
|
||||||
const { injectCSS } = require("../utils");
|
const { injectCSS } = require("../utils");
|
||||||
let eastAsianChars = new RegExp("[\u{3040}-\u{30ff}\u{3400}-\u{4dbf}\u{4e00}-\u{9fff}\u{f900}-\u{faff}\u{ff66}-\u{ff9f}]");
|
let eastAsianChars = /\p{Script=Han}|\p{Script=Katakana}|\p{Script=Hiragana}|\p{Script=Hangul}|\p{Script=Han}/u;
|
||||||
let revRomanized = false;
|
let revRomanized = false;
|
||||||
|
|
||||||
module.exports = async (win, options) => {
|
module.exports = async (win, options) => {
|
||||||
|
|||||||
@ -39,7 +39,6 @@ const setup = () => {
|
|||||||
|
|
||||||
/** @param {Electron.BrowserWindow} win */
|
/** @param {Electron.BrowserWindow} win */
|
||||||
module.exports = (win, options) => {
|
module.exports = (win, options) => {
|
||||||
config.init(options);
|
|
||||||
// Register the callback for new song information
|
// Register the callback for new song information
|
||||||
is.windows() && options.interactive ?
|
is.windows() && options.interactive ?
|
||||||
require("./interactive")(win) :
|
require("./interactive")(win) :
|
||||||
|
|||||||
@ -1,23 +1,5 @@
|
|||||||
const { setOptions, setMenuOptions } = require("../../config/plugins");
|
const { PluginConfig } = require("../../config/dynamic");
|
||||||
const defaultConfig = require("../../config/defaults");
|
|
||||||
|
|
||||||
let config = defaultConfig.plugins["notifications"];
|
const config = new PluginConfig("notifications");
|
||||||
|
|
||||||
module.exports.init = (options) => {
|
module.exports = { ...config };
|
||||||
config = { ...config, ...options };
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports.setAndMaybeRestart = (option, value) => {
|
|
||||||
config[option] = value;
|
|
||||||
setMenuOptions("notifications", config);
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports.set = (option, value) => {
|
|
||||||
config[option] = value;
|
|
||||||
setOptions("notifications", config);
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports.get = (option) => {
|
|
||||||
let res = config[option];
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
|
|||||||
2
tray.js
2
tray.js
@ -40,7 +40,7 @@ module.exports.setUpTray = (app, win) => {
|
|||||||
|
|
||||||
tray = new Tray(trayIcon);
|
tray = new Tray(trayIcon);
|
||||||
|
|
||||||
tray.setToolTip("Youtube Music");
|
tray.setToolTip("YouTube Music");
|
||||||
|
|
||||||
// macOS only
|
// macOS only
|
||||||
tray.setIgnoreDoubleClickEvents(true);
|
tray.setIgnoreDoubleClickEvents(true);
|
||||||
|
|||||||
Reference in New Issue
Block a user