// ==UserScript==
// @name hitomi.la 小优化
// @namespace https://greasyfork.org/zh-CN/users/200067#1
// @version 1.88
// @description 优化在线阅读,分包下载,资源下载加速,标题自动换行,标签汉化,点击预览图新标签页打开,非搜索增加选页功能,
// @author 不会英语会写点代码的小白
// @match https://hitomi.la/*
// @run-at document-body
// @grant unsafeWindow
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_xmlhttpRequest
// @connect mirror.ghproxy.com
// @connect githubusercontent.com
// @connect github.com
// @connect download.fastgit.org
// @connect gh.gh2233.ml
// ==/UserScript==
let $;
let main=()=>{
'use strict'
if(!$){
if(window.load_ehtagtranslation_db_text)return;
window.load_ehtagtranslation_db_text=(json)=>{
if(!$){
setTimeout(window.load_ehtagtranslation_db_text,100,json);
return;
}
let array=json.data
json={}
for(let j of array) json[j.namespace]=j;
array=null;
let a=$('.gallery-content > div');
//if(!a.length)return;
newStyle:{addNewStyle(`
nav > ul > li#lang > a {
padding: 10px 70px 10px 15px;
}
.gallery-content > div > h1.lillie {
white-space: normal;
}
@media (max-width : 768px) {
.dj-img-cont{
position: sticky;
}
}
`);}
a.find('a.lillie').attr('target','_blank');
if(document.body.clientWidth<769){
let paddingTop=(document.body.clientWidth==768?'35px':'6px');
a.each((index,el)=>{
let d=el.querySelector('a.lillie');
el.removeChild(d);
el=el.querySelector('div.dj-content');
el.style.paddingTop=paddingTop;
el.prepend(d);
});
}
//增加选页功能
a=document.querySelector('.gallery-content');
if(location.pathname!='/search.html'){
let aa=document.querySelector('.page-container');
if(aa){
a.parentNode.insertBefore(aa.cloneNode(true),a);
}
}
let aliasMap = {
'loli':'lolicon',
'shota':'shotacon'
}
let alias=(str)=>{
let str2=aliasMap[str];
return str2?str2:str.toLowerCase();
}
let translateList=['female','male','other','mixed','artist','character','cosplayer','group','parody'];
let reg=/^(.+)( [♀♂])/
let each_fun=(index,el)=>{
let obj=reg.exec(el.innerHTML),str;
if(obj){
str=obj[2]==' ♀'?'female':'male';
let map=json[str].data[alias(obj[1])];
if(map){
el.title=map.intro;
el.innerHTML=map.name+obj[2];
return;
}
el.innerHTML=obj[1];
}
let str2=alias(el.innerHTML);
for(let val of translateList){
if(val != str){
obj=json[val].data[str2];
if(obj){
el.title=obj.intro;
el.innerHTML=obj.name+(str?str:val=='female'?'♀':val=='male'?'♂':'');
break;
}
}
}
}
let dlbt=$('#dl-button');
T1:{
let TMap={
'tags':'标签',
'artists':'艺术家',
'series':'原作',
'characters':'角色',
'language':'语言',
'type':'类型',
'group':'团队',
}
let each_fun2=(index,el)=>{
el.title=el.innerHTML;
let str=TMap[el.innerHTML.toLowerCase()];
if(str)el.innerHTML=str;
}
$('.dj-content td.relatedtags a').each(each_fun); //列表的标签
$('.dj-content tr > td:nth-of-type(1)').each(each_fun2); //列表的行名
if(dlbt.length){
$('.gallery-info ul#tags a').each(each_fun); //详情页的标签
translateList.splice(5,1);
translateList.unshift('character');
$('.gallery-info ul#characters a').each(each_fun); //详情页的角色
$('.gallery-info tr > td:nth-of-type(1)').each(each_fun2); //详情页的行名
}
//工具栏
$('nav > ul > li > a[href]').each(each_fun2);
let el=$('nav > ul > li#lang > a');
if(el.length){
el.html(el.children());
el.prepend('语言 ');
}
}
each_fun=(index,el)=>{
let str=alias(el.innerHTML),map;
for(let val of translateList){
map=json[val].data[str];
if(map){
el.innerHTML=map.name;
el.title=map.intro
break;
}
}
}
//原作
translateList=['parody'];
$('.dj-content tr:nth-of-type(1) > td:nth-of-type(2) a').each(each_fun);
if(dlbt.length){
$('.gallery-info tr:nth-of-type(4) > td:nth-of-type(2) a').each(each_fun);
translateList=['group']; //团队
$('.gallery-info tr:nth-of-type(1) > td:nth-of-type(2) a').each(each_fun);
}
//类型
translateList=['reclass'];
aliasMap={
'artist CG':'artistcg',
'game CG':'gamecg',
}
$('.dj-content tr:nth-of-type(2) > td:nth-of-type(2) a').each(each_fun);
if(dlbt.length){
let el=$('.gallery-info tr:nth-of-type(2) > td:nth-of-type(2)');
el.html('<a href="/type/'+el.html()+'-all.html">'+el.html()+'</a>');
el.find('a').each(each_fun);
}
/*
translateList=['language'];
aliasMap={'中文':'chinese'}
$('.dj-content tr:nth-of-type(3) > td:nth-of-type(2) a').each(each_fun);
if(dlbt.length)$('.gallery-info tr:nth-of-type(3) > td:nth-of-type(2) a').each(each_fun);
*/
}
let _limitLists=window.limitLists
window.limitLists=()=>{
_limitLists.apply(this,arguments);
if(!document.querySelectorAll('.gallery-content > div').length)return;
$=window.jQuery;
main();
}
let is_add_script=!0;
let xhr_onload=(r)=> {
if(!document.body){
setTimeout(xhr_onload,100,r);
return
}
if(is_add_script){
is_add_script=!1;
let data = r.response;
let URL_= window.URL || window.webkitURL || window;
let i= document.createElement('script');
i.type = 'text/javascript';
i.src=URL_.createObjectURL(data);
document.body.appendChild(i);
}
if(r.responseText){
GM_setValue('js_last_time',new Date().getTime());
GM_setValue('js_text',r.responseText);
}
}
let js_text=GM_getValue('js_text');
if(js_text){
xhr_onload({response:new Blob([js_text],{type: "application/x-javascript"})});
if(GM_getValue('js_last_time',0)+86400000>new Date().getTime())return;
}
let urls=[
'https://mirror.ghproxy.com/https://github.com/EhTagTranslation/Database/releases/latest/download/db.text.js',
'https://download.fastgit.org/EhTagTranslation/Database/releases/latest/download/db.text.js',
'https://gh.gh2233.ml/https://github.com/EhTagTranslation/Database/releases/latest/download/db.text.js',
'https://github.com/EhTagTranslation/Database/releases/latest/download/db.text.js'
];
let xhr={
method: 'GET',
responseType: "blob",
timeout : 5000,
onload: xhr_onload,
onerror :(er)=>{
xhr.url=urls.shift();
if(xhr.url)GM_xmlhttpRequest(xhr);
console.error(er);
}
}
xhr.ontimeout=xhr.onerror
xhr.onabort=xhr.onerror
xhr.url=urls.shift();
GM_xmlhttpRequest(xhr);
return
}
let dlbt=$('#dl-button');
if(!dlbt.length)return;
let galleryid=window.galleryid;
dlbt.attr('href','javascript:void(0);');
let files=window.galleryinfo.files,
files_length=files.length;
//下载按钮扩展
{
newStyle:{addNewStyle(`
.cover > a , #_div-dlP_ {
text-align: center;
display: block;
}
#_div-dlP_ span, #_div-dlP_ label, #_div-dlP_ input {
vertical-align: middle;
font-size: 14px;
}
.gallery-info > table {
table-layout: fixed;/*限制tag长度*/
}
`);}
let div1=$('<div id="_div-dlP_" style="line-height: 25px;"/>');
let in2,in1,rd2,rd3,in3,rd4,rd5;
div1.append([
in2=$('<span>下载并发数:</span><input type="number" style="width:38px" id="_in2_"/>'),
'<input type="radio" name="_radio1_" style="" id="_rd1_"/><label for="_rd1_">分包下载数:</label>',
in1=$('<input type="number" style="width:38px;" id="_in1_"/>'),
rd2=$('<br/><input type="radio" name="_radio1_" style="margin-left:4px;" id="_rd2_"/><label for="_rd2_">不打包下载</label>'),
rd3=$('<input type="radio" name="_radio1_" style="margin-left:4px;" id="_rd3_"/><label for="_rd3_">按大小分包:</label>'),
in3=$('<input type="number" style="width:55px" id="_in3_"/><span>M</span>'),
rd4=$('<br/><span>图片格式:</span><input type="radio" name="_radio2_" style="margin-left:4px;" id="_rd4_" v="1"/><label for="_rd4_">webp</label>'),
rd5=$('<input type="radio" name="_radio2_" style="margin-left:4px;" id="_rd5_" v="2"/><label for="_rd5_">avif</label>')
]);
in2=in2.eq(1),rd2=rd2.eq(1),rd3=rd3.eq(0),in3=in3.eq(0),rd4=rd4.eq(2),rd5=rd5.eq(0),
in1.val(GM_getValue('_in1_','1')),in2.val(GM_getValue('_in2_','1')),in3.val(GM_getValue('_in3_','1024'));
let rd_change=(e)=>{
let rd=$(e.target);
GM_setValue(rd.attr('name'),rd.attr('id'));
}
div1.find('input[type=radio][name=_radio1_]#'+GM_getValue('_radio1_','_rd1_')).attr("checked", "checked");
div1.find('input[type=radio][name=_radio1_]').on("change",rd_change);
div1.find('input[type=radio][name=_radio2_]#'+GM_getValue('_radio2_','_rd4_')).attr("checked", "checked");
div1.find('input[type=radio][name=_radio2_]').on("change",rd_change);
div1.find('input[type=number]').on("change",(e)=>{
let num=$(e.target);
GM_setValue(num.attr('id'),num.val());
});
let dlt=$('<span style="position:absolute;left:0px;right:0px;vertical-align:middle;"/>'),
progressbar =$('#progressbar');
progressbar.append(dlt);
progressbar.css({
'text-align': 'center',
'position': 'relative'
});
progressbar.after(div1);
var url_from_url_from_hash=(image)=>{
return window.url_from_url_from_hash(galleryid,image,rd4.is(':checked')?'webp':'avif', undefined, 'a');
}
var get_fileName=(image)=>{
return image.name.replace(/[^.]*$/, rd4.is(':checked')?'webp':'avif');
}
$('.gallery h1 a').parent().prepend('('+files_length+')');
const JSZip=window.JSZip;
window.download_gallery=function(galleryname){
let t=new Date().getTime();
if(!galleryname)galleryname='hitomi';
dlbt.hide();
dlt.html('0/'+files_length);
progressbar.show();
progressbar.progressbar({value: false});
let in2v=parseInt(in2.val()),
responseType,p=[],
rd2b=rd2.is(':checked'),
rd3b=rd3.is(':checked');
if(in2v<1)in2v=1;
if(rd2b){
responseType= 'blob'
}else{
responseType= 'arraybuffer'
JSZip.prototype.length=0;
var val_,ii4=0,ii2;
if(rd3b){
var max=0,ii7=1;
JSZip.prototype.max=0;
JSZip.prototype.size=0;
ii4=files_length-20;
val_=parseInt(in3.val());
val_=(val_<50?50:val_>2048?2048:val_)*1048576;//限制大小50M-2048M
}else if((val_=parseInt(in1.val()))>1){
ii2=1;
val_=parseInt(files_length/val_);
if(val_<50)val_=50;
ii4=parseInt(files_length/val_)-(files_length%val_<20?1:0);
}
var ii5=0,ii6=0,zipName=galleryname,pp,zip,zips = [new JSZip()];
}
function dl(url,index,isRetry){
new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState === 4) {
if (this.status === 200) {
resolve(this.response);
} else {
reject(`dl(${url}) failed, xhr.status: ${this.status}`);
}
}
}
xhr.open('GET', url);
xhr.responseType=responseType;
xhr.send();
}).then(re=>{
ii--;
re.index=index;
p.push(re);
dlt.html(p.length+'/'+files_length);
progressbar.progressbar('value',p.length/files_length*100);
}).catch(er=>{
if(isRetry){
setTimeout(dl,500,url,index,isRetry-1);
}
console.error(er);
});
}
let c=0,ii=0,ii3=0;
function dl2(){
do{
if(ii3<p.length){
pp=p[ii3];
delete p[ii3++];
if(rd2b){
saveAs(pp,galleryname+'_'+get_fileName(files[pp.index]));
break;
}
if(rd3b){
ii2=pp.byteLength;
ii5=ii6;
if(pp.index>max){
if(ii7){
max=pp.index;
}else ii5++;
}
}else if(ii4){
ii5=Math.floor(pp.index/val_);
if(ii5>ii4)ii5=ii4;
}
zip=zips[ii5];
if(!zip){
zips.push(zip=new JSZip());
if(rd3b)zip.size=(ii7?ii7:max)+2;
}else if(rd3b)zip.size++;
zip.file(get_fileName(files[pp.index]),pp);
if(ii3==files_length
|| ii4!=ii5
&& (zip.length+=ii2)>=val_
&& (!rd3b||zip.size<ii4&&(ii7=zip.size>max?max:0))
){
let saveName=zipName+'.zip';
zip.generateAsync({type:'blob'}).then(function(content){
saveAs(content,saveName);
});
delete zip.length;
delete zips[ii5];
zipName=galleryname+' ('+(++ii6)+')';
}
}else break;
}while(1);
while(ii<in2v){
if(c<files_length){
dl(url_from_url_from_hash(files[c]),c++,100);
ii++;
}else break;
}
if(ii3<files_length){
setTimeout(dl2,rd2b?(c==files_length?200:100):50);
}else{
zip=null;
progressbar.hide();
dlbt.show();
p.length=0;
//console.log('下载时间:'+(new Date().getTime()-t)/1000+'秒');
}
}
dl2();
}
}
{
newStyle:{addNewStyle(`
#_img_, #_div-loader_ {
position: absolute;
inset: 0px;
margin: auto;
}
#_img_ {
max-height: 100%;
max-width: 100%;
}
._title_, ._page_ {
font-weight: bold;
text-shadow: black 0px 0px 2px, black 0px 0px 2px, black 0px 0px 2px;
color: #fff;
position: absolute;
padding-top: 8px;
padding-bottom: 8px;
transform: translate(-50%,0%);
-webkit-user-select:none;
-moz-user-select:none;
-ms-user-select:none;
user-select:none;
}
.opacity0 {
opacity: .0;
}
._title_:hover, ._page_:hover {
opacity: 1
}
.lum-close-button {
position: absolute;
right: 5px;
top: 5px;
width: 32px;
height: 32px;
opacity: .3
}
.lum-close-button:hover {
opacity: 1
}
.lum-close-button:after,.lum-close-button:before {
position: absolute;
left: 15px;
content: " ";
height: 33px;
width: 2px;
background-color: #fff;
}
.lum-close-button:before {
transform: rotate(45deg)
}
.lum-close-button:after {
transform: rotate(-45deg)
}
.loader-hide {
display: none;
}
.loader {
display: block;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: 66px;
height: 20px;
-webkit-animation: loader-rotate 1.8s linear infinite;
animation: loader-rotate 1.8s linear infinite
}
.loader:after,.loader:before {
content: "";
display: block;
width: 20px;
height: 20px;
position: absolute;
top: 50%;
margin-top: -10px;
border-radius: 20px;
background: hsla(0,0%,100%,.9)
}
.loader:before {
left: 0;
-webkit-animation: loader-before 1.8s linear infinite;
animation: loader-before 1.8s linear infinite
}
.loader:after {
right: 0;
-webkit-animation: loader-after 1.8s linear infinite;
animation: loader-after 1.8s linear infinite;
-webkit-animation-delay: -.9s;
animation-delay: -.9s
}
@-webkit-keyframes loader-rotate {
0% {
transform: translate(-50%,-50%) rotate(0)
}
50% {
transform: translate(-50%,-50%) rotate(-180deg)
}
to {
transform: translate(-50%,-50%) rotate(-1turn)
}
}
@keyframes loader-rotate {
0% {
transform: translate(-50%,-50%) rotate(0)
}
50% {
transform: translate(-50%,-50%) rotate(-180deg)
}
to {
transform: translate(-50%,-50%) rotate(-1turn)
}
}
@-webkit-keyframes loader-before {
0% {
transform: scale(1)
}
10% {
transform: scale(1.2) translateX(6px)
}
25% {
transform: scale(1.3) translateX(8px)
}
40% {
transform: scale(1.2) translateX(6px)
}
50% {
transform: scale(1)
}
60% {
transform: scale(.8) translateX(6px)
}
75% {
transform: scale(.7) translateX(8px)
}
90% {
transform: scale(.8) translateX(6px)
}
to {
transform: scale(1)
}
}
@keyframes loader-before {
0% {
transform: scale(1)
}
10% {
transform: scale(1.2) translateX(6px)
}
25% {
transform: scale(1.3) translateX(8px)
}
40% {
transform: scale(1.2) translateX(6px)
}
50% {
transform: scale(1)
}
60% {
transform: scale(.8) translateX(6px)
}
75% {
transform: scale(.7) translateX(8px)
}
90% {
transform: scale(.8) translateX(6px)
}
to {
transform: scale(1)
}
}
@-webkit-keyframes loader-after {
0% {
transform: scale(1)
}
10% {
transform: scale(1.2) translateX(-6px)
}
25% {
transform: scale(1.3) translateX(-8px)
}
40% {
transform: scale(1.2) translateX(-6px)
}
50% {
transform: scale(1)
}
60% {
transform: scale(.8) translateX(-6px)
}
75% {
transform: scale(.7) translateX(-8px)
}
90% {
transform: scale(.8) translateX(-6px)
}
to {
transform: scale(1)
}
}
@keyframes loader-after {
0% {
transform: scale(1)
}
10% {
transform: scale(1.2) translateX(-6px)
}
25% {
transform: scale(1.3) translateX(-8px)
}
40% {
transform: scale(1.2) translateX(-6px)
}
50% {
transform: scale(1)
}
60% {
transform: scale(.8) translateX(-6px)
}
75% {
transform: scale(.7) translateX(-8px)
}
90% {
transform: scale(.8) translateX(-6px)
}
to {
transform: scale(1)
}
}`);}
$('.cover-column > a:eq(0)').attr('href','javascript:_VIEW_();');
let view=$(`
<div tabindex="1" style="display: none;">
<div id="_div_" style="height: 100%;width: 100%;text-align: center;position: fixed;z-index: 99999;background-color: #000000d4;">
<div id="_div-loader_" style="width: 200px;height: 200px;">
<div id="_loader_" class="loader-hide"/>
</div>
<img id="_img_" i="0"/>
<span class="_title_"/>
<span class="_page_" style="bottom: 0px;"/>
<div class="lum-close-button"/>
</div>
</div>`);
document.body.prepend(view[0]);
let hideView=(e)=>{
view.hide();
img.hide();
if(typeof e != 'undefined'){
window.history.back(-1);
e.stopPropagation();
}
}
$('.lum-close-button').click(hideView);
var startX,startY,fx=0;
$('#_div_').on('touchstart', function(e) {
if(fx==-1||e.originalEvent.touches.length!=1){
fx=-1;
}else{
let touch = e.originalEvent.changedTouches[0];
startX = touch.pageX;
startY = touch.pageY;
}
return true;
}).on('touchmove', (e)=> {
if(fx==-1||e.originalEvent.touches.length!=1){
fx=-1;
return true;
}
let touch = e.originalEvent.changedTouches[0];
if(fx<3){
if (touch.pageX - startX > 10) {
fx=1;
//console.log("右划");
} else if (touch.pageX - startX < -10) {
fx=2;
//console.log("左划");
}
}
if(fx>2||fx==0){
if (touch.pageY - startY > 10) {
fx=3;
//console.log("下划");
} else if (touch.pageY - startY < -10) {
fx=4;
//console.log("上划");
}
}
startX = touch.pageX;
startY = touch.pageY;
if(fx!=0)e.preventDefault();
return fx!=0;
}).on('touchend',(e)=> {
if(e.originalEvent.touches.length==0){
if(fx==2||fx==4){//下一张
img.trigger("click");
}else if(fx==1||fx==3){//上一张
window._VIEW_(parseInt(img.attr('i'))-1);
}
fx=0;
}
}).click(hideView);
let img=$('#_img_');
img.click((e)=>{
window._VIEW_(parseInt(img.attr('i'))+1);
e.stopPropagation();
});
img.load(()=>{
if(sl_id){
clearTimeout(sl_id);
sl_id=0;
}
img.show();
loader.attr('class','loader-hide');
let i=parseInt(img.attr('i'));
let image=files[i++];
title.html(get_fileName(image));
page.html(i+'/'+files_length);
title.removeClass('opacity0');
page.removeClass('opacity0');
htp_id=setTimeout(hideTitleAndPage,2000);
image=files[i];
if(image){
prepImg.attr('src',url_from_url_from_hash(image));
return;
}
prepImg.removeAttr('src');
});
let prepImg=$('<img>');
let loader=$('#_loader_');
loader.parent().click((e)=>loader.is(':visible')&&e.stopPropagation());
let showLoader=()=>{
if(sl_id){
sl_id=0;
img[0].complete||img.hide();
loader.attr('class','loader');
}
}
let title=$('._title_'),page=$('._page_');
let hideTitleAndPage=(is_ct)=>{
if(htp_id){
if(is_ct)clearTimeout(htp_id);
htp_id=0;
title.addClass('opacity0');
page.addClass('opacity0');
}
}
let sl_id,htp_id;
window._VIEW_=(i)=>{
let is_hash=0;
if(typeof i=='undefined'||(is_hash=i==-1))i=parseInt(img.attr('i'));
let image=files[i];
if(!image)return;
if(sl_id)clearTimeout(sl_id);
sl_id=setTimeout(showLoader,100);
img.attr('i',i);
img.attr('src',url_from_url_from_hash(image));
hideTitleAndPage(1);
if(view.is(':hidden')){
view.show();
if(!is_hash)location.hash='#VIEW';
view[0].focus({preventScroll: true});
}
}
var _get_pagenum_hash=window.get_pagenum_hash
window.get_pagenum_hash=()=>{
if(location.hash=='#VIEW'){
if(view.is(':hidden'))window._VIEW_(-1);
return files.length;
}else if(!view.is(':hidden'))hideView();
return _get_pagenum_hash.apply(this,arguments);
}
let as=$('.thumbnail-list a'),reg=/#([0-9]+)$/,ex;
for(let i=0,l=as.length;i<l;i++){
ex=reg.exec(as[i].href);
if(ex){
as[i].href='javascript:_VIEW_('+(parseInt(ex[1])-1)+');';
}
}
view.keydown((event)=>{//键盘事件
if(view.is(':visible')){
var e = event || window.event;
var k = e.keyCode || e.which;
//console.log(k);
switch(k) {
case 27://Esc键
hideView();
break;
case 37://←键
window._VIEW_(parseInt(img.attr('i'))-1);
break;
case 32://空格键
case 39://→键
img.trigger("click");
break;
default: return;
}
e.stopPropagation();
e.preventDefault();
}
});
}
}
try{
var window=window;
if(unsafeWindow)window=unsafeWindow;
}catch(er){}
var URL = URL || window.webkitURL || window;
function saveAs(blob, filename){
/*var type = blob.type;
var force_saveable_type = 'application/octet-stream';
if (type && type != force_saveable_type) { // 强制下载,而非在浏览器中打开
var slice = blob.slice || blob.webkitSlice || blob.mozSlice;
blob = slice.call(blob, 0, blob.size, force_saveable_type);
}*/
var url = URL.createObjectURL(blob);
var save_link = document.createElement('a');
save_link.href = url;
save_link.download = filename;
/*var event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
save_link.dispatchEvent(event);*/
//console.log(url,save_link,filename);
save_link.click();
URL.revokeObjectURL(url);
}
function addNewStyle(newStyle,e) {
var styleElement = document.createElement('style');
styleElement.type = 'text/css';
styleElement.innerHTML=newStyle;
(e?e:document.body).appendChild(styleElement);
}
main();