ニコニコ静画、簡単NGスクリプト

申し訳ないが見たくないイラストはNG


Install this script?
// ==UserScript==// @name         ニコニコ静画、簡単NGスクリプト// @namespace    http://tampermonkey.net/// @version      1.814// @description  申し訳ないが見たくないイラストはNG// @author       cbxm// @match        https://seiga.nicovideo.jp/tag/*// @match        https://seiga.nicovideo.jp/seiga/*// @match        https://seiga.nicovideo.jp/watch/*// @match        https://seiga.nicovideo.jp/my/personalize*// @match        https://nicoad.nicovideo.jp/widget/*// @match        https://seiga.nicovideo.jp/search/*// @match        https://seiga.nicovideo.jp/illust/list// @match        https://seiga.nicovideo.jp/shunga/list// @connect      seiga.nicovideo.jp// @connect      nicoad.nicovideo.jp// @grant        GM.xmlHttpRequest// @grant        GM.getValue// @grant        GM.setValue// @run-at document-start// @license MIT// ==/UserScript==(async () => {"use strict";;;//汎用関数class Util {static WaitDocumentElement() {return new Promise(r => {if (document.documentElement != null) {return r();}window.addEventListener("DOMContentLoaded", () => {return r();});});}//https://stackoverflow.com/questions/69368851/type-safe-way-of-narrowing-type-of-arrays-by-length-when-nouncheckedindexedacces//TypeScriptくんを#得させるための関数static HasLengthAtLeast(arr, len) {return arr != null && arr.length >= len;}//TypeScriptくんを#得させるための関数static IsLength(arr, len) {return arr != null && arr.length == len;}//xmlString=未探査部分static XmlToObj(xmlString) {const F = (xmlString, obj) => {//タグを抜き出すlet tagMatchs = null;while (true) {tagMatchs = xmlString.match(/<([^>]+)>/); //タグを探す//タグがないということはそれが値になるif (tagMatchs == null) {return xmlString;}if (tagMatchs[1]?.[tagMatchs[1].length - 1] == "/") {xmlString = xmlString.replace(/<[^>]+>([^]*)/, "$1");}else {break;}}if (!Util.HasLengthAtLeast(tagMatchs, 2)) {return xmlString;}const tag = tagMatchs[1];//タグの内側とその先を抜き出すconst matchChildlen = [];while (true) {const matchs = xmlString.match(new RegExp(`^[^<]*<${tag}>([^]+?)<\/${tag}>([^]*)`));if (matchs == null || !Util.HasLengthAtLeast(matchs, 3)) {break;}matchChildlen.push(matchs[1]);xmlString = matchs[2];}//タグあったのにマッチしなかったおかしいif (matchChildlen.length == 0) {return obj;}//そのタグが一つしかないとき、オブジェクトになるif (Util.IsLength(matchChildlen, 1)) {//子を探すobj[tag] = F(matchChildlen[0], {});}//そのタグが複数あるとき、配列になるif (matchChildlen.length > 1) {obj = [];for (let i = 0; i < matchChildlen.length; i++) {//子を探すobj[i] = F(matchChildlen[i], {});}}//兄弟を探すF(xmlString, obj);return obj;};//初期化で<xml>を取り除くxmlString = xmlString.replace(/\s*<[^>]+>([^]+)/, "$1");return F(xmlString, {});}static HtmlToDocument(str) {const parser = new DOMParser();return parser.parseFromString(str, "text/html");}static HtmlToChildNodes(str) {return this.HtmlToDocument(str).body.childNodes;}static HtmlToElement(str) {return this.HtmlToDocument(str).body.firstElementChild;}static HtmlToSVG(s) {var div = document.createElementNS('https://www.w3.org/1999/xhtml', 'div');div.innerHTML = '<svg xmlns="https://www.w3.org/2000/svg">' + s + '</svg>';var frag = document.createDocumentFragment();while (div.firstChild?.firstChild)frag.appendChild(div.firstChild.firstChild);return frag;}static Wait(ms) {return new Promise(r => setTimeout(() => r(null), ms));}static WithTimeOut(p, ms) {return Promise.race([p, this.Wait(ms)]);}static async Retry(p, retryCount, wait, predicate) {for (let i = 0; i < retryCount; i++) {const r###lt = await p();if (predicate(r###lt)) {return r###lt;}//console.log("wait...");await Util.Wait(wait);}return null;}static async Download(url, name) {const link = document.createElement("a");document.body.appendChild(link);link.download = name;link.href = url;link.click();//すぐに消すと反応しないとかawait this.Wait(100);document.body.removeChild(link);}static GMFetchText(url, optopns) {//console.log(url);return new Promise((resolve, reject) => {GM.xmlHttpRequest({url: url,...optopns,onload: (response) => {// リダイレクトを処理(Chromeだと処理できないバグ?https://github.com/Tampermonkey/tampermonkey/issues/2134)if (response.responseText == null && response.status >= 300 && response.status < 400) {if (url != response.finalUrl) {return this.GMFetchText(response.finalUrl, optopns);}console.error("リダイレクトを処理できませんでした");}resolve(response.responseText);},onerror: (e) => {console.error(e);reject("");}});});}static Unique(array) {return Array.from(new Set(array));}static IsElementInViewport(el) {var rect = el.getBoundingClientRect();return (rect.top >= 0 &&rect.left >= 0 &&rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&rect.right <= (window.innerWidth || document.documentElement.clientWidth));}static SetCookie(key, value, option = "") {window.document.cookie = encodeURIComponent(key) + "=" + encodeURIComponent(value) + "; " + option;}static SetCookieKeyAndValue(keyAndValue) {window.document.cookie = keyAndValue;}static GetAllCookie() {const cookies = window.document.cookie.split(";").map(c => decodeURI(c).replace(/^\s/, ""));let keyVal = [];for (let i = 0; i < cookies.length; i++) {//cookies[i]=cookies[i].replace(/^\s/,"");     ???const s = cookies[i].match(/^(.*?)=(.*?)$/);if (Util.HasLengthAtLeast(s, 3)) {keyVal.push({ key: s[1], val: s[2] });}}return keyVal;}static GetCookie(key) {const cookies = window.document.cookie.split(";").map(c => decodeURI(c).replace(/^\s/, ""));for (var c of cookies) {if (RegExp(key).test(c)) {return c;}}return null;}static GetCookieVal(key) {const cookies = window.document.cookie.split(";").map(c => decodeURI(c).replace(/^\s/, ""));for (var c of cookies) {const matched = c.match(`${key}=([^]*)`);if (Util.HasLengthAtLeast(matched, 2)) {return matched[1];}}return null;}static DeleteCookie(key) {window.document.cookie = encodeURI(key) + "=; max-age=0";}};class Fetcher {static GMFetchText(url) {return Util.GMFetchText(url, {method: "GET"});}static async FetchIllustDatas(ids) {if (ids.length == 0) {return { illusts: [], userIds: [] };}const url = `https:\/\/seiga.nicovideo.jp/api/illust/info?id_list=${ids.join()}`;const res = await this.GMFetchText(url);const obj = Util.XmlToObj(res);if (obj.response == undefined) {return { illusts: [], userIds: [] };}const list = Array.isArray(obj.response.image_list) ? obj.response.image_list : [obj.response.image_list.image];const illusts = [];for (let i = 0; i < list.length; i++) {illusts[i] = {illustId: list[i].id,created: new Date(list[i].created)};}return {illusts: illusts,userIds: list.map(l => l.user_id)};}static async FetchUserName(userId) {const url = "https://seiga.nicovideo.jp/api/user/info?id=" + userId;const json = Util.XmlToObj(await this.GMFetchText(url));if (json.response == undefined) {return { illusts: [], userIds: [] };}return json.response.user.nickname;}static async FetchUserId(illustId) {const url = "https://seiga.nicovideo.jp/api/illust/info?id=im" + illustId;const r###ltText = await this.GMFetchText(url);const json = Util.XmlToObj(r###ltText);if (json.response == undefined) {return { illusts: [], userIds: [] };}return json.response.image.user_id;}};class Storage {constructor(storageName) {this.storageName = "";this.storageName = storageName;}async GetStorageData(defaultValue = null) {const text = await GM.getValue(this.storageName, null);return text != null ? JSON.parse(decodeURIComponent(text)) : defaultValue;}async SetStorageData(data) {await GM.setValue(this.storageName, encodeURIComponent(JSON.stringify(data)));}};;//MutationObserver使った便利関数class Observer {static Wait(predicate, parent = document, option = null) {return new Promise(r => {if (option == null) {option = {childList: true,subtree: true};}const mutationObserver = new MutationObserver((mrs) => {if (predicate(mrs)) {mutationObserver.disconnect();r(mrs);return;}});mutationObserver.observe(parent, option);});};static WaitAddedNodes(predicate, parent, option = null) {return new Promise(r => {if (option == null) {option = {childList: true,subtree: true};}const mutationObserver = new MutationObserver(async (mrs) => {//console.log(document.head.innerHTML);//console.log(document.body.innerHTML);const r###lt = [];for (let node of mrs) {//console.log(added);for (let i = 0; i < node.addedNodes.length; i++) {r###lt.push(...await predicate(node.addedNodes[i]));}}if (r###lt.length != 0) {mutationObserver.disconnect();r(r###lt);return;}});mutationObserver.observe(parent, option);});};static WaitAddedNode(predicate, parent, option = null) {return new Promise(r => {if (option == null) {option = {childList: true,subtree: true};}if (option.childList == undefined && option.attributes == undefined && option.characterData == undefined) {option.childList = true;option.subtree = true;}const mutationObserver = new MutationObserver(async (mrs) => {//console.log(document.head.innerHTML);//console.log(document.body.innerHTML);for (let node of mrs) {//console.log(added);for (let i = 0; i < node.addedNodes.length; i++) {const ret = await predicate(node.addedNodes[i]);if (ret != null) {mutationObserver.disconnect();r(ret);return;}}}});mutationObserver.observe(parent, option);});};static async DefinitelyGetElementById(id, parent = document.documentElement, option = null) {if (!(option?.doNotNormalCheck ?? false)) {const e = document.getElementById(id);if (e != null) {return e;}}return this.WaitAddedNode(e => (e instanceof Element && e.id == id) ? e : null, parent, option);}//getElementsByClassNameをつかうけど単体static async DefinitelyGetElementByClassName(className, parent = document.documentElement, option = null) {if (!(option?.doNotNormalCheck ?? false)) {const e = parent.getElementsByClassName(className)[0];if (e != null) {return e;}}return this.WaitAddedNode(e => {if (e instanceof Element) {if (e.classList.contains(className)) {return e;}if (option?.isDeepSearch ?? false) {const c = e.getElementsByClassName(className);if (c.length != 0) {return c[0];}}}return null;}, parent, option);}//getElementsByTagNameをつかうけど単体static async DefinitelyGetElementByTagName(tagName, parent = document.documentElement, option = null) {tagName = tagName.toUpperCase();if (!(option?.doNotNormalCheck ?? false)) {const e = parent.getElementsByTagName(tagName)[0];if (e != null) {return e;}}return this.WaitAddedNode(e => {if (e instanceof Element) {if (e.tagName == tagName) {return e;}if (option?.isDeepSearch ?? false) {const c = e.getElementsByTagName(tagName);if (c.length != 0) {return c[0];}}}return null;}, parent, option);}static async DefinitelyGetElementsByClassName(className, parent = document.documentElement, option = null) {if (!(option?.doNotNormalCheck ?? false)) {const e = parent.getElementsByClassName(className);if (e.length != 0) {return Array.from(e);}}return this.WaitAddedNodes(e => {const ret = [];if (e instanceof Element) {if (e.classList.contains(className)) {ret.push(e);}if (option?.isDeepSearch ?? false) {ret.push(...Array.from(e.getElementsByClassName(className)));}}return ret;}, parent, option);}static async DefinitelyGetElementsByTagName(tagName, parent = document.documentElement, option = null) {tagName = tagName.toUpperCase();if (!(option?.doNotNormalCheck ?? false)) {const e = parent.getElementsByTagName(tagName);if (e.length != 0) {return Array.from(e);}}return this.WaitAddedNodes(e => {const ret = [];if (e instanceof Element) {if (e.tagName == tagName) {ret.push(e);}if (option?.isDeepSearch ?? false) {ret.push(...Array.from(e.getElementsByTagName(tagName)));}}return ret;}, parent, option);}};//暫定OK、暫定荒らし、確定OK、確定荒らし//type Status = "OK" | "NG" | "LOK" | "LNG"let VirtualPageType;(function (VirtualPageType) {VirtualPageType[VirtualPageType["None"] = -1] = "None";VirtualPageType[VirtualPageType["TAG_SEARCH"] = 0] = "TAG_SEARCH";VirtualPageType[VirtualPageType["ILLUST"] = 1] = "ILLUST";VirtualPageType[VirtualPageType["PERSONALIZE"] = 2] = "PERSONALIZE";VirtualPageType[VirtualPageType["ADS"] = 3] = "ADS";VirtualPageType[VirtualPageType["KEYWORD_SEARCH"] = 4] = "KEYWORD_SEARCH";VirtualPageType[VirtualPageType["MAX"] = 5] = "MAX";})(VirtualPageType || (VirtualPageType = {}));;;;const pageInfos = [{type: VirtualPageType.TAG_SEARCH,regex: /https:\/\/seiga.nicovideo.jp\/tag\/.*/,name: "タグ検索",},{type: VirtualPageType.ILLUST,regex: /https:\/\/seiga.nicovideo.jp\/(seiga|watch)\/.*/,name: "イラストページ",},{type: VirtualPageType.PERSONALIZE,regex: /https:\/\/seiga.nicovideo.jp\/my\/personalize.*/,name: "定点観測",},{type: VirtualPageType.ADS,regex: /https:\/\/nicoad.nicovideo.jp\/widget\/.*/,name: "ニコニ広告",},{type: VirtualPageType.KEYWORD_SEARCH,regex: /https:\/\/seiga.nicovideo.jp\/search\/.*/,name: "キーワード検索",},{type: VirtualPageType.TAG_SEARCH,regex: /https:\/\/seiga.nicovideo.jp\/illust\/list/,name: "静画イラスト一覧",},{type: VirtualPageType.KEYWORD_SEARCH,regex: /https:\/\/seiga.nicovideo.jp\/shunga\/list/,name: "春画イラスト一覧",}];const virtualPageInfos = [{illustListName: "item_list",illustItemName: "list_item",},{illustListName: "item_list",illustItemName: "list_item_cutout",},{illustListName: "list_body",illustItemName: "illust_thumb",},{// 空ならul,ilを使うillustListName: "",illustItemName: "",},{illustListName: "illust_pict_all",illustItemName: "illust_list_img",}];let Status;(function (Status) {Status[Status["NONE"] = 0] = "NONE";Status[Status["OK"] = 1] = "OK";Status[Status["NG"] = 2] = "NG";Status[Status["WHITE"] = 3] = "WHITE";Status[Status["BLACK"] = 4] = "BLACK";Status[Status["AUTO"] = 5] = "AUTO";Status[Status["MAX"] = 6] = "MAX";})(Status || (Status = {}));class Main {constructor() {this.cache = new Map();this.illustInfos = [];this.illustListElements = new Set();this.selectedList = [];this.cacheStorage = new Storage("NICONICO_RENTO_ARASI_NG_DATA_CACHE");this.optionStorage = new Storage("NICONICO_RENTO_ARASI_NG_OPTION_CACHE");this.imgIntersectionObserver = new IntersectionObserver(entries => {for (let e of entries) {if (e.intersectionRatio > 0) {const img = e.target;if (img.src != null && img.dataset != null && img.dataset.src != null) {img.src = img.dataset.src;}this.imgIntersectionObserver.unobserve(img);}}});}ListToMap(list) {for (let o of list) {o.name ?? (o.name = "");}if (list[0] != null && list[0].userId != null) {return new Map(list.map(o => {const userId = o.userId;delete o.userId;for (let illust of o.illusts) {illust.illustId = illust.id;delete illust.id;}return [userId, o];}));}return new Map(list);}async GetStorageData() {const obj = await this.cacheStorage.GetStorageData([]);this.cache = this.ListToMap(obj);//console.log(this.cache);const defaultOption = {usePages: [true, true, true, true, true, true, true],judge: {isJudge: false,time: 1 * 60 * 60 * 1000, //一時間postCount: 5,period: 30,isAutoNGHidden: false},createUserLink: true,createBlackWhiteButton: true,okCacheMax: 1000, //どのくらいがいいのかわからない};this.option = await this.optionStorage.GetStorageData(defaultOption);if (this.option.usePages == undefined) {this.option.usePages = defaultOption.usePages;}for (let i = 0; i < VirtualPageType.MAX; i++) {if (this.option.usePages[i] == undefined) {this.option.usePages[i] = defaultOption.usePages[i];}}if (this.option.judge == undefined) {this.option.judge = defaultOption.judge;}if (this.option.judge.time == undefined) {this.option.judge.time = defaultOption.judge.time;}if (this.option.judge.postCount == undefined) {this.option.judge.postCount = defaultOption.judge.postCount;}if (this.option.judge.period == undefined) {this.option.judge.period = defaultOption.judge.period;}if (this.option.judge.isJudge == undefined) {this.option.judge.isJudge = defaultOption.judge.isJudge;}if (this.option.judge.isAutoNGHidden == undefined) {this.option.judge.isAutoNGHidden = defaultOption.judge.isAutoNGHidden;}if (this.option.createUserLink == undefined) {this.option.createUserLink = defaultOption.createUserLink;}if (this.option.createBlackWhiteButton == undefined) {this.option.createBlackWhiteButton = defaultOption.createBlackWhiteButton;}if (this.option.okCacheMax == undefined) {this.option.okCacheMax = defaultOption.okCacheMax;}//console.log(this.option);}GetInfo(illustId) {for (let [userId, user] of this.cache) {if (user.illusts == null) {console.log(userId, user);user.illusts = [];}for (let illust of user.illusts) {if (illust.illustId == illustId) {return { userId: userId, user: user, illust: illust };}}}return undefined;}CheckAutoNG(user) {if (user.illusts.length == 0 || user.status != Status.OK) {return;}const createdNumbers = user.illusts.map(illust => {if (typeof illust.created == "string") {illust.created = new Date(illust.created);}return illust.created.getTime();});//新しい順const sorted = createdNumbers.sort((a, b) => b - a);const currentDateNumber = new Date().getTime();const periodMS = this.option.judge.period * 86400000;for (let i = 0; i < sorted.length; i++) {if (periodMS != 0 && sorted[i] <= currentDateNumber - periodMS) {break;}let j = i + 1;let postCount = 1;while (true) {if (j >= sorted.length || sorted[i] - sorted[j] > this.option.judge.time || (periodMS != 0 && sorted[j] <= currentDateNumber - periodMS)) {break;}j++;postCount++;}if (postCount >= this.option.judge.postCount) {user.status = Status.AUTO;return;}}};GetIllustIds(itemListElement) {const illustIdElements = itemListElement.getElementsByTagName("img");const illustIds = new Set();for (let i = 0; i < illustIdElements.length; i++) {// https://lohas.nicoseiga.jp//thumb/xxxxxxuz?yyyyyy から xxxxx を抜き出すconst idMatchs = illustIdElements[i].src.match(/(\d+).+?(?:\?\d+)?$/);if (idMatchs == null) {continue;}const id = idMatchs[idMatchs.length - 1];illustIds.add(id);}return [...illustIds];}DrawList() {if (this.optionDialog == null) {return;}const list = this.optionDialog.getElementsByClassName("scrollUL")[0];const onlyCurrentPageCheckbox = this.optionDialog.getElementsByClassName("onlyCurrentPageCheckbox")[0];const listStatusSelect = this.optionDialog.getElementsByClassName("listStatusSelect")[0];if (list == undefined || onlyCurrentPageCheckbox == undefined || listStatusSelect == undefined) {return;}const status = listStatusSelect.value == "ALL" ? "" : Status[listStatusSelect.value];list.innerHTML = "";for (let [userId, user] of this.cache) {if (status != "" && user.status != status) {continue;}const info = this.illustInfos.find(info => info.userId == userId);let sampleIllustId = (info == undefined) ? undefined : info.illust.illustId;if (onlyCurrentPageCheckbox.checked && sampleIllustId == undefined) {continue;}if (sampleIllustId == undefined && user.illusts[0] != undefined) {sampleIllustId = user.illusts[0].illustId;}const div = document.createElement("div");div.style.height = "70px";div.style.display = "flex";div.style.flexDirection = "column";div.className = "userInfoItem";list.appendChild(div);div.addEventListener("mouseup", e => this.ClickList(div));{const nameIdDiv = document.createElement("div");nameIdDiv.style.top = "relative";nameIdDiv.style.position = "4px";div.appendChild(nameIdDiv);{const nameSpan = document.createElement("span");nameSpan.className = "userName";nameSpan.textContent = user.name;nameSpan.style.fontSize = "130%";nameSpan.style.color = "black";nameSpan.style.width = "66px";nameSpan.style.height = "24px";nameSpan.style.padding = "3px";nameIdDiv.appendChild(nameSpan);const idSpan = document.createElement("span");idSpan.className = "userId";idSpan.textContent = userId;idSpan.style.fontSize = "130%";idSpan.style.color = "black";idSpan.style.width = "66px";idSpan.style.padding = "3px";nameIdDiv.appendChild(idSpan);}const userAndSampleImgDiv = document.createElement("div");div.appendChild(userAndSampleImgDiv);{const aUser = document.createElement("a");aUser.href = `https:\/\/seiga.nicovideo.jp/user/illust/${userId}`;userAndSampleImgDiv.appendChild(aUser);{const imgUser = document.createElement("img");imgUser.dataset.src = `https:\/\/secure-dcdn.cdn.nimg.jp/nicoaccount/usericon/${Math.floor(parseInt(userId) / 10000)}/${userId}.jpg`;imgUser.style.height = "40px";imgUser.style.position = "relative";imgUser.style.padding = "0 20px 0 10px";imgUser.style.top = "-5px";this.imgIntersectionObserver.observe(imgUser);aUser.appendChild(imgUser);imgUser.addEventListener("error", () => {imgUser.src = "https:\/\/secure-dcdn.cdn.nimg.jp/nicoaccount/usericon/defaults/blank.jpg";});}if (sampleIllustId != undefined) {const aSample = document.createElement("a");aSample.href = `https:/\/seiga.nicovideo.jp/seiga/im${sampleIllustId}`;userAndSampleImgDiv.appendChild(aSample);{const imgSample = document.createElement("img");imgSample.dataset.src = `https:\/\/lohas.nicoseiga.jp\/\/thumb/${sampleIllustId}c`;imgSample.style.height = "30px";this.imgIntersectionObserver.observe(imgSample);imgSample.style.position = "relative";imgSample.style.top = "-5px";aSample.appendChild(imgSample);const bigSample = document.createElement("img");bigSample.dataset.src = `https:\/\/lohas.nicoseiga.jp\/\/thumb/${sampleIllustId}c`;bigSample.style.height = "100px";this.imgIntersectionObserver.observe(bigSample);bigSample.style.pointerEvents = "none";bigSample.style.position = "absolute";bigSample.style.zIndex = "110";imgSample.addEventListener("mouseover", () => {const clientRect = imgSample.getBoundingClientRect();const x = window.scrollX + clientRect.left + imgSample.width / 2 - 50;const y = window.scrollY + clientRect.top + imgSample.height / 2 - 50;bigSample.style.top = y + "px";bigSample.style.left = x + "px";document.body.appendChild(bigSample);});imgSample.addEventListener("mouseleave", () => {bigSample.remove();});}}}}}}ClickList(target) {if (target != null) {if (this.selectedList.includes(target)) {target.style.backgroundColor = "";this.selectedList = this.selectedList.filter(s => s != target);}else {target.style.backgroundColor = "rgba(0, 140, 255, 0.5)";this.selectedList.push(target);}}}async SetOptionButton() {if (document.getElementById("optionSpan") != null) {return;}const optionSpan = document.createElement("span");optionSpan.id = "optionSpan";optionSpan.style.margin = "0 10px";optionSpan.style.lineHeight = "29px";if (this.currentPage == VirtualPageType.KEYWORD_SEARCH) {const nextSibling = await Util.WithTimeOut(Observer.DefinitelyGetElementByClassName("search_tab_border"), 10000);if (nextSibling == null) {return;}nextSibling.insertAdjacentElement("beforebegin", optionSpan);}else {const parent = await Util.WithTimeOut(Observer.DefinitelyGetElementByClassName("sg_pankuzu"), 10000);if (parent == null) {return;}parent.appendChild(optionSpan);}{const optionButton = document.createElement("input");optionButton.type = "button";optionButton.value = "簡単NGスクリプト";optionButton.style.backgroundColor = "yellow";optionButton.style.padding = "1px 10px";optionButton.style.fontSize = "110%";optionButton.style.cssText += "color: black !important;";optionButton.addEventListener("click", () => {if (this.optionDialog.parentElement == null) {optionSpan.appendChild(this.optionDialog);return;}this.optionDialog.style.display = (this.optionDialog.style.display == "none") ? "block" : "none";});optionSpan.appendChild(optionButton);this.optionDialog = document.createElement("div");this.optionDialog.style.backgroundColor = "white";this.optionDialog.style.position = "absolute";this.optionDialog.style.padding = "5px";this.optionDialog.style.marginLeft = "10px";this.optionDialog.style.zIndex = "100";this.optionDialog.style.border = "2px solid";{const list1 = document.createElement("div");list1.style.display = "flex";list1.style.paddingTop = "5px";list1.style.paddingBottom = "10px";this.optionDialog.appendChild(list1);{const listStatusSelect = document.createElement("select");listStatusSelect.className = "listStatusSelect";listStatusSelect.style.margin = "5px";list1.appendChild(listStatusSelect);for (let i = 1; i <= Status.MAX; i++) {const option = document.createElement("option");const text = i == Status.MAX ? "ALL" : Status[i];option.value = text;option.textContent = text;listStatusSelect.appendChild(option);}listStatusSelect.addEventListener("change", () => {while (this.selectedList.length != 0) {const element = this.selectedList.pop();if (element != undefined) {element.style.backgroundColor = "";}}this.DrawList();});const onlyCurrentPageLabel = document.createElement("label");onlyCurrentPageLabel.style.color = "black";onlyCurrentPageLabel.style.padding = "3px";onlyCurrentPageLabel.style.display = "flex";list1.appendChild(onlyCurrentPageLabel);{const onlyCurrentPageCheckbox = document.createElement("input");onlyCurrentPageCheckbox.type = "checkbox";onlyCurrentPageCheckbox.className = "onlyCurrentPageCheckbox";onlyCurrentPageCheckbox.checked = true;onlyCurrentPageCheckbox.style.padding = "3px";onlyCurrentPageCheckbox.style.margin = "10px";onlyCurrentPageCheckbox.style.marginRight = "3px";onlyCurrentPageCheckbox.style.marginLeft = "0px";onlyCurrentPageLabel.appendChild(onlyCurrentPageCheckbox);onlyCurrentPageCheckbox.addEventListener("change", () => this.DrawList());const onlyCurrentPageText = document.createElement("div");onlyCurrentPageText.textContent = "このページだけ";onlyCurrentPageText.style.color = "black";onlyCurrentPageLabel.appendChild(onlyCurrentPageText);}const allSelect = document.createElement("input");allSelect.type = "button";allSelect.value = "全選択";allSelect.style.color = "black";allSelect.style.fontSize = "120%";allSelect.style.padding = "0 5px";allSelect.style.margin = "3px";list1.appendChild(allSelect);allSelect.addEventListener("click", () => {const infos = Array.from(document.getElementsByClassName("userInfoItem"));for (let info of infos) {this.ClickList(info);}});const detailButton = document.createElement("input");detailButton.type = "button";detailButton.value = "設定";detailButton.style.color = "black";detailButton.style.fontSize = "120%";detailButton.style.margin = "3px";detailButton.style.marginLeft = "45px";detailButton.style.padding = "0 10px";list1.appendChild(detailButton);detailButton.addEventListener("click", () => detailDialog.style.display = (detailDialog.style.display == "none") ? "block" : "none");const detailDialog = document.createElement("div");detailDialog.style.backgroundColor = "white";detailDialog.style.display = "none";detailDialog.style.position = "absolute";detailDialog.style.paddingLeft = "10px";detailDialog.style.zIndex = "100";detailDialog.style.border = "2px solid";detailDialog.style.left = "360px";detailDialog.style.top = "10px";detailDialog.style.minWidth = "350px";list1.appendChild(detailDialog);const useSettingH3 = document.createElement("h1");useSettingH3.textContent = "使うところ";useSettingH3.style.fontSize = "140%";useSettingH3.style.marginTop = "10px";useSettingH3.style.color = "black";detailDialog.appendChild(useSettingH3);const setUseListDiv = document.createElement("div");setUseListDiv.style.marginBottom = "10px";setUseListDiv.style.display = "flex";setUseListDiv.style.flexWrap = "wrap";detailDialog.appendChild(setUseListDiv);{for (let i = 0; i < pageInfos.length; i++) {const setUseLabel = document.createElement("label");setUseLabel.style.display = "inline-block";setUseListDiv.appendChild(setUseLabel);{const setUsePageCheckbox = document.createElement("input");setUsePageCheckbox.type = "checkbox";setUsePageCheckbox.checked = this.option.usePages[i];setUsePageCheckbox.style.padding = "3px";setUsePageCheckbox.style.margin = "10px";setUsePageCheckbox.style.marginRight = "3px";setUseLabel.appendChild(setUsePageCheckbox);setUsePageCheckbox.addEventListener("change", async () => {this.option.usePages[i] = setUsePageCheckbox.checked;await this.optionStorage.SetStorageData(this.option);});const setUsePageText = document.createElement("span");setUsePageText.textContent = pageInfos[i].name;setUsePageText.style.padding = "3px";setUsePageText.style.fontSize = "120%";setUsePageText.style.color = "black";setUseLabel.appendChild(setUsePageText);}}}const otherSettingH3 = document.createElement("h1");otherSettingH3.textContent = "イラストサムネ";otherSettingH3.style.fontSize = "140%";otherSettingH3.style.marginTop = "10px";otherSettingH3.style.color = "black";detailDialog.appendChild(otherSettingH3);const setCreateUserLinkDiv = document.createElement("div");setCreateUserLinkDiv.style.display = "flex";detailDialog.appendChild(setCreateUserLinkDiv);{const setCreateUserLinkChackbox = document.createElement("input");setCreateUserLinkChackbox.type = "checkbox";setCreateUserLinkChackbox.id = "createUserLink";setCreateUserLinkChackbox.checked = this.option.createUserLink;setCreateUserLinkChackbox.style.padding = "3px";setCreateUserLinkChackbox.style.margin = "10px";setCreateUserLinkChackbox.style.marginRight = "3px";setCreateUserLinkDiv.appendChild(setCreateUserLinkChackbox);setCreateUserLinkChackbox.addEventListener("change", async () => {this.option.createUserLink = setCreateUserLinkChackbox.checked;await this.optionStorage.SetStorageData(this.option);});const setCreateUserLinkDivLabel = document.createElement("label");setCreateUserLinkDivLabel.htmlFor = "createUserLink";setCreateUserLinkDivLabel.textContent = "ユーザー名をユーザーページへのリンクにする";setCreateUserLinkDivLabel.style.color = "black";setCreateUserLinkDivLabel.style.padding = "3px";setCreateUserLinkDivLabel.style.fontSize = "120%";setCreateUserLinkDiv.appendChild(setCreateUserLinkDivLabel);}const setCreateBlackWhiteButtonDiv = document.createElement("div");setCreateBlackWhiteButtonDiv.style.display = "flex";detailDialog.appendChild(setCreateBlackWhiteButtonDiv);{const setCreateBlackWhiteButtonChackbox = document.createElement("input");setCreateBlackWhiteButtonChackbox.type = "checkbox";setCreateBlackWhiteButtonChackbox.id = "setCreateBlackWhiteButton";setCreateBlackWhiteButtonChackbox.checked = this.option.createBlackWhiteButton;setCreateBlackWhiteButtonChackbox.style.padding = "3px";setCreateBlackWhiteButtonChackbox.style.margin = "10px";setCreateBlackWhiteButtonChackbox.style.marginRight = "3px";setCreateBlackWhiteButtonDiv.appendChild(setCreateBlackWhiteButtonChackbox);setCreateBlackWhiteButtonChackbox.addEventListener("change", async () => {this.option.createBlackWhiteButton = setCreateBlackWhiteButtonChackbox.checked;await this.optionStorage.SetStorageData(this.option);});const setCreateBlackWhiteButtonLabel = document.createElement("label");setCreateBlackWhiteButtonLabel.htmlFor = "setCreateBlackWhiteButton";setCreateBlackWhiteButtonLabel.textContent = "白黒ボタンを付ける";setCreateBlackWhiteButtonLabel.style.color = "black";setCreateBlackWhiteButtonLabel.style.padding = "3px";setCreateBlackWhiteButtonLabel.style.fontSize = "120%";setCreateBlackWhiteButtonDiv.appendChild(setCreateBlackWhiteButtonLabel);}const otherSettingH4 = document.createElement("h1");otherSettingH4.textContent = "連投自動NG";otherSettingH4.style.fontSize = "140%";otherSettingH4.style.marginTop = "10px";otherSettingH4.style.color = "black";detailDialog.appendChild(otherSettingH4);const judgeRigorCover = document.createElement("div");const setIsJudgeDiv = document.createElement("div");setIsJudgeDiv.style.display = "flex";detailDialog.appendChild(setIsJudgeDiv);{const isJudgeCheckbox = document.createElement("input");isJudgeCheckbox.type = "checkbox";isJudgeCheckbox.id = "isJudgeCheckbox";isJudgeCheckbox.checked = this.option.judge.isJudge;isJudgeCheckbox.style.padding = "3px";isJudgeCheckbox.style.margin = "10px";isJudgeCheckbox.style.marginRight = "3px";setIsJudgeDiv.appendChild(isJudgeCheckbox);isJudgeCheckbox.addEventListener("change", async () => {this.option.judge.isJudge = isJudgeCheckbox.checked;if (this.option.judge.isJudge) {judgeRigorCover.style.visibility = "hidden";}else {judgeRigorCover.style.visibility = "visible";}await this.optionStorage.SetStorageData(this.option);});const isJudgeLabel = document.createElement("label");isJudgeLabel.htmlFor = "isJudgeCheckbox";isJudgeLabel.textContent = "有効にする";isJudgeLabel.style.color = "black";isJudgeLabel.style.padding = "3px";isJudgeLabel.style.fontSize = "120%";setIsJudgeDiv.appendChild(isJudgeLabel);}const setJudgeDiv = document.createElement("div");setJudgeDiv.style.padding = "5px";setJudgeDiv.style.position = "relative";detailDialog.appendChild(setJudgeDiv);{const setJudgeRigorDiv = document.createElement("div");setJudgeRigorDiv.style.padding = "0px 10px 5px 10px";setJudgeDiv.appendChild(setJudgeRigorDiv);{const setJudgeTime = document.createElement("input");setJudgeTime.type = "time";setJudgeTime.style.height = "20px";setJudgeTime.style.fontSize = "120%";const hour = ('00' + Math.floor(this.option.judge.time / 60 / 1000 / 60).toString()).slice(-2);const minutes = ('00' + (this.option.judge.time / 60 / 1000 % 60).toString()).slice(-2);setJudgeTime.value = `${hour}:${minutes}`;setJudgeTime.addEventListener("change", async () => {const [h, m] = setJudgeTime.value.split(":").map(s => parseInt(s));const ms = ((h * 60) + m) * 60 * 1000;if (ms >= 1) {this.option.judge.time = ms;await this.optionStorage.SetStorageData(this.option);}else {const hour = ('00' + Math.floor(this.option.judge.time / 60 / 1000 / 60).toString()).slice(-2);const minutes = ('00' + (this.option.judge.time / 60 / 1000 % 60).toString()).slice(-2);setJudgeTime.value = `${hour}:${minutes}`;}});setJudgeRigorDiv.appendChild(setJudgeTime);const setJudgeText1 = document.createElement("span");setJudgeText1.textContent = "以内に";setJudgeText1.style.color = "black";setJudgeText1.style.fontSize = "15px";setJudgeRigorDiv.appendChild(setJudgeText1);const setJudgePostCount = document.createElement("input");setJudgePostCount.type = "number";setJudgePostCount.value = this.option.judge.postCount.toString();setJudgePostCount.min = "2";setJudgePostCount.style.width = "40px";setJudgePostCount.style.height = "20px";setJudgePostCount.style.fontSize = "120%";setJudgePostCount.addEventListener("change", async () => {const num = parseInt(setJudgePostCount.value);if (num >= 2) {this.option.judge.postCount = num;await this.optionStorage.SetStorageData(this.option);}else {this.option.judge.postCount = 2;setJudgePostCount.value = this.option.judge.postCount.toString();}});setJudgeRigorDiv.appendChild(setJudgePostCount);const setJudgeText2 = document.createElement("span");setJudgeText2.textContent = "回投稿で仮荒らし認定";setJudgeText2.style.color = "black";setJudgeText2.style.fontSize = "15px";setJudgeRigorDiv.appendChild(setJudgeText2);}const setJudgePeriodDiv = document.createElement("div");setJudgePeriodDiv.style.padding = "0px 10px 5px 10px";setJudgeDiv.appendChild(setJudgePeriodDiv);{//日const setJudgePeriod = document.createElement("input");setJudgePeriod.style.marginRight = "5px";setJudgePeriod.type = "text";setJudgePeriod.style.width = "40px";setJudgePeriod.style.height = "18px";setJudgePeriod.style.fontSize = "120%";setJudgePeriod.value = this.option.judge.period.toString();setJudgePeriodDiv.appendChild(setJudgePeriod);setJudgePeriod.addEventListener("change", async () => {const num = Number(setJudgePeriod.value);if (num >= 0) {this.option.judge.period = num;await this.optionStorage.SetStorageData(this.option);}else {this.option.judge.period = 0;setJudgePeriod.value = this.option.judge.period.toString();}});const setJudgePeriodText = document.createElement("span");setJudgePeriodText.textContent = "日前のイラストまで対象(0で無限)";setJudgePeriodText.style.color = "black";setJudgePeriodText.style.fontSize = "15px";setJudgePeriodDiv.appendChild(setJudgePeriodText);}const setAutoNGHiddenDiv = document.createElement("div");setAutoNGHiddenDiv.style.padding = "0px 10px";setJudgeDiv.appendChild(setAutoNGHiddenDiv);{const setAutoNGHiddenLabel = document.createElement("label");setAutoNGHiddenDiv.appendChild(setAutoNGHiddenLabel);{const setAutoNGHiddenCheckbox = document.createElement("input");setAutoNGHiddenCheckbox.style.padding = "3px";setAutoNGHiddenCheckbox.style.marginRight = "5px";setAutoNGHiddenCheckbox.type = "checkbox";setAutoNGHiddenCheckbox.checked = this.option.judge.isAutoNGHidden;setAutoNGHiddenLabel.appendChild(setAutoNGHiddenCheckbox);setAutoNGHiddenCheckbox.addEventListener("change", async () => {this.option.judge.isAutoNGHidden = setAutoNGHiddenCheckbox.checked;for (let info of this.illustInfos) {this.UpdateIllust(info);this.DrawBlackWhiteButton(info);}this.UpdateIllustList();await this.optionStorage.SetStorageData(this.option);});const setAutoNGHiddenText = document.createElement("span");setAutoNGHiddenText.textContent = "自動NGしたのを非表示にする";setAutoNGHiddenText.style.color = "black";setAutoNGHiddenText.style.fontSize = "15px";setAutoNGHiddenLabel.appendChild(setAutoNGHiddenText);}}judgeRigorCover.style.backgroundColor = "gray";judgeRigorCover.style.width = "320px";judgeRigorCover.style.height = "100%";judgeRigorCover.style.zIndex = "1000";judgeRigorCover.style.opacity = "0.5";judgeRigorCover.style.position = "absolute";judgeRigorCover.style.top = "0";setJudgeDiv.appendChild(judgeRigorCover);if (this.option.judge.isJudge) {judgeRigorCover.style.visibility = "hidden";}else {judgeRigorCover.style.visibility = "visible";}}const otherSettingH5 = document.createElement("h1");otherSettingH5.textContent = "その他";otherSettingH5.style.fontSize = "140%";otherSettingH5.style.marginTop = "10px";otherSettingH5.style.color = "black";detailDialog.appendChild(otherSettingH5);//const setToOKPeriodDiv = document.createElement("div");//setToOKPeriodDiv.style.padding = "5px";//detailDialog.appendChild(setToOKPeriodDiv);//{//    const setToOKPeriodText1 = document.createElement("div");//    setToOKPeriodText1.textContent = "取得したなかで最新絵が";//    setToOKPeriodText1.style.color = "black";//    setToOKPeriodText1.style.fontSize = "15px";//    setToOKPeriodDiv.appendChild(setToOKPeriodText1);//    const setToOKPeriodText2 = document.createElement("div");//    setToOKPeriodText2.textContent = "これより前のものなら未分類化(0で無効)";//    setToOKPeriodText2.style.color = "black";//    setToOKPeriodText2.style.fontSize = "15px";//    setToOKPeriodDiv.appendChild(setToOKPeriodText2);//    for (let i = Status.OK; i < Status.MAX; i++) {//        const setToOKPeriodStatusDiv = document.createElement("div");//        setToOKPeriodDiv.appendChild(setToOKPeriodStatusDiv);//        const setToOKPeriodStatusNameText = document.createElement("span");//        setToOKPeriodStatusNameText.textContent = Status[i]+": ";//        setToOKPeriodStatusNameText.style.color = "black";//        setToOKPeriodStatusNameText.style.fontSize = "15px";//        setToOKPeriodStatusDiv.appendChild(setToOKPeriodStatusNameText);//        if (i == Status.OK) {//            const setToOKPeriodStatusOKText = document.createElement("span");//            setToOKPeriodStatusOKText.textContent = "これが未分類リスト";//            setToOKPeriodStatusOKText.style.color = "black";//            setToOKPeriodStatusOKText.style.fontSize = "15px";//            setToOKPeriodStatusDiv.appendChild(setToOKPeriodStatusOKText);//            continue;//        }//        //日//        const setToOKPeriod = document.createElement("input");//        setToOKPeriod.style.marginRight = "5px";//        setToOKPeriod.type = "text";//        setToOKPeriod.style.width = "40px";//        setToOKPeriod.style.height = "5px";//        setToOKPeriod.style.fontSize = "120%";//        setToOKPeriod.value = this.option.judge.period.toString();//        setToOKPeriodStatusDiv.appendChild(setToOKPeriod);//        setToOKPeriod.addEventListener("change", async () => {//            const num = Number(setToOKPeriod.value);//            if (num >= 0) {//                this.option.judge.period = num;//                await this.optionStorage.SetStorageData(this.option);//            } else {//                this.option.judge.period = 0;//                setToOKPeriod.value = this.option.judge.period.toString();//            }//        });//        const setToOKPeriodText = document.createElement("span");//        setToOKPeriodText.textContent = "日";//        setToOKPeriodText.style.color = "black";//        setToOKPeriodText.style.fontSize = "15px";//        setToOKPeriodStatusDiv.appendChild(setToOKPeriodText);//    }//}const setOKCacheMaxFlex = document.createElement("div");setOKCacheMaxFlex.style.padding = "5px";detailDialog.appendChild(setOKCacheMaxFlex);{const setOKCacheMaxText1 = document.createElement("span");setOKCacheMaxText1.textContent = "OKユーザーのキャッシュ最大数:";setOKCacheMaxText1.style.color = "black";setOKCacheMaxText1.style.fontSize = "15px";setOKCacheMaxFlex.appendChild(setOKCacheMaxText1);const setOKCacheMax = document.createElement("input");setOKCacheMax.type = "number";setOKCacheMax.value = this.option.okCacheMax.toString();setOKCacheMax.style.width = "80px";setOKCacheMax.min = "100";setOKCacheMax.style.height = "20px";setOKCacheMax.style.fontSize = "120%";setOKCacheMax.addEventListener("change", async () => {const num = parseInt(setOKCacheMax.value);if (num >= 100) {this.option.okCacheMax = num;await this.optionStorage.SetStorageData(this.option);}else {this.option.okCacheMax = 100;setOKCacheMax.value = this.option.okCacheMax.toString();}});setOKCacheMaxFlex.appendChild(setOKCacheMax);}}const list2 = document.createElement("div");list2.style.position = "relative";list2.style.display = "flex";this.optionDialog.appendChild(list2);{const userInfoList = document.createElement("ul");userInfoList.className = "scrollUL";userInfoList.style.overflowY = "scroll";userInfoList.style.overflowX = "hidden";userInfoList.style.height = "400px";userInfoList.style.width = "250px";list2.appendChild(userInfoList);const buttonList = document.createElement("ul");buttonList.style.width = "90px";list2.appendChild(buttonList);{const moveButtonList = document.createElement("div");moveButtonList.style.marginTop = "20px";moveButtonList.style.marginBottom = "10px";buttonList.appendChild(moveButtonList);{for (let i = Status.OK; i < Status.MAX; i++) {const div = document.createElement("div");moveButtonList.appendChild(div);{const toButton = document.createElement("input");toButton.type = "button";toButton.style.padding = "3px";toButton.style.fontSize = "130%";toButton.style.margin = "3px";toButton.value = "→ " + Status[i];toButton.name = Status[i];div.appendChild(toButton);toButton.addEventListener("click", async () => {while (this.selectedList.length != 0) {const element = this.selectedList.pop();if (element == undefined) {continue;}element.style.backgroundColor = "";const userId = element.getElementsByClassName("userId")[0].textContent;if (userId == undefined) {continue;}const user = this.cache.get(userId);if (user != undefined) {user.status = Status[toButton.name];}}for (let info of this.illustInfos) {this.UpdateIllust(info);this.DrawBlackWhiteButton(info);}this.UpdateIllustList();this.DrawList();await this.cacheStorage.SetStorageData([...this.cache]);});}}}const DeleteSelectedUser = () => {while (this.selectedList.length != 0) {const element = this.selectedList.pop();if (element == undefined) {continue;}const userId = element.getElementsByClassName("userId")[0].textContent;if (userId == undefined) {continue;}this.cache.delete(userId);const infos = this.illustInfos.filter(info => info.userId == userId);for (let info of infos) {info.user.status = Status.WHITE;this.UpdateIllust(info);this.DrawBlackWhiteButton(info);}this.UpdateIllustList();this.illustInfos = this.illustInfos.filter(info => info.userId != userId);}};const div = document.createElement("div");buttonList.appendChild(div);{const selectedCacheClearButton = document.createElement("input");selectedCacheClearButton.type = "button";selectedCacheClearButton.style.padding = "3px";selectedCacheClearButton.style.fontSize = "120%";selectedCacheClearButton.style.margin = "3px";selectedCacheClearButton.style.marginTop = "5px";selectedCacheClearButton.style.backgroundColor = "yellow";selectedCacheClearButton.style.cssText += "color: black !important";selectedCacheClearButton.value = "→ DELETE";div.appendChild(selectedCacheClearButton);selectedCacheClearButton.addEventListener("click", async () => {if (!window.confirm("選択したアイテムのキャッシュクリアしていいですか?\nホワイト・ブラックリストも削除されます。")) {return;}DeleteSelectedUser();this.DrawList();await this.cacheStorage.SetStorageData([...this.cache]);});}const div2 = document.createElement("div");buttonList.appendChild(div2);{const allCacheClearButton = document.createElement("input");allCacheClearButton.type = "button";allCacheClearButton.style.padding = "3px";allCacheClearButton.style.fontSize = "120%";allCacheClearButton.style.margin = "3px";allCacheClearButton.style.backgroundColor = "red";allCacheClearButton.value = "ALL DELETE";div2.appendChild(allCacheClearButton);allCacheClearButton.addEventListener("click", async () => {if (!window.confirm("全キャッシュクリアしていいですか?\nホワイト・ブラックリストも削除されます。")) {return;}for (let info of this.illustInfos) {info.user.status = Status.WHITE;this.UpdateIllust(info);this.DrawBlackWhiteButton(info);}this.illustInfos = [];this.UpdateIllustList();this.cache.clear();this.DrawList();await this.cacheStorage.SetStorageData([...this.cache]);});}const div3 = document.createElement("div");buttonList.appendChild(div3);{const reStartButton = document.createElement("input");reStartButton.type = "button";reStartButton.style.padding = "3px";reStartButton.style.fontSize = "120%";reStartButton.style.margin = "3px";reStartButton.style.marginTop = "10px";reStartButton.style.backgroundColor = "green";reStartButton.style.cssText += "color: white !important";reStartButton.value = "RE START";div3.appendChild(reStartButton);reStartButton.addEventListener("click", async () => {await this.Run();});}const div4 = document.createElement("div");div4.style.marginTop = "10px";div4.style.marginBottom = "10px";buttonList.appendChild(div4);{const importDiv = document.createElement("div");importDiv.style.position = "relative";div4.appendChild(importDiv);{const importButton = document.createElement("input");importButton.type = "button";importButton.style.padding = "3px";importButton.style.fontSize = "120%";importButton.style.margin = "3px";importButton.style.marginTop = "10px";importButton.value = "← IMPORT";importDiv.appendChild(importButton);const importFile = document.createElement("input");importFile.type = "file";importFile.style.position = "absolute";importFile.style.opacity = "0";importFile.style.width = "80px";importFile.style.top = "8px";importFile.style.left = "0";importFile.accept = "text/plain";importFile.style.padding = "0";importDiv.appendChild(importFile);importFile.addEventListener("change", async (e) => {if (e.target == null) {return;}const files = e.target.files;if (files == null) {return;}const file = files[0];if (file.type != "text/plain") {alert("テキストファイルを入れてください。");return;}if (!window.confirm("インポートしていいですか?\nインポートする前に、今選択しているユーザーは削除されます。")) {return;}DeleteSelectedUser();this.DrawList();const reader = new FileReader();reader.readAsText(file);reader.onload = async () => {if (typeof reader.r###lt != "string") {return;}const importUsers = this.ListToMap(JSON.parse(reader.r###lt));for (let [imUserId, imUser] of importUsers) {for (let illust of imUser.illusts) {illust.created = new Date(illust.created);}}for (let [imUserId, imUser] of importUsers) {if (imUser == null) {continue;}const cachedUser = this.cache.get(imUserId);if (cachedUser == undefined) {this.cache.set(imUserId, imUser);}else {cachedUser.status = imUser.status;for (let illust of cachedUser.illusts) {if (cachedUser.illusts.some(c => c.illustId == illust.illustId)) {continue;}if (illust == null) {continue;}cachedUser.illusts.push(illust);}}}await this.cacheStorage.SetStorageData([...this.cache]);this.Run();};});}const exportEiv = document.createElement("div");div4.appendChild(exportEiv);{const reStartButton = document.createElement("input");reStartButton.type = "button";reStartButton.style.padding = "3px";reStartButton.style.fontSize = "120%";reStartButton.style.margin = "3px";reStartButton.style.marginTop = "5px";reStartButton.value = "→ EXPORT";exportEiv.appendChild(reStartButton);reStartButton.addEventListener("click", async () => {const selectedUsers = new Map();for (let element of this.selectedList) {if (element == undefined) {continue;}const userId = element.getElementsByClassName("userId")[0].textContent;if (userId == null) {continue;}const user = this.cache.get(userId);if (user != undefined) {selectedUsers.set(userId, user);}}if (selectedUsers.size == 0) {alert("出力するユーザーを選択してください");return;}const listStatusSelect = this.optionDialog.getElementsByClassName("listStatusSelect")[0];const status = listStatusSelect.value;const blob = new Blob([JSON.stringify(selectedUsers)], { type: "text/plain" });const dlUrl = URL.createObjectURL(blob);await Util.Download(dlUrl, `niconicoNG_${status}.txt`);});}}}}}}}UpdateIllust(info) {const img = info.element.getElementsByTagName("img")[0] ?? info.element.getElementsByClassName("image-layer")[0];if (info.user.status == Status.OK || info.user.status == Status.WHITE) {if (img != null) {img.style.filter = "brightness(1)";}if (info.element.parentElement == null) {info.parent.appendChild(info.element);}}if (info.user.status == Status.NG || (info.user.status == Status.AUTO && !this.option.judge.isAutoNGHidden)) {if (img != null) {img.style.filter = "brightness(0.3)";}info.parent.appendChild(info.element);}if (info.user.status == Status.BLACK || (info.user.status == Status.AUTO && this.option.judge.isAutoNGHidden)) {info.element.remove();}}UpdateIllustList() {for (let illustListElement of this.illustListElements) {if (this.currentPage == VirtualPageType.ILLUST) {for (let moreLink of Array.from(illustListElement.getElementsByClassName("list_more_link"))) {if (moreLink.parentElement == null) {continue;}moreLink.parentElement.appendChild(moreLink);}}if (this.currentPage == VirtualPageType.KEYWORD_SEARCH) {const brs = illustListElement.getElementsByTagName("br");while (brs.length) {brs[0].remove();}for (var i = 0; i < illustListElement.childElementCount; i++) {if ((i % 6) != 4) {continue;}illustListElement.children[i].insertAdjacentHTML("afterend", "<br clear='all'>");}illustListElement.insertAdjacentHTML("beforeend", "<br clear='all'>");}if (this.currentPage == VirtualPageType.PERSONALIZE) {const brs = Array.from(illustListElement.getElementsByTagName("br"));for (let br of brs) {br.remove();}const items = Array.from(illustListElement.getElementsByClassName(virtualPageInfos[this.currentPage].illustItemName));for (let i = 0; i < items.length; i++) {if ((i + 1) % 4 == 0 || i == items.length - 1) {const br = document.createElement("br");br.clear = "all";items[i].insertAdjacentElement("afterend", br);}}}if (this.currentPage == VirtualPageType.ADS) {const ds = illustListElement.getElementsByClassName("ADS_Dammy");while (ds.length)ds[0].remove();if (1 < illustListElement.childElementCount) {for (var i = illustListElement.childElementCount; i < 3; i++) {const dammy = document.createElement("div");dammy.classList.add("ADS_Dammy");dammy.style.width = illustListElement.children[0].clientWidth + "px";illustListElement.appendChild(dammy);}}}}}CreateUserLink(illustInfo) {if (this.currentPage == VirtualPageType.PERSONALIZE || !this.option.createUserLink || illustInfo.element.getElementsByClassName("userLink").length > 0) {return;}const userElement = illustInfo.element.getElementsByClassName("user")[0];if (userElement == null) {return;}const userA = document.createElement("a");userA.className = "userLink";userA.href = "https://seiga.nicovideo.jp/user/illust/" + illustInfo.userId;userA.style.left = "0";userA.style.zIndex = "10";userA.style.right = "10px";userA.style.position = "absolute";userA.style.border = "0";userA.style.opacity = "0";userA.addEventListener("mouseover", () => {userA.style.border = "solid 1px silver";userA.style.opacity = "0.3";});userA.addEventListener("mouseleave", () => {userA.style.border = "0";userA.style.opacity = "0";});if (this.currentPage == VirtualPageType.TAG_SEARCH) {userA.style.height = "10px";userA.style.top = "34px";userA.style.backgroundColor = "silver";}if (this.currentPage == VirtualPageType.ILLUST) {userA.style.height = "20px";userA.style.top = "20px";userA.style.backgroundColor = "black";}userElement.style.position = "relative";userElement.style.zIndex = "20";userElement.style.pointerEvents = "none";userElement.insertAdjacentElement("beforebegin", userA);}async DrawBlackWhiteButton(illustInfo) {if (!this.option.createBlackWhiteButton) {return;}if (illustInfo.user.status == Status.BLACK || illustInfo.user.status == Status.WHITE) {if (illustInfo.user.status == Status.WHITE) {const list = Array.from(illustInfo.element.getElementsByClassName("toListButton"));for (let l of list) {l.remove();}}return;}if (illustInfo.element.getElementsByClassName("toListButton").length > 0) {return;}const whiteButton = document.createElement("input");const blackButton = document.createElement("input");whiteButton.style.zIndex = "20";whiteButton.style.visibility = "hidden";whiteButton.style.cursor = "default";if (this.currentPage == VirtualPageType.TAG_SEARCH) {whiteButton.style.left = "117px";whiteButton.style.top = "-30px";whiteButton.style.width = "40px";whiteButton.style.height = "25px";whiteButton.style.position = "relative";}if (this.currentPage == VirtualPageType.ILLUST) {whiteButton.style.left = "54px";whiteButton.style.top = "-19px";whiteButton.style.width = "30px";whiteButton.style.height = "19px";whiteButton.style.position = "relative";}if (this.currentPage == VirtualPageType.PERSONALIZE) {whiteButton.style.top = "240px";whiteButton.style.width = "40px";whiteButton.style.height = "25px";whiteButton.style.position = "absolute";illustInfo.element.style.position = "relative";illustInfo.element.style.height = "258px";}if (this.currentPage == VirtualPageType.ADS) {whiteButton.style.top = "85px";whiteButton.style.width = "30px";whiteButton.style.height = "19px";whiteButton.style.position = "absolute";whiteButton.style.border = "2px solid #736b5e";illustInfo.element.style.position = "relative";}if (this.currentPage == VirtualPageType.KEYWORD_SEARCH) {whiteButton.style.top = "144px";whiteButton.style.width = "30px";whiteButton.style.height = "19px";whiteButton.style.position = "absolute";illustInfo.element.style.position = "relative";}//上記のスタイルを両方に適用blackButton.style.cssText = whiteButton.style.cssText;whiteButton.type = "button";blackButton.type = "button";whiteButton.className = "toListButton";blackButton.className = "toListButton";whiteButton.name = "white";blackButton.name = "black";whiteButton.style.cssText += `background-color : white !important;`;blackButton.style.cssText += `background-color : black !important;`;if (this.currentPage == VirtualPageType.PERSONALIZE) {whiteButton.style.left = "77px";blackButton.style.left = "117px";}if (this.currentPage == VirtualPageType.ADS) {whiteButton.style.left = "135px";blackButton.style.left = "165px";}if (this.currentPage == VirtualPageType.KEYWORD_SEARCH) {whiteButton.style.right = "28px";blackButton.style.right = "-2px";}whiteButton.addEventListener("contextmenu", async (e) => {e.preventDefault();illustInfo.user.status = Status.OK;for (let info of this.illustInfos) {this.UpdateIllust(info);}this.UpdateIllustList();this.DrawList();await this.cacheStorage.SetStorageData([...this.cache]);});whiteButton.addEventListener("click", async () => {illustInfo.user.status = Status.WHITE;for (let info of this.illustInfos) {this.UpdateIllust(info);const buttons = info.element.getElementsByClassName("toListButton");while (buttons.length != 0) {buttons[0].remove();}}this.UpdateIllustList();this.DrawList();await this.cacheStorage.SetStorageData([...this.cache]);});blackButton.addEventListener("contextmenu", async (e) => {e.preventDefault();illustInfo.user.status = Status.NG;for (let info of this.illustInfos) {this.UpdateIllust(info);}this.UpdateIllustList();this.DrawList();await this.cacheStorage.SetStorageData([...this.cache]);});blackButton.addEventListener("click", async () => {illustInfo.user.status = Status.BLACK;for (let info of this.illustInfos) {this.UpdateIllust(info);}this.UpdateIllustList();this.DrawList();await this.cacheStorage.SetStorageData([...this.cache]);});if (this.currentPage == VirtualPageType.TAG_SEARCH) {const infoElement = illustInfo.element.getElementsByClassName("illust_count")[0];blackButton.addEventListener("mouseover", () => {infoElement.style.opacity = "1";});blackButton.addEventListener("mouseleave", () => {infoElement.style.opacity = "";});whiteButton.addEventListener("mouseover", () => {infoElement.style.opacity = "1";});whiteButton.addEventListener("mouseleave", () => {infoElement.style.opacity = "";});}if (this.currentPage == VirtualPageType.ILLUST) {const infoElement = illustInfo.element.getElementsByClassName("illust_info")[0];blackButton.addEventListener("mouseover", () => {infoElement.style.bottom = "0px";});blackButton.addEventListener("mouseleave", () => {infoElement.style.bottom = "";});whiteButton.addEventListener("mouseover", () => {infoElement.style.bottom = "0px";});whiteButton.addEventListener("mouseleave", () => {infoElement.style.bottom = "";});}illustInfo.element.addEventListener("mouseover", () => {blackButton.style.visibility = "visible";whiteButton.style.visibility = "visible";});illustInfo.element.addEventListener("touchstart", () => {blackButton.style.visibility = "visible";whiteButton.style.visibility = "visible";});illustInfo.element.addEventListener("mouseleave", () => {blackButton.style.visibility = "hidden";whiteButton.style.visibility = "hidden";});illustInfo.element.addEventListener("touchend", () => {blackButton.style.visibility = "hidden";whiteButton.style.visibility = "hidden";});if (this.currentPage == VirtualPageType.ADS) {illustInfo.element.insertAdjacentElement("afterbegin", blackButton);illustInfo.element.insertAdjacentElement("afterbegin", whiteButton);return;}illustInfo.element.appendChild(whiteButton);illustInfo.element.appendChild(blackButton);}async AddInfos(illustListElement) {const illustItemName = virtualPageInfos[this.currentPage].illustItemName;let illustElements;if (this.currentPage == VirtualPageType.KEYWORD_SEARCH || this.currentPage == VirtualPageType.PERSONALIZE) {illustElements = Array.from(illustListElement.getElementsByClassName(illustItemName));}else {illustElements = Array.from(illustListElement.getElementsByTagName("li")).filter(e => illustItemName == "" || e.classList.contains(illustItemName) || e.firstElementChild?.classList.contains(illustItemName));}const illustIds = this.GetIllustIds(illustListElement);const names = Array.from(illustListElement.getElementsByClassName("user"));//console.log(illustIds);//console.log(illustElements);//console.log(names);//キャッシュからの情報と合わせて追加(もうこれ分かんねぇこともある)for (let i = 0; i < illustIds.length; i++) {if (this.illustInfos.some(info => info.illust.illustId == illustIds[i] && info.element == illustElements[i])) {continue;}if (illustElements[i] == null) {continue;}const info = this.GetInfo(illustIds[i]);if (info != undefined && names[i]?.textContent != null) {info.user.name = names[i].textContent ?? info.user.name;}this.illustInfos.push({userId: info == undefined ? "" : info.userId,illust: info == undefined ? { created: "", illustId: illustIds[i] } : info.illust,user: info == undefined ? { illusts: [], status: Status.NONE, name: names[i]?.textContent ?? "" } : info.user,element: illustElements[i],parent: illustListElement});}}SetCurrentPage(url) {for (let i = 0; i < pageInfos.length; i++) {if (pageInfos[i].regex.test(url)) {this.currentPage = pageInfos[i].type;return this.option.usePages[i];}}this.currentPage = VirtualPageType.None;return false;}GetPage() {return this.currentPage;}//メインクラス、メイン関数の肥大化もう始まってる!async Run(illustListElements) {const illustListName = virtualPageInfos[this.currentPage].illustListName;let firstIllustListElement;if (illustListName == "") {firstIllustListElement = await Observer.DefinitelyGetElementByTagName("ul", undefined, { isDeepSearch: true });}else {firstIllustListElement = await Observer.DefinitelyGetElementByClassName(illustListName, undefined, { isDeepSearch: true });}if (this.currentPage == VirtualPageType.ADS) {await Observer.DefinitelyGetElementByTagName("li", undefined, { isDeepSearch: true });if (firstIllustListElement) {firstIllustListElement.style.visibility = "hidden";firstIllustListElement.style.overflow = "hidden";}}await Util.WithTimeOut(Observer.DefinitelyGetElementById("footer"), 1000);if (illustListElements == null) {if (illustListName == "") {illustListElements = Array.from(document.getElementsByTagName("ul"));}else {illustListElements = Array.from(document.getElementsByClassName(illustListName));}}for (let illustListElement of illustListElements) {illustListElement.style.visibility = "hidden";await this.AddInfos(illustListElement);this.illustListElements.add(illustListElement);}//console.log("infos", this.illustInfos, this.illustInfos.length);//誰のイラストかこれもう分かんねぇやつ達const unkownInfos = this.illustInfos.filter(info => info.userId == "");//console.log("unkownInfos", unkownInfos);//この戻り値なんかダサい・・・ダサくない?const r###lt = await Fetcher.FetchIllustDatas(unkownInfos.map(info => info.illust.illustId));//誰のかこれもう分かんねぇやつらとキャッシュまで!?の情報更新for (let i = 0; i < unkownInfos.length; i++) {if (r###lt.illusts[i] == null) {//alert("null!!!");//console.log(r###lt);//debugger;continue;}unkownInfos[i].illust = r###lt.illusts[i];unkownInfos[i].userId = r###lt.userIds[i];let cachedUser = this.cache.get(r###lt.userIds[i]);if (cachedUser == undefined) {if (unkownInfos[i].user == null) {//alert("null!!!");//console.log(unkownInfos);//debugger;continue;}unkownInfos[i].user.status = Status.OK;this.cache.set(unkownInfos[i].userId, unkownInfos[i].user);}else {////キャッシュ使ったら後ろにしとくthis.cache.delete(r###lt.userIds[i]);this.cache.set(r###lt.userIds[i], cachedUser);unkownInfos[i].user = cachedUser;}if (!unkownInfos[i].user.illusts.some(illust => illust.illustId == r###lt.illusts[i].illustId)) {unkownInfos[i].user.illusts.push(r###lt.illusts[i]);}}// IDが見つからないものを削除するthis.illustInfos = this.illustInfos.filter(info => info.userId != "");//増えすぎたキャッシュ削除if (this.cache.size > 0) {let okCount = 0;for (let [userId, user] of this.cache) {if (user.status == Status.OK) {okCount++;}}for (let [userId, user] of this.cache) {if (okCount < this.option.okCacheMax) {break;}//OK以外消さない//今使ってたら消さないif (user.status == Status.OK && !this.illustInfos.some(info => info.userId == userId)) {this.cache.delete(userId);okCount--;}}}//console.log(r###lt);//ブラック,ホワイトリストにないイラストエレメントにボタン追加for (let illustInfo of this.illustInfos) {this.DrawBlackWhiteButton(illustInfo);this.CreateUserLink(illustInfo);}if (this.option.judge.isJudge) {//投稿者の荒らし判定更新 ↓これは重複排除for (let c of [...new Set(this.illustInfos.map(u => u.user))]) {this.CheckAutoNG(c);}}await this.cacheStorage.SetStorageData([...this.cache]);for (let info of this.illustInfos) {this.UpdateIllust(info);}this.UpdateIllustList();for (let illustListElement of illustListElements) {illustListElement.style.visibility = "visible";}await this.SetOptionButton();this.DrawList();}async StartObserve() {const illustListName = virtualPageInfos[this.currentPage].illustListName;if (illustListName == "") {return;}const illustListParent = (await Observer.DefinitelyGetElementByClassName(illustListName)).parentNode;const mutationObserver = new MutationObserver(async (mrs) => {for (let mr of mrs) {for (let i = 0; i < mr.addedNodes.length; i++) {const element = mr.addedNodes[i];if (element.classList == null) {continue;}if (element.classList.contains(illustListName)) {await this.Run([element]);}}}});mutationObserver.observe(illustListParent ?? document, {childList: true,subtree: true});}};const main = new Main();await main.GetStorageData();const isUseNG = main.SetCurrentPage(location.href);await Util.WaitDocumentElement();main.SetOptionButton();if (!isUseNG) {return;}await main.Run();await main.StartObserve();})();