您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Manage your follows
当前为
// ==UserScript== // @name New MangaDex Follows // @namespace http://greasyfork.icu/scripts/430295-new-mangadex-follows // @version 1.1.3 // @description Manage your follows // @author Australis // @match https://mangadex.org/* // @icon https://www.google.com/s2/favicons?domain=mangadex.org // @grant none // ==/UserScript== if(localStorage.getItem("seriesdex") == null) seriesdex = [] else seriesdex = JSON.parse(localStorage.getItem("seriesdex")) var classChapter = "flex chapter" //class of the elements containing the chapters var classFeed = "chapter-feed__chapters-list" //class containing the chapter cluster var grouptagclass = "group-tag line-clamp-1 -my-1" var newStyle = newInner("style","text/css",".hideme {\ndisplay: none;\n}") document.querySelector("head").append(newStyle) var filter = JSON.parse(localStorage.getItem("filter")) if(filter == undefined || filter == null) { console.log("filter: "+JSON.stringify(filter)) filter = true localStorage.setItem("filter",JSON.stringify(filter)) } whitelist = [] blacklist = [] function GetNumero(text){ for(let t of text.split(" ")){ console.log(t) if((t*1)>0) return t*1 } return NaN } function ScriptForm(){ if(document.URL.includes("https://mangadex.org/titles/feed") && !document.getElementById("script_btn")){ console.log("executing ScriptForm") var options_loc = "flex items-center mb-4" if(/*!document.getElementById("script_btn") && */document.getElementsByClassName(options_loc).length){ var newButton = newInner("div","",'<button id="script_btn" onclick="NMDF()" style="right: 2rem;position: absolute;">SCRIPT OPTIONS</button><popup id="script_body" style="position: fixed;right: 2rem;top: 5.5rem;width: 75%;background-color: var(--bg-color);z-index: 5;padding: 2rem;display: none;"><h2>New MangaDex Follows Script Options</h2><label><input type="checkbox" id="filter" value="filter"> Filter by groups</label><p>You can filter chapters by adding certain groups to a blacklist (so it\'s hidden) or whitelist (so it only shows that group releases), by clicking at the 🔧 besides the title. This only applies to 1 series at a time.</p><button class="menu__item--active-highlight" id="nmdf_save" onclick="SC()" style="background-color: orangered;padding: 0.5rem;margin: 0.5rem;">Save Changes</button><button id="nmdf_exit" onclick="EXIT()">Exit</button></popup>') document.getElementsByClassName(options_loc)[0].append(newButton.children[0]) document.getElementsByClassName(options_loc)[0].append(newButton.children[0]) console.log("form added") } else setTimeout(ScriptForm,500) } } window.NMDF = function(){ var daBody = document.getElementById("script_body") document.getElementById("filter").checked = filter if(daBody.style.display == "none"){ daBody.style.display = "block" } else{ daBody.style.display = "none" } } var unchecked = true window.NMDFilter = function(event){ var daElement = event.target.parentElement.parentElement var daModal = document.getElementById("daModal") let ttext,ctext let gtext = [] let glink = [] let bgg = false let id = getID(daElement) let daSeries = seriesdex[FS(seriesdex,id)] for(let link of daElement.getElementsByTagName("a")){ if(link.innerText != ""){ if(link.href.includes("/title/")) ttext = link.innerText.replaceAll("\n","") if(link.href.includes("/group/")) { console.log(link) if(!gtext.includes(link.innerText.replaceAll("\n",""))){ gtext.push(link.innerText.replaceAll("\n","")) glink.push(link.href) } } } } let gtags = document.getElementsByClassName("flex items-center")[1] if(gtags.innerText.includes("No Group") && gtags.getElementsByTagName("i").length){ gtext.push("No Group") glink.push("0/0/0/0/0/0") } console.log(gtext) console.log(glink) if(!daModal) createModal() let closebutton = '<span class="close">×</span>' let series = '<p id="'+id+'">SERIES NAME: '+ttext+'</p>' let lastext = daSeries.last let nextext = daSeries.nextc if(lastext == -10 || lastext == "-10") { lastext = "Not registered" nextext = "Not registered" } let last = '<p>Last chapter read: '+daSeries.last+'</p>' if(nextext == 10000) nextext = "Up to date" let next = '<p>Next chapter: '+nextext+'</p>' let groups = '<p>Groups:</p>' let daTable = '<table><tr><th>Name</th><th>ID</th><th style="text-align: center;">Whitelisted</th><th style="text-align: center;">Blacklisted</th></tr>' for(let w=0;w<gtext.length;w++){ let gid = getID3(glink[w]) let wcheck = "" let bcheck = "" if(HideThis(whitelist,id,gid)) wcheck = "checked" if(HideThis(blacklist,id,gid)) bcheck = "checked" daTable+='<tr><td>'+gtext[w]+'</td><td>'+gid+'</td><td style="text-align: center;"><input type="checkbox" id="wl'+w+'" name="wl'+w+'" '+wcheck+'></td><td style="text-align: center;"><input type="checkbox" id="bl'+w+'" name="bl'+w+'" '+bcheck+'></td></tr>' } daTable+="</table>" let savebtn = '<div style="text-align: right;"><button onclick="SaveFilter(event)" style="margin: 0.5rem;">SAVE CHANGES</button></div>' daModal.firstChild.innerHTML= closebutton+series+next+last+groups+daTable+savebtn daModal.style.display = "block" if(unchecked){ window.onclick = function(event) { var daModal = document.getElementById("daModal") if (event.target == daModal) { daModal.style.display = "none" } } unchecked = false } var closebtn = document.getElementsByClassName("close")[0] closebtn.onclick = function() { daModal.style.display = "none" } } function createModal(){ console.log("creating modal") var modal = newInner("div","modal",'<div class="modal-content"></div>') modal.id = "daModal" var funky = document.getElementById("__layout") funky.insertBefore(modal,funky.firstChild) var daStyle = newInner("style","text/css",'.modal {display: none;position: fixed;z-index: 2;padding-top: 100px;right: 0;top: 0;width: calc(100% - 256px);height: 100%;overflow: auto;background-color: rgb(0,0,0);background-color: rgba(0,0,0,0.4);}.modal-content {background-color: var(--bg-color);margin: auto;padding: 20px;border: 1px solid #888;width: 80%;}.close {color: #aaaaaa;float: right;font-size: 28px;font-weight: bold;}.close:hover,.close:focus {color: #000;text-decoration: none;cursor: pointer;}') document.querySelector("head").append(daStyle) var daTableStyle = newInner("style","text/css",'table {border-collapse: collapse;border-spacing: 0;width: 100%;border: 1px solid #ddd;}th, td {text-align: left;padding: 16px;}') document.querySelector("head").append(daTableStyle) } window.SC = function(){ filter = document.getElementById("filter").checked localStorage.setItem("filter",JSON.stringify(filter)) document.getElementById("script_body").style.display = "none" } window.EXIT = function(){ document.getElementById("script_body").style.display = "none" } function FS(array, number){//FindSeries return array.findIndex(q => q.id == number) } function HideThis(array,series,group){ if(array.findIndex(q => q[0] == series && q[1] == group) >= 0) return true return false } function OnlyThis(array,series,group){ if(array.findIndex(q => q[0] == series && q[1] == group) < 0) return 0 //it's not there if(array.findIndex(q => q[0] == series && q[1] != group) >= 0) return 1 //the series is listed but not this group if(array.findIndex(q => q[0] == series && q[1] == group) >= 0) return 2 //the series is listed with this group return 3 //series is not listed } disURL = "" function NextNext(array,pointer,next){ if(next[0] < array[pointer].nextc*1 && array[pointer].last < next[0]) { array[pointer].nextc = next[0] array[pointer].nextl = next[1] } } function newInner(tag,classN,inner){ var temp = document.createElement(tag) if(classN == "text/css") temp.type = classN else temp.className = classN temp.innerHTML = inner return temp } function cloneDOM(tag,nodo){ var temp = document.createElement(tag) temp = nodo.cloneNode(true) return temp } function newDOM(tag,classN,style){ var temp = document.createElement(tag) temp.className = classN temp.style.display = style return temp } function HasBeenRead(nodo){ if(!nodo.getElementsByTagName("svg")[0].className.baseVal.includes(" feather ")) return true else return false } function ChangeToBL(nodo){ if(nodo.parentElement.getElementsByClassName("showme").length) console.log("still blacklisted?")//InverseIt(nodo.parentElement)//HideItAgain else { var parche = newInner("a","font-bold truncate showme blacklisted","BLACKLISTED") nodo.parentElement.append(parche)//removeAttribute("href") nodo.className += " hideme" } } function InverseIt(nodo){//ShowItgain let hideme = nodo.getElementsByClassName("hideme")[0] let showme = nodo.getElementsByClassName("showme")[0] if(!!hideme && !!showme){ console.log("inversing in process") hideme.className = nodo.children[2].className.replace("hideme","showme") showme.className = nodo.children[3].className.replace("showme","hideme") } } function HideItAgain(nodo){ console.log("Hide It Again in process") let hideme = nodo.getElementsByClassName("hideme")[0] let showme = nodo.getElementsByClassName("showme")[0] hideme.className = nodo.children[2].className.replace("hideme","showme") showme.className = nodo.children[3].className.replace("showme","hideme") } function getID(nodo){ return nodo.getElementsByTagName("a")[0].href.split("/")[4] } function getID2(nodo){ return nodo.getElementsByTagName("a")[1].href.split("/")[4] } function getID3(text){ return text.split("/")[4] } function ProcessGroups(process,batch,i,id_series){//todo: fix syntaxis to consider every scenario if(filter){ var repeated = false var icono,newdiv var groupclass = "md:col-span-2" var externals = "flex items-center" var groupflex = batch[i].getElementsByClassName(groupclass)[0] //get the groups of this chapters if(!groupflex) groupflex = batch[i].getElementsByClassName(externals)[1] //external chapters if(batch[i].getElementsByClassName("nmf-single").length) { groupflex = batch[i].getElementsByClassName("group-tag") //already processed repeated = true } else{ if(groupflex.getElementsByTagName("svg").length) icono = cloneDOM("svg",groupflex.getElementsByTagName("svg")[0]) else icono = newInner("div","",'<svg data-v-9117f4b0="" data-v-d4f823fe="" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="small text-icon-black dark:text-icon-white icon"><path data-v-9117f4b0="" d="M17 21V19C17 17.9391 16.5786 16.9217 15.8284 16.1716C15.0783 15.4214 14.0609 15 13 15H5C3.93913 15 2.92172 15.4214 2.17157 16.1716C1.42143 16.9217 1 17.9391 1 19V21" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path><path data-v-9117f4b0="" d="M9 11C11.2091 11 13 9.20914 13 7C13 4.79086 11.2091 3 9 3C6.79086 3 5 4.79086 5 7C5 9.20914 6.79086 11 9 11Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path><path data-v-9117f4b0="" d="M23 20.9999V18.9999C22.9993 18.1136 22.7044 17.2527 22.1614 16.5522C21.6184 15.8517 20.8581 15.3515 20 15.1299" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path><path data-v-9117f4b0="" d="M16 3.12988C16.8604 3.35018 17.623 3.85058 18.1676 4.55219C18.7122 5.2538 19.0078 6.11671 19.0078 7.00488C19.0078 7.89305 18.7122 8.75596 18.1676 9.45757C17.623 10.1592 16.8604 10.6596 16 10.8799" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg>').firstChild newdiv = newDOM("div",groupclass+" nmf-groups","inline-grid") } function GFP(groupflex,z,process,batch,i,id_series){ let wl = false let bl = false var gid = 0 if(groupflex.innerText == "No Group") gid = 0 else { if(groupflex.children[z].href) gid = groupflex.children[z].href.split("/")[4] else if(groupflex.children[z].parentElement.href) gid = groupflex.children[z].parentElement.href.split("/")[4] //external links else { groupflex = groupflex.getElementsByClassName("nmf-single")[z].children[1] }//console.log(groupflex.children[z]) } //check if should be shown if(HideThis(blacklist,id_series,gid)) { console.log("blacklisted! hidethis") process += false bl = true //ChangeToBL(batch[i].getElementsByTagName("a")[0]) } else if(OnlyThis(whitelist,id_series,gid) == 1) { console.log("not in whitelist!") process += false } else if(OnlyThis(whitelist,id_series,gid) == 2) { console.log("whitelisted!") process += true wl = true } else{ process += true } //add buttons // if(!groupflex.getElementsByClassName("nmf-single").length){ // var single = newDOM("div","nmf-single","flex") // var newicono // if(!!icono) { // newicono= cloneDOM("svg",icono) // single.append(newicono) // } // var dagroup = document.createElement("a") // dagroup = groupflex.children[z].cloneNode(true) // if(dagroup.tagName != "A") { // dagroup = newInner("a",grouptagclass,groupflex.children[z].innerText) // if(!!groupflex.children[z].parentElement.href) dagroup.href = groupflex.children[z].parentElement.href //for external // } // dagroup.style.maxWidth = "80%" // dagroup.title = groupflex.children[z].innerText // single.append(dagroup) // var executor // if(wl) executor = newInner("div","list-options","<button title=\"Remove from Whitelist\" onclick=\"WL('"+id_series+"','"+gid+"')\">✅</button><button title=\"Add to Blacklist\" onclick=\"BL('"+id_series+"','"+gid+"')\">❌</button>") // else if(bl) executor = newInner("div","list-options","<button title=\"Add to Whitelist\" onclick=\"WL('"+id_series+"','"+gid+"')\">✅</button><button title=\"Remove from Blacklist\" onclick=\"BL('"+id_series+"','"+gid+"')\">❌</button>") // else executor = newInner("div","list-options","<button title=\"Add to Whitelist\" onclick=\"WL('"+id_series+"','"+gid+"')\">✅</button><button title=\"Add to Blacklist\" onclick=\"BL('"+id_series+"','"+gid+"')\">❌</button>") // single.append(executor) // newdiv.append(single) // } return process } try{ if(!repeated){ for(let z=1; z<groupflex.children.length; z++){ process = GFP(groupflex,z,process,batch,i,id_series) } if(groupflex.children.length == 1) process = GFP(groupflex,0,process,batch,i,id_series) // if(!batch[i].getElementsByClassName(groupclass+" nmf-groups").length) groupflex.parentElement.replaceChild(newdiv,groupflex) // else return true return process } else{//has been repeated for(let g of groupflex){ var gid = getID(g.parentElement) //check if should be shown if(HideThis(blacklist,id_series,gid)) { console.log("blacklisted! processgroups") process += false ChangeToBL(batch[i].getElementsByTagName("a")[0]) } else if(OnlyThis(whitelist,id_series,gid) == 1) { console.log("not in whitelist!") process += false } else if(OnlyThis(whitelist,id_series,gid) == 2) { console.log("whitelisted!") process += true } else{ process += true } } return process } } catch(e){ console.log("groupflex error") console.log(e) console.log(batch[i]) return true } } } function DecideNext(pseries,nextc,nextl,last,link,id_series,l){ if(pseries >= 0) NextNext(seriesdex,pseries,[nextc,nextl]) else seriesdex.push({id:id_series, name:l.firstChild.innerText, last:last, nextc:nextc, nextl:nextl}) let index = FS(follows,id_series) if(index >= 0){ if(seriesdex[pseries].last < last || seriesdex[pseries].last == null) seriesdex[pseries].last = last if(nextc > last){ NextNext(follows,index,[nextc,nextl]) NextNext(seriesdex,pseries,[nextc,nextl]) } if(l != follows[index].pointer) { while(l.getElementsByClassName(classChapter)[0] != undefined) follows[index].pointer.getElementsByClassName(classChapter)[0].append(l.getElementsByClassName(classChapter)[0]) } } else{ follows.push({id:id_series, ch:last, url:link, nextc:nextc, nextl:nextl, pointer:l}) } if(pseries == -1) pseries = FS(seriesdex,id_series) if(seriesdex[pseries].nextc == 0 || seriesdex[pseries].nextc == null || seriesdex[pseries].nextc == 10000 || (seriesdex[pseries].nextc > nextc && seriesdex[pseries].last < nextc)){ seriesdex[pseries].nextc = nextc seriesdex[pseries].nextl = nextl } } var feedone = "mb-4" function FollowsFeed(){ if(JSON.parse(localStorage.getItem("whitelist"))) whitelist = JSON.parse(localStorage.getItem("whitelist")) if(JSON.parse(localStorage.getItem("blacklist"))) blacklist = JSON.parse(localStorage.getItem("blacklist")) if(document.URL.includes("titles/feed")) { var feedwhole = "mb-12" if(document.getElementsByClassName(feedwhole).length){//if page is loaded console.log("FollowsFeed") lista = document.getElementsByClassName(feedwhole)[0].getElementsByClassName(feedone) console.log("lista loaded") createModal() for(let i = seriesdex.length-1; i>=0; i--){//to correct a previous bug if(seriesdex[i].id.includes("/")) seriesdex.splice(i,1) } for(let l of lista){//check the list try{ var id_series = getID(l)//.getElementsByTagName("a")[0].href.split("/")[4] var batch = l.getElementsByClassName(classChapter) var chap, link, read, nextc, nextl, last nextc = 10000 nextl = "" let pseries = FS(seriesdex,id_series) if(pseries < 0) last = -10 else last = seriesdex[pseries].last if(batch.length){//if there's chapters for(let i=0; i<batch.length; i++){ var name = batch[i].getElementsByTagName("a")[0].innerText.replace("\n"," ") var current = name.split(" ")[1]*1 var process = false batch[i].getElementsByTagName("a")[0].setAttribute("title",name) try{//for external links JSON.parse(current) } catch(e){ current = batch[i].getElementsByTagName("a")[0].innerText.replace("\n"," ").split(" ")[2]*1 if(Number.isNaN(current)) current = 0 } if(filter) process = ProcessGroups(process,batch,i,id_series) else process = true if(process){//should be shown if(!HasBeenRead(batch[i])){ if(last < current && nextc > last && nextc > current){ nextc = current nextl = batch[i].getElementsByTagName("a")[0].href.split("chapter/")[1] } } else if(HasBeenRead(batch[i])){ if(last < current) last = current } if(filter) InverseIt(batch[i].getElementsByTagName("a")[0].parentElement) } else{//has to be hidden if(filter) ChangeToBL(batch[i].getElementsByTagName("a")[0]) } } } DecideNext(pseries,nextc,nextl,last,link,id_series,l) } catch(e){ console.log("error processing lista") console.log(e) } } for(let f of follows){//consider chapters that aren't together let avail = f.pointer.getElementsByClassName(classChapter) let lastest = -10 let newest = 10000 let link = null let current = FS(seriesdex,f.id) if(current >= 0){ lastest = seriesdex[current].last newest = seriesdex[current].nextc } for(let a of avail){ if(!a.getElementsByClassName("continue").length){ let elem = a.getElementsByTagName("a")[0] let disONE = elem.innerText.replace("\n"," ").split(" ")[1]*1 try{ JSON.parse(disONE)//for external links } catch(e){ console.log("external link") disONE = elem.innerText.replace("\n"," ").split(" ")[2]*1 if(Number.isNaN(disONE)) disONE = 0 } let unread = (!HasBeenRead(a)) if(disONE > lastest && !unread) lastest = disONE if(unread && newest > disONE && disONE > lastest) { newest = disONE link = elem.href.split("chapter/")[1] } } } f.ch = lastest if(newest > lastest) { f.nextc = newest f.nextl = link } else{ f.nextc = 10000 f.nextl = null } if(lastest > seriesdex[current].last) { seriesdex[current].last = lastest } else{ if(seriesdex[current].nextc != f.nextc){ seriesdex[current].nextc = f.nextc seriesdex[current].nextl = f.nextl } } } for(let l of lista){//add the continue link if necessary and add filtering button let fbtn = newInner("button","nmf-btn","🔧") fbtn.style.float = "right" fbtn.setAttribute("onclick","NMDFilter(event)") let titu = l.getElementsByClassName("chapter-feed__title")[0] if(!!!l.getElementsByClassName("nmf-btn").length) titu.insertBefore(fbtn,titu.firstChild) let elem = l.getElementsByTagName("a")[0] if(elem){ //l.firstChild.getElementsByTagName("a")[0] let daONE = seriesdex[FS(seriesdex,elem.href.split("/")[4])] let extrainfo = "" if(l.getElementsByClassName(classFeed).length == 0) l.style.display = "none" else if(daONE.nextc > daONE.last && daONE.nextl){ if(daONE.last != -10 && (daONE.nextc - daONE.last >= 1.2)) extrainfo = " (WARNING: skipped chapters)" if(daONE.last == -10) extrainfo = " (WARNING: no previous info)" let newbutton = newInner("div",classFeed,"<button class=\"continue\"><a href=\"/chapter/"+daONE.nextl+"\">CONTINUE to Chapter "+daONE.nextc+extrainfo+"</button>") if(l.getElementsByClassName("continue").length == 0) l.getElementsByClassName("chapter-feed__chapters")[0].insertBefore(newbutton,l.getElementsByClassName(classFeed)[0]) else l.getElementsByClassName("continue")[0].parentElement.innerHTML = newbutton.innerHTML } if((daONE.nextl == null || daONE.nextl == "") && l.getElementsByClassName("continue")[0] != undefined) l.getElementsByClassName("continue")[0].parentElement.remove() } } for(let n=follows.length-1; n >= 0; n--){//put unread series on top of the list if(follows[n].pointer.getElementsByClassName("continue")[0] != undefined) lista[0].parentElement.insertBefore(follows[n].pointer,lista[0]) } localStorage.setItem("seriesdex",JSON.stringify(seriesdex)) } else repeat = setTimeout(FollowsFeed,5000) } } function Clickear(){ hola = document.getElementsByClassName("follows__content mb-12")[0].firstChild.children state = true try{ for(let h of hola){ if(h.innerHTML != "<!---->"){ if(h.firstChild.firstChild.lastChild.tagName == "BUTTON") { h.firstChild.firstChild.lastChild.click() } else state = false } } if(state) setTimeout(Clickear,2500) else FillTitles() } catch(e){ setTimeout(Clickear,2500) } } function Llenar(X){ let temp = [] console.log("now filling "+X.firstChild.firstChild.firstChild.innerText) for(let t of X.getElementsByClassName("manga-card")){ var id = getID(t)//.getElementsByTagName("a")[0].href.split("/")[4] var name = t.getElementsByTagName("a")[0].innerText.replaceAll("\n ","").replaceAll("\n ","") temp.push({id:id, name:name, last:null, nextc:null, nextl:null }) if(temp.length == 0) temp = [{id:id, name:name, last:null, nextc:null, nextl:null}] } console.log("Done Filling!!") return temp } function NewButton(){ try{ newb = document.createElement("button") newb.innerHTML = "<button id=\"fill-btn\" data-v-621772ff=\"\" type=\"button\" class=\"v-btn v-btn--is-elevated v-btn--has-bg theme--dark v-size--default\"><span class=\"v-btn__content\"><span data-v-621772ff=\"\" aria-hidden=\"true\" class=\"v-icon notranslate theme--dark\" onclick=\"Fill()\"><a>FILL</a></span></span></button>" if(!document.getElementById("fill-btn")) document.getElementsByClassName("controls mb-auto ml-auto")[0].appendChild(newb) dl = document.createElement("div") dl.innerHTML="<button class=\"rounded relative md-btn flex items-center px-3 my-6 justify-center text-white bg-primary hover:bg-primary-darken active:bg-primary-darken2 glow px-4 px-6\" onclick=\"DownloadCSV()\">Download CSV</button><button class=\"rounded relative md-btn flex items-center px-3 my-6 justify-center text-white bg-primary hover:bg-primary-darken active:bg-primary-darken2 glow px-4 px-6\" onclick=\"DownloadJSON()\">Download JSON<button>" document.getElementsByClassName("follows__display")[0].parentElement.insertBefore(dl,document.getElementsByClassName("follows__display")[0]) } catch(e){ setTimeout(NewButton,500) } } function FillTitles(){ try{ titles = document.getElementsByClassName("follows__content")[0].firstChild.children if(titles != undefined){ console.log("Filling Titles") for(t of titles){ if(t.innerHTML != "<!---->"){ let status = t.firstChild.firstChild.firstChild.innerText if(status == "Reading") reading = Llenar(t) if(status == "On Hold") onhold = Llenar(t) if(status == "Plan To Read") planto = Llenar(t) if(status == "Dropped") dropped = Llenar(t) if(status == "Completed") completed = Llenar(t) } } let oldr = JSON.parse(localStorage.getItem("reading")) let oldo = JSON.parse(localStorage.getItem("onhold")) let oldp = JSON.parse(localStorage.getItem("planto")) let oldd = JSON.parse(localStorage.getItem("dropped")) let oldc = JSON.parse(localStorage.getItem("completed")) for(let r of reading){ if(FS(seriesdex,r.id) == -1) seriesdex.push(r) } function Copiar(arrA,argB){ if(FS(arrA, argB.id) >= 0){ let indice = FS(arrA, argB.id) arrA[indice].last = argB.last arrA[indice].nextc = argB.nextc arrA[indice].nextl = argB.nextl } } for(let i = seriesdex.length-1; i >= 0; i--){ Copiar(completed, seriesdex[i]) Copiar(onhold, seriesdex[i]) Copiar(reading, seriesdex[i]) Copiar(dropped, seriesdex[i]) //Copiar(planto, seriesdex[i]) } function UpdateArrays(old,array){ for(let a of array){ let indice = FS(old,a.id) if(old[indice].last > a.last) { a.last = old[indice].last a.nextc = old[indice].nextc a.nextl = old[indice].nextl } } return array } reading = UpdateArrays(oldr,reading) //planto = UpdateArrays(oldp,planto) onhold = UpdateArrays(oldo,onhold) dropped = UpdateArrays(oldd,dropped) completed = UpdateArrays(oldc,completed) localStorage.setItem("reading",JSON.stringify(reading)) localStorage.setItem("planto",JSON.stringify(planto)) localStorage.setItem("onhold",JSON.stringify(onhold)) localStorage.setItem("dropped",JSON.stringify(dropped)) localStorage.setItem("completed",JSON.stringify(completed)) alert("Done!") } } catch(e){ console.log("error filling titles") console.log(e) } } function main(){ if(document.getElementsByClassName("ml-4 cursor-pointer rounded-full overflow-hidden bg-accent flex items-center justify-center").length && document.getElementsByClassName("ml-4 cursor-pointer rounded-full overflow-hidden bg-accent flex items-center justify-center")[0].firstChild.tagName == "IMG"){//is logged if(document.URL.includes("https://mangadex.org/user/me")){ console.log("Script ready") function EsperaBotones(){ try{ botones = document.getElementsByClassName("follows__content mb-12")[0].getElementsByTagName("button") } catch(e){ setTimeout(EsperaBotones,1000) } } EsperaBotones() function Repetir(){ estado = true for(let b of botones){ if(b.innerText.includes("Load More")) { b.click() estado = false } } if(estado) FillTitles() else setTimeout(Repetir,2500) } document.Fill = function(){ console.log("Loading series...") alert("Please wait until the next alert, this can take several minutes depending of how many series you follow.") Repetir() } if(document.getElementsByClassName("select__tab select__tab-active")[0].innerText == "Follows"){ NewButton() } } if(document.URL.includes("https://mangadex.org/titles/feed")){ console.log("checking feed") follows = [] ScriptForm() if(document.getElementsByClassName(feedone).length) FollowsFeed() else setTimeout(main,2000) } if(document.URL.includes("https://mangadex.org/title/")){ console.log("Checking a series") var fstatus if(JSON.parse(localStorage.getItem("whitelist"))) whitelist = JSON.parse(localStorage.getItem("whitelist")) if(JSON.parse(localStorage.getItem("blacklist"))) blacklist = JSON.parse(localStorage.getItem("blacklist")) function UpdatingSeriesData(){ var loadedp = "flex gap-2 sm:mb-0 mb-2" if(document.getElementsByClassName(loadedp).length){//if page is loaded console.log("loaded") var toProcess = false var id_series = document.URL.split("/")[4] var daLast = -110 var daNext = 10000 var daNLink = null var tags = document.getElementsByClassName("tag bg-accent") var volChange = document.getElementsByClassName("col-span-4") var sus = false fstatus = document.getElementsByClassName(loadedp)[0].firstChild.innerText //following status console.log("fstatus: "+fstatus) if(fstatus == ""){ setTimeout(UpdatingSeriesData,500) return } var toConsider = ["Reading","Completed","On Hold","Dropped","Added To Library"] var lastup = document.getElementsByClassName("chapter-grid")[0].innerText.split(" ")[1]*1 if(Number.isNaN(lastup) || HideThis(blacklist,id_series,getID(document.getElementsByClassName(grouptagclass)[0].parentElement))) lastup = 100000 for(let t of tags){ //console.log(t.innerText) if(t.innerText.toLowerCase().includes("4-koma")) { sus = true console.log("SUS!!") } } function Apoo(){ if(toConsider.includes(fstatus)){//(fstatus == "Reading"){ console.log("reading series") toProcess = true daVolumes = document.getElementsByClassName("rounded flex flex-col gap-2") for(let dv of daVolumes){ //console.log("checking volumes") daChapters = dv.getElementsByClassName("chapter-grid") for(let dc of daChapters){ //console.log("checking chapters") let current if(dc.innerText.includes("Oneshot")) current = 0 else current = GetNumero(dc.innerText.split("\n")[0]) if(Number.isNaN(current)) current = GetNumero(dc.parentElement.parentElement.parentElement.innerText.split("\n")[0]) if(current <= daLast) break //console.log("checking "+current) // console.log(dc.innerText) if(sus){ console.log("sus checking "+current) if(current < lastup) lastup = current else { console.log("break") return } } if(current <= daLast) break if((!HideThis(blacklist,id_series,getID2(dc)) || HideThis(whitelist,id_series,getID2(dc))) && !HasBeenRead(dc) && daNext > current && daNext > daLast){ daNext = current console.log("daNext: "+daNext) daNLink = getID(dc)//.getElementsByTagName("a")[0].href.split("/")[4] console.log("daNLink: "+daNLink) }//todo: multiple groups if((HideThis(blacklist,id_series,getID2(dc)) || OnlyThis(whitelist,id_series,getID2(dc))==1) && !HasBeenRead(dc) && daNext > current && daNext > daLast){//not consider if it's blacklisted daNext = 10000 daNLink = null } if(HasBeenRead(dc) && daLast < current) { daLast = current if(daNext <= daLast) { daNext = 10000 daNLink = null } console.log("found a last one") break } } } } } Apoo() let daIndex = FS(seriesdex,id_series) if(daIndex >= 0){ if(seriesdex[daIndex].name != document.title.replace(" - MangaDex","")) seriesdex[daIndex].name = document.title.replace(" - MangaDex","") console.log("previous last: "+seriesdex[daIndex].last) if(sus){ seriesdex[daIndex].last = daLast seriesdex[daIndex].nextc = daNext seriesdex[daIndex].nextl = daNLink }else if(seriesdex[daIndex].last <= daLast) { seriesdex[daIndex].last = daLast seriesdex[daIndex].nextc = daNext seriesdex[daIndex].nextl = daNLink } console.log("new last: "+seriesdex[daIndex].last) } else { if(toProcess){//not registered console.log("new series!") seriesdex.push({id:id_series, name:document.title.replace(" - MangaDex",""), last:daLast, nextc:daNext, nextl:daNLink}) } else{//fixes bug that adds everything if(fstatus != "Plan to Read") seriesdex.splice(daIndex,1) } } if(FS(seriesdex,id_series) >= 0) console.log(seriesdex[FS(seriesdex,id_series)]) localStorage.setItem("seriesdex",JSON.stringify(seriesdex)) } else setTimeout(UpdatingSeriesData,500) } UpdatingSeriesData() } } else setTimeout(main,5000) } function Loop(){ try{ if(disURL != document.URL){ console.log("loop") repeat = setTimeout(main,5000) disURL = document.URL trigger = false } } catch(e){ console.log("error loop") } frutyloop = setTimeout(Loop,1000) } frutyloop = setTimeout(Loop,1000) function exportToJsonFile(jsonData) { let dataStr = JSON.stringify(jsonData); let dataUri = 'data:application/json;charset=utf-8,'+ encodeURIComponent(dataStr); let exportFileDefaultName = 'seriesdex.json'; let linkElement = document.createElement('a'); linkElement.setAttribute('href', dataUri); linkElement.setAttribute('download', exportFileDefaultName); linkElement.click(); } function parseJSONToCSVStr(jsonData) { if(jsonData.length == 0) { return ''; } let keys = Object.keys(jsonData[0]); let columnDelimiter = '\t'; let lineDelimiter = '\n'; let csvColumnHeader = keys.join(columnDelimiter); let csvStr = csvColumnHeader + lineDelimiter; jsonData.forEach(item => { keys.forEach((key, index) => { if( (index > 0) && (index < keys.length) ) { csvStr += columnDelimiter; } csvStr += item[key]; }); csvStr += lineDelimiter; }); return encodeURIComponent(csvStr);; } function exportToCsvFile(jsonData) { let csvStr = parseJSONToCSVStr(jsonData); let dataUri = 'data:text/csv;charset=utf-8,'+ csvStr; let exportFileDefaultName = 'MangaDexFollowFeed.csv'; let linkElement = document.createElement('a'); linkElement.setAttribute('href', dataUri); linkElement.setAttribute('download', exportFileDefaultName); linkElement.click(); } function PrepareData(lala){ var temp = [] reading = JSON.parse(localStorage.getItem("reading")) planto = JSON.parse(localStorage.getItem("planto")) onhold = JSON.parse(localStorage.getItem("onhold")) dropped = JSON.parse(localStorage.getItem("dropped")) completed = JSON.parse(localStorage.getItem("completed")) function Processing(arrayy,naame){ for(let a of arrayy){ let last if(lala){ //if(a.last*1 < 0 || JSON.parse(a.last) == null) last = "unregistered" if(a.last*1 < 0 || a.last == null) last = "unregistered" else last = a.last } else last = a.last temp.push({id:a.id,name:a.name,state:naame,last:last}) if(temp.length == 0) temp = [{id:a.id,name:a.name,state:naame,last:last}] } } Processing(reading,"Reading") Processing(onhold,"On Hold") Processing(planto,"Plan to Read") Processing(dropped,"Dropped") Processing(completed,"Completed") return temp } window.FF = function(){//for debugging FollowsFeed() } window.DownloadCSV = function(){ exportToCsvFile(PrepareData(true)) } window.DownloadJSON = function(){ exportToJsonFile(PrepareData(false)) } document.onscroll = function() { // if(document.URL.includes("titles/feed")) { var w = document.documentElement.clientHeight; var over = document.documentElement.scrollTopMax; if(document.documentElement.scrollTop < over) trigger = true if(w < over && document.documentElement.scrollTop == over) { if(trigger) setTimeout(main,500) trigger = false } // } } document.WL = function(id,gid){ if(OnlyThis(whitelist,id,gid) < 2 ) {//it's not included whitelist.push([id,gid]) alert("This group has been added to the whitelist for this series. Click the botton again to undo it.") } if(HideThis(whitelist,id,gid)){ whitelist.splice(whitelist.findIndex(q => q[0] == id && q[1] == gid),1) alert("This group has been removed from the whitelist for this series.") } UpdateShown() localStorage.setItem("whitelist",JSON.stringify(whitelist)) } document.BL = function(id,gid){ if(!HideThis(blacklist,id,gid)){ blacklist.push([id,gid]) alert("This group has been added to the blacklist for this series. Click the botton again to undo it.") } else{ blacklist.splice(blacklist.findIndex(q => q[0] == id && q[1] == gid),1) alert("This group has been removed from the blacklist for this series.") } UpdateShown() localStorage.setItem("blacklist",JSON.stringify(blacklist)) } window.SaveFilter = function(event){ let nodo = event.target.parentElement.parentElement function AddtoArray(array,id,gid){ if(array.findIndex(q => q[0] == id && q[1] == gid) < 0) array.push([id,gid]) return array } function RemoveFromArray(array,id,gid){ let index = array.findIndex(q => q[0] == id && q[1] == gid) if(index >= 0) { array.splice(index,1) alert("Removed from the list") } return array } for(let x=1; x<nodo.children[5].firstChild.childElementCount; x++){ let gid = nodo.children[5].firstChild.children[1].cells[1].innerText let wl = JSON.parse(nodo.children[5].firstChild.children[1].cells[2].firstChild.checked) let bl = JSON.parse(nodo.children[5].firstChild.children[1].cells[3].firstChild.checked) let id = nodo.children[1].id if(wl&&bl) alert("It can't be part of both lists") else if(wl) { AddtoArray(whitelist,id,gid) alert("Whitelisted") } else if(bl) { AddtoArray(blacklist,id,gid) alert("Blacklisted") } if(!wl) RemoveFromArray(whitelist,id,gid) if(!bl) RemoveFromArray(blacklist,id,gid) } localStorage.setItem("whitelist",JSON.stringify(whitelist)) localStorage.setItem("blacklist",JSON.stringify(blacklist)) } function UpdateShown(){ let hidden = document.getElementsByClassName("hideme") if(hidden.length){ //document.getElementsByClassName("hideme")[0].parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement == l for(let h of hidden) {//document.getElementsByClassName("hideme")[0].parentElement.parentElement.parentElement == batch[i] let batch = h.parentElement.parentElement.parentElement let l = batch.parentElement.parentElement.parentElement.parentElement let id = getID(l)//.getElementsByTagName("a")[0].href.split("/")[4] let gel = h.parentElement.parentElement.children[1] let gid = 0 if(gel.getElementsByTagName("a").length) gid = getID(gel)//.getElementsByTagName("a")[0].href.split("/")[4] else if(gel.getElementsByTagName("span").length) gid = gel.getElementsByTagName("span")[0].parentElement.href.split("/")[4] if(!HideThis(blacklist,id,gid)) InverseIt(h.parentElement) //else InverseIt(h.parentElement) } } }