mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-11 18:41:47 +00:00
lint
This commit is contained in:
@ -1,15 +1,26 @@
|
|||||||
const { existsSync, mkdirSync, createWriteStream, writeFileSync } = require('fs');
|
const {
|
||||||
|
existsSync,
|
||||||
|
mkdirSync,
|
||||||
|
createWriteStream,
|
||||||
|
writeFileSync,
|
||||||
|
} = require("fs");
|
||||||
const { join } = require("path");
|
const { join } = require("path");
|
||||||
|
|
||||||
const { fetchFromGenius } = require("../lyrics-genius/back");
|
const { fetchFromGenius } = require("../lyrics-genius/back");
|
||||||
const { isEnabled } = require("../../config/plugins");
|
const { isEnabled } = require("../../config/plugins");
|
||||||
const { getImage } = require("../../providers/song-info");
|
const { getImage } = require("../../providers/song-info");
|
||||||
const { injectCSS } = require("../utils");
|
const { injectCSS } = require("../utils");
|
||||||
const { presets, cropMaxWidth, getFolder, setBadge, sendFeedback: sendFeedback_ } = require('./utils');
|
const {
|
||||||
|
presets,
|
||||||
|
cropMaxWidth,
|
||||||
|
getFolder,
|
||||||
|
setBadge,
|
||||||
|
sendFeedback: sendFeedback_,
|
||||||
|
} = require("./utils");
|
||||||
|
|
||||||
const { ipcMain, app, dialog } = require("electron");
|
const { ipcMain, app, dialog } = require("electron");
|
||||||
const is = require("electron-is");
|
const is = require("electron-is");
|
||||||
const { Innertube, UniversalCache, Utils } = require('youtubei.js');
|
const { Innertube, UniversalCache, Utils } = require("youtubei.js");
|
||||||
const ytpl = require("ytpl"); // REPLACE with youtubei getplaylist https://github.com/LuanRT/YouTube.js#getplaylistid
|
const ytpl = require("ytpl"); // REPLACE with youtubei getplaylist https://github.com/LuanRT/YouTube.js#getplaylistid
|
||||||
|
|
||||||
const filenamify = require("filenamify");
|
const filenamify = require("filenamify");
|
||||||
@ -27,8 +38,8 @@ const cache = {
|
|||||||
getCoverBuffer: {
|
getCoverBuffer: {
|
||||||
buffer: null,
|
buffer: null,
|
||||||
url: null,
|
url: null,
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
const config = require("./config");
|
const config = require("./config");
|
||||||
|
|
||||||
@ -42,7 +53,6 @@ const sendError = (error) => {
|
|||||||
setBadge(0); // close badge
|
setBadge(0); // close badge
|
||||||
sendFeedback_(win); // reset feedback
|
sendFeedback_(win); // reset feedback
|
||||||
|
|
||||||
|
|
||||||
console.error(error);
|
console.error(error);
|
||||||
dialog.showMessageBox({
|
dialog.showMessageBox({
|
||||||
type: "info",
|
type: "info",
|
||||||
@ -58,17 +68,28 @@ module.exports = async (win_, options) => {
|
|||||||
config.init(options);
|
config.init(options);
|
||||||
injectCSS(win.webContents, join(__dirname, "style.css"));
|
injectCSS(win.webContents, join(__dirname, "style.css"));
|
||||||
|
|
||||||
yt = await Innertube.create({ cache: new UniversalCache(false), generate_session_locally: true });
|
yt = await Innertube.create({
|
||||||
|
cache: new UniversalCache(false),
|
||||||
|
generate_session_locally: true,
|
||||||
|
});
|
||||||
ipcMain.on("download-song", (_, url) => downloadSong(url));
|
ipcMain.on("download-song", (_, url) => downloadSong(url));
|
||||||
ipcMain.on("video-src-changed", async (_, data) => {
|
ipcMain.on("video-src-changed", async (_, data) => {
|
||||||
playingUrl = JSON.parse(data)?.microformat?.microformatDataRenderer?.urlCanonical;
|
playingUrl =
|
||||||
|
JSON.parse(data)?.microformat?.microformatDataRenderer?.urlCanonical;
|
||||||
});
|
});
|
||||||
ipcMain.on("download-playlist-request", async (_event, url) => downloadPlaylist(url));
|
ipcMain.on("download-playlist-request", async (_event, url) =>
|
||||||
|
downloadPlaylist(url),
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.downloadSong = downloadSong;
|
module.exports.downloadSong = downloadSong;
|
||||||
|
|
||||||
async function downloadSong(url, playlistFolder = undefined, trackId = undefined, increasePlaylistProgress = () => { }) {
|
async function downloadSong(
|
||||||
|
url,
|
||||||
|
playlistFolder = undefined,
|
||||||
|
trackId = undefined,
|
||||||
|
increasePlaylistProgress = () => {},
|
||||||
|
) {
|
||||||
const sendFeedback = (message, progress) => {
|
const sendFeedback = (message, progress) => {
|
||||||
if (!playlistFolder) {
|
if (!playlistFolder) {
|
||||||
sendFeedback_(win, message);
|
sendFeedback_(win, message);
|
||||||
@ -78,19 +99,22 @@ async function downloadSong(url, playlistFolder = undefined, trackId = undefined
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
sendFeedback(`Downloading...`, 2);
|
sendFeedback("Downloading...", 2);
|
||||||
|
|
||||||
const id = getVideoId(url);
|
const id = getVideoId(url);
|
||||||
const info = await yt.music.getInfo(id);
|
const info = await yt.music.getInfo(id);
|
||||||
|
|
||||||
const metadata = getMetadata(info);
|
const metadata = getMetadata(info);
|
||||||
if (metadata.album === 'N/A') metadata.album = '';
|
if (metadata.album === "N/A") metadata.album = "";
|
||||||
metadata.trackId = trackId;
|
metadata.trackId = trackId;
|
||||||
|
|
||||||
const dir = playlistFolder || config.get('downloadFolder') || app.getPath("downloads");
|
const dir =
|
||||||
const name = `${metadata.artist ? `${metadata.artist} - ` : ""}${metadata.title}`;
|
playlistFolder || config.get("downloadFolder") || app.getPath("downloads");
|
||||||
|
const name = `${metadata.artist ? `${metadata.artist} - ` : ""}${
|
||||||
|
metadata.title
|
||||||
|
}`;
|
||||||
|
|
||||||
const extension = presets[config.get('preset')]?.extension || 'mp3';
|
const extension = presets[config.get("preset")]?.extension || "mp3";
|
||||||
|
|
||||||
const filename = filenamify(`${name}.${extension}`, {
|
const filename = filenamify(`${name}.${extension}`, {
|
||||||
replacement: "_",
|
replacement: "_",
|
||||||
@ -98,21 +122,23 @@ async function downloadSong(url, playlistFolder = undefined, trackId = undefined
|
|||||||
});
|
});
|
||||||
const filePath = join(dir, filename);
|
const filePath = join(dir, filename);
|
||||||
|
|
||||||
if (config.get('skipExisting') && existsSync(filePath)) {
|
if (config.get("skipExisting") && existsSync(filePath)) {
|
||||||
sendFeedback(null, -1);
|
sendFeedback(null, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const download_options = {
|
const download_options = {
|
||||||
type: 'audio', // audio, video or video+audio
|
type: "audio", // audio, video or video+audio
|
||||||
quality: 'best', // best, bestefficiency, 144p, 240p, 480p, 720p and so on.
|
quality: "best", // best, bestefficiency, 144p, 240p, 480p, 720p and so on.
|
||||||
format: 'any' // media container format
|
format: "any", // media container format
|
||||||
};
|
};
|
||||||
|
|
||||||
const format = info.chooseFormat(download_options);
|
const format = info.chooseFormat(download_options);
|
||||||
const stream = await info.download(download_options);
|
const stream = await info.download(download_options);
|
||||||
|
|
||||||
console.info(`Downloading ${metadata.artist} - ${metadata.title} [${metadata.id}]`);
|
console.info(
|
||||||
|
`Downloading ${metadata.artist} - ${metadata.title} [${metadata.id}]`,
|
||||||
|
);
|
||||||
|
|
||||||
const iterableStream = Utils.streamToIterable(stream);
|
const iterableStream = Utils.streamToIterable(stream);
|
||||||
|
|
||||||
@ -120,23 +146,33 @@ async function downloadSong(url, playlistFolder = undefined, trackId = undefined
|
|||||||
mkdirSync(dir);
|
mkdirSync(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!presets[config.get('preset')]) {
|
if (!presets[config.get("preset")]) {
|
||||||
const fileBuffer = await iterableStreamToMP3(iterableStream, metadata, format.content_length, sendFeedback, increasePlaylistProgress);
|
const fileBuffer = await iterableStreamToMP3(
|
||||||
|
iterableStream,
|
||||||
|
metadata,
|
||||||
|
format.content_length,
|
||||||
|
sendFeedback,
|
||||||
|
increasePlaylistProgress,
|
||||||
|
);
|
||||||
writeFileSync(filePath, await writeID3(fileBuffer, metadata, sendFeedback));
|
writeFileSync(filePath, await writeID3(fileBuffer, metadata, sendFeedback));
|
||||||
} else {
|
} else {
|
||||||
const file = createWriteStream(filePath);
|
const file = createWriteStream(filePath);
|
||||||
let downloaded = 0;
|
let downloaded = 0;
|
||||||
let total = format.content_length;
|
const total = format.content_length;
|
||||||
|
|
||||||
for await (const chunk of iterableStream) {
|
for await (const chunk of iterableStream) {
|
||||||
downloaded += chunk.length;
|
downloaded += chunk.length;
|
||||||
const ratio = downloaded / total;
|
const ratio = downloaded / total;
|
||||||
const progress = Math.floor(ratio * 100);
|
const progress = Math.floor(ratio * 100);
|
||||||
sendFeedback("Download: " + progress + "%", ratio);
|
sendFeedback(`Download: ${progress}%`, ratio);
|
||||||
increasePlaylistProgress(ratio);
|
increasePlaylistProgress(ratio);
|
||||||
file.write(chunk);
|
file.write(chunk);
|
||||||
}
|
}
|
||||||
await ffmpegWriteTags(filePath, metadata, presets[config.get('preset')]?.ffmpegArgs);
|
await ffmpegWriteTags(
|
||||||
|
filePath,
|
||||||
|
metadata,
|
||||||
|
presets[config.get("preset")]?.ffmpegArgs,
|
||||||
|
);
|
||||||
sendFeedback(null, -1);
|
sendFeedback(null, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,16 +180,22 @@ async function downloadSong(url, playlistFolder = undefined, trackId = undefined
|
|||||||
console.info(`Done: "${filePath}"`);
|
console.info(`Done: "${filePath}"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function iterableStreamToMP3(stream, metadata, content_length, sendFeedback, increasePlaylistProgress = () => { }) {
|
async function iterableStreamToMP3(
|
||||||
|
stream,
|
||||||
|
metadata,
|
||||||
|
content_length,
|
||||||
|
sendFeedback,
|
||||||
|
increasePlaylistProgress = () => {},
|
||||||
|
) {
|
||||||
const chunks = [];
|
const chunks = [];
|
||||||
let downloaded = 0;
|
let downloaded = 0;
|
||||||
let total = content_length;
|
const total = content_length;
|
||||||
for await (const chunk of stream) {
|
for await (const chunk of stream) {
|
||||||
downloaded += chunk.length;
|
downloaded += chunk.length;
|
||||||
chunks.push(chunk);
|
chunks.push(chunk);
|
||||||
const ratio = downloaded / total;
|
const ratio = downloaded / total;
|
||||||
const progress = Math.floor(ratio * 100);
|
const progress = Math.floor(ratio * 100);
|
||||||
sendFeedback("Download: " + progress + "%", ratio);
|
sendFeedback(`Download: ${progress}%`, ratio);
|
||||||
// 15% for download, 85% for conversion
|
// 15% for download, 85% for conversion
|
||||||
// This is a very rough estimate, trying to make the progress bar look nice
|
// This is a very rough estimate, trying to make the progress bar look nice
|
||||||
increasePlaylistProgress(ratio * 0.15);
|
increasePlaylistProgress(ratio * 0.15);
|
||||||
@ -175,7 +217,7 @@ async function iterableStreamToMP3(stream, metadata, content_length, sendFeedbac
|
|||||||
sendFeedback("Converting…");
|
sendFeedback("Converting…");
|
||||||
|
|
||||||
ffmpeg.setProgress(({ ratio }) => {
|
ffmpeg.setProgress(({ ratio }) => {
|
||||||
sendFeedback("Converting: " + Math.floor(ratio * 100) + "%", ratio);
|
sendFeedback(`Converting: ${Math.floor(ratio * 100)}%`, ratio);
|
||||||
increasePlaylistProgress(0.15 + ratio * 0.85);
|
increasePlaylistProgress(0.15 + ratio * 0.85);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -183,12 +225,12 @@ async function iterableStreamToMP3(stream, metadata, content_length, sendFeedbac
|
|||||||
"-i",
|
"-i",
|
||||||
safeVideoName,
|
safeVideoName,
|
||||||
...getFFmpegMetadataArgs(metadata),
|
...getFFmpegMetadataArgs(metadata),
|
||||||
safeVideoName + ".mp3"
|
`${safeVideoName}.mp3`,
|
||||||
);
|
);
|
||||||
|
|
||||||
sendFeedback("Saving…");
|
sendFeedback("Saving…");
|
||||||
|
|
||||||
return ffmpeg.FS("readFile", safeVideoName + ".mp3");
|
return ffmpeg.FS("readFile", `${safeVideoName}.mp3`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
sendError(e);
|
sendError(e);
|
||||||
} finally {
|
} finally {
|
||||||
@ -204,8 +246,8 @@ async function getCoverBuffer(url) {
|
|||||||
store.url = url;
|
store.url = url;
|
||||||
|
|
||||||
const nativeImage = cropMaxWidth(await getImage(url));
|
const nativeImage = cropMaxWidth(await getImage(url));
|
||||||
store.buffer = nativeImage && !nativeImage.isEmpty() ?
|
store.buffer =
|
||||||
nativeImage.toPNG() : null;
|
nativeImage && !nativeImage.isEmpty() ? nativeImage.toPNG() : null;
|
||||||
|
|
||||||
return store.buffer;
|
return store.buffer;
|
||||||
}
|
}
|
||||||
@ -219,9 +261,7 @@ async function writeID3(buffer, metadata, sendFeedback) {
|
|||||||
const writer = new ID3Writer(buffer);
|
const writer = new ID3Writer(buffer);
|
||||||
|
|
||||||
// Create the metadata tags
|
// Create the metadata tags
|
||||||
writer
|
writer.setFrame("TIT2", metadata.title).setFrame("TPE1", [metadata.artist]);
|
||||||
.setFrame("TIT2", metadata.title)
|
|
||||||
.setFrame("TPE1", [metadata.artist]);
|
|
||||||
if (metadata.album) {
|
if (metadata.album) {
|
||||||
writer.setFrame("TALB", metadata.album);
|
writer.setFrame("TALB", metadata.album);
|
||||||
}
|
}
|
||||||
@ -236,7 +276,7 @@ async function writeID3(buffer, metadata, sendFeedback) {
|
|||||||
const lyrics = await fetchFromGenius(metadata);
|
const lyrics = await fetchFromGenius(metadata);
|
||||||
if (lyrics) {
|
if (lyrics) {
|
||||||
writer.setFrame("USLT", {
|
writer.setFrame("USLT", {
|
||||||
description: '',
|
description: "",
|
||||||
lyrics: lyrics,
|
lyrics: lyrics,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -257,28 +297,31 @@ async function downloadPlaylist(givenUrl) {
|
|||||||
givenUrl = new URL(givenUrl);
|
givenUrl = new URL(givenUrl);
|
||||||
} catch {
|
} catch {
|
||||||
givenUrl = undefined;
|
givenUrl = undefined;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
const playlistId = getPlaylistID(givenUrl)
|
}
|
||||||
|| getPlaylistID(new URL(win.webContents.getURL()))
|
const playlistId =
|
||||||
|| getPlaylistID(new URL(playingUrl));
|
getPlaylistID(givenUrl) ||
|
||||||
|
getPlaylistID(new URL(win.webContents.getURL())) ||
|
||||||
|
getPlaylistID(new URL(playingUrl));
|
||||||
|
|
||||||
if (!playlistId) {
|
if (!playlistId) {
|
||||||
sendError(new Error("No playlist ID found"));
|
sendError(new Error("No playlist ID found"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sendFeedback = message => sendFeedback_(win, message);
|
const sendFeedback = (message) => sendFeedback_(win, message);
|
||||||
|
|
||||||
console.log(`trying to get playlist ID: '${playlistId}'`);
|
console.log(`trying to get playlist ID: '${playlistId}'`);
|
||||||
sendFeedback("Getting playlist info…");
|
sendFeedback("Getting playlist info…");
|
||||||
let playlist;
|
let playlist;
|
||||||
try {
|
try {
|
||||||
playlist = await ytpl(playlistId, {
|
playlist = await ytpl(playlistId, {
|
||||||
limit: config.get('playlistMaxItems') || Infinity,
|
limit: config.get("playlistMaxItems") || Infinity,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
sendError("Error getting playlist info: make sure it isn't a private or \"Mixed for you\" playlist\n\n" + e);
|
sendError(
|
||||||
|
`Error getting playlist info: make sure it isn\'t a private or "Mixed for you" playlist\n\n${e}`,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (playlist.items.length === 0) sendError(new Error("Playlist is empty"));
|
if (playlist.items.length === 0) sendError(new Error("Playlist is empty"));
|
||||||
@ -287,16 +330,16 @@ async function downloadPlaylist(givenUrl) {
|
|||||||
await downloadSong(playlist.items[0].url);
|
await downloadSong(playlist.items[0].url);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let isAlbum = playlist.title.startsWith('Album - ');
|
const isAlbum = playlist.title.startsWith("Album - ");
|
||||||
if (isAlbum) {
|
if (isAlbum) {
|
||||||
playlist.title = playlist.title.slice(8);
|
playlist.title = playlist.title.slice(8);
|
||||||
}
|
}
|
||||||
const safePlaylistTitle = filenamify(playlist.title, { replacement: ' ' });
|
const safePlaylistTitle = filenamify(playlist.title, { replacement: " " });
|
||||||
|
|
||||||
const folder = getFolder(config.get('downloadFolder'));
|
const folder = getFolder(config.get("downloadFolder"));
|
||||||
const playlistFolder = join(folder, safePlaylistTitle);
|
const playlistFolder = join(folder, safePlaylistTitle);
|
||||||
if (existsSync(playlistFolder)) {
|
if (existsSync(playlistFolder)) {
|
||||||
if (!config.get('skipExisting')) {
|
if (!config.get("skipExisting")) {
|
||||||
sendError(new Error(`The folder ${playlistFolder} already exists`));
|
sendError(new Error(`The folder ${playlistFolder} already exists`));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -314,7 +357,7 @@ async function downloadPlaylist(givenUrl) {
|
|||||||
|
|
||||||
if (is.dev()) {
|
if (is.dev()) {
|
||||||
console.log(
|
console.log(
|
||||||
`Downloading playlist "${playlist.title}" - ${playlist.items.length} songs (${playlistId})`
|
`Downloading playlist "${playlist.title}" - ${playlist.items.length} songs (${playlistId})`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,7 +371,7 @@ async function downloadPlaylist(givenUrl) {
|
|||||||
|
|
||||||
const increaseProgress = (itemPercentage) => {
|
const increaseProgress = (itemPercentage) => {
|
||||||
const currentProgress = (counter - 1) / playlist.items.length;
|
const currentProgress = (counter - 1) / playlist.items.length;
|
||||||
const newProgress = currentProgress + (progressStep * itemPercentage);
|
const newProgress = currentProgress + progressStep * itemPercentage;
|
||||||
win.setProgressBar(newProgress);
|
win.setProgressBar(newProgress);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -336,8 +379,16 @@ async function downloadPlaylist(givenUrl) {
|
|||||||
for (const song of playlist.items) {
|
for (const song of playlist.items) {
|
||||||
sendFeedback(`Downloading ${counter}/${playlist.items.length}...`);
|
sendFeedback(`Downloading ${counter}/${playlist.items.length}...`);
|
||||||
const trackId = isAlbum ? counter : undefined;
|
const trackId = isAlbum ? counter : undefined;
|
||||||
await downloadSong(song.url, playlistFolder, trackId, increaseProgress)
|
await downloadSong(
|
||||||
.catch((e) => sendError(`Error downloading "${song.author.name} - ${song.title}":\n ${e}`));
|
song.url,
|
||||||
|
playlistFolder,
|
||||||
|
trackId,
|
||||||
|
increaseProgress,
|
||||||
|
).catch((e) =>
|
||||||
|
sendError(
|
||||||
|
`Error downloading "${song.author.name} - ${song.title}":\n ${e}`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
win.setProgressBar(counter / playlist.items.length);
|
win.setProgressBar(counter / playlist.items.length);
|
||||||
setBadge(playlist.items.length - counter);
|
setBadge(playlist.items.length - counter);
|
||||||
@ -365,7 +416,7 @@ async function ffmpegWriteTags(filePath, metadata, ffmpegArgs = []) {
|
|||||||
filePath,
|
filePath,
|
||||||
...getFFmpegMetadataArgs(metadata),
|
...getFFmpegMetadataArgs(metadata),
|
||||||
...ffmpegArgs,
|
...ffmpegArgs,
|
||||||
filePath
|
filePath,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
sendError(e);
|
sendError(e);
|
||||||
@ -385,25 +436,26 @@ function getFFmpegMetadataArgs(metadata) {
|
|||||||
...(metadata.album ? ["-metadata", `album=${metadata.album}`] : []),
|
...(metadata.album ? ["-metadata", `album=${metadata.album}`] : []),
|
||||||
...(metadata.trackId ? ["-metadata", `track=${metadata.trackId}`] : []),
|
...(metadata.trackId ? ["-metadata", `track=${metadata.trackId}`] : []),
|
||||||
];
|
];
|
||||||
};
|
}
|
||||||
|
|
||||||
// Playlist radio modifier needs to be cut from playlist ID
|
// Playlist radio modifier needs to be cut from playlist ID
|
||||||
const INVALID_PLAYLIST_MODIFIER = 'RDAMPL';
|
const INVALID_PLAYLIST_MODIFIER = "RDAMPL";
|
||||||
|
|
||||||
const getPlaylistID = aURL => {
|
const getPlaylistID = (aURL) => {
|
||||||
const result = aURL?.searchParams.get("list") || aURL?.searchParams.get("playlist");
|
const result =
|
||||||
|
aURL?.searchParams.get("list") || aURL?.searchParams.get("playlist");
|
||||||
if (result?.startsWith(INVALID_PLAYLIST_MODIFIER)) {
|
if (result?.startsWith(INVALID_PLAYLIST_MODIFIER)) {
|
||||||
return result.slice(6)
|
return result.slice(6);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getVideoId = url => {
|
const getVideoId = (url) => {
|
||||||
if (typeof url === "string") {
|
if (typeof url === "string") {
|
||||||
url = new URL(url);
|
url = new URL(url);
|
||||||
}
|
}
|
||||||
return url.searchParams.get("v");
|
return url.searchParams.get("v");
|
||||||
}
|
};
|
||||||
|
|
||||||
const getMetadata = (info) => ({
|
const getMetadata = (info) => ({
|
||||||
id: info.basic_info.id,
|
id: info.basic_info.id,
|
||||||
|
|||||||
@ -4,20 +4,18 @@ const { downloadPlaylist } = require("./back");
|
|||||||
const { defaultMenuDownloadLabel, getFolder, presets } = require("./utils");
|
const { defaultMenuDownloadLabel, getFolder, presets } = require("./utils");
|
||||||
const config = require("./config");
|
const config = require("./config");
|
||||||
|
|
||||||
let downloadLabel = defaultMenuDownloadLabel;
|
|
||||||
|
|
||||||
module.exports = () => {
|
module.exports = () => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
label: downloadLabel,
|
label: defaultMenuDownloadLabel,
|
||||||
click: () => downloadPlaylist(),
|
click: () => downloadPlaylist(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Choose download folder",
|
label: "Choose download folder",
|
||||||
click: () => {
|
click: () => {
|
||||||
let result = dialog.showOpenDialogSync({
|
const result = dialog.showOpenDialogSync({
|
||||||
properties: ["openDirectory", "createDirectory"],
|
properties: ["openDirectory", "createDirectory"],
|
||||||
defaultPath: getFolder(config.get('downloadFolder')),
|
defaultPath: getFolder(config.get("downloadFolder")),
|
||||||
});
|
});
|
||||||
if (result) {
|
if (result) {
|
||||||
config.set("downloadFolder", result[0]);
|
config.set("downloadFolder", result[0]);
|
||||||
@ -29,7 +27,7 @@ module.exports = () => {
|
|||||||
submenu: Object.keys(presets).map((preset) => ({
|
submenu: Object.keys(presets).map((preset) => ({
|
||||||
label: preset,
|
label: preset,
|
||||||
type: "radio",
|
type: "radio",
|
||||||
checked: config.get('preset') === preset,
|
checked: config.get("preset") === preset,
|
||||||
click: () => {
|
click: () => {
|
||||||
config.set("preset", preset);
|
config.set("preset", preset);
|
||||||
},
|
},
|
||||||
@ -38,10 +36,10 @@ module.exports = () => {
|
|||||||
{
|
{
|
||||||
label: "Skip existing files",
|
label: "Skip existing files",
|
||||||
type: "checkbox",
|
type: "checkbox",
|
||||||
checked: config.get('skipExisting'),
|
checked: config.get("skipExisting"),
|
||||||
click: (item) => {
|
click: (item) => {
|
||||||
config.set("skipExisting", item.checked);
|
config.set("skipExisting", item.checked);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user