Greasy Fork is available in English.
Manage your follows
当前为
// ==UserScript==
// @name New MangaDex Follows
// @namespace http://greasyfork.icu/scripts/430295-new-mangadex-follows
// @version 1.0.4
// @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"))
function FS(array, number){//FindSeries
return array.findIndex(q => q.id == number)
}
button_reload = 0
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 Reload1(){
elem_no = follows.length
if(before < elem_no) button_reload = setTimeout(Reload1,4000)
else repeat = setTimeout(FollowsFeed,2000)
before = follows.length
}
function Reload(){
if(lista.length == 0) button_reload = setTimeout(Reload,1000)
else repeat = setTimeout(FollowsFeed,2000)
}
function FollowsFeed(){
var classChapter = "flex chapter"
var classFeed = "chapter-feed__chapters-list"
if(document.URL.includes("titles/feed")) {
try{
console.log("FollowsFeed")
lista = document.getElementsByClassName("mb-12")[0].getElementsByClassName("mb-4")
console.log("lista loaded")
for(let i = seriesdex.length-1; i>=0; i--){//to correct latest bug
if(seriesdex[i].id.includes("/")) seriesdex.splice(i,1)
}
try{
clearInterval(button_reload)
}
catch(e){
console.log("no reload")
}
try{
clearInterval(repeat)
}
catch(e){
console.log("no repeat")
}
for(let l of lista){
//if(!l.className.includes("my-6") && l.style.display != "none") {
try{
var id_series = l.getElementsByTagName("a")[0].href.split("/")[4]
var batch = l.getElementsByClassName(classChapter)
var chap, link, read, nextc, nextl, last
nextc = 10000
nextl = ""
pseries = FS(seriesdex,id_series)
if(pseries < 0) last = -10
else last = seriesdex[pseries].last
function HasBeenRead(nodo){
if(!nodo.getElementsByTagName("svg")[0].className.baseVal.includes(" feather ")) return true
else return false
}
if(batch.length){
for(let i=0; i<batch.length; i++){
var current = batch[i].getElementsByTagName("a")[0].innerText.replace("\n"," ").split(" ")[1]*1
try{//for external links
JSON.parse(current)
}
catch(e){
current = batch[i].getElementsByTagName("a")[0].innerText.replace("\n"," ").split(" ")[2]*1
}
if(!HasBeenRead(batch[i])){
if(last < current && nextc > last && nextc > current){
nextc = current
nextl = batch[i].getElementsByTagName("a")[0].href.split("chapter/")[1]
}
}
else if(HasBeenRead(batch[i])){
if(last < current) last = current
}
}
}
if(pseries >= 0) NextNext(seriesdex,pseries,[nextc,nextl])
else seriesdex.push({id:id_series, name:l.firstChild.innerText, last:last, nextc:nextc, nextl:nextl})
index = FS(follows,id_series)
if(index >= 0){
if(seriesdex[pseries].last < last || seriesdex[pseries].last == null) seriesdex[pseries].last = last
if(nextc > last){
NextNext(follows,index,[nextc,nextl])
NextNext(seriesdex,pseries,[nextc,nextl])
}
if(l != follows[index].pointer) {
while(l.getElementsByClassName(classChapter)[0] != undefined) follows[index].pointer.getElementsByClassName(classChapter)[0].append(l.getElementsByClassName(classChapter)[0])
}
//else console.log("new?")
}
else{
follows.push({id:id_series, ch:last, url:link, nextc:nextc, nextl:nextl, pointer:l})
}
// if(pseries >= 0){
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
}
// }
}
catch(e){
console.log(e)
// console.log(l)
}
//}
}
for(let f of follows){
let avail = f.pointer.getElementsByClassName(classChapter)
let lastest = -10
let newest = 10000
let link = null
let current = FS(seriesdex,f.id)
if(current >= 0){
lastest = seriesdex[current].last
newest = seriesdex[current].nextc
}
for(let a of avail){
if(!a.getElementsByClassName("continue").length){
let disONE = a.getElementsByTagName("a")[0].innerText.replace("\n"," ").split(" ")[1]*1
try{
JSON.parse(disONE)//for external links
}
catch(e){
disONE = a.getElementsByTagName("a")[0].innerText.replace("\n"," ").split(" ")[2]*1
}
let unread = (!HasBeenRead(a))
if(disONE > lastest && !unread) lastest = disONE
if(unread && newest > disONE && disONE > lastest) {
newest = disONE
link = a.getElementsByTagName("a")[0].href.split("chapter/")[1]
}
}
}
// console.log(f.pointer.getElementsByTagName("h6")[0].innerText+" last: "+lastest+" nextc: "+newest)
f.ch = lastest
if(newest > lastest) {
f.nextc = newest
f.nextl = link
}
else{
f.nextc = 10000
f.nextl = null
}
if(lastest > seriesdex[current].last) {
seriesdex[current].last = lastest
// seriesdex[current].nextc = f.nextc
// seriesdex[current].nextl = f.nextl
}
else{//lastest <= seriesdex[current].last
if(seriesdex[current].nextc != f.nextc){
seriesdex[current].nextc = f.nextc
seriesdex[current].nextl = f.nextl
}
}
}
for(let l of lista){
if(l.getElementsByTagName("a")[0]){ //l.firstChild.getElementsByTagName("a")[0]
let daONE = seriesdex[FS(seriesdex,l.getElementsByTagName("a")[0].href.split("/")[4])]
if(l.getElementsByClassName(classFeed).length == 0) l.style.display = "none"
else if(daONE.nextc > daONE.last && daONE.nextl){
let newbutton = document.createElement("div")
newbutton.className = classFeed
newbutton.innerHTML = "<button class=\"continue\"><a href=\"/chapter/"+daONE.nextl+"\">CONTINUE to Chapter "+daONE.nextc+"</button>"
if(l.getElementsByClassName("continue").length == 0) l.getElementsByClassName("chapter-feed__chapters")[0].insertBefore(newbutton,l.getElementsByClassName(classFeed)[0])
else l.getElementsByClassName("continue")[0].parentElement.innerHTML = newbutton.innerHTML
}
if((daONE.nextl == null || daONE.nextl == "") && l.getElementsByClassName("continue")[0] != undefined) l.getElementsByClassName("continue")[0].parentElement.remove()
}
}
for(let n=follows.length-1; n >= 0; n--){
if(follows[n].pointer.getElementsByClassName("continue")[0] != undefined) lista[0].parentElement.insertBefore(follows[n].pointer,lista[0])
}
localStorage.setItem("seriesdex",JSON.stringify(seriesdex))
//interval = setInterval(FollowsFeed,120000)
}
catch(e){
console.log("error FollowsFeed")
console.log(e)
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 = t.getElementsByTagName("a")[0].href.split("/")[4]
var name = t.getElementsByTagName("a")[0].innerText.replaceAll("\n ","").replaceAll("\n ","")
temp.push({id:id, name:name, last:null, nextc:null, nextl:null })
if(temp.length == 0) temp = [{id:id, name:name, last:null, nextc:null, nextl:null}]
}
console.log("Done Filling!!")
return temp
}
function NewButton(){
try{
newb = document.createElement("button")
newb.innerHTML = "<button id=\"fill-btn\" data-v-621772ff=\"\" type=\"button\" class=\"v-btn v-btn--is-elevated v-btn--has-bg theme--dark v-size--default\"><span class=\"v-btn__content\"><span data-v-621772ff=\"\" aria-hidden=\"true\" class=\"v-icon notranslate theme--dark\" onclick=\"Fill()\"><a>FILL</a></span></span></button>"
if(!document.getElementById("fill-btn")) document.getElementsByClassName("controls mb-auto ml-auto")[0].appendChild(newb)
dl = document.createElement("div")
dl.innerHTML="<button class=\"rounded relative md-btn flex items-center px-3 my-6 justify-center text-white bg-primary hover:bg-primary-darken active:bg-primary-darken2 glow px-4 px-6\" onclick=\"DownloadCSV()\">Download CSV</button><button class=\"rounded relative md-btn flex items-center px-3 my-6 justify-center text-white bg-primary hover:bg-primary-darken active:bg-primary-darken2 glow px-4 px-6\" onclick=\"DownloadJSON()\">Download JSON<button>"
document.getElementsByClassName("follows__display")[0].parentElement.insertBefore(dl,document.getElementsByClassName("follows__display")[0])
}
catch(e){
setTimeout(NewButton,500)
}
}
function FillTitles(){
try{
titles = document.getElementsByClassName("follows__content")[0].firstChild.children
if(titles != undefined){
console.log("Filling Titles")
for(t of titles){
if(t.innerHTML != "<!---->"){
if(t.firstChild.firstChild.firstChild.innerText == "Reading") reading = Llenar(t)
if(t.firstChild.firstChild.firstChild.innerText == "On Hold") onhold = Llenar(t)
if(t.firstChild.firstChild.firstChild.innerText == "Plan To Read") planto = Llenar(t)
if(t.firstChild.firstChild.firstChild.innerText == "Dropped") dropped = Llenar(t)
if(t.firstChild.firstChild.firstChild.innerText == "Completed") completed = Llenar(t)
}
}
for(let r of reading){
if(FS(seriesdex,r.id) == -1) seriesdex.push(r)
}
function Copiar(arrA,argB){
if(FS(arrA, argB.id) >= 0){
arrA[FS(arrA, argB.id)].last = argB.last
}
}
for(let i = seriesdex.length-1; i >= 0; i--){
Copiar(completed, seriesdex[i])
Copiar(onhold, seriesdex[i])
Copiar(reading, seriesdex[i])
Copiar(dropped, seriesdex[i])
//Copiar(planto, seriesdex[i])
}
localStorage.setItem("reading",JSON.stringify(reading))
localStorage.setItem("planto",JSON.stringify(planto))
localStorage.setItem("onhold",JSON.stringify(onhold))
localStorage.setItem("dropped",JSON.stringify(dropped))
localStorage.setItem("completed",JSON.stringify(completed))
alert("Done!")
}
}
catch(e){
console.log(e)
// setTimeout(FillTitles, 5500)
}
}
function main(){
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("user__tab-active")[0].innerText == "Follows"){
NewButton()
}
}
if(document.URL.includes("https://mangadex.org/titles/feed")){
follows = []
elem_no = 0
before = 0
function DoFollows(){
FollowsFeed()
//repeat = setTimeout(FollowsFeed,30000)
}
if(document.getElementsByClassName("mb-4").length) DoFollows()
else setTimeout(main,2000)
}
}
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"
else last = a.last
}
else last = a.last
temp.push({id:a.id,name:a.name,state:naame,last:last})
if(temp.length == 0) temp = [{id:a.id,name:a.name,state:naame,last:last}]
}
}
Processing(reading,"Reading")
Processing(onhold,"On Hold")
Processing(planto,"Plan to Read")
Processing(dropped,"Dropped")
Processing(completed,"Completed")
return temp
}
window.FF = function(){//for debugging
FollowsFeed()
}
window.DownloadCSV = function(){
exportToCsvFile(PrepareData(true))
}
window.DownloadJSON = function(){
exportToJsonFile(PrepareData(false))
}
document.onscroll = function() {
// Detect webkit browser (Chrome, Safari)
// console.log("scrolling")
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(FollowsFeed,500)
trigger = false
}
Reader()
}