diff --git a/config/defaults.js b/config/defaults.js index f053324150..f106e58e42 100644 --- a/config/defaults.js +++ b/config/defaults.js @@ -76,6 +76,10 @@ const defaultConfig = { "music_offtopic", ], }, + "local-subscriptions": { + enabled: false, + subscriptions: {} + } }, }; diff --git a/plugins/local-subscriptions/actions.js b/plugins/local-subscriptions/actions.js new file mode 100644 index 0000000000..913ac21690 --- /dev/null +++ b/plugins/local-subscriptions/actions.js @@ -0,0 +1,24 @@ +const { triggerAction } = require("../utils"); + +const CHANNEL = 'local-subscriptions' +const ACTIONS = { + SUBS_WIN_BTN: 'subscriptions-window-button', + SUBS_LI_CLK: 'subscriptions-list-item-click' +} + +function openSubscriptionsWindow() { + triggerAction(CHANNEL, ACTIONS.SUBS_WIN_BTN) +} + +function handleListItemClick(pathname) { + triggerAction(CHANNEL, ACTIONS.SUBS_LI_CLK, pathname) +} + +module.exports = { + CHANNEL, + ACTIONS, + actions: { + openSubscriptionsWindow, + handleListItemClick + } +}; diff --git a/plugins/local-subscriptions/back.js b/plugins/local-subscriptions/back.js new file mode 100644 index 0000000000..079c0db6bc --- /dev/null +++ b/plugins/local-subscriptions/back.js @@ -0,0 +1,57 @@ +const { BrowserWindow, ipcMain } = require("electron"); +const path = require("path"); +const defaultConfig = require("../../config/defaults"); +const { getOptions, setOptions } = require("../../config/plugins"); + +const { injectCSS, listenAction, templatePath } = require("../utils"); +const { ACTIONS, CHANNEL } = require("./actions.js"); + +let subscriptionsWindow; + +module.exports = win => { + // inject CSS in main window + injectCSS(win.webContents, path.join(__dirname, "style.css"), () => { + win.webContents.send("subscriptions-css-ready"); + }); + + listenAction(CHANNEL, (event, action, data) => { + switch(action) { + // Open new window and send there local subscriptions from options + case ACTIONS.SUBS_WIN_BTN: + subscriptionsWindow = new BrowserWindow({ + parent: win, + webPreferences: { + preload: path.join(__dirname, "popup.js"), + affinity: "main-window" + }}) + subscriptionsWindow.loadFile(templatePath(__dirname, "subscriptions-menu.html")) + subscriptionsWindow.webContents.on('did-stop-loading', () => subscriptionsWindow.webContents.send('saved-subscriptions', getOptions('local-subscriptions').subscriptions)) + break; + case ACTIONS.SUBS_LI_CLK: + subscriptionsWindow.close(); + console.log(action) + win.loadURL(defaultConfig.url + data); + break; + default: + console.log("Unknown action: " + action); + } + }) + + // Handles sub button click and saves changes in options + ipcMain.on('sub-btn-clk', (event, pathname, channelName) => { + const currentSubscriptions = getOptions('local-subscriptions'); + const newSubscription = {[pathname]: {channelName, subDate: new Date()}} + const didSubscribe = !!currentSubscriptions.subscriptions[pathname]; + + if (didSubscribe) { + delete currentSubscriptions.subscriptions[pathname]; + setOptions('local-subscriptions', {...currentSubscriptions}) + } else { + setOptions('local-subscriptions', {...currentSubscriptions, + subscriptions: {...currentSubscriptions.subscriptions, ...newSubscription}}); + } + }) + + win.webContents.on('did-stop-loading', () => win.webContents.send('subscriptions-page-stop-loading')) + win.webContents.on('did-navigate-in-page', () => win.webContents.send('subscriptions-location-change')); +}; diff --git a/plugins/local-subscriptions/front.js b/plugins/local-subscriptions/front.js new file mode 100644 index 0000000000..a8e8fd6d78 --- /dev/null +++ b/plugins/local-subscriptions/front.js @@ -0,0 +1,36 @@ +const { ipcRenderer } = require("electron"); +const { ElementFromFile, templatePath } = require("../utils"); + +// Send channel data to 'back' on 'sub-btn-clk' channel +const localSubscriptionButtonHandler = () => { + const channelName = document.querySelector('.title.style-scope.ytmusic-immersive-header-renderer').innerHTML + ipcRenderer.send('sub-btn-clk', window.location.pathname, channelName); +} + +module.exports = () => { + // On css load add local subscriptions button to the menu + ipcRenderer.on('subscriptions-css-ready', () => { + const localSubscriptionsButton = ElementFromFile(templatePath(__dirname, "subscriptions-tab.html")); + const menu = document.querySelector("ytmusic-pivot-bar-renderer"); + + if (menu) { + menu.appendChild(localSubscriptionsButton); + } + }); + + // On page loading finnish check if it is a channel page + // If it is add sub button to the page + ipcRenderer.on('subscriptions-page-stop-loading', () => { + const isChannelPage = window.location.pathname.includes('channel'); + + if (isChannelPage) { + const buttons = document.querySelector(".buttons.style-scope.ytmusic-immersive-header-renderer"); + if (buttons) { + const localSubscriptionButton = document.createElement('button') + localSubscriptionButton.innerText = 'Local Subscription' + localSubscriptionButton.onclick = localSubscriptionButtonHandler; + buttons.appendChild(localSubscriptionButton); + } + } + }); +}; diff --git a/plugins/local-subscriptions/popup.js b/plugins/local-subscriptions/popup.js new file mode 100644 index 0000000000..fdcc2e7945 --- /dev/null +++ b/plugins/local-subscriptions/popup.js @@ -0,0 +1,31 @@ +const { ipcRenderer, contextBridge } = require("electron"); +const { ElementFromHtml } = require("../utils"); +const {handleListItemClick} =require('./actions').actions; + + +// Couldn't manage to attach actions to global object +// Only contextBridge have worked + +// const actions = require('./actions.js').actions || {}; +// Object.keys(actions).forEach((actionName) => { +// console.log(actionName); +// globalThis.API = {}; +// globalThis.API[actionName] = actions[actionName]; +// }) + +contextBridge.exposeInMainWorld('SUBS_WIN', { + handleListItemClick +}) + +// Load subscriptions in a list on window load +ipcRenderer.on('saved-subscriptions', (evt, subs) => { + const subList = document.getElementById('subscriptions-list'); + + if (subList) { + Object.keys(subs).forEach(subKey => { + const sub = subs[subKey]; + const subEl = ElementFromHtml(`