// ==UserScript== // @name Novel Sites Enhance // @name:ja 小説サイト機能強化 // @namespace https://greasyfork.org/en/users/1264733 // @version 2024-06-08 v3 // @description Kakuyomu / Narou / Alphapolis auto bookmark & cheering, hightlight author & unreads, enhance history, download as txt // @description:ja アルファポリス・カクヨム・なろう 自動しおり、自動応援、ハイライト著者と未読小説、強化閲覧履歴、TXTダウンロード。 // @author LE37 // @license MIT // @include /^https:\/\/kakuyomu\.jp\/my\/antenna\/reading_histories/ // @include /^https:\/\/kakuyomu\.jp\/my\/antenna\/works/ // @include /^https:\/\/kakuyomu\.jp\/works\/[0-9]+$/ // @include /^https:\/\/kakuyomu\.jp\/works\/[0-9]+\/episodes\/[^\/]+$/ // @include /^https:\/\/syosetu\.com\/favnovelmain\/list\// // @include /^https:\/\/ncode\.syosetu\.com\/[A-z0-9]+\/?$/ // @include /^https:\/\/ncode\.syosetu\.com\/[A-z0-9]+\/[0-9]+\/?$/ // @include /^https:\/\/yomou\.syosetu\.com\/rireki\/list\/$/ // @include /^https:\/\/www\.alphapolis\.co\.jp\/mypage\/notification\/index\/110000/ // @include /^https:\/\/www\.alphapolis\.co\.jp\/novel\/[0-9]+/[0-9]+/episode/[0-9]+$/ // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @downloadURL none // ==/UserScript== (()=>{ 'use strict'; let gMk; switch (location.host) { case "kakuyomu.jp": gMk = "HUN_K"; break; case "ncode.syosetu.com": case "syosetu.com": case "yomou.syosetu.com": gMk = "HUN_N"; break; case "www.alphapolis.co.jp": gMk = "HUN_A"; break; } // GM menu GM_registerMenuCommand("AutoCheering", CCR); GM_registerMenuCommand("LocalHistory", URH); GM_registerMenuCommand("DownloadText", DAS); GM_registerMenuCommand("AuthorSelect", ADA); GM_registerMenuCommand("UnreadCounts", SUN); GM_registerMenuCommand("CustomColour", SUC); GM_registerMenuCommand("ButnPosition", BPS); // Read list const URD = GM_getValue(gMk); let tlo = URD ? URD : { ATC:false, AUH:false, SDB:false, FAC:"indigo", FCC:"orange", FUC:"red", FAU:3, FAL:[], RRK:{} }; let atc = tlo.ATC ? tlo.ATC : false; let auh = tlo.AUH ? tlo.AUH : false; let sdb = tlo.SDB ? tlo.SDB : false; let tac = tlo.FAC ? tlo.FAC : "red"; let tcc = tlo.FCC ? tlo.FCC : "deepskyblue"; let tuc = tlo.FUC ? tlo.FUC : "orange"; let tau = tlo.FAU; // Right, bottom, move dist, icon dist let tbl = tlo.FBL ? tlo.FBL : [4, 4, 1, 2]; let rrk = tlo.RRK ? tlo.RRK : {}; const tal = tlo.FAL; // Download delay time: max, min const dTime = [10000, 5000]; // Download type: 0 separate 1 combine const dType = 0; // Save list function USV() { tlo = { ATC:atc, AUH:auh, SDB:sdb, FAC:tac, FCC:tcc, FUC:tuc, FAU:tau, FBL:tbl, FAL:tal, RRK:rrk }; GM_setValue(gMk, tlo); } let sFa, sFb, sFc, sFd, sFe; sFa = sFb = sFc = sFd = sFe = false; let fAuthor; const uRi = location.href; const rMb = navigator.userAgent.includes("Mobile"); const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); switch (true) { case uRi.includes("/my/"): case uRi.includes("/favnovelmain/"): case uRi.includes("/mypage/"): FAV(); break; case /^https:\/\/ncode\.syosetu\.com\/[A-z0-9]+\/?$/.test(uRi): { if(document.getElementById("novel_honbun")) { EPI(); } else { // Add resume button(base on casutom history) if (auh) { const cKey = location.pathname.split("/")[1]; if(Object.hasOwn(rrk, cKey)) { CRB(cKey, "p.novel_title", "https://ncode.syosetu.com/", "/"); } } } break; } case uRi.includes("/rireki"): //console.log("DoNothing"); break; case /^https:\/\/kakuyomu\.jp\/works\/[0-9]+$/.test(uRi): { // Add resume button(base on custom history) if (auh) { sleep(2000).then(() => { const cKey = location.pathname.split("/")[2]; if (Object.hasOwn(rrk, cKey) && rrk[cKey].epi.length <= 4) { const data = JSON.parse(document.getElementById("__NEXT_DATA__").innerHTML); const re = new RegExp("Episode:"); const keys = data.props.pageProps.__APOLLO_STATE__; let i = 1; for (let key in keys) { if (re.test(key)) { if (i === parseInt(rrk[cKey].epi)) { rrk[cKey].epi = keys[key].id; USV(); break; } i++; } } } CRB(cKey, "a[title]", "https://kakuyomu.jp/works/", "/episodes/"); }); } break; } default: EPI(); } // Episode page function EPI() { // eCheer button; let eCb; let rMf = false; switch (gMk) { case "HUN_K": { eCb = document.getElementById("episodeFooter-action-cheerButton"); if ( document.getElementById("episodeFooter-action-cheerButton-cheer").classList.contains("isShown") && tal.some(name => document.title.includes('(' + name + ') -')) ) { rMf = true; } if (auh) { ANH(location.pathname.split("/")[2], location.pathname.split("/")[4], document.querySelector("h1.js-vertical-composition-item>a").title, null); } break; } case "HUN_N": { eCb = document.querySelector("a.js-novelgood_change"); if ( document.querySelector("div.is-empty") && tal.some(name => document.querySelector('div.contents1 a:nth-child(2)').textContent.includes(name)) ) { rMf = true; } // Auto siori/bookmark if (document.querySelector("li.bookmark_now")) { sleep(Math.floor((Math.random() * (5000 - 2000 + 1)) + 2000)).then(() => { document.querySelector("li.bookmark_now>a").click(); }); } if (auh) { ANH(location.pathname.split("/")[1], location.pathname.split("/")[2], document.title.split(" - ")[0], null); } break; } case "HUN_A": eCb = document.getElementById("contentMangaLikeBtnCircle"); if ( !eCb.classList.contains("max") && tal.some(name => uRi.includes(name)) ) { rMf = true; } break; } // Save updated custom reading history if (auh) { USV(); } const ioc = new IntersectionObserver((entries) => { if (entries[0].intersectionRatio <= 0) return; ioc.disconnect(); if (rMf) { eCb.style.backgroundColor = tcc; if (atc) { if (gMk === "HUN_A") { // Randomnumber = Math.floor(Math.random() * (maximum - minimum + 1)) + minimum; let x = 0; setInterval(function() { if (x < parseInt(eCb.getAttribute("data-content-like-limit"))) { //console.log(x); eCb.click(); } else { return; } x++; }, Math.floor(Math.random() * (1000 - 500 + 1)) + 500); } else { eCb.click(); } //console.log("===いいね==="); sleep(1500).then(() => { if (gMk === "HUN_K" && !document.getElementById("episodeFooter-action-cheerButton-cheer").classList.contains("isShown") || gMk === "HUN_N" && !document.querySelector("div.is-empty") || gMk === "HUN_A" && document.getElementById("contentMangaLikeBtnCircle").classList.contains("max") ) { eCb.style.backgroundColor = ""; } }); } } }); if (gMk !== "HUN_N" || !document.querySelector("span.p-novelgood-form__status")) { ioc.observe(eCb); } } // Favorite page function FAV() { let fNode, fUnreadCount; switch (gMk) { case "HUN_K": fAuthor = "p.widget-antennaList-author"; fNode = "li.widget-antennaList-item"; fUnreadCount = "li.widget-antennaList-unreadEpisodeCount"; break; case "HUN_N": fAuthor = "div.p-up-bookmark-item__author>a"; fNode = "li.p-up-bookmark-item"; fUnreadCount = "span.p-up-bookmark-item__unread-num"; break; case "HUN_A": fAuthor = "h2.title>a"; fNode = "div.content-main"; fUnreadCount = "a.disp-order"; break; } const tNode = document.querySelectorAll(fNode); for(let i = 0; i < tNode.length; i++) { const fAuthorTag = tNode[i].querySelector(fAuthor); const fAuthorName = (gMk === "HUN_A") ? fAuthorTag.href.match(/\d+$/)[0] : fAuthorTag.textContent; fAuthorTag.style.color = CHK(fAuthorTag, fAuthorName) ? tac : ""; const tUnreadCount = tNode[i].querySelector(fUnreadCount); const fCurrent = (gMk === "HUN_A") && tUnreadCount ? parseInt(tUnreadCount.textContent.match(/[0-9]+/)[0]) : 0; let tUnreadNum; if (tUnreadCount) { tUnreadNum = (gMk === "HUN_K") ? parseInt(tUnreadCount.textContent.match(/[0-9]+/)[0]) : (gMk === "HUN_N") ? parseInt(tUnreadCount.textContent) : parseInt(tNode[i].querySelector("a.total").textContent.match(/[0-9]+/)[0]) - fCurrent; } else { tUnreadNum = 0; } const fUnreadColor = CHK(fAuthorTag, fAuthorName) ? tac : tUnreadCount && tUnreadNum > tau ? tuc : ""; if (tUnreadCount) { if (gMk === "HUN_K") { tNode[i].querySelector("a.widget-antennaList-continueReading").style.color = fUnreadColor; } else if (gMk === "HUN_N") { tNode[i].querySelector("span.p-up-bookmark-item__unread").style.color = fUnreadColor; } else { tUnreadCount.style.color = fUnreadColor; } } else { if (gMk === "HUN_A") { fAuthorTag.style.color = tuc; } } } } // Check author name function CHK(elem, s) { const result = tal.some((v) => s === v); if (sFa) { elem.style.border = result ? "thin solid fuchsia" : "thin solid dodgerblue"; } else { elem.style.border = "none"; } return result; } // Add fav author function ADA() { if (!sFa) { sFa = true; document.addEventListener("click", AAH, true); } else { sFa = false; document.removeEventListener("click", AAH, true); USV(); } document.getElementById("nse_asb").textContent = sFa ? "💖" : "💟"; FAV(); } // Add author handler function AAH(e) { e.preventDefault(); if (e.target.closest(fAuthor)) { if (gMk === "HUN_A") { UTL(e, e.target.href.match(/\d+$/)[0]); } else { UTL(e, e.target.textContent); } FAV(); } return false; } // Update temp list function UTL(e, s) { const i = tal.findIndex((v) => v === s); if (i !== -1) { tal.splice(i,1); } else { tal.push(s); } //console.log(tal); return tal; } // Auto cheering function CCR() { atc = !atc; const ttt = atc ? "On" : "Off"; alert("AutoCheering is " + ttt); USV(); } // Auto update reading history function URH() { auh = !auh; const ttt = auh ? "On" : "Off"; alert("AutoUpdateHistory is " + ttt); USV(); } // Set unread number function SUN() { const t = parseInt(prompt("Enter unread counts", tau), 10); if (t >= 0) { tau = t; } else { tau = 3; alert("Invalid number, default[3] will be used."); } USV(); FAV(); } // Set unread colour function SUC() { if ( uRi.includes("/my/") || uRi.includes("/favnovelmain/") || uRi.includes("/mypage/") ) { let ccmu; if (!sFc) { sFc = true; CMU(); ccmu = document.getElementById("nse_cmu"); ccmu.style.display = ""; ccmu.addEventListener("click", CSH, true); } else { sFc = false; ccmu = document.getElementById("nse_cmu"); ccmu.style.display = "none"; ccmu.removeEventListener("click", CSH, true); USV(); } } } let tCate; // Colour select handler function CSH(e) { e.preventDefault(); if (e.target.classList.contains("nse_cca")) { e.target.textContent = "▣" + e.target.textContent.slice(1); const cca = document.getElementsByClassName("nse_cca"); for(let i = 0; i < cca.length; i++) { cca[i].textContent = cca[i] === e.target ? "◉" + cca[i].textContent.slice(1) : "○" + cca[i].textContent.slice(1); } tCate = e.target.textContent.slice(1, 2); let tctc; switch (tCate) { case "0": tctc = tac; break; case "1": tctc = tcc; break; case "2": tctc = tuc; break; } const ccb = document.getElementsByClassName("nse_cco"); for(let j = 0; j < ccb.length; j++) { ccb[j].textContent = ccb[j].style.color === tctc ? "▣ColourTest" : "▢ColourTest"; } } else if (e.target.classList.contains("nse_cco")) { const cca = document.getElementsByClassName("nse_cca"); for(let i = 0; i < cca.length; i++) { if (cca[i].textContent.slice(1, 2) === tCate) cca[i].style.color = e.target.style.color; } switch (tCate) { case "0": tac = e.target.style.color; break; case "1": tcc = e.target.style.color; break; case "2": tuc = e.target.style.color; break; } const ccb = document.getElementsByClassName("nse_cco"); for(let j = 0; j < ccb.length; j++) { ccb[j].textContent = ccb[j] === e.target ? "▣ColourTest" : "▢ColourTest"; } FAV(); } return false; } // Create colour list function CMU() { if (!document.getElementById("nse_cmu")) { const cMenu = document.body.appendChild(document.createElement("div")); cMenu.id = "nse_cmu"; const cCates = [ 'AuthorColour', 'ButtonColour', 'UnreadColour' ]; cCates.forEach((item, index) => { let tctc; switch (index) { case 0: tctc = tac; break; case 1: tctc = tcc; break; case 2: tctc = tuc; break; } const cMc = cMenu.appendChild(document.createElement("p")); cMc.classList.add("nse_cca"); cMc.style = 'position: fixed; bottom: ' + (4+index)*5 + '%; right: 22%; z-index: 9999; color: ' + tctc + '; background-color: #393939; padding: 10px;'; cMc.type = "button"; cMc.textContent = "○" + index + ". " + item; }); const colors = ['deepskyblue', 'blue', 'lime', 'green', 'fuchsia', 'indigo', 'orange', 'red']; colors.forEach((item, index) => { const cMb = cMenu.appendChild(document.createElement("p")); cMb.classList.add("nse_cco"); cMb.style = 'position: fixed; bottom: ' + (4+index)*5 + '%; right: 55%; z-index: 9999; color: ' + item + '; background-color: #F3F3F3; padding: 10px;'; cMb.type = "button"; cMb.textContent = "▢ColourTest"; }); cMenu.style.display = "none"; } } // Custom reading history function CRH(elem, upa, upb) { if (!document.getElementById("nse_rhd")) { const crl = document.getElementById(elem); if (gMk === "HUN_K") { const gBody = document.querySelector("body#page-my-antenna-worksGuest"); if (gBody) { gBody.style.overflow = "auto"; } } crl.innerHTML = '

閲覧履歴:

' + '
'; } document.getElementById("nse_rhd").innerHTML = ""; Object.keys(rrk).reverse().forEach(k => { // Update version patch if (!rrk[k].bmk) { rrk[k].bmk = null; } const vbmk = rrk[k].bmk === "1" ? " 💖 " : rrk[k].bmk === "2" ? " 🖤 " : " ❓ "; const vlink = (gMk === "HUN_K" && (rrk[k].epi.length <= 4)) ? '' + rrk[k].tit + '' : '' + rrk[k].tit + ''; document.getElementById("nse_rhd").innerHTML += '

' + '' + '' + rrk[k].tim + '' + '' + vbmk + '' + vlink + '

'; }); } // Create resume button function CRB(key, elem, upa, upb) { const tbtn = document.querySelector(elem).appendChild(document.createElement("a")); tbtn.href = upa + key + upb + rrk[key].epi; tbtn.textContent = "▶続きから読む"; tbtn.style = "margin-left: 1em; color: dodgerblue; cursor: pointer;"; } // Create import button function CIB(node, etit, eepi) { let bookmark; const no = document.getElementsByClassName(node); for (let i = no.length - 1; i >= 0; i--) { switch (location.host) { case "kakuyomu.jp": { const cno = no[i].querySelectorAll("li"); let cepi; if (uRi.includes("histo")) { cepi = (cno.length === 2) ? cno[1].textContent.slice(3,-1) : (cno[2].textContent.slice(3,-1) - cno[1].textContent.slice(2,-1)).toString(); bookmark = null; } else { cepi = (cno.length === 2) ? cno[0].textContent.slice(3,-1) : (cno[1].textContent.slice(3,-1) - cno[0].textContent.slice(2,-1)).toString(); bookmark = "1"; } ANH(no[i].querySelector(eepi).href.split("/")[4], cepi, no[i].querySelector(etit).textContent, bookmark); break; } case "syosetu.com": case "yomou.syosetu.com": { let title; if (location.host.startsWith("y")) { title = no[i].querySelector(etit).textContent.slice(0, 12); bookmark = null; } else { title = no[i].querySelector(etit).textContent.slice(3, 15); bookmark = "1"; } ANH(no[i].querySelector(etit).href.split("/")[3], no[i].querySelector(eepi).href.split("/")[4], title, bookmark); break; } } } USV(); alert("result: " + JSON.stringify(rrk)); } // Add new history function ANH(key, epi, title, bmk) { let tim = new Date().toISOString().split('T')[0]; if ( !uRi.includes("/favnovelmain/") && !uRi.includes("/antenna/works") ) { if (Object.hasOwn(rrk, key)) { if ( uRi.includes("_histor") || uRi.includes("/rireki") ) { tim = rrk[key].tim; } bmk = rrk[key].bmk; delete rrk[key]; } } else { rrk[key].bmk = bmk; } if (!Object.hasOwn(rrk, key)) { if (title.length > 12) { title = title.slice(0, 12); } rrk[key] = {"epi": epi, "tit": title, "tim": tim, "bmk": bmk}; } } // Download all switch function DAS() { sdb = !sdb; const eee = sdb ? "On" : "Off"; alert("Download all episodes is " + eee); USV(); } // Narou get episodes from download page function NGL(title, url, elem) { fetch(url).then((response) => { if (response.ok) { return response.text(); } throw new Error('Something went wrong'); }) .then(async (text) => { const doc = new DOMParser().parseFromString(text, 'text/html'); const data = doc.querySelector(elem).textContent; const min = parseInt(prompt("Enter a start episode number", "1")); const max = parseInt(prompt("Enter a end episode number", "2")); let nlc = ""; if (min >= 1 && min <= max) { const ept = data.split("\n"); for (let i = 1; i < data.split("\n").length - 1; ) { const tit = i + ". " + ept[i]; const url = uRi + i + "/"; // download episode base on input range if (i >= min && i <= max) { await sleep(Math.floor((Math.random() * (dTime[0] - dTime[1] + 1)) + dTime[1])).then(() => { nlc += tit + ": " + url + "\n"; //console.log(tit, url); GEC(tit, url, "div#novel_honbun"); }); } i++; } } else { alert("Invalid Inputs"); } // Wait for last epicode??? sleep(dTime[0]).then(() => { // Save episodes list SAT(title + "_目次", nlc); // Save episodes content const clnk = document.getElementById("nse_sml"); if(clnk) { clnk.download = title + ".txt"; clnk.click(); document.body.removeChild(clnk); alert("File downloads completed"); } }); }) .catch((error) => { //console.log(error); }); } // Kakuyomu get episodes list from novel page async function KGL(title, url, elem) { const data = JSON.parse(document.getElementById(elem).innerHTML); const re = new RegExp("Episode:"); const keys = data.props.pageProps.__APOLLO_STATE__; const min = parseInt(prompt("Enter a start episode number", "1")); const max = parseInt(prompt("Enter a end episode number", "2")); let nlc = ""; if (min >= 1 && min <= max) { let i = 1; for (let key in keys) { if (re.test(key)) { const ttit = i + ". " + keys[key].title; const turl = url + "/episodes/" + keys[key].id; // download episode base on input range if (i >= min && i <= max) { await sleep(Math.floor((Math.random() * (dTime[0] - dTime[1] + 1)) + dTime[1])).then(() => { nlc += ttit + ": " +turl + "\n"; //console.log(nlc); GEC(ttit, turl, "div.widget-episodeBody"); }); } i++; } } } else { alert("Invalid Inputs"); } // Wait for last epicode??? sleep(dTime[0]).then(() => { // Save episodes list SAT(title + "_目次", nlc); // Save episodes content const clnk = document.getElementById("nse_sml"); if(clnk) { clnk.download = title + ".txt"; clnk.click(); document.body.removeChild(clnk); alert("File downloads completed"); } }); } // Get episode content function GEC(title, url, elem) { fetch(url).then((response) => { if (response.ok) { return response.text(); } throw new Error('Something went wrong'); }) .then((text) => { const doc = new DOMParser().parseFromString(text, 'text/html'); const data = doc.querySelector(elem).textContent; if (dType === 0) { // Separate txt SAT(title, data); } else { // Combine SML(title, data); } }) .catch((error) => { //console.log(error); }); } // Download current epicode as txt function DCE() { let elem, title; if (gMk === "HUN_K") { elem = "div.widget-episodeBody"; title = document.querySelector("p.widget-episodeTitle") ? document.querySelector("p.widget-episodeTitle").textContent : document.title.replace(/\s/g,"").match(/[^-]+/); } else if (gMk === "HUN_N") { elem = "div#novel_honbun"; title = document.querySelector("p.novel_subtitle") ? document.querySelector("p.novel_subtitle").textContent : document.title.split("-")[1]; } const data = document.querySelector(elem).textContent; SAT(title, data); alert("File downloads completed"); } // Save as txt function SAT(title, text) { //console.log(text); const link = document.createElement("a"); link.href = "data:text/plain;charset=utf-8," + encodeURIComponent(text); link.download = title + ".txt"; link.style.display = "none"; document.body.appendChild(link); link.click(); document.body.removeChild(link); } // Save multiple data to link function SML(title, text) { if (!document.getElementById("nse_sml")) { const link = document.body.appendChild(document.createElement("a")); link.id = "nse_sml"; link.href = "data:text/plain;charset=utf-8," + ""; link.style.display = "none"; } document.getElementById("nse_sml").href += encodeURIComponent(title + "\n" + text + "\n"); } // Create float buttons CFB(); function CFB() { if (!document.getElementById("nse_fcm")) { const cDiv = document.body.appendChild(document.createElement("div")); cDiv.id = "nse_fcm"; } const posx = tbl[0], posy = tbl[1], diff = tbl[3]; BCR("nse_fcb", "💠", "right: " + posx + "em;", "bottom: " + posy + "em;", ""); if (auh) { BCR("nse_rhb", "🕓", "right: " + (posx - diff) + "em;", "bottom: " + posy + "em;", "none"); BCR("nse_shb", "💾", "right: " + (posx - diff) + "em;", "bottom: " + (posy + diff) + "em;", "none"); } switch (true) { case uRi.includes("/antenna/works"): case uRi.includes("/favnovelmain/"): BCR("nse_asb", "💟", "right: " + posx + "em;", "bottom: " + (posy - diff) + "em;", "none"); BCR("nse_csb", "🎨", "right: " + (posx + diff) + "em;", "bottom: " + (posy - diff) + "em;", "none"); BCR("nse_urb", "🔢", "right: " + (posx + diff) + "em;", "bottom: " + posy + "em;", "none"); if (auh) { BCR("nse_ihb", "💕", "right: " + posx + "em;", "bottom: " + (posy + diff) + "em;", "none"); } break; case uRi.includes("_histor"): case uRi.includes("/rireki"): if (auh) { BCR("nse_ihb", "💕", "right: " + posx + "em;", "bottom: " + (posy + diff) + "em;", "none"); } break; case /^https:\/\/ncode\.syosetu\.com\/[A-z0-9]+/.test(uRi): case /^https:\/\/kakuyomu\.jp\/works\/[0-9]+/.test(uRi): if (sdb) { BCR("nse_dlb", "📥", "right: " + (posx + diff) + "em;", "bottom: " + (posy + diff) + "em;", "none"); } break; } document.getElementById("nse_fcb").addEventListener("click", SCB, true); } // Button positon tweak function BPS() { const cfcb = document.getElementById("nse_fcb"); const cfcm = document.getElementById("nse_fcm"); if (!sFe) { sFe = true; cfcb.removeEventListener("click", SCB, true); cfcm.removeEventListener("click", FBH, true); const bno = document.getElementsByClassName("nse_cfb"); let bi = bno.length - 1; while (bi >= 0) { bno[bi].remove(); --bi; } const posx = tbl[0], posy = tbl[1], diff = tbl[3]; BCR("nse_ptu", "⏫", "right: " + posx + "em;", "bottom: " + (posy + diff) + "em;", ""); BCR("nse_ptd", "⏬", "right: " + posx + "em;", "bottom: " + (posy - diff) + "em;", ""); BCR("nse_ptl", "⏪", "right: " + (posx + diff) + "em;", "bottom: " + posy + "em;", ""); BCR("nse_ptr", "⏩", "right: " + (posx - diff) + "em;", "bottom: " + posy + "em;", ""); cfcm.addEventListener("click", PTH, true); } else { sFe = sFb = false; cfcm.removeEventListener("click", PTH, true); cfcb.remove(); const tno = document.getElementsByClassName("nse_cft"); let ti = tno.length - 1; while (ti >= 0) { tno[ti].remove(); --ti; } USV(); CFB(); } } // Position tweak handler function PTH(e) { const dist = tbl[2]; switch (e.target.id) { // Reset case "nse_fcb": tbl = [4, 4, 1, 2]; break; // Up case "nse_ptu": tbl[1] = tbl[1] + dist; break; // Down case "nse_ptd": tbl[1] = tbl[1] - dist; break; // Left case "nse_ptl": tbl[0] = tbl[0] + dist; break; // Right case "nse_ptr": tbl[0] = tbl[0] - dist; break; default: //console.log("DoNothing"); } const cfcb = document.getElementById("nse_fcb"); cfcb.style.right = tbl[0] + "em"; cfcb.style.bottom = tbl[1] + "em"; } // Show child button function SCB() { if (!sFb) { sFb = true; document.getElementById("nse_fcm").addEventListener("click", FBH, true); } else { sFb = false; document.getElementById("nse_fcm").removeEventListener("click", FBH, true); } const no = document.getElementsByClassName("nse_cfb"); for (let i = 0; i < no.length; i++) { no[i].style.display = sFb ? "" : "none"; } } // Buttons handler function FBH(e) { switch (e.target.id) { // Author select button case "nse_asb": ADA(); break; // Colour setting button case "nse_csb": SUC(); break; // Unreads setting button case "nse_urb": SUN(); break; // Reading history button case "nse_rhb": { if (!document.getElementById("nse_rhp")) { const cDiv = document.body.appendChild(document.createElement("div")); cDiv.id = "nse_rhp"; const cPos = !rMb ? " width: 50%; left: 25%;" : " width: 98%; left: 1%;"; cDiv.style = "position: fixed;" + cPos + " overflow-y: scroll; height: 52%; top:10%; z-index: 9999; background-color: #f1f3f5; display: none;"; } const crhp = document.getElementById("nse_rhp"); if (!sFd) { sFd = true; crhp.style.display = ""; if (gMk === "HUN_K") { CRH("nse_rhp", "https://kakuyomu.jp/works/", "/episodes/"); } else if (gMk === "HUN_N") { CRH("nse_rhp", "https://ncode.syosetu.com/", "/"); } crhp.addEventListener("click", RHB, true); } else { sFd = false; crhp.style.display = "none"; // Clear history crhp.innerHTML = ""; crhp.removeEventListener("click", RHB, true); USV(); } break; } // Save history button case "nse_shb": { let htit, upa, upb; if (gMk === "HUN_K") { htit = "カクヨム閲覧履歴"; upa = "https://kakuyomu.jp/works/"; upb = "/episodes/"; } else if (gMk === "HUN_N") { htit = "なろう閲覧履歴"; upa = "https://ncode.syosetu.com/"; upb = "/"; } let htxt = ""; Object.keys(rrk).reverse().forEach(k => { const vbmk = rrk[k].bmk === "1" ? " 💖 " : rrk[k].bmk === "2" ? " 🖤 " : " ❓ "; let kpt = ""; let vlink = upa + k + upb + rrk[k].epi; if (gMk === "HUN_K") { if (rrk[k].epi.length <= 4) { kpt = "[" + rrk[k].epi + "]"; vlink = upa + k + "/resume_reading"; } } htxt += rrk[k].tim + vbmk + rrk[k].tit.replace(/\n/g,'') + kpt + ": " + vlink + "\n"; }); SAT(htit, htxt); alert("File downloads completed"); break; } // Import history button case "nse_ihb": if (gMk === "HUN_K") { CIB("widget-antennaList-item", "h4.widget-antennaList-title", "a.widget-antennaList-continueReading"); } else if (gMk === "HUN_N") { if (location.host.startsWith("y")) { CIB("p-rireki-item", "a.c-card__title", "div.p-rireki-item__button-link>a.c-button"); } else { CIB("p-up-bookmark-item", "div.p-up-bookmark-item__title>a", "a.c-button--sm"); } } break; // Download button case "nse_dlb": if ( /^https:\/\/ncode\.syosetu\.com\/[A-z0-9]+\/?$/.test(uRi) || /^https:\/\/kakuyomu\.jp\/works\/[0-9]+$/.test(uRi) ) { // Add download all episodes button if (gMk === "HUN_N") { NGL(document.title, document.querySelector("ul.undernavi li:nth-child(2) a").href, 'select[name="no"]'); } else { KGL(document.title.split("(")[0], uRi, "__NEXT_DATA__"); } } else { // Add download current episodes button DCE(); } break; default: //console.log("DoNothing"); } return false; } // Reading history button function RHB(e) { if (e.target.classList.contains("nse_drh")) { // Delete history button const key = e.target.getAttribute("data"); delete rrk[key]; CRH(); } else if (e.target.classList.contains("nse_brh")) { // Bookmark history button const key = e.target.getAttribute("data"); rrk[key].bmk = rrk[key].bmk === "1" ? "2" : "1"; CRH(); } } // Button creater function BCR(id, text, posx, posy, show) { const cButton = document.getElementById("nse_fcm").appendChild(document.createElement("button")); cButton.id = id; if (id === "nse_fcb") { //console.log("💠"); } else if (sFe) { cButton.classList.add("nse_cft"); } else { cButton.classList.add("nse_cfb"); } cButton.textContent = text; cButton.style = "position: fixed; width: 44px; height: 44px; z-index: 9999; font-size: 200%; opacity: 50%; cursor:pointer; border: none; padding: unset;" + posx + posy; cButton.type = "button"; cButton.style.display = show; } })();