// ==UserScript==
// @name E绅士一键添加收藏
// @name:en Ehentai Onekey Add Favorites
// @namespace https://greasyfork.org/zh-CN/users/51670-ruaruarua
// @version 0.3.1
// @description 一键添加收藏9,再也不用看烦人的弹窗啦
// @description:en onekey add favorites
// @author ruaruarua
// @match https://exhentai.org/*
// @match https://e-hentai.org/*
// @icon https://exhentai.org/favicon.ico
// @grant GM_xmlhttpRequest
// @grant GM_registerMenuCommand
// ==/UserScript==
(async function () {
'use strict';
const DEFAULT_FAV = 9;
let favcat = [];
const addStyle = (() => {
const style = {
gallery:
'.fav_gallery{width: 20px;position: relative;top: -22px;}#gdf#gdf{padding-top: 0px;padding-left: 0px;margin-top: 20px;margin-left: 30px;cursor: pointer;}',
m: 'td#fav_td{width: 20px;padding: 0px 5px}.fav_m{width: 20px;padding: 0px;margin: 0px}',
p: 'td#fav_td{width: 20px;padding: 0px 5px}.fav_p,.fav_m{width: 20px;padding: 0px;margin: 0px}',
l: '.fav_l{top: -4px;width: 20px;padding: 0px;position: absolute;}',
e: '.fav_e{left: 22px;top: 150px;width: 20px;padding: 0px;position: absolute;}',
t: '.fav_t{width: 20px;position: absolute;top: 19px;left: -22px;}',
};
return (favType) => {
const favStyle = document.createElement('style');
favStyle.innerHTML = style[favType];
document.head.appendChild(favStyle);
};
})();
const handleFav = async (favUrl, isAddFav, favcat) => {
const res = await fetch(favUrl, {
method: 'POST',
headers: {
Referer: favUrl,
Origin: location.origin,
'Content-Type': 'application/x-www-form-urlencoded',
},
body: isAddFav
? `favcat=${favcat}&favnote=&apply=Add+to+Favorites&update=1`
: 'favcat=favdel&favnote=&update=1',
credentials: 'same-origin',
referrer: favUrl,
});
if (!res.ok) throw new Error('Fail to add favorites.');
const html = await res.text();
let updateStyle = [
...html.matchAll(/<script type="text\/javascript">([\s\S]*?)<\/script>/g),
][1][1];
updateStyle = updateStyle.replace(/window\.opener\./g, '').replace(/window\.close\(\);/, '');
eval(updateStyle);
};
const resetOnclick = (e, favUrl, isAddFn, favcat) => {
e.removeAttribute('onclick');
e.addEventListener('click', () => {
handleFav(favUrl, isAddFn(), favcat);
});
};
const createFavSelect = (favUrl, favClass) => {
const select = document.createElement('select');
select.innerHTML = '<option value="" disabled selected hidden></option>';
favcat.forEach(
(favname, idx) => (select.innerHTML += `<option value="${idx}">${favname}</option>`)
);
select.className = favClass;
select.addEventListener('change', (event) => {
handleFav(favUrl, true, event.target.value);
});
return select;
};
const updateFavcat = async () => {
try {
const res = await fetch(location.origin + '/uconfig.php');
if (!res.ok) throw new Error('can not fetch /uconfig.php');
const html = await res.text();
// 未登录则返回空数组;
const matchFavcat = [...html.matchAll(/input type="text" name="favorite_\d" value="(.*?)"/g)];
const favcat = matchFavcat.map((arr) => arr[1]);
localStorage.favcat = JSON.stringify(favcat);
} catch (error) {
console.log(error);
if (localStorage.favcat) return;
const favcat = Array.from({ length: 10 }).map((_, idx) => 'Favorites ' + idx);
localStorage.favcat = JSON.stringify(favcat);
}
};
GM_registerMenuCommand('update favcat', updateFavcat);
if (!localStorage.favcat) await updateFavcat();
favcat = JSON.parse(localStorage.favcat);
const matchGallery = location.pathname.match(/\/g\/(\d+)\/(\w+)/);
if (matchGallery) {
const favUrl = `${location.origin}/gallerypopups.php?gid=${matchGallery[1]}&t=${matchGallery[2]}&act=addfav`;
const favoritelink = document.querySelector('#favoritelink');
const gdf = document.querySelector('#gdf');
addStyle('gallery');
resetOnclick(gdf, favUrl, () => favoritelink.innerText === ' Add to Favorites', DEFAULT_FAV);
gdf.parentElement.appendChild(createFavSelect(favUrl, 'fav_gallery'));
document.body.addEventListener('keydown', (e) => {
if (e.key === 'q' && !e.repeat) {
handleFav(favUrl, true, DEFAULT_FAV);
}
});
} else {
const dms = document.querySelector('.searchnav div:last-child select');
if (!dms) return;
const displayMode = dms.value;
const styleStrategy = {
m: {
selector: '.glthumb + div',
addSelect(e, favUrl) {
const thead = document.querySelector('table.itg tr');
thead.insertBefore(document.createElement('th'), thead.firstChild);
const newAddSelect = (ne, nfavUrl) => {
const td = ne.parentElement.parentElement.insertBefore(
document.createElement('td'),
ne.parentElement
);
td.id = 'fav_td';
td.appendChild(createFavSelect(nfavUrl, 'fav_m'));
};
newAddSelect(e, favUrl);
this.addSelect = newAddSelect;
},
},
p: {
selector: '.glthumb + div',
addSelect(e, favUrl) {
styleStrategy.m.addSelect.call(this, e, favUrl);
},
},
l: {
selector: '.glthumb + div > :first-child',
addSelect(e, favUrl) {
e.style = 'left: 23px';
e.parentElement.appendChild(createFavSelect(favUrl, 'fav_l'));
},
},
e: {
selector: '.gl3e>:nth-child(2)',
addSelect(e, favUrl) {
e.parentElement.appendChild(createFavSelect(favUrl, 'fav_e'));
},
},
t: {
selector: '.gl5t>:first-child>:nth-child(2)',
addSelect(e, favUrl) {
e.parentElement.appendChild(createFavSelect(favUrl, 'fav_t'));
},
},
};
addStyle(displayMode);
const strategy = styleStrategy[displayMode];
document.querySelectorAll(strategy.selector).forEach((e) => {
const favUrl = e.onclick.toString().match(/https.*addfav/)[0];
resetOnclick(e, favUrl, () => !e.hasAttribute('title'), DEFAULT_FAV);
strategy.addSelect(e, favUrl);
});
}
})();