mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-11 18:41:47 +00:00
351 lines
9.2 KiB
JavaScript
351 lines
9.2 KiB
JavaScript
"use strict";
|
|
const path = require("path");
|
|
|
|
const electron = require("electron");
|
|
const is = require("electron-is");
|
|
const unhandled = require("electron-unhandled");
|
|
const { autoUpdater } = require("electron-updater");
|
|
|
|
const config = require("./config");
|
|
const { setApplicationMenu } = require("./menu");
|
|
const { fileExists, injectCSS } = require("./plugins/utils");
|
|
const { isTesting } = require("./utils/testing");
|
|
const { setUpTray } = require("./tray");
|
|
|
|
// Catch errors and log them
|
|
unhandled({
|
|
logger: console.error,
|
|
showDialog: false,
|
|
});
|
|
|
|
const app = electron.app;
|
|
app.commandLine.appendSwitch(
|
|
"js-flags",
|
|
// WebAssembly flags
|
|
"--experimental-wasm-threads --experimental-wasm-bulk-memory"
|
|
);
|
|
app.allowRendererProcessReuse = true; // https://github.com/electron/electron/issues/18397
|
|
if (config.get("options.disableHardwareAcceleration")) {
|
|
if (is.dev()) {
|
|
console.log("Disabling hardware acceleration");
|
|
}
|
|
app.disableHardwareAcceleration();
|
|
}
|
|
|
|
if (config.get("options.proxy")) {
|
|
app.commandLine.appendSwitch("proxy-server", config.get("options.proxy"));
|
|
}
|
|
|
|
// Adds debug features like hotkeys for triggering dev tools and reload
|
|
require("electron-debug")({
|
|
showDevTools: false //disable automatic devTools on new window
|
|
});
|
|
|
|
// Prevent window being garbage collected
|
|
let mainWindow;
|
|
autoUpdater.autoDownload = false;
|
|
|
|
let icon = "assets/youtube-music.png";
|
|
if (process.platform == "win32") {
|
|
icon = "assets/generated/icon.ico";
|
|
} else if (process.platform == "darwin") {
|
|
icon = "assets/generated/icon.icns";
|
|
}
|
|
|
|
function onClosed() {
|
|
// Dereference the window
|
|
// For multiple windows store them in an array
|
|
mainWindow = null;
|
|
}
|
|
|
|
function loadPlugins(win) {
|
|
injectCSS(win.webContents, path.join(__dirname, "youtube-music.css"));
|
|
win.webContents.once("did-finish-load", () => {
|
|
if (is.dev()) {
|
|
console.log("did finish load");
|
|
win.webContents.openDevTools();
|
|
}
|
|
});
|
|
|
|
config.plugins.getEnabled().forEach(([plugin, options]) => {
|
|
console.log("Loaded plugin - " + plugin);
|
|
const pluginPath = path.join(__dirname, "plugins", plugin, "back.js");
|
|
fileExists(pluginPath, () => {
|
|
const handle = require(pluginPath);
|
|
handle(win, options);
|
|
});
|
|
});
|
|
}
|
|
|
|
function createMainWindow() {
|
|
const windowSize = config.get("window-size");
|
|
const windowMaximized = config.get("window-maximized");
|
|
const windowPosition = config.get("window-position");
|
|
const useInlineMenu = config.plugins.isEnabled("in-app-menu");
|
|
|
|
const win = new electron.BrowserWindow({
|
|
icon: icon,
|
|
width: windowSize.width,
|
|
height: windowSize.height,
|
|
backgroundColor: "#000",
|
|
show: false,
|
|
webPreferences: {
|
|
// TODO: re-enable contextIsolation once it can work with ffmepg.wasm
|
|
// Possible bundling? https://github.com/ffmpegwasm/ffmpeg.wasm/issues/126
|
|
contextIsolation: false,
|
|
preload: path.join(__dirname, "preload.js"),
|
|
nodeIntegrationInSubFrames: true,
|
|
nativeWindowOpen: true, // window.open return Window object(like in regular browsers), not BrowserWindowProxy
|
|
enableRemoteModule: true,
|
|
affinity: "main-window", // main window, and addition windows should work in one process
|
|
...(isTesting()
|
|
? {
|
|
// Only necessary when testing with Spectron
|
|
contextIsolation: false,
|
|
nodeIntegration: true,
|
|
}
|
|
: undefined),
|
|
},
|
|
frame: !is.macOS() && !useInlineMenu,
|
|
titleBarStyle: useInlineMenu
|
|
? "hidden"
|
|
: is.macOS()
|
|
? "hiddenInset"
|
|
: "default",
|
|
autoHideMenuBar: config.get("options.hideMenu"),
|
|
});
|
|
if (windowPosition) {
|
|
const { x, y } = windowPosition;
|
|
win.setPosition(x, y);
|
|
}
|
|
if (windowMaximized) {
|
|
win.maximize();
|
|
}
|
|
|
|
const urlToLoad = config.get("options.resumeOnStart")
|
|
? config.get("url")
|
|
: config.defaultConfig.url;
|
|
win.webContents.loadURL(urlToLoad);
|
|
win.on("closed", onClosed);
|
|
|
|
win.on("move", () => {
|
|
let position = win.getPosition();
|
|
config.set("window-position", { x: position[0], y: position[1] });
|
|
});
|
|
|
|
win.on("resize", () => {
|
|
const windowSize = win.getSize();
|
|
|
|
config.set("window-maximized", win.isMaximized());
|
|
if (!win.isMaximized()) {
|
|
config.set("window-size", {
|
|
width: windowSize[0],
|
|
height: windowSize[1],
|
|
});
|
|
}
|
|
});
|
|
|
|
win.webContents.on("render-process-gone", (event, webContents, details) => {
|
|
showUnresponsiveDialog(win, details);
|
|
});
|
|
|
|
win.once("ready-to-show", () => {
|
|
if (config.get("options.appVisible")) {
|
|
win.show();
|
|
}
|
|
});
|
|
|
|
return win;
|
|
}
|
|
|
|
app.once("browser-window-created", (event, win) => {
|
|
loadPlugins(win);
|
|
|
|
win.webContents.on("did-fail-load", (
|
|
_event,
|
|
errorCode,
|
|
errorDescription,
|
|
validatedURL,
|
|
isMainFrame,
|
|
frameProcessId,
|
|
frameRoutingId,
|
|
) => {
|
|
const log = JSON.stringify({
|
|
error: "did-fail-load",
|
|
errorCode,
|
|
errorDescription,
|
|
validatedURL,
|
|
isMainFrame,
|
|
frameProcessId,
|
|
frameRoutingId,
|
|
}, null, "\t");
|
|
if (is.dev()) {
|
|
console.log(log);
|
|
}
|
|
if( !(config.plugins.isEnabled("in-app-menu") && errorCode === -3)) { // -3 is a false positive with in-app-menu
|
|
win.webContents.send("log", log);
|
|
win.webContents.loadFile(path.join(__dirname, "error.html"));
|
|
}
|
|
});
|
|
|
|
win.webContents.on("will-prevent-unload", (event) => {
|
|
event.preventDefault();
|
|
});
|
|
|
|
win.webContents.on("did-navigate-in-page", () => {
|
|
const url = win.webContents.getURL();
|
|
if (url.startsWith("https://music.youtube.com")) {
|
|
config.set("url", url);
|
|
}
|
|
});
|
|
|
|
win.webContents.on("will-navigate", (_, url) => {
|
|
if (url.startsWith("https://accounts.google.com")) {
|
|
// Force user-agent "Firefox Windows" for Google OAuth to work
|
|
// From https://github.com/firebase/firebase-js-sdk/issues/2478#issuecomment-571356751
|
|
// Only set on accounts.google.com, otherwise querySelectors in preload scripts fail (?)
|
|
const userAgent =
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:70.0) Gecko/20100101 Firefox/70.0";
|
|
|
|
win.webContents.session.webRequest.onBeforeSendHeaders((details, cb) => {
|
|
details.requestHeaders["User-Agent"] = userAgent;
|
|
cb({ requestHeaders: details.requestHeaders });
|
|
});
|
|
}
|
|
});
|
|
|
|
win.webContents.on(
|
|
"new-window",
|
|
(e, url, frameName, disposition, options) => {
|
|
// hook on new opened window
|
|
|
|
// at now new window in mainWindow renderer process.
|
|
// Also, this will automatically get an option `nodeIntegration=false`(not override to true, like in iframe's) - like in regular browsers
|
|
options.webPreferences.affinity = "main-window";
|
|
}
|
|
);
|
|
});
|
|
|
|
app.on("window-all-closed", () => {
|
|
if (process.platform !== "darwin") {
|
|
app.quit();
|
|
}
|
|
|
|
// Unregister all shortcuts.
|
|
electron.globalShortcut.unregisterAll();
|
|
});
|
|
|
|
app.on("activate", () => {
|
|
// On OS X it's common to re-create a window in the app when the
|
|
// dock icon is clicked and there are no other windows open.
|
|
if (mainWindow === null) {
|
|
mainWindow = createMainWindow();
|
|
} else if (!mainWindow.isVisible()) {
|
|
mainWindow.show();
|
|
}
|
|
});
|
|
|
|
app.on("ready", () => {
|
|
if (config.get("options.autoResetAppCache")) {
|
|
// Clear cache after 20s
|
|
const clearCacheTimeout = setTimeout(() => {
|
|
if (is.dev()) {
|
|
console.log("Clearing app cache.");
|
|
}
|
|
electron.session.defaultSession.clearCache();
|
|
clearTimeout(clearCacheTimeout);
|
|
}, 20000);
|
|
}
|
|
|
|
mainWindow = createMainWindow();
|
|
setApplicationMenu(mainWindow);
|
|
if (config.get("options.restartOnConfigChanges")) {
|
|
config.watch(() => {
|
|
app.relaunch();
|
|
app.exit();
|
|
});
|
|
}
|
|
setUpTray(app, mainWindow);
|
|
|
|
// Autostart at login
|
|
app.setLoginItemSettings({
|
|
openAtLogin: config.get("options.startAtLogin"),
|
|
});
|
|
|
|
if (!is.dev() && config.get("options.autoUpdates")) {
|
|
const updateTimeout = setTimeout(() => {
|
|
autoUpdater.checkForUpdatesAndNotify();
|
|
clearTimeout(updateTimeout);
|
|
}, 2000);
|
|
autoUpdater.on("update-available", () => {
|
|
const downloadLink =
|
|
"https://github.com/th-ch/youtube-music/releases/latest";
|
|
const dialogOpts = {
|
|
type: "info",
|
|
buttons: ["OK", "Download", "Disable updates"],
|
|
title: "Application Update",
|
|
message: "A new version is available",
|
|
detail: `A new version is available and can be downloaded at ${downloadLink}`,
|
|
};
|
|
electron.dialog.showMessageBox(dialogOpts).then((dialogOutput) => {
|
|
switch (dialogOutput.response) {
|
|
// Download
|
|
case 1:
|
|
electron.shell.openExternal(downloadLink);
|
|
break;
|
|
// Disable updates
|
|
case 2:
|
|
config.set("options.autoUpdates", false);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// Optimized for Mac OS X
|
|
if (is.macOS() && !config.get("options.appVisible")) {
|
|
app.dock.hide();
|
|
}
|
|
|
|
let forceQuit = false;
|
|
app.on("before-quit", () => {
|
|
forceQuit = true;
|
|
});
|
|
|
|
if (is.macOS() || config.get("options.tray")) {
|
|
mainWindow.on("close", (event) => {
|
|
// Hide the window instead of quitting (quit is available in tray options)
|
|
if (!forceQuit) {
|
|
event.preventDefault();
|
|
mainWindow.hide();
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
function showUnresponsiveDialog(win, details) {
|
|
if (!!details) {
|
|
console.log("Unresponsive Error!\n"+JSON.stringify(details, null, "\t"))
|
|
}
|
|
electron.dialog.showMessageBox(win, {
|
|
type: "error",
|
|
title: "Window Unresponsive",
|
|
message: "The Application is Unresponsive",
|
|
details: "We are sorry for the inconvenience! please choose what to do:",
|
|
buttons: ["Wait", "Relaunch", "Quit"],
|
|
cancelId: 0
|
|
}).then( result => {
|
|
switch (result.response) {
|
|
case 1: //if relaunch - relaunch+exit
|
|
app.relaunch();
|
|
case 2:
|
|
app.quit();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
});
|
|
}
|