// ==UserScript==
// @name copymanga-自动存储浏览记录
// @namespace http://tampermonkey.net/
// @description 自动存储拷贝漫画的浏览记录,以防拷贝卷记录跑路。
// @version 1.1
// @author Y_jun
// @license MIT
// @icon https://hi77-overseas.mangafuna.xyz/static/free.ico
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// @match *://*.copymanga.com/*
// @match *://*.copymanga.org/*
// @match *://*.copymanga.net/*
// @match *://*.copymanga.info/*
// @match *://*.copymanga.site/*
// @match *://*.copymanga.tv/*
// @match *://*.mangacopy.com/*
// @match *://copymanga.com/*
// @match *://copymanga.org/*
// @match *://copymanga.net/*
// @match *://copymanga.info/*
// @match *://copymanga.site/*
// @match *://copymanga.tv/*
// @match *://mangacopy.com/*
// @run-at document-start
// ==/UserScript==
let changeTotal = 1; //1:完整保存浏览记录,0:只保存前几页
let offset = 0;
let limit = 25;
let total = 50;
let lastIndex = 1;
let token = 'Token xxxxxxx'
function sleep(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
function completeDate(value) {
return value < 10 ? "0" + value : value;
}
function getNowFormatTime() {
let nowDate = new Date();
let colon = ":";
let char = "-";
let day = nowDate.getDate();
let month = nowDate.getMonth() + 1;//注意月份需要+1
let year = nowDate.getFullYear();
let h = nowDate.getHours();
let m = nowDate.getMinutes();
let s = nowDate.getSeconds();
//补全0,并拼接
return year + char + completeDate(month) + char + completeDate(day) + " " + completeDate(h) + colon + completeDate(m) + colon + completeDate(s);
}
function addNotice() {
let button = document.createElement('button');
button.id = 'save-button';
button.style.marginLeft = '20px';
button.textContent = '开始保存完整记录';
button.onclick = () => {
button.className = 'allow-save-liulan';
}
let notice = document.createElement('span');
notice.id = 'save-liulan';
notice.style.marginLeft = '20px';
notice.textContent = '尚未保存浏览记录';
let collectActionArea = document.querySelector('.collectAction');
collectActionArea.appendChild(button)
collectActionArea.appendChild(notice);
}
function editNotice(text) {
let notice = document.getElementById('save-liulan');
notice.textContent = text;
}
function getPopularNum(popularStr) {
if (popularStr.indexOf('W') > -1) {
return Number(popularStr.substring(0, popularStr.length - 1)) * 10000;
}
if (popularStr.indexOf('K') > -1) {
return Number(popularStr.substring(0, popularStr.length - 1)) * 1000;
}
return Number(popularStr);
}
async function getLiulanList() {
const datetime = getNowFormatTime();
while (offset < total) {
if (!document.querySelector('.allow-save-liulan')) {
await sleep(2000);
continue;
}
editNotice('保存浏览记录中,进度:' + Math.round(offset / total * 10000) / 100 + "%");
GM_xmlhttpRequest({
method: "get",
url: `${window.location.origin}/api/kb/web/browses?limit=${limit}&offset=${offset}&free_type=1`,
data: "",
headers: {
"Content-Type": "application/json",
"Authorization": token,
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.160 Safari/537.36"
},
onload: res => {
if (res.status === 200) {
const response = JSON.parse(res.response);
if (response.code === 200) {
const results = response.results;
total = changeTotal === 1 ? results.total : total;
const mangaList = results.list;
mangaList.forEach((manga) => {
const uuid = manga.comic.uuid;
const authors = [];
if (Array.isArray(manga.comic.author)) {
const authorList = manga.comic.author;
authorList.forEach((author) => {
authors.push(author.name);
})
}
const mangaObj = {
"name": manga.comic.name,
"lastRead": manga.last_chapter_name,
"lastIndex": lastIndex,
"lastTime": datetime,
"lastChapter": manga.comic.last_chapter_name,
"updateTime": manga.comic.datetime_updated,
"popular": manga.comic.popular,
"authors": authors,
"path": manga.comic.path_word
}
lastIndex++;
GM_setValue(uuid, mangaObj);
});
} else {
editNotice('保存浏览记录出错');
console.log('code不为200:\n' + res);
total = 1;
}
} else {
editNotice('保存浏览记录出错');
console.log('status不为200:\n' + res);
total = 1;
}
},
onerror: () => {
console.log('读取浏览记录失败');
}
});
offset += limit;
await sleep(2000);
}
editNotice('保存完毕');
}
function getLastRead(path, count = 1) {
if (document.querySelector('.table-default') === null) {
if (count <= 50) {
const args = Array.from(arguments).slice(0, arguments.length);
args.push(count + 1);
setTimeout(getLastRead, 200, ...args);
}
return;
}
const name = document.querySelector('h6').textContent;
const updateArr = document.querySelector('.table-default-right').textContent.split('更新');
const lastChapter = updateArr[1].substring(3);
const updateTime = updateArr[2].substring(3);
const authors = document.querySelectorAll('.comicParticulars-right-txt')[1].innerHTML.match(/>[^<]+<\/a>/g);
for (let i = 0; i < authors.length; i++) {
const author = authors[i];
authors[i] = author.substring(1, author.length - 4);
}
const popularStr = document.querySelectorAll('.comicParticulars-right-txt')[2].innerText;
const popular = getPopularNum(popularStr);
GM_xmlhttpRequest({
method: "get",
url: `${window.location.origin}/api/v3/comic2/${path}/query?platform=1&_update=true`,
data: "",
headers: {
"Content-Type": "application/json",
"Authorization": token,
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.160 Safari/537.36"
},
onload: res => {
if (res.status === 200) {
const response = JSON.parse(res.response);
if (response.code === 200) {
const results = response.results;
if (results.browse) {
const mangaObj = {
"name": name,
"lastRead": results.browse.chapter_name,
"lastIndex": 0,
"lastTime": getNowFormatTime(),
"lastChapter": lastChapter,
"updateTime": updateTime,
"popular": popular,
"authors": authors,
"path": path
}
GM_setValue(results.browse.comic_uuid, mangaObj);
}
} else {
console.log('code不为200:\n' + res);
}
} else {
console.log('status不为200:\n' + res);
}
},
onerror: () => {
console.log('读取最近阅读失败');
}
});
}
window.onload = function () {
const pathArr = window.location.pathname.split('/');
if (window.location.pathname === '/web/person/liulan') {
addNotice();
getLiulanList();
} else if (pathArr.length === 3 && pathArr[1] === 'comic') {
document.addEventListener('visibilitychange', () => {
getLastRead(pathArr[2].replace('#', ''));
});
}
}