From 206bf575d15b7a45c8f67dd5b0c07cef3d4a5cd0 Mon Sep 17 00:00:00 2001 From: Honza Cieslar <109418897+honzawashere@users.noreply.github.com> Date: Sat, 18 Nov 2023 13:21:49 +0100 Subject: [PATCH] Add files via upload --- Index.js | 104 +++-- NoAdPreload.js | 391 ++++++++++++++++-- Preload.js | 391 ++++++++++++++++-- package-lock.json | 4 +- package.json | 2 +- plugins/adblocker/Plugin.js | 60 +-- plugins/adblocker/functions/load.js | 12 + plugins/adblocker/handlers/adblocker.js | 16 + plugins/ambient-mode/Plugin.js | 9 + plugins/ambient-mode/functions/clearCanvas.js | 13 + plugins/ambient-mode/functions/drawCanvas.js | 20 + plugins/ambient-mode/handlers/ambient-mode.js | 15 + plugins/bypass-premium-restrictions/Plugin.js | 116 +----- .../functions/disableMiniplayer.js | 12 + .../functions/disablePremium.js | 13 + .../functions/enableMiniplayer.js | 12 + .../functions/enablePremium.js | 12 + .../handlers/disable-miniplayer.js | 17 + .../handlers/disable-premium-upgrade.js | 17 + plugins/close-background/Plugin.js | 6 + .../handlers/close-background.js | 9 + plugins/color-changer/Plugin.js | 100 +---- .../color-changer/functions/clearColors.js | 6 + .../color-changer/functions/updateColors.js | 6 + .../handlers/color-changer-private-songs.js | 22 + .../handlers/color-changer-songs.js | 22 + .../handlers/color-changer-videos.js | 26 ++ .../color-changer/handlers/color-changer.js | 15 + plugins/dev-tools/Plugin.js | 7 + plugins/disable-better-fullscreen/Plugin.js | 6 + .../handlers/disable-better-fullscreen.js | 12 + plugins/disable-tray/Plugin.js | 6 + plugins/disable-tray/handlers/disable-tray.js | 11 + plugins/disable-yt-sans/Plugin.js | 6 + .../handlers/disable-yt-sans.js | 9 + plugins/discord-rpc/Plugin.js | 232 ++--------- .../discord-rpc/functions/ConnectPresence.js | 51 +++ .../discord-rpc/functions/UpdatePresence.js | 92 +++++ plugins/discord-rpc/handlers/discord-rpc.js | 15 + .../handlers/discord-show-cover.js | 14 + .../handlers/discord-show-playback.js | 14 + .../handlers/discord-show-songdata.js | 14 + .../discord-rpc/handlers/discord-show-time.js | 14 + plugins/downloader/Plugin.js | 212 +--------- .../downloader/functions/createNewPrompt.js | 4 + plugins/downloader/functions/downloadMP3.js | 91 ++++ plugins/downloader/functions/downloadMP4.js | 99 +++++ plugins/downloader/handlers/download-mp3.js | 6 + plugins/downloader/handlers/download-mp4.js | 6 + plugins/gaming-mode/Plugin.js | 26 +- plugins/gaming-mode/handlers/gamer-mode.js | 10 + plugins/premium-features/Plugin.js | 29 +- .../handlers/show-premium-tag.js | 10 + plugins/resume-playback-on-launch/Plugin.js | 20 +- .../handlers/resume-playback-on-launch.js | 10 + 55 files changed, 1671 insertions(+), 803 deletions(-) create mode 100644 plugins/adblocker/functions/load.js create mode 100644 plugins/adblocker/handlers/adblocker.js create mode 100644 plugins/ambient-mode/Plugin.js create mode 100644 plugins/ambient-mode/functions/clearCanvas.js create mode 100644 plugins/ambient-mode/functions/drawCanvas.js create mode 100644 plugins/ambient-mode/handlers/ambient-mode.js create mode 100644 plugins/bypass-premium-restrictions/functions/disableMiniplayer.js create mode 100644 plugins/bypass-premium-restrictions/functions/disablePremium.js create mode 100644 plugins/bypass-premium-restrictions/functions/enableMiniplayer.js create mode 100644 plugins/bypass-premium-restrictions/functions/enablePremium.js create mode 100644 plugins/bypass-premium-restrictions/handlers/disable-miniplayer.js create mode 100644 plugins/bypass-premium-restrictions/handlers/disable-premium-upgrade.js create mode 100644 plugins/close-background/Plugin.js create mode 100644 plugins/close-background/handlers/close-background.js create mode 100644 plugins/color-changer/functions/clearColors.js create mode 100644 plugins/color-changer/functions/updateColors.js create mode 100644 plugins/color-changer/handlers/color-changer-private-songs.js create mode 100644 plugins/color-changer/handlers/color-changer-songs.js create mode 100644 plugins/color-changer/handlers/color-changer-videos.js create mode 100644 plugins/color-changer/handlers/color-changer.js create mode 100644 plugins/dev-tools/Plugin.js create mode 100644 plugins/disable-better-fullscreen/Plugin.js create mode 100644 plugins/disable-better-fullscreen/handlers/disable-better-fullscreen.js create mode 100644 plugins/disable-tray/Plugin.js create mode 100644 plugins/disable-tray/handlers/disable-tray.js create mode 100644 plugins/disable-yt-sans/Plugin.js create mode 100644 plugins/disable-yt-sans/handlers/disable-yt-sans.js create mode 100644 plugins/discord-rpc/functions/ConnectPresence.js create mode 100644 plugins/discord-rpc/functions/UpdatePresence.js create mode 100644 plugins/discord-rpc/handlers/discord-rpc.js create mode 100644 plugins/discord-rpc/handlers/discord-show-cover.js create mode 100644 plugins/discord-rpc/handlers/discord-show-playback.js create mode 100644 plugins/discord-rpc/handlers/discord-show-songdata.js create mode 100644 plugins/discord-rpc/handlers/discord-show-time.js create mode 100644 plugins/downloader/functions/createNewPrompt.js create mode 100644 plugins/downloader/functions/downloadMP3.js create mode 100644 plugins/downloader/functions/downloadMP4.js create mode 100644 plugins/downloader/handlers/download-mp3.js create mode 100644 plugins/downloader/handlers/download-mp4.js create mode 100644 plugins/gaming-mode/handlers/gamer-mode.js create mode 100644 plugins/premium-features/handlers/show-premium-tag.js create mode 100644 plugins/resume-playback-on-launch/handlers/resume-playback-on-launch.js diff --git a/Index.js b/Index.js index 8c17600..0819c7c 100644 --- a/Index.js +++ b/Index.js @@ -1,33 +1,37 @@ +let preloadPath = ""; +let wasPreloadEnabled = false; +let currentWindow; + const electron = require("electron") const path = require("path"); const unhandled = require("electron-unhandled") -const {finishWebLoad, preloadPlugins, addTray, bypassNetwork} = require("./scripts/web/WebManager"); -const {createDatabase, get, set, getJSON} = require("./scripts/database/PluginManager"); -const {getLastSongInfo} = require("./scripts/database/PluginManager"); -const store = require("electron-store"); +const { get } = require("./scripts/database/PluginManager") +const {finishWebLoad, redoFinishWebLoad} = require("./scripts/web/WebManager"); +const {getLastSongInfo, createDatabase} = require("./scripts/database/PluginManager"); +const {bypassNetwork} = require("./scripts/web/Managers/Window/networkManager") +const {addTray} = require("./scripts/web/Managers/Window/windowManager") +const {preloadPlugins} = require("./scripts/web/Managers/Window/pluginManager"); const gotTheLock = electron.app.requestSingleInstanceLock(); if (!gotTheLock) { process.exit() } -let w - -unhandled({ showDialog: false, logger: console.log }) +unhandled({showDialog: false, logger: console.log}) -if(get("gamer-mode") === true) { - console.log(`[Window] app.disableHardwareAcceleration() called.`) +if (get("gamer-mode") === true) { electron.app.disableHardwareAcceleration() } electron.app.on("ready", async () => { - let pr - if(get("adblocker") === true) { - pr = path.join(__dirname, "Preload.js") - } else { - pr = path.join(__dirname, "NoAdPreload.js") + if (get("adblocker") === true) { + preloadPath = path.join(__dirname, "Preload.js") + } + if (get("adblocker") === false) { + preloadPath = path.join(__dirname, "NoAdPreload.js") } + const window = new electron.BrowserWindow( { title: "YouTube Music", @@ -36,7 +40,7 @@ electron.app.on("ready", async () => { minWidth: 1280, minHeight: 720, webPreferences: { - preload: pr, + preload: preloadPath, nodeIntegration: true }, frame: false @@ -44,12 +48,8 @@ electron.app.on("ready", async () => { ) this.browserWindow = window - w = window + currentWindow = window electron.Menu.setApplicationMenu(null) - const is = require("electron-is") - if(is.dev()) { - w.webContents.openDevTools({ mode: "detach" }) - } bypassNetwork(window) preloadPlugins(window) @@ -58,63 +58,55 @@ electron.app.on("ready", async () => { const oldSongInfo = getLastSongInfo() - if(get("resume-playback-on-launch") === true) { - console.log(`[Window] Loading YouTube Music page with last video...`) + if (get("resume-playback-on-launch") === true) { try { window.loadURL(`https://music.youtube.com/watch?v=${oldSongInfo.info.details.videoId || undefined}&t=${oldSongInfo.time}&list=${oldSongInfo.list}`).then(() => { - if(window.webContents.getURL().includes("https://music.youtube.com")) { - console.log(`[Window] Showing window`) window.show() - } else { - console.log(`[Window] Got consent page, inserting css`) + }) + } catch (e) { + window.loadURL("https://music.youtube.com/").then(() => { window.show() - } - }) - } catch(e) { - console.log(`[Window] Loading YouTube Music page...`) - window.loadURL("https://music.youtube.com/").then(async () => { - if(window.webContents.getURL().includes("https://music.youtube.com")) { - console.log(`[Window] Showing window`) - window.show() - } else { - console.log(`[Window] Got consent page, inserting css`) - window.show() - } }) } } else { - console.log(`[Window] Loading YouTube Music page...`) - window.loadURL("https://music.youtube.com/").then(async () => { - if(window.webContents.getURL().includes("https://music.youtube.com")) { - console.log(`[Window] Showing window`) - window.show() - } else { - console.log(`[Window] Got consent page, inserting css`) - window.show() - } + window.loadURL("https://music.youtube.com/").then(() => { + window.show() }) } electron.ipcMain.on("preload-enabled", () => { - console.log("[Preload] Preload script enabled") - finishWebLoad(window) + if (wasPreloadEnabled === true) { + redoFinishWebLoad(window) + return + } + if (wasPreloadEnabled === false) { + finishWebLoad(window) + wasPreloadEnabled = true + } + }) + + window.webContents.on("render-process-gone", () => { + electron.dialog.showMessageBox({ + title: "YouTube Music", + message: "Unfortunately, it looks like that YouTube Music has crashed. Please reload the app.", + icon: path.join(__dirname, "..", "..", "icons", "tray.png") + }) }) }) electron.app.on("second-instance", () => { - if(!w) { - console.log(`[Window] Already one session running, closing...`) + if (!currentWindow) { process.exit() return } - if(w.isMinimized()) { - w.restore() + if (currentWindow.isMinimized()) { + currentWindow.restore() } - if(!w.isVisible()) { - w.show() + if (!currentWindow.isVisible()) { + currentWindow.show() } - w.focus() + currentWindow.focus() }) \ No newline at end of file diff --git a/NoAdPreload.js b/NoAdPreload.js index 1249f7e..b5e70ec 100644 --- a/NoAdPreload.js +++ b/NoAdPreload.js @@ -1,3 +1,348 @@ +if (!document.URL.startsWith("https://music.youtube.com/")) return + +function insertCustomMenu() { + const policy = trustedTypes.createPolicy("myPolicy", { + createHTML: (string) => { + return string; + } + }) + + const div = document.createElement("div") + div.classList.add("plugins-menu") + div.classList.add("hidden") + div.id = "plugins-menu" + + const div_dialog = document.createElement("div") + div_dialog.classList.add("plugins-dialog") + div_dialog.id = "plugins-dialog" + + const div_title = document.createElement("div") + div_title.classList.add("plugins-title") + + const div_close = document.createElement("div") + div_close.classList.add("close-menu") + + div_close.onclick = () => { + document.querySelector("#plugins-menu").classList.add("hidden") + } + + const div_close1 = document.createElement("img") + div_close1.setAttribute("src", "https://raw.githubusercontent.com/binaryfunt/electron-seamless-titlebar-tutorial/master/src/icons/close-w-10.png") + + const div_title_h1 = document.createElement("h1") + div_title_h1.innerHTML = policy.createHTML("App Settings") + div_title.appendChild(div_title_h1) + + const div_content = document.createElement("div") + div_content.classList.add("plugins-options") + div_content.id = "plugins-options" + + const div_options = document.createElement("div") + div_options.id = "options" + div_options.classList.add("options") + + const option1 = document.createElement("div") + option1.id = "option1" + option1.classList.add("option") + option1.classList.add("option-selected") + + const option1title = document.createElement("h1") + option1title.innerHTML = policy.createHTML("Visual") + + const option2 = document.createElement("div") + option2.id = "option2" + option2.classList.add("option") + + const option2title = document.createElement("h1") + option2title.innerHTML = policy.createHTML("Plugins") + + const option3 = document.createElement("div") + option3.id = "option2" + option3.classList.add("option") + + const option3title = document.createElement("h1") + option3title.innerHTML = policy.createHTML("Developer") + + const tab1 = document.createElement("div") + tab1.id = "tab1" + tab1.classList.add("tabxd") + + const tab2 = document.createElement("div") + tab2.id = "tab2" + tab2.classList.add("tabxd") + tab2.classList.add("hidden") + + const tab3 = document.createElement("div") + tab3.id = "tab3" + tab3.classList.add("tabxd") + tab3.classList.add("hidden") + + const tab1c = document.createElement("div") + tab1c.id = "tab1c" + tab1c.classList.add("tabc") + + const tab2c = document.createElement("div") + tab2c.id = "tab2c" + tab2c.classList.add("tabc") + + const tab3c = document.createElement("div") + tab3c.id = "tab3c" + tab3c.classList.add("tabc") + + option1.onclick = () => { + option1.classList.add("option-selected") + option2.classList.remove("option-selected") + option3.classList.remove("option-selected") + tab1.classList.remove("hidden") + tab2.classList.add("hidden") + tab3.classList.add("hidden") + } + + option2.onclick = () => { + option1.classList.remove("option-selected") + option2.classList.add("option-selected") + option3.classList.remove("option-selected") + tab1.classList.add("hidden") + tab2.classList.remove("hidden") + tab3.classList.add("hidden") + } + + option3.onclick = () => { + option1.classList.remove("option-selected") + option2.classList.remove("option-selected") + option3.classList.add("option-selected") + tab1.classList.add("hidden") + tab2.classList.add("hidden") + tab3.classList.remove("hidden") + } + + div.appendChild(div_dialog) + div_dialog.appendChild(div_title) + div_title.appendChild(div_close) + div_close.appendChild(div_close1) + div_dialog.appendChild(div_content) + div_content.appendChild(div_options) + div_options.appendChild(option1) + div_options.appendChild(option2) + div_options.appendChild(option3) + option1.appendChild(option1title) + option2.appendChild(option2title) + option3.appendChild(option3title) + div_dialog.appendChild(tab1) + div_dialog.appendChild(tab2) + div_dialog.appendChild(tab3) + tab1.appendChild(tab1c) + tab2.appendChild(tab2c) + tab3.appendChild(tab3c) + + function createSection(tab, name, alias) { + if (tab === 1) { + const section = document.createElement("div") + section.id = alias + section.classList.add("section") + + const title = document.createElement("h1") + title.innerHTML = policy.createHTML(name) + + const br = document.createElement("br") + br.id = "br" + + tab1c.appendChild(section) + section.appendChild(title) + section.appendChild(br) + } + if (tab === 2) { + const section = document.createElement("div") + section.id = alias + section.classList.add("section") + + const title = document.createElement("h1") + title.innerHTML = policy.createHTML(name) + + const br = document.createElement("br") + br.id = "br" + + tab2c.appendChild(section) + section.appendChild(title) + section.appendChild(br) + } + if (tab === 3) { + const section = document.createElement("div") + section.id = alias + section.classList.add("section") + + const title = document.createElement("h1") + title.innerHTML = policy.createHTML(name) + + const br = document.createElement("br") + br.id = "br" + + tab3c.appendChild(section) + section.appendChild(title) + section.appendChild(br) + } + } + + function createBr() { + const br = document.createElement("br") + br.id = "br" + tab1c.appendChild(br) + } + + function createSetting(section, name, alias, description, no_slider, require_premium, disable_premium) { + const s = document.getElementById(section) + + const setting = document.createElement("div") + setting.classList.add("setting") + setting.id = "setting" + + const section_1 = document.createElement("div") + section_1.id = alias + "_1" + + const section_2 = document.createElement("div") + section_2.id = alias + "_2" + section_2.classList.add("section-2") + + const title = document.createElement("h1") + title.innerHTML = policy.createHTML(name) + + const d = document.createElement("h2") + d.innerHTML = policy.createHTML(description) + + const br = document.createElement("br") + br.id = "br" + + s.appendChild(setting) + setting.appendChild(section_1) + setting.appendChild(section_2) + section_1.appendChild(title) + section_2.appendChild(d) + section_2.appendChild(br) + + const toggle_button = document.createElement("div") + toggle_button.classList.add("toggle-button") + toggle_button.id = "toggle_button" + toggle_button.setAttribute("for", alias) + toggle_button.setAttribute("plugin", section) + + const toggle_line = document.createElement("div") + toggle_line.classList.add("toggle-line") + toggle_line.id = alias + + if (!no_slider) { + section_1.appendChild(toggle_line) + toggle_line.appendChild(toggle_button) + } + if (no_slider) { + setting.classList.add("clickable") + setting.id = "clickable" + setting.setAttribute("for", alias) + setting.setAttribute("plugin", section) + } + if (disable_premium) { + setting.setAttribute("disable-premium", "") + toggle_button.setAttribute("disable-premium", "") + } + if (require_premium) { + setting.setAttribute("require-premium", "") + toggle_button.setAttribute("require-premium", "") + } + } + + document.body.appendChild(div) + + createSection(1, "Ambient Mode", "ambient-mode") + createSetting("ambient-mode", "Ambient Mode", "ambient-mode", "This will create ambient mode effect around the image/video. May be laggy on slower devices.") + createSection(1, "YouTube Sans", "disable-yt-sans") + createSetting("disable-yt-sans", "Disable YouTube Sans", "disable-yt-sans", "This will disable the YouTube Sans font and replace it by default font (Requires app reload)") + createSection(1, "Improved Fullscreen", "disable-improved-fullscreen") + createSetting("disable-improved-fullscreen", "Disable Improved Fullscreen", "disable-better-fullscreen", "This will disable redesigned fullscreen") + createSection(1, "Tray", "disable-tray") + createSetting("disable-tray", "Disable Tray", "disable-tray", "This will hide icon in tray") + createSection(1, "Background", "close-background") + createSetting("close-background", "Stay in background after closing", "close-background", "When you close the app, it will stay in background") + createSection(2, "adBlocker", "adblocker") + createSetting("adblocker", "Enabled", "adblocker", "This will block ads for you. If you are a Premium user, don't use this.", false, false, true) + createSection(2, "Bypass Premium Restrictions", "bypass-premium-restrictions") + createSetting("bypass-premium-restrictions", "Disable Miniplayer", "disable-miniplayer", "Disables Miniplayer for you. If you are a Premium user, you don't need this.", false, false, true) + createSetting("bypass-premium-restrictions", "Disable Premium Upgrade", "disable-premium-upgrade", "Hides all Upgrade to Premium buttons. If you are a Premium user, you don't need this.", false, false, true) + createSection(2, "Color Changer", "color-changer") + createSetting("color-changer", "Enabled", "color-changer", "Enables Color Changer.") + createSetting("color-changer", "Songs", "color-changer-songs", "Changes color for songs.") + createSetting("color-changer", "Videos", "color-changer-videos", "Changes color for videos.") + createSetting("color-changer", "Private Songs", "color-changer-private-songs", "Changes color for private songs.") + createSection(2, "Discord Rich Presence", "discord-rpc") + createSetting("discord-rpc", "Enabled", "discord-rpc", "Enables Discord Rich Presence (Playing YouTube Music).") + createSetting("discord-rpc", "Playback", "discord-show-playback", "Should presence contain Playing/Paused status?") + createSetting("discord-rpc", "Cover", "discord-show-cover", "Should presence contain track cover or YouTube Music logo?") + createSetting("discord-rpc", "Song Data", "discord-show-songdata", "Should presence contain song data or no?") + createSetting("discord-rpc", "Left Time", "discord-show-time", "Should presence show left time?") + createSection(2, "Downloader", "downloader") + createSetting("downloader", "Download as mp3", "download-mp3", "Downloads current video as mp3.", true) + createSetting("downloader", "Download as mp4", "download-mp4", "Downloads current video as mp4.", true) + createSection(2, "Gaming Mode", "gaming-mode") + createSetting("gaming-mode", "Enabled", "gamer-mode", "When you minimize this app or you leave it on background, it hides app's content to save as much resources as possible.") + createSection(2, "Premium Features", "premium-features") + createSetting("premium-features", "Show Premium Title", "show-premium-tag", "If you are a premium user, you will see 'Premium' on Discord Rich Presence and app's title. Only available for Premium users.", false, true) + createSection(2, "Resume Playback On Launch", "resume-playback-on-launch") + createSetting("resume-playback-on-launch", "Enabled", "resume-playback-on-launch", "Before closing, this saves last song you were playing before you close the app and opens it when you launch the app again.") + createBr() + createSection(3, "Dev Tools", "dev-tools") + createSetting("dev-tools", "Show Dev Tools", "show-dev-tools", "Opens developer tools for you.", true) + + document.querySelector("ytmusic-settings-button").onclick = () => { + const customSettings = document.createElement("ytd-compact-link-renderer") + customSettings.id = "app-settings" + const settingsPage = document.querySelector("yt-multi-page-menu-section-renderer > #items") + settingsPage.appendChild(customSettings) + const ytFormattedString = document.querySelector("#app-settings > a > tp-yt-paper-item > yt-formatted-string") + const ytAttributedString = document.querySelector("#app-settings > a > tp-yt-paper-item > #primary-text-container > #label > yt-attributed-string") + + const ytImg = document.createElement("img") + ytImg.setAttribute("draggable", false) + ytImg.src = "https://raw.githubusercontent.com/honzawashere/YouTube-Music/new/icons/settings.png" + ytImg.style.width = "24px" + ytImg.style.height = "24px" + + const ytContentIcon = document.querySelector("#app-settings > a > tp-yt-paper-item > #content-icon > yt-icon") + ytContentIcon.appendChild(ytImg) + + const ytSecondaryString = document.querySelector("#app-settings > a > tp-yt-paper-item > #secondary-text") + + ytFormattedString.removeAttribute("is-empty") + ytAttributedString.innerHTML = policy.createHTML("App Settings") + ytSecondaryString.setAttribute("hidden", "") + + document.querySelector("#app-settings > a").onclick = () => { + document.querySelector("#plugins-menu").classList.remove("hidden") + document.querySelector("body > ytmusic-app > ytmusic-popup-container > tp-yt-iron-dropdown:nth-child(2)").style.display = "none" + document.querySelector("body > ytmusic-app > ytmusic-popup-container > tp-yt-iron-dropdown:nth-child(2)").setAttribute("aria-hidden", true) + } + } +} + +let currentCanvasSrc = null + +function createCanvas() { + const canvas = document.createElement("canvas") + canvas.id = "ambientModeCanvas" + canvas.classList.add("ambient-mode-canvas") + canvas.width = 800 + canvas.height = 800 + + const player = document.querySelector("ytmusic-player") + player.appendChild(canvas) +} + +document.addEventListener("DOMContentLoaded", () => { + if (!document.querySelector("#items > ytmusic-guide-entry-renderer:nth-child(4) > tp-yt-paper-item")) { + ipcRenderer.send("premium") + } + + insertCustomMenu() + createCanvas() +}) + const {ipcRenderer} = require("electron") const $ = document.querySelector.bind(document); @@ -77,6 +422,7 @@ function createFullscreen() { document.addEventListener("DOMContentLoaded", () => { document.querySelector("#left-content > yt-icon-button").remove() + document.querySelector("ytmusic-app-layout").setAttribute("not-maximized", "") createFullscreen() const observer = new MutationObserver(() => { @@ -87,18 +433,20 @@ document.addEventListener("DOMContentLoaded", () => { const video = $("video") video.id = "video" - observer2.observe(document.getElementById("video"), {attributes: true, childList: true, subtree: true}); observer3.observe(document.getElementById("movie_player"), { attributes: true, childList: true, subtree: true }); + video.addEventListener("loadeddata", () => { + ipcRenderer.send("ambient-mode") + }) video.addEventListener("play", () => { ipcRenderer.send("play") setTimeout(() => { - if(document.querySelector("ytmusic-app-layout").getAttribute("player-visible") !== "") { + if (document.querySelector("ytmusic-app-layout").getAttribute("player-visible") !== "") { ipcRenderer.send("rate-limited") document.querySelector("ytmusic-app-layout").setAttribute("player-visible", "") } @@ -110,29 +458,12 @@ document.addEventListener("DOMContentLoaded", () => { video.addEventListener("seeked", () => { ipcRenderer.send("seek") }) + video.addEventListener("timeupdate", () => { + ipcRenderer.send("seek") + }) } }) - const observer2 = new MutationObserver(() => { - const video = document.querySelector("#video") - const data = document.querySelector("#player").getAttribute("video-mode") - - if (data === '') { - const width = video.style.width - const height = video.style.height - - const songControls = document.querySelector("#player > div.song-media-controls.style-scope.ytmusic-player") - - songControls.style.width = width - songControls.style.height = height - - return - } - const songControls = document.querySelector("#player > div.song-media-controls.style-scope.ytmusic-player") - songControls.style.width = "100%" - songControls.style.height = "100%" - }) - const observer3 = new MutationObserver(() => { if (document.querySelector("#movie_player")) { if (document.querySelector("#movie_player").classList.contains("buffering-mode")) { @@ -169,22 +500,28 @@ document.addEventListener("DOMContentLoaded", () => { b.onclick = (e) => { if (b.getAttribute("enabled") !== null) { b.removeAttribute("enabled") - ipcRenderer.send("button-clicked", [b.getAttribute("for")]) + ipcRenderer.send("button-clicked", [{ + for: b.getAttribute("for"), + plugin: b.getAttribute("plugin") + }]) return } b.setAttribute("enabled", "") - ipcRenderer.send("button-clicked", [b.getAttribute("for")]) + ipcRenderer.send("button-clicked", [{for: b.getAttribute("for"), plugin: b.getAttribute("plugin")}]) } }) document.querySelectorAll("#clickable").forEach(b => { b.onclick = (e) => { if (b.getAttribute("enabled") !== null) { b.removeAttribute("enabled") - ipcRenderer.send("button-clicked", [b.getAttribute("for")]) + ipcRenderer.send("button-clicked", [{ + for: b.getAttribute("for"), + plugin: b.getAttribute("plugin") + }]) return } b.setAttribute("enabled", "") - ipcRenderer.send("button-clicked", [b.getAttribute("for")]) + ipcRenderer.send("button-clicked", [{for: b.getAttribute("for"), plugin: b.getAttribute("plugin")}]) } }) observer4.disconnect() @@ -210,7 +547,7 @@ document.addEventListener("DOMContentLoaded", () => { observer4.observe(document.documentElement, {childList: true, subtree: true}) observer6.observe(document.documentElement, {childList: true, subtree: true}) - if(document.querySelector("#av-id > ytmusic-av-toggle")) { + if (document.querySelector("#av-id > ytmusic-av-toggle")) { observer5.observe(document.querySelector("#av-id > ytmusic-av-toggle"), {childList: true, subtree: true}) } diff --git a/Preload.js b/Preload.js index 38cd46b..e5a491b 100644 --- a/Preload.js +++ b/Preload.js @@ -1,5 +1,350 @@ require("@cliqz/adblocker-electron-preload/dist/preload.cjs") +if (!document.URL.startsWith("https://music.youtube.com/")) return + +function insertCustomMenu() { + const policy = trustedTypes.createPolicy("myPolicy", { + createHTML: (string) => { + return string; + } + }) + + const div = document.createElement("div") + div.classList.add("plugins-menu") + div.classList.add("hidden") + div.id = "plugins-menu" + + const div_dialog = document.createElement("div") + div_dialog.classList.add("plugins-dialog") + div_dialog.id = "plugins-dialog" + + const div_title = document.createElement("div") + div_title.classList.add("plugins-title") + + const div_close = document.createElement("div") + div_close.classList.add("close-menu") + + div_close.onclick = () => { + document.querySelector("#plugins-menu").classList.add("hidden") + } + + const div_close1 = document.createElement("img") + div_close1.setAttribute("src", "https://raw.githubusercontent.com/binaryfunt/electron-seamless-titlebar-tutorial/master/src/icons/close-w-10.png") + + const div_title_h1 = document.createElement("h1") + div_title_h1.innerHTML = policy.createHTML("App Settings") + div_title.appendChild(div_title_h1) + + const div_content = document.createElement("div") + div_content.classList.add("plugins-options") + div_content.id = "plugins-options" + + const div_options = document.createElement("div") + div_options.id = "options" + div_options.classList.add("options") + + const option1 = document.createElement("div") + option1.id = "option1" + option1.classList.add("option") + option1.classList.add("option-selected") + + const option1title = document.createElement("h1") + option1title.innerHTML = policy.createHTML("Visual") + + const option2 = document.createElement("div") + option2.id = "option2" + option2.classList.add("option") + + const option2title = document.createElement("h1") + option2title.innerHTML = policy.createHTML("Plugins") + + const option3 = document.createElement("div") + option3.id = "option2" + option3.classList.add("option") + + const option3title = document.createElement("h1") + option3title.innerHTML = policy.createHTML("Developer") + + const tab1 = document.createElement("div") + tab1.id = "tab1" + tab1.classList.add("tabxd") + + const tab2 = document.createElement("div") + tab2.id = "tab2" + tab2.classList.add("tabxd") + tab2.classList.add("hidden") + + const tab3 = document.createElement("div") + tab3.id = "tab3" + tab3.classList.add("tabxd") + tab3.classList.add("hidden") + + const tab1c = document.createElement("div") + tab1c.id = "tab1c" + tab1c.classList.add("tabc") + + const tab2c = document.createElement("div") + tab2c.id = "tab2c" + tab2c.classList.add("tabc") + + const tab3c = document.createElement("div") + tab3c.id = "tab3c" + tab3c.classList.add("tabc") + + option1.onclick = () => { + option1.classList.add("option-selected") + option2.classList.remove("option-selected") + option3.classList.remove("option-selected") + tab1.classList.remove("hidden") + tab2.classList.add("hidden") + tab3.classList.add("hidden") + } + + option2.onclick = () => { + option1.classList.remove("option-selected") + option2.classList.add("option-selected") + option3.classList.remove("option-selected") + tab1.classList.add("hidden") + tab2.classList.remove("hidden") + tab3.classList.add("hidden") + } + + option3.onclick = () => { + option1.classList.remove("option-selected") + option2.classList.remove("option-selected") + option3.classList.add("option-selected") + tab1.classList.add("hidden") + tab2.classList.add("hidden") + tab3.classList.remove("hidden") + } + + div.appendChild(div_dialog) + div_dialog.appendChild(div_title) + div_title.appendChild(div_close) + div_close.appendChild(div_close1) + div_dialog.appendChild(div_content) + div_content.appendChild(div_options) + div_options.appendChild(option1) + div_options.appendChild(option2) + div_options.appendChild(option3) + option1.appendChild(option1title) + option2.appendChild(option2title) + option3.appendChild(option3title) + div_dialog.appendChild(tab1) + div_dialog.appendChild(tab2) + div_dialog.appendChild(tab3) + tab1.appendChild(tab1c) + tab2.appendChild(tab2c) + tab3.appendChild(tab3c) + + function createSection(tab, name, alias) { + if (tab === 1) { + const section = document.createElement("div") + section.id = alias + section.classList.add("section") + + const title = document.createElement("h1") + title.innerHTML = policy.createHTML(name) + + const br = document.createElement("br") + br.id = "br" + + tab1c.appendChild(section) + section.appendChild(title) + section.appendChild(br) + } + if (tab === 2) { + const section = document.createElement("div") + section.id = alias + section.classList.add("section") + + const title = document.createElement("h1") + title.innerHTML = policy.createHTML(name) + + const br = document.createElement("br") + br.id = "br" + + tab2c.appendChild(section) + section.appendChild(title) + section.appendChild(br) + } + if (tab === 3) { + const section = document.createElement("div") + section.id = alias + section.classList.add("section") + + const title = document.createElement("h1") + title.innerHTML = policy.createHTML(name) + + const br = document.createElement("br") + br.id = "br" + + tab3c.appendChild(section) + section.appendChild(title) + section.appendChild(br) + } + } + + function createBr() { + const br = document.createElement("br") + br.id = "br" + tab1c.appendChild(br) + } + + function createSetting(section, name, alias, description, no_slider, require_premium, disable_premium) { + const s = document.getElementById(section) + + const setting = document.createElement("div") + setting.classList.add("setting") + setting.id = "setting" + + const section_1 = document.createElement("div") + section_1.id = alias + "_1" + + const section_2 = document.createElement("div") + section_2.id = alias + "_2" + section_2.classList.add("section-2") + + const title = document.createElement("h1") + title.innerHTML = policy.createHTML(name) + + const d = document.createElement("h2") + d.innerHTML = policy.createHTML(description) + + const br = document.createElement("br") + br.id = "br" + + s.appendChild(setting) + setting.appendChild(section_1) + setting.appendChild(section_2) + section_1.appendChild(title) + section_2.appendChild(d) + section_2.appendChild(br) + + const toggle_button = document.createElement("div") + toggle_button.classList.add("toggle-button") + toggle_button.id = "toggle_button" + toggle_button.setAttribute("for", alias) + toggle_button.setAttribute("plugin", section) + + const toggle_line = document.createElement("div") + toggle_line.classList.add("toggle-line") + toggle_line.id = alias + + if (!no_slider) { + section_1.appendChild(toggle_line) + toggle_line.appendChild(toggle_button) + } + if (no_slider) { + setting.classList.add("clickable") + setting.id = "clickable" + setting.setAttribute("for", alias) + setting.setAttribute("plugin", section) + } + if (disable_premium) { + setting.setAttribute("disable-premium", "") + toggle_button.setAttribute("disable-premium", "") + } + if (require_premium) { + setting.setAttribute("require-premium", "") + toggle_button.setAttribute("require-premium", "") + } + } + + document.body.appendChild(div) + + createSection(1, "Ambient Mode", "ambient-mode") + createSetting("ambient-mode", "Ambient Mode", "ambient-mode", "This will create ambient mode effect around the image/video. May be laggy on slower devices.") + createSection(1, "YouTube Sans", "disable-yt-sans") + createSetting("disable-yt-sans", "Disable YouTube Sans", "disable-yt-sans", "This will disable the YouTube Sans font and replace it by default font (Requires app reload)") + createSection(1, "Improved Fullscreen", "disable-improved-fullscreen") + createSetting("disable-improved-fullscreen", "Disable Improved Fullscreen", "disable-better-fullscreen", "This will disable redesigned fullscreen") + createSection(1, "Tray", "disable-tray") + createSetting("disable-tray", "Disable Tray", "disable-tray", "This will hide icon in tray") + createSection(1, "Background", "close-background") + createSetting("close-background", "Stay in background after closing", "close-background", "When you close the app, it will stay in background") + createSection(2, "adBlocker", "adblocker") + createSetting("adblocker", "Enabled", "adblocker", "This will block ads for you. If you are a Premium user, don't use this.", false, false, true) + createSection(2, "Bypass Premium Restrictions", "bypass-premium-restrictions") + createSetting("bypass-premium-restrictions", "Disable Miniplayer", "disable-miniplayer", "Disables Miniplayer for you. If you are a Premium user, you don't need this.", false, false, true) + createSetting("bypass-premium-restrictions", "Disable Premium Upgrade", "disable-premium-upgrade", "Hides all Upgrade to Premium buttons. If you are a Premium user, you don't need this.", false, false, true) + createSection(2, "Color Changer", "color-changer") + createSetting("color-changer", "Enabled", "color-changer", "Enables Color Changer.") + createSetting("color-changer", "Songs", "color-changer-songs", "Changes color for songs.") + createSetting("color-changer", "Videos", "color-changer-videos", "Changes color for videos.") + createSetting("color-changer", "Private Songs", "color-changer-private-songs", "Changes color for private songs.") + createSection(2, "Discord Rich Presence", "discord-rpc") + createSetting("discord-rpc", "Enabled", "discord-rpc", "Enables Discord Rich Presence (Playing YouTube Music).") + createSetting("discord-rpc", "Playback", "discord-show-playback", "Should presence contain Playing/Paused status?") + createSetting("discord-rpc", "Cover", "discord-show-cover", "Should presence contain track cover or YouTube Music logo?") + createSetting("discord-rpc", "Song Data", "discord-show-songdata", "Should presence contain song data or no?") + createSetting("discord-rpc", "Left Time", "discord-show-time", "Should presence show left time?") + createSection(2, "Downloader", "downloader") + createSetting("downloader", "Download as mp3", "download-mp3", "Downloads current video as mp3.", true) + createSetting("downloader", "Download as mp4", "download-mp4", "Downloads current video as mp4.", true) + createSection(2, "Gaming Mode", "gaming-mode") + createSetting("gaming-mode", "Enabled", "gamer-mode", "When you minimize this app or you leave it on background, it hides app's content to save as much resources as possible.") + createSection(2, "Premium Features", "premium-features") + createSetting("premium-features", "Show Premium Title", "show-premium-tag", "If you are a premium user, you will see 'Premium' on Discord Rich Presence and app's title. Only available for Premium users.", false, true) + createSection(2, "Resume Playback On Launch", "resume-playback-on-launch") + createSetting("resume-playback-on-launch", "Enabled", "resume-playback-on-launch", "Before closing, this saves last song you were playing before you close the app and opens it when you launch the app again.") + createBr() + createSection(3, "Dev Tools", "dev-tools") + createSetting("dev-tools", "Show Dev Tools", "show-dev-tools", "Opens developer tools for you.", true) + + document.querySelector("ytmusic-settings-button").onclick = () => { + const customSettings = document.createElement("ytd-compact-link-renderer") + customSettings.id = "app-settings" + const settingsPage = document.querySelector("yt-multi-page-menu-section-renderer > #items") + settingsPage.appendChild(customSettings) + const ytFormattedString = document.querySelector("#app-settings > a > tp-yt-paper-item > yt-formatted-string") + const ytAttributedString = document.querySelector("#app-settings > a > tp-yt-paper-item > #primary-text-container > #label > yt-attributed-string") + + const ytImg = document.createElement("img") + ytImg.setAttribute("draggable", false) + ytImg.src = "https://raw.githubusercontent.com/honzawashere/YouTube-Music/new/icons/settings.png" + ytImg.style.width = "24px" + ytImg.style.height = "24px" + + const ytContentIcon = document.querySelector("#app-settings > a > tp-yt-paper-item > #content-icon > yt-icon") + ytContentIcon.appendChild(ytImg) + + const ytSecondaryString = document.querySelector("#app-settings > a > tp-yt-paper-item > #secondary-text") + + ytFormattedString.removeAttribute("is-empty") + ytAttributedString.innerHTML = policy.createHTML("App Settings") + ytSecondaryString.setAttribute("hidden", "") + + document.querySelector("#app-settings > a").onclick = () => { + document.querySelector("#plugins-menu").classList.remove("hidden") + document.querySelector("body > ytmusic-app > ytmusic-popup-container > tp-yt-iron-dropdown:nth-child(2)").style.display = "none" + document.querySelector("body > ytmusic-app > ytmusic-popup-container > tp-yt-iron-dropdown:nth-child(2)").setAttribute("aria-hidden", true) + } + } +} + +let currentCanvasSrc = null + +function createCanvas() { + const canvas = document.createElement("canvas") + canvas.id = "ambientModeCanvas" + canvas.classList.add("ambient-mode-canvas") + canvas.width = 800 + canvas.height = 800 + + const player = document.querySelector("ytmusic-player") + player.appendChild(canvas) +} + +document.addEventListener("DOMContentLoaded", () => { + if (!document.querySelector("#items > ytmusic-guide-entry-renderer:nth-child(4) > tp-yt-paper-item")) { + ipcRenderer.send("premium") + } + + insertCustomMenu() + createCanvas() +}) + const {ipcRenderer} = require("electron") const $ = document.querySelector.bind(document); @@ -79,6 +424,7 @@ function createFullscreen() { document.addEventListener("DOMContentLoaded", () => { document.querySelector("#left-content > yt-icon-button").remove() + document.querySelector("ytmusic-app-layout").setAttribute("not-maximized", "") createFullscreen() const observer = new MutationObserver(() => { @@ -89,18 +435,20 @@ document.addEventListener("DOMContentLoaded", () => { const video = $("video") video.id = "video" - observer2.observe(document.getElementById("video"), {attributes: true, childList: true, subtree: true}); observer3.observe(document.getElementById("movie_player"), { attributes: true, childList: true, subtree: true }); + video.addEventListener("loadeddata", () => { + ipcRenderer.send("ambient-mode") + }) video.addEventListener("play", () => { ipcRenderer.send("play") setTimeout(() => { - if(document.querySelector("ytmusic-app-layout").getAttribute("player-visible") !== "") { + if (document.querySelector("ytmusic-app-layout").getAttribute("player-visible") !== "") { ipcRenderer.send("rate-limited") document.querySelector("ytmusic-app-layout").setAttribute("player-visible", "") } @@ -112,29 +460,12 @@ document.addEventListener("DOMContentLoaded", () => { video.addEventListener("seeked", () => { ipcRenderer.send("seek") }) + video.addEventListener("timeupdate", () => { + ipcRenderer.send("seek") + }) } }) - const observer2 = new MutationObserver(() => { - const video = document.querySelector("#video") - const data = document.querySelector("#player").getAttribute("video-mode") - - if (data === '') { - const width = video.style.width - const height = video.style.height - - const songControls = document.querySelector("#player > div.song-media-controls.style-scope.ytmusic-player") - - songControls.style.width = width - songControls.style.height = height - - return - } - const songControls = document.querySelector("#player > div.song-media-controls.style-scope.ytmusic-player") - songControls.style.width = "100%" - songControls.style.height = "100%" - }) - const observer3 = new MutationObserver(() => { if (document.querySelector("#movie_player")) { if (document.querySelector("#movie_player").classList.contains("buffering-mode")) { @@ -171,22 +502,28 @@ document.addEventListener("DOMContentLoaded", () => { b.onclick = (e) => { if (b.getAttribute("enabled") !== null) { b.removeAttribute("enabled") - ipcRenderer.send("button-clicked", [b.getAttribute("for")]) + ipcRenderer.send("button-clicked", [{ + for: b.getAttribute("for"), + plugin: b.getAttribute("plugin") + }]) return } b.setAttribute("enabled", "") - ipcRenderer.send("button-clicked", [b.getAttribute("for")]) + ipcRenderer.send("button-clicked", [{for: b.getAttribute("for"), plugin: b.getAttribute("plugin")}]) } }) document.querySelectorAll("#clickable").forEach(b => { b.onclick = (e) => { if (b.getAttribute("enabled") !== null) { b.removeAttribute("enabled") - ipcRenderer.send("button-clicked", [b.getAttribute("for")]) + ipcRenderer.send("button-clicked", [{ + for: b.getAttribute("for"), + plugin: b.getAttribute("plugin") + }]) return } b.setAttribute("enabled", "") - ipcRenderer.send("button-clicked", [b.getAttribute("for")]) + ipcRenderer.send("button-clicked", [{for: b.getAttribute("for"), plugin: b.getAttribute("plugin")}]) } }) observer4.disconnect() @@ -212,7 +549,7 @@ document.addEventListener("DOMContentLoaded", () => { observer4.observe(document.documentElement, {childList: true, subtree: true}) observer6.observe(document.documentElement, {childList: true, subtree: true}) - if(document.querySelector("#av-id > ytmusic-av-toggle")) { + if (document.querySelector("#av-id > ytmusic-av-toggle")) { observer5.observe(document.querySelector("#av-id > ytmusic-av-toggle"), {childList: true, subtree: true}) } diff --git a/package-lock.json b/package-lock.json index e386786..7674d9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "youtube-music", - "version": "3.0.4", + "version": "3.0.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "youtube-music", - "version": "3.0.4", + "version": "3.0.5", "license": "ISC", "dependencies": { "@cliqz/adblocker-electron": "^1.26.8", diff --git a/package.json b/package.json index 49871aa..7c56fe2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "youtube-music", - "version": "3.0.5", + "version": "3.0.6", "description": "YouTube Music's app but with more options and modifications which can improve your experience.", "main": "Index.js", "scripts": { diff --git a/plugins/adblocker/Plugin.js b/plugins/adblocker/Plugin.js index 361b927..f6058b3 100644 --- a/plugins/adblocker/Plugin.js +++ b/plugins/adblocker/Plugin.js @@ -1,50 +1,16 @@ -const {get, set} = require("../../scripts/database/PluginManager") -const path = require("path"); +const loadAdblocker = require("./functions/load") +const {get} = require("../../scripts/database/PluginManager"); -module.exports.plugin = { - name: "Ad Blocker" -} - -module.exports.handle = () => { - const {browserWindow} = require("../../Index") - if (get("adblocker") === true) { - set("adblocker", false) - const electron = require("electron") - electron.dialog.showMessageBox({title: "YouTube Music", message: "Please reload the app to disable adBlocker.", icon: path.join(__dirname, "..", "..", "icons", "tray.png")}) - } else { - set("adblocker", true) - this.load(browserWindow) - const electron = require("electron") - electron.dialog.showMessageBox({title: "YouTube Music", message: "Please reload the app to enable adBlocker.", icon: path.join(__dirname, "..", "..", "icons", "tray.png")}) - } -} - -module.exports.preload = (window) => { - if (get("adblocker") === true) { - this.load(window) - } else { - return +module.exports = { + handle: (setting) => { + const PluginSetting = require("./handlers/" + setting) + PluginSetting() + }, + enable: (window) => { + loadAdblocker(window) + }, + disable: () => {}, + preload: (window) => { + if(get("adblocker") === true) loadAdblocker(window) } -} - -module.exports.disable = () => { - return -} - -module.exports.enable = () => { - return -} - -module.exports.load = (window) => { - const {ElectronBlocker} = require('@cliqz/adblocker-electron') - const {fetch} = require("node-fetch") - const fs = require("fs/promises") - const blocker = ElectronBlocker.fromPrebuiltAdsAndTracking(fetch, { - path: 'adblocker.bin', - read: fs.readFile, - write: fs.writeFile, - }).then((blocker) => { - blocker.enableBlockingInSession(window.webContents.session); - console.log(`[AdBlocker] BlockingInSession from PrebuiltAdsAndTracking enabled.`) - }) } \ No newline at end of file diff --git a/plugins/adblocker/functions/load.js b/plugins/adblocker/functions/load.js new file mode 100644 index 0000000..c54d62f --- /dev/null +++ b/plugins/adblocker/functions/load.js @@ -0,0 +1,12 @@ +module.exports = (window) => { + const {ElectronBlocker} = require("@cliqz/adblocker-electron"); + const {fetch} = require("node-fetch"); + const fs = require("fs/promises"); + const blocker = ElectronBlocker.fromPrebuiltAdsAndTracking(fetch, { + path: 'adblocker.bin', + read: fs.readFile, + write: fs.writeFile, + }).then((blocker) => { + blocker.enableBlockingInSession(window.webContents.session); + }) +} \ No newline at end of file diff --git a/plugins/adblocker/handlers/adblocker.js b/plugins/adblocker/handlers/adblocker.js new file mode 100644 index 0000000..c34872e --- /dev/null +++ b/plugins/adblocker/handlers/adblocker.js @@ -0,0 +1,16 @@ +const {get, set} = require("../../../scripts/database/PluginManager"); +const path = require("path"); + +module.exports = () => { + const {browserWindow} = require("../../../Index"); + if (get("adblocker") === true) { + set("adblocker", false) + const electron = require("electron") + electron.dialog.showMessageBox({title: "YouTube Music", message: "Please reload the app to disable adBlocker.", icon: path.join(__dirname, "..", "..", "..", "..", "icons", "tray.png")}) + } else { + set("adblocker", true) + this.load(browserWindow) + const electron = require("electron") + electron.dialog.showMessageBox({title: "YouTube Music", message: "Please reload the app to enable adBlocker.", icon: path.join(__dirname, "..", "..", "..", "..", "icons", "tray.png")}) + } +} \ No newline at end of file diff --git a/plugins/ambient-mode/Plugin.js b/plugins/ambient-mode/Plugin.js new file mode 100644 index 0000000..8947ab8 --- /dev/null +++ b/plugins/ambient-mode/Plugin.js @@ -0,0 +1,9 @@ +module.exports = { + handle: (setting) => { + const PluginSetting = require("./handlers/" + setting) + PluginSetting.handle() + }, + preload: () => {}, + enable: () => {}, + disable: () => {} +} \ No newline at end of file diff --git a/plugins/ambient-mode/functions/clearCanvas.js b/plugins/ambient-mode/functions/clearCanvas.js new file mode 100644 index 0000000..17de196 --- /dev/null +++ b/plugins/ambient-mode/functions/clearCanvas.js @@ -0,0 +1,13 @@ +module.exports = () => { + const {browserWindow} = require("../../../Index") + + browserWindow.webContents.executeJavaScript(` + function clearCanvas() { + let ambientCanvas = document.querySelector("canvas") + let ambientContext = ambientCanvas.getContext("2d") + ambientContext.clearRect(0, 0, 800, 800) + } + + clearCanvas() + `) +} \ No newline at end of file diff --git a/plugins/ambient-mode/functions/drawCanvas.js b/plugins/ambient-mode/functions/drawCanvas.js new file mode 100644 index 0000000..b4c13ac --- /dev/null +++ b/plugins/ambient-mode/functions/drawCanvas.js @@ -0,0 +1,20 @@ +module.exports = () => { + const {browserWindow} = require("../../../Index") + + browserWindow.webContents.executeJavaScript(` + function drawToCanvas() { + if (document.querySelector("ytmusic-player-page").getAttribute("video-mode") === null) { + let ambientCanvas = document.querySelector("canvas") + let ambientContext = ambientCanvas.getContext("2d") + ambientContext.drawImage(document.querySelector("#song-image > yt-img-shadow > img"), 0,0, 800, 800) + } else { + let ambientCanvas = document.querySelector("canvas") + let ambientContext = ambientCanvas.getContext("2d") + ambientContext.drawImage(document.querySelector("video"), 0,0, 800, 800) + requestAnimationFrame(drawToCanvas) + } + } + + drawToCanvas() + `) +} \ No newline at end of file diff --git a/plugins/ambient-mode/handlers/ambient-mode.js b/plugins/ambient-mode/handlers/ambient-mode.js new file mode 100644 index 0000000..dcccec9 --- /dev/null +++ b/plugins/ambient-mode/handlers/ambient-mode.js @@ -0,0 +1,15 @@ +const {get, set} = require("../../../scripts/database/PluginManager"); + +module.exports.handle = () => { + if(get("ambient-mode") === false) { + set("ambient-mode", true) + const drawCanvas = require("../functions/drawCanvas") + drawCanvas() + return + } + if(get("ambient-mode") === true) { + set("ambient-mode", false) + const clearCanvas = require("../functions/clearCanvas") + clearCanvas() + } +} \ No newline at end of file diff --git a/plugins/bypass-premium-restrictions/Plugin.js b/plugins/bypass-premium-restrictions/Plugin.js index 2fa9161..312077b 100644 --- a/plugins/bypass-premium-restrictions/Plugin.js +++ b/plugins/bypass-premium-restrictions/Plugin.js @@ -1,107 +1,21 @@ -const {get, set} = require("../../scripts/database/PluginManager") -const electron = require("electron"); -const {browserWindow} = require("../../Index"); - -module.exports.plugin = { - name: "Bypass Premium Restrictions", -} - -module.exports.handle = (p) => { - const {browserWindow} = require("../../Index") - if (p === "disable-miniplayer") { +const {get} = require("../../scripts/database/PluginManager") +const enableMiniplayer = require("./functions/enableMiniplayer") +const enablePremium = require("./functions/enablePremium") + +module.exports = { + handle: (setting) => { + const PluginSetting = require("./handlers/" + setting) + PluginSetting() + }, + preload: () => {}, + enable: () => { if (get("disable-miniplayer") === true) { - set("disable-miniplayer", false) - this.disableMiniplayer(browserWindow) - return - } - if (get("disable-miniplayer") === false) { - set("disable-miniplayer", true) - this.enableMiniplayer(browserWindow) - return + const { browserWindow } = require("../../Index") + enableMiniplayer(browserWindow) } - } - if (p === "disable-premium-upgrade") { if (get("disable-premium-upgrade") === true) { - set("disable-premium-upgrade", false) - this.disablePremium(browserWindow) - return - } - if (get("disable-premium-upgrade") === false) { - set("disable-premium-upgrade", true) - this.enablePremium(browserWindow) + const { browserWindow } = require("../../Index") + enablePremium(browserWindow) } } -} - -module.exports.preload = () => { - return -} - -module.exports.enable = (window) => { - if (get("disable-miniplayer") === true) { - this.enableMiniplayer(window) - } - if (get("disable-premium-upgrade") === true) { - this.enablePremium(window) - } -} - -module.exports.enableMiniplayer = (window) => { - const code = [ - "document.querySelector('#player').removeAttribute('mini-player-required')", - "", - "document.querySelector('#player > div.song-media-controls.style-scope.ytmusic-player > div > tp-yt-paper-icon-button.player-close-button.style-scope.ytmusic-player').onclick = () => {", - "document.querySelector('#player').removeAttribute('player-ui-state')", - "};0" - ].join("\n") - - console.log(`[Miniplayer] Applied JS`) - window.webContents.executeJavaScript(code) -} - -module.exports.disableMiniplayer = (window) => { - const code = [ - "document.querySelector('#player').setAttribute('mini-player-required', '')", - "", - "document.querySelector('#player').setAttribute('player-ui-state', 'MINIPLAYER')", - "document.querySelector('#player > div.song-media-controls.style-scope.ytmusic-player > div > tp-yt-paper-icon-button.player-close-button.style-scope.ytmusic-player').onclick = () => {", - "return", - "};0" - ].join("\n") - - console.log(`[Miniplayer] Applied JS to disable`) - window.webContents.executeJavaScript(code) -} - -module.exports.enablePremium = (window) => { - const code = [ - "if(!document.querySelector(\"#items > ytmusic-guide-entry-renderer:nth-child(4) > tp-yt-paper-item\")) {\n", - " ipcRenderer.send(\"premium\")\n", - "}", - "document.querySelector(\"#items > ytmusic-guide-entry-renderer:nth-child(4) > tp-yt-paper-item\").setAttribute('hidden', '')", - "document.querySelector(\"#mini-guide-renderer > #sections > ytmusic-guide-section-renderer > #items > ytmusic-guide-entry-renderer:nth-child(4) > tp-yt-paper-item\").setAttribute('hidden', '')", - "document.querySelector(\"#right-content > ytmusic-settings-button\").onclick = () => {", - "if(document.querySelector(\"#items > ytd-compact-link-renderer:nth-child(2) > a\").href === 'https://music.youtube.com/music_premium') {", - "document.querySelector(\"#items > ytd-compact-link-renderer:nth-child(2)\").setAttribute('hidden', '')", - "}", - "};0" - ].join("\n") - - console.log(`[Premium] Removed all Upgrade elements`) - window.webContents.executeJavaScript(code) -} - -module.exports.disablePremium = (window) => { - const code = [ - "document.querySelector(\"#items > ytmusic-guide-entry-renderer:nth-child(4) > tp-yt-paper-item\").removeAttribute('hidden')", - "document.querySelector(\"#right-content > ytmusic-settings-button\").onclick = () => {", - "if(document.querySelector(\"#items > ytd-compact-link-renderer:nth-child(2) > a\").href === 'https://music.youtube.com/music_premium') {", - "document.querySelector(\"#items > ytd-compact-link-renderer:nth-child(2)\").removeAttribute('hidden')", - "document.querySelector(\"#mini-guide-renderer > #sections > ytmusic-guide-section-renderer > #items > ytmusic-guide-entry-renderer:nth-child(4) > tp-yt-paper-item\").removeAttribute('hidden')", - "}", - "};0" - ].join("\n") - - console.log(`[Premium] Added all Upgrade elements`) - window.webContents.executeJavaScript(code) } \ No newline at end of file diff --git a/plugins/bypass-premium-restrictions/functions/disableMiniplayer.js b/plugins/bypass-premium-restrictions/functions/disableMiniplayer.js new file mode 100644 index 0000000..82949c4 --- /dev/null +++ b/plugins/bypass-premium-restrictions/functions/disableMiniplayer.js @@ -0,0 +1,12 @@ +module.exports = (window) => { + const code = [ + "document.querySelector('#player').setAttribute('mini-player-required', '')", + "", + "document.querySelector('#player').setAttribute('player-ui-state', 'MINIPLAYER')", + "document.querySelector('#player > div.song-media-controls.style-scope.ytmusic-player > div > tp-yt-paper-icon-button.player-close-button.style-scope.ytmusic-player').onclick = () => {", + "return", + "};0" + ].join("\n") + + window.webContents.executeJavaScript(code) +} \ No newline at end of file diff --git a/plugins/bypass-premium-restrictions/functions/disablePremium.js b/plugins/bypass-premium-restrictions/functions/disablePremium.js new file mode 100644 index 0000000..75c9624 --- /dev/null +++ b/plugins/bypass-premium-restrictions/functions/disablePremium.js @@ -0,0 +1,13 @@ +module.exports = (window) => { + const code = [ + "document.querySelector(\"#items > ytmusic-guide-entry-renderer:nth-child(4) > tp-yt-paper-item\").removeAttribute('hidden')", + "document.querySelector(\"#right-content > ytmusic-settings-button\").onclick = () => {", + "if(document.querySelector(\"#items > ytd-compact-link-renderer:nth-child(2) > a\").href === 'https://music.youtube.com/music_premium') {", + "document.querySelector(\"#items > ytd-compact-link-renderer:nth-child(2)\").removeAttribute('hidden')", + "document.querySelector(\"#mini-guide-renderer > #sections > ytmusic-guide-section-renderer > #items > ytmusic-guide-entry-renderer:nth-child(4) > tp-yt-paper-item\").removeAttribute('hidden')", + "}", + "};0" + ].join("\n") + + window.webContents.executeJavaScript(code) +} \ No newline at end of file diff --git a/plugins/bypass-premium-restrictions/functions/enableMiniplayer.js b/plugins/bypass-premium-restrictions/functions/enableMiniplayer.js new file mode 100644 index 0000000..01e352d --- /dev/null +++ b/plugins/bypass-premium-restrictions/functions/enableMiniplayer.js @@ -0,0 +1,12 @@ +module.exports = (window) => { + const code = [ + "document.querySelector('#player').removeAttribute('mini-player-required')", + "document.querySelector('ytmusic-player-page').removeAttribute('mini-player-enabled')", + "", + "document.querySelector('#player > div.song-media-controls.style-scope.ytmusic-player > div > tp-yt-paper-icon-button.player-close-button.style-scope.ytmusic-player').onclick = () => {", + "document.querySelector('#player').removeAttribute('player-ui-state')", + "};0" + ].join("\n") + + window.webContents.executeJavaScript(code) +} \ No newline at end of file diff --git a/plugins/bypass-premium-restrictions/functions/enablePremium.js b/plugins/bypass-premium-restrictions/functions/enablePremium.js new file mode 100644 index 0000000..8e87415 --- /dev/null +++ b/plugins/bypass-premium-restrictions/functions/enablePremium.js @@ -0,0 +1,12 @@ +module.exports = (window) => { + const code = [ + "document.querySelector(\"#items > ytmusic-guide-entry-renderer:nth-child(4) > tp-yt-paper-item\").setAttribute('hidden', '')", + "document.querySelector(\"#right-content > ytmusic-settings-button\").onclick = () => {", + "if(document.querySelector(\"#items > ytd-compact-link-renderer:nth-child(2) > a\").href === 'https://music.youtube.com/music_premium') {", + "document.querySelector(\"#items > ytd-compact-link-renderer:nth-child(2)\").setAttribute('hidden', '')", + "}", + "};0" + ].join("\n") + + window.webContents.executeJavaScript(code) +} \ No newline at end of file diff --git a/plugins/bypass-premium-restrictions/handlers/disable-miniplayer.js b/plugins/bypass-premium-restrictions/handlers/disable-miniplayer.js new file mode 100644 index 0000000..1526ffa --- /dev/null +++ b/plugins/bypass-premium-restrictions/handlers/disable-miniplayer.js @@ -0,0 +1,17 @@ +const {get, set} = require("../../../scripts/database/PluginManager"); +const {browserWindow} = require("../../../Index"); + +const enableMiniplayer = require("../functions/enableMiniplayer") +const disableMiniplayer = require("../functions/disableMiniplayer") + +module.exports = () => { + if (get("disable-miniplayer") === true) { + set("disable-miniplayer", false) + disableMiniplayer(browserWindow) + return + } + if (get("disable-miniplayer") === false) { + set("disable-miniplayer", true) + enableMiniplayer(browserWindow) + } +} \ No newline at end of file diff --git a/plugins/bypass-premium-restrictions/handlers/disable-premium-upgrade.js b/plugins/bypass-premium-restrictions/handlers/disable-premium-upgrade.js new file mode 100644 index 0000000..ce98174 --- /dev/null +++ b/plugins/bypass-premium-restrictions/handlers/disable-premium-upgrade.js @@ -0,0 +1,17 @@ +const {get, set} = require("../../../scripts/database/PluginManager"); +const {browserWindow} = require("../../../Index"); + +const disablePremium = require("../functions/disablePremium") +const enablePremium = require("../functions/enablePremium") + +module.exports = () => { + if (get("disable-premium-upgrade") === true) { + set("disable-premium-upgrade", false) + disablePremium(browserWindow) + return + } + if (get("disable-premium-upgrade") === false) { + set("disable-premium-upgrade", true) + enablePremium(browserWindow) + } +} \ No newline at end of file diff --git a/plugins/close-background/Plugin.js b/plugins/close-background/Plugin.js new file mode 100644 index 0000000..032a30b --- /dev/null +++ b/plugins/close-background/Plugin.js @@ -0,0 +1,6 @@ +module.exports = { + handle: (setting) => { + const PluginSetting = require("./handlers/" + setting) + PluginSetting() + }, +} \ No newline at end of file diff --git a/plugins/close-background/handlers/close-background.js b/plugins/close-background/handlers/close-background.js new file mode 100644 index 0000000..b41bc36 --- /dev/null +++ b/plugins/close-background/handlers/close-background.js @@ -0,0 +1,9 @@ +const {set, get} = require("../../../scripts/database/PluginManager"); + +module.exports = () => { + if (get("close-background") === true) { + set("close-background", false) + } else { + set("close-background", true) + } +} \ No newline at end of file diff --git a/plugins/color-changer/Plugin.js b/plugins/color-changer/Plugin.js index 3a14bc7..e2c5354 100644 --- a/plugins/color-changer/Plugin.js +++ b/plugins/color-changer/Plugin.js @@ -1,91 +1,13 @@ -const {get, set} = require("../../scripts/database/PluginManager") -const {updateColors, resetColors, getSongInfo} = require("../../scripts/web/SongInfoManager"); - -module.exports.plugin = { - name: "Color Changer" -} - -module.exports.handle = () => { - if (get("color-changer") === false) { - set("color-changer", true) - this.turnOn() - return +const {clearColors} = require("./functions/clearColors") + +module.exports = { + handle: (setting) => { + const PluginSetting = require("./handlers/" + setting) + PluginSetting() + }, + preload: () => {}, + enable: () => {}, + disable: () => { + clearColors() } - if (get("color-changer") === true) { - set("color-changer", false) - this.disable() - } -} - -module.exports.handle_songs = () => { - if (get("color-changer-songs") === false) { - const i = getSongInfo() - set("color-changer-songs", true) - if (i.videoType === "MUSIC_VIDEO_TYPE_ATV") { - this.turnOn() - } - return - } - if (get("color-changer-songs") === true) { - const i = getSongInfo() - set("color-changer-songs", false) - if (i.videoType === "MUSIC_VIDEO_TYPE_ATV") { - this.disable() - } - } -} - -module.exports.handle_videos = () => { - if (get("color-changer-videos") === false) { - const i = getSongInfo() - set("color-changer-videos", true) - if (i.videoType !== "MUSIC_VIDEO_TYPE_ATV") { - if (i.videoType !== "MUSIC_VIDEO_TYPE_PRIVATELY_OWNED_TRACK") { - this.turnOn() - } - } - return - } - if (get("color-changer-videos") === true) { - const i = getSongInfo() - set("color-changer-videos", false) - if (i.videoType !== "MUSIC_VIDEO_TYPE_ATV") { - if (i.videoType !== "MUSIC_VIDEO_TYPE_PRIVATELY_OWNED_TRACK") { - this.disable() - } - } - } -} - -module.exports.handle_private = () => { - if (get("color-changer-private-songs") === false) { - const i = getSongInfo() - set("color-changer-private-songs", true) - if (i.videoType === "MUSIC_VIDEO_TYPE_PRIVATELY_OWNED_TRACK") { - this.turnOn() - } - return - } - if (get("color-changer-private-songs") === true) { - const i = getSongInfo() - set("color-changer-private-songs", false) - if (i.videoType === "MUSIC_VIDEO_TYPE_PRIVATELY_OWNED_TRACK") { - this.disable() - } - } -} - -module.exports.preload = () => { - return -} -module.exports.enable = () => { - return -} -module.exports.turnOn = () => { - const {browserWindow} = require("../../Index"); - updateColors(browserWindow) -} -module.exports.disable = () => { - const {browserWindow} = require("../../Index"); - resetColors(browserWindow) } \ No newline at end of file diff --git a/plugins/color-changer/functions/clearColors.js b/plugins/color-changer/functions/clearColors.js new file mode 100644 index 0000000..e3dccd8 --- /dev/null +++ b/plugins/color-changer/functions/clearColors.js @@ -0,0 +1,6 @@ +const {resetColors} = require("../../../scripts/web/Managers/SongInfo/ColorManager"); + +module.exports = () => { + const {browserWindow} = require("../../../Index"); + resetColors(browserWindow) +} \ No newline at end of file diff --git a/plugins/color-changer/functions/updateColors.js b/plugins/color-changer/functions/updateColors.js new file mode 100644 index 0000000..9a01729 --- /dev/null +++ b/plugins/color-changer/functions/updateColors.js @@ -0,0 +1,6 @@ +const {updateColors} = require("../../../scripts/web/Managers/SongInfo/ColorManager"); + +module.exports = () => { + const {browserWindow} = require("../../../Index"); + updateColors(browserWindow) +} \ No newline at end of file diff --git a/plugins/color-changer/handlers/color-changer-private-songs.js b/plugins/color-changer/handlers/color-changer-private-songs.js new file mode 100644 index 0000000..7dc0397 --- /dev/null +++ b/plugins/color-changer/handlers/color-changer-private-songs.js @@ -0,0 +1,22 @@ +const {get, set} = require("../../../scripts/database/PluginManager"); +const {getSongInfo} = require("../../../scripts/web/SongInfoManager"); + +module.exports = () => { + if (get("color-changer-private-songs") === false) { + const songInfo = getSongInfo() + set("color-changer-private-songs", true) + if (songInfo.videoType === "MUSIC_VIDEO_TYPE_PRIVATELY_OWNED_TRACK") { + const {updateColors} = require("../functions/updateColors"); + updateColors() + } + return + } + if (get("color-changer-private-songs") === true) { + const songInfo = getSongInfo() + set("color-changer-private-songs", false) + if (songInfo.videoType === "MUSIC_VIDEO_TYPE_PRIVATELY_OWNED_TRACK") { + const {clearColors} = require("../functions/clearColors") + clearColors() + } + } +} \ No newline at end of file diff --git a/plugins/color-changer/handlers/color-changer-songs.js b/plugins/color-changer/handlers/color-changer-songs.js new file mode 100644 index 0000000..65d6a06 --- /dev/null +++ b/plugins/color-changer/handlers/color-changer-songs.js @@ -0,0 +1,22 @@ +const {get, set} = require("../../../scripts/database/PluginManager"); +const {getSongInfo} = require("../../../scripts/web/SongInfoManager"); + +module.exports = () => { + if (get("color-changer-songs") === false) { + const songInfo = getSongInfo() + set("color-changer-songs", true) + if (songInfo.videoType === "MUSIC_VIDEO_TYPE_ATV") { + const {updateColors} = require("../functions/updateColors"); + updateColors() + } + return + } + if (get("color-changer-songs") === true) { + const songInfo = getSongInfo() + set("color-changer-songs", false) + if (songInfo.videoType === "MUSIC_VIDEO_TYPE_ATV") { + const {clearColors} = require("../functions/clearColors"); + clearColors() + } + } +} \ No newline at end of file diff --git a/plugins/color-changer/handlers/color-changer-videos.js b/plugins/color-changer/handlers/color-changer-videos.js new file mode 100644 index 0000000..1da5725 --- /dev/null +++ b/plugins/color-changer/handlers/color-changer-videos.js @@ -0,0 +1,26 @@ +const {get, set} = require("../../../scripts/database/PluginManager"); +const {getSongInfo} = require("../../../scripts/web/SongInfoManager"); + +module.exports = () => { + if (get("color-changer-videos") === false) { + const songInfo = getSongInfo() + set("color-changer-videos", true) + if (songInfo.videoType !== "MUSIC_VIDEO_TYPE_ATV") { + if (songInfo.videoType !== "MUSIC_VIDEO_TYPE_PRIVATELY_OWNED_TRACK") { + const {updateColors} = require("../functions/updateColors"); + updateColors() + } + } + return + } + if (get("color-changer-videos") === true) { + const songInfo = getSongInfo() + set("color-changer-videos", false) + if (songInfo.videoType !== "MUSIC_VIDEO_TYPE_ATV") { + if (songInfo.videoType !== "MUSIC_VIDEO_TYPE_PRIVATELY_OWNED_TRACK") { + const {clearColors} = require("../functions/clearColors"); + clearColors() + } + } + } +} \ No newline at end of file diff --git a/plugins/color-changer/handlers/color-changer.js b/plugins/color-changer/handlers/color-changer.js new file mode 100644 index 0000000..f7f033e --- /dev/null +++ b/plugins/color-changer/handlers/color-changer.js @@ -0,0 +1,15 @@ +const {get, set} = require("../../../scripts/database/PluginManager"); + +module.exports = () => { + if (get("color-changer") === false) { + set("color-changer", true) + const {updateColors} = require("../functions/updateColors"); + updateColors() + return + } + if (get("color-changer") === true) { + set("color-changer", false) + const {clearColors} = require("../functions/clearColors") + clearColors() + } +} \ No newline at end of file diff --git a/plugins/dev-tools/Plugin.js b/plugins/dev-tools/Plugin.js new file mode 100644 index 0000000..6f2b0a4 --- /dev/null +++ b/plugins/dev-tools/Plugin.js @@ -0,0 +1,7 @@ +const { browserWindow } = require("../../Index") + +module.exports = { + handle: (setting) => { + browserWindow.webContents.openDevTools({mode: "detach"}) + }, +} \ No newline at end of file diff --git a/plugins/disable-better-fullscreen/Plugin.js b/plugins/disable-better-fullscreen/Plugin.js new file mode 100644 index 0000000..032a30b --- /dev/null +++ b/plugins/disable-better-fullscreen/Plugin.js @@ -0,0 +1,6 @@ +module.exports = { + handle: (setting) => { + const PluginSetting = require("./handlers/" + setting) + PluginSetting() + }, +} \ No newline at end of file diff --git a/plugins/disable-better-fullscreen/handlers/disable-better-fullscreen.js b/plugins/disable-better-fullscreen/handlers/disable-better-fullscreen.js new file mode 100644 index 0000000..e380fa5 --- /dev/null +++ b/plugins/disable-better-fullscreen/handlers/disable-better-fullscreen.js @@ -0,0 +1,12 @@ +const {get, set} = require("../../../scripts/database/PluginManager"); +const { browserWindow } = require("../../../Index") + +module.exports = () => { + if (get("disable-better-fullscreen") === true) { + set("disable-better-fullscreen", false) + browserWindow.webContents.executeJavaScript(`document.querySelector("ytmusic-app-layout").removeAttribute("disable-better-fullscreen")`) + } else { + set("disable-better-fullscreen", true) + browserWindow.webContents.executeJavaScript(`document.querySelector("ytmusic-app-layout").setAttribute("disable-better-fullscreen", "")`) + } +} \ No newline at end of file diff --git a/plugins/disable-tray/Plugin.js b/plugins/disable-tray/Plugin.js new file mode 100644 index 0000000..032a30b --- /dev/null +++ b/plugins/disable-tray/Plugin.js @@ -0,0 +1,6 @@ +module.exports = { + handle: (setting) => { + const PluginSetting = require("./handlers/" + setting) + PluginSetting() + }, +} \ No newline at end of file diff --git a/plugins/disable-tray/handlers/disable-tray.js b/plugins/disable-tray/handlers/disable-tray.js new file mode 100644 index 0000000..68522a5 --- /dev/null +++ b/plugins/disable-tray/handlers/disable-tray.js @@ -0,0 +1,11 @@ +const {set, get} = require("../../../scripts/database/PluginManager"); +const {addTray, destroyTray} = require("../../../scripts/web/Managers/Window/windowManager") +module.exports = () => { + if (get("disable-tray") === true) { + set("disable-tray", false) + addTray(window) + } else { + set("disable-tray", true) + destroyTray() + } +} \ No newline at end of file diff --git a/plugins/disable-yt-sans/Plugin.js b/plugins/disable-yt-sans/Plugin.js new file mode 100644 index 0000000..5b7596b --- /dev/null +++ b/plugins/disable-yt-sans/Plugin.js @@ -0,0 +1,6 @@ +module.exports = { + handle: (setting) => { + const PluginSetting = require("./handlers/" + setting) + PluginSetting() + } +} \ No newline at end of file diff --git a/plugins/disable-yt-sans/handlers/disable-yt-sans.js b/plugins/disable-yt-sans/handlers/disable-yt-sans.js new file mode 100644 index 0000000..20eb699 --- /dev/null +++ b/plugins/disable-yt-sans/handlers/disable-yt-sans.js @@ -0,0 +1,9 @@ +const {get, set} = require("../../../scripts/database/PluginManager"); + +module.exports = () => { + if (get("disable-yt-sans") === true) { + set("disable-yt-sans", false) + } else { + set("disable-yt-sans", true) + } +} \ No newline at end of file diff --git a/plugins/discord-rpc/Plugin.js b/plugins/discord-rpc/Plugin.js index f030672..26226b1 100644 --- a/plugins/discord-rpc/Plugin.js +++ b/plugins/discord-rpc/Plugin.js @@ -1,213 +1,27 @@ -const {get, set} = require("../../scripts/database/PluginManager") +const {getConnectedPresence, connectPresence} = require("./functions/ConnectPresence"); +const {updatePresence} = require("./functions/UpdatePresence"); -module.exports.plugin = { +module.exports = { name: "Discord Rich Presence", -} - -const DiscordRPC = require("discord-rpc") -const {browserWindow} = require("../../Index"); -const RPC = new DiscordRPC.Client({transport: "ipc"}) -let ConnectedRPC = null -let i = null - -module.exports.handle = (m) => { - if(m === "discord-rpc") { - if (get("discord-rpc") === false) { - set("discord-rpc", true) - this.enable(browserWindow) - return - } - if (get("discord-rpc") === true) { - set("discord-rpc", false) - this.disable() - } - } - if(m === "discord-show-playback") { - if (get("discord-show-playback") === false) { - set("discord-show-playback", true) - this.updatePresence() - return - } - if (get("discord-show-playback") === true) { - set("discord-show-playback", false) - this.updatePresence() - } - } - if(m === "discord-show-cover") { - if (get("discord-show-cover") === false) { - set("discord-show-cover", true) - this.updatePresence() - return - } - if (get("discord-show-cover") === true) { - set("discord-show-cover", false) - this.updatePresence() - } - } - if(m === "discord-show-songdata") { - if (get("discord-show-songdata") === false) { - set("discord-show-songdata", true) - this.updatePresence() - return - } - if (get("discord-show-songdata") === true) { - set("discord-show-songdata", false) - this.updatePresence() - } - } - if(m === "discord-show-time") { - if (get("discord-show-time") === false) { - set("discord-show-time", true) - this.updatePresence() - return - } - if (get("discord-show-time") === true) { - set("discord-show-time", false) - this.updatePresence() - } - } -} - -module.exports.connectPresence = () => { - if (ConnectedRPC !== null) return - const s = require("electron-store") - const st = new s() - if (st.get("app.premium-user") === true) { - RPC.connect("1163966541675638874").then(u => { - ConnectedRPC = RPC - if(i !== null) { - console.log("[Discord] Interval will be cleared") - clearInterval(i) - } - console.log(`[Discord] Connection created`) - }).catch(e => { - if (e) return console.log(`[Discord] Connection was not created - ${e}`) - i = setInterval(() => { - this.connectPresence() - }, 30000) - ConnectedRPC = null - }) - } else { - RPC.connect("922907049170464809").then(u => { - ConnectedRPC = RPC - console.log(`[Discord] Connection created`) - - RPC.on("message", (m) => {console.log(`[Discord] ${m}`) }) - RPC.on("disconnect", () => { return ConnectedRPC = null }) - RPC.on("close", () => { return ConnectedRPC = null }) - - }).catch(e => { - if (e) return console.log(`[Discord] Connection was not created - ${e}`) - ConnectedRPC = null - }) + handle: (setting) => { + const PluginSetting = require("./handlers/" + setting) + PluginSetting() + }, + enable: (window) => { + if(getConnectedPresence() === null) { + connectPresence() + } + + const {changePlayState} = require("../../scripts/web/SongInfoManager"); + changePlayState(window, "play") + }, + disable: () => { + getConnectedPresence().clearActivity() + }, + preload: () => { + connectPresence() + }, + updatePresence: (state, progress) => { + updatePresence(state, progress) } - - - RPC.on("disconnect", () => { - ConnectedRPC = null - }) -} - -module.exports.updatePresence = (st, progress) => { - let lastProgress = 1 - let lastState = "" - - let state; - - const songInfoManager = require("../../scripts/web/SongInfoManager") - const songInfo = songInfoManager.getSongInfo() - - if (ConnectedRPC === null) return - if (songInfo.details === undefined) return - - let length = songInfo.details.lengthSeconds * 1000 - - let p - let u - - if (progress !== undefined) { - p = progress - lastProgress = progress - } else { - p = lastProgress - } - - if (st !== undefined) { - state = st - lastState = st - } else { - state = lastState - } - - let startTime = Date.now() - p * 1000 - let endTime = startTime + length - - if (songInfo.videoType !== "MUSIC_VIDEO_TYPE_PRIVATELY_OWNED_TRACK") { - u = songInfo.details.thumbnail.thumbnails[0].url.split("?")[0].split("=")[0] - } else { - u = songInfo.details.thumbnail.thumbnails[3].url - } - - if (st === "pause") { - ConnectedRPC.setActivity( - { - smallImageKey: get("discord-show-playback") === true ? "pause" : undefined, - smallImageText: get("discord-show-playback") === true ? "Paused" : undefined, - largeImageKey: u, - largeImageText: "@honzawashere", - type: 4, - details: get("discord-show-songdata") === true ? songInfo.details.title : "Listening to Music", - state: get("discord-show-songdata") === true ? songInfo.details.author : undefined, - } - ).catch(e => { - if (e) return console.log(e) - }) - } else if (st === "play") { - ConnectedRPC.setActivity( - { - smallImageKey: get("discord-show-playback") === true ? "play" : undefined, - smallImageText: get("discord-show-playback") === true ? "Playing" : undefined, - largeImageKey: get("discord-show-cover") === true ? u : "largebadge", - largeImageText: "@honzawashere", - type: 4, - details: get("discord-show-songdata") === true ? songInfo.details.title : "Listening to Music", - state: get("discord-show-songdata") === true ? songInfo.details.author : undefined, - startTimestamp: get("discord-show-time") === true ? startTime : undefined, - endTimestamp: get("discord-show-time") === true ? endTime : undefined - } - ).catch(e => { - if (e) return console.log(e) - }) - } else { - ConnectedRPC.setActivity( - { - smallImageKey: get("discord-show-playback") === true ? "play" : undefined, - smallImageText: get("discord-show-playback") === true ? "Playing" : undefined, - largeImageKey: get("discord-show-cover") === true ? u : "largebadge", - largeImageText: "@honzawashere", - type: 4, - details: get("discord-show-songdata") === true ? songInfo.details.title : "Listening to Music", - state: get("discord-show-songdata") === true ? songInfo.details.author : undefined, - startTimestamp: get("discord-show-time") === true ? startTime : undefined, - endTimestamp: get("discord-show-time") === true ? endTime : undefined - } - ).catch(e => { - if (e) return console.log(e) - }) - } -} - -module.exports.preload = () => { - this.connectPresence() -} - -module.exports.enable = (window) => { - const {changePlayState} = require("../../scripts/web/SongInfoManager"); - this.connectPresence() - changePlayState(window, "play") -} - -module.exports.disable = () => { - ConnectedRPC.clearActivity() - return } \ No newline at end of file diff --git a/plugins/discord-rpc/functions/ConnectPresence.js b/plugins/discord-rpc/functions/ConnectPresence.js new file mode 100644 index 0000000..c0093c8 --- /dev/null +++ b/plugins/discord-rpc/functions/ConnectPresence.js @@ -0,0 +1,51 @@ +const DiscordRPC = require("discord-rpc") +const rpcClient = new DiscordRPC.Client({transport: "ipc"}) + +let connectedRPC = null +let reconnectInterval = null + +module.exports.connectPresence = () => { + if (connectedRPC !== null) return + + const electronStore = require("electron-store") + const store = new electronStore() + + if (store.get("app.premium-user") === true) { + rpcClient.connect("1163966541675638874").then(u => { + connectedRPC = rpcClient + if (reconnectInterval !== null) { + clearInterval(reconnectInterval) + } + }).catch(e => { + if (e) return + reconnectInterval = setInterval(() => { + this.connectPresence() + }, 30000) + connectedRPC = null + }) + } else { + rpcClient.connect("922907049170464809").then(u => { + connectedRPC = rpcClient + + rpcClient.on("disconnect", () => { + return connectedRPC = null + }) + rpcClient.on("close", () => { + return connectedRPC = null + }) + + }).catch(e => { + if (e) return + connectedRPC = null + }) + } + + + rpcClient.on("disconnect", () => { + connectedRPC = null + }) +} + +module.exports.getConnectedPresence = () => { + return connectedRPC +} \ No newline at end of file diff --git a/plugins/discord-rpc/functions/UpdatePresence.js b/plugins/discord-rpc/functions/UpdatePresence.js new file mode 100644 index 0000000..60d1b0e --- /dev/null +++ b/plugins/discord-rpc/functions/UpdatePresence.js @@ -0,0 +1,92 @@ +const {get} = require("../../../scripts/database/PluginManager"); +const {getConnectedPresence} = require("./ConnectPresence"); + +let lastProgress = 1 +let lastState = "" + +module.exports.updatePresence = (state, progress) => { + let currentProgress; + let currentThumbnailURL; + let currentState; + + const {getSongInfo} = require("../../../scripts/web/SongInfoManager"); + const songInfo = getSongInfo() + + const connectedRPC = getConnectedPresence() + + if (connectedRPC === null) return + if (songInfo.details === undefined) return + + let length = songInfo.details.lengthSeconds * 1000 + + if (progress !== undefined) { + currentProgress = progress + lastProgress = progress + } else { + currentProgress = lastProgress + } + + if (currentState !== undefined) { + currentState = state + lastState = state + } else { + currentState = lastState + } + + let startTime = Date.now() - currentProgress * 1000 + let endTime = startTime + length + + if (songInfo.videoType !== "MUSIC_VIDEO_TYPE_PRIVATELY_OWNED_TRACK") { + currentThumbnailURL = songInfo.details.thumbnail.thumbnails[0].url.split("?")[0].split("=")[0] + } else { + currentThumbnailURL = songInfo.details.thumbnail.thumbnails[3].url + } + + if (state === "pause") { + connectedRPC.setActivity( + { + smallImageKey: get("discord-show-playback") === true ? "pause" : undefined, + smallImageText: get("discord-show-playback") === true ? "Paused" : undefined, + largeImageKey: get("discord-show-cover") === true ? currentThumbnailURL : "largebadge", + largeImageText: "@honzawashere", + type: 4, + details: get("discord-show-songdata") === true ? songInfo.details.title : "Listening to Music", + state: get("discord-show-songdata") === true ? songInfo.details.author : undefined, + } + ).catch(e => { + if (e) console.log(e) + }) + } else if (state === "play") { + connectedRPC.setActivity( + { + smallImageKey: get("discord-show-playback") === true ? "play" : undefined, + smallImageText: get("discord-show-playback") === true ? "Playing" : undefined, + largeImageKey: get("discord-show-cover") === true ? currentThumbnailURL : "largebadge", + largeImageText: "@honzawashere", + type: 4, + details: get("discord-show-songdata") === true ? songInfo.details.title : "Listening to Music", + state: get("discord-show-songdata") === true ? songInfo.details.author : undefined, + startTimestamp: get("discord-show-time") === true ? startTime : undefined, + endTimestamp: get("discord-show-time") === true ? endTime : undefined + } + ).catch(e => { + if (e) console.log(e) + }) + } else { + connectedRPC.setActivity( + { + smallImageKey: get("discord-show-playback") === true ? "play" : undefined, + smallImageText: get("discord-show-playback") === true ? "Playing" : undefined, + largeImageKey: get("discord-show-cover") === true ? currentThumbnailURL : "largebadge", + largeImageText: "@honzawashere", + type: 4, + details: get("discord-show-songdata") === true ? songInfo.details.title : "Listening to Music", + state: get("discord-show-songdata") === true ? songInfo.details.author : undefined, + startTimestamp: get("discord-show-time") === true ? startTime : undefined, + endTimestamp: get("discord-show-time") === true ? endTime : undefined + } + ).catch(e => { + if (e) console.log(e) + }) + } +} \ No newline at end of file diff --git a/plugins/discord-rpc/handlers/discord-rpc.js b/plugins/discord-rpc/handlers/discord-rpc.js new file mode 100644 index 0000000..1c1d7ae --- /dev/null +++ b/plugins/discord-rpc/handlers/discord-rpc.js @@ -0,0 +1,15 @@ +const {get, set} = require("../../../scripts/database/PluginManager"); +const {enable, disable} = require("../Plugin") + +module.exports = () => { + if (get("discord-rpc") === false) { + set("discord-rpc", true) + const {browserWindow} = require("../../../Index"); + enable(browserWindow) + return + } + if (get("discord-rpc") === true) { + set("discord-rpc", false) + disable() + } +} \ No newline at end of file diff --git a/plugins/discord-rpc/handlers/discord-show-cover.js b/plugins/discord-rpc/handlers/discord-show-cover.js new file mode 100644 index 0000000..e9d4091 --- /dev/null +++ b/plugins/discord-rpc/handlers/discord-show-cover.js @@ -0,0 +1,14 @@ +const {get, set} = require("../../../scripts/database/PluginManager"); +const {updatePresence} = require("../Plugin"); + +module.exports = () => { + if (get("discord-show-cover") === false) { + set("discord-show-cover", true) + updatePresence() + return + } + if (get("discord-show-cover") === true) { + set("discord-show-cover", false) + updatePresence() + } +} \ No newline at end of file diff --git a/plugins/discord-rpc/handlers/discord-show-playback.js b/plugins/discord-rpc/handlers/discord-show-playback.js new file mode 100644 index 0000000..1949c68 --- /dev/null +++ b/plugins/discord-rpc/handlers/discord-show-playback.js @@ -0,0 +1,14 @@ +const {get, set} = require("../../../scripts/database/PluginManager"); +const {updatePresence} = require("../Plugin"); + +module.exports = () => { + if (get("discord-show-playback") === false) { + set("discord-show-playback", true) + updatePresence() + return + } + if (get("discord-show-playback") === true) { + set("discord-show-playback", false) + updatePresence() + } +} \ No newline at end of file diff --git a/plugins/discord-rpc/handlers/discord-show-songdata.js b/plugins/discord-rpc/handlers/discord-show-songdata.js new file mode 100644 index 0000000..0a663a2 --- /dev/null +++ b/plugins/discord-rpc/handlers/discord-show-songdata.js @@ -0,0 +1,14 @@ +const {get, set} = require("../../../scripts/database/PluginManager"); +const {updatePresence} = require("../Plugin"); + +module.exports = () => { + if (get("discord-show-songdata") === false) { + set("discord-show-songdata", true) + updatePresence() + return + } + if (get("discord-show-songdata") === true) { + set("discord-show-songdata", false) + updatePresence() + } +} \ No newline at end of file diff --git a/plugins/discord-rpc/handlers/discord-show-time.js b/plugins/discord-rpc/handlers/discord-show-time.js new file mode 100644 index 0000000..276189c --- /dev/null +++ b/plugins/discord-rpc/handlers/discord-show-time.js @@ -0,0 +1,14 @@ +const {get, set} = require("../../../scripts/database/PluginManager"); +const {updatePresence} = require("../Plugin"); + +module.exports = () => { + if (get("discord-show-time") === false) { + set("discord-show-time", true) + updatePresence() + return + } + if (get("discord-show-time") === true) { + set("discord-show-time", false) + updatePresence() + } +} \ No newline at end of file diff --git a/plugins/downloader/Plugin.js b/plugins/downloader/Plugin.js index abeafad..f63a670 100644 --- a/plugins/downloader/Plugin.js +++ b/plugins/downloader/Plugin.js @@ -4,206 +4,12 @@ const {rmSync} = require("fs"); const child_process = require("child_process"); const path = require("path"); -module.exports.plugin = { - name: "Downloader", -} - -module.exports.preload = () => { - return -} - -module.exports.enable = () => { - return -} - -module.exports.downloadMp3 = (window) => { - const ytdl = require("ytdl-core") - const ffmpeg = require("fluent-ffmpeg") - //const sharp = require("sharp") - - const ffmpegPath = require('ffmpeg-static').replace( - 'app.asar', - 'app.asar.unpacked' - ) - - ffmpeg.setFfmpegPath(ffmpegPath) - - const os = require("os") - const songInfo = getSongInfo() - - if (!songInfo.details.videoId) { - const electron = require("electron") - electron.dialog.showMessageBox({title: "YouTube Music", message: "Please play some video to download.", icon: path.join(__dirname, "..", "..", "icons", "tray.png")}) - return - } - if (songInfo.videoType === "MUSIC_VIDEO_TYPE_PRIVATELY_OWNED_TRACK") { - const electron = require("electron") - electron.dialog.showMessageBox({ - title: "YouTube Music", - message: "This video is private (only for you). YouTube Music is not able to download this video." - }) - return - } - - window.setTitle(window.getTitle() + " - Downloading...") - - const stream = ytdl(songInfo.details.videoId, { - filter: "audioonly", - quality: "highestaudio" - }) - - const title = songInfo.details.title.replace(/[<>:"/\\|?*]/g, '') - - ffmpeg(stream) - .audioBitrate(256) - .save(os.homedir() + "/Downloads/" + `${title}.mp3`) - .on("end", async () => { - const fs = require("fs") - const ID3Writer = require("browser-id3-writer") - - const writer = new ID3Writer(fs.readFileSync(os.homedir() + "/Downloads/" + `${title}.mp3`)) - - writer.setFrame("TIT2", title) - writer.setFrame("TPE1", [songInfo.details.author]) - writer.setFrame("WPAY", "https://music.youtube.com/watch?v=" + songInfo.details.videoId) - - let album = null; - - window.webContents.executeJavaScript("document.querySelector(\"#layout > ytmusic-player-bar > div.middle-controls.style-scope.ytmusic-player-bar > div.content-info-wrapper.style-scope.ytmusic-player-bar > span > span.subtitle.style-scope.ytmusic-player-bar > yt-formatted-string > a:nth-child(3)\").innerHTML").then(album => { - writer.setFrame("TALB", album) - - window.webContents.executeJavaScript("document.querySelector(\"#layout > ytmusic-player-bar > div.middle-controls.style-scope.ytmusic-player-bar > div.content-info-wrapper.style-scope.ytmusic-player-bar > span > span.subtitle.style-scope.ytmusic-player-bar > yt-formatted-string > span:nth-child(5)\").innerHTML").then(year => { - writer.setFrame("TYER", year) - }).catch(e => { - if (e) return - }) - }).catch(e => { - if (e) return - }) - - const fetch = require("node-fetch") - - let findImage = await fetch(songInfo.details.thumbnail.thumbnails[0].url.split("?")[0].split("=")[0]) - let buff = Buffer.from(await findImage.arrayBuffer()) - - writer.setFrame('APIC', { - type: 3, - data: buff, - description: `${album === null ? '' : `${album}'s cover`}` - }); - - // const image = sharp(buff) - // - // image.metadata().then(metadata => { - // const { width, height } = metadata - // - // let size - // if(width > height) { - // size = { width: height, height: height } - // } else { - // size = { width: width, height: width } - // } - // - // return image.resize(size.width, size.height).toBuffer().then(img => { - // writer.setFrame('APIC', { - // type: 3, - // data: Buffer.from(img), - // description: `${album === null ? '' : `${album}'s cover`}` - // }); - // }).catch(e => { - // if(e) return console.log(e) - // }) - // }) - - writer.addTag(); - - window.setTitle(window.getTitle().replace("- Downloading...", "- Writing downloaded data...")) - const finalBuffer = Buffer.from(writer.arrayBuffer) - fs.writeFileSync(os.homedir() + "/Downloads/" + `${title}.mp3`, finalBuffer) - window.setTitle(window.getTitle().replace(" - Writing downloaded data...", "")) - }) -} - -module.exports.downloadMp4 = (window) => { - const ytdl = require("ytdl-core") - const ffmpeg = require("fluent-ffmpeg") - - const ffmpegPath = require('ffmpeg-static').replace( - 'app.asar', - 'app.asar.unpacked' - ) - - ffmpeg.setFfmpegPath(ffmpegPath) - - const songInfo = getSongInfo() - - const os = require("os") - - if (!songInfo.details.videoId) { - const electron = require("electron") - electron.dialog.showMessageBox({title: "YouTube Music", message: "Please play some video to download.", icon: path.join(__dirname, "..", "..", "icons", "tray.png")}) - return - } - if (songInfo.videoType === "MUSIC_VIDEO_TYPE_PRIVATELY_OWNED_TRACK") { - const electron = require("electron") - electron.dialog.showMessageBox({ - title: "YouTube Music", - message: "This video is private (only for you). YouTube Music is not able to download this video." - }) - return - } - - const stream = ytdl(songInfo.details.videoId, { - filter: "videoonly", - quality: "highest" - }) - - const stream2 = ytdl(songInfo.details.videoId, { - filter: "audioonly", - quality: "highest" - }) - - const title = songInfo.details.title.replace(/[<>:"/\\|?*]/g, '') - window.setTitle(window.getTitle() + " - Downloading and writing video data...") - - const videoId = songInfo.details.videoId - - ffmpeg(stream) - .videoCodec("copy") - .save(join(__dirname, videoId + "-video.mp4")) - .on("end", () => { - ffmpeg(stream2) - .audioCodec("aac") - .save(join(__dirname, videoId + "-audio.mp4")) - .on("end", () => { - const ffmpegCommand = `"` + join(__dirname, "ffmpeg.exe") + `"`; - const ffmpegArguments = [ - '-i', `"` + join(__dirname, videoId + "-audio.mp4") + `"`, - '-i', `"` + join(__dirname, videoId + "-video.mp4") + `"`, - `"` + os.homedir() + "/Downloads/" + `${title}.mp4` + `"`, - ]; - - const ffmpegProcess = child_process.spawn(ffmpegCommand, ffmpegArguments, { shell: true }) - - ffmpegProcess.stdout.on("data", (d) => { - console.log(d) - }) - - ffmpegProcess.on('error', (err) => { - console.error('Error executing ffmpeg: ' + err); - }); - - ffmpegProcess.on('exit', (code) => { - if (code === 0) { - console.log('Video and audio merged successfully.') - rmSync("./" + videoId + "-video.mp4") - rmSync("./" + videoId + "-audio.mp4") - } else { - console.error('Error during ffmpeg execution.') - } - }); - }) - }) -} - -//C:\ffmpeg\bin\ \ No newline at end of file +module.exports = { + handle: (option) => { + const PluginOption = require("./handlers/" + option) + PluginOption() + }, + preload: () => {}, + enable: () => {}, + disable: () => {} +} \ No newline at end of file diff --git a/plugins/downloader/functions/createNewPrompt.js b/plugins/downloader/functions/createNewPrompt.js new file mode 100644 index 0000000..eb5d9dd --- /dev/null +++ b/plugins/downloader/functions/createNewPrompt.js @@ -0,0 +1,4 @@ +module.exports.createNewPrompt = (codecs) => { + const { browserWindow } = require("../../../Index") + +} \ No newline at end of file diff --git a/plugins/downloader/functions/downloadMP3.js b/plugins/downloader/functions/downloadMP3.js new file mode 100644 index 0000000..9c4bc35 --- /dev/null +++ b/plugins/downloader/functions/downloadMP3.js @@ -0,0 +1,91 @@ +const {getSongInfo} = require("../../../scripts/web/SongInfoManager"); +const path = require("path"); + +module.exports = (window) => { + const ytdl = require("ytdl-core") + const ffmpeg = require("fluent-ffmpeg") + + const ffmpegPath = require('ffmpeg-static').replace( + 'app.asar', + 'app.asar.unpacked' + ) + + ffmpeg.setFfmpegPath(ffmpegPath) + + const os = require("os") + const songInfo = getSongInfo() + + if (!songInfo.details.videoId) { + const electron = require("electron") + electron.dialog.showMessageBox({ + title: "YouTube Music", + message: "Please play some video to download.", + icon: path.join(__dirname, "..", "..", "..", "icons", "tray.png") + }) + return + } + if (songInfo.videoType === "MUSIC_VIDEO_TYPE_PRIVATELY_OWNED_TRACK") { + const electron = require("electron") + electron.dialog.showMessageBox({ + title: "YouTube Music", + message: "This video is private (only for you). YouTube Music is not able to download this video.", + icon: path.join(__dirname, "..", "..", "..", "icons", "tray.png") + }) + return + } + + window.setTitle(window.getTitle() + " - Downloading...") + + const stream = ytdl(songInfo.details.videoId, { + filter: "audioonly", + quality: "highestaudio" + }) + + const title = songInfo.details.title.replace(/[<>:"/\\|?*]/g, '') + + ffmpeg(stream) + .audioBitrate(256) + .save(os.homedir() + "/Downloads/" + `${title}.mp3`) + .on("end", async () => { + const fs = require("fs") + const ID3Writer = require("browser-id3-writer") + + const writer = new ID3Writer(fs.readFileSync(os.homedir() + "/Downloads/" + `${title}.mp3`)) + + writer.setFrame("TIT2", title) + writer.setFrame("TPE1", [songInfo.details.author]) + writer.setFrame("WPAY", "https://music.youtube.com/watch?v=" + songInfo.details.videoId) + + let album = null; + + window.webContents.executeJavaScript("document.querySelector(\"#layout > ytmusic-player-bar > div.middle-controls.style-scope.ytmusic-player-bar > div.content-info-wrapper.style-scope.ytmusic-player-bar > span > span.subtitle.style-scope.ytmusic-player-bar > yt-formatted-string > a:nth-child(3)\").innerHTML").then(album => { + writer.setFrame("TALB", album) + + window.webContents.executeJavaScript("document.querySelector(\"#layout > ytmusic-player-bar > div.middle-controls.style-scope.ytmusic-player-bar > div.content-info-wrapper.style-scope.ytmusic-player-bar > span > span.subtitle.style-scope.ytmusic-player-bar > yt-formatted-string > span:nth-child(5)\").innerHTML").then(year => { + writer.setFrame("TYER", year) + }).catch(e => { + if (e) return + }) + }).catch(e => { + if (e) return + }) + + const fetch = require("node-fetch") + + let findImage = await fetch(songInfo.details.thumbnail.thumbnails[0].url.split("?")[0].split("=")[0]) + let buff = Buffer.from(await findImage.arrayBuffer()) + + writer.setFrame('APIC', { + type: 3, + data: buff, + description: `${album === null ? '' : `${album}'s cover`}` + }); + + writer.addTag(); + + window.setTitle(window.getTitle().replace("- Downloading...", "- Writing downloaded data...")) + const finalBuffer = Buffer.from(writer.arrayBuffer) + fs.writeFileSync(os.homedir() + "/Downloads/" + `${title}.mp3`, finalBuffer) + window.setTitle(window.getTitle().replace(" - Writing downloaded data...", "")) + }) +} \ No newline at end of file diff --git a/plugins/downloader/functions/downloadMP4.js b/plugins/downloader/functions/downloadMP4.js new file mode 100644 index 0000000..5dca901 --- /dev/null +++ b/plugins/downloader/functions/downloadMP4.js @@ -0,0 +1,99 @@ +const {getSongInfo} = require("../../../scripts/web/SongInfoManager"); +const path = require("path"); +const {join} = require("path"); +const child_process = require("child_process"); +const {rmSync} = require("fs"); + +module.exports.getCodecs = async (window) => { + const ytdl = require("ytdl-core") + const songInfo = getSongInfo() + + if (!songInfo.details.videoId) { + const electron = require("electron") + electron.dialog.showMessageBox({ + title: "YouTube Music", + message: "Please play some video to download.", + icon: path.join(__dirname, "..", "..", "..", "icons", "tray.png") + }) + return + } + if (songInfo.videoType === "MUSIC_VIDEO_TYPE_PRIVATELY_OWNED_TRACK") { + const electron = require("electron") + electron.dialog.showMessageBox({ + title: "YouTube Music", + message: "This video is private (only for you). YouTube Music is not able to download this video.", + icon: path.join(__dirname, "..", "..", "..", "icons", "tray.png") + }) + return + } + + const info = await ytdl.getInfo(songInfo.details.videoId) + + const codecs = info.formats + const validCodecs = [] + + codecs.forEach(codec => { + if (codec.videoCodec !== "vp9" && codec.videoCodec !== null) { + validCodecs.push(codec) + } + }) + + createNewPrompt(validCodecs) +} + +module.exports.downloadMP4 = async (window, codec) => { + const ytdl = require("ytdl-core") + const ffmpeg = require("fluent-ffmpeg") + + const ffmpegPath = require('ffmpeg-static').replace('app.asar', 'app.asar.unpacked') + + ffmpeg.setFfmpegPath(ffmpegPath) + + const songInfo = getSongInfo() + + const os = require("os") + + const stream = ytdl.chooseFormat(codec) + + const stream2 = ytdl(songInfo.details.videoId, { + filter: "audioonly", quality: "highest" + }) + + const title = songInfo.details.title.replace(/[<>:"/\\|?*]/g, '') + window.setTitle(window.getTitle() + " - Downloading and writing video data...") + + const videoId = songInfo.details.videoId + + ffmpeg(stream.url) + .videoCodec("copy") + .save(join(__dirname, "..", videoId + "-video.mp4")) + .on("end", () => { + ffmpeg(stream2) + .audioCodec("aac") + .save(join(__dirname, "..", videoId + "-audio.mp4")) + .on("end", () => { + const ffmpegCommand = `"` + join(__dirname, "..", "ffmpeg.exe") + `"`; + const ffmpegArguments = ['-i', `"` + join(__dirname, "..", videoId + "-audio.mp4") + `"`, '-i', `"` + join(__dirname, "..", videoId + "-video.mp4") + `"`, `"` + os.homedir() + "/Downloads/" + `${title}.mp4` + `"`,]; + + const ffmpegProcess = child_process.spawn(ffmpegCommand, ffmpegArguments, {shell: true}) + + ffmpegProcess.stdout.on("data", (d) => { + console.log(d) + }) + + ffmpegProcess.on('error', (err) => { + console.error('Error executing ffmpeg: ' + err); + }); + + ffmpegProcess.on('exit', (code) => { + if (code === 0) { + console.log('Video and audio merged successfully.') + rmSync(join(__dirname, "..", videoId + "-audio.mp4")) + rmSync(join(__dirname, "..", videoId + "-video.mp4")) + } else { + console.error('Error during ffmpeg execution.') + } + }); + }) + }) +} \ No newline at end of file diff --git a/plugins/downloader/handlers/download-mp3.js b/plugins/downloader/handlers/download-mp3.js new file mode 100644 index 0000000..cd89f1f --- /dev/null +++ b/plugins/downloader/handlers/download-mp3.js @@ -0,0 +1,6 @@ +const downloadMP3 = require("../functions/downloadMP3") + +module.exports = () => { + const { browserWindow } = require("../../../Index") + downloadMP3(browserWindow) +} \ No newline at end of file diff --git a/plugins/downloader/handlers/download-mp4.js b/plugins/downloader/handlers/download-mp4.js new file mode 100644 index 0000000..e5b2440 --- /dev/null +++ b/plugins/downloader/handlers/download-mp4.js @@ -0,0 +1,6 @@ +const downloadMP4 = require("../functions/downloadMP4") + +module.exports = () => { + const { browserWindow } = require("../../../Index") + downloadMP4.getCodecs(browserWindow) +} \ No newline at end of file diff --git a/plugins/gaming-mode/Plugin.js b/plugins/gaming-mode/Plugin.js index 00a5879..ba83c39 100644 --- a/plugins/gaming-mode/Plugin.js +++ b/plugins/gaming-mode/Plugin.js @@ -1,19 +1,17 @@ -const {get, set} = require("../../scripts/database/PluginManager"); -const path = require("path"); -module.exports.plugin = { - name: "Gamer Mode", -} - -module.exports.handle = () => { - if (get("gamer-mode") === false) { - set("gamer-mode", true) +module.exports = { + handle: (setting) => { + const PluginSetting = require("./handlers/" + setting) + PluginSetting() + }, + enable: () => { const electron = require("electron") + const path = require("path"); electron.dialog.showMessageBox({ title: "YouTube Music", message: "Relaunching of the app is recommended.", icon: path.join(__dirname, "..", "..", "icons", "tray.png") }) - return - } - if (get("gamer-mode") === true) { - set("gamer-mode", false) + }, + disable: () => { const electron = require("electron") + const path = require("path"); electron.dialog.showMessageBox({ title: "YouTube Music", message: "Relaunching of the app is recommended.", icon: path.join(__dirname, "..", "..", "icons", "tray.png") }) - } + }, + preload: () => {} } \ No newline at end of file diff --git a/plugins/gaming-mode/handlers/gamer-mode.js b/plugins/gaming-mode/handlers/gamer-mode.js new file mode 100644 index 0000000..d2867af --- /dev/null +++ b/plugins/gaming-mode/handlers/gamer-mode.js @@ -0,0 +1,10 @@ +const {get, set} = require("../../../scripts/database/PluginManager"); + +module.exports = () => { + if (get("gamer-mode") === false) { + set("gamer-mode", true) + } + if (get("gamer-mode") === true) { + set("gamer-mode", false) + } +} \ No newline at end of file diff --git a/plugins/premium-features/Plugin.js b/plugins/premium-features/Plugin.js index eec23df..ba83c39 100644 --- a/plugins/premium-features/Plugin.js +++ b/plugins/premium-features/Plugin.js @@ -1,18 +1,17 @@ -const {get, set} = require("../../scripts/database/PluginManager"); -module.exports.plugin = { - name: "Premium Features", -} - -module.exports.handle = () => { - if (get("show-premium-tag") === false) { - set("show-premium-tag", true) +module.exports = { + handle: (setting) => { + const PluginSetting = require("./handlers/" + setting) + PluginSetting() + }, + enable: () => { const electron = require("electron") - electron.dialog.showMessageBox({ title: "YouTube Music", message: "Relaunching of the app is recommended." }) - return - } - if (get("show-premium-tag") === true) { - set("show-premium-tag", false) + const path = require("path"); + electron.dialog.showMessageBox({ title: "YouTube Music", message: "Relaunching of the app is recommended.", icon: path.join(__dirname, "..", "..", "icons", "tray.png") }) + }, + disable: () => { const electron = require("electron") - electron.dialog.showMessageBox({ title: "YouTube Music", message: "Relaunching of the app is recommended." }) - } + const path = require("path"); + electron.dialog.showMessageBox({ title: "YouTube Music", message: "Relaunching of the app is recommended.", icon: path.join(__dirname, "..", "..", "icons", "tray.png") }) + }, + preload: () => {} } \ No newline at end of file diff --git a/plugins/premium-features/handlers/show-premium-tag.js b/plugins/premium-features/handlers/show-premium-tag.js new file mode 100644 index 0000000..7328b9c --- /dev/null +++ b/plugins/premium-features/handlers/show-premium-tag.js @@ -0,0 +1,10 @@ +const {get, set} = require("../../../scripts/database/PluginManager"); + +module.exports = () => { + if (get("show-premium-tag") === false) { + set("show-premium-tag", true) + } + if (get("show-premium-tag") === true) { + set("show-premium-tag", false) + } +} \ No newline at end of file diff --git a/plugins/resume-playback-on-launch/Plugin.js b/plugins/resume-playback-on-launch/Plugin.js index d606bc3..0920bd3 100644 --- a/plugins/resume-playback-on-launch/Plugin.js +++ b/plugins/resume-playback-on-launch/Plugin.js @@ -1,13 +1,9 @@ -const {get, set} = require("../../scripts/database/PluginManager") - -module.exports.plugin = { - name: "Save Last Song", -} - -module.exports.handle = () => { - if(get("resume-playback-on-launch") === false) { - set("resume-playback-on-launch", true) - } else { - set("resume-playback-on-launch", false) - } +module.exports = { + handle: (setting) => { + const PluginSetting = require("./handlers/" + setting) + PluginSetting() + }, + enable: () => {}, + disable: () => {}, + preload: () => {} } \ No newline at end of file diff --git a/plugins/resume-playback-on-launch/handlers/resume-playback-on-launch.js b/plugins/resume-playback-on-launch/handlers/resume-playback-on-launch.js new file mode 100644 index 0000000..b171a4f --- /dev/null +++ b/plugins/resume-playback-on-launch/handlers/resume-playback-on-launch.js @@ -0,0 +1,10 @@ +const {get, set} = require("../../../scripts/database/PluginManager"); + +module.exports = () => { + if (get("resume-playback-on-launch") === false) { + set("resume-playback-on-launch", true) + } + if (get("resume-playback-on-launch") === true) { + set("resume-playback-on-launch", false) + } +} \ No newline at end of file