mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-10 18:21:47 +00:00
allow downloading playlists from popup menu
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
const { contextBridge } = require("electron");
|
||||
const { ipcRenderer } = require("electron");
|
||||
|
||||
const { defaultConfig } = require("../../config");
|
||||
const { getSongMenu } = require("../../providers/dom-elements");
|
||||
@ -13,15 +13,17 @@ const downloadButton = ElementFromFile(
|
||||
);
|
||||
let pluginOptions = {};
|
||||
|
||||
const observer = new MutationObserver((mutations, observer) => {
|
||||
const observer = new MutationObserver(() => {
|
||||
if (!menu) {
|
||||
menu = getSongMenu();
|
||||
if (!menu) return;
|
||||
}
|
||||
if (menu.contains(downloadButton)) return;
|
||||
const menuUrl = document.querySelector('tp-yt-paper-listbox [tabindex="0"] #navigation-endpoint')?.href;
|
||||
if (menuUrl && !menuUrl.includes('watch?')) return;
|
||||
|
||||
if (menu && !menu.contains(downloadButton)) {
|
||||
menu.prepend(downloadButton);
|
||||
progress = document.querySelector("#ytmcustom-download");
|
||||
}
|
||||
});
|
||||
|
||||
const reinit = () => {
|
||||
@ -46,7 +48,13 @@ global.download = () => {
|
||||
?.querySelector('ytmusic-menu-navigation-item-renderer.iron-selected[tabindex="0"] #navigation-endpoint')
|
||||
?.getAttribute("href");
|
||||
if (videoUrl) {
|
||||
if (videoUrl.startsWith('watch?')) {
|
||||
videoUrl = baseUrl + "/" + videoUrl;
|
||||
}
|
||||
if (videoUrl.includes('?playlist=')) {
|
||||
ipcRenderer.send('download-playlist-request', videoUrl);
|
||||
return;
|
||||
}
|
||||
metadata = null;
|
||||
} else {
|
||||
metadata = global.songInfo;
|
||||
@ -78,10 +86,13 @@ global.download = () => {
|
||||
|
||||
function observeMenu(options) {
|
||||
pluginOptions = { ...pluginOptions, ...options };
|
||||
observer.observe(document, {
|
||||
|
||||
document.addEventListener('apiLoaded', () => {
|
||||
observer.observe(document.querySelector('ytmusic-popup-container'), {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}, { once: true, passive: true })
|
||||
}
|
||||
|
||||
module.exports = observeMenu;
|
||||
|
||||
@ -14,20 +14,66 @@ let downloadLabel = defaultMenuDownloadLabel;
|
||||
let playingPlaylistId = undefined;
|
||||
let callbackIsRegistered = false;
|
||||
|
||||
const INVALID_PLAYLIST_MODIFIER = 'RDAMPLPL';
|
||||
|
||||
module.exports = (win, options) => {
|
||||
if (!callbackIsRegistered) {
|
||||
ipcMain.on("video-src-changed", async (_, data) => {
|
||||
playingPlaylistId = JSON.parse(data)?.videoDetails?.playlistId;
|
||||
});
|
||||
ipcMain.on("download-playlist-request", async (_event, url) => downloadPlaylist(url, win, options));
|
||||
callbackIsRegistered = true;
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
label: downloadLabel,
|
||||
click: async () => {
|
||||
const currentPagePlaylistId = new URL(win.webContents.getURL()).searchParams.get("list");
|
||||
const playlistId = currentPagePlaylistId || playingPlaylistId;
|
||||
click: () => downloadPlaylist(undefined, win, options)
|
||||
},
|
||||
{
|
||||
label: "Choose download folder",
|
||||
click: () => {
|
||||
let result = dialog.showOpenDialogSync({
|
||||
properties: ["openDirectory", "createDirectory"],
|
||||
defaultPath: getFolder(options.downloadFolder),
|
||||
});
|
||||
if (result) {
|
||||
options.downloadFolder = result[0];
|
||||
setOptions("downloader", options);
|
||||
} // else = user pressed cancel
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Presets",
|
||||
submenu: Object.keys(presets).map((preset) => ({
|
||||
label: preset,
|
||||
type: "radio",
|
||||
click: () => {
|
||||
options.preset = preset;
|
||||
setOptions("downloader", options);
|
||||
},
|
||||
checked: options.preset === preset || presets[preset] === undefined,
|
||||
})),
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
async function downloadPlaylist(url, win, options) {
|
||||
const getPlaylistID = aURL => {
|
||||
const result = aURL?.searchParams.get("list") || aURL?.searchParams.get("playlist");
|
||||
return (!result || result.startsWith(INVALID_PLAYLIST_MODIFIER)) ? undefined : result;
|
||||
};
|
||||
if (url) {
|
||||
try {
|
||||
url = new URL(url);
|
||||
} catch {
|
||||
url = undefined;
|
||||
};
|
||||
}
|
||||
const playlistId = getPlaylistID(url)
|
||||
|| getPlaylistID(new URL(win.webContents.getURL()))
|
||||
|| playingPlaylistId;
|
||||
|
||||
if (!playlistId) {
|
||||
sendError(win, new Error("No playlist ID found"));
|
||||
return;
|
||||
@ -66,7 +112,7 @@ module.exports = (win, options) => {
|
||||
|
||||
if (is.dev()) {
|
||||
console.log(
|
||||
`Downloading playlist "${playlistTitle}" (${playlist.items.length} songs)`
|
||||
`Downloading playlist "${playlistTitle}" - ${playlist.items.length} songs (${playlistId})`
|
||||
);
|
||||
}
|
||||
|
||||
@ -94,32 +140,4 @@ module.exports = (win, options) => {
|
||||
options
|
||||
);
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Choose download folder",
|
||||
click: () => {
|
||||
let result = dialog.showOpenDialogSync({
|
||||
properties: ["openDirectory", "createDirectory"],
|
||||
defaultPath: getFolder(options.downloadFolder),
|
||||
});
|
||||
if (result) {
|
||||
options.downloadFolder = result[0];
|
||||
setOptions("downloader", options);
|
||||
} // else = user pressed cancel
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Presets",
|
||||
submenu: Object.keys(presets).map((preset) => ({
|
||||
label: preset,
|
||||
type: "radio",
|
||||
click: () => {
|
||||
options.preset = preset;
|
||||
setOptions("downloader", options);
|
||||
},
|
||||
checked: options.preset === preset || presets[preset] === undefined,
|
||||
})),
|
||||
},
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user