// ==UserScript==
// @name MangaDex Follows
// @namespace https://greasyfork.org/es/scripts/411685-mangadex-follows
// @version 1.3.7.4.1
// @description Manage your follows page
// @author Australis
// @match https://mangadex.org/*
// @exclude https://mangadex.org/chapter/*
// @grant GM_addStyle
// ==/UserScript==
GM_addStyle(".checkit::before {content: \"❌❌ \";}")
const debug = false
function log(string){
if(debug) console.log(string)
}
log("Executing");
//DB Handling
//prefixes of implementation that we want to test
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
//prefixes of window.IDB objects
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction;
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange
if (!window.indexedDB) {
window.alert("Your browser doesn't support a stable version of IndexedDB. MangaDex Follows Script won't work for you")
}
const seriesDataExample = [
{ id: 149, name: '', status: '', last_read: 34, last_update: 1830012313}
];
var db;
var request = window.indexedDB.open("MDF", 2);
request.onerror = function(event) {
console.log("error: ");
};
request.onsuccess = function(event) {
db = request.result;
log("success: "+ db);
main();
};
request.onupgradeneeded = function(event) {
var db = event.target.result;
var objectStore = db.createObjectStore("series", {keyPath: "id"});
objectStore = db.createObjectStore("whitelist", {keyPath: "id", });
objectStore = db.createObjectStore("blacklist", {keyPath: "id"});
objectStore = db.createObjectStore("gap", {keyPath: "id"});
// for (var i in seriesDataExample) {
// objectStore.add(seriesDataExample[i]);
// }
}
function dbRead(variable,seriesID){
var transaction = db.transaction([variable],"readwrite");
var objectStore = transaction.objectStore(variable);
var request = objectStore.get(seriesID);
request.onerror = function(event) {
log("Unable to retrieve "+variable+" from database!");
};
request.onsuccess = function(event) {
// Do something with the request.result!
if(request.result) {
log(request.result);
} else {
log(variable+" couldn't be found in the database!");
//add it
}
};
}
function dbReadAll(variable,callback) {
var objectStore = db.transaction(variable).objectStore(variable);
objectStore.openCursor().onsuccess = function(event) {
var temp = []
var cursor = event.target.result;
if (cursor) {
temp.push(cursor.value)
cursor.continue();
} else {
log("No more entries!");
callback(temp)
}
};
}
function dbReadAll2(variable,callback){
var db
log("dbReadAll2")
request = window.indexedDB.open("MDF", 2)
request.onsuccess = function(event) {
db = request.result;
console.log("success: "+ db);
try{
var objectStore = db.transaction(variable).objectStore(variable);
var temp2 = []
objectStore.openCursor().onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
temp2.push(cursor.value)
cursor.continue();
} else {
console.log("No more entries!");
// console.log(temp2)
return callback(temp2)
}
}
}
catch(e){
log("Variable not available");
return []
}
};
request.onerror = function(event) {
log("database error")
}
}
i = -1
function dbReadAll3(variable,arrays){
i++
var db
log("dbReadAll3 "+variable[i])
var request = window.indexedDB.open("MDF", 2)
var temp2 = []
request.onsuccess = function(event) {
// for(let i = 0; i < variable.length; i++){
db = request.result;
console.log("success: "+ db);
try{
var objectStore = db.transaction(variable[i]).objectStore(variable[i]);
objectStore.openCursor().onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
temp2.push(cursor.value)
cursor.continue();
} else {
console.log("No more entries!\n"+temp2);
// console.log(temp2)
switch(i){
case 0:
blacklist = temp2
return dbReadAll3(variable)
break
case 1:
whitelist = temp2
return dbReadAll3(variable)
break
case 2:
gap = temp2
break
}
}
}
objectStore.openCursor().onerror = function(event) {
console.log("cursor error "+variable[i])
}
}
catch(e){
log("Variable not available");
switch(i){
case 0:
blacklist = temp2
return dbReadAll3(variable)
break
case 1:
whitelist = temp2
return dbReadAll3(variable)
break
case 2:
gap = temp2
break
}
}
// }
};
request.onerror = function(event) {
log("database error")
}
}
function dbAdd(variable,seriesObj) {
var request = db.transaction([variable], "readwrite").objectStore(variable).put(seriesObj);
request.onsuccess = function(event) {
log("Current "+variable+" has been added to database.");
};
request.onerror = function(event) {
log("No duplicates allowed!!");
}
}
function dbUpdate(variable,seriesObj){
for(let s of seriesObj){
dbAdd(variable,s)
}
}
function dbRemove(variable,seriesID) {
var request = db.transaction([variable], "readwrite").objectStore(variable).delete(seriesID);
request.onsuccess = function(event) {
log(variable+" "+seriesID+" has been removed from database.");
};
}
//Variable handling
function LoadLists(input){
let dalist = []
function doThis(callback){
dalist = dbR3adAll(input)
callback()
}
function callback(){
log(input+" loaded - "+dalist.length)
}
try{
doThis(callback)
.then(function(){return dalist})
}
catch(e){
log("failed to load "+input)
return dalist
}
}
checker = []
let nodes = []
function Checker(node){
if(checker.length == 0) checker = [node]
else checker.push(node)
log(node)
}
function CleanChecker(id,r){
try{
if(nodes.lenght == 0) nodes.push([id,[r]])
else{
add = true
for(let n of nodes){
log("a node")
if(n[0] == id) {
log("existing node")
if(!n[1].includes(r)) n[1].push(r)
add = false
}
}
if(add) nodes.push([id,[r]])
}
}catch(e){
log("CleanChecker error: "+e)
}
}
function Decider(){
log("Decider")
for(let n of nodes){
if(n[1].length > 1){
log("deciding")
var save_c = 100000
var save_v = 100000
var save_r = false
var best = []
log(n[1])
for(let m of n[1]){
// log("save_c "+save_c)
let dataset = m.children[2].childNodes[1].dataset
log("chapter "+dataset.chapter)
if(dataset.volume*1){
if(save_v > dataset.volume*1){
save_v = dataset.volume*1
save_c = dataset.chapter*1
save_r = m
best = []
}
else if(save_c > dataset.chapter*1){
log("next one?")
save_c = dataset.chapter*1
save_r = m
best = []
}
else if(save_c == dataset.chapter*1){
log("same")
if(!best.includes(save_r)) best.push(save_r)
if(!best.includes(m)) best.push(m)
}
}
else{
if(save_c > dataset.chapter*1){
log("next one?")
save_c = dataset.chapter*1
save_r = m
best = []
}
else if(save_c == dataset.chapter*1){
log("same")
if(!best.includes(save_r)) best.push(save_r)
if(!best.includes(m)) best.push(m)
}
else log("no coincidence")
}
}
if(best.length){
for(let b of best) CleanCheckerB(n[0]*1,b)
}
else CleanCheckerB(n[0]*1,save_r)
}
else {
CleanCheckerB(n[0]*1,n[1][0])
}
}
return true
}
function CleanCheckerB(id,row){
try{
for(var x=checker.length-1; x>=0; x--){
if(checker[x][0] == id && checker[x][1] == row) checker.splice(x,1)
}
}catch(e){
log("CleanChecker error: "+e)
checker = []
}
}
function Ahead(){
try{
if(checker.length){
for(c of checker){
let dataset = c[1].children[2].childNodes[1].dataset
if(dataset.mangaId){
if(c[1].getElementsByClassName("chapter_mark_read_button grey")[0]) c[1].getElementsByClassName("chapter_mark_read_button grey")[0].setAttribute("class","chapter_mark_read_button")
else log(c)
if(c[1].getElementsByClassName("chapter_mark_read_button")[0]) c[1].getElementsByClassName("chapter_mark_read_button")[0].setAttribute("style","color: red")
else log(c)
}
}
}
checker = []
}catch(e){
log(e)
log(c)
}
}
function FS(array, number){//FindSeries
return array.findIndex(q => q.id*1 == number*1)
}
blacklist = []
whitelist = []
gap = []
lista = 0
function main(){
log("main")
// try{
// new Promise(function() {
// return dbReadAll2("blacklist",loadList)
// }).then(function() { // (**)
// return dbReadAll2("whitelist",loadList)
// }).then(function() { // (***)
// return dbReadAll2("gap",loadList)
// }).then(function() {
// return dbReadAll2("series",main2)
// });
// dbReadAll2("blacklist",loadList)
// dbReadAll2("whitelist",loadList)
// dbReadAll2("gap",loadList)
// dbReadAll2("series",main2)
dbReadAll3(["blacklist","whitelist","gap"],[blacklist,whitelist,gap])
dbReadAll2("series",main2)
// var enhance;
try{
if(JSON.parse(localStorage.getItem("enhance")) != null) enhance = JSON.parse(localStorage.getItem("enhance"))
else enhance = true
}
catch(e){
log("error with enhance")
enhance = true
}
function loadList(res){
switch(lista){
case 0:
lista++
if(res == null) break
blacklist = res
break
case 1:
lista++
if(res == null) break
whitelist = res
break
case 2:
lista++
if(res == null) break
gap = res
break
}
}
function main2(res){
log("main2")
series = res
updater = []
log("series loaded - "+series.length)
//add titles from follows
if(document.URL.includes('mangadex.org/follows/manga')){
series_col = document.getElementsByClassName("manga-entry border-bottom");
for(var s of series_col){
var row = s.getElementsByClassName("row m-0")[1];
var name = row.children[0].innerText;
var state = row.children[2].innerText;
var id = s.dataset.id;
var node = {id: id, name: name, state: state, last_read: 0, last_update: 0}
var add = true;
if(series){
for(var m of series){
if(m.id*1 === id*1){
add = false;
if(m.state !== state) {
m.state = state;
if(updater.findIndex(q => q == m) < 0) updater.push(m)
}
}
}
if(add) {
series.push(node);
if(updater.findIndex(q => q == node) < 0) updater.push(node)
}
}
else {
series = [node]
updater = [node]
}
}
// localStorage.setItem('series',JSON.stringify(series))
// dbUpdate("series",series)
dbUpdate("series",updater)
}
else if(document.URL.includes('mangadex.org/follows')){
//read chapters
row = document.getElementsByClassName("chapter-container")[0].children;
function Hide(DataSet){
for(var b of blacklist){
if(b[0]*1 == DataSet.mangaId*1 && b[1]*1 == DataSet.group*1) return true
}
return false
}
function OnlyThis(DataSet){
for(var w of whitelist){
if(w[0]*1 == DataSet.mangaId*1 && w[1]*1 != DataSet.group*1) return 0
if(w[0]*1 == DataSet.mangaId*1 && w[1]*1 == DataSet.group*1) return 1
}
return 2
}
let changeH = false
let changeO = false
function Process(){
for(var r of row){
let dataset = r.children[2].childNodes[1].dataset;
if(dataset.mangaId){
let manga_id = dataset.mangaId*1;
if(enhance) try{
if(Hide(dataset)) {
title = r.children[0].innerHTML
r.setAttribute("style","display: none")
changeH = true
}
else if(changeH){
title2 = r.children[0].innerHTML
if(r.children[0].classList.contains("d-md-flex")) r.children[0].innerHTML = title
title = title2
changeH = false
}
if(!OnlyThis(dataset)) {
title = r.children[0].innerHTML
r.setAttribute("style","display: none")
changeO = true
}
else if(changeO){
title2 = r.children[0].innerHTML
if(r.children[0].classList.contains("d-md-flex")) r.children[0].innerHTML = title
title = title2
changeO = false
}
}catch(e){
log("enhance error, "+e)
}
try{
pointer = FS(series,manga_id)
if(series[pointer].last_read.toString().includes("v")){//if is divided by volume
if(series[pointer].last_read.toString() == "0v0") r.children[0].classList.value += " checkit"
else if(r.children[0].classList.value.includes("checkit")) log("ERASE THIS (vol version)!!")
log("a volume one, "+series[FS(series,manga_id)].last_read)
log(r)
q = series[pointer].last_read.split("v")
vol = q[0]
chap = q[1]
if(r.innerHTML.includes("mark_unread")){
if(chap*1 < dataset.chapter*1 && vol*1 == dataset.volume*1) {
log("new chapter")
series[pointer].last_read = dataset.volume+"v"+dataset.chapter;
if(updater.findIndex(q => q == series[pointer]) < 0) updater.push(series[pointer]);
}
if(vol < dataset.volume*1) {
log("new volume")
series[pointer].last_read = dataset.volume+"v"+dataset.chapter;
if(updater.findIndex(q => q == series[pointer]) < 0) updater.push(series[pointer]);
}
}
else if(enhance){
if((chap*1 >= dataset.chapter*1 && vol*1 == dataset.volume*1) || vol*1 > dataset.volume*1){ //a duplicate
r.getElementsByClassName("chapter_mark_read_button grey")[0].setAttribute("class","chapter_mark_read_button")
if(gap.findIndex(q => q[0]*1 == manga_id) >= 0){
let lgap = gap[gap.findIndex(q => q[0]*1 == dataset.mangaId)][1]
log("a gapped one: ",lgap)
log("current chapter: "+dataset.volume+"v"+dataset.chapter)
if(chap*1 >= lgap[0].split("v")[1] && vol*1>= lgap[0].split("v")[0] &&
lgap[1].split("v")[1] >= dataset.chapter*1 && vol*1<= lgap[1].split("v")[0]) r.getElementsByClassName("chapter_mark_read_button")[0].setAttribute("style","color: green")
}
else if(!(dataset.title.toLowerCase().includes("extra") || dataset.title.toLowerCase().includes("omake"))){
r.getElementsByClassName("chapter_mark_read_button")[0].setAttribute("style","color: blue")
}
else r.getElementsByClassName("chapter_mark_read_button")[0].setAttribute("style","color: green")
}
else{//a new one
if(chap*1 < dataset.chapter*1+1.11 && vol*1 == dataset.volume*1){//skipped chapter
Checker([manga_id,r])
}
if(chap*1 < dataset.chapter*1 && vol*1 == dataset.volume*1 && dataset.chapter*1 <= chap*1+1.11){//next chapter
// CleanChecker(manga_id)
CleanChecker(manga_id,r)
}
}
}
}
else{//if not divided by volume
this_last = series[FS(series,manga_id)].last_read*1
if(r.innerHTML.includes("mark_unread")){
if(this_last < dataset.chapter*1) {
series[FS(series,manga_id)].last_read = dataset.chapter*1;
if(updater.findIndex(q => q == series[FS(series,manga_id)]) < 0) updater.push(series[FS(series,manga_id)])
}
}
else if(enhance){
if(this_last == 0) r.children[0].classList.value += " checkit"
else if(r.children[0].classList.value.includes("checkit")) log("ERASE THIS!!")
if(this_last >= dataset.chapter*1){ //a duplicate
log("a duplicate")
if(r.getElementsByClassName("chapter_mark_read_button grey")[0]) r.getElementsByClassName("chapter_mark_read_button grey")[0].setAttribute("class","chapter_mark_read_button")
if(gap.findIndex(q => q[0]*1 == manga_id) >= 0){
let lgap = gap[gap.findIndex(q => q[0]*1 == dataset.mangaId)][1]
log("a gapped one: ",lgap)
log("current chapter: "+dataset.chapter)
if(dataset.chapter*1 >= lgap[0] &&
lgap[1] >= dataset.chapter*1) r.getElementsByClassName("chapter_mark_read_button")[0].setAttribute("style","color: green")
}
else if(dataset.title.toLowerCase().includes("extra") || dataset.title.toLowerCase().includes("omake") || (dataset.chapter*1)%1 == 0.5){
r.getElementsByClassName("chapter_mark_read_button")[0].setAttribute("style","color: green")
}
else r.getElementsByClassName("chapter_mark_read_button")[0].setAttribute("style","color: blue")
}
else{//a new one
if(this_last != 0
&& this_last < dataset.chapter*1+1.11){//skipped chapter
// if((dataset.chapter*1)%1 && series[FS(series,manga_id)][3]*1+0.1 <= dataset.chapter*1) log("skipped parted chapter")
Checker([manga_id,r])
}
if(this_last < dataset.chapter*1
&& dataset.chapter*1 <= this_last+1.11){//next chapter
if((dataset.chapter*1)%1 && dataset.chapter*1 == Math.round((this_last+0.1+Number.EPSILON)*10)/10) {//Math.round((18.3+0.1+Number.EPSILON)*10)/10
log("next parted chapter")
CleanChecker(manga_id,r)
}
else if((dataset.chapter*1)%1 && dataset.chapter*1 == this_last+0.5) {
log("next extra chapter")
CleanChecker(manga_id,r)
}
else if((dataset.chapter*1)%1 && this_last-this_last%1 < dataset.chapter*1-(dataset.chapter*1)%1
&& dataset.chapter*1 == this_last-this_last%1+1.1){
log("next new parted chapter")
CleanChecker(manga_id,r)
}
else if((dataset.chapter*1)%1 == 0) {
log("regular next chapter")
CleanChecker(manga_id,r)
}
}
}
}
}
}catch(e){
//series not included
log("series not included?\n"+e)
log(dataset.mangaId+" "+r.children[0].innerText)
let this_last = 0
if(r.innerHTML.includes("mark_unread")) this_last = dataset.chapter*1;
if(FS(series,dataset.mangaId) == -1) {
cnode = {id: dataset.mangaId, name: r.children[0].innerText, state: ' Reading', last_read: this_last, last_update: dataset.timestamp}
series.push(cnode)
if(updater.findIndex(q => q == cnode) < 0) updater.push(cnode)
}
}
}//end if
}//end for
return true
}
if(Process()) Process() //a second one to reduce false positives
if(Decider()) Ahead()
// localStorage.setItem('series',JSON.stringify(series))
// dbUpdate("series",series)
dbUpdate("series",updater)
}
if(document.URL.includes('/title/')){
log("title")
notVOL = false
var follow_stat = document.getElementsByClassName("btn-group")[0].childNodes[0].childNodes[0].className;
let mangaId = document.URL.split("/")[4]*1
function ProcVol(){
try{
for(let t of temp){
[lastv,lastc] = last.split("v")
if(t.dataset != null){
let dataset = t.dataset;
let manga_id = dataset.mangaId;
let vol = dataset.volume*1
if(vol == 0) {
notVOL = true
last = 0
Chapters()
return false
}
if(process && lastc == dataset.chapter*1 && lastv == vol){
if(!t.innerHTML.includes("mark_unread")){
last = "0v0"
log("reset")
}
else process = false
}
if(t.innerHTML.includes("mark_unread")) {
if(lastc < dataset.chapter*1 && lastv == vol) {//a new read chapter from same volume
last = vol+"v"+dataset.chapter
process = false
series[FS(series,manga_id)].last_read = last;
if(updater.findIndex(q => q == series[FS(series,manga_id)]) < 0) updater.push(series[FS(series,manga_id)])
}
if(lastv < vol){//a new volume is read
log("new volume")
last = vol+"v"+dataset.chapter
series[FS(series,manga_id)].last_read = last;
if(updater.findIndex(q => q == series[FS(series,manga_id)]) < 0) updater.push(series[FS(series,manga_id)])
}
if(time < dataset.timestamp*1){
time = dataset.timestamp*1
series[FS(series,manga_id)].last_update = dataset.timestamp*1
if(updater.findIndex(q => q == series[FS(series,manga_id)]) < 0) updater.push(series[FS(series,manga_id)])
}
}
}//end if
}//end for
log("done ProcVol, current last: "+last)
// localStorage.setItem('series',JSON.stringify(series))
// dbUpdate("series",series)
dbUpdate("series",updater)
}catch(e){
log("ProcVol error\n"+e)
}
}
function Chapters(){
try{
if(last.toString().includes("v")){//is parted as independent chapters per volume
ProcVol()
}
else{//is default
for(let t of temp){
if(t.dataset != null){
let dataset = t.dataset;
let manga_id = dataset.mangaId;
let timestamp = dataset.timestamp
if(dataset.volume != null) {
vol = dataset.volume*1
}
else {
vol = 10000-1
notVOL = true
}
if(checkvol && cvol > vol && !notVOL) {//volume change and not first iteration
if(cchp <= dataset.chapter*1){ //if it's not a successive chapter
log("volume!!")
checkvol = false
last = "0v0"
ProcVol()
}
}
if(!last.toString().includes("v")){
if(process && last == dataset.chapter*1){
if(!t.innerHTML.includes("mark_unread")){
last = 0
log("reset")
}
else process = false
}
if(t.innerHTML.includes("mark_unread")) {
if(last < dataset.chapter*1) {
process = false
last = dataset.chapter*1;
series[FS(series,manga_id)].last_read = dataset.chapter*1;
if(updater.findIndex(q => q == series[FS(series,manga_id)]) < 0) updater.push(series[FS(series,manga_id)])
}
if(time < dataset.timestamp*1){
time = dataset.timestamp*1
series[FS(series,manga_id)].last_update = dataset.timestamp*1
if(updater.findIndex(q => q == series[FS(series,manga_id)]) < 0) updater.push(series[FS(series,manga_id)])
}
}
cvol = vol
cchp = dataset.chapter*1
}//end if
}//end if
}//end for
log("new last: "+last)
// localStorage.setItem('series',JSON.stringify(series))
// dbUpdate("series",series)
dbUpdate("series",updater)
log("OK");
}//end else
}catch(e){
log("Chapters error\n"+e)
}
}
var temp = document.getElementsByClassName("chapter-row d-flex row no-gutters p-2 align-items-center border-bottom odd-row");
var last = 0
var time = 0
var pos = FS(series,mangaId)
if(pos >= 0) {
last = series[pos].last_read
time = series[pos].last_update
}
log("old last: "+last)
process = true
var cvol = 10000
var cchp = 0
checkvol = true
let state = document.getElementsByClassName("btn dropdown-toggle")[0].getElementsByClassName("d-none d-xl-inline")[0].innerText
let name = document.title.split(" (Title)")[0]
let id = document.URL.split("/")[4]
let node = {id: id, name: name, state: state, last_read: last, last_update: time}
let add = true;
let z = FS(series,id)
if(z == -1){
series.push(node)
log(name+" added to series")
if(updater.findIndex(q => q == node) < 0) updater.push(node)
}
else{
if(series[z].state !== state) {
series[z].state = state;
if(updater.findIndex(q => q == series[z]) < 0) updater.push(series[z])
}
}
if(!follow_stat.includes("fa-bookmark")){
Chapters()
}
}
if(document.URL.includes('mangadex.org/follows') && !document.URL.includes('mangadex.org/follows/manga')){
seriesDL = []
for(s of series){
seriesDL.push([s.id,s.name,s.status,s.last_read,s.last_update])
}
let data = [['ID','Series name','Status','Last Read','Last Update']].concat(seriesDL);
for(var d of data){
if(d[1].includes("\"")) d[1] = d[1].replaceAll("\"","|")
if(d[1].includes(";")) d[1] = d[1].replaceAll(";",":")
if(d.length == 5 && d[5] != 0) d[4] = new Date(d[4]*1000)
else d.push("Unknown")
}
// Building the CSV from the Data two-dimensional array
// Each column is separated by ";" and new line "\n" for next row
let csvContent = '';
data.forEach(function(infoArray, index) {
dataString = infoArray.join(';');
csvContent += index < data.length ? dataString + '\n' : dataString;
});
// The download function takes a CSV string, the filename and mimeType as parameters
// Scroll/look down at the bottom of this snippet to see how download is called
let download = function(content, fileName, mimeType) {
var a = document.createElement('a');
mimeType = mimeType || 'application/octet-stream';
if (navigator.msSaveBlob) { // IE10
navigator.msSaveBlob(new Blob([content], {
type: mimeType
}), fileName);
} else if (URL && 'download' in a) { //html5 A[download]
a.href = URL.createObjectURL(new Blob([content], {
type: mimeType
}));
a.setAttribute('download', fileName);
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
} else {
location.href = 'data:application/octet-stream,' + encodeURIComponent(content); // only this mime type is supported
}
}
document.download = function(){download(csvContent, 'MangaDex.csv', 'text/csv;encoding:utf-8')}
let boton = document.createElement("li")
boton.setAttribute("class","nav-item")
boton.setAttribute("href","#")
boton.setAttribute("onclick","download()")
boton.appendChild(document.createElement("a"))
boton.children[0].setAttribute("class","nav-link")
boton.children[0].appendChild(document.createElement("span"))
boton.children[0].children[0].setAttribute("class","fas fa-download fa-fw")
boton.children[0].children[0].setAttribute("aria-hidden","true")
boton.children[0].appendChild(document.createElement("span"))
boton.children[0].children[1].setAttribute("class","d-none d-md-inline")
boton.children[0].children[1].innerText = "Export"
document.getElementsByClassName("nav nav-tabs")[0].insertBefore(boton,document.getElementsByClassName("nav nav-tabs")[0].children[4])
let boton2 = document.createElement("li")
boton2.appendChild(document.createElement("a"))
boton2.firstChild.setAttribute("class","nav-link")
boton2.firstChild.innerText = "Script Options"
boton2.firstChild.setAttribute("onclick","Show()")
document.getElementsByClassName("nav nav-tabs")[0].insertBefore(boton2,document.getElementsByClassName("nav nav-tabs")[0].children[5])
}
CreateMenu()
document.getElementById("enhancer").checked = enhance
}
// }
// catch(e){
// log("ERROR!!")
// log(e)
// }
}
function CreateMenu(){
gg = document.createElement("style")
gg.innerText = ".modal_row {display: grid;grid-gap: 5px;grid-template-columns: 20vw 20vw 5vw;}"
gg.innerText+= ".modalX {display: none;position: fixed;z-index: 10;padding-top: 10vh;left: 0;top: 0;width: 99%; height: 100%; overflow: auto; background-color: rgb(0,0,0); background-color: rgba(0,0,0,0.4); color: white;}"
gg.innerText+= ".modalo {position: relative;background-color: black;margin: auto;padding: 2vw;border: 1px solid #888;width: 80%;box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);-webkit-animation-name: animatetop;-webkit-animation-duration: 0.4s;animation-name: animatetop;animation-duration: 0.4s}"
gg.innerText+= "@-webkit-keyframes animatetop {from {top:-300px; opacity:0} to {top:0; opacity:1}}"
gg.innerText+= "@keyframes animatetop {from {top:-300px; opacity:0}to {top:0; opacity:1}}"
gg.innerText+= ".closex {color: white;float: right;font-size: 28px;font-weight: bold;padding-right: 8vw;}"
gg.innerText+= ".closex:hover,.close:focus {color: #000;text-decoration: none;cursor: pointer;}"
gg.innerText+= ".half {width: 45%;display: inline-block;}"
document.querySelector("head").appendChild(gg)
modal = document.createElement("div")
modal.setAttribute("class","modalX")
modal.setAttribute("id","modalX")
// modal.setAttribute("style","margin: auto;width: 70vw;")
closer = document.createElement("span")
closer.setAttribute("class","closex")
closer.innerText = "×"
closer.setAttribute("onclick","CloseThis()")
modal.appendChild(closer)
form = document.createElement("div")
elem1 = document.createElement("div") //checkbox
elem2 = document.createElement("div") //whitelist
elem3 = document.createElement("div") //blacklist
elem4 = document.createElement("div") //gap
modbut = document.createElement("button") //save button
canbut = document.createElement("button") //cancel button
modt1 = document.createElement("h2") //title1
modt1.setAttribute("title","series & group ID are the numbers in their URLs, after /title/ and /group/ respectively")
modt1.innerText = "Whitelist elements"
modt2 = document.createElement("h2") //title2
modt2.setAttribute("title","series & group ID are the numbers in their URLs, after /title/ and /group/ respectively")
modt2.innerText = "Blacklist elements"
modt3 = document.createElement("h2") //title3
modt3.setAttribute("title","series ID are the numbers after /title/ in their URL, and the gap has to include the chapters available between the gap")
modt3.innerText = "Gap list elements"
form.setAttribute("class","modalo")
form.setAttribute("id","ScriptForm")
// form.setAttribute("action","")
elem1A = document.createElement("input")
elem1A.setAttribute("type","checkbox")
elem1A.setAttribute("id","enhancer")
elem1A.setAttribute("name","enhancer")
elem1A.setAttribute("style","margin:5px;")
elem1A.setAttribute("checked",enhance)
elem1B = document.createElement("label")
elem1B.setAttribute("for","enhancer")
elem1B.innerText = "\tHighlight unread chapters"
elem1.appendChild(elem1A)
elem1.appendChild(elem1B)
elem2.setAttribute("id","whitelister")
elem2.setAttribute("style","display:grid;grid-gap:5px;")
modalrow1 = document.createElement("div")
modalrow1.setAttribute("class","modal_row")
title2A = document.createElement("span")
title2B = document.createElement("span")
title2A.innerText = "series ID"
title2B.innerText = "group ID"
modalrow1.appendChild(title2A)
modalrow1.appendChild(title2B)
elem2.appendChild(modt1)
elem2.appendChild(modalrow1)
function Row1(w){
let modalrow2 = document.createElement("div")
modalrow2.setAttribute("class","modal_row")
let span2A = document.createElement("span")
let input2A = document.createElement("input")
input2A.setAttribute("type","number")
input2A.setAttribute("name","mangaID")
input2A.setAttribute("value",w[0])
span2A.appendChild(input2A)
let span2B = document.createElement("span")
let input2B = document.createElement("input")
input2B.setAttribute("type","number")
input2B.setAttribute("name","groupID")
input2B.setAttribute("value",w[1])
span2B.appendChild(input2B)
modalrow2.appendChild(span2A)
modalrow2.appendChild(span2B)
let del = document.createElement("p")
del.innerText = "DELETE"
del.setAttribute("onclick","this.parentElement.remove()")
modalrow2.appendChild(del)
return modalrow2
}
if(whitelist.length) for(let w of whitelist){
elem2.appendChild(Row1(w))
// let modalrow2 = document.createElement("div")
// modalrow2.setAttribute("class","modal_row")
// let span2A = document.createElement("span")
// let input2A = document.createElement("input")
// input2A.setAttribute("type","number")
// input2A.setAttribute("name","mangaID")
// input2A.setAttribute("value",w[0])
// span2A.appendChild(input2A)
// let span2B = document.createElement("span")
// let input2B = document.createElement("input")
// input2B.setAttribute("type","number")
// input2B.setAttribute("name","groupID")
// input2B.setAttribute("value",w[1])
// span2B.appendChild(input2B)
// modalrow2.appendChild(span2A)
// modalrow2.appendChild(span2B)
// let del = document.createElement("p")
// del.innerText = "DELETE"
// del.setAttribute("onclick","this.parentElement.remove()")
// modalrow2.appendChild(del)
// elem2.appendChild(modalrow2)
}
// else{
// modalrow2 = document.createElement("div")
// modalrow2.setAttribute("class","modal_row")
// }
add = document.createElement("p")
add.setAttribute("id","adder")
add.innerText = "ADD NEW"
add.setAttribute("onclick","this.remove();AddWL(this)")
elem2.appendChild(add)
elem3.setAttribute("id","blacklister")
elem3.appendChild(modt2)
elem3.appendChild(modalrow1.cloneNode(true))
if(blacklist.length) for(let b of blacklist){
elem3.appendChild(Row1(b))
// let modalrow2 = document.createElement("div")
// modalrow2.setAttribute("class","modal_row")
// let span2A = document.createElement("span")
// let input2A = document.createElement("input")
// input2A.setAttribute("type","number")
// input2A.setAttribute("name","mangaID")
// input2A.setAttribute("value",b[0])
// span2A.appendChild(input2A)
// let span2B = document.createElement("span")
// let input2B = document.createElement("input")
// input2B.setAttribute("type","number")
// input2B.setAttribute("name","groupID")
// input2B.setAttribute("value",b[1])
// span2B.appendChild(input2B)
// modalrow2.appendChild(span2A)
// modalrow2.appendChild(span2B)
// let del = document.createElement("p")
// del.innerText = "DELETE"
// del.setAttribute("onclick","this.parentElement.remove()")
// modalrow2.appendChild(del)
// elem3.appendChild(modalrow2)
}
// else{
// modalrow2 = document.createElement("div")
// modalrow2.setAttribute("class","modal_row")
// }
add = document.createElement("p")
add.setAttribute("id","adder")
add.innerText = "ADD NEW"
add.setAttribute("onclick","this.remove();AddBL(this)")
elem3.appendChild(add)
elem4.setAttribute("id","gapper")
modalrow1 = document.createElement("div")
modalrow1.setAttribute("class","modal_row")
let title4A = document.createElement("span")
let title4B = document.createElement("span")
let title4B1 = document.createElement("span")
let title4B2 = document.createElement("span")
title4B1.setAttribute("class","half")
title4B2.setAttribute("class","half")
title4A.innerText = "series ID"
title4B1.innerText = "Gap start"
title4B2.innerText = "Gap end"
title4B.appendChild(title4B1)
title4B.appendChild(title4B2)
modalrow1.appendChild(title4A)
modalrow1.appendChild(title4B)
elem4.appendChild(modt3)
elem4.appendChild(modalrow1)
if(gap.length) for(let g of gap){
let modalrow2 = document.createElement("div")
modalrow2.setAttribute("class","modal_row")
let span2A = document.createElement("span")
let input2A = document.createElement("input")
input2A.setAttribute("type","number")
input2A.setAttribute("name","mangaIDgap")
input2A.setAttribute("value",g[0])
span2A.appendChild(input2A)
let span2B = document.createElement("span")
let span2B1 = document.createElement("span")
let span2B2 = document.createElement("span")
let input2B1 = document.createElement("input")
input2B1.setAttribute("type","number")
input2B1.setAttribute("class","half")
input2B1.setAttribute("name","gap1")
input2B1.setAttribute("value",g[1][0])
span2B.appendChild(input2B1)
span2B2 = document.createElement("span")
let input2B2 = document.createElement("input")
input2B2.setAttribute("type","number")
input2B2.setAttribute("class","half")
input2B2.setAttribute("name","gap2")
input2B2.setAttribute("value",g[1][1])
span2B.appendChild(input2B2)
modalrow2.appendChild(span2A)
modalrow2.appendChild(span2B)
let del = document.createElement("p")
del.innerText = "DELETE"
del.setAttribute("onclick","this.parentElement.remove()")
modalrow2.appendChild(del)
elem4.appendChild(modalrow2)
}
// else{
// modalrow2 = document.createElement("div")
// modalrow2.setAttribute("class","modal_row")
// }
add = document.createElement("p")
add.setAttribute("id","adder")
add.innerText = "ADD NEW"
add.setAttribute("onclick","this.remove();AddGap(this)")
elem4.appendChild(add)
form.appendChild(elem1)
form.appendChild(elem2)
form.appendChild(elem3)
form.appendChild(elem4)
modal.appendChild(form)
buttons = document.createElement("div")
modbut.setAttribute("onclick","UpdateValues()")
modbut.innerText = "Save Changes & Reload"
modbut.setAttribute("style","margin:auto;width:30%;display:block;")
buttons.appendChild(modbut)
canbut.setAttribute("onclick","CloseThis()")
canbut.innerText = "Exit without Saving Changes"
canbut.setAttribute("style","margin:auto;width:30%;display:block;")
buttons.appendChild(canbut)
form.appendChild(buttons)
document.querySelector("body").appendChild(modal)
}
function NewRow1(){
let modalrow2 = document.createElement("div")
modalrow2.setAttribute("class","modal_row")
let span2A = document.createElement("span")
let input2A = document.createElement("input")
input2A.setAttribute("type","number")
input2A.setAttribute("name","mangaID")
input2A.setAttribute("value",0)
span2A.appendChild(input2A)
let span2B = document.createElement("span")
let input2B = document.createElement("input")
input2B.setAttribute("type","number")
input2B.setAttribute("name","groupID")
input2B.setAttribute("value",0)
span2B.appendChild(input2B)
modalrow2.appendChild(span2A)
modalrow2.appendChild(span2B)
let del = document.createElement("p")
del.innerText = "DELETE"
del.setAttribute("onclick","this.parentElement.remove()")
modalrow2.appendChild(del)
return modalrow2
}
function NewRow2(){
let modalrow2 = document.createElement("div")
modalrow2.setAttribute("class","modal_row")
let span2A = document.createElement("span")
let input2A = document.createElement("input")
input2A.setAttribute("type","number")
input2A.setAttribute("name","mangaIDgap")
input2A.setAttribute("value",0)
span2A.appendChild(input2A)
let span2B = document.createElement("span")
let span2B1 = document.createElement("span")
let span2B2 = document.createElement("span")
let input2B1 = document.createElement("input")
input2B1.setAttribute("type","number")
input2B1.setAttribute("class","half")
input2B1.setAttribute("name","gap1")
input2B1.setAttribute("value",0)
span2B.appendChild(input2B1)
span2B2 = document.createElement("span")
let input2B2 = document.createElement("input")
input2B2.setAttribute("type","number")
input2B2.setAttribute("class","half")
input2B2.setAttribute("name","gap2")
input2B2.setAttribute("value",0)
span2B.appendChild(input2B2)
modalrow2.appendChild(span2A)
modalrow2.appendChild(span2B)
let del = document.createElement("p")
del.innerText = "DELETE"
del.setAttribute("onclick","this.parentElement.remove()")
modalrow2.appendChild(del)
return modalrow2
}
function NewButton(ToDo){
add = document.createElement("p")
add.setAttribute("id","adder")
add.setAttribute("onclick",ToDo)
add.innerText = "ADD NEW"
return add
}
document.Show = function(){
modalX.style.display = "block";
}
document.CloseThis = function(){
modalX.style.display = "none";
}
document.AddWL = function(element){
element.remove()
elem2.appendChild(NewRow1())
elem2.appendChild(NewButton("this.remove();AddWL(this)"))
}
document.AddBL = function(element){
element.remove()
elem3.appendChild(NewRow1())
elem3.appendChild(NewButton("this.remove();AddBL(this)"))
}
document.AddGap = function(element){
element.remove()
elem4.appendChild(NewRow2())
elem4.appendChild(NewButton("this.remove();AddGap(this)"))
}
document.UpdateValues = function() {
log("Updating")
var elements = document.getElementById("ScriptForm").children;
log(elements)
enhance = document.getElementById("ScriptForm").getElementsByTagName("input")[0].checked
obj1 =[];
obj2 =[];
obj3 =[];
let wl = elements[1].getElementsByClassName("modal_row")
let bl = elements[2].getElementsByClassName("modal_row")
let gl = elements[3].getElementsByClassName("modal_row")
for(let i = 1; i < wl.length; i++){
let inputs = wl[i].getElementsByTagName("input")
obj1.push([inputs.mangaID.value*1,inputs.groupID.value*1])
}
for(let i = 1; i < bl.length; i++){
let inputs = bl[i].getElementsByTagName("input")
obj2.push([inputs.mangaID.value*1,inputs.groupID.value*1])
}
for(let j = 1; j < gl.length; j++){
let spans = gl[j].getElementsByTagName("input")
obj3.push([spans.mangaIDgap.value*1,[spans.gap1.value*1,spans.gap2.value*1]])
}
// localStorage.setItem('whitelist',JSON.stringify(obj1));
// localStorage.setItem('blacklist',JSON.stringify(obj2));
// localStorage.setItem('gap',JSON.stringify(obj3));
localStorage.setItem('enhance',JSON.stringify(enhance))
dbUpdate("whitelist",obj1)
dbUpdate("blacklist",obj2)
dbUpdate("gap",obj3)
location.reload()
}