// ==UserScript== // @name New MangaDex Follows // @namespace https://greasyfork.org/scripts/430295-new-mangadex-follows // @version 1.2.1 // @description Manage your follows // @author Australis // @match https://mangadex.org/* // @icon https://www.google.com/s2/favicons?domain=mangadex.org // @grant none // @license MIT // @downloadURL none // ==/UserScript== function LoadSD(){ if(localStorage.getItem("seriesdex") == null) seriesdex = [] else seriesdex = JSON.parse(localStorage.getItem("seriesdex")) //1.2 if(localStorage.getItem("forbidden") == null) forbidden = [] else forbidden = JSON.parse(localStorage.getItem("forbidden")) } LoadSD() //GLOBAL VARIABLES // var seriesdex,forbidden,whitelist,blacklist,titlepage,frutyloop,repeat,lista,new_r,new_c,new_d,new_o,new_p,follows,trigger,fstatus,funky 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 loadedp = "flex gap-2 sm:mb-0 mb-2" //status var feedone = "mb-2"//mb-4 var MAXNUM = 10000 var MINNUM = -10 var disURL = "" var unchecked = true var preevent = null whitelist = [] blacklist = [] var orphans = [] titlepage = null var filter,pikapika handler = false var newStyle = newInner("style","text/css",".hideme {\ndisplay: none;\n} .levy {\nwhite-space: nowrap;\noverflow: hidden;\ntext-overflow: ellipsis;\nmax-width: 30vw;\ndisplay: block;} .centered{\ntext-align: center;} .yellow{\ncolor: yellow !important}") //1.2 document.querySelector("head").append(newStyle) filter = LoadCheckers("filter") pikapika = LoadCheckers("pikapika") //FUNCTIONS function LoadCheckers(name){//1.2 let varr = JSON.parse(localStorage.getItem(name)) if(varr == undefined || varr == null) { console.info(`${name}: ${JSON.stringify(varr)}`) varr = true SafeSave(name,varr) } return varr } function SafeLoad(name){//1.2 let temp = [] if(localStorage.getItem(name)) temp = JSON.parse(localStorage.getItem(name)) return temp } function GetNumero(text){ let skip = false if(text.includes("Ch.") && text.includes(" - ")) text = text.split(" - ")[0] //1.2 for(let t of text.replaceAll("\n"," ").replaceAll("\t"," ").split(" ")){ if(t == "Vol.") skip = true else if(t.includes(".")){//1.2 let num = t.split(".") if(num.length > 2){ let resto = "" for(let i = 1; i') modal.id = "daModal" var body = document.querySelector("body") body.insertBefore(modal,body.firstElementChild) //1.2 var daStyle = newInner("style","text/css",'.modal {display: none;position: fixed;z-index: 500;padding-top: 100px;right: 0;top: 0;width: 100%;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) } else console.info("modal already exists") } function FS(array, number){//FindSeries return array.findIndex(q => q.id == number) } function HideThis(series,group){ for(let g of group){//1.2 if(blacklist.findIndex(q => q[0] == series && q[1] == g) >= 0){ //q[1] == group console.info("hide this!") return true } if(blacklist.findIndex(q => q[0] == 0 && q[1] == g) >= 0){ console.info(`group ${g} globally blocked`) return true } } return false } function OnlyThis(series,group){ let result = 0 for(let g of group){//1.2 if(whitelist.findIndex(q => q[0] == series && q[1] == g) >= 0) { //the series is listed with this group console.info("onlythis!") return 2 } if(whitelist.findIndex(q => q[0] == series && q[1] != g) >= 0) { //the series is listed but not this group console.info("not whitelisted") result = 1 } } return result } 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 InverseIt(nodo){//ShowItgain let hideme = getCN2(nodo,"hideme")[0] let showme = getCN2(nodo,"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 getTID(nodo){//1.2 //getID let result = null if(nodo && getTAG(nodo,"a").length) result = getTAG(nodo,"a")[0].href.split("/")[4] //1.2 if(result && result.includes("?")) result = result.split("?")[0] return result } function getGID(nodo){//1.2 //getID2 let result = [] function Push(x){ result.push(x) if(result.length == 0) result = [x] } if(nodo){ for(let a of getTAG(nodo,"a")){ let b = a.href if(b.includes("?")) b = b.split("?")[0] if(b.includes("/group/")) Push(getID3(b)) } if(getCN("cursor-default").length) Push(0) } else return null return result } function getID3(text){ return text.split("/")[4] } function HasBeenRead(nodo){ if(!getTAG(nodo,"svg")[0].className.baseVal.includes(" feather-eye ")) { // CleanFB(nodo) return true } else return false } function FollowsFeed(){ whitelist = SafeLoad("whitelist") blacklist = SafeLoad("blacklist") LoadSD()//1.1.3.3 unreads = 0 follows = [] if(document.URL.includes("titles/feed")) { var feedwhole = "mb-12" if(getCN(feedwhole).length){//if page is loaded console.log("FollowsFeed") lista = getCN2(getCN(feedwhole)[0],feedone) console.log("lista loaded") createModal() for(let i = seriesdex.length-1; i>=0; i--){//to correct previous bugs if(seriesdex[i].id.includes("/") || seriesdex[i].id.includes("?")) { console.log("bug correction! removing this one:") console.log(seriesdex[i]) seriesdex.splice(i,1) } else{ if(seriesdex[i].last == null) seriesdex[i].last = MINNUM if(seriesdex[i].nextc == MAXNUM || seriesdex[i].nextc == null || forbidden.includes(seriesdex[i].nextl)) DefaultNext(seriesdex[i]) if(!seriesdex[i].mu) seriesdex[i].mu = 0 //1.2 if(!Number.isFinite(seriesdex[i].last)){ if(Number.isFinite(seriesdex[i].last*1)) seriesdex[i].last*=1 else{ let digits = ["1","2","3","4","5","6","7","8","9","0"] let daNumber = "" for(let j of seriesdex[i].last){ if(!digits.includes(j)) break else daNumber+=j } if(daNumber.length) seriesdex[i].last = daNumber*1 else seriesdex[i].last = MINNUM } } if(seriesdex[i].last == seriesdex[i].nextc) DefaultNext(seriesdex[i]) } } let rep = 0 function DecideNext(pseries,nextc,nextl,last,link,id_series,l){//moved - 1.2 let daName = l.children[1].title //1.2 if(forbidden.includes(nextl)){ nextl = null nextc = MAXNUM } if(daName[0] == " ") daName = daName.slice(1) if(pseries >= 0) RevisaNext2(seriesdex[pseries],[nextc,nextl]) else seriesdex.push({id:id_series, mu:0, name:daName, last:last, nextc:nextc, nextl:nextl, time:0}) 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){ RevisaNext2(follows[index],[nextc,nextl]) RevisaNext2(seriesdex[pseries],[nextc,nextl]) } else DefaultNext(seriesdex[pseries]) if(l != follows[index].pointer){ //while(getCN2(l,classChapter)[0] != undefined) getCN2(follows[index].pointer,classChapter)[0].parentElement.append(getCN2(l,classChapter)[0]) //1.2 for(let n of getCN2(l,classChapter)){ let temp = cloneDOM("div",n) if(!l.className.includes("dummy") && !follows[index].pointer.innerText.includes(n.innerText)) {//1.2.1 getCN2(follows[index].pointer,classChapter)[0].parentElement.append(temp) } } l.style.display = "none" } } else{ follows.push({id:id_series, ch:last, url:link, nextc:nextc, nextl:nextl, pointer:l}) } if(pseries == -1) pseries = FS(seriesdex,id_series) //should be the last let ati = seriesdex[pseries].nextc //1.2 if(ati == 0 || ati == null || ati == MAXNUM || (ati > nextc && seriesdex[pseries].last < nextc)){ seriesdex[pseries].nextc = nextc seriesdex[pseries].nextl = nextl } } function ProcessGroups(batchi,id_series){ if(filter){ var icono,newdiv var gid = getGID(batchi) let OTresult = OnlyThis(id_series,gid) if(OTresult == 2) { console.log("whitelisted!!") return true } if(HideThis(id_series,gid)) { console.log("blacklisted!! hidethis") funky = "BLACKLIST" return false } if(OTresult == 1) { console.log("not in whitelist!!") funky = "WHITELIST" return false } //not part of any list return true } else return true } function ChangeToBL(nodo){//moved - 1.2 if(getCN2(nodo.parentElement,"showme").length) console.log("still blacklisted?") else { var parche = newInner("a","font-bold truncate showme blacklisted",`BLOCKED (${funky})`) nodo.parentElement.append(parche) nodo.className += " hideme" } } let lastnode if(!getCN("dummy").length) lastnode = cloneDOM("div",lista[lista.length-1]) else lastnode = null do{//1.1.3.2 for(let l of lista){//check the list try{ var id_series = getTID(l) var batch = getCN2(l,classChapter) var chap, link, read, nextc, nextl, last nextc = MAXNUM nextl = null let pseries = FS(seriesdex,id_series) if(pseries < 0) last = MINNUM else { last = seriesdex[pseries].last if(seriesdex[pseries].name == "") seriesdex[pseries].name = l.children[1].title //1.2 } function GetVol(text){//1.1.3.2 if(text.includes("Vol.")){ for(let t of text.replaceAll("\n"," ").split(" ")){ if(!Number.isNaN(t*1)) return t*1 } } else return false } if(batch.length){//if there's chapters let prevgid = false for(let i=0; i',']')) if(filter) process = ProcessGroups(batch[i],id_series) if(process){//should be shown if(!HasBeenRead(batch[i])){ if(last > current && (name.toLowerCase().includes("extra") || name.toLowerCase().includes("omake") || Number.isInteger(current - 0.5) || Number.isInteger(current - 0.9))) { getTAG(batch[i],"svg")[0].classList.add("amarillo") //1.2 } if(pseries >= 0 && !!seriesdex[pseries].lastv && vol){//1.1.3.2 if(pseries >= 0 && vol == seriesdex[pseries].lastv+1 || (vol == seriesdex[pseries].lastv && last < current && nextc > last && nextc >= current)){ nextc = current nextl = getTAG(batch[i],"a")[0].href.split("chapter/")[1] } } else if(last < current && nextc > last && nextc > current){ nextc = current nextl = getTAG(batch[i],"a")[0].href.split("chapter/")[1] if(forbidden.includes(nextl)) CleanFB(batch[i]) //1.2.1 //shouldn't be part of forbidden prevgid = getGID(batch[i]) //1.1.3.3 } else if(current == nextc){//1.1.3.3 let gids = getGID(batch[i]) if(prevgid == [0]){//give priority to real groups nextl = getTAG(batch[i],"a")[0].href.split("chapter/")[1] } prevgid = gids } } else{// if(HasBeenRead(batch[i])){ if(getTAG(batch[i],"svg")[0].classList.contains("yellow")) {//1.2 getTAG(batch[i],"svg")[0].classList.remove("yellow") } if(last < current) last = current let thistmp = (new Date(getTAG(batch[i],"time")[0].dateTime)).getTime() if(thistmp > timestamp) timestamp = thistmp } if(filter) InverseIt(getTAG(batch[i],"a")[0].parentElement) } else{//has to be hidden console.log("not to process") console.log(batch[i]) console.log(seriesdex[pseries]) let cid = getTID(batch[i]) if((!seriesdex[pseries].lastv && current > last) || (seriesdex[pseries].lastv && (vol > seriesdex[pseries].lastv || (vol == seriesdex[pseries].lastv && current > last)))){//1.2.1 FBPush(cid) getTAG(batch[i],"svg")[0].style.color = "red" if(forbidden.includes(nextl)) { console.log("reseting due forbidden") DefaultNext(seriesdex[pseries]) } } else{ console.log(`${cid} less than last (${current} <= ${last}\n${name})`) CleanFB(batch[i]) if(getTAG(batch[i],"svg")[0].style.color) getTAG(batch[i],"svg")[0].style.removeProperty("color") } let card = getCN2(l,"continue") if(card.length && card[0].firstChild.href == getTAG(batch[i],"a")[0].href.split("chapter/")[1]){ nextc = MAXNUM nextl = null } if(filter) ChangeToBL(getTAG(batch[i],"a")[0]) } } } DecideNext(pseries,nextc,nextl,last,link,id_series,l) } catch(e){ console.log("error processing lista") console.log(e) } } }while(rep++ < 1) 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 = getCN2(l,"chapter-feed__title")[0] let fbtn_container = cloneDOM("a",titu) fbtn_container.innerHTML = "" fbtn_container.removeAttribute("href") fbtn_container.append(fbtn) fbtn_container.style.display = "block" if(filter && !getCN2(l,"nmf-btn").length) { titu.parentElement.insertBefore(fbtn_container,titu) titu.style.width = "95%" } let elem = getTAG(l,"a")[0] if(elem){ let daONE = seriesdex[FS(seriesdex,getID3(elem.href))] let extrainfo = "" if(getCN2(l,classFeed).length == 0) l.style.display = "none" else if(daONE.nextc > daONE.last && daONE.nextl){ if(daONE.last != MINNUM && (daONE.nextc - daONE.last >= 1.2)) extrainfo = " (WARNING: skipped chapters)" if(daONE.last == MINNUM && daONE.nextc != 1) extrainfo = " (WARNING: no previous info)" if(daONE.last == MINNUM && daONE.nextc <= 1.1) extrainfo = " (Start reading!)"//1.1.3.2 let newbutton = newInner("div",classFeed,``) if(getCN2(l,"continue").length == 0) getCN2(l,"chapter-feed__chapters")[0].insertBefore(newbutton,getCN2(l,classFeed)[0]) else getCN2(l,"continue")[0].parentElement.innerHTML = newbutton.innerHTML } if(((daONE.nextl == null || daONE.nextl == "") || daONE.last >= daONE.nextc) && getCN2(l,"continue")[0] != undefined){ getCN2(l,"continue")[0].parentElement.remove() } } } //TopWoNerae()//1.2 console.info("TOP WO NERAE!") let amor = [] for(let o of getCN("amarillo")){ amor.push(o) } for(let a of amor){ a.classList.replace("amarillo","yellow") } for(let n=follows.length-1; n >= 0; n--){//put unread chapters on top of the list if(getCN2(follows[n].pointer,"yellow").length || follows[n].pointer.innerHTML.includes(" feather-eye ")) { lista[0].parentElement.insertBefore(follows[n].pointer,lista[0]) //1.2 console.log("unread UP!") } } for(let n=follows.length-1; n >= 0; n--){//put unread series on top of the list if(getCN2(follows[n].pointer,"continue").length) { lista[0].parentElement.insertBefore(follows[n].pointer,lista[0]) //1.2 console.log("continue UP!") } } for(let n=follows.length-1; n >= 0; n--){//put comikey's unread series on top of the list since they expire quicker if(getCN2(follows[n].pointer,"continue").length && follows[n].pointer.innerText.includes("Comikey")) { lista[0].parentElement.insertBefore(follows[n].pointer,lista[0]) //1.2 console.log("comikey UP!") } } //end TopWoNerae if(lastnode && lista[lista.length-1].innerText != lastnode.innerText){//1.2 //to not mess up the pagination for some reason let ultimo = cloneDOM("div",lastnode) console.log("dummy this time:") console.log(ultimo) ultimo.style.display = "none" ultimo.className+= " dummy" lista[0].parentElement.append(ultimo) } if(!frutyloop) { frutyloop = true // for(let i=1; i<6; i++) setTimeout(KeepChecking,i*2000) KeepChecking() } SafeSave("seriesdex",seriesdex) } else setTimeout(FollowsFeed,1000) } } function KeepChecking(){//1.2 if(frutyloop){ let totales = getCN("flex-shrink-0 cursor-pointer").length let noleidos = getCN("flex-shrink-0 cursor-pointer feather-eye").length if(unreads != totales-noleidos){ if(noleidos > 0) FollowsFeed() unreads = totales-noleidos } setTimeout(KeepChecking,2000) } } function Llenar2(){//1.1.3.2 function DefaultObj(){//moved - 1,2 return {id:0,mu:0,name:"",last:MINNUM,nextc:MAXNUM,nextl:null, time:0} } function Walala(){ // console.log("walala") let items = getCN("manga-card bg-accent") let temp = [] function WaitElement(nodo){ console.log("waiting") if(nodo.length) setTimeout(Primero,1000) else setTimeout(WaitElement(nodo),500) } function Primero(){ try{ for(let i of items){ let manga = DefaultObj() manga.id = getTID(i) manga.name = getTAG(i,"span")[0].innerText//1.2//i.firstChild.innerText if(FS(temp,manga.id) < 0) temp.push(manga) } ClickSiguiente() } catch(e){ console.warn("catch primero") console.error(e) setTimeout(Primero,500) } } function ClickSiguiente(){ try{ let pagination = getCN("flex justify-center flex-wrap gap-2 my-6")[0].children let final = pagination[pagination.length-1].innerText*1 let actual = 0 for(let p of pagination){ if(p.className.includes("bg-primary")) actual = p.innerText*1 if(!!actual && p.innerText*1 == actual+1) { p.click() Segundo() } if(!!actual && actual == final) { NextTab() console.log(temp) return temp } } } catch(e){ if(!getCN("flex justify-center flex-wrap gap-2 my-6")[0]){ console.warn("no pagination") NextTab() return temp } } } function Segundo(){ try{ items = getCN("manga-card bg-accent") let dummy = DefaultObj() dummy.id = getTID(items[0]) dummy.name = items[0].firstChild.innerText if(FS(temp,dummy.id)>=0) { setTimeout(Segundo,500) } else Primero() } catch(e){ console.warn("catch segundo") console.error(e) setTimeout(Segundo,5000) } } WaitElement(items) return temp } var tabs = getCN("select__tab") console.log(tabs) let firsttab = tabs[0] if(!firsttab.className.includes("active")) firsttab.click() function FillTitles(){ try{ console.info("Filling Titles") let oldr = SafeLoad("reading") let oldo = SafeLoad("onhold") let oldp = SafeLoad("planto") let oldd = SafeLoad("dropped") let oldc = SafeLoad("completed") function Copiar(arrA,argB){ let indice = FS(arrA, argB.id) if(indice >= 0){ arrA[indice].last = argB.last arrA[indice].nextc = argB.nextc arrA[indice].nextl = argB.nextl //1.2 if(!arrA[indice].mu) arrA[indice].mu = argB.mu arrA[indice].time = argB.time } } for(let s of seriesdex){ Copiar(new_c, s) Copiar(new_o, s) Copiar(new_r, s) Copiar(new_d, s) } function UpdateArrays(old,neww){ for(let a of neww){ let indice = FS(old,a.id) if(indice >= 0) {//1.2 let name = a.name a = old[indice] if(old[indice].name != name) a.name = name } } return neww } new_r = UpdateArrays(oldr,new_r) new_p = UpdateArrays(oldp,new_p) new_o = UpdateArrays(oldo,new_o) new_d = UpdateArrays(oldd,new_d) new_c = UpdateArrays(oldc,new_c) SafeSave("reading",new_r) SafeSave("planto",new_p) SafeSave("onhold",new_o) SafeSave("dropped",new_d) SafeSave("completed",new_c) alert("Done!") } catch(e){ console.log("error filling titles") console.log(e) } } function NextTab(){ console.log("next tab") for(let x=0; x= 0){ let nextl = array[index].nextl let nextc = array[index].nextc let last = array[index].last let mu = array[index].mu let time = array[index].time array[index].last = sd.last if(nextl && nextc > sd.last && nextc < sd.nextc){ console.log("there's a new chapter to consider") array[index].nextl = nextl array[index].nextc = nextc } if(sd.lastv){ array[index].lastv = sd.lastv if(sd.nextv) array[index].nextv = sd.nextv console.log("volume sorting in consideration") } if(time){ if(sd.time && time > sd.time){ console.log("there was a latter update") array[index].time = time } if(!sd.time){ console.log("there was no previous time") array[index].time = time } } if(mu){ if(!sd.mu){ console.log("there was no mangaupdate link before") array[index].mu = mu } } } else console.log("there's nothing to process??") SafeSave(arrayname,array) console.log(arrayname+" updated with sd:") console.log(array[index]) } function CompareSD(arrayname,sd){//1.2 console.log("Comparing SD with "+arrayname) let array = SafeLoad(arrayname) let index = FS(array,sd.id) if(index >= 0){ let nextl = array[index].nextl let nextc = array[index].nextc let last = array[index].last let mu = array[index].mu let time = array[index].time array[index] = sd if(nextl && nextc > sd.last && nextc < sd.nextc){ console.log("there's a new chapter to consider") array[index].nextl = nextl array[index].nextc = nextc } if(last > sd.last){ console.log("a new last") array[index].last = last } if(time){ if(sd.time && time > sd.time){ console.log("there was a latter update") array[index].time = time } if(!sd.time){ console.log("there was no previous time") array[index].time = time } } if(mu){ // console.log("mu "+arrayname+": "+mu) if(!sd.mu){ console.log("there was no mangaupdate link before") array[index].mu = mu } else if(sd.mu && mu != sd.mu){ console.log("mangaupdate link is different... updating it!") array[index].mu = mu } } else if(sd.mu){ console.log(`adding mangaupdate link: ${sd.mu}`) array[index].mu = sd.mu } } else console.log("there's nothing to process??") SafeSave(arrayname,array) console.log(arrayname+" updated with seriesdex:") console.log(array[index]) } function getCN(classname){//1.2 return document.getElementsByClassName(classname) } function getCN2(nodo,classname){//1.2 return nodo.getElementsByClassName(classname) } function getTAG(nodo,tagname){//1.2 return nodo.getElementsByTagName(tagname) } function SafeSave(item,array){//1.2 localStorage.setItem(item,JSON.stringify(array)) } function getFstatus(fstatus){//1.2 let arrayname = null if(fstatus == "Reading") arrayname = "reading" if(fstatus == "Completed") arrayname = "completed" if(fstatus == "Dropped") arrayname = "dropped" if(fstatus == "On Hold") arrayname = "onhold" if(fstatus == "Plan to Read") arrayname = "planto" return arrayname } function RevisaNext(nodo){//1.2 if(nodo.last >= nodo.nextc) DefaultNext(nodo) } function RevisaNext2(nodo,xxx){//1.2 if(xxx.length == 2){ if(nodo.last >= xxx[0] || nodo.last >= nodo.nextc) DefaultNext(nodo) if(xxx[0] > nodo.last && xxx[0] <= nodo.nextc){ nodo.nextc = xxx[0] nodo.nextl = xxx[1] } } else{ if(xxx[2] > nodo.lastv){ nodo.nextv = xxx[2] nodo.nextc = xxx[0] nodo.nextl = xxx[1] } if(xxx[2] == nodo.lastv){ if(nodo.last >= xxx[0] || nodo.last >= nodo.nextc) DefaultNext(nodo) if(xxx[0] > nodo.last && xxx[0] <= nodo.nextc){ nodo.nextc = xxx[0] nodo.nextl = xxx[1] // nodo.nextv = xxx[2] //redundant } } } } function DefaultNext(q){//1.2 q.nextc = MAXNUM q.nextl = null if(q.lastv) q.nextv = MAXNUM } function CleanFB(nodo){ let id = getTID(nodo) let index = forbidden.indexOf(id) if(index >= 0) { console.log(`deleting ${id} from forbidden`) forbidden.splice(index,1) console.log("length: "+forbidden.length) } else console.log(`${id} not part of forbidden`) SafeSave("forbidden",forbidden) } function FBPush(x){//1.2 if(!forbidden.includes(x)){ console.log(`adding ${x} to forbidden`) forbidden.push(x) } else console.log(`${x} already forbidden`) SafeSave("forbidden",forbidden) } //WINDOW FUNCTIONS window.SC = function(){ filter = document.getElementById("filter").checked SafeSave("filter",filter) alert("Changes saved successfully")//1.2 } window.ReadNext = function(){//1.1.3.3 FollowsFeed() var daModal = document.getElementById("daModal") if(!daModal) createModal() let reading = SafeLoad("reading") let daTable = '' for(let s of seriesdex){ if(s.nextl && s.last < s.nextc){ let name = s.name if(name == ""){ let index = FS(reading,s.id) if(index >= 0) name = reading[index].name } if(s.nextc > s.last+1.1) name+=" ‼️" daTable+=`` } } daTable+="
NameUnread Chapter
${name}CH. ${s.nextc}
" let closebutton = '×' daModal.firstChild.innerHTML= closebutton+daTable var closebtn = getCN("close")[0] closebtn.onclick = function() { daModal.style.display = "none" } } window.DisplayOrphans = function(){//1.2 FollowsFeed() var daModal = document.getElementById("daModal") if(!daModal) createModal() let reading = SafeLoad("reading") let daTable = '' for(let o of orphans){ let name = o.name let arl,kink if(o.nextc != MAXNUM) { //if(o.nextc > o.last+1.1) name+=" ‼️" arl = 'CH. '+o.nextc kink = ' href="/chapter/'+o.nextl+'"' } else { arl = '🚫' kink = '' } daTable+='' } daTable+="
NameUnread Chapter
'+name+''+arl+'
" let closebutton = '×

The following series aren\'t part of any list, they\'re just marked to be notified, visit their title page to add them to a list (like Reading, for example)

' daModal.firstChild.innerHTML= closebutton+daTable var closebtn = getCN("close")[0] closebtn.onclick = function() { daModal.style.display = "none" } } window.NMDF = function(){//1.1.3.3 let fcheck,ycheck function Checkear(a){//1.2 if(a) return " checked" else return "" } fcheck = Checkear(filter) ycheck = Checkear(pikapika) var daModal = document.getElementById("daModal") if(!daModal) createModal() let closebutton = '×' let d1 = '
Description

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.

' let d2 = '' let body = '

New MangaDex Follows Script Settings

'+d1+d2+'' let series = '
' function FindOrphans(){//1.2 console.log("searching for orphans") let com = SafeLoad("completed") let ptr = SafeLoad("planto") let dro = SafeLoad("dropped") let rea = SafeLoad("reading") let onh = SafeLoad("onhold") let x = 0 for(let s of seriesdex){ let z = 0 for(let y of [com,ptr,dro,rea,onh]) if(FS(y,s.id)>=0) z++ if(z==0){ console.log("an orphan!") console.log(s) if(FS(orphans,s.id) < 0) orphans.push(s) x++ } } return x } if(FindOrphans()) series+='' //1.2 daModal.firstChild.innerHTML= closebutton+body+series 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 } } window.Close = function(){ document.getElementById("daModal").style.display = "none" } window.NMDFilter = function(event){ if(document.URL.includes("/title/")) main() var daElement = event.target.parentElement.parentElement preevent = event //1.1.3.3 var daModal = document.getElementById("daModal") let ttext let gtext = [] let glink = [] let id = getTID(daElement) if(document.URL.includes("/title/")) { id = getID3(document.URL) ttext = getCN("mb-1")[0].innerText } let daSeries = seriesdex[FS(seriesdex,id)] for(let link of getTAG(daElement,"a")){ if(link.innerText != ""){ if(link.href.includes("/title/")) ttext = link.innerText.replaceAll("\n","") if(link.href.includes("/group/")) { if(!gtext.includes(link.innerText.replaceAll("\n",""))){ gtext.push(link.innerText.replaceAll("\n","")) glink.push(link.href) } } } } let gtags = getCN2(daElement,"flex items-center") for(let g of gtags){ if(g.innerText.includes("No Group")){ gtext.push("No Group") glink.push("0/0/0/0/0/0") break } } if(!daModal) createModal() let closebutton = '×' let series = '

SERIES NAME: '+ttext+'

' if(document.URL.includes("/title/")){//1.2 fstatus = getCN(loadedp)[0].firstChild.innerText //following status series+="

Status: "+fstatus.toUpperCase()+"

" let arrayname = getFstatus(fstatus) let temp if(arrayname != "planto") temp = SafeLoad(arrayname) daSeries = temp[FS(temp,id)] } if(daSeries.mu) series+='
🔗 MangaUpdates Link 🔗' if(daSeries.name == "") seriesdex[FS(seriesdex,id)].name = ttext let lastext = daSeries.last let lastvol = "" if(daSeries.lastv) { lastvol = "Vol "+daSeries.lastv lastext = " Ch "+daSeries.last //1.2 } let nextext = daSeries.nextc let nextlink = '' if(!!daSeries.nextl) nextlink = ' href="https://mangadex.org/chapter/'+daSeries.nextl+'"' console.log(lastext) if(daSeries.last == MINNUM || daSeries.last == "-10" || JSON.parse(daSeries.last) == null) { lastext = "Not registered" nextext = "Not registered" } let last = '
Last chapter read: '+lastext+'
' if(daSeries.lastv) last = '
Last chapter read: '+lastvol+''+lastext+'
' if(nextext == MAXNUM) nextext = "Up to date" let next = '
Next chapter: '+nextext+'
' let groups = '

Groups:

' let daTable = ''//1.1.3.3 for(let w=0;w'+gtext[w]+''//1.1.3.3 } daTable+="
NameWhitelistedBlacklisted
" let savebtn = '
' 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 } } 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 } let count = 0 let latabla = getTAG(nodo,"table")[0] //1.2 for(let j of latabla.firstChild.children){ if(j.cells[2].firstChild.checked) count++ } if(count > 1){ alert("There can only be one whitelisted group per series. If you want to block more than one group then you should add them to the blacklist") } else{ for(let x=1; x=0){ seriesdex[i].last = newvalue*1 if(seriesdex[i].last >= seriesdex[i].nextc) DefaultNext(seriesdex[i]) if(document.URL.includes("/title/")){//1.2 if(getCN(loadedp).length){ UpdateSD(getFstatus(getCN(loadedp)[0].firstChild.innerText),seriesdex[i]) } } console.log("seriesdex entry:") console.log(seriesdex[i]) SafeSave("seriesdex",seriesdex) //1.1.3.3 ReloadFF()//1.1.3.3 } else{ if(document.URL.includes("/title/")){ if(getCN(loadedp).length){ let arrayname = getFstatus(getCN(loadedp)[0].firstChild.innerText) let temp = SafeLoad(arrayname) let j = FS(temp,id) temp[j].last = newvalue*1 if(temp[j].nextl && temp[j].nextc <= newvalue*1) DefaultNext(temp[j]) SafeSave(arrayname,temp) } } else console.log("error NewLast") } } if(Number.isNaN(newvalue*1)) alert("Enter a number!") else if(!newvalue){ console.log("cancel by user") } else { console.log("New Last!") newvalue*=1 let i = FS(seriesdex,id) if(newvalue < seriesdex[i].last){ if(confirm("The new value is lower than the last one read, are you sure you want to set it to "+newvalue+"?")) Proceso(newvalue,i) } else{ Proceso(newvalue,i) } } } window.NewLastV = function(event){//1.2 LoadSD() var daElement = event.target.parentElement.parentElement var newvalue = prompt("Enter a new value for last vol","1") var id = getTAG(daElement,"p")[0].id if(Number.isNaN(newvalue*1)) alert("Enter a number!") else if(!newvalue){ console.log("cancel by user") } else { console.log("New LastV!") newvalue*=1 let i = FS(seriesdex,id) if(i >= 0){ seriesdex[i].lastv = newvalue*1 if(seriesdex[i].last >= seriesdex[i].nextc) DefaultNext(seriesdex[i]) if(document.URL.includes("/title/")){//1.2 if(getCN(loadedp).length){ UpdateSD(getFstatus(getCN(loadedp)[0].firstChild.innerText),seriesdex[i]) } } console.log("seriesdex entry:") console.log(seriesdex[i]) SafeSave("seriesdex",seriesdex) //1.1.3.3 } else{ if(document.URL.includes("/title/")){ if(getCN(loadedp).length){ let arrayname = getFstatus(getCN(loadedp)[0].firstChild.innerText) let temp = SafeLoad(arrayname) let j = FS(temp,id) temp[j].lastv = newvalue if(temp[j].nextv && temp[j].nextv < newvalue) DefaultNext(temp[j]) SafeSave(arrayname,temp) } } else console.log("error NewLastV") } ReloadFF()//1.1.3.3 } } window.ReloadFF = function(){ main() //FollowsFeed() NMDFilter(preevent) } window.ShowSD = function(){//1.1.3.3 FollowsFeed() var daModal = document.getElementById("daModal") if(!daModal) createModal() let reading = SafeLoad("reading") let daTable = '' for(let s of seriesdex){ let name = s.name if(name == ""){ let index = FS(reading,s.id) if(index >= 0) name = reading[index].name } if(s.nextc != MAXNUM && s.nextc > s.last+1.1) name+=" ‼️" let lastone = s.last if(lastone < 0 || lastone == null) lastone = '🚫' let nextone, nextlink if(s.nextl == null || s.nextl == "") { nextlink = '' nextone = '🚫' } else { nextlink = ' href="/chapter/'+s.nextl+'"' nextone = 'CH. '+s.nextc } daTable+='' } daTable+="
NameLast ReadNext Chapter
'+name+''+lastone+' '+nextone+'
" let closebutton = '×' daModal.firstChild.innerHTML= closebutton+daTable var closebtn = getCN("close")[0] closebtn.onclick = function() { daModal.style.display = "none" } } window.NewLast2 = function(event){//1.1.3.3 LoadSD() var daElement = event.target while(daElement.tagName != "TR") daElement = daElement.parentElement //1.2 var newvalue = prompt("Enter a new value for last read","1") var id = getTID(daElement) let sid = FS(seriesdex,id) //1.2 if(Number.isNaN(newvalue*1)) alert("Enter a number!") else if(!newvalue){ console.log("cancel by user") } else { console.log("New Last2!") function McCloud(arraynode){//1.2 arraynode.last = newvalue*1 if(arraynode.last >= arraynode.nextc) DefaultNext(arraynode) } McCloud(seriesdex[sid]) console.log(seriesdex[sid]) SafeSave("seriesdex",seriesdex) //1.1.3.3 FollowsFeed() //1.2 let arrays = ["reading","completed","planto","onhold","dropped"] for(let a of arrays){ let temp = SafeLoad(a) let index = FS(temp,seriesdex[sid].id) if(index >= 0){ McCloud(temp[index]) SafeSave(a,temp) } } ShowSD() //1.2 } } window.NewLast3 = function(event){//1.2 LoadSD() var daElement = event.target while(daElement.tagName != "TR") daElement = daElement.parentElement var newvalue = prompt("Enter a new value for last read","1") var id = getTID(daElement) if(Number.isNaN(newvalue*1)) alert("Enter a number!") else if(!newvalue){ console.log("cancel by user") } else { console.log("New Last3!") let stat = getTAG(daElement,"td")[2].innerText let temp = [] let sid = FS(seriesdex,id) let arrayname = getFstatus(stat) //1.2 temp = SafeLoad(arrayname) let tid = FS(temp,id) function UpdateData(array,index){ array[index].last = newvalue*1 if(array[index].last >= array[index].nextc) DefaultNext(array[index]) } if(sid >= 0) { UpdateData(seriesdex,sid) console.log("seriesdex entry:") console.log(seriesdex[sid]) } UpdateData(temp,tid) console.log(arrayname+" entry:") console.log(temp[tid]) SafeSave("seriesdex",seriesdex) //1.1.3.3 SafeSave(arrayname,temp) //1.2 main() //1.2 } } window.FS = function(array,number){//for debugging FS(array, number) } window.FF = function(){//for debugging FollowsFeed() } //THE MAIN FUNCTION function main(){ let logo = "ml-4 cursor-pointer rounded-full overflow-hidden bg-accent flex items-center justify-center" if(getCN(logo).length && getCN(logo)[0].firstChild.tagName == "IMG"){//is logged LoadSD() frutyloop = false if(document.URL.includes("https://mangadex.org/titles/follows")){ console.log("Script ready") function EsperaBotones(){ try{ let botones = getTAG(getCN("px-6 mb-4 mt-2")[0],"a") } catch(e){ setTimeout(EsperaBotones,500) } } EsperaBotones() 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.") Llenar2() } function NewButton(){//moved - 1.2 try{ let newb = document.createElement("button") newb.innerHTML = '' if(!document.getElementById("fill-btn")) getCN("controls mb-auto ml-auto")[0].appendChild(newb) let titulo = getCN("flex items-center mb-4")[0] let dl = cloneDOM('div',titulo)//document.createElement("div") dl.id="dlbtn" dl.innerHTML='' if(!!!document.getElementById("dlbtn") && !!dl) titulo.insertAdjacentElement('afterend',dl) } catch(e){ setTimeout(NewButton,500) } } if(!document.getElementById("dlbtn")) NewButton() } if(document.URL.includes("https://mangadex.org/titles/feed")){ console.log("checking feed") function ScriptForm(){//moved - 1.2 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(getCN(options_loc).length){ var newButton = newInner("div","",'') getCN(options_loc)[0].append(newButton.children[0]) console.log("form added") } else setTimeout(ScriptForm,500) } } follows = [] ScriptForm() if(getCN(feedone).length) FollowsFeed() else setTimeout(main,2000) } if(document.URL.includes("https://mangadex.org/title/")){ console.log("Checking a series") var fstatus whitelist = SafeLoad("whitelist") blacklist = SafeLoad("blacklist") var chgrid = "chapter-grid" function UpdatingSeriesData(){ var toConsider = ["Reading","Completed","On Hold","Dropped","Added To Library"] let timestamp = 0 //1.2 let mu = 0 //1.2 fstatus = getCN(loadedp)[0].firstChild.innerText //following status if(getCN(loadedp).length && getCN(chgrid).length){//if page is loaded console.log("loaded") var toProcess = false var id_series = getID3(document.URL)//1.2 //document.URL.split("/")[4] let daIndex = FS(seriesdex,id_series) var daLast = MINNUM if(daIndex >= 0) daLast = seriesdex[daIndex].last var daLastV = null var daNext,daNLink DefNext() var nextvol = MAXNUM var tags = getCN("tag bg-accent") var volChange = getCN("col-span-4") var sus = false let prevvol = null console.log("fstatus: "+fstatus) if(fstatus == ""){ setTimeout(UpdatingSeriesData,500) return } for(let x of getTAG(getCN("readmore")[0],"a")){//1.2 if(x.href.includes("mangaupdates")) mu = x.href.split("=")[1]*1 } function GetChapter(dc,dv){//1.2 let current if(dc.innerText.toLowerCase().includes("oneshot")) current = 0 //1.1.3.3 else if(dc.innerText.includes("Ch.")) current = GetNumero(dc.innerText) else { let turkey = dc.parentElement while(!turkey.innerText.includes("Chapter ") && turkey != dv) turkey = turkey.parentElement if(turkey.innerText.includes("Volume ")) current = 0 else current = GetNumero(turkey.innerText) } return current } function DefNext(){//1.2 daNext = MAXNUM daNLink = null } if(!sus){ function getVol(txt){ let temp = txt.replaceAll("\n"," ").replaceAll("\t"," ") for(let t of temp.split(" ")){ if(Number.isFinite(t*1)) return t*1 } return 0 } for(let v of document.getElementsByClassName("grid grid-cols-12 volume-head mb-2")){ if(v.innerText.includes("No Volume")){ console.log("volume sorting doesn't apply!") break } if((v.innerText.includes("Ch. 1 -") || v.innerText.includes("Ch. 0 -")) && getVol(v.innerText) > 1){ console.log("SUS!") sus = true break } } } function Apoo(){ if(toConsider.includes(fstatus)){//(fstatus == "Reading"){ console.log("reading series:") console.log(seriesdex[daIndex]) toProcess = true let continuar = true //1.2 function DefaultProcess(dv,dc,current,currvol){//1.2 let cid = getTID(dc) if(forbidden.includes(cid)){//if chapter is marked as forbidden console.log("forbidden chapter "+cid) if(GetChapter(dc,dv) > seriesdex[daIndex].last) getTAG(dc,"svg")[0].style.color = "red" else{ if(getTAG(dc,"svg")[0].style.color) getTAG(dc,"svg")[0].style.removeProperty("color") CleanFB(dc) } if(seriesdex[daIndex].nextl == cid) { DefaultNext(seriesdex[daIndex]) //if it's stored as next one, ignore it } } else if((!HideThis(id_series,getGID(dc)) || OnlyThis(id_series,getGID(dc))==2) && OnlyThis(id_series,getGID(dc))!=1 && !HasBeenRead(dc) && daNext >= current && daNext > daLast && current > daLast){ daNext = current console.log("daNext: "+daNext) daNLink = cid//getTID(dc) console.log("daNLink: "+daNLink) } else if((HideThis(id_series,getGID(dc)) || OnlyThis(id_series,getGID(dc))==1) && !HasBeenRead(dc)){// && daNext > current && daNext > daLast){//not consider if it's blacklisted if(daNext >= current && daNext > daLast && current > daLast){//1.2 FBPush(cid) } if(current <= daLast){ //check for a forbidden chapter that can be ignored console.log(`ignore ${cid} for forbidden`) CleanFB(dc) } if(daIndex >= 0 && cid == seriesdex[daIndex].nextl){//ignores a next chapter if it's blacklisted console.log("reseting daNext") DefNext() } } //1.1.3.3 else if(!(HideThis(id_series,getGID(dc)) || OnlyThis(id_series,getGID(dc))==1) && HasBeenRead(dc) && daLast < current) { daLast = current let thistmp = (new Date(getTAG(dc,"time")[0].dateTime)).getTime() if(thistmp > timestamp) timestamp = thistmp if(daNext <= daLast) { DefNext() } console.log("found a last one: "+daLast) } else { console.log(`${cid} shouldn't be forbidden`) CleanFB(dc) } } function VolProcess(dv,dc,current,currvol){//1.2 function ASSign(){ daNext = current console.log("daNext: vol "+currvol+" chap "+daNext) daNLink = getTID(dc) console.log("daNLink: "+daNLink) } function FoundLast(){ daLast = current let thistmp = (new Date(getTAG(dc,"time")[0].dateTime)).getTime() if(thistmp > timestamp) timestamp = thistmp if(daNext <= daLast) DefNext() console.log("found a last one: "+daLast) } if(HasBeenRead(dc)){ console.log("sus checking vol "+GetNumero(dv.parentElement.innerText)+" ch "+current) if(currvol > daLastV){ daLastV = currvol FoundLast() } else if(currvol == daLastV){ if(daLast < current) FoundLast() } //currvol < daLastV are irrelevant } else{//unread chapters let cid = getTID(dc) if((!HideThis(id_series,getGID(dc)) || OnlyThis(id_series,getGID(dc))==2) && OnlyThis(id_series,getGID(dc))!=1){//to consider if(daLastV == currvol && daNext >= current && daNext > daLast) ASSign() else if(daLastV < currvol && nextvol >= daLastV){ if(nextvol > currvol) { nextvol = currvol ASSign() } else if(nextvol == currvol) ASSign() } } else if((HideThis(id_series,getGID(dc)) || OnlyThis(id_series,getGID(dc))==1)){// && daNext > current && daNext > daLast){//not consider if it's blacklisted if(daNext >= current && daNext > daLast){//1.2 FBPush(cid) if(daIndex >= 0 && cid == seriesdex[daIndex].nextl){//ignores a next chapter if it's blacklisted console.log("reseting daNext") DefNext() } } if(current < daLast) { console.log(`${cid} can be ignored (sus)`) CleanFB(dc) dc.style.removeProperty("color") } } } } for(let dv of getCN("rounded flex flex-col gap-2")){ for(let dc of getCN2(dv,chgrid)){ let current = GetChapter(dc,dv) let currvol = GetNumero(dv.parentElement.innerText) //1.2 if(sus) VolProcess(dv,dc,current,currvol) else DefaultProcess(dv,dc,current,currvol) //1.2 } } return true } return false } function UpdateStorage(obj,item){//1.1.3.3 let temp = SafeLoad(item) //1.2 let index = FS(temp,obj.id) if(index >= 0){//1.2 console.log("it's part of "+item) console.log(obj) if(obj.name == "MangaDex") obj.name = temp[index].name if(obj.last >= temp[index].last){ console.log("new last is equal or greater than last registered") console.log("old: "+temp[index].last) console.log("new: "+obj.last) if(obj.lastv == temp[index].lastv) { temp[index] = obj console.log("same volume, new chapter") } if(obj.lastv && temp[index].lastv && obj.lastv >= temp[index].lastv) { temp[index] = obj console.log("new volume") } if(!obj.lastv && temp[index].lastv){ temp[index] = obj console.log("was stored as volume but it shouldn't") } if(!temp[index].lastv){ temp[index] = obj if(obj.lastv) console.log("now consider with volume sorting") else console.log("no volume sorting") } } else{ console.log("new last is lower than last registered, checking for volume sorting") if(temp[index].lastv && obj.lastv && temp[index].lastv <= obj.lastv) { temp[index] = obj console.log("new volume") } if(!temp[index].nextv && obj.nextv) { temp[index] = obj console.log("new chapter") } if(temp[index].nextv && obj.nextv && temp[index].nextv < obj.nextv) { temp[index] = obj console.log("new unread chapter on new volume") } if(obj.nextl && temp[index].last < obj.nextc){ temp[index].nextc = obj.nextc temp[index].nextl = obj.nextl console.log("new unread chapter but earlier last read") } if(!obj.nextl){ temp[index].nextc = obj.nextc temp[index].nextl = obj.nextl console.log("no next unread chapter") } if(obj.mu && !temp[index].mu){ temp[index].mu = obj.mu console.log("added mangaupdates link") } if(!temp[index].time && obj.time){ temp[index].time = obj.time console.log("added update time") } } RevisaNext(temp[index]) } else{//if(index == -1) temp.push(obj) console.log("added to "+item+"!") } SafeSave(item,temp) console.log("stored changes in "+item+"!") console.log(temp[index]) console.log("index: "+index) // return temp[index] //1.2 } var removedsd = false function RemoveFromSD(mangaid){//1.1.3.3 removedsd = false let index = FS(seriesdex,mangaid) if(index >= 0) { console.log("removed from seriesdex:") console.log(seriesdex[index]) seriesdex.splice(index,1) SafeSave("seriesdex",seriesdex) removedsd = true } } function Registrar(){ //1.1.3.3 let manga let marked = false if(sus) manga = {id:id_series, mu:mu, name:document.title.replace(" - MangaDex",""), last:daLast, lastv: daLastV, nextv:nextvol, nextc:daNext, nextl:daNLink, time:timestamp} else manga = {id:id_series, mu:mu, name:document.title.replace(" - MangaDex",""), last:daLast, nextc:daNext, nextl:daNLink, time:timestamp} let campana = (getTAG(getCN("sm:ml-2")[0],"svg")[0].firstChild.getAttribute("d") == "M18 8C18 6.4087 17.3679 4.88258 16.2426 3.75736C15.1174 2.63214 13.5913 2 12 2C10.4087 2 8.88258 2.63214 7.75736 3.75736C6.63214 4.88258 6 6.4087 6 8C6 15 3 17 3 17H12") let blink = getFstatus(fstatus) UpdateStorage(manga,blink) if(daIndex >= 0) { // LoadSD() CompareSD(blink,seriesdex[daIndex]) //1.2 } if(campana) { UpdateStorage(manga,"seriesdex") } else marked = true if(marked) RemoveFromSD(manga.id) //Delete duplicates //1.2 console.log("Checking for duplicates") for(let c of ["Completed","Plan to Read","On Hold","Dropped","Reading"]){ if(c != fstatus){ let namevar = getFstatus(c) if(namevar){ console.log("Checking "+namevar) let temp = SafeLoad(namevar) //1.2 let index = FS(temp,id_series) if(index >= 0){ console.log("Duplicated in "+namevar) console.log(temp[index]) temp.splice(index,1) SafeSave(namevar,temp) console.log("Deleted from "+namevar) } } } } console.log("reference:") console.log(manga) console.log("the one registered in "+fstatus+":") let final = SafeLoad(blink) let k = FS(final,id_series) console.log(final[k]) return true } function LoadWBS(){ let ww = getCN("flex gap-x-2")[0] let newbtn = cloneDOM("div",ww) newbtn.id="FilterG" newbtn.innerHTML = '' if(!document.getElementById("FilterG")) ww.parentElement.insertBefore(newbtn,ww) createModal() } if(Apoo() && daIndex >= 0){ LoadWBS() if(seriesdex[daIndex].name != document.title.replace(" - MangaDex","") && document.title != "MangaDex") seriesdex[daIndex].name = document.title.replace(" - MangaDex","") console.log("previous last: "+seriesdex[daIndex].last) console.log("updating values") if(Registrar() && !removedsd) console.log("new last: "+seriesdex[daIndex].last) } else if(daIndex >= 0){//fixes bug that adds everything if(!toConsider.includes(fstatus)) seriesdex.splice(daIndex,1)//1.1.3.2 SafeSave("seriesdex",seriesdex)//1.1.3.3 } else if(daIndex == -1 && toProcess){//not registered if(fstatus == "Reading") console.log("new series!")//1.1.3.3 Registrar() LoadWBS() } if(FS(seriesdex,id_series) >= 0) { LoadWBS() console.log("seriesdex entry:") console.log(seriesdex[FS(seriesdex,id_series)]) } } else if(getCN("text-center").length && getCN("text-center")[0].innerText == "No Chapters"){ console.log("no chapters!") let daIndex = FS(seriesdex,getID3(document.URL)) for(let x of getTAG(getCN("readmore")[0],"a")){//1.2 if(x.href.includes("mangaupdates")) { mu = x.href.split("=")[1]*1 console.log("mu: "+mu) } } function LoadWBS(){//1.2 let ww = getCN("text-center")[0].parentElement let newbtn = cloneDOM("div",ww) newbtn.id="FilterG" newbtn.innerHTML = '' if(!document.getElementById("FilterG")) ww.parentElement.insertBefore(newbtn,ww) createModal() } function Empty(){//1.2 console.log("Empty()") let temp = {id: getID3(document.URL),mu:mu,name: document.title.replace(" - MangaDex",""),last: MINNUM,nextc: MAXNUM,nextl: null, time:timestamp} function UpdateEmpty(arrayname,obj){ console.log("mu ue "+arrayname+": "+mu) console.log("reference data:") console.log(obj) let dummy = SafeLoad(arrayname) let index = FS(dummy,obj.id) dummy[index].mu = mu obj.mu = mu if(!obj.time && dummy[index].time) obj.time = dummy[index].time if(index >= 0) { console.log(arrayname+" data:") console.log(dummy[index]) if(dummy[index].last < 0 && dummy[index].nextl == null) dummy[index] = obj //else it has previous data } else dummy.push(obj) SafeSave(arrayname,dummy) console.log("new data ("+arrayname+"):") console.log(dummy[index]) } if(fstatus == "Reading") { UpdateEmpty("reading",temp) UpdateEmpty("seriesdex",temp) if(daIndex >= 0) CompareSD("reading",seriesdex[daIndex]) } else if(fstatus == "On Hold") { UpdateEmpty("onhold",temp) if(daIndex >= 0) CompareSD("onhold",seriesdex[daIndex]) } else if(fstatus == "Dropped") { UpdateEmpty("dropped",temp) if(daIndex >= 0) CompareSD("dropped",seriesdex[daIndex]) } } if(getCN("w-full").length){ for(let f of getCN("w-full")){ if(fstatus == "Completed" && f.innerText.includes("Final Chapter")){ let completed = SafeLoad("completed") let temp = {id: getID3(document.URL),mu:mu,name: document.title.replace(" - MangaDex",""),last: GetNumero(f.innerText), time:timestamp} let index = FS(completed,temp.id) if(index >= 0) completed[index] = temp else completed.push(temp) SafeSave("completed",completed) console.log("new data (completed):") console.log(temp) if(FS(seriesdex,temp.id) >= 0){ seriesdex.splice(FS(seriesdex,temp.id),1) console.log("removed from seriesdex!") SafeSave("seriesdex",seriesdex) } } } Empty() //1.2 } else if(toConsider.includes(fstatus)){//1.1.3.3 Empty() //1.2 } LoadWBS() //1.2 } else setTimeout(UpdatingSeriesData,500) } try{ UpdatingSeriesData() } catch(e){ console.log("catch UpdatingSeriesData") setTimeout(UpdatingSeriesData,1000) } } if(document.URL.includes("https://mangadex.org/chapter/")){//1.2 if(!titlepage) titlepage = getTAG(getCN("menu flex-col")[0],"a")[0].href let nextlink = null let menuclass = "menu flex flex-col gap-2 bg-background p-4"//"menu flex flex-col gap-2 bg-background p-4 open pinned" if(getCN(menuclass)[0].children[4].children[2].href) nextlink = getCN(menuclass)[0].children[4].children[2].href if(nextlink && forbidden.includes(getTID(nextlink))){//it's a blacklisted chapter if(getCN("md--pages")[0].firstChild.childElementCount == document.URL.split("/")[5]*1){//last page alert("Next chapter is blacklisted. Don't click it if you don't want to read it. Ctrl+M to go to title page.") } } if(forbidden.includes(getID3(document.URL))){ console.log("FORBIDDEN!!") window.location.href = titlepage } } if(document.URL.includes("https://mangadex.org/user/me")){//1.2 function DisplayTabla(){ if(getCN("select__tab-active")[0].innerText == "Info"){ let com = SafeLoad("completed") let ptr = SafeLoad("planto") let dro = SafeLoad("dropped") let rea = SafeLoad("reading") let onh = SafeLoad("onhold") let daTable = 'NameMU LinkStatusLast ReadNextLast Update' function LlenarTabla(array,stat){ for(let a of array){ let mulink = '' let mubody = '🚫' if(a.mu){ mulink = ' href="https://www.mangaupdates.com/series.html?id='+a.mu+'"' mubody = '🔗' } let stamp = '⚠️' if(a.time) stamp = (new Date(a.time)).toLocaleDateString() let lastone = '🚫' if(JSON.parse(a.last) != null && a.last > MINNUM) { if(!a.lastv) lastone = a.last else lastone = "v"+a.lastv+"c"+a.last } let nextone = '🚫' let nextlink = '' if(a.nextl){ nextone = a.nextc if(a.nextv) nextone = "v"+a.nextv+"c"+a.nextc nextlink = ' href="/chapter/'+a.nextl+'"' } let bell = '🔕' if(FS(seriesdex,a.id) >= 0) bell = '🔔 ' daTable+='",'\>')+'">'+bell+a.name+''+mubody+''+stat+'
'+lastone+'
'+nextone+''+stamp+'' } } LlenarTabla(rea,"Reading") LlenarTabla(onh,"On Hold") LlenarTabla(dro,"Dropped") LlenarTabla(ptr,"Plan to Read") LlenarTabla(com,"Completed") let divTabla = newInner("table","table",daTable) divTabla.id = "divTabla" divTabla.style.display = "grid" if(!document.getElementById("divTabla")){ let target = null if(getCN("px-6 page-container").length) target = getCN("px-6 page-container")[0].parentElement.parentElement if(target) target.append(divTabla) else setTimeout(target.append(divTabla),500) } else document.getElementById("divTabla").innerHTML = daTable } } DisplayTabla() } } else setTimeout(main,5000) } document.addEventListener('keydown', function(event) { if(document.URL.includes("/chapter/") && event.ctrlKey && (event.key === 'm' || event.key === 'M')){ window.location.href = titlepage } }); //EXPORT FUNCTIONS 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 = [] let reading = SafeLoad("reading") let planto = SafeLoad("planto") let onhold = SafeLoad("onhold") let dropped = SafeLoad("dropped") let completed = SafeLoad("completed") function Processing(arrayy,naame){ for(let a of arrayy){ let last,daTime 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 if(a.time) daTime = new Date(a.time).toLocaleString() else daTime = "unregistered" } else { last = a.last daTime = a.time } temp.push({id:a.id,mu:a.mu,name:a.name,state:naame,last:last, time:(new Date(a.time).toLocaleString())}) if(temp.length == 0) temp = [{id:a.id,mu:a.mu,name:a.name,state:naame,last:last, time:(new Date(a.time).toLocaleString())}] } } if(reading.length+planto.length+onhold.length+dropped.length+completed.length){ Processing(reading,"Reading") Processing(onhold,"On Hold") Processing(planto,"Plan to Read") Processing(dropped,"Dropped") Processing(completed,"Completed") return temp } else{ alert("There's no data. Please press the FILL button to collect the data") return null } } window.DownloadCSV = function(){ exportToCsvFile(PrepareData(true)) } window.DownloadJSON = function(){ exportToJsonFile(PrepareData(false)) } document.onscroll = function(){ 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 && !filling) setTimeout(main,500) trigger = false } }