Inserts each YouTube video ID, title, and channel name into your Supabase table exactly once
当前为
// ==UserScript==
// @name YouTube → Supabase Logger
// @description Inserts each YouTube video ID, title, and channel name into your Supabase table exactly once
// @match https://www.youtube.com/
// @run-at document-end
// @version 0.0.1.20250508195644
// @namespace https://greasyfork.org/users/1435046
// ==/UserScript==
(function() {
'use strict';
// Supabase configuration
const SUPABASE_URL = 'https://haughsijawbsqwumuryg.supabase.co';
const SUPABASE_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImhhdWdoc2lqYXdic3F3dW11cnlnIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzM0ODE3MjYsImV4cCI6MjA0OTA1NzcyNn0.stESUMuJEs4CNBWGtxZr1XNp2XpnQeXmKkq3fNaVE-c';
const TABLE = 'youtube_recommended_videos_table';
// Keep track of which IDs have already been sent
const seen = new Set();
// Extracts the “v” parameter from a YouTube URL
function getVideoId(href) {
try {
const u = new URL(href);
return u.searchParams.get('v');
} catch {
return null;
}
}
// Posts a row with id, title, and channel name
function insertVideoData(id, title, channel) {
fetch(`${SUPABASE_URL}/rest/v1/${TABLE}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': SUPABASE_KEY,
'Authorization': `Bearer ${SUPABASE_KEY}`
},
body: JSON.stringify([{
video_id_column: id,
video_title_column: title,
video_channel_name_column: channel
}])
});
}
// Scan all video items on the page
function logAndSend() {
const ITEM_SELECTOR = 'ytd-video-renderer, ytd-grid-video-renderer, ytd-compact-video-renderer';
const TITLE_LINK_SEL = 'a#video-title-link';
const CHANNEL_SEL = 'ytd-channel-name a';
document.querySelectorAll(ITEM_SELECTOR).forEach(item => {
const linkEl = item.querySelector(TITLE_LINK_SEL);
if (!linkEl) return;
const href = linkEl.href;
const id = getVideoId(href);
if (!id || seen.has(id)) return;
seen.add(id);
// Pull title from aria-label exactly as in your blocker script
const title = linkEl.getAttribute('aria-label').trim() || '‹no title›';
// Pull channel name
const chanEl = item.querySelector(CHANNEL_SEL);
const channel = chanEl ? chanEl.textContent.trim() : '‹no channel›';
insertVideoData(id, title, channel);
});
}
// Initial scan
logAndSend();
// Watch for new videos being loaded into the DOM
new MutationObserver(logAndSend)
.observe(document.body, { childList: true, subtree: true });
// Also re-scan after YouTube navigation events
window.addEventListener('yt-navigate-finish', logAndSend);
})();