// ==UserScript==
// @name New MangaDex Follows
// @namespace https://greasyfork.org/scripts/430295-new-mangadex-follows
// @version 1.1.3.3
// @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"))
}
LoadSD()
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","",'📜 SCRIPT SETTINGS ')
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(){
//1.1.3.3
let ischecked = ""
if(filter) ischecked = " checked"
var daModal = document.getElementById("daModal")
if(!daModal) createModal()
let closebutton = '× '
let body = '
New MangaDex Follows Script Settings Filter by groupsYou 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.
Save Changes Exit '
let series = 'Check unread chapters Check follows list '
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"
}
var unchecked = true
var preevent = null
window.NMDFilter = function(event){
var daElement = event.target.parentElement.parentElement
preevent = event //1.1.3.3
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 = '× '
let series = 'SERIES NAME: '+ttext+'
'
if(daSeries.name == "") seriesdex[FS(seriesdex,id)].name = ttext
let lastext = daSeries.last
let nextext = daSeries.nextc
let nextlink = ''
if(!!daSeries.nextl) nextlink = ' href="https://mangadex.org/chapter/'+daSeries.nextl+'"'
if(lastext == -10 || lastext == "-10") {
lastext = "Not registered"
nextext = "Not registered"
}
let last = 'Last chapter read: '+lastext+' ✍️
'
if(nextext == 10000) nextext = "Up to date"
let next = ''
let groups = 'Groups:
'
//let daTable = 'Name ID Whitelisted Blacklisted '
let daTable = '"
let savebtn = 'SAVE CHANGES
'
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.ReloadFF = function(){
main()
//FollowsFeed()
NMDFilter(preevent)
}
window.NewLast = function(event){//1.1.3.3
LoadSD()
var daElement = event.target.parentElement.parentElement
var newvalue = prompt("Enter a new value for last read","1")
var id = daElement.getElementsByTagName("p")[0].id
if(Number.isNaN(newvalue*1)) alert("Enter a number!")
else if(!newvalue){
console.log("cancel by user")
}
else {
console.log("New Last!")
daElement.innerHTML.replace('Last chapter read: '+seriesdex[FS(seriesdex,id)].last,'Last chapter read: '+newvalue)
seriesdex[FS(seriesdex,id)].last = newvalue*1
if(seriesdex[FS(seriesdex,id)].last >= seriesdex[FS(seriesdex,id)].nextc){
seriesdex[FS(seriesdex,id)].nextc = 10000
seriesdex[FS(seriesdex,id)].nextl = null
}
console.log(seriesdex[FS(seriesdex,id)])
localStorage.setItem("seriesdex",JSON.stringify(seriesdex)) //1.1.3.3
//FollowsFeed()
ReloadFF()//1.1.3.3
}
}
function createModal(){
console.log("creating modal")
var modal = newInner("div","modal",'
')
modal.id = "daModal"
var funky = document.getElementById("__layout")
if(!document.getElementById("daModal")) funky.insertBefore(modal,funky.firstChild)
var daStyle = newInner("style","text/css",'.modal {display: none;position: fixed;z-index: 5;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.ReadNext = function(){//1.1.3.3
FollowsFeed()
var daModal = document.getElementById("daModal")
if(!daModal) createModal()
let reading = JSON.parse(localStorage.getItem("reading"))
let daTable = 'Name Unread Chapter '
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+=''+name+' CH. '+s.nextc+' '
}
}
daTable+="
"
let closebutton = '× '
daModal.firstChild.innerHTML= closebutton+daTable
var closebtn = document.getElementsByClassName("close")[0]
closebtn.onclick = function() {
daModal.style.display = "none"
}
}
window.ShowSD = function(){//1.1.3.3
FollowsFeed()
var daModal = document.getElementById("daModal")
if(!daModal) createModal()
let reading = JSON.parse(localStorage.getItem("reading"))
let daTable = 'Name Last Read Next Chapter '
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 != 10000 && 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+=''+name+' '+lastone+' ✍️ '+nextone+' '
}
daTable+="
"
let closebutton = '× '
daModal.firstChild.innerHTML= closebutton+daTable
var closebtn = document.getElementsByClassName("close")[0]
closebtn.onclick = function() {
daModal.style.display = "none"
}
}
window.NewLast2 = function(event){//1.1.3.3
LoadSD()
var daElement = event.target.parentElement.parentElement
var newvalue = prompt("Enter a new value for last read","1")
var id = getID(daElement)
if(Number.isNaN(newvalue*1)) alert("Enter a number!")
else if(!newvalue){
console.log("cancel by user")
}
else {
console.log("New Last!")
daElement.innerHTML = daElement.innerHTML.replace(''+seriesdex[FS(seriesdex,id)].last,''+newvalue)
daElement.innerHTML = daElement.innerHTML.replace('🚫',''+newvalue)
//console.log(daElement.innerHTML)
seriesdex[FS(seriesdex,id)].last = newvalue*1
if(seriesdex[FS(seriesdex,id)].last >= seriesdex[FS(seriesdex,id)].nextc){
seriesdex[FS(seriesdex,id)].nextc = 10000
seriesdex[FS(seriesdex,id)].nextl = null
}
console.log(seriesdex[FS(seriesdex,id)])
localStorage.setItem("seriesdex",JSON.stringify(seriesdex)) //1.1.3.3
FollowsFeed()
//ReloadFF()//1.1.3.3
}
}
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= 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"))
LoadSD()//1.1.3.3
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("/")) {
console.log("bug correction! removing this one:")
console.log(seriesdex[i])
seriesdex.splice(i,1)
}
else{
if(seriesdex[i].last == null) seriesdex[i].last = -10
if(seriesdex[i].nextc == 10000) seriesdex[i].nextl = null
if(seriesdex[i].nextc == null) seriesdex[i].nextc = 10000
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
}
}
if(seriesdex[i].last == seriesdex[i].nextc){
seriesdex[i].nextc = 10000
seriesdex[i].nextl = null
}
}
}
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 = null
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
let prevgid = false
for(let i=0; i current && (name.toLowerCase().includes("extra") || Number.isInteger(current - 0.5) || Number.isInteger(current - 0.9))) batch[i].getElementsByTagName("svg")[0].style.color = "yellow" //1.1.3.3
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 = 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]
prevgid = getGroup(batch[i]) //1.1.3.3
// console.log("new nextc: "+nextc)
}
else if(current == nextc){//1.1.3.3
let gids = getGroup(batch[i])
//if(gids == 0) prevgid = 0
if(prevgid == 0){//give priority to real groups
nextl = batch[i].getElementsByTagName("a")[0].href.split("chapter/")[1]
}
prevgid = gids
}
}
else if(HasBeenRead(batch[i])){
if(batch[i].getElementsByTagName("svg")[0].style.color) batch[i].getElementsByTagName("svg")[0].style.removeProperty("color") //1.1.3.3
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])
let card = l.getElementsByClassName("continue")
if(card.length && card[0].firstChild.href == batch[i].getElementsByTagName("a")[0].href.split("chapter/")[1]){
nextc = 10000
nextl = null
}
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,"CONTINUE to Chapter "+daONE.nextc+extrainfo+" ")
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 = 'FILL '
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='Download CSV Download JSON '
if(!!!document.getElementById("dlbtn") && !!dl) 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 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
}
}
//1.1.3.3
if(!(HideThis(blacklist,id_series,getID2(dc)) || OnlyThis(whitelist,id_series,getID2(dc))==1) && HasBeenRead(dc) && daLast < current) {
daLast = current
if(daNext <= daLast) {
daNext = 10000
daNLink = null
}
console.log("found a last one")
break
}
}
}
return true
}
return false
}
function UpdateStorage(obj,item){//1.1.3.3
let temp = JSON.parse(localStorage.getItem(item))
let index = FS(temp,obj.id)
if(item == "seriesdex") {
if(index >= 0 && obj.last >= temp[index].last) temp[index] = obj
else if(index == -1){
temp.push(obj)
console.log("added to seriesdex!")
}
seriesdex = temp
}
else if(index >= 0){//it's part of array
temp[index] = obj
}
else{//needs to be added
temp.push(obj)
console.log("added!")
}
localStorage.setItem(item,JSON.stringify(temp))
console.log("stored changes in "+item+"!")
}
function Registrar(){ //1.1.3.3
let manga
if(sus) manga = {id:id_series, name:document.title.replace(" - MangaDex",""), last:daLast, lastv: daLastV, nextc:daNext, nextl:daNLink}
else manga = {id:id_series, name:document.title.replace(" - MangaDex",""), last:daLast, nextc:daNext, nextl:daNLink}
if(fstatus == "Completed") UpdateStorage(manga,"completed")
if(fstatus == "Plan to Read") UpdateStorage(manga,"planto")
if(fstatus == "On Hold") UpdateStorage(manga,"onhold")
if(fstatus == "Dropped") UpdateStorage(manga,"dropped")
let campana = (document.getElementsByClassName("sm:ml-2")[0].getElementsByTagName("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")
if(fstatus == "Reading") {
UpdateStorage(manga,"reading")
UpdateStorage(manga,"seriesdex")
}
else if(campana) UpdateStorage(manga,"seriesdex")
else RemoveFromSD(manga.id)
console.log("the one registered in "+fstatus+":")
console.log(manga)
return true
}
if(Apoo() && daIndex >= 0){
let ww = document.getElementsByClassName("flex gap-x-2")[0]
let newbtn = cloneDOM("div",ww)
newbtn.id="FilterG"
newbtn.innerHTML = ' 🔧 WHITE/BLACKLIST GROUPS HERE 🔧 '
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
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
localStorage.setItem("seriesdex",JSON.stringify(seriesdex))//1.1.3.3
}
else if(daIndex == -1 && toProcess){//not registered
if(fstatus == "Reading") console.log("new series!")//1.1.3.3
Registrar()
}
if(FS(seriesdex,id_series) >= 0) {
console.log("seriesdex entry:")
console.log(seriesdex[FS(seriesdex,id_series)])
}
// localStorage.setItem("seriesdex",JSON.stringify(seriesdex))
}
else if(document.getElementsByClassName("text-center")[0].innerText == "No Chapters"){
console.log("no chapters!")
if(document.getElementsByClassName("w-full").length){
for(let f of document.getElementsByClassName("w-full")){
if(fstatus == "Completed" && f.innerText.includes("Final Chapter")){
let completed = JSON.parse(localStorage.getItem("completed"))
let temp = {id: getID3(document.URL),name: document.title.replace(" - MangaDex",""),last: GetNumero(f.innerText),nextc: 10000,nextl: null}
let index = FS(completed,temp.id)
if(index >= 0) completed[index] = temp
else completed.push(temp)
localStorage.setItem("completed",JSON.stringify(completed))
console.log("new data:")
console.log(temp)
if(FS(seriesdex,temp.id) >= 0){
seriesdex.splice(FS(seriesdex,temp.id),1)
console.log("removed from seriesdex!")
localStorage.setItem("seriesdex",JSON.stringify(seriesdex))
}
}
}
}
else if(toConsider.includes(fstatus)){//1.1.3.3
let temp = {id: getID(document.URL),name: document.title.replace(" - MangaDex",""),last: -10,nextc: 10000,nextl: null}
function UpdateEmpty(arrayname,obj){
let dummy = JSON.parse(localStorage.getItem(arrayname))
let index = FS(dummy,obj.id)
if(index >= 0) {
if(dummy[index].last < 0 && dummy[index].nextl == null) dummy[index] = obj
//else it has previous data
}
else dummy.push(obj)
localStorage.setItem(arrayname,JSON.stringify(dummy))
console.log("new data:")
console.log(temp)
}
if(fstatus == "Reading") {
UpdateEmpty("reading",temp)
UpdateEmpty("seriesdex",temp)
}
else if(status == "On Hold") UpdateEmpty("onhold",temp)
else if(status == "Dropped") UpdateEmpty("dropped",temp)
}
}
else setTimeout(UpdatingSeriesData,500)
}
UpdatingSeriesData()
}
}
else setTimeout(main,5000)
}
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)
localStorage.setItem("seriesdex",JSON.stringify(seriesdex))
removedsd = true
}
}
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