Skip to content

Commit

Permalink
Merge branch 'master' into custom-electron-prompt
Browse files Browse the repository at this point in the history
  • Loading branch information
Araxeus authored May 7, 2021
2 parents 6b147b0 + 5faeddb commit 5418ef7
Show file tree
Hide file tree
Showing 16 changed files with 199 additions and 82 deletions.
1 change: 0 additions & 1 deletion config/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ const defaultConfig = {
api_root: "http://ws.audioscrobbler.com/2.0/",
api_key: "04d76faaac8726e60988e14c105d421a", // api key registered by @semvis123
secret: "a5d2a36fdf64819290f6982481eaffa2",
suffixesToRemove: [' - Topic', 'VEVO'] // removes suffixes of the artist name, for better recognition
},
discord: {
enabled: false,
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "youtube-music",
"productName": "YouTube Music",
"version": "1.12.0",
"version": "1.12.1",
"description": "YouTube Music Desktop App - including custom plugins",
"license": "MIT",
"repository": "th-ch/youtube-music",
Expand Down Expand Up @@ -42,6 +42,7 @@
"scripts": {
"test": "jest",
"start": "electron .",
"start:debug": "ELECTRON_ENABLE_LOGGING=1 electron .",
"icon": "rimraf assets/generated && electron-icon-maker --input=assets/youtube-music.png --output=assets/generated",
"generate:package": "node utils/generate-package-json.js",
"postinstall": "yarn run icon && yarn run plugins",
Expand Down Expand Up @@ -69,6 +70,7 @@
"async-mutex": "^0.3.1",
"browser-id3-writer": "^4.4.0",
"custom-electron-prompt": "^1.1.0",
"chokidar": "^3.5.1",
"custom-electron-titlebar": "^3.2.6",
"discord-rpc": "^3.2.0",
"electron-debug": "^3.2.0",
Expand Down
15 changes: 11 additions & 4 deletions plugins/downloader/back.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const { dialog, ipcMain } = require("electron");
const getSongInfo = require("../../providers/song-info");
const { injectCSS, listenAction } = require("../utils");
const { ACTIONS, CHANNEL } = require("./actions.js");
const { getImage } = require("../../providers/song-info");

const sendError = (win, err) => {
const dialogOpts = {
Expand Down Expand Up @@ -41,23 +42,29 @@ function handle(win) {
}
});

ipcMain.on("add-metadata", (event, filePath, songBuffer, currentMetadata) => {
ipcMain.on("add-metadata", async (event, filePath, songBuffer, currentMetadata) => {
let fileBuffer = songBuffer;
const songMetadata = { ...metadata, ...currentMetadata };

if (!songMetadata.image && songMetadata.imageSrc) {
songMetadata.image = await getImage(songMetadata.imageSrc);
}

try {
const coverBuffer = songMetadata.image.toPNG();
const coverBuffer = songMetadata.image ? songMetadata.image.toPNG() : null;
const writer = new ID3Writer(songBuffer);

// Create the metadata tags
writer
.setFrame("TIT2", songMetadata.title)
.setFrame("TPE1", [songMetadata.artist])
.setFrame("APIC", {
.setFrame("TPE1", [songMetadata.artist]);
if (coverBuffer) {
writer.setFrame("APIC", {
type: 3,
data: coverBuffer,
description: "",
});
}
writer.addTag();
fileBuffer = Buffer.from(writer.arrayBuffer);
} catch (error) {
Expand Down
13 changes: 9 additions & 4 deletions plugins/downloader/front.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,18 @@ const baseUrl = defaultConfig.url;
// contextBridge.exposeInMainWorld("downloader", {
// download: () => {
global.download = () => {
let metadata;
let videoUrl = getSongMenu()
.querySelector("ytmusic-menu-navigation-item-renderer")
.querySelector("#navigation-endpoint")
.getAttribute("href");
videoUrl = !videoUrl
? global.songInfo.url || window.location.href
: baseUrl + "/" + videoUrl;
if (videoUrl) {
videoUrl = baseUrl + "/" + videoUrl;
metadata = null;
} else {
metadata = global.songInfo;
videoUrl = metadata.url || window.location.href;
}

downloadVideoToMP3(
videoUrl,
Expand All @@ -61,7 +66,7 @@ global.download = () => {
},
reinit,
pluginOptions,
global.songInfo
metadata
);
};
// });
Expand Down
40 changes: 30 additions & 10 deletions plugins/downloader/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const { URL } = require("url");
const { dialog, ipcMain } = require("electron");
const is = require("electron-is");
const ytpl = require("ytpl");
const chokidar = require('chokidar');

const { setOptions } = require("../../config/plugins");
const getSongInfo = require("../../providers/song-info");
Expand All @@ -15,7 +16,7 @@ let downloadLabel = defaultMenuDownloadLabel;
let metadataURL = undefined;
let callbackIsRegistered = false;

module.exports = (win, options, refreshMenu) => {
module.exports = (win, options) => {
if (!callbackIsRegistered) {
const registerCallback = getSongInfo(win);
registerCallback((info) => {
Expand All @@ -35,7 +36,10 @@ module.exports = (win, options, refreshMenu) => {
return;
}

const playlist = await ytpl(playlistID);
console.log("trying to get playlist ID" +playlistID);
const playlist = await ytpl(playlistID,
{ limit: options.playlistMaxItems || Infinity }
);
const playlistTitle = playlist.title;

const folder = getFolder(options.downloadFolder);
Expand All @@ -49,24 +53,40 @@ module.exports = (win, options, refreshMenu) => {
}
mkdirSync(playlistFolder, { recursive: true });

ipcMain.on("downloader-feedback", (_, feedback) => {
downloadLabel = feedback;
refreshMenu();
dialog.showMessageBox({
type: "info",
buttons: ["OK"],
title: "Started Download",
message: `Downloading Playlist "${playlistTitle}"`,
detail: `(${playlist.items.length} songs)`,
});

downloadLabel = `Downloading "${playlistTitle}"`;
refreshMenu();

if (is.dev()) {
console.log(
`Downloading playlist "${playlistTitle}" (${playlist.items.length} songs)`
);
}

playlist.items.slice(0, options.playlistMaxItems).forEach((song) => {
const steps = 1 / playlist.items.length;
let progress = 0;

win.setProgressBar(2); // starts with indefinite bar

let dirWatcher = chokidar.watch(playlistFolder);
dirWatcher.on('add', () => {
progress += steps;
if (progress >= 0.9999) {
win.setProgressBar(-1); // close progress bar
dirWatcher.close().then(() => dirWatcher = null);
} else {
win.setProgressBar(progress);
}
});

playlist.items.forEach((song) => {
win.webContents.send(
"downloader-download-playlist",
song,
song.url,
playlistTitle,
options
);
Expand Down
32 changes: 19 additions & 13 deletions plugins/downloader/youtube-dl.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ const ytdl = require("ytdl-core");

const { triggerAction, triggerActionSync } = require("../utils");
const { ACTIONS, CHANNEL } = require("./actions.js");
const { defaultMenuDownloadLabel, getFolder } = require("./utils");
const { getFolder } = require("./utils");
const { cleanupArtistName } = require("../../providers/song-info");

const { createFFmpeg } = FFmpeg;
const ffmpeg = createFFmpeg({
Expand All @@ -24,7 +25,7 @@ const ffmpeg = createFFmpeg({
});
const ffmpegMutex = new Mutex();

const downloadVideoToMP3 = (
const downloadVideoToMP3 = async (
videoUrl,
sendFeedback,
sendError,
Expand All @@ -35,6 +36,16 @@ const downloadVideoToMP3 = (
) => {
sendFeedback("Downloading…");

if (metadata === null) {
const info = await ytdl.getInfo(videoUrl);
const thumbnails = info.videoDetails?.author?.thumbnails;
metadata = {
artist: info.videoDetails?.media?.artist || cleanupArtistName(info.videoDetails?.author?.name) || "",
title: info.videoDetails?.media?.song || info.videoDetails?.title || "",
imageSrc: thumbnails ? thumbnails[thumbnails.length - 1].url : ""
}
}

let videoName = "YouTube Music - Unknown title";
let videoReadableStream;
try {
Expand Down Expand Up @@ -135,6 +146,7 @@ const toMP3 = async (
ipcRenderer.send("add-metadata", filePath, fileBuffer, {
artist: metadata.artist,
title: metadata.title,
imageSrc: metadata.imageSrc
});
ipcRenderer.once("add-metadata-done", reinit);
} catch (e) {
Expand Down Expand Up @@ -165,22 +177,16 @@ module.exports = {

ipcRenderer.on(
"downloader-download-playlist",
(_, songMetadata, playlistFolder, options) => {
const reinit = () =>
ipcRenderer.send("downloader-feedback", defaultMenuDownloadLabel);

(_, url, playlistFolder, options) => {
downloadVideoToMP3(
songMetadata.url,
(feedback) => {
ipcRenderer.send("downloader-feedback", feedback);
},
url,
() => {},
(error) => {
triggerAction(CHANNEL, ACTIONS.ERROR, error);
reinit();
},
reinit,
() => {},
options,
songMetadata,
null,
playlistFolder
);
}
Expand Down
21 changes: 4 additions & 17 deletions plugins/last-fm/back.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,10 @@ const { setOptions } = require('../../config/plugins');
const getSongInfo = require('../../providers/song-info');
const defaultConfig = require('../../config/defaults');

const cleanupArtistName = (config, artist) => {
// removes the suffixes of the artist name for more recognition by last.fm
const { suffixesToRemove } = config;
if (suffixesToRemove === undefined) return artist;

for (suffix of suffixesToRemove) {
artist = artist.replace(suffix, '');
}
return artist;
}

const createFormData = params => {
// creates the body for in the post request
const formData = new URLSearchParams();
for (key in params) {
for (const key in params) {
formData.append(key, params[key]);
}
return formData;
Expand All @@ -28,7 +17,7 @@ const createQueryString = (params, api_sig) => {
// creates a querystring
const queryData = [];
params.api_sig = api_sig;
for (key in params) {
for (const key in params) {
queryData.push(`${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`);
}
return '?'+queryData.join('&');
Expand All @@ -37,12 +26,12 @@ const createQueryString = (params, api_sig) => {
const createApiSig = (params, secret) => {
// this function creates the api signature, see: https://www.last.fm/api/authspec
const keys = [];
for (key in params) {
for (const key in params) {
keys.push(key);
}
keys.sort();
let sig = '';
for (key of keys) {
for (const key of keys) {
if (String(key) === 'format')
continue
sig += `${key}${params[key]}`;
Expand Down Expand Up @@ -157,8 +146,6 @@ const lastfm = async (win, config) => {
registerCallback( songInfo => {
// set remove the old scrobble timer
clearTimeout(scrobbleTimer);
// make the artist name a bit cleaner
songInfo.artist = cleanupArtistName(config, songInfo.artist);
if (!songInfo.isPaused) {
setNowPlaying(songInfo, config);
// scrobble when the song is half way through, or has passed the 4 minute mark
Expand Down
3 changes: 2 additions & 1 deletion plugins/precise-volume/front.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,13 @@ function setupLocalArrowShortcuts(options) {
}

function callback(event) {
event.preventDefault();
switch (event.code) {
case "ArrowUp":
event.preventDefault();
changeVolume(true, options);
break;
case "ArrowDown":
event.preventDefault();
changeVolume(false, options);
break;
}
Expand Down
29 changes: 17 additions & 12 deletions plugins/precise-volume/preload.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
const { ipcRenderer } = require("electron");
const is = require("electron-is");

let ignored = {
id: ["volume-slider", "expand-volume-slider"],
types: ["mousewheel", "keydown", "keyup"]
};

// Override specific listeners of volume-slider by modifying Element.prototype
function overrideAddEventListener() {
// Events to ignore
const nativeEvents = ["mousewheel", "keydown", "keyup"];
// Save native addEventListener
Element.prototype._addEventListener = Element.prototype.addEventListener;
// Override addEventListener to Ignore specific events in volume-slider
Element.prototype.addEventListener = function (type, listener, useCapture = false) {
if (this.tagName === "TP-YT-PAPER-SLIDER") { // tagName of #volume-slider
for (const eventType of nativeEvents) {
if (eventType === type) {
return;
}
}
}//else
this._addEventListener(type, listener, useCapture);
if (!(
ignored.id.includes(this.id) &&
ignored.types.includes(type)
)) {
this._addEventListener(type, listener, useCapture);
} else if (is.dev()) {
console.log(`Ignoring event: "${this.id}.${type}()"`);
}
};
}

module.exports = () => {
overrideAddEventListener();
// Restore original function after did-finish-load to avoid keeping Element.prototype altered
ipcRenderer.once("restoreAddEventListener", () => { //called from Main to make sure page is completly loaded
ipcRenderer.once("restoreAddEventListener", () => { // Called from main to make sure page is completly loaded
Element.prototype.addEventListener = Element.prototype._addEventListener;
Element.prototype._addEventListener = undefined;
ignored = undefined;
});
};
2 changes: 1 addition & 1 deletion plugins/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ module.exports.fileExists = (path, callbackIfExists) => {
};

module.exports.injectCSS = (webContents, filepath, cb = undefined) => {
webContents.once("did-finish-load", async () => {
webContents.on("did-finish-load", async () => {
await webContents.insertCSS(fs.readFileSync(filepath, "utf8"));
if (cb) {
cb();
Expand Down
Loading

0 comments on commit 5418ef7

Please sign in to comment.