您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Bangumi 章节批量添加时间
// ==UserScript== // @name Bangumi章节批量添加时间 // @namespace http://tampermonkey.net/ // @version 2.1 // @description Bangumi 章节批量添加时间 // @include /^https?:\/\/(bangumi\.tv|bgm\.tv|chii\.in)\/subject\/.*\/ep\/.*/ // @author 墨云 // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; // 等待指定选择器的元素出现后执行回调 function waitForEl(selector, cb, interval = 300, timeout = 10000) { const start = Date.now(); const timer = setInterval(() => { const el = document.querySelector(selector); if (el) { clearInterval(timer); cb(el); } else if (Date.now() - start > timeout) { clearInterval(timer); } }, interval); } // waitForEl('div.markItUpHeader', function (toolbarToRemove) { if (toolbarToRemove) { toolbarToRemove.remove(); } }); // ---------------------------------------- // 日历图标 function createCalendarIcon() { const icon = document.createElement('div'); icon.style.cssText = "width:16px;height:16px;position:relative;border:1px solid #007AFF;border-radius:2px;background:#fff;"; const header = document.createElement('div'); header.style.cssText = "position:absolute;top:0;left:0;width:100%;height:5px;background:#007AFF;border-top-left-radius:2px;border-top-right-radius:2px;"; icon.appendChild(header); const dotStyle = "width:3px;height:3px;background:#007AFF;border-radius:50%;position:absolute;top:1px;"; const dotLeft = document.createElement('div'); dotLeft.style.cssText = dotStyle + "left:2px;"; const dotRight = document.createElement('div'); dotRight.style.cssText = dotStyle + "right:2px;"; icon.appendChild(dotLeft); icon.appendChild(dotRight); return icon; } // 创建弹窗 function createModal(onConfirm) { const overlay = document.createElement('div'); overlay.style.cssText = "position:fixed;left:0;top:0;width:100%;height:100%;background:rgba(0,0,0,0.5);z-index:10000;"; const modal = document.createElement('div'); modal.style.cssText = "position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);background:#fff;padding:20px;border-radius:8px;min-width:300px;"; overlay.appendChild(modal); // 从第几集开始(选填) const startEpDiv = document.createElement('div'); startEpDiv.style.cssText = "margin-bottom:20px;"; startEpDiv.innerHTML = `<div>从第几集开始(选填):</div><input type="number" min="1" placeholder="留空则从当前第一个开始" style="width:100%;" />`; // 日期选择区域 const dateLabel = document.createElement('label'); dateLabel.textContent = "选择日期:"; const dateInput = document.createElement('input'); dateInput.type = "date"; dateInput.style.cssText = "width:100%;margin-bottom:20px;"; // 更新周期选择区域 const cycleLabel = document.createElement('label'); cycleLabel.textContent = "选择更新周期:"; const cycleSelect = document.createElement('select'); cycleSelect.style.cssText = "width:100%;margin-bottom:20px;"; const defOpt = document.createElement('option'); defOpt.value = ""; defOpt.textContent = "更新周期"; defOpt.disabled = true; defOpt.selected = true; cycleSelect.appendChild(defOpt); // 更新周期选项 ["周更", "日更", "工作日更", "特定星期更", "当天更完"].forEach(t => { const opt = document.createElement('option'); opt.value = t; opt.textContent = t; cycleSelect.appendChild(opt); }); // 一天几更(默认为1) const dailyMultiDiv = document.createElement('div'); dailyMultiDiv.style.cssText = "margin-top:10px;"; dailyMultiDiv.innerHTML = `<div>一天几更(默认为1):</div><input type="number" min="1" value="1" style="width:100%;" />`; // 复选框区域:仅当选择“特定星期更”时显示 const weekdayDiv = document.createElement('div'); weekdayDiv.style.cssText = "margin-top:10px;display:none;"; weekdayDiv.innerHTML = ` <div>选择星期(至少选2个):</div> <label><input type='checkbox' value='1'> 星期一</label> <label><input type='checkbox' value='2'> 星期二</label> <label><input type='checkbox' value='3'> 星期三</label> <label><input type='checkbox' value='4'> 星期四</label> <label><input type='checkbox' value='5'> 星期五</label> <label><input type='checkbox' value='6'> 星期六</label> <label><input type='checkbox' value='7'> 星期日</label> `; cycleSelect.addEventListener('change', function () { if (cycleSelect.value === "特定星期更") { weekdayDiv.style.display = "block"; } else { weekdayDiv.style.display = "none"; } }); // 按钮区域 const btnDiv = document.createElement('div'); btnDiv.style.cssText = "text-align:right;margin-top:20px;"; const confirmBtn = document.createElement('button'); confirmBtn.textContent = "确定"; confirmBtn.style.marginRight = "10px"; const cancelBtn = document.createElement('button'); cancelBtn.textContent = "取消"; btnDiv.appendChild(confirmBtn); btnDiv.appendChild(cancelBtn); // 按顺序将各部分添加到弹窗中 modal.append(startEpDiv, dateLabel, dateInput, cycleLabel, cycleSelect, dailyMultiDiv, weekdayDiv, btnDiv); document.body.appendChild(overlay); confirmBtn.addEventListener('click', () => { const dVal = dateInput.value; const cycleVal = cycleSelect.value; let extra = null; if (cycleVal === "特定星期更") { const checkboxes = weekdayDiv.querySelectorAll("input[type='checkbox']"); extra = []; checkboxes.forEach(chk => { if (chk.checked) extra.push(parseInt(chk.value, 10)); }); if (extra.length < 2) { alert("请至少选择两个星期!"); return; } } const dailyMultiInput = dailyMultiDiv.querySelector("input[type='number']"); const dailyMulti = parseInt(dailyMultiInput.value, 10); if (isNaN(dailyMulti) || dailyMulti < 1) { alert("请输入有效的一天几更数字(至少1)"); return; } // 获取“从第几集开始”的值 const startEpInput = startEpDiv.querySelector("input[type='number']"); const startEpVal = startEpInput.value.trim(); const startEp = startEpVal === "" ? null : parseInt(startEpVal, 10); onConfirm(dVal, cycleVal, extra, dailyMulti, startEp); document.body.removeChild(overlay); }); cancelBtn.addEventListener('click', () => { document.body.removeChild(overlay); }); } // 日期处理及增量函数 function formatDate(date) { const y = date.getFullYear(); const m = String(date.getMonth() + 1).padStart(2, '0'); const d = String(date.getDate()).padStart(2, '0'); return `${y}-${m}-${d}`; } function addDays(date, n) { let d = new Date(date); d.setDate(d.getDate() + n); return d; } function addWeeks(date, n) { return addDays(date, 7 * n); } function addBusinessDays(date, n) { let d = new Date(date); while (n > 0) { d.setDate(d.getDate() + 1); if (d.getDay() !== 0 && d.getDay() !== 6) n--; } return d; } // “当天更完”选项 function computeDate(date, cycle, offset) { if (cycle === "日更") return addDays(date, offset); if (cycle === "周更") return addWeeks(date, offset); if (cycle === "工作日更") return addBusinessDays(date, offset); if (cycle === "当天更完") return date; return addDays(date, offset); } // 返回日期对应的星期(1 为星期一,7 为星期日) function getWeekday(d) { let wd = d.getDay(); return wd === 0 ? 7 : wd; } // 针对“特定星期更”的处理 function getNextScheduledDateOnOrAfter(date, selectedDays) { let d = new Date(date); while (!selectedDays.includes(getWeekday(d))) { d = addDays(d, 1); } return d; } function getNextScheduledDate(d, selectedDays) { let candidate = addDays(d, 1); while (!selectedDays.includes(getWeekday(candidate))) { candidate = addDays(candidate, 1); } return candidate; } function computeSpecificDate(startDate, selectedDays, offset) { let d = computeDate(startDate, "日更", 0); // 使用日更逻辑计算第一集日期 let scheduledDate = new Date(d); let episodeCount = 0; while (episodeCount < offset) { scheduledDate = getNextScheduledDate(scheduledDate, selectedDays); episodeCount++; } return scheduledDate; } // 处理文本域数据 function processData(startDate, cycle, extra, dailyMulti, startEp) { const ta = document.querySelector('textarea[name="ep_list"]'); if (!ta) { alert("未找到目标文本域!"); return; } const lines = ta.value.split(/\r?\n/); let started = (startEp === null); let uniqueCount = 0; // 累计处理的【唯一】章节数 const mapping = {}; // 记录第一列章节号到对应的有效偏移量 const res = lines.map(line => { if (!line.trim()) return line; const parts = line.split("|"); const chapter = parts[0].trim(); // 若尚未开始处理 if (!started) { if (chapter === String(startEp)) { started = true; } else { return line; } } let effectiveOffset; if (mapping.hasOwnProperty(chapter)) { effectiveOffset = mapping[chapter]; } else { effectiveOffset = Math.floor(uniqueCount / dailyMulti); mapping[chapter] = effectiveOffset; uniqueCount++; } let newDate; if (cycle === "特定星期更" && Array.isArray(extra)) { newDate = computeSpecificDate(new Date(startDate), extra, effectiveOffset); } else { newDate = computeDate(new Date(startDate), cycle, effectiveOffset); } parts[4] = formatDate(newDate); return parts.join("|"); }); ta.value = res.join("\n"); } // 注入逻辑 function injectButton() { waitForEl('textarea[name="ep_list"]', function (el) { const newDiv = document.createElement('div'); newDiv.style.cssText = 'display: block; margin-bottom: 5px;'; const link = document.createElement('a'); link.href = "#"; // 使用#作为链接占位符 link.title = "添加时间"; link.style.cursor = "pointer"; link.appendChild(createCalendarIcon()); newDiv.appendChild(link); el.parentNode.insertBefore(newDiv, el); link.addEventListener('click', e => { e.preventDefault(); createModal((dateVal, cycleVal, extra, dailyMulti, startEp) => { if (!dateVal) { alert("请选择日期!"); return; } const d = new Date(dateVal); if (isNaN(d.getTime())) { alert("无效的日期!"); return; } if (!cycleVal) { alert("请选择更新周期!"); return; } processData(d, cycleVal, extra, dailyMulti, startEp); }); }); }); } injectButton(); })();