您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
自动标记看过的影片
// ==UserScript== // @name JavDB Watched Marker // @version 1.1 // @namespace https://gist.github.com/sqzw-x // @description 自动标记看过的影片 // @match https://javdb.com/* // @grant GM_registerMenuCommand // @grant GM_addElement // @license MIT // ==/UserScript== "use strict"; const get_localStorage = (key) => JSON.parse(localStorage.getItem(key)); const set_localStorage = (key, value) => localStorage.setItem(key, JSON.stringify(value)); const URL_SET_KEY = "javdb-watched-url-set"; const NUM_SET_KEY = "javdb-watched-num-set"; let watchedURLSet = new Set(get_localStorage(URL_SET_KEY)); let watchedNumSet = new Set(get_localStorage(NUM_SET_KEY)); // 创建隐藏的文件输入框 const fileInput = GM_addElement(document.body, "input", { type: "file", accept: ".json", style: "display: none", }); fileInput.addEventListener("change", handleFileSelect); // 注册油猴菜单 GM_registerMenuCommand("导入看过列表", () => fileInput.click()); GM_registerMenuCommand("手动添加看过", showManualInputDialog); // 处理文件导入 function handleFileSelect(event) { const file = event.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = (e) => { try { const r = JSON.parse(e.target.result); // r is an array of objects // each object has a url property and a number property // add each url to watchedURLSet and each num to watchedNumSet r.forEach((item) => { watchedURLSet.add(item.url); watchedNumSet.add(item.number); }); set_localStorage(URL_SET_KEY, Array.from(watchedURLSet)); set_localStorage(NUM_SET_KEY, Array.from(watchedNumSet)); } catch (error) { console.error("解析文件失败:", error); alert("无法解析文件,请确保是有效的JSON格式"); } }; reader.readAsText(file); } // 显示手动输入对话框 function showManualInputDialog() { // 创建对话框容器 const dialogContainer = document.createElement("div"); dialogContainer.style.position = "fixed"; dialogContainer.style.top = "0"; dialogContainer.style.left = "0"; dialogContainer.style.width = "100%"; dialogContainer.style.height = "100%"; dialogContainer.style.backgroundColor = "rgba(0, 0, 0, 0.7)"; dialogContainer.style.display = "flex"; dialogContainer.style.justifyContent = "center"; dialogContainer.style.alignItems = "center"; dialogContainer.style.zIndex = "10000"; // 创建对话框内容 const dialog = document.createElement("div"); dialog.style.backgroundColor = "white"; dialog.style.padding = "20px"; dialog.style.borderRadius = "5px"; dialog.style.width = "300px"; dialog.style.maxWidth = "90%"; dialog.innerHTML = ` <h3 style="margin-top: 0">添加已观看视频</h3> <div style="margin-bottom: 10px;"> <label for="url-input">URL或ID:</label> <input id="url-input" type="text" style="width: 100%; box-sizing: border-box;" placeholder="例如: abc123"> </div> <div style="margin-bottom: 15px;"> <label for="number-input">番号:</label> <input id="number-input" type="text" style="width: 100%; box-sizing: border-box;" placeholder="例如: ABC-123"> </div> <div style="text-align: right;"> <button id="cancel-btn" style="margin-right: 10px; padding: 5px 10px;">取消</button> <button id="save-btn" style="padding: 5px 10px;">保存</button> </div> `; dialogContainer.appendChild(dialog); document.body.appendChild(dialogContainer); // 添加事件监听 document.getElementById("cancel-btn").addEventListener("click", () => { document.body.removeChild(dialogContainer); }); document.getElementById("save-btn").addEventListener("click", () => { const urlInput = document.getElementById("url-input").value.trim(); const numberInput = document.getElementById("number-input").value.trim(); if (urlInput) { // 从URL中提取ID部分 const urlId = urlInput.includes("/v/") ? urlInput.split("/v/")[1] : urlInput; watchedURLSet.add(urlId); set_localStorage(URL_SET_KEY, Array.from(watchedURLSet)); } if (numberInput) { watchedNumSet.add(numberInput); set_localStorage(NUM_SET_KEY, Array.from(watchedNumSet)); } if (urlInput || numberInput) { alert("已添加到观看列表"); markWatchedVideos(); // 重新标记视频 } else { alert("请至少输入一项"); return; } document.body.removeChild(dialogContainer); }); } // 标记已看过的视频 function markWatchedVideos() { const videos = document.querySelectorAll(".item"); const watched = (v) => { const link = v.querySelector("a"); if (link) { const url = link.getAttribute("href")?.replace("/v/", ""); return url && watchedURLSet.has(url) ? "看过" : null; } const num = v.querySelector(".video-title strong").textContent; return num && watchedNumSet.has(num) ? "可能看过" : null; }; videos.forEach((v) => { const t = watched(v); if (t) { const marker = document.createElement("span"); marker.className = "review"; marker.textContent = t; v.querySelector(".cover").appendChild(marker); } }); } // 初始化 function init() { markWatchedVideos(); } init();