Greasy Fork

New MangaDex Follows

Manage your follows

目前为 2021-11-03 提交的版本。查看 最新版本

// ==UserScript==
// @name         New MangaDex Follows
// @namespace    https://greasyfork.org/scripts/430295-new-mangadex-follows
// @version      1.1.3.2
// @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){
    let skip = false
    for(let t of text.split(" ")){
        //console.log(t)
        if(t == "Vol.") skip = true
        if((t*1)>0) {
            //console.log("number: "+t)
            if(skip){
                skip = false
            }
            else return t*1
        }
    }
    console.log("no number found")
    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)
    if(document.URL.includes("/title/")) id = getID3(document.URL)
    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(document.URL.includes("/title/")) ttext = document.getElementsByClassName("mb-1")[0].innerText
    if(!daModal) createModal()
    let closebutton = '<span class="close">&times;</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: '+lastext+'</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){
        console.log("hide this!")
        return true
    }
    return false
}

function OnlyThis(array,series,group){
    if(array.findIndex(q => q[0] == series && q[1] == group) >= 0) { //the series is listed with this group
        console.log("only this case 2: listed!!")
        return 2
    }
    if(array.findIndex(q => q[0] == series && q[1] != group) >= 0) { //the series is listed but not this group
        console.log("only this case 1: listed but not this one")
        return 1
    }
    if(array.findIndex(q => q[0] == series && q[1] == group) < 0) { //it's not there
        console.log("only this case 0: not here")
        return 0
    }
    console.log("only this case 3: not listed")
    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,batchi,id_series){//todo: fix syntaxis to consider every scenario
    if(filter){
        var icono,newdiv
        var groupclass = "md:col-span-2"
        var externals = "flex items-center"
        var groupflex = batchi.getElementsByClassName(groupclass)[0] //get the groups of this chapters
        if(!groupflex) groupflex = batchi.getElementsByClassName(externals)[1] //external chapters
        console.log(groupflex)
        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
                return 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
                wl = true
                return true
            }
            else{
                process += true
            }
            return process
        }
        try{
            for(let z=1; z<groupflex.children.length; z++){
                process = GFP(groupflex,z,process,/*batch,i,*/id_series)
                if(!process) {
                    console.log("break!!")
                    break
                }
            }
            if(groupflex.children.length == 1) process = GFP(groupflex,0,process,/*batch,i,*/id_series)
            return process
        }
        catch(e){
            console.log("groupflex error")
            console.log(e)
            console.log(batchi)
            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])
        }
        else{
            seriesdex[pseries].nextc = 10000
            seriesdex[pseries].nextl = null
        }
        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-2"//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)
                else{
                    if(seriesdex[i].last == null) seriesdex[i].last = -10
                    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 = -10
                        }
                    }
                }
            }
            let rep = 0
            do{//1.1.3.2
                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

                        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
                            for(let i=0; i<batch.length; i++){
                                var name = batch[i].getElementsByTagName("a")[0].innerText.replace("\n"," ")
                                console.log("processing "+name)
                                var current = GetNumero(name)//name.split(" ")[1]*1
                                var vol = GetVol(name)
                                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(!!seriesdex[pseries].lastV && vol){//1.1.3.2
                                            if(vol == seriesdex[pseries].lastV+1 || (vol == seriesdex[pseries].lastV && last < current && nextc > last && nextc > current)){
                                                nextc = current
                                                nextl = batch[i].getElementsByTagName("a")[0].href.split("chapter/")[1]
                                                console.log("new nextc: "+nextc)
                                            }
                                        }
                                        else if(last < current && nextc > last && nextc > current){
                                            nextc = current
                                            nextl = batch[i].getElementsByTagName("a")[0].href.split("chapter/")[1]
                                            console.log("new nextc: "+nextc)
                                        }
                                    }
                                    else if(HasBeenRead(batch[i])){
                                        if(last < current) last = current
                                    }
                                    if(filter) InverseIt(batch[i].getElementsByTagName("a")[0].parentElement)
                                }
                                else{//has to be hidden
                                    console.log("not to process")
                                    console.log(batch[i])
                                    console.log(seriesdex[pseries])
                                    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)
                    }
                }
            }while(rep++ < 1)

//             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
//                     console.log("newest: "+newest)
//                 }
//                 for(let a of avail){
//                     //if(!a.getElementsByClassName("continue").length){
//                         let elem = a.getElementsByTagName("a")[0]
//                         let disONE = GetNumero(elem.innerText)//.replace("\n"," ").split(" ")[1]*1
//                         let process = ProcessGroups(false,a,id_series)
//                         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(process && disONE > lastest && !unread) lastest = disONE
//                         if(process && 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
//                     console.log("new nextc:: "+newest)
//                 }
//                 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]
                let fbtn_container = cloneDOM("a",titu)
                fbtn_container.innerHTML = ""
                fbtn_container.removeAttribute("href")
                fbtn_container.append(fbtn)
                fbtn_container.style.display = "block"
                //fbtn_container.style.float = "right"
                if(filter && !!!l.getElementsByClassName("nmf-btn").length) {
                    titu.parentElement.insertBefore(fbtn_container,titu)
                    titu.style.width = "95%"
                }
                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 && daONE.nextc != 1) extrainfo = " (WARNING: no previous info)"
                        if(daONE.last == -10 && daONE.nextc == 1) extrainfo = " (Start reading!)"//1.1.3.2
                        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 == "") || daONE.last >= daONE.nextc) && l.getElementsByClassName("continue")[0] != undefined){
                        l.getElementsByClassName("continue")[0].parentElement.remove()
                        if(daONE.last >= daONE.nextc){//1.1.3.2
                            daONE.nextc = 10000
                            daONE.nextl = null
                        }
                    }
                }
            }

            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{
        let newb = document.createElement("button")
        newb.innerHTML = '<button id="fill-btn" data-v-621772ff="" type="button" class="bg-primary 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)

        let titulo = document.getElementsByClassName("flex items-center mb-4")[0]
        let dl = cloneDOM('div',titulo)//document.createElement("div")
        dl.id="dlbtn"
        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()" style="margin-left: 0.5rem;margin-right: 1rem;background-color: var(--md-primary);border-width: 0.5rem;border-color: var(--md-primary);">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()" style="margin-left: 0.5rem;margin-right: 1rem;background-color: var(--md-primary);border-width: 0.5rem;border-color: var(--md-primary);">Download JSON</button>'
        titulo.insertAdjacentElement('afterend',dl)
    }
    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 temp_r){
                if(FS(seriesdex,r.id) == -1) seriesdex.push(r)
            }

            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
                }
            }

            for(let i = seriesdex.length-1; i >= 0; i--){
                Copiar(temp_c, seriesdex[i])
                Copiar(temp_o, seriesdex[i])
                Copiar(temp_r, seriesdex[i])
                Copiar(temp_d, seriesdex[i])
                //Copiar(temp_d, seriesdex[i])
            }

            function UpdateArrays(old,array){
                for(let a of array){
                    let indice = FS(old,a.id)
                    if(indice >= 0 && old[indice].last > a.last) {
                        a.last = old[indice].last
                        a.nextc = old[indice].nextc
                        a.nextl = old[indice].nextl
                    }
                }
                return array
            }

            temp_r = UpdateArrays(oldr,temp_r)
            temp_p = UpdateArrays(oldp,temp_p)
            temp_o = UpdateArrays(oldo,temp_o)
            temp_d = UpdateArrays(oldd,temp_d)
            temp_c = UpdateArrays(oldc,temp_c)

            localStorage.setItem("reading",JSON.stringify(temp_r))
            localStorage.setItem("planto",JSON.stringify(temp_p))
            localStorage.setItem("onhold",JSON.stringify(temp_o))
            localStorage.setItem("dropped",JSON.stringify(temp_d))
            localStorage.setItem("completed",JSON.stringify(temp_c))
            alert("Done!")
        // }
    }
    catch(e){
        console.log("error filling titles")
        console.log(e)
    }
}

function GetNumero2(text){
    let skip = false
    let condition = [text]
    console.log(text)
    if(text.includes(" ")) condition = text.split(" ")
    for(let t of condition){
        //console.log(t)
        if(t == "Vol.") skip = true
        if((t*1)>0) {
            //console.log("number: "+t)
            if(skip){
                skip = false
            }
            else return t*1
        }
    }
    console.log("no number found")
    return NaN
}

function DefaultObj(){
    return {id:0,name:"",last:-10,nextc:10000,nextl:null}
}

function Llenar2(){//1.1.3.2
    function Walala(){
        console.log("walala")
        let items = document.getElementsByClassName("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(){
            //console.log("primero")
            try{
                for(let i of items){
                    manga = DefaultObj()
                    manga.id = getID(i)
                    manga.name = i.firstChild.innerText
                    if(FS(temp,manga.id) < 0) temp.push(manga)
                }
                //console.log(temp)
                ClickSiguiente()
            }
            catch(e){
                console.log("catch primero")
                console.log(e)
                /*catchcount++
        if(catchcount < 20) */setTimeout(Primero,500)
            }
            //console.log("fin primero")
        }

        function ClickSiguiente(){
            //console.log("click siguiente")
            try{
                let pagination = document.getElementsByClassName("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){
                    //console.log("for pagination")
                    if(p.className.includes("bg-primary")) actual = p.innerText*1
                    if(!!actual && p.innerText*1 == actual+1) {
                        //if(confirm("Siguiente")){
                        p.click()
                        Segundo()
                        //}
                    }
                    if(!!actual && actual == final) {
                        //if(confirm("Next Tab")){
                        NextTab()
                        return temp
                        //}
                    }
                }
            }
            catch(e){
                if(!document.getElementsByClassName("flex justify-center flex-wrap gap-2 my-6")[0]){
                    console.log("no pagination")
                    NextTab()
                    return temp
                }
            }
        }

        function Segundo(){
            //console.log("segundo")
            try{
                let items = document.getElementsByClassName("manga-card bg-accent")
                let dummy = DefaultObj()
                dummy.id = getID(items[0])
                dummy.name = items[0].firstChild.innerText
                if(FS(temp,dummy.id)>=0) {
                    //console.log("esperando nuevos")
                    setTimeout(Segundo,500)
                }
                else Primero()
            }
            catch(e){
                console.log("catch segundo")
                console.log(e)
                /*catchcount++
        if(catchcount < 20) */setTimeout(Segundo,5000)
            }
            //console.log("fin segundo")
        }

        WaitElement(items)

        return temp
    }
    var tabs = document.getElementsByClassName("select__tab")
    console.log(tabs)
    let firsttab = document.getElementsByClassName("select__tab")[0]
    if(!firsttab.className.includes("active")) firsttab.click()
    function NextTab(){
        console.log("next tab")
        for(let x=0; x<tabs.length; x++){
            if(tabs[x].className.includes("active")){
                if(x+1 < tabs.length){
                    tabs[x+1].click()
                    setTimeout(Unbelievable,3000)
                }
                else{
                    console.log("End of loading mangas")
                    FillTitles()
                }
            }
        }
    }
    function Unbelievable(){
        console.log("unbelievable")
        try{
            document.getElementsByClassName("flex justify-center flex-wrap gap-2 my-6")[0].children[0].click()
        }
        catch(e){
            console.log("no pagination")
        }
        for(let t of tabs){
            if(t.className.includes("tab-active")){
                console.log("checking active tab")
                if(t.innerText == "Reading") {
                    console.log(t.innerText)
                    temp_r = Walala()
                    console.log("temp_r:")
                    console.log(temp_r)
                    //NextTab()
                }
                if(t.innerText == "Plan To Read") {
                    console.log(t.innerText)
                    temp_p = Walala()
                    console.log("temp_p:")
                    console.log(temp_p)
                    //NextTab()
                }
                if(t.innerText == "Completed") {
                    console.log(t.innerText)
                    temp_c = Walala()
                    console.log("temp_c:")
                    console.log(temp_c)
                    //NextTab()
                }
                if(t.innerText == "On Hold") {
                    console.log(t.innerText)
                    temp_o = Walala()
                    console.log("temp_o:")
                    console.log(temp_o)
                    //NextTab()
                }
                if(t.innerText == "Re-reading"){
                    console.log(t.innerText)
                    console.log("who gives a shit lol")
                    NextTab()
                }
                if(t.innerText == "Dropped") {
                    console.log(t.innerText)
                    temp_d = Walala()
                    console.log("temp_d:")
                    console.log(temp_d)
                    //NextTab()
                    console.log("END!!")
                }
            }
        }
    }

    Unbelievable()
}

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/follows")){
            console.log("Script ready")

            function EsperaBotones(){
                try{
                    botones = document.getElementsByClassName("px-6 mb-4 mt-2")[0].getElementsByTagName("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()
            }

            if(!document.getElementById("dlbtn")) 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 && document.getElementsByClassName("chapter-grid").length){//if page is loaded
                    console.log("loaded")
                    var toProcess = false
                    var id_series = document.URL.split("/")[4]
                    let daIndex = FS(seriesdex,id_series)
                    var daLast = -10
                    var daLastV = null
                    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(!daLastV) daLastV = GetNumero(dv.parentElement.innerText.replaceAll("\n"," "))//1.1.3.2
                                        if(current < lastup) lastup = current
                                        else {
                                            console.log("break")
                                            return
                                        }
                                    }
                                    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
                                        if(daIndex >= 0 && getID(dc) == seriesdex[daIndex].nextl){//ignores a next chapter if it's blacklisted
                                            console.log("reseting daNext")
                                            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()
                    if(daIndex >= 0){
                        let ww = document.getElementsByClassName("flex gap-x-2")[0]
                        let newbtn = cloneDOM("div",ww)
                        newbtn.id="FilterG"
                        newbtn.innerHTML = '<button data-v-cae07f5c="" data-v-4e000227="" class="rounded relative md-btn flex items-center" style="min-height: 48px; min-width: 220px;" onclick="NMDFilter(event)"><!----> <span data-v-cae07f5c="" class="flex items-center justify-center font-medium select-none" style="pointer-events: none;"><!---->WHITE/BLACKLIST GROUPS HERE</span></button>'
                        if(!document.getElementById("FilterG")) ww.parentElement.insertBefore(newbtn,ww)
                        createModal()
                        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].last = daLast
                        if(sus) seriesdex[daIndex].lastv = daLastV //1.1.3.2
                        console.log("updating values")
                        seriesdex[daIndex].nextc = daNext
                        seriesdex[daIndex].nextl = daNLink
                        console.log("new last: "+seriesdex[daIndex].last)
                    }
                    else {
                        if(toProcess){//not registered
                            console.log("new series!")
                            if(sus) seriesdex.push({id:id_series, name:document.title.replace(" - MangaDex",""), last:daLast, lastv: daLastV, nextc:daNext, nextl:daNLink})
                            else seriesdex.push({id:id_series, name:document.title.replace(" - MangaDex",""), last:daLast, nextc:daNext, nextl:daNLink})
                        }
                        else{//fixes bug that adds everything
                            if(!toConsider.includes(fstatus)) seriesdex.splice(daIndex,1)//1.1.3.2
                        }
                    }
                    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}]
        }
    }

    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.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
    }
    let count = 0
    for(let j of nodo.children[5].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<nodo.children[5].firstChild.childElementCount; x++){
            let gid = nodo.children[5].firstChild.children[x].cells[1].innerText
            let wl = JSON.parse(nodo.children[5].firstChild.children[x].cells[2].firstChild.checked)
            let bl = JSON.parse(nodo.children[5].firstChild.children[x].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)
        }
    }
}