您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
ローカル保存または既定値でタグ通報フォームを自動入力。
当前为
// ==UserScript== // @name Niconico Tag Allegation Autofill // @namespace https://gf.qytechs.cn/users/prozent55 // @version 1.0.1 // @description ローカル保存または既定値でタグ通報フォームを自動入力。 // @match https://www.nicovideo.jp/comment_allegation/* // @run-at document-idle // @connect ext.nicovideo.jp // @grant GM.xmlHttpRequest // @grant GM_xmlHttpRequest // @license MIT // ==/UserScript== (() => { 'use strict'; // ===== defaults ===== const DEFAULT_TARGET = 'tag'; const DEFAULT_ITEM = 'search_interference'; const DEFAULT_REASON_BODY = '動画の内容とは無関係なタグがロックされており、削除できません。\n' + 'タグ検索や関連機能に支障をきたすため、荒らし行為にあたり利用規約違反の可能性があると判断しました。'; // ===== WL (localStorage) ===== const WL_KEY = 'zr_tag_wl_v1'; const WL_DEFAULT = [ '真夏の夜の淫夢','淫夢実況シリーズ','ひとくち淫夢','淫夢本編リンク','本編改造淫夢','BB先輩シリーズ',"ホラー淫夢","タクヤさん" ]; const loadWL = () => { try { const s = localStorage.getItem(WL_KEY); return s ? JSON.parse(s) : WL_DEFAULT.slice(); } catch { return WL_DEFAULT.slice(); } }; const saveWL = (arr) => { try { localStorage.setItem(WL_KEY, JSON.stringify(arr||[])); } catch {} }; // ===== form cache (read only) ===== const KP = 'zippy_nico_tag_form_'; const K_TARGET = KP + 'target'; const K_ITEM = KP + 'item'; const K_TEXT = KP + 'text'; const storage = { async get(k, d){ try{ const v = localStorage.getItem('__'+k); return v==null?d:JSON.parse(v);}catch{ return d; } }, async set(k, v){ try{ localStorage.setItem('__'+k, JSON.stringify(v)); }catch{} } }; // ===== util ===== const norm = s => (s||'').trim().toLowerCase(); const qs = (s, r=document) => r.querySelector(s); const qsa = (s, r=document) => Array.from(r.querySelectorAll(s)); const fire = (el) => { if (!el) return; el.dispatchEvent(new Event('input',{bubbles:true})); el.dispatchEvent(new Event('change',{bubbles:true})); }; function setVal(el, val){ const proto = el?.constructor?.prototype || HTMLTextAreaElement.prototype; const d = proto && Object.getOwnPropertyDescriptor(proto,'value'); if (d?.set) d.set.call(el, val); else el.value = val; fire(el); } function toast(msg,ms=1200){ const n=document.createElement('div'); n.textContent=msg; Object.assign(n.style,{position:'fixed',right:'16px',bottom:'110px',zIndex:999999,background:'#00c853',color:'#fff',padding:'8px 10px',borderRadius:'8px',boxShadow:'0 4px 12px rgba(0,0,0,.25)',opacity:'0',transition:'opacity .15s'}); document.body.appendChild(n); requestAnimationFrame(()=>n.style.opacity='1'); setTimeout(()=>{ n.style.opacity='0'; setTimeout(()=>n.remove(),180); },ms); } function waitForForm(ms=8000){ return new Promise(res=>{ const pick = () => { const radios = qsa('input[type="radio"][name="target"]'); const select = qs('select[name="select_allegation"]'); const ta = qs('textarea[name="inquiry"]#inquiry'); return (radios.length && select && ta) ? {radios, select, ta} : null; }; const first = pick(); if (first) return res(first); const to = setTimeout(()=>{ mo.disconnect(); res(null); }, ms); const mo = new MutationObserver(()=>{ const f = pick(); if (f){ clearTimeout(to); mo.disconnect(); res(f); }}); mo.observe(document.body,{childList:true,subtree:true}); }); } // ===== getthumbinfo ===== function videoIdFromPath(){ const m=location.pathname.match(/\/comment_allegation\/([a-z]{2}\d+)/i); return m?m[1]:null; } function httpGet(url){ return new Promise((resolve,reject)=>{ const fn = (typeof GM?.xmlHttpRequest==='function')?GM.xmlHttpRequest:(typeof GM_xmlhttpRequest==='function')?GM_xmlHttpRequest:null; if (!fn) return reject(new Error('GM.xmlHttpRequest not available')); fn({ method:'GET', url, onload:r=>resolve(r.responseText), onerror:reject }); }); } async function fetchTags(videoId){ if (!videoId) return []; const url = `https://ext.nicovideo.jp/api/getthumbinfo/${encodeURIComponent(videoId)}`; let xml=''; try{ xml=await httpGet(url); }catch{ return []; } let doc; try{ doc=new DOMParser().parseFromString(xml,'text/xml'); }catch{ return []; } const nodes = Array.from(doc.querySelectorAll('thumb > tags > tag, tags > tag')); return nodes.map(t=>({ name:(t.textContent||'').trim(), locked:(t.getAttribute('lock')==='1'||t.getAttribute('locked')==='1') })) .filter(x=>x.name); } function filterWLAllLocked(thumbTags, wl){ const src = thumbTags.filter(t=>t.locked).map(t=>t.name); if (!src.length || !wl.length) return []; const S = src.map(norm); const out=[]; for (const w of wl){ const i=S.indexOf(norm(w)); if(i!==-1 && !out.includes(src[i])) out.push(src[i]); } return out; } // ===== body compose ===== const TAG_LINE_RE = /^【タグの内容】.*(?:\r?\n)?/m; function composeWithTagLine(currentText, tags){ const body0 = (currentText || '').replace(TAG_LINE_RE, ''); const tagLineOnly = `【タグの内容】\n${tags.length ? tags.join('、') : '(未特定)'}\n`; const body = body0.trim() ? body0.replace(/^\r?\n+/, '') : `【違反と判断された理由】\n${DEFAULT_REASON_BODY}`; return tagLineOnly + body; } // ===== panel (WL edit / reset) ===== function panel(nodes, reapply){ if (document.getElementById('zr-min2-host')) return; const host = document.createElement('div'); host.id = 'zr-min2-host'; Object.assign(host.style,{position:'fixed',right:'16px',bottom:'16px',zIndex:999999}); document.body.appendChild(host); const root = host.attachShadow({ mode:'open' }); const wrap = document.createElement('div'); wrap.className = 'zr-min2'; wrap.innerHTML = ` <div class="row"><b>自動入力(ローカル⇄既定)</b></div> <div class="row"> <button id="zr-edit" type="button">編集</button> <button id="zr-reset" type="button">既定に戻す</button> </div> `; const style = document.createElement('style'); style.textContent = ` :host { all: initial; } .zr-min2 { all: initial; display:block; font:12px/1.4 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Noto Sans JP","Hiragino Kaku Gothic ProN",Meiryo,sans-serif; color:#fff; background:#0b1220cc; backdrop-filter:blur(6px); padding:10px 12px; border-radius:10px; box-shadow:0 8px 20px rgba(0,0,0,.35); } .row { all: initial; display:block; margin:6px 0; font:inherit; color:inherit; } b { all: initial; font:inherit; font-weight:700; color:inherit; } button { all: initial; font:inherit; color:#fff; background:#1f6feb; padding:6px 10px; border-radius:6px; cursor:pointer; margin-right:6px; box-shadow:0 1px 2px rgba(0,0,0,.25); } button:hover { background:#2b7af3; } button:active { background:#195bd0; } button#zr-reset { background:#d93025; } `; root.append(style, wrap); root.getElementById('zr-edit').addEventListener('click', () => { const cur = JSON.stringify(loadWL(), null, 2); const nxt = prompt('ホワイトリスト(JSON配列):', cur); if (!nxt) return; try { saveWL(JSON.parse(nxt)); reapply({ forceDefaultBody:false }); toast('編集を保存しました'); } catch { alert('JSONが不正です'); } }); root.getElementById('zr-reset').addEventListener('click', () => { saveWL(WL_DEFAULT.slice()); reapply({ forceDefaultBody:true }); toast('既定に戻しました'); }); } // ===== main ===== (async function main(){ const nodes = await waitForForm(); if (!nodes) return; const { radios, select, ta } = nodes; const savedTarget = await storage.get(K_TARGET, ''); const savedItem = await storage.get(K_ITEM, ''); const savedText = await storage.get(K_TEXT, ''); const target = savedTarget || DEFAULT_TARGET; const item = savedItem || DEFAULT_ITEM; const r = radios.find(x => x.value === String(target)); if (r){ r.checked = true; fire(r); } if ([...select.options].some(o => o.value === item)) { select.value = item; fire(select); } const videoId = videoIdFromPath(); const thumbTags = await fetchTags(videoId); const applyNow = ({ forceDefaultBody = false } = {}) => { const wl = loadWL(); const hit = filterWLAllLocked(thumbTags, wl); const cur = forceDefaultBody ? '' : (savedText || ta.value || ''); const next = composeWithTagLine(cur, hit); setVal(ta, next); const check = ta.value || ''; const ensured = check.replace(/^【タグの内容】[^\r\n]*\r?\n?/, (m) => m.endsWith('\n') ? m : (m + '\n')); if (ensured !== check) setVal(ta, ensured); }; applyNow(); panel(nodes, applyNow); })(); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址