From b652a011a5a08978db6660aeca6908c47a7cf07a Mon Sep 17 00:00:00 2001 From: Araxeus <78568641+Araxeus@users.noreply.github.com> Date: Sun, 12 Mar 2023 20:00:10 +0200 Subject: [PATCH] lint --- plugins/downloader/back.js | 674 ++++++++++++++++++++----------------- plugins/downloader/menu.js | 16 +- 2 files changed, 370 insertions(+), 320 deletions(-) diff --git a/plugins/downloader/back.js b/plugins/downloader/back.js index 044ba3f9..94920e85 100644 --- a/plugins/downloader/back.js +++ b/plugins/downloader/back.js @@ -1,15 +1,26 @@ -const { existsSync, mkdirSync, createWriteStream, writeFileSync } = require('fs'); +const { + existsSync, + mkdirSync, + createWriteStream, + writeFileSync, +} = require("fs"); const { join } = require("path"); const { fetchFromGenius } = require("../lyrics-genius/back"); const { isEnabled } = require("../../config/plugins"); const { getImage } = require("../../providers/song-info"); 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 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 filenamify = require("filenamify"); @@ -17,18 +28,18 @@ const ID3Writer = require("browser-id3-writer"); const { randomBytes } = require("crypto"); const Mutex = require("async-mutex").Mutex; const ffmpeg = require("@ffmpeg/ffmpeg").createFFmpeg({ - log: false, - logger: () => { }, // console.log, - progress: () => { }, // console.log, + log: false, + logger: () => {}, // console.log, + progress: () => {}, // console.log, }); const ffmpegMutex = new Mutex(); const cache = { - getCoverBuffer: { - buffer: null, - url: null, - } -} + getCoverBuffer: { + buffer: null, + url: null, + }, +}; const config = require("./config"); @@ -38,377 +49,418 @@ let win; let playingUrl = undefined; const sendError = (error) => { - win.setProgressBar(-1); // close progress bar - setBadge(0); // close badge - sendFeedback_(win); // reset feedback + win.setProgressBar(-1); // close progress bar + setBadge(0); // close badge + sendFeedback_(win); // reset feedback - - console.error(error); - dialog.showMessageBox({ - type: "info", - buttons: ["OK"], - title: "Error in download!", - message: "Argh! Apologies, download failed…", - detail: error.toString(), - }); + console.error(error); + dialog.showMessageBox({ + type: "info", + buttons: ["OK"], + title: "Error in download!", + message: "Argh! Apologies, download failed…", + detail: error.toString(), + }); }; module.exports = async (win_, options) => { - win = win_; - config.init(options); - injectCSS(win.webContents, join(__dirname, "style.css")); + win = win_; + config.init(options); + injectCSS(win.webContents, join(__dirname, "style.css")); - yt = await Innertube.create({ cache: new UniversalCache(false), generate_session_locally: true }); - ipcMain.on("download-song", (_, url) => downloadSong(url)); - ipcMain.on("video-src-changed", async (_, data) => { - playingUrl = JSON.parse(data)?.microformat?.microformatDataRenderer?.urlCanonical; - }); - ipcMain.on("download-playlist-request", async (_event, url) => downloadPlaylist(url)); + yt = await Innertube.create({ + cache: new UniversalCache(false), + generate_session_locally: true, + }); + ipcMain.on("download-song", (_, url) => downloadSong(url)); + ipcMain.on("video-src-changed", async (_, data) => { + playingUrl = + JSON.parse(data)?.microformat?.microformatDataRenderer?.urlCanonical; + }); + ipcMain.on("download-playlist-request", async (_event, url) => + downloadPlaylist(url), + ); }; module.exports.downloadSong = downloadSong; -async function downloadSong(url, playlistFolder = undefined, trackId = undefined, increasePlaylistProgress = () => { }) { - const sendFeedback = (message, progress) => { - if (!playlistFolder) { - sendFeedback_(win, message); - if (!isNaN(progress)) { - win.setProgressBar(progress); - } - } - }; +async function downloadSong( + url, + playlistFolder = undefined, + trackId = undefined, + increasePlaylistProgress = () => {}, +) { + const sendFeedback = (message, progress) => { + if (!playlistFolder) { + sendFeedback_(win, message); + if (!isNaN(progress)) { + win.setProgressBar(progress); + } + } + }; - sendFeedback(`Downloading...`, 2); + sendFeedback("Downloading...", 2); - const id = getVideoId(url); - const info = await yt.music.getInfo(id); + const id = getVideoId(url); + const info = await yt.music.getInfo(id); - const metadata = getMetadata(info); - if (metadata.album === 'N/A') metadata.album = ''; - metadata.trackId = trackId; + const metadata = getMetadata(info); + if (metadata.album === "N/A") metadata.album = ""; + metadata.trackId = trackId; - const dir = playlistFolder || config.get('downloadFolder') || app.getPath("downloads"); - const name = `${metadata.artist ? `${metadata.artist} - ` : ""}${metadata.title}`; + const dir = + 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}`, { - replacement: "_", - maxLength: 255, - }); - const filePath = join(dir, filename); + const filename = filenamify(`${name}.${extension}`, { + replacement: "_", + maxLength: 255, + }); + const filePath = join(dir, filename); - if (config.get('skipExisting') && existsSync(filePath)) { - sendFeedback(null, -1); - return; - } + if (config.get("skipExisting") && existsSync(filePath)) { + sendFeedback(null, -1); + return; + } - const download_options = { - type: 'audio', // audio, video or video+audio - quality: 'best', // best, bestefficiency, 144p, 240p, 480p, 720p and so on. - format: 'any' // media container format - }; + const download_options = { + type: "audio", // audio, video or video+audio + quality: "best", // best, bestefficiency, 144p, 240p, 480p, 720p and so on. + format: "any", // media container format + }; - const format = info.chooseFormat(download_options); - const stream = await info.download(download_options); + const format = info.chooseFormat(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); - if (!existsSync(dir)) { - mkdirSync(dir); - } + if (!existsSync(dir)) { + mkdirSync(dir); + } - if (!presets[config.get('preset')]) { - const fileBuffer = await iterableStreamToMP3(iterableStream, metadata, format.content_length, sendFeedback, increasePlaylistProgress); - writeFileSync(filePath, await writeID3(fileBuffer, metadata, sendFeedback)); - } else { - const file = createWriteStream(filePath); - let downloaded = 0; - let total = format.content_length; + if (!presets[config.get("preset")]) { + const fileBuffer = await iterableStreamToMP3( + iterableStream, + metadata, + format.content_length, + sendFeedback, + increasePlaylistProgress, + ); + writeFileSync(filePath, await writeID3(fileBuffer, metadata, sendFeedback)); + } else { + const file = createWriteStream(filePath); + let downloaded = 0; + const total = format.content_length; - for await (const chunk of iterableStream) { - downloaded += chunk.length; - const ratio = downloaded / total; - const progress = Math.floor(ratio * 100); - sendFeedback("Download: " + progress + "%", ratio); - increasePlaylistProgress(ratio); - file.write(chunk); - } - await ffmpegWriteTags(filePath, metadata, presets[config.get('preset')]?.ffmpegArgs); - sendFeedback(null, -1); - } + for await (const chunk of iterableStream) { + downloaded += chunk.length; + const ratio = downloaded / total; + const progress = Math.floor(ratio * 100); + sendFeedback(`Download: ${progress}%`, ratio); + increasePlaylistProgress(ratio); + file.write(chunk); + } + await ffmpegWriteTags( + filePath, + metadata, + presets[config.get("preset")]?.ffmpegArgs, + ); + sendFeedback(null, -1); + } - sendFeedback(null, -1); - console.info(`Done: "${filePath}"`); + sendFeedback(null, -1); + console.info(`Done: "${filePath}"`); } -async function iterableStreamToMP3(stream, metadata, content_length, sendFeedback, increasePlaylistProgress = () => { }) { - const chunks = []; - let downloaded = 0; - let total = content_length; - for await (const chunk of stream) { - downloaded += chunk.length; - chunks.push(chunk); - const ratio = downloaded / total; - const progress = Math.floor(ratio * 100); - sendFeedback("Download: " + progress + "%", ratio); - // 15% for download, 85% for conversion - // This is a very rough estimate, trying to make the progress bar look nice - increasePlaylistProgress(ratio * 0.15); - } - sendFeedback("Loading…", 2); // indefinite progress bar after download +async function iterableStreamToMP3( + stream, + metadata, + content_length, + sendFeedback, + increasePlaylistProgress = () => {}, +) { + const chunks = []; + let downloaded = 0; + const total = content_length; + for await (const chunk of stream) { + downloaded += chunk.length; + chunks.push(chunk); + const ratio = downloaded / total; + const progress = Math.floor(ratio * 100); + sendFeedback(`Download: ${progress}%`, ratio); + // 15% for download, 85% for conversion + // This is a very rough estimate, trying to make the progress bar look nice + increasePlaylistProgress(ratio * 0.15); + } + sendFeedback("Loading…", 2); // indefinite progress bar after download - const buffer = Buffer.concat(chunks); - const safeVideoName = randomBytes(32).toString("hex"); - const releaseFFmpegMutex = await ffmpegMutex.acquire(); + const buffer = Buffer.concat(chunks); + const safeVideoName = randomBytes(32).toString("hex"); + const releaseFFmpegMutex = await ffmpegMutex.acquire(); - try { - if (!ffmpeg.isLoaded()) { - await ffmpeg.load(); - } + try { + if (!ffmpeg.isLoaded()) { + await ffmpeg.load(); + } - sendFeedback("Preparing file…"); - ffmpeg.FS("writeFile", safeVideoName, buffer); + sendFeedback("Preparing file…"); + ffmpeg.FS("writeFile", safeVideoName, buffer); - sendFeedback("Converting…"); + sendFeedback("Converting…"); - ffmpeg.setProgress(({ ratio }) => { - sendFeedback("Converting: " + Math.floor(ratio * 100) + "%", ratio); - increasePlaylistProgress(0.15 + ratio * 0.85); - }); + ffmpeg.setProgress(({ ratio }) => { + sendFeedback(`Converting: ${Math.floor(ratio * 100)}%`, ratio); + increasePlaylistProgress(0.15 + ratio * 0.85); + }); - await ffmpeg.run( - "-i", - safeVideoName, - ...getFFmpegMetadataArgs(metadata), - safeVideoName + ".mp3" - ); + await ffmpeg.run( + "-i", + safeVideoName, + ...getFFmpegMetadataArgs(metadata), + `${safeVideoName}.mp3`, + ); - sendFeedback("Saving…"); + sendFeedback("Saving…"); - return ffmpeg.FS("readFile", safeVideoName + ".mp3"); - } catch (e) { - sendError(e); - } finally { - releaseFFmpegMutex(); - } + return ffmpeg.FS("readFile", `${safeVideoName}.mp3`); + } catch (e) { + sendError(e); + } finally { + releaseFFmpegMutex(); + } } async function getCoverBuffer(url) { - const store = cache.getCoverBuffer; - if (store.url === url) { - return store.buffer; - } - store.url = url; + const store = cache.getCoverBuffer; + if (store.url === url) { + return store.buffer; + } + store.url = url; - const nativeImage = cropMaxWidth(await getImage(url)); - store.buffer = nativeImage && !nativeImage.isEmpty() ? - nativeImage.toPNG() : null; + const nativeImage = cropMaxWidth(await getImage(url)); + store.buffer = + nativeImage && !nativeImage.isEmpty() ? nativeImage.toPNG() : null; - return store.buffer; + return store.buffer; } async function writeID3(buffer, metadata, sendFeedback) { - try { - sendFeedback("Writing ID3 tags..."); + try { + sendFeedback("Writing ID3 tags..."); - const coverBuffer = await getCoverBuffer(metadata.image); + const coverBuffer = await getCoverBuffer(metadata.image); - const writer = new ID3Writer(buffer); + const writer = new ID3Writer(buffer); - // Create the metadata tags - writer - .setFrame("TIT2", metadata.title) - .setFrame("TPE1", [metadata.artist]); - if (metadata.album) { - writer.setFrame("TALB", metadata.album); - } - if (coverBuffer) { - writer.setFrame("APIC", { - type: 3, - data: coverBuffer, - description: "", - }); - } - if (isEnabled("lyrics-genius")) { - const lyrics = await fetchFromGenius(metadata); - if (lyrics) { - writer.setFrame("USLT", { - description: '', - lyrics: lyrics, - }); - } - } - if (metadata.trackId) { - writer.setFrame("TRCK", metadata.trackId); - } - writer.addTag(); - return Buffer.from(writer.arrayBuffer); - } catch (e) { - sendError(e); - } + // Create the metadata tags + writer.setFrame("TIT2", metadata.title).setFrame("TPE1", [metadata.artist]); + if (metadata.album) { + writer.setFrame("TALB", metadata.album); + } + if (coverBuffer) { + writer.setFrame("APIC", { + type: 3, + data: coverBuffer, + description: "", + }); + } + if (isEnabled("lyrics-genius")) { + const lyrics = await fetchFromGenius(metadata); + if (lyrics) { + writer.setFrame("USLT", { + description: "", + lyrics: lyrics, + }); + } + } + if (metadata.trackId) { + writer.setFrame("TRCK", metadata.trackId); + } + writer.addTag(); + return Buffer.from(writer.arrayBuffer); + } catch (e) { + sendError(e); + } } async function downloadPlaylist(givenUrl) { - if (givenUrl) { - try { - givenUrl = new URL(givenUrl); - } catch { - givenUrl = undefined; - }; - } - const playlistId = getPlaylistID(givenUrl) - || getPlaylistID(new URL(win.webContents.getURL())) - || getPlaylistID(new URL(playingUrl)); + if (givenUrl) { + try { + givenUrl = new URL(givenUrl); + } catch { + givenUrl = undefined; + } + } + const playlistId = + getPlaylistID(givenUrl) || + getPlaylistID(new URL(win.webContents.getURL())) || + getPlaylistID(new URL(playingUrl)); - if (!playlistId) { - sendError(new Error("No playlist ID found")); - return; - } + if (!playlistId) { + sendError(new Error("No playlist ID found")); + return; + } - const sendFeedback = message => sendFeedback_(win, message); + const sendFeedback = (message) => sendFeedback_(win, message); - console.log(`trying to get playlist ID: '${playlistId}'`); - sendFeedback("Getting playlist info…"); - let playlist; - try { - playlist = await ytpl(playlistId, { - limit: config.get('playlistMaxItems') || Infinity, - }); - } catch (e) { - sendError("Error getting playlist info: make sure it isn't a private or \"Mixed for you\" playlist\n\n" + e); - return; - } - if (playlist.items.length === 0) sendError(new Error("Playlist is empty")); - if (playlist.items.length === 1) { - sendFeedback("Playlist has only one item, downloading it directly"); - await downloadSong(playlist.items[0].url); - return; - } - let isAlbum = playlist.title.startsWith('Album - '); - if (isAlbum) { - playlist.title = playlist.title.slice(8); - } - const safePlaylistTitle = filenamify(playlist.title, { replacement: ' ' }); + console.log(`trying to get playlist ID: '${playlistId}'`); + sendFeedback("Getting playlist info…"); + let playlist; + try { + playlist = await ytpl(playlistId, { + limit: config.get("playlistMaxItems") || Infinity, + }); + } catch (e) { + sendError( + `Error getting playlist info: make sure it isn\'t a private or "Mixed for you" playlist\n\n${e}`, + ); + return; + } + if (playlist.items.length === 0) sendError(new Error("Playlist is empty")); + if (playlist.items.length === 1) { + sendFeedback("Playlist has only one item, downloading it directly"); + await downloadSong(playlist.items[0].url); + return; + } + const isAlbum = playlist.title.startsWith("Album - "); + if (isAlbum) { + playlist.title = playlist.title.slice(8); + } + const safePlaylistTitle = filenamify(playlist.title, { replacement: " " }); - const folder = getFolder(config.get('downloadFolder')); - const playlistFolder = join(folder, safePlaylistTitle); - if (existsSync(playlistFolder)) { - if (!config.get('skipExisting')) { - sendError(new Error(`The folder ${playlistFolder} already exists`)); - return; - } - } else { - mkdirSync(playlistFolder, { recursive: true }); - } + const folder = getFolder(config.get("downloadFolder")); + const playlistFolder = join(folder, safePlaylistTitle); + if (existsSync(playlistFolder)) { + if (!config.get("skipExisting")) { + sendError(new Error(`The folder ${playlistFolder} already exists`)); + return; + } + } else { + mkdirSync(playlistFolder, { recursive: true }); + } - dialog.showMessageBox({ - type: "info", - buttons: ["OK"], - title: "Started Download", - message: `Downloading Playlist "${playlist.title}"`, - detail: `(${playlist.items.length} songs)`, - }); + dialog.showMessageBox({ + type: "info", + buttons: ["OK"], + title: "Started Download", + message: `Downloading Playlist "${playlist.title}"`, + detail: `(${playlist.items.length} songs)`, + }); - if (is.dev()) { - console.log( - `Downloading playlist "${playlist.title}" - ${playlist.items.length} songs (${playlistId})` - ); - } + if (is.dev()) { + console.log( + `Downloading playlist "${playlist.title}" - ${playlist.items.length} songs (${playlistId})`, + ); + } - win.setProgressBar(2); // starts with indefinite bar + win.setProgressBar(2); // starts with indefinite bar - setBadge(playlist.items.length); + setBadge(playlist.items.length); - let counter = 1; + let counter = 1; - const progressStep = 1 / playlist.items.length; + const progressStep = 1 / playlist.items.length; - const increaseProgress = (itemPercentage) => { - const currentProgress = (counter - 1) / playlist.items.length; - const newProgress = currentProgress + (progressStep * itemPercentage); - win.setProgressBar(newProgress); - }; + const increaseProgress = (itemPercentage) => { + const currentProgress = (counter - 1) / playlist.items.length; + const newProgress = currentProgress + progressStep * itemPercentage; + win.setProgressBar(newProgress); + }; - try { - for (const song of playlist.items) { - sendFeedback(`Downloading ${counter}/${playlist.items.length}...`); - const trackId = isAlbum ? counter : undefined; - await downloadSong(song.url, playlistFolder, trackId, increaseProgress) - .catch((e) => sendError(`Error downloading "${song.author.name} - ${song.title}":\n ${e}`)); + try { + for (const song of playlist.items) { + sendFeedback(`Downloading ${counter}/${playlist.items.length}...`); + const trackId = isAlbum ? counter : undefined; + await downloadSong( + song.url, + playlistFolder, + trackId, + increaseProgress, + ).catch((e) => + sendError( + `Error downloading "${song.author.name} - ${song.title}":\n ${e}`, + ), + ); - win.setProgressBar(counter / playlist.items.length); - setBadge(playlist.items.length - counter); - counter++; - } - } catch (e) { - sendError(e); - } finally { - win.setProgressBar(-1); // close progress bar - setBadge(0); // close badge counter - sendFeedback(); // clear feedback - } + win.setProgressBar(counter / playlist.items.length); + setBadge(playlist.items.length - counter); + counter++; + } + } catch (e) { + sendError(e); + } finally { + win.setProgressBar(-1); // close progress bar + setBadge(0); // close badge counter + sendFeedback(); // clear feedback + } } async function ffmpegWriteTags(filePath, metadata, ffmpegArgs = []) { - const releaseFFmpegMutex = await ffmpegMutex.acquire(); + const releaseFFmpegMutex = await ffmpegMutex.acquire(); - try { - if (!ffmpeg.isLoaded()) { - await ffmpeg.load(); - } + try { + if (!ffmpeg.isLoaded()) { + await ffmpeg.load(); + } - await ffmpeg.run( - "-i", - filePath, - ...getFFmpegMetadataArgs(metadata), - ...ffmpegArgs, - filePath - ); - } catch (e) { - sendError(e); - } finally { - releaseFFmpegMutex(); - } + await ffmpeg.run( + "-i", + filePath, + ...getFFmpegMetadataArgs(metadata), + ...ffmpegArgs, + filePath, + ); + } catch (e) { + sendError(e); + } finally { + releaseFFmpegMutex(); + } } function getFFmpegMetadataArgs(metadata) { - if (!metadata) { - return; - } + if (!metadata) { + return; + } - return [ - ...(metadata.title ? ["-metadata", `title=${metadata.title}`] : []), - ...(metadata.artist ? ["-metadata", `artist=${metadata.artist}`] : []), - ...(metadata.album ? ["-metadata", `album=${metadata.album}`] : []), - ...(metadata.trackId ? ["-metadata", `track=${metadata.trackId}`] : []), - ]; -}; - -// Playlist radio modifier needs to be cut from playlist ID -const INVALID_PLAYLIST_MODIFIER = 'RDAMPL'; - -const getPlaylistID = aURL => { - const result = aURL?.searchParams.get("list") || aURL?.searchParams.get("playlist"); - if (result?.startsWith(INVALID_PLAYLIST_MODIFIER)) { - return result.slice(6) - } - return result; -}; - -const getVideoId = url => { - if (typeof url === "string") { - url = new URL(url); - } - return url.searchParams.get("v"); + return [ + ...(metadata.title ? ["-metadata", `title=${metadata.title}`] : []), + ...(metadata.artist ? ["-metadata", `artist=${metadata.artist}`] : []), + ...(metadata.album ? ["-metadata", `album=${metadata.album}`] : []), + ...(metadata.trackId ? ["-metadata", `track=${metadata.trackId}`] : []), + ]; } +// Playlist radio modifier needs to be cut from playlist ID +const INVALID_PLAYLIST_MODIFIER = "RDAMPL"; + +const getPlaylistID = (aURL) => { + const result = + aURL?.searchParams.get("list") || aURL?.searchParams.get("playlist"); + if (result?.startsWith(INVALID_PLAYLIST_MODIFIER)) { + return result.slice(6); + } + return result; +}; + +const getVideoId = (url) => { + if (typeof url === "string") { + url = new URL(url); + } + return url.searchParams.get("v"); +}; + const getMetadata = (info) => ({ - id: info.basic_info.id, - title: info.basic_info.title, - artist: info.basic_info.author, - album: info.player_overlays?.browser_media_session?.album?.text, - image: info.basic_info.thumbnail[0].url, + id: info.basic_info.id, + title: info.basic_info.title, + artist: info.basic_info.author, + album: info.player_overlays?.browser_media_session?.album?.text, + image: info.basic_info.thumbnail[0].url, }); diff --git a/plugins/downloader/menu.js b/plugins/downloader/menu.js index 86e4136c..6d58bbf2 100644 --- a/plugins/downloader/menu.js +++ b/plugins/downloader/menu.js @@ -4,20 +4,18 @@ const { downloadPlaylist } = require("./back"); const { defaultMenuDownloadLabel, getFolder, presets } = require("./utils"); const config = require("./config"); -let downloadLabel = defaultMenuDownloadLabel; - module.exports = () => { return [ { - label: downloadLabel, + label: defaultMenuDownloadLabel, click: () => downloadPlaylist(), }, { label: "Choose download folder", click: () => { - let result = dialog.showOpenDialogSync({ + const result = dialog.showOpenDialogSync({ properties: ["openDirectory", "createDirectory"], - defaultPath: getFolder(config.get('downloadFolder')), + defaultPath: getFolder(config.get("downloadFolder")), }); if (result) { config.set("downloadFolder", result[0]); @@ -29,7 +27,7 @@ module.exports = () => { submenu: Object.keys(presets).map((preset) => ({ label: preset, type: "radio", - checked: config.get('preset') === preset, + checked: config.get("preset") === preset, click: () => { config.set("preset", preset); }, @@ -38,10 +36,10 @@ module.exports = () => { { label: "Skip existing files", type: "checkbox", - checked: config.get('skipExisting'), + checked: config.get("skipExisting"), click: (item) => { config.set("skipExisting", item.checked); - } - } + }, + }, ]; };