Adds a note-taking feature on YouTube videos, storing notes per video using localStorage.
当前为
// ==UserScript==
// @name YouTube Video Notes
// @namespace http://tampermonkey.net/
// @version 1.8
// @description Adds a note-taking feature on YouTube videos, storing notes per video using localStorage.
// @author You
// @match https://www.youtube.com/*
// @grant none
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
let lastVideoId = null; // Track last video to detect changes
function createButton(id, text, displayStyle, clickHandler, customStyles = '') {
const button = document.createElement('button');
button.id = id;
button.innerText = text;
button.className = 'yt-spec-button-shape-next yt-spec-button-shape-next--filled yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-s';
button.style.cssText = `margin-top: 10px; display: ${displayStyle}; ${customStyles}`;
button.addEventListener('click', clickHandler);
return button;
}
function createNoteUI(videoId, existingNote) {
const container = document.createElement('div');
container.className = 'yt-note-container item style-scope ytd-watch-metadata';
container.style.cssText = `
background: var(--yt-spec-badge-chip-background);
width: 100%;
border-radius: 12px;
font-size: 14px;
padding: 8px;
box-sizing: border-box;
`;
const noteArea = document.createElement('textarea');
noteArea.id = `yt-note-textarea-${videoId}`;
noteArea.style.cssText = `
width: 100%;
height: 80px;
font-family: inherit;
resize: vertical;
display: ${existingNote ? 'block' : 'none'};
box-sizing: border-box;
padding: 4px;
color: #fff;
background: transparent;
border-radius: 4px;
border: 1px solid white;
`;
noteArea.value = existingNote || '';
noteArea.disabled = !existingNote; // Disable if no note exists
const button = createButton(`yt-note-button-${videoId}`, existingNote ? 'Edit Note' : 'Write Note', 'inline-block', () => {
noteArea.style.display = 'block';
noteArea.disabled = false;
saveButton.style.display = 'inline-block';
deleteButton.style.display = 'inline-block';
button.style.display = 'none';
});
const saveButton = createButton(`yt-note-save-${videoId}`, 'Save', existingNote ? 'none' : 'inline-block', () => {
const noteText = noteArea.value.trim();
if (noteText) {
localStorage.setItem(`yt-note-${videoId}`, noteText);
button.innerText = 'Edit Note';
button.style.display = 'inline-block';
saveButton.style.display = 'none';
deleteButton.style.display = 'inline-block';
noteArea.disabled = true;
}
}, 'margin-left: 6px;');
const deleteButton = createButton(`yt-note-delete-${videoId}`, 'Delete Note', existingNote ? 'inline-block' : 'none', () => {
localStorage.removeItem(`yt-note-${videoId}`); // Delete note
noteArea.value = '';
button.innerText = 'Write Note';
button.style.display = 'inline-block';
saveButton.style.display = 'none';
deleteButton.style.display = 'none';
noteArea.disabled = true;
}, 'margin-left: 6px;');
container.appendChild(noteArea);
container.appendChild(button);
container.appendChild(saveButton);
container.appendChild(deleteButton);
return container;
}
function insertNoteUI() {
const videoId = new URL(window.location.href).searchParams.get('v');
if (!videoId || videoId === lastVideoId) return; // Prevent duplicate insertion
lastVideoId = videoId; // Update last video ID
const existingNote = localStorage.getItem(`yt-note-${videoId}`) || '';
const commentSection = document.getElementById('comments');
if (!commentSection) {
setTimeout(insertNoteUI, 2000);
return;
}
// Remove old note UI before inserting a new one
const oldNote = document.querySelector('.yt-note-container');
if (oldNote) oldNote.remove();
const noteUI = createNoteUI(videoId, existingNote);
commentSection.parentNode.insertBefore(noteUI, commentSection);
}
function observeNavigationChanges() {
// YouTube fires "yt-navigate-finish" when navigation happens within SPA
document.addEventListener('yt-navigate-finish', () => {
setTimeout(insertNoteUI, 2000);
});
// Also check for URL changes manually (backup method)
let lastUrl = location.href;
setInterval(() => {
if (location.href !== lastUrl) {
lastUrl = location.href;
insertNoteUI();
}
}, 1000);
}
// Run script on initial load and handle SPA navigation
window.addEventListener('load', () => {
setTimeout(() => {
insertNoteUI();
observeNavigationChanges();
}, 2000);
});
})();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址