71462d83de
Removed the Nebot chat plugin and its files, and added the Return YouTube Dislike plugin with main process logic, renderer preload, and manifest. Updated plugin manager and main process to support internal plugin pages and improved plugin event handling. Minor updates to renderer and documentation.
86 lines
3.0 KiB
JavaScript
86 lines
3.0 KiB
JavaScript
// Return YouTube Dislike - main process side
|
|
// Provides an IPC endpoint to fetch dislike data, bypassing page CSP.
|
|
// Also injects the renderer script into YouTube pages in webviews.
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
module.exports.activate = function(ctx) {
|
|
const CACHE_TTL_MS = 3 * 60 * 1000; // 3 minutes
|
|
const cache = new Map(); // key: videoId -> { t, data }
|
|
|
|
async function fetchVotes(videoId) {
|
|
const url = `https://returnyoutubedislikeapi.com/votes?videoId=${encodeURIComponent(videoId)}`;
|
|
let resp;
|
|
try {
|
|
resp = await fetch(url, { method: 'GET', headers: { 'Accept': 'application/json' } });
|
|
} catch (e) {
|
|
ctx.warn('[RYD] fetch failed', e);
|
|
return null;
|
|
}
|
|
if (!resp.ok) return null;
|
|
try { return await resp.json(); } catch { return null; }
|
|
}
|
|
|
|
ctx.registerIPC('return-youtube-dislike:get', async (_e, { videoId }) => {
|
|
if (!videoId || typeof videoId !== 'string') return { ok: false, error: 'bad_args' };
|
|
const now = Date.now();
|
|
const ent = cache.get(videoId);
|
|
if (ent && (now - ent.t) < CACHE_TTL_MS) {
|
|
return { ok: true, data: ent.data, cached: true };
|
|
}
|
|
const data = await fetchVotes(videoId);
|
|
if (!data) return { ok: false, error: 'fetch_failed' };
|
|
cache.set(videoId, { t: now, data });
|
|
return { ok: true, data };
|
|
});
|
|
|
|
// Load the renderer script
|
|
const rendererScriptPath = path.join(ctx.paths.pluginDir, 'renderer-preload.js');
|
|
let rendererScript = '';
|
|
try {
|
|
rendererScript = fs.readFileSync(rendererScriptPath, 'utf8');
|
|
} catch (e) {
|
|
ctx.error('[RYD] Failed to load renderer script:', e);
|
|
return;
|
|
}
|
|
|
|
// Listen for web contents creation to inject into YouTube pages
|
|
ctx.on('web-contents-created', (contents) => {
|
|
// Only inject into webviews (guest pages), not the main window
|
|
if (!contents.hostWebContents) return;
|
|
|
|
// Handle IPC messages from the injected script
|
|
contents.on('ipc-message', async (event, message) => {
|
|
if (message && message.data && message.data.channel === 'return-youtube-dislike:get') {
|
|
const { videoId, id } = message.data.args[0];
|
|
try {
|
|
const data = await fetchVotes(videoId);
|
|
if (data) {
|
|
event.reply('return-youtube-dislike:get', { ok: true, data, id });
|
|
} else {
|
|
event.reply('return-youtube-dislike:get', { ok: false, error: 'fetch_failed', id });
|
|
}
|
|
} catch (e) {
|
|
event.reply('return-youtube-dislike:get', { ok: false, error: e.message, id });
|
|
}
|
|
}
|
|
});
|
|
|
|
contents.on('dom-ready', () => {
|
|
const url = contents.getURL();
|
|
if (!url || !/^(?:.*\.)?youtube\.com$/.test(new URL(url).hostname)) return;
|
|
|
|
// Inject the script into the guest page
|
|
try {
|
|
contents.executeJavaScript(rendererScript);
|
|
ctx.log('[RYD] Injected script into YouTube page');
|
|
} catch (e) {
|
|
ctx.warn('[RYD] Failed to inject script:', e);
|
|
}
|
|
});
|
|
});
|
|
|
|
ctx.log('Return YouTube Dislike plugin activated');
|
|
};
|