Compare commits

...

15 Commits

Author SHA1 Message Date
c5bda4f3be Merge pull request #178 from th-ch/snyk-upgrade-da4beb25f2fa1631098996298cd49f89
[Snyk] Upgrade electron-store from 7.0.1 to 7.0.2
2021-03-09 19:50:17 +01:00
3dc92b4939 fix: upgrade electron-store from 7.0.1 to 7.0.2
Snyk has created this PR to upgrade electron-store from 7.0.1 to 7.0.2.

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
2021-03-05 02:19:09 +00:00
TC
150146385f Bump version 2021-03-04 23:09:27 +01:00
TC
f50bd32fa3 Fix resumeOnStart option 2021-03-04 23:09:01 +01:00
0dcf820944 Merge pull request #177 from NNowakowski/resume-last-song-on-start
Added function to toggle resuming of last song when app starts
2021-03-04 22:57:41 +01:00
6fd16684f7 Merge pull request #175 from th-ch/snyk-upgrade-024effb4b0bec6e73345b87366580cf3
[Snyk] Upgrade discord-rpc from 3.1.4 to 3.2.0
2021-03-04 22:54:13 +01:00
TC
eaa957168f Add plugin to disable autoplay 2021-03-04 22:47:53 +01:00
TC
796a7aaaf1 Fix download/speed menu item 2021-03-04 21:29:37 +01:00
9aaae7b2d9 🚀 Added function to toggle resuming of last song when app starts 2021-03-04 14:14:49 +01:00
c00609223b fix: upgrade discord-rpc from 3.1.4 to 3.2.0
Snyk has created this PR to upgrade discord-rpc from 3.1.4 to 3.2.0.

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
2021-03-04 02:19:26 +00:00
5641c3fc87 Merge pull request #154 from th-ch/snyk-upgrade-3f26f6e01fe99104189d358a840963dd
[Snyk] Upgrade @cliqz/adblocker-electron from 1.19.0 to 1.20.0
2021-02-24 23:11:02 +01:00
dd1bdae947 Added metadata to downloader plugin, and updated packages 2021-02-24 22:53:31 +01:00
TC
70973b2281 Clear cache after 20s if option is enabled 2021-02-24 21:08:25 +01:00
TC
5842a6d42f Handle uncaught errors 2021-02-24 20:53:41 +01:00
538ab52abd fix: upgrade @cliqz/adblocker-electron from 1.19.0 to 1.20.0
Snyk has created this PR to upgrade @cliqz/adblocker-electron from 1.19.0 to 1.20.0.

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
2021-02-12 02:19:15 +00:00
14 changed files with 1991 additions and 1830 deletions

View File

@ -14,6 +14,7 @@ const defaultConfig = {
restartOnConfigChanges: false, restartOnConfigChanges: false,
trayClickPlayPause: false, trayClickPlayPause: false,
autoResetAppCache: false, autoResetAppCache: false,
resumeOnStart: true,
}, },
plugins: { plugins: {
// Enabled plugins // Enabled plugins

View File

@ -1,3 +1,4 @@
const defaultConfig = require("./defaults");
const plugins = require("./plugins"); const plugins = require("./plugins");
const store = require("./store"); const store = require("./store");
@ -10,6 +11,7 @@ const get = (key) => {
}; };
module.exports = { module.exports = {
defaultConfig,
get, get,
set, set,
edit: () => store.openInEditor(), edit: () => store.openInEditor(),

View File

@ -3,6 +3,11 @@ const Store = require("electron-store");
const defaults = require("./defaults"); const defaults = require("./defaults");
const migrations = { const migrations = {
">=1.11.0": (store) => {
if (store.get("options.resumeOnStart") === undefined) {
store.set("options.resumeOnStart", true);
}
},
">=1.7.0": (store) => { ">=1.7.0": (store) => {
const enabledPlugins = store.get("plugins"); const enabledPlugins = store.get("plugins");
if (!Array.isArray(enabledPlugins)) { if (!Array.isArray(enabledPlugins)) {

View File

@ -3,6 +3,7 @@ const path = require("path");
const electron = require("electron"); const electron = require("electron");
const is = require("electron-is"); const is = require("electron-is");
const unhandled = require("electron-unhandled");
const { autoUpdater } = require("electron-updater"); const { autoUpdater } = require("electron-updater");
const config = require("./config"); const config = require("./config");
@ -11,6 +12,12 @@ const { fileExists, injectCSS } = require("./plugins/utils");
const { isTesting } = require("./utils/testing"); const { isTesting } = require("./utils/testing");
const { setUpTray } = require("./tray"); const { setUpTray } = require("./tray");
// Catch errors and log them
unhandled({
logger: console.error,
showDialog: false,
});
const app = electron.app; const app = electron.app;
app.commandLine.appendSwitch( app.commandLine.appendSwitch(
"js-flags", "js-flags",
@ -104,7 +111,10 @@ function createMainWindow() {
win.maximize(); win.maximize();
} }
win.webContents.loadURL(config.get("url")); const urlToLoad = config.get("options.resumeOnStart")
? config.get("url")
: config.defaultConfig.url;
win.webContents.loadURL(urlToLoad);
win.on("closed", onClosed); win.on("closed", onClosed);
win.on("move", () => { win.on("move", () => {
@ -202,8 +212,14 @@ app.on("activate", () => {
app.on("ready", () => { app.on("ready", () => {
if (config.get("options.autoResetAppCache")) { if (config.get("options.autoResetAppCache")) {
// Clear cache // Clear cache after 20s
electron.session.defaultSession.clearCache(); const clearCacheTimeout = setTimeout(() => {
if (is.dev()) {
console.log("Clearing app cache.");
}
electron.session.defaultSession.clearCache();
clearTimeout(clearCacheTimeout);
}, 20000);
} }
mainWindow = createMainWindow(); mainWindow = createMainWindow();

View File

@ -66,6 +66,14 @@ const mainMenuTemplate = (win) => [
config.set("options.autoResetAppCache", item.checked); config.set("options.autoResetAppCache", item.checked);
}, },
}, },
{
label: "Resume last song when app starts",
type: "checkbox",
checked: config.get("options.resumeOnStart"),
click: (item) => {
config.set("options.resumeOnStart", item.checked);
},
},
...(is.windows() || is.linux() ...(is.windows() || is.linux()
? [ ? [
{ {

View File

@ -1,7 +1,7 @@
{ {
"name": "youtube-music", "name": "youtube-music",
"productName": "YouTube Music", "productName": "YouTube Music",
"version": "1.10.0", "version": "1.11.0",
"description": "YouTube Music Desktop App - including custom plugins", "description": "YouTube Music Desktop App - including custom plugins",
"license": "MIT", "license": "MIT",
"repository": "th-ch/youtube-music", "repository": "th-ch/youtube-music",
@ -19,7 +19,10 @@
}, },
"win": { "win": {
"icon": "assets/generated/icons/win/icon.ico", "icon": "assets/generated/icons/win/icon.ico",
"target": ["nsis", "portable"] "target": [
"nsis",
"portable"
]
}, },
"nsis": { "nsis": {
"runAfterFinish": false "runAfterFinish": false
@ -59,31 +62,33 @@
"npm": "Please use yarn and not npm" "npm": "Please use yarn and not npm"
}, },
"dependencies": { "dependencies": {
"@cliqz/adblocker-electron": "^1.19.0", "@cliqz/adblocker-electron": "^1.20.0",
"@ffmpeg/core": "^0.8.5", "@ffmpeg/core": "^0.8.5",
"@ffmpeg/ffmpeg": "^0.9.7", "@ffmpeg/ffmpeg": "^0.9.7",
"YoutubeNonStop": "git://github.com/lawfx/YoutubeNonStop.git#v0.8.1", "YoutubeNonStop": "git://github.com/lawfx/YoutubeNonStop.git#v0.8.1",
"discord-rpc": "^3.1.4", "browser-id3-writer": "^4.4.0",
"discord-rpc": "^3.2.0",
"downloads-folder": "^3.0.1", "downloads-folder": "^3.0.1",
"electron-debug": "^3.2.0", "electron-debug": "^3.2.0",
"electron-is": "^3.0.0", "electron-is": "^3.0.0",
"electron-localshortcut": "^3.2.1", "electron-localshortcut": "^3.2.1",
"electron-store": "^6.0.1", "electron-store": "^7.0.2",
"electron-unhandled": "^3.0.2",
"electron-updater": "^4.3.6", "electron-updater": "^4.3.6",
"filenamify": "^4.2.0", "filenamify": "^4.2.0",
"node-fetch": "^2.6.1", "node-fetch": "^2.6.1",
"ytdl-core": "^4.3.0" "ytdl-core": "^4.4.5"
}, },
"devDependencies": { "devDependencies": {
"electron": "^11.1.1", "electron": "^11.2.3",
"electron-builder": "^22.8.1", "electron-builder": "^22.9.1",
"electron-devtools-installer": "^3.1.1", "electron-devtools-installer": "^3.1.1",
"electron-icon-maker": "0.0.5", "electron-icon-maker": "0.0.5",
"get-port": "^5.1.1", "get-port": "^5.1.1",
"jest": "^26.4.2", "jest": "^26.6.3",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"spectron": "^13.0.0", "spectron": "^13.0.0",
"xo": "^0.33.1" "xo": "^0.37.1"
}, },
"resolutions": { "resolutions": {
"yargs-parser": "18.1.3" "yargs-parser": "18.1.3"

View File

@ -0,0 +1,25 @@
let videoElement = null;
const observer = new MutationObserver((mutations, observer) => {
if (!videoElement) {
videoElement = document.querySelector("video");
}
if (videoElement) {
videoElement.ontimeupdate = () => {
if (videoElement.currentTime === 0 && videoElement.duration !== NaN) {
// auto-confirm-when-paused plugin can interfere here if not disabled!
videoElement.pause();
}
};
}
});
function observeVideoElement() {
observer.observe(document, {
childList: true,
subtree: true,
});
}
module.exports = observeVideoElement;

View File

@ -1,6 +1,8 @@
const { writeFileSync } = require("fs");
const { join } = require("path"); const { join } = require("path");
const { dialog } = require("electron"); const ID3Writer = require("browser-id3-writer");
const { dialog, ipcMain } = require("electron");
const getSongInfo = require("../../providers/song-info"); const getSongInfo = require("../../providers/song-info");
const { injectCSS, listenAction } = require("../utils"); const { injectCSS, listenAction } = require("../utils");
@ -23,10 +25,7 @@ function handle(win) {
injectCSS(win.webContents, join(__dirname, "style.css")); injectCSS(win.webContents, join(__dirname, "style.css"));
const registerCallback = getSongInfo(win); const registerCallback = getSongInfo(win);
registerCallback((info) => { registerCallback((info) => {
metadata = { metadata = info;
...info,
image: info.image ? info.image.toDataURL() : undefined,
};
}); });
listenAction(CHANNEL, (event, action, error) => { listenAction(CHANNEL, (event, action, error) => {
@ -41,6 +40,33 @@ function handle(win) {
console.log("Unknown action: " + action); console.log("Unknown action: " + action);
} }
}); });
ipcMain.on("add-metadata", (event, filePath, songBuffer) => {
let fileBuffer = songBuffer;
try {
const coverBuffer = metadata.image.toPNG();
const writer = new ID3Writer(songBuffer);
// Create the metadata tags
writer
.setFrame("TIT2", metadata.title)
.setFrame("TPE1", [metadata.artist])
.setFrame("APIC", {
type: 3,
data: coverBuffer,
description: "",
});
writer.addTag();
fileBuffer = Buffer.from(writer.arrayBuffer);
} catch (error) {
sendError(win, error);
}
writeFileSync(filePath, fileBuffer);
// Notify the youtube-dl file
event.reply("add-metadata-done");
});
} }
module.exports = handle; module.exports = handle;

View File

@ -1,5 +1,6 @@
const { contextBridge } = require("electron"); const { contextBridge } = require("electron");
const { getSongMenu } = require("../../providers/dom-elements");
const { ElementFromFile, templatePath, triggerAction } = require("../utils"); const { ElementFromFile, templatePath, triggerAction } = require("../utils");
const { ACTIONS, CHANNEL } = require("./actions.js"); const { ACTIONS, CHANNEL } = require("./actions.js");
const { downloadVideoToMP3 } = require("./youtube-dl"); const { downloadVideoToMP3 } = require("./youtube-dl");
@ -13,7 +14,7 @@ let pluginOptions = {};
const observer = new MutationObserver((mutations, observer) => { const observer = new MutationObserver((mutations, observer) => {
if (!menu) { if (!menu) {
menu = document.querySelector("ytmusic-menu-popup-renderer paper-listbox"); menu = getSongMenu();
} }
if (menu && !menu.contains(downloadButton)) { if (menu && !menu.contains(downloadButton)) {

View File

@ -1,8 +1,8 @@
const { randomBytes } = require("crypto"); const { randomBytes } = require("crypto");
const { writeFileSync } = require("fs");
const { join } = require("path"); const { join } = require("path");
const downloadsFolder = require("downloads-folder"); const downloadsFolder = require("downloads-folder");
const { ipcRenderer } = require("electron");
const is = require("electron-is"); const is = require("electron-is");
const filenamify = require("filenamify"); const filenamify = require("filenamify");
@ -109,12 +109,15 @@ const toMP3 = async (
const filename = filenamify(name + "." + extension, { const filename = filenamify(name + "." + extension, {
replacement: "_", replacement: "_",
}); });
writeFileSync(
// Add the metadata
sendFeedback("Adding metadata…");
ipcRenderer.send(
"add-metadata",
join(folder, filename), join(folder, filename),
ffmpeg.FS("readFile", safeVideoName + "." + extension) ffmpeg.FS("readFile", safeVideoName + "." + extension)
); );
ipcRenderer.once("add-metadata-done", reinit);
reinit();
} catch (e) { } catch (e) {
sendError(e); sendError(e);
} }

View File

@ -1,4 +1,7 @@
const { watchDOMElement } = require("../../providers/dom-elements"); const {
getSongMenu,
watchDOMElement,
} = require("../../providers/dom-elements");
const { ElementFromFile, templatePath } = require("../utils"); const { ElementFromFile, templatePath } = require("../utils");
const slider = ElementFromFile(templatePath(__dirname, "slider.html")); const slider = ElementFromFile(templatePath(__dirname, "slider.html"));
@ -49,8 +52,7 @@ module.exports = () => {
watchDOMElement( watchDOMElement(
"menu", "menu",
(document) => (document) => getSongMenu(document),
document.querySelector("ytmusic-menu-popup-renderer paper-listbox"),
(menuElement) => { (menuElement) => {
if (!menuElement.contains(slider)) { if (!menuElement.contains(slider)) {
menuElement.prepend(slider); menuElement.prepend(slider);

View File

@ -5,7 +5,7 @@
aria-disabled="false" aria-disabled="false"
aria-selected="false" aria-selected="false"
> >
<paper-slider <tp-yt-paper-slider
id="playback-speed-slider" id="playback-speed-slider"
class="volume-slider style-scope ytmusic-player-bar on-hover" class="volume-slider style-scope ytmusic-player-bar on-hover"
max="100" max="100"
@ -22,68 +22,53 @@
aria-disabled="false" aria-disabled="false"
value="50" value="50"
><!--css-build:shady--> ><!--css-build:shady-->
<div id="sliderContainer" class="style-scope paper-slider"> <div id="sliderContainer" class="style-scope tp-yt-paper-slider">
<div class="bar-container style-scope paper-slider"> <div class="bar-container style-scope tp-yt-paper-slider">
<paper-progress <tp-yt-paper-progress
id="sliderBar" id="sliderBar"
aria-hidden="true" aria-hidden="true"
class="style-scope paper-slider" class="style-scope tp-yt-paper-slider"
role="progressbar" role="progressbar"
value="50" value="50"
aria-valuenow="50" aria-valuenow="50"
aria-valuemin="0" aria-valuemin="0"
aria-valuemax="100" aria-valuemax="100"
aria-disabled="false" aria-disabled="false"
style="touch-action: none;" style="touch-action: none"
><!--css-build:shady--> ><!--css-build:shady-->
<div id="progressContainer" class="style-scope paper-progress"> <div id="progressContainer" class="style-scope tp-yt-paper-progress">
<div <div
id="secondaryProgress" id="secondaryProgress"
class="style-scope paper-progress" class="style-scope tp-yt-paper-progress"
hidden="true" hidden="true"
style="transform: scaleX(0);" style="transform: scaleX(0)"
></div> ></div>
<div <div
id="primaryProgress" id="primaryProgress"
class="style-scope paper-progress" class="style-scope tp-yt-paper-progress"
style="transform: scaleX(0.5);" style="transform: scaleX(0.5)"
></div> ></div>
</div> </div>
</paper-progress> </tp-yt-paper-progress>
</div> </div>
<dom-if class="style-scope paper-slider" <dom-if class="style-scope tp-yt-paper-slider"
><template is="dom-if"></template ><template is="dom-if"></template
></dom-if> ></dom-if>
<div <div
id="sliderKnob" id="sliderKnob"
class="slider-knob style-scope paper-slider" class="slider-knob style-scope tp-yt-paper-slider"
style="left: 50%; touch-action: none;" style="left: 50%; touch-action: none"
> >
<div <div
class="slider-knob-inner style-scope paper-slider" class="slider-knob-inner style-scope tp-yt-paper-slider"
value="50" value="50"
></div> ></div>
<paper-ripple
id="ink"
center=""
class="circle style-scope paper-slider"
style="display: none;"
><!--css-build:shady-->
<div
id="background"
class="style-scope paper-ripple"
style="opacity: 0.006008;"
></div>
<div id="waves" class="style-scope paper-ripple"></div>
</paper-ripple>
</div> </div>
</div> </div>
<dom-if class="style-scope paper-slider" <dom-if class="style-scope tp-yt-paper-slider"
><template is="dom-if"></template ><template is="dom-if"></template></dom-if
></dom-if> ></tp-yt-paper-slider>
</paper-slider>
<div <div
class="text style-scope ytmusic-toggle-menu-service-item-renderer" class="text style-scope ytmusic-toggle-menu-service-item-renderer"

View File

@ -17,4 +17,7 @@ const watchDOMElement = (name, selectorFn, cb) => {
}); });
}; };
module.exports = { watchDOMElement }; const getSongMenu = () =>
document.querySelector("ytmusic-menu-popup-renderer tp-yt-paper-listbox");
module.exports = { getSongMenu, watchDOMElement };

3617
yarn.lock

File diff suppressed because it is too large Load Diff