// ==UserScript==
// @name ニコニコ静画、簡単NGスクリプト
// @namespace http://tampermonkey.net/
// @version 0.810
// @description 申し訳ないが連投荒らしはNG
// @author cbxm
// @match https://seiga.nicovideo.jp/tag/*
// @grant GM.xmlHttpRequest
// @grant GM.getValue
// @grant GM.setValue
// @run-at document-start
// ==/UserScript==
(async () => {
"use strict";
;
;
class Util {
//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;
}
}
const tag = tagMatchs[1];
//タグの内側とその先を抜き出す
const matchChildlen = [];
while (true) {
const matchs = xmlString.match(new RegExp(`^[^<]*<${tag}>([^]+?)<\/${tag}>([^]*)`));
if (matchs == null) {
break;
}
matchChildlen.push(matchs[1]);
xmlString = matchs[2];
}
//タグあったのにマッチしなかったおかしい
if (matchChildlen.length == 0) {
return obj;
}
//そのタグが一つしかないとき、オブジェクトになる
if (matchChildlen.length == 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 Wait(ms) {
return new Promise(r => setTimeout(r, ms));
}
}
;
class Fetcher {
static GMFetchText(url) {
return new Promise(r => {
GM.xmlHttpRequest({
url: url,
method: "GET",
onload: (response) => {
r(response.responseText);
}
});
});
}
static async FetchIllustDatas(ids) {
if (ids.length == 0) {
return { illusts: [], userIds: [] };
}
const url = `http:\/\/seiga.nicovideo.jp/api/illust/info?id_list=${ids.join()}`;
const res = await this.GMFetchText(url);
const obj = Util.XmlToObj(res);
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] = {
id: 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 = "http://seiga.nicovideo.jp/api/user/info?id=" + userId;
const json = Util.XmlToObj(await this.GMFetchText(url));
return json.response.user.nickname;
}
static async FetchUserId(illustId) {
const url = "https://seiga.nicovideo.jp/api/illust/info?id=im" + illustId;
const resultText = await this.GMFetchText(url);
const json = Util.XmlToObj(resultText);
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)));
}
}
;
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 WaitAddedNode(predicate, parent, option = null) {
return new Promise(r => {
if (option == null) {
option = {
childList: true,
subtree: true
};
}
const mutationObserver = new MutationObserver((mrs) => {
//console.log(document.head.innerHTML);
//console.log(document.body.innerHTML);
for (let node of mrs) {
node.addedNodes.forEach(added => {
//console.log(added);
if (predicate(added)) {
mutationObserver.disconnect();
r(added);
return;
}
});
}
});
mutationObserver.observe(parent, option);
});
}
;
static async DefinitelyGetElementById(id, parent = document, option = null) {
const e = document.getElementById(id);
if (e != null) {
return e;
}
return this.WaitAddedNode(e => e.id != null && e.id == id, parent, option);
}
//getElementsByClassNameをつかうけど単体なので注意
static async DefinitelyGetElementByClassName(className, parent = document, option = null) {
const e = document.getElementsByClassName(className)[0];
if (e != null) {
return e;
}
return this.WaitAddedNode(e => e.className != null && e.className == className, parent, option);
}
//getElementsByTagNameをつかうけど単体なので注意
static async DefinitelyGetElementByTagName(tagName, parent = document, option = null) {
tagName = tagName.toUpperCase();
const e = document.getElementsByTagName(tagName)[0];
if (e != null) {
return e;
}
return this.WaitAddedNode(e => e.tagName != null && e.tagName == tagName, parent, option);
}
}
;
//暫定OK、暫定荒らし、確定OK、確定荒らし
//type Status = "OK" | "NG" | "LOK" | "LNG"
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["MAX"] = 5] = "MAX";
})(Status || (Status = {}));
class Main {
constructor() {
this.cache = [];
this.illustInfos = [];
this.selectedList = [];
this.cacheStorage = new Storage("NICONICO_RENTO_ARASI_NG_DATA_CACHE");
this.optionStorage = new Storage("NICONICO_RENTO_ARASI_NG_OPTION_CACHE");
}
async GetStorageData() {
this.cache = (await this.cacheStorage.GetStorageData([]))
.map(c => {
if (typeof c.status == "string") {
if (c.status == "LOK") {
c.status = Status.WHITE;
}
else if (c.status == "LNG") {
c.status = Status.BLACK;
}
else if (c.status == "OK") {
c.status = Status.OK;
}
else if (c.status == "NG") {
c.status = Status.NG;
}
else {
c.status = Status.OK;
}
}
return c;
});
//console.log(this.cache);
const defaultOption = {
judge: {
time: 1 * 60 * 60 * 1000,
postCount: 3
},
okCacheMax: 1000 //どのくらいがいいのかわからない
};
this.option = await this.optionStorage.GetStorageData(defaultOption);
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.okCacheMax == undefined) {
this.option.okCacheMax = defaultOption.okCacheMax;
}
//console.log(this.option);
}
GetInfo(illustId) {
for (let c of this.cache) {
for (let illust of c.illusts) {
if (illust.id == illustId) {
return { user: c, illust: illust };
}
}
}
return undefined;
}
ChackArasi(user) {
if (user.illusts.length == 0 || user.status == Status.BLACK || user.status == Status.WHITE || user.status == Status.NG) {
return;
}
for (let illust of user.illusts) {
if (typeof illust.created == "string") {
illust.created = new Date(illust.created);
}
}
//新しい順
const sorted = user.illusts.sort((a, b) => b.created.getTime() - a.created.getTime());
for (let i = 0; i < sorted.length; i++) {
const currentDate = sorted[i].created;
let j = i + 1;
let postCount = 1;
while (true) {
if (j >= sorted.length || currentDate.getTime() - sorted[j].created.getTime() > this.option.judge.time) {
break;
}
j++;
postCount++;
}
if (postCount >= this.option.judge.postCount) {
user.status = Status.NG;
return;
}
}
}
;
GetIllustIds(itemListElement) {
//document.getElementsByClassName("item_list")[0]
const illustIdElements = itemListElement.getElementsByTagName("a");
const illustIds = [];
for (let i = 0; i < illustIdElements.length; i++) {
const idMatchs = illustIdElements[i].href.match(/im(\d+)/);
if (idMatchs == null) {
continue;
}
const id = idMatchs[1];
illustIds.push(id);
}
return illustIds;
}
DrawList() {
const list = document.getElementById("scrollUL");
const onlyCurrentPageCheckbox = document.getElementById("onlyCurrentPageCheckbox");
const listStatusSelect = document.getElementById("listStatusSelect");
if (list == undefined || onlyCurrentPageCheckbox == undefined || listStatusSelect == undefined) {
return;
}
const status = Status[listStatusSelect.value];
list.innerHTML = "";
for (let user of this.cache) {
if (user.status == status) {
const info = this.illustInfos.find(info => info.user == user);
let sampleIllustId = info != undefined ? info.illustId : undefined;
if (onlyCurrentPageCheckbox.checked && sampleIllustId == undefined) {
continue;
}
if (sampleIllustId == undefined) {
sampleIllustId = user.illusts[0].id;
}
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("click", e => this.ClickList(e.currentTarget));
{
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 = info == undefined ? "" : info.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 = user.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/${user.userId}`;
userAndSampleImgDiv.appendChild(aUser);
{
const imgUser = document.createElement("img");
imgUser.src = `https:\/\/secure-dcdn.cdn.nimg.jp/nicoaccount/usericon/${Math.floor(parseInt(user.userId) / 10000)}/${user.userId}.jpg`;
imgUser.style.height = "40px";
imgUser.style.position = "relative";
imgUser.style.padding = "0 20px 0 10px";
imgUser.style.top = "-5px";
aUser.appendChild(imgUser);
imgUser.addEventListener("error", () => {
imgUser.src = "https:\/\/secure-dcdn.cdn.nimg.jp/nicoaccount/usericon/defaults/blank.jpg";
});
}
const aSample = document.createElement("a");
aSample.href = `https:/\/seiga.nicovideo.jp/seiga/im${sampleIllustId}`;
userAndSampleImgDiv.appendChild(aSample);
{
const imgSample = document.createElement("img");
imgSample.src = `https:\/\/lohas.nicoseiga.jp\/\/thumb/${sampleIllustId}c`;
imgSample.style.height = "30px";
imgSample.style.position = "relative";
imgSample.style.top = "-5px";
aSample.appendChild(imgSample);
const bigSample = document.createElement("img");
bigSample.src = `https:\/\/lohas.nicoseiga.jp\/\/thumb/${sampleIllustId}c`;
bigSample.style.height = "100px";
bigSample.style.pointerEvents = "none";
bigSample.style.position = "absolute";
bigSample.style.zIndex = "10";
imgSample.addEventListener("mouseover", () => {
const clientRect = imgSample.getBoundingClientRect();
const x = window.pageXOffset + clientRect.left + imgSample.width / 2 - 50;
const y = window.pageYOffset + 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() {
const parent = await Observer.DefinitelyGetElementByClassName("sg_pankuzu");
if (document.getElementById("optionSpan") != null) {
return;
}
const optionSpan = document.createElement("span");
optionSpan.id = "optionSpan";
optionSpan.style.margin = "0 10px";
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", () => {
optionDialog.style.display = (optionDialog.style.display == "none") ? "block" : "none";
});
optionSpan.appendChild(optionButton);
const optionDialog = document.createElement("div");
optionDialog.style.backgroundColor = "white";
optionDialog.style.display = "none";
optionDialog.style.position = "absolute";
optionDialog.style.padding = "5px";
optionDialog.style.marginLeft = "10px";
optionDialog.style.zIndex = "10";
optionDialog.style.border = "2px solid";
optionSpan.appendChild(optionDialog);
{
const setJudgeRigorFlex = document.createElement("div");
setJudgeRigorFlex.style.padding = "10px 10px 5px 10px";
optionDialog.appendChild(setJudgeRigorFlex);
{
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}`;
}
});
setJudgeRigorFlex.appendChild(setJudgeTime);
const setJudgeText1 = document.createElement("span");
setJudgeText1.textContent = "以内に";
setJudgeText1.style.color = "black";
setJudgeText1.style.fontSize = "15px";
setJudgeRigorFlex.appendChild(setJudgeText1);
const setJudgePostCount = document.createElement("input");
setJudgePostCount.type = "number";
setJudgePostCount.value = this.option.judge.postCount.toString();
setJudgePostCount.style.width = "40px";
setJudgePostCount.min = "2";
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();
}
});
setJudgeRigorFlex.appendChild(setJudgePostCount);
const setJudgeText2 = document.createElement("span");
setJudgeText2.textContent = "回投稿で仮荒らし認定";
setJudgeText2.style.color = "black";
setJudgeText2.style.fontSize = "15px";
setJudgeRigorFlex.appendChild(setJudgeText2);
}
const list1 = document.createElement("div");
list1.style.display = "flex";
optionDialog.appendChild(list1);
{
const listStatusSelect = document.createElement("select");
listStatusSelect.id = "listStatusSelect";
listStatusSelect.style.margin = "5px";
list1.appendChild(listStatusSelect);
for (let i = 1; i < Status.MAX; i++) {
const option = document.createElement("option");
option.value = Status[i];
option.textContent = Status[i];
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 onlyCurrentPageCheckbox = document.createElement("input");
onlyCurrentPageCheckbox.type = "checkbox";
onlyCurrentPageCheckbox.id = "onlyCurrentPageCheckbox";
onlyCurrentPageCheckbox.checked = true;
onlyCurrentPageCheckbox.style.padding = "3px";
list1.appendChild(onlyCurrentPageCheckbox);
onlyCurrentPageCheckbox.addEventListener("change", () => this.DrawList());
const onlyCurrentPageLabel = document.createElement("label");
onlyCurrentPageLabel.htmlFor = "onlyCurrentPageCheckbox";
onlyCurrentPageLabel.textContent = "このページだけ";
onlyCurrentPageLabel.style.color = "black";
onlyCurrentPageLabel.style.padding = "3px";
list1.appendChild(onlyCurrentPageLabel);
const allSelect = document.createElement("input");
allSelect.type = "button";
allSelect.value = "全選択";
allSelect.style.color = "black";
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.margin = "3px";
detailButton.style.marginLeft = "40px";
detailButton.style.padding = "0 5px";
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.padding = "10px";
detailDialog.style.zIndex = "10";
detailDialog.style.border = "2px solid";
detailDialog.style.left = "360px";
detailDialog.style.top = "50px";
list1.appendChild(detailDialog);
const setOKCacheMaxFlex = document.createElement("div");
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";
optionDialog.appendChild(list2);
{
const userInfoList = document.createElement("ul");
userInfoList.id = "scrollUL";
userInfoList.style.overflowY = "scroll";
userInfoList.style.overflowX = "hidden";
userInfoList.style.height = "300px";
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 = 1; 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;
const user = this.cache.find(c => c.userId == userId);
if (user != undefined) {
user.status = Status[toButton.name];
}
}
for (let info of this.illustInfos) {
this.UpdateIllust(info);
this.DrawBlackWhiteButton(info);
}
this.DrawList();
await this.cacheStorage.SetStorageData(this.cache);
});
}
}
}
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;
}
while (this.selectedList.length != 0) {
const element = this.selectedList.pop();
if (element != undefined) {
const userId = element.getElementsByClassName("userId")[0].textContent;
this.cache = this.cache.filter(c => c.userId != userId);
const infos = this.illustInfos.filter(c => c.user != undefined && c.user.userId == userId);
for (let info of infos) {
if (info != undefined && info.user != undefined) {
info.user.status = Status.WHITE;
this.UpdateIllust(info);
this.DrawBlackWhiteButton(info);
}
}
this.illustInfos = this.illustInfos.filter(c => c.user != undefined && c.user.userId != userId);
}
}
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\nDELETE";
div2.appendChild(allCacheClearButton);
allCacheClearButton.addEventListener("click", async () => {
if (!window.confirm("全キャッシュクリアしていいですか?\nホワイト・ブラックリストも削除されます。")) {
return;
}
for (let info of this.illustInfos) {
if (info.user != undefined) {
info.user.status = Status.WHITE;
this.UpdateIllust(info);
this.DrawBlackWhiteButton(info);
}
}
this.illustInfos = [];
this.cache = [];
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();
this.DrawList();
});
}
}
}
}
}
}
UpdateIllust(info) {
if (info.user == undefined) {
return;
}
if (info.user.status == Status.OK || info.user.status == Status.WHITE) {
info.element.getElementsByTagName("img")[0].style.filter = "brightness(1)";
if (info.element.parentElement == null) {
info.parent.appendChild(info.element);
}
}
if (info.user.status == Status.NG) {
info.element.getElementsByTagName("img")[0].style.filter = "brightness(0.3)";
info.parent.appendChild(info.element);
}
if (info.user.status == Status.BLACK) {
info.element.remove();
}
}
DrawBlackWhiteButton(illustInfo) {
if (illustInfo.user == undefined || illustInfo.user.status == Status.BLACK || illustInfo.user.status == Status.WHITE) {
if (illustInfo.user != undefined && 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.position = "relative";
whiteButton.style.left = "110px";
whiteButton.style.top = "-30px";
whiteButton.style.width = "40px";
whiteButton.style.height = "25px";
whiteButton.style.visibility = "hidden";
//上記のスタイルを両方に適用
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;`;
whiteButton.style.left = "110px";
blackButton.style.left = "115px";
whiteButton.addEventListener("contextmenu", async (e) => {
e.preventDefault();
if (illustInfo.user == undefined) {
return;
}
illustInfo.user.status = Status.OK;
for (let info of this.illustInfos) {
if (info.user != illustInfo.user) {
continue;
}
this.UpdateIllust(info);
}
this.DrawList();
await this.cacheStorage.SetStorageData(this.cache);
});
whiteButton.addEventListener("click", async () => {
if (illustInfo.user == undefined) {
return;
}
illustInfo.user.status = Status.WHITE;
for (let info of this.illustInfos) {
if (info.user != illustInfo.user) {
continue;
}
this.UpdateIllust(info);
const buttons = info.element.getElementsByClassName("toListButton");
while (buttons.length != 0) {
buttons[0].remove();
}
}
this.DrawList();
await this.cacheStorage.SetStorageData(this.cache);
});
blackButton.addEventListener("contextmenu", async (e) => {
e.preventDefault();
if (illustInfo.user == undefined) {
return;
}
illustInfo.user.status = Status.NG;
for (let info of this.illustInfos) {
if (info.user != illustInfo.user) {
continue;
}
this.UpdateIllust(info);
}
this.DrawList();
await this.cacheStorage.SetStorageData(this.cache);
});
blackButton.addEventListener("click", async () => {
if (illustInfo.user == undefined) {
return;
}
illustInfo.user.status = Status.BLACK;
for (let info of this.illustInfos) {
if (info.user != illustInfo.user) {
continue;
}
this.UpdateIllust(info);
}
this.DrawList();
await this.cacheStorage.SetStorageData(this.cache);
});
illustInfo.element.addEventListener("mouseover", () => {
blackButton.style.visibility = "visible";
whiteButton.style.visibility = "visible";
});
illustInfo.element.addEventListener("mouseleave", () => {
blackButton.style.visibility = "hidden";
whiteButton.style.visibility = "hidden";
});
illustInfo.element.appendChild(whiteButton);
illustInfo.element.appendChild(blackButton);
}
async AddInfos(illustListElement) {
var _a;
const illustElements = Array.from(illustListElement.getElementsByClassName("list_item"));
const illustIds = this.GetIllustIds(illustListElement);
const names = Array.from(illustListElement.getElementsByClassName("user"));
//キャッシュからの情報と合わせて追加(もうこれ分かんねぇこともある)
for (let i = 0; i < illustIds.length; i++) {
if (this.illustInfos.some(info => info.illustId == illustIds[i])) {
continue;
}
const info = this.GetInfo(illustIds[i]);
this.illustInfos.push({
name: (_a = names[i].textContent) !== null && _a !== void 0 ? _a : "",
illustId: illustIds[i],
illust: info == undefined ? undefined : info.illust,
user: info == undefined ? undefined : info.user,
element: illustElements[i],
parent: illustListElement
});
}
}
//メインクラス、メイン関数の肥大化もう始まってる!
async Run(illustListElements) {
await Observer.DefinitelyGetElementByClassName("illust_list");
await Observer.DefinitelyGetElementById("footer");
illustListElements = illustListElements !== null && illustListElements !== void 0 ? illustListElements : Array.from(document.getElementsByClassName("item_list"));
for (let illustListElement of illustListElements) {
illustListElement.style.visibility = "hidden";
await this.AddInfos(illustListElement);
}
//console.log("infos", this.illustInfos);
//これもう分かんねぇやつら
const unkownInfos = this.illustInfos.filter(info => info.user == undefined);
//この戻り値なんかダサい・・・ダサくない?
const result = await Fetcher.FetchIllustDatas(unkownInfos.map(info => info.illustId));
//これもう分かんねぇやつらとキャッシュまで!?の情報更新
for (let i = 0; i < unkownInfos.length; i++) {
unkownInfos[i].illust = result.illusts[i];
let user = this.cache.find((c) => c.userId == result.userIds[i]);
if (user == undefined) {
user = {
userId: result.userIds[i],
illusts: [],
status: Status.OK
};
this.cache.push(user);
}
else {
//キャッシュ使ったら後ろにしとく
this.cache = this.cache.filter(c => c != user);
this.cache.push(user);
}
user.illusts.push(result.illusts[i]);
unkownInfos[i].user = user;
}
//増えすぎたキャッシュ削除
if (this.cache.length > 0) {
let okCount = 0;
for (let c of this.cache) {
if (c.status == Status.OK) {
okCount++;
}
}
while (okCount > this.option.okCacheMax) {
//OK以外消さない
if (this.cache[0].status != Status.OK) {
const c = this.cache.shift();
this.cache.push(c);
continue;
}
//今使ってたら消さない
if (this.illustInfos.some(info => info.user == this.cache[0])) {
break;
}
this.cache.shift();
okCount--;
}
}
//console.log(result);
//ブラック,ホワイトリストにないイラストエレメントにボタン追加
for (let illustInfo of this.illustInfos) {
this.DrawBlackWhiteButton(illustInfo);
}
//情報取ってきた投稿者の荒らし判定更新 ↓これは重複排除
for (let c of [...new Set(unkownInfos.map(u => u.user))]) {
if (c != undefined) {
this.ChackArasi(c);
}
}
await this.cacheStorage.SetStorageData(this.cache);
await this.SetOptionButton();
this.DrawList();
for (let info of this.illustInfos) {
this.UpdateIllust(info);
}
for (let illustListElement of illustListElements) {
illustListElement.style.visibility = "visible";
}
}
}
;
const main = new Main();
await main.GetStorageData();
await main.Run();
const illustList = await Observer.DefinitelyGetElementByClassName("illust_list");
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 && element.classList.contains("item_list")) {
await main.Run([element]);
}
}
}
});
mutationObserver.observe(illustList, {
childList: true,
subtree: true
});
})();
//# sourceMappingURL=script.js.map