// ==UserScript==
// @name Mananelo/Mangakakalot/Manganato/Manga4life Bookmarks Export
// @namespace http://smoondev.com/
// @version 2.26
// @description Writes Mangakakalot, Manganelo, Manganato, Manga4life Bookmarks (name and visited number) to "manga_bookmarks.txt" on "Export Bookmarks" button click
// @author Shawn Moon
// @match https://mangakakalot.com/bookmark*
// @match https://*.manganelo.com/bookmark*
// @match https://manga4life.com/user/bookmark.php
// @match https://manga4life.com/user/subscription.php
// @match https://manganato.com/bookmark*
// @match https://mangakakalot.fun/user/bookmarks
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.min.js
// ==/UserScript==
function addBookarkStyles(css) {
var head, style;
head = document.getElementsByTagName('head')[0];
if (!head) { return; }
style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = css;
head.appendChild(style);
}
addBookarkStyles(`
#export_container_nato, #export_container_kakalot, #export_container_m4l {
color: #000;
cursor: pointer;
float: right;
}
#export_container_fun {
display: inline-block;
vertical-align: bottom;
}
#export_container_kakalot {
margin-right: 10px;
}
#export_nato:hover, #export_kakalot:hover, #export_m4l:hover {
background-color: #b6e4e3;
color: #000;
cursor: pointer;
}
#export_nato, #export_kakalot, #export_m4l {
border-radius: 5px;
text-decoration: none;
color: #fff;
background-color: #76cdcb;
border: none;
font-weight: 600;
}
#export_nato, #export_kakalot {
padding: 4px 8px;
}
#export_m4l {
padding: 1px 12px;
font-size: 16.5px;
}
#export_fun {
color: #f05759;
background-color: #fff;
border: 1px solid #f05759;
display: inline-block;
margin-bottom: 0;
font-weight: 400;
text-align: center;
touch-action: manipulation;
cursor: pointer;
white-space: nowrap;
padding: 6px 12px;
border-radius: 0;
user-select: none;
transition: all .2s ease-in-out;
}
#export_fun:hover {
color: #fff;
background-color: #f05759;
}
#inclURL_nato, #inclURL_kakalot, #inclURL_fun, #inclURL_m4l {
margin-left: 10px;
}
.inclURL_kakalot, .inclURL_m4l {
color: #ffffff;
}
.inclURL_m4l {
color: #ffffff;
font-size: 15px;
font-weight: 500;
}
.inclURL_fun {
font-weight:normal;
}
#temp_data {
position: absolute; top: -9999px;
left: -9999px;
}
`);
(async function() {
'use strict';
let pageI, bmTag, bmTitle, lastViewed, btnContainer, exportButtonID, inclURL, bookmarkedTitles = '',
exportContainer, pageCount = 0, domain = window.location.hostname, bmLabel = 'Bookmarks'
if(domain == 'mangakakalot.com') {
pageI = '.group_page a'
bmTag = '.bookmark_item'
bmTitle = '.bookmark_title'
lastViewed = '.bookmark_chap a'
btnContainer = '.breadcrumbs p'
inclURL = 'inclURL_kakalot'
pageCount = parseInt($(`${pageI}`).last().text().replace(/\D+/g, ''))
exportButtonID = 'export_kakalot'
exportContainer = 'export_container_kakalot'
} else if(domain == 'manganato.com' || domain == 'm.manganelo.com') {
btnContainer = '.panel-breadcrumb'
inclURL = 'inclURL_nato'
exportButtonID = 'export_nato'
exportContainer = 'export_container_nato'
} else if (domain == 'mangakakalot.fun') {
bmTag = '.list-group-item'
bmTitle = '.media-heading a'
lastViewed = '.media-body p a'
btnContainer = '.container-fluid:first div:last'
inclURL = 'inclURL_fun'
exportButtonID = 'export_fun'
exportContainer = 'export_container_fun'
} else if (domain == 'manga4life.com') {
inclURL = 'inclURL_m4l'
exportButtonID = 'export_m4l'
btnContainer = '.BoxHeader'
exportContainer = 'export_container_m4l'
if(!window.location.pathname.includes('bookmark.php')) {
bmLabel = 'Subscriptions'
}
}
const waitFor = delay => new Promise(resolve => setTimeout(resolve, delay));
const saveFile = saveData => {
// save file
const fileData = new Blob([saveData], {type:"application/octet-stream"})
saveAs(fileData, "manga_bookmarks.txt")
$(`#${exportButtonID}`).html(`Export ${bmLabel}`).prop('disabled', false)
}
const deleteTemp = () => {
// delete temp container
$('#temp_data').remove()
}
const getCookie = (name = 'user_acc') => {
let returnVal = false
const value = `; ${document.cookie}`
try {
const parts = value.split(`; ${name}=`)
if (parts.length === 2) {
let user = parts.pop().split(';').shift()
if(name == 'user_acc') {
user = JSON.parse(decodeURIComponent(user))
returnVal = user.user_data
}
}
} catch (e) {
returnVal = false
}
return returnVal
}
const getBMs = async (userCookie, currentPage = 1) => {
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
var urlencoded = new URLSearchParams();
urlencoded.append("out_type", "json");
urlencoded.append("bm_source", "manganato");
urlencoded.append("bm_page", currentPage);
urlencoded.append("user_data", userCookie);
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow'
};
let bmArray = []
return await fetch("https://user.mngusr.com/bookmark_get_list_full", requestOptions)
.then(response => response.json())
.then(result => result)
.catch(error => console.log('ExportError', error));
}
const getFunBMs = (url) => {
let bmItems = $(`${bmTag}`)
for(let i = 0; i < bmItems.length; i++) {
let title = $(bmItems[i]).find(bmTitle)[0]?.text || false
let lastViewed = $(bmItems[i]).find('.media-body p a')[0] || false
bookmarkedTitles += `${title} || Viewed: ${lastViewed ? lastViewed.text : 'None'} ${url ? (lastViewed ? `- ${lastViewed.href}` : '') : ''} \n`
}
saveFile(bookmarkedTitles)
}
const getM4LBMs = (url) => {
var myHeaders = new Headers();
let userCookie = document.cookie
myHeaders.append("cookie", userCookie);
var urlencoded = new URLSearchParams();
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow'
};
let isM4LBM = window.location.pathname.includes('bookmark.php')
fetch(`https://manga4life.com/user/${isM4LBM ? 'bookmark.get.php' : 'subscription.get.php'}`, requestOptions)
.then(response => response.json())
.then(result => {
let {success = false, val = []} = result
let lastViewedArr = []
if(success && val.length) {
if(!isM4LBM) {
let lastViewed = $('script:last')
if(lastViewed[0]) {
let regex = /(?<=vm\.LastChapterRead\s=)(.*)(?=;)/g
let match = lastViewed[0].innerText.match(regex)
if(match.length) {
lastViewedArr = JSON.parse(match[0])
}
}
}
for(let i = 0; i < val.length; i++) {
let indexStr = '', readStatus = false
let chapter = isM4LBM ? val[i].Chapter : '1'
if(!isM4LBM) {
for(let j = 0; j < lastViewedArr.length; j++){
if(lastViewedArr[j].SeriesID == val[i].SeriesID){
chapter = lastViewedArr[j].Chapter;
}
}
let indexTest = chapter.substring(0, 1);
if(indexTest > 0 && indexTest != 1){
indexStr = "-index-"+indexTest;
}
if(val[i].ReadStatus == "1"){
readStatus = "Reading";
} else if(val[i].ReadStatus == "2"){
readStatus = "Finished";
} else if(val[i].ReadStatus == "3"){
readStatus = "On-hold";
} else if(val[i].ReadStatus == "4"){
readStatus = "Dropped";
} else if(val[i].ReadStatus == "5"){
readStatus = "Plan to read";
}
}
let chapterStr = parseInt(chapter.slice(1, -1)) || 1
let page = val[i].Page == '0' ? 1 : `-page-${val[i].Page}`
let link = `https://manga4life.com/read-online/${val[i].IndexName}-chapter-${chapterStr}${indexStr}${isM4LBM ? page : ''}.html`
bookmarkedTitles += `${val[i].SeriesName} ${readStatus ? `|| Status: ${readStatus}` : ''} || Viewed: ${chapterStr} ${url ? `- ${link}` : ''} \n`
}
saveFile(bookmarkedTitles)
}
})
.catch(error => console.log('error', error));
}
if($(`${exportContainer}`).length === 0){
$(`${btnContainer}`).append(`<div id='${exportContainer}'><button id='${exportButtonID}'>Export ${bmLabel}</button><input type="checkbox" id="${inclURL}"><span style="margin-left: 5px;"><label for="${inclURL}" class='${inclURL}'>Add URL</span></label></div>`)
}
const getBookmarks = (url) => {
// main function generate file
deleteTemp()
$('body').append("<div id='temp_data'>")
let pageSuccess = 0;
let bookmarkedTitles = bookmarkHeader
for(let i = 0; i < pageCount; i++) {
$("#temp_data").append(`<div id='page${i+1}'>`)
$(`#page${i+1}`).load(`https://${domain}/bookmark?page=${i+1} ${bmTag}`, (resp,status,xhr) => {
if(status == "success") { pageSuccess++ }
if(pageSuccess == pageCount) {
let bmItem = $(`#temp_data ${bmTag}`)
for(let j = 0; j < bmItem.length; j++) {
if($(bmItem[j]).find(`${bmTitle}`).text()) {
let last_viewed = $(bmItem[j]).find(`${lastViewed}`),
bookmarked_title = $(bmItem[j]).find(`${bmTitle}`);
if(bookmarked_title.length > 0) {
bookmarkedTitles += $(bmItem[j]).find(`${bmTitle}`).text() + ` || Viewed: ${last_viewed.length > 0 ? last_viewed[0].text : 'Not Found' } ${url ? `- ${last_viewed[0].href}` : ''} \n`
}
}
}
saveFile(bookmarkedTitles)
deleteTemp()
}
})
}
}
$(`#${exportButtonID}`).on('click', async function() {
let bookmarkHeader = `===========================\n${domain} ${bmLabel}\n===========================\n`
bookmarkedTitles = bookmarkHeader
let inclURLCheck = $(`#${inclURL}`).is(':checked');
if(domain == 'mangakakalot.com') {
$(this).html('Generating File...').prop('disabled', true)
getBookmarks(inclURLCheck)
} else if(domain == 'manganato.com' || domain == 'm.manganelo.com') {
let userData = getCookie()
if(userData) {
$(this).html('Generating File...').prop('disabled', true)
let initBMFetch = await getBMs(userData)
pageCount = initBMFetch.bm_page_total || 0
if(pageCount > 0) {
for(let i = 1; i <= pageCount; i++) {
let currPage = await getBMs(userData, i)
let currPageBMs = currPage.data
for(let j = 0; j < currPageBMs.length; j++) {
bookmarkedTitles += `${currPageBMs[j].note_story_name} || Viewed: ${currPageBMs[j].chapter_namenow} ${inclURLCheck ? `- ${currPageBMs[j].link_chapter_now}` : ''} \n`
}
}
saveFile(bookmarkedTitles)
}
}
} else if (domain == 'mangakakalot.fun') {
getFunBMs(inclURLCheck)
} else if (domain == 'manga4life.com') {
getM4LBMs(inclURLCheck)
}
})
})();