Compare commits

...

8 Commits

Author SHA1 Message Date
TC
fc48b920a8 Bump app version to 1.6.0 2020-11-11 12:22:36 +01:00
TC
9bc81da6f2 Plugins/event handlers in each window 2020-11-11 12:16:01 +01:00
TC
2b3363f5dc Bump YoutubeNonStop 2020-11-11 11:36:40 +01:00
TC
bcff6e5134 Add notifications plugin (notify of song on play event) 2020-11-11 11:35:58 +01:00
1dcf76b006 Merge pull request #54 from th-ch/snyk-upgrade-1b704161a30f8a56030e33c24f620f14
[Snyk] Upgrade electron-store from 6.0.0 to 6.0.1
2020-11-04 22:36:53 +01:00
7bdc0f42a2 fix: upgrade electron-store from 6.0.0 to 6.0.1
Snyk has created this PR to upgrade electron-store from 6.0.0 to 6.0.1.

See this package in npm:


See this project in Snyk:
https://app.snyk.io/org/th-ch/project/81809c53-bb7b-46b9-a0d7-806d45d74ac6?utm_source=github&utm_medium=upgrade-pr
2020-10-27 02:19:22 +00:00
TC
023f5b6bc3 Block alert if leaving page when playing (onbeforeunload event) 2020-10-19 22:44:39 +02:00
TC
3e97e9307c Option to toggle devtools 2020-10-18 17:02:12 +02:00
9 changed files with 229 additions and 68 deletions

113
index.js
View File

@ -41,33 +41,7 @@ function onClosed() {
mainWindow = null;
}
function createMainWindow() {
const windowSize = store.get("window-size");
const windowMaximized = store.get("window-maximized");
const win = new electron.BrowserWindow({
icon: icon,
width: windowSize.width,
height: windowSize.height,
backgroundColor: "#000",
show: false,
webPreferences: {
nodeIntegration: isTesting(), // Only necessary when testing with Spectron
preload: path.join(__dirname, "preload.js"),
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
},
frame: !is.macOS(),
titleBarStyle: is.macOS() ? "hiddenInset" : "default",
});
if (windowMaximized) {
win.maximize();
}
win.webContents.loadURL(store.get("url"));
win.on("closed", onClosed);
function loadPlugins(win) {
injectCSS(win.webContents, path.join(__dirname, "youtube-music.css"));
win.webContents.on("did-finish-load", () => {
if (is.dev()) {
@ -84,6 +58,61 @@ function createMainWindow() {
handle(win);
});
});
}
function createMainWindow() {
const windowSize = store.get("window-size");
const windowMaximized = store.get("window-maximized");
const win = new electron.BrowserWindow({
icon: icon,
width: windowSize.width,
height: windowSize.height,
backgroundColor: "#000",
show: false,
webPreferences: {
nodeIntegration: isTesting(), // Only necessary when testing with Spectron
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
},
frame: !is.macOS(),
titleBarStyle: is.macOS() ? "hiddenInset" : "default",
});
if (windowMaximized) {
win.maximize();
}
win.webContents.loadURL(store.get("url"));
win.on("closed", onClosed);
win.on("move", () => {
let position = win.getPosition();
store.set("window-position", { x: position[0], y: position[1] });
});
win.on("resize", () => {
const windowSize = win.getSize();
store.set("window-maximized", win.isMaximized());
if (!win.isMaximized()) {
store.set("window-size", { width: windowSize[0], height: windowSize[1] });
}
});
win.once("ready-to-show", () => {
if (isAppVisible()) {
win.show();
}
});
return win;
}
app.on("browser-window-created", (event, win) => {
loadPlugins(win);
win.webContents.on("did-fail-load", () => {
if (is.dev()) {
@ -92,6 +121,10 @@ function createMainWindow() {
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")) {
@ -124,29 +157,7 @@ function createMainWindow() {
options.webPreferences.affinity = "main-window";
}
);
win.on("move", () => {
let position = win.getPosition();
store.set("window-position", { x: position[0], y: position[1] });
});
win.on("resize", () => {
const windowSize = win.getSize();
store.set("window-maximized", win.isMaximized());
if (!win.isMaximized()) {
store.set("window-size", { width: windowSize[0], height: windowSize[1] });
}
});
win.once("ready-to-show", () => {
if (isAppVisible()) {
win.show();
}
});
return win;
}
});
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
@ -168,8 +179,8 @@ app.on("activate", () => {
});
app.on("ready", () => {
setApplicationMenu();
mainWindow = createMainWindow();
setApplicationMenu(mainWindow);
setUpTray(app, mainWindow);
// Autostart at login

19
menu.js
View File

@ -13,7 +13,7 @@ const {
startAtLogin,
} = require("./store");
const mainMenuTemplate = [
const mainMenuTemplate = (win) => [
{
label: "Plugins",
submenu: getAllPlugins().map((plugin) => {
@ -79,13 +79,26 @@ const mainMenuTemplate = [
},
],
},
{
label: "Toggle DevTools",
// Cannot use "toggleDevTools" role in MacOS
click: () => {
const { webContents } = win;
if (webContents.isDevToolsOpened()) {
webContents.closeDevTools();
} else {
const devToolsOptions = {};
webContents.openDevTools(devToolsOptions);
}
},
},
],
},
];
module.exports.mainMenuTemplate = mainMenuTemplate;
module.exports.setApplicationMenu = () => {
const menuTemplate = [...mainMenuTemplate];
module.exports.setApplicationMenu = (win) => {
const menuTemplate = [...mainMenuTemplate(win)];
if (process.platform === "darwin") {
const name = app.name;
menuTemplate.unshift({

View File

@ -1,7 +1,7 @@
{
"name": "youtube-music",
"productName": "YouTube Music",
"version": "1.5.0",
"version": "1.6.0",
"description": "YouTube Music Desktop App - including custom plugins",
"license": "MIT",
"repository": "th-ch/youtube-music",
@ -47,11 +47,11 @@
},
"dependencies": {
"@cliqz/adblocker-electron": "^1.18.3",
"YoutubeNonStop": "git://github.com/lawfx/YoutubeNonStop.git#v0.7.1",
"YoutubeNonStop": "git://github.com/lawfx/YoutubeNonStop.git#v0.8.0",
"electron-debug": "^3.1.0",
"electron-is": "^3.0.0",
"electron-localshortcut": "^3.2.1",
"electron-store": "^6.0.0",
"electron-store": "^6.0.1",
"electron-updater": "^4.3.5",
"node-fetch": "^2.6.1"
},

View File

@ -0,0 +1,18 @@
const { triggerAction } = require("../utils");
const CHANNEL = "notification";
const ACTIONS = {
NOTIFICATION: "notification",
};
function notify(info) {
triggerAction(CHANNEL, ACTIONS.NOTIFICATION, info);
}
module.exports = {
CHANNEL,
ACTIONS,
global: {
notify,
},
};

View File

@ -0,0 +1,33 @@
const { nativeImage, Notification } = require("electron");
const { listenAction } = require("../utils");
const { ACTIONS, CHANNEL } = require("./actions.js");
function notify(info) {
let notificationImage = "assets/youtube-music.png";
if (info.image) {
notificationImage = nativeImage.createFromDataURL(info.image);
}
const notification = {
title: info.title || "Playing",
body: info.artist,
icon: notificationImage,
silent: true,
};
new Notification(notification).show();
}
function listenAndNotify() {
listenAction(CHANNEL, (event, action, imageSrc) => {
switch (action) {
case ACTIONS.NOTIFICATION:
notify(imageSrc);
break;
default:
console.log("Unknown action: " + action);
}
});
}
module.exports = listenAndNotify;

View File

@ -0,0 +1,86 @@
let videoElement = null;
let image = null;
const observer = new MutationObserver((mutations, observer) => {
if (!videoElement) {
videoElement = document.querySelector("video");
}
if (!image) {
image = document.querySelector(".ytmusic-player-bar.image");
}
if (videoElement !== null && image !== null) {
observer.disconnect();
let notificationImage = null;
videoElement.addEventListener("play", () => {
notify({
title: getTitle(),
artist: getArtist(),
image: notificationImage,
});
});
image.addEventListener("load", () => {
notificationImage = null;
const imageInBase64 = convertImageToBase64(image);
if (image && image.complete && image.naturalHeight !== 0) {
notificationImage = imageInBase64;
}
});
}
});
// Convert an image (DOM element) to base64 string
const convertImageToBase64 = (image, size = 256) => {
image.setAttribute("crossorigin", "anonymous");
const c = document.createElement("canvas");
c.height = size;
c.width = size;
const ctx = c.getContext("2d");
ctx.drawImage(
image,
0,
0,
image.naturalWidth,
image.naturalHeight,
0,
0,
c.width,
c.height
);
const imageInBase64 = c.toDataURL();
return imageInBase64;
};
const getTitle = () => {
const title = document.querySelector(".title.ytmusic-player-bar").textContent;
return title;
};
const getArtist = () => {
const bar = document.querySelectorAll(".subtitle.ytmusic-player-bar")[0];
let artist;
if (bar.querySelectorAll(".yt-simple-endpoint.yt-formatted-string")[0]) {
artist = bar.querySelectorAll(".yt-simple-endpoint.yt-formatted-string")[0]
.textContent;
} else if (bar.querySelectorAll(".byline.ytmusic-player-bar")[0]) {
artist = bar.querySelectorAll(".byline.ytmusic-player-bar")[0].textContent;
}
return artist;
};
const observeVideoAndThumbnail = () => {
observer.observe(document, {
childList: true,
subtree: true,
});
};
module.exports = observeVideoAndThumbnail;

View File

@ -20,8 +20,8 @@ module.exports.templatePath = (pluginPath, name) => {
return path.join(pluginPath, "templates", name);
};
module.exports.triggerAction = (channel, action) => {
return ipcRenderer.send(channel, action);
module.exports.triggerAction = (channel, action, ...args) => {
return ipcRenderer.send(channel, action, ...args);
};
module.exports.listenAction = (channel, callback) => {

View File

@ -61,7 +61,7 @@ module.exports.setUpTray = (app, win) => {
win.show();
},
},
...mainMenuTemplate,
...mainMenuTemplate(win),
{
label: "Quit",
click: () => {

View File

@ -1379,9 +1379,9 @@
dependencies:
"@wdio/logger" "6.4.7"
"YoutubeNonStop@git://github.com/lawfx/YoutubeNonStop.git#v0.7.1":
"YoutubeNonStop@git://github.com/lawfx/YoutubeNonStop.git#v0.8.0":
version "0.0.0"
resolved "git://github.com/lawfx/YoutubeNonStop.git#4f8cc214636226ecc8ea2b830435855c067aea2e"
resolved "git://github.com/lawfx/YoutubeNonStop.git#c2252130fbd63baa70047355a84fe424adb1c9e0"
abab@^2.0.3:
version "2.0.5"
@ -2392,7 +2392,7 @@ concat-stream@^1.6.2:
readable-stream "^2.2.2"
typedarray "^0.0.6"
conf@^7.1.1:
conf@^7.1.2:
version "7.1.2"
resolved "https://registry.yarnpkg.com/conf/-/conf-7.1.2.tgz#d9678a9d8f04de8bf5cd475105da8fdae49c2ec4"
integrity sha512-r8/HEoWPFn4CztjhMJaWNAe5n+gPUCSaJ0oufbqDLFKsA1V8JjAG7G+p0pgoDFAws9Bpk2VtVLLXqOBA7WxLeg==
@ -3022,12 +3022,12 @@ electron-publish@22.8.1:
lazy-val "^1.0.4"
mime "^2.4.6"
electron-store@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/electron-store/-/electron-store-6.0.0.tgz#92a5f8295a326f074281ae0d6a307454e6f68243"
integrity sha512-ujb0a/6gxMxb9vOQ2BjOehK9VCyq5OKvttekd9v/tohA9oBHnAdV+Vxu4eoRh+/F9ShPFhcvDZkMdqO5i+TXUw==
electron-store@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/electron-store/-/electron-store-6.0.1.tgz#2178b9dc37aeb749d99cf9d1d1bc090890b922dc"
integrity sha512-8rdM0XEmDGsLuZM2oRABzsLX+XmD5x3rwxPMEPv0MrN9/BWanyy3ilb2v+tCrKtIZVF3MxUiZ9Bfqe8e0popKQ==
dependencies:
conf "^7.1.1"
conf "^7.1.2"
type-fest "^0.16.0"
electron-updater@^4.3.5: