diff --git a/CSS/youtube.css b/CSS/youtube.css index b0a275c..da75d85 100644 --- a/CSS/youtube.css +++ b/CSS/youtube.css @@ -91,12 +91,12 @@ ytd-comment-renderer #content-text { /* subscribe button */ ytd-subscribe-button-renderer { - background-color: #6b5b95 !important; + background-color: #6b5b9500 !important; color: #ffffff !important; } -ytd-subscribe-button-renderer:hover { - background-color: #9d7bcf !important; +ytd-subscribe-button-renderer:hover * { + color: #8f4df3 !important; } #search-form { diff --git a/JS/clientAdBlock.js b/JS/clientAdBlock.js index 8c5b01f..6cbb2b1 100644 --- a/JS/clientAdBlock.js +++ b/JS/clientAdBlock.js @@ -11,12 +11,12 @@ function checkAdBlock(url, target, features, originalWindowOpen) { // needs to be inside the function or it'll get assigned twice async function setupAdBlock(perms) { - // attach listeners to the document body for each event type - ['click', 'mousedown', 'mouseup', 'dblclick', 'keydown', 'keyup', 'submit'].forEach((eventType) => { - document.body.addEventListener(eventType, (e) => { - console.log(`Event ${e.type} triggered by:`, e.target); - }, true); // use capture phase - }); + // // attach listeners to the document body for each event type + // ['click', 'mousedown', 'mouseup', 'dblclick', 'keydown', 'keyup', 'submit'].forEach((eventType) => { + // document.body.addEventListener(eventType, (e) => { + // console.log(`Event ${e.type} triggered by:`, e.target); + // }, true); // use capture phase + // }); const originalWindowOpen = window.open, isValidURL = (u) => { try { return new URL(u); } catch (_) { return false; } } diff --git a/JS/preload.cjs b/JS/preload.cjs index e20bf03..a65ff77 100644 --- a/JS/preload.cjs +++ b/JS/preload.cjs @@ -14,6 +14,10 @@ process.once("loaded", () => { const element = document.querySelector(selector); if (element) element.innerHTML += policy.createHTML(htmlString); }, + overwriteinner: (selector, htmlString) => { + const element = document.querySelector(selector); + if (element) element.innerHTML = policy.createHTML(htmlString); + }, insertBefore: (selector, htmlString) => { const element = document.querySelector(selector); if (element) element.innerHTML = policy.createHTML(htmlString) + element.innerHTML; diff --git a/addon/addonmanager.js b/addon/addonmanager.js new file mode 100644 index 0000000..b9ffe34 --- /dev/null +++ b/addon/addonmanager.js @@ -0,0 +1,37 @@ +import { isValidURL } from "../utils/misc.js"; +import { findPath } from "../utils/paths.js"; + + +import fs from 'fs'; +const youtube = fs.readFileSync(await findPath('youtubeutils.js')); + +/** + * @param {Electron.WebContents} contents + */ +const youtubeinject = (contents) => { + const f = () => contents.executeJavaScript(youtube).then(() => contents.executeJavaScript('injectDislike()')); + contents.addListener('did-finish-load', f); + contents.addListener('did-navigate', async (_) => { + const hostname = await contents.executeJavaScript('window.location.hostname'); + if (hostname !== 'www.youtube.com') return contents.removeListener('did-navigate', f); + else f(); + }) +} + + +/** + * @param {Electron.WebContents} contents + */ +export default async function addonManager(contents) { + try { + const hostname = await contents.executeJavaScript('window.location.hostname'); + + if (hostname === 'www.youtube.com') return youtubeinject(contents); + + return {}; + } + catch (err) { + console.error(err); + return {}; + } +} \ No newline at end of file diff --git a/addon/youtubeutils.js b/addon/youtubeutils.js new file mode 100644 index 0000000..d4885c2 --- /dev/null +++ b/addon/youtubeutils.js @@ -0,0 +1,74 @@ +function convertToNumber(text) { + const trimmedText = text.trim().toUpperCase(); + const suffixMultipliers = { + K: 1_000, + M: 1_000_000, + B: 1_000_000_000, + T: 1_000_000_000_000 + }; + const regex = /^(\d+(?:\.\d+)?)([KMBT]?)$/; + const match = trimmedText.match(regex); + + if (!match) { + throw new Error('Invalid format'); + } + + const [, numberPart, suffix] = match; + const num = parseFloat(numberPart); + + return num * (suffix ? suffixMultipliers[suffix] : 1); +} + + + +async function waitForEl(selector) { + return new Promise(resolve => { + const i = setInterval(() => { + if (document.querySelector(selector)) { + clearInterval(i); + resolve(true); + } + }, 500) + }); +} + + + +async function injectDislike() { + try { + const vid = new URLSearchParams(window.location.search)?.get('v'); + + if (!vid) return console.info('VID not found!') + const r = await fetch(`https://returnyoutubedislikeapi.com/votes?videoId=${vid}`, { + headers: { + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9', + 'Pragma': 'no-cache', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive' + }, + method: 'GET' + }); + + const data = await r.json(), + { dateCreated, dislikes, likes, viewCount } = data; + + // document.querySelector('like-button-view-model') + // ?.querySelector('.yt-spec-button-shape-next__button-text-content') + // ?.textContent + + const dislikelstr = 'dislike-button-view-model yt-touch-feedback-shape'; + await waitForEl(dislikelstr); + + const dislikel = document.querySelector(dislikelstr); + dislikel?.querySelectorAll('.yt-spec-button-shape-next__button-text-content')?.forEach(el => el?.remove()); + + window.safeHTML.write(dislikelstr, `
${dislikes}
`); + } + catch (err) { + console.error(err); + return { dislikes: -1 }; + } +} + + +window.addEventListener('DOMContentLoaded', injectDislike); \ No newline at end of file diff --git a/main.js b/main.js index d929ec5..de914b4 100644 --- a/main.js +++ b/main.js @@ -10,6 +10,7 @@ import { } from './serverJS/imports.js'; import { getSitePerms, promptForPerms } from './utils/dialogue.js'; import { getCurrentWindow } from './serverJS/tabs_server.js'; +import addonManager from './addon/addonmanager.js'; // await (await import('./utils/args.js')).handleArgs(); @@ -63,10 +64,10 @@ async function createWindow(customSession) { if (r) loadTabs(customSession, tabs); } else { - mainWebView.webContents.loadURL('https://hianime.to'); + // mainWebView.webContents.loadURL('https://hianime.to'); // mainWebView.webContents.loadURL('https://duckduckgo.com/?t=h_&hps=1&start=1&q=hi&ia=web'); // mainWebView.webContents.loadURL('https://www.youtube.com/watch?v=aPO5JaShu2U', { userAgent: agent }); - // mainWebView.webContents.loadURL('https://www.youtube.com', { userAgent: agent }); + mainWebView.webContents.loadURL('https://www.youtube.com', { userAgent: agent }); // mainWebView.webContents.loadURL('https://electronjs.org'); mainWebView.webContents.setBackgroundThrottling(true); mainWindow.currentView = mainWebView; @@ -128,6 +129,7 @@ app.whenReady().then(async () => { app.on('web-contents-created', async (e, contents) => { // contents.openDevTools({ mode: 'detach' }); setUpShortcuts(uid); + contents.addListener('did-finish-load', () => addonManager(contents)); const u = await contents.executeJavaScript('window.location.href'); if (contents.getType() === 'webview') handleWebViewInit(contents); }); diff --git a/serverJS/intercept.js b/serverJS/intercept.js index 7330ce2..c60b086 100644 --- a/serverJS/intercept.js +++ b/serverJS/intercept.js @@ -4,9 +4,9 @@ import fs from "fs"; import * as history from "./history.cjs"; const { addHistory } = history; import { net, shell } from "electron"; -import spawnworker from "./spawnworker.js"; import { checkInternetConnectivity } from "../utils/misc.js"; import loggermod from '../utils/logger.cjs'; +import addonManager from "../addon/addonmanager.js"; const { logger } = loggermod; export const noworker = ['www.youtube.com', 'accounts.youtube.com', 'accounts.google.com', '.*\.googlevideo\.com']; @@ -33,11 +33,12 @@ export default async function intercept(request, uid) { if (u.hostname.startsWith('ion-adblock')) { const links = await request.json(); - console.log(links); + // console.log(links); const r = links.map(l => ([l, blocked(l)])); return new Response(JSON.stringify(r)); } + else if (u.hostname.startsWith('ion-addons')) return new Response(JSON.stringify(await addonManager(request))); else if (u.protocol === 'file:' || u.hostname.startsWith('ion-local')) { const filePath = await findPath(u.pathname.split('/')?.at(-1), true); diff --git a/utils/misc.js b/utils/misc.js index 9d1eb40..7cd3ecd 100644 --- a/utils/misc.js +++ b/utils/misc.js @@ -30,7 +30,7 @@ export async function addEl(window, hostname) { } const p = path.resolve(import.meta.dirname, '../CSS', src); - console.log(p); + if (src && fs.existsSync(p)) { const srccontent = fs.readFileSync(p).toString(); window.webContents.insertCSS(srccontent);