// ==UserScript==
// @name 一键批量加载页面[EX绅士][exhentai]
// @namespace exhentaigetallpage
// @version 0.6.2
// @description 一键批量加载所有后续页面内容
// @author allence_frede
// @match *://exhentai.org/tag/*
// @match *://exhentai.org/*f_search*
// @match *://exhentai.org/g/*
// @grant none
// @require http://code.jquery.com/jquery-1.11.0.min.js
// @license GNU GPLv3
// ==/UserScript==
var exhentaiGetAllPage = function ($) {
let cfg = {
load_pages_in_once: 20,
all_page_count: 0,
load_page_count: 1,
load_page_url: [],
load_pages_at_first_open: false,
}
let db = null
return {
init: function () {
//去除购买广告入口
$('#spa').remove()
//初始化
initTool()
initDB()
let cfg_old = get('load_pages_in_once')
if (Object.keys(cfg_old)) {
Object.assign(cfg, cfg_old)
}
cfg_old = get('load_pages_at_first_open')
if (Object.keys(cfg_old)) {
cfg_old.load_pages_at_first_open = cfg_old.load_pages_at_first_open ? cfg_old.load_pages_at_first_open.bool() : false
Object.assign(cfg, cfg_old)
}
loadPanel()
openInNewTab(null)
setNewCss()
autoLoadPage()
},
pageLoadMore: function () {
pageLoadMore()
},
pageViewSwitch: function () {
pageViewSwitch()
},
autoLoadPageBtnText: function () {
return autoLoadPageBtnText
}
}
/**
* 获取功能按钮文字-首次打开自动加载后续页面
*/
function autoLoadPageBtnText() {
return cfg.load_pages_at_first_open ? '开启首次打开自动加载' : '关闭首次打开自动加载'
}
/**
* 开关首次打开自动加载后续页面
*/
function setAutoLoadPageAtFirst() {
cfg.load_pages_at_first_open = !cfg.load_pages_at_first_open
set('load_pages_at_first_open', cfg.load_pages_at_first_open)
}
/**
* 加载页面时识别首次打开自动加载后续页面
*/
function autoLoadPage() {
if(cfg.load_pages_at_first_open){
pageLoadMore()
}
}
/**
* 注入面板
*/
function loadPanel() {
setPageAllCount()
setPageNow()
setLoadPageUrlList()
setPanelEl()
setPanelCss()
setMethod()
}
/**
* 读取可加载总页数
*/
function setPageAllCount() {
let num = $('table.ptt td').eq(-2).text()
cfg.all_page_count = Number(num)
}
/**
* 设置当前读取的页数
*/
function setPageNow() {
let count = 1
let count1 = /page=(\d+)|p=(\d+)/.exec(window.location.href)
let count2 = /\/(\d+)$/.exec(window.location.pathname)
if (!count1 && !count2) {
return false
} else if (count1) {
if (count1[1]) {
count = count1[1]
}
if (count1[2]) {
count = count1[2]
}
} else if (count2) {
count = count2[1]
}
cfg.load_page_count = Number(count) + 1
}
/**
* 设置加载页面URL列表
*/
function setLoadPageUrlList() {
let url_list = []
if (cfg.all_page_count > 1) {
let url_base = ''
if (/\/tag\//.test(window.location.href)) {
url_base = window.location.href.replace(/\/\d+$|\/\d+\?from=.*$/,'')+'/{p}'
} else {
let glup = '?'
if(window.location.href.indexOf(glup) !== false) {
glup = '&'
}
url_base = window.location.href + glup + 'p={p}&page={p}'
}
for (let i = cfg.load_page_count; i < cfg.all_page_count; i++) {
url_list.push(url_base.replaceAll('{p}', i))
}
url_list = url_list.chunk(cfg.load_pages_in_once)
}
cfg.load_page_url = url_list
}
/**
* 设置面板界面
*/
function setPanelEl() {
let el = '<div id="egap">\
<div class="item" method="pageLoadMore">一键加载后续<span id="page-load">' + cfg.load_pages_in_once + '</span>个页面</div>\
<div class="item page-info cursor-clear">当前已加载 \
<span class="page-now">' + cfg.load_page_count + '</span> / ' + cfg.all_page_count + '\
</div>\
<div class="item" method="pageViewSwitch">图墙列表倒序</div>\
<div class="item" method="goToTop">回到顶部</div>\
<div class="item" method="setLoadPagesInOnce" value="设置每次加载后续页数">设置每次加载后续页数</div>\
<div class="item" method="setAutoLoadPageAtFirst">'+autoLoadPageBtnText()+'</div>\
</div>'
$('body').prepend(el)
}
/**
* 设置面板样式
*/
function setPanelCss() {
let css = '<style>\
#egap{\
position: fixed;\
top:10px;\
left:10px;\
z-index: 5000;\
opacity: 0.3;\
-webkit-user-select:none;\
-moz-user-select:none;\
-ms-user-select:none;\
user-select:none;\
}\
#egap:hover{\
opacity:1;\
}\
#egap .item{\
min-width:120px;\
height:30px;\
line-height:30px;\
color:#EEEEEE;\
background: #4f535b;\
border: 1px solid #000000;\
text-align: center;\
font-size:14px;\
cursor:pointer;\
box-sizing: border-box;\
padding: 0 6px;\
margin-top: 10px;\
}\
#egap #newLoadPagesInOnce{\
width: 120px;\
}\
#egap .cursor-clear{\
cursor: default !important;\
}\
</style>'
$('body').append(css)
}
/**
* 面板绑定触发方法
*/
function setMethod() {
$('div[method="pageLoadMore"]').on('click', function () {
pageLoadMore()
})
$('div[method="pageViewSwitch"]').on('click', function () {
pageViewSwitch()
})
$('div[method="goToTop"]').on('click', function () {
goToTop()
})
$('div[method="setLoadPagesInOnce"]').on('dblclick', function () {
$(this).html('<input type="number" id="newLoadPagesInOnce">')
$('input#newLoadPagesInOnce').on('blur', function () {
let num = $(this).val()
if (num) {
var re = /^[0-9]+$/ ;
if (re.test(num)) {
num = Number(num)
if (num <= 0) {
alert('至少填写 1 !!!')
} else {
setLoadPagesInOnce(num)
$('div[method="setLoadPagesInOnce"]').html($('div[method="setLoadPagesInOnce"]').attr('value'))
}
} else {
alert('请输入一个正整数!!!')
}
} else {
$('div[method="setLoadPagesInOnce"]').html($('div[method="setLoadPagesInOnce"]').attr('value'))
}
})
})
$('div[method="setAutoLoadPageAtFirst"]').on('dblclick', function () {
setAutoLoadPageAtFirst()
$(this).text(autoLoadPageBtnText())
})
}
/**
* 设置新的样式效果
* 主要用于适配 高分辨屏幕 和 竖屏
*/
function setNewCss() {
$('#gdt .c').remove()
let style = '\
<style type="text/css">\
#gdt{\
max-width: none !important;\
display: grid !important;\
}\
@media screen and (max-width:2200px) and (min-width:1080px) {\
.ido{\
max-width: 100% !important;\
}\
.gdtl {\
width: auto !important;\
max-width: 239px !important;\
min-width: 214px !important;\
}\
.gld {\
display: grid;\
grid-template-columns:repeat(5,1fr)\
}\
}\
@supports(display: grid) {\
@media screen and (min-width:2171px) and (max-width:2611px){\
.gld {\
grid-template-columns:repeat(8,1fr) !important;\
}\
#gdt {\
grid-template-columns:repeat(10,1fr) !important;\
}\
}\
@media screen and (min-width:1951px) and (max-width:2171px) {\
.gld {\
grid-template-columns:repeat(7,1fr) !important;\
}\
#gdt {\
grid-template-columns:repeat(9,1fr) !important;\
}\
}\
@media screen and (min-width:1740px) and (max-width:1951px) {\
.gld {\
grid-template-columns:repeat(6,1fr) !important;\
}\
#gdt {\
grid-template-columns:repeat(8,1fr) !important;\
}\
}\
@media screen and (min-width:1531px) and (max-width:1740px) {\
.gld {\
grid-template-columns:repeat(5,1fr) !important;\
}\
#gdt {\
grid-template-columns:repeat(7,1fr) !important;\
}\
}\
@media screen and (min-width:1360px) and (max-width:1531px) {\
.gld {\
grid-template-columns:repeat(5,1fr) !important;\
}\
#gdt {\
grid-template-columns:repeat(5,1fr) !important;\
}\
}\
@media screen and (min-width:1080px) and (max-width:1360px) {\
.gld {\
grid-template-columns:repeat(4,1fr) !important;\
}\
#gdt {\
grid-template-columns:repeat(5,1fr) !important;\
}\
}\
@media screen and (min-width:0px) and (max-width:1080px) {\
.gld {\
grid-template-columns:repeat(4,1fr) !important;\
}\
#gdt {\
grid-template-columns:repeat(4,1fr) !important;\
}\
}\
}\
</style>'
style = $(style);
$("body").append(style);
}
/**
* 读取下一页
*/
function pageLoadMore() {
if (cfg.load_page_url.length > 0) {
let url_list = cfg.load_page_url[0]
for (let url of url_list) {
getDataList(url.webApi())
}
cfg.load_page_url.shift()
}
}
/**
* 列表是否倒序显示
*/
function pageViewSwitch() {
let clear = ''
// 结果页倒序
if ($('.gl1t').length) {
let lists = $('.gl1t').toArray().reverse()
$('.itg.gld').empty()
for (let i in lists) {
$('.itg.gld').append(lists[i])
}
$('.itg.gld').append(clear)
}
// 详情页倒序
if ($('.gdtl').length) {
let lists = $('.gdtl').toArray().reverse()
$('#gdt').empty()
for (let i in lists) {
$('#gdt').append(lists[i])
}
$('.itg.gld').append(clear)
}
}
/**
* 从网页内容解析出数据列表
* @param string content 文本内容
*/
function getDataList(content) {
let target_in_detail = content.match(/<div id="gdt">(.*)<div class="c"><\/div><\/div><div class="gtb">/)
let target_in_gallery = content.match(/<div class="itg gld">(.*)<\/div><table class="ptb"/)
if (target_in_detail) {
let target = openInNewTab(target_in_detail[1])
$('#gdt').append(target)
setLoadPageCount()
}
if (target_in_gallery) {
let target = openInNewTab(target_in_gallery[1])
$('.itg.gld').append(target)
setLoadPageCount()
}
}
/**
* 在新窗口打开结果/图片
* @param string el 查询结果字符串
*/
function openInNewTab(el) {
if (el === null) {
$('.gl1t a,.gdtl a').attr('target', '_blank')
return true
}
el = el.replaceAll('<a', '<a target="_blank"')
return el
}
/**
* 回到顶部
*/
function goToTop() {
$('html , body').animate({scrollTop: 0},'fast');
}
/**
* 设置当前读取的页面数
*/
function setLoadPageCount() {
cfg.load_page_count += 1
$('.page-now').text(cfg.load_page_count)
}
/**
* 设置一次性读取的后续页数
* @param number num 新数值
*/
function setLoadPagesInOnce(num) {
cfg.load_pages_in_once = num
$('#page-load').text(cfg.load_pages_in_once)
set('load_pages_in_once', cfg.load_pages_in_once)
}
/**
* 注入工具函数
*/
function initTool() {
String.prototype.bool = function() {
return (/^true$/i).test(this)
}
// 数组分块
Array.prototype.chunk = function (n) {
let l = this.length
if (l === 0) return []
if (l > n) {
let chunks = []
for(let i=0; i<l; i=i+n){
chunks.push(this.slice(i, i+n));
}
return chunks
} else {
return [this]
}
}
// 网络请求函数
String.prototype.webApi = function () {
let res = null
$.ajaxSettings.async = false
$.get(this, function (response) {
res = response
})
return res
}
}
/**
* 初始化本地数据库
*/
function initDB() {
if (db === null) {
if (!window.localStorage) {
console.error('本浏览器不支持 IndexedDB')
return false
}
db = window.localStorage
return true
}
return true
}
/**
* 读取数据
*/
function get(name = null) {
let all = {}
if (name) {
all[name] = db[name]
} else {
for (const k in window.localStorage) {
all[k] = window.localStorage[k]
}
}
return all
}
/**
* 添加数据
* @param string name 配置名
* @param string content 配置值
*/
function set(name, content) {
localStorage.setItem(name, content);
}
}(jQuery)
// 执行初始化
exhentaiGetAllPage.init()