mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-11 18:41:47 +00:00
Merge pull request #252 from Araxeus/fix-download-idtag-if-not-playing
Fix downloader metadata if not currently playing
This commit is contained in:
@ -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 = {
|
||||
@ -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) {
|
||||
|
||||
@ -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,
|
||||
@ -61,7 +66,7 @@ global.download = () => {
|
||||
},
|
||||
reinit,
|
||||
pluginOptions,
|
||||
global.songInfo
|
||||
metadata
|
||||
);
|
||||
};
|
||||
// });
|
||||
|
||||
@ -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");
|
||||
@ -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) => {
|
||||
@ -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);
|
||||
@ -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
|
||||
);
|
||||
|
||||
@ -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({
|
||||
@ -24,7 +25,7 @@ const ffmpeg = createFFmpeg({
|
||||
});
|
||||
const ffmpegMutex = new Mutex();
|
||||
|
||||
const downloadVideoToMP3 = (
|
||||
const downloadVideoToMP3 = async (
|
||||
videoUrl,
|
||||
sendFeedback,
|
||||
sendError,
|
||||
@ -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 {
|
||||
@ -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) {
|
||||
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
@ -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('&');
|
||||
@ -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]}`;
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user