([A-Za-z]+).*?<\/td>/,
categoryTag: /g\/c\/(\w+)\./,
slashOnly: /^[\\/]*$/,
originalImagePattern: /\/fullimg(?:\.php\?|\/)/
@@ -373,6 +375,11 @@ function isInPeakHours() {
return (day === 0 ? hour >= 5 : hour >= 14) && hour < 20;
}
+function PostedTime() {
+ var galleryTime = (document.documentElement.innerHTML.match(ehDownloadRegex.postedTime) || [])[1];
+ return Date.parse(galleryTime + '+0000');
+}
+
function isRecentGallery() {
// 2022-06-07
// A couple of minor tweaks to the "Download source image" changes, since it dropped the utilization by a lot more than we needed it to:
@@ -381,18 +388,14 @@ function isRecentGallery() {
// 2022-11-25
// - One of two new image servers that replace the current oldest image server is now live. (The second one will probably go live in about a month.)
// - Increased the cutoff for how old a gallery has to be before it charges GP for original file downloads during peak hours from 30 days to 90 days.
- var galleryTime = (document.documentElement.innerHTML.match(ehDownloadRegex.postedTime) || [])[1];
- var time = Date.parse(galleryTime + '+0000');
- return Date.now() - time < 90 * 24 * 60 * 60 * 1000;
+ return Date.now() - PostedTime() < 90 * 24 * 60 * 60 * 1000;
}
function isAncientGallery() {
// 2023-07-07
// - Galleries posted more than 1 year ago now always require GP to use the "download original image" links. As before, galleries uploaded 3-12 months ago can still use this function with the image quota outside of peak hours, while galleries uploaded less than 3 months ago can do this even during peak hours.
// (This still doesn't apply to donators, whose image limits are tied to account rather than IP address and thus cannot be "refreshed" just by switching IP)
- var galleryTime = (document.documentElement.innerHTML.match(ehDownloadRegex.postedTime) || [])[1];
- var time = Date.parse(galleryTime + '+0000');
- return Date.now() - time >= 365 * 24 * 60 * 60 * 1000;
+ return Date.now() - PostedTime() >= 365 * 24 * 60 * 60 * 1000;
}
function isDonator() {
@@ -541,7 +544,7 @@ function storeRes(res, index) {
updateTotalStatus();
if (!isPausing) checkFailed();
-
+
res = null;
}
@@ -568,6 +571,53 @@ function generateZip(isFromFS, fs, isRetry, forced){
if (setting['save-info'] === 'file' || !setting['save-info']) {
(dirName && !ehDownloadRegex.slashOnly.test(dirName) ? zip.folder(dirName) : zip).file('info.txt', infoStr.replace(/\n/gi, '\r\n'));
+ } else if (setting['save-info'] === 'comicinfo_xml') {
+ // https://anansi-project.github.io/docs/comicinfo/intro
+ const doc = document.implementation.createDocument("", "", null);
+ const ComicInfo = doc.createElement("ComicInfo");
+ function appendElement(field, value){
+ if (value === undefined) return;
+ const el = doc.createElement(field);
+ el.textContent = value;
+ ComicInfo.appendChild(el);
+ }
+ if (infoObj["SubTitle"]) // No consensus for element SubTitle in ComicInfo yet
+ appendElement("Title", infoObj["SubTitle"]);
+ else
+ appendElement("Title", infoObj["Title"]);
+ appendElement("Summary", infoObj["Uploader Comment"]);
+ const PosetedDate = new Date(PostedTime());
+ appendElement("Year", PosetedDate.getUTCFullYear());
+ appendElement("Month", PosetedDate.getUTCMonth());
+ appendElement("Day", PosetedDate.getUTCDay());
+ var artist = infoObj["Tags"].find(tag => tag.startsWith("artist:"));
+ if (artist !== undefined)
+ appendElement("Writer", artist.slice(7));
+ else {
+ artist = infoObj["Tags"].find(tag => tag.startsWith("艺术家:"))
+ if (artist !== undefined)
+ appendElement("Writer", artist.slice(4));
+ }
+ appendElement("Publisher", infoObj["Uploader"]);
+ appendElement("Genre", infoObj["Category"]);
+ appendElement("Tags", infoObj["Tags"].join(","));
+ appendElement("Web", window.location.href);
+ const language = (document.documentElement.innerHTML.match(ehDownloadRegex.Language) || [])[1]; // use regex to avoid conflict with EhSyringe
+ if (language !== undefined) {
+ const LanguageCode = new Map([["Afrikaans", "af"], ["Albanian", "sq"], ["Arabic", "ar"], ["Aramaic", "arc"], ["Armenian", "hy"], ["Bengali", "bn"], ["Bosnian", "bs"], ["Bulgarian", "bg"], ["Burmese", "my"], ["Catalan", "ca"], ["Cebuano", "ceb"], ["Chinese", "zh"], ["Cree", "cr"], ["Croatian", "hr"], ["Czech", "cs"], ["Danish", "da"], ["Dutch", "nl"], ["English", "en"], ["Esperanto", "eo"], ["Estonian", "et"], ["Finnish", "fi"], ["French", "fr"], ["Georgian", "ka"], ["German", "de"], ["Greek", "el"], ["Gujarati", "gu"], ["Hebrew", "he"], ["Hindi", "hi"], ["Hmong", "hmn"], ["Hungarian", "hu"], ["Icelandic", "is"], ["Indonesian", "id"], ["Irish", "ga"], ["Italian", "it"], ["Japanese", "ja"], ["Javanese", "jv"], ["Kannada", "kn"], ["Kazakh", "kk"], ["Khmer", "km"], ["Korean", "ko"], ["Kurdish", "ku"], ["Ladino", "lad"], ["Lao", "lo"], ["Latin", "la"], ["Latvian", "lv"], ["Marathi", "mr"], ["Mongolian", "mn"], ["Nepali", "ne"], ["Norwegian", "no"], ["Oromo", "om"], ["Papiamento", "pap"], ["Pashto", "ps"], ["Persian", "fa"], ["Polish", "pl"], ["Portuguese", "pt"], ["Punjabi", "pa"], ["Romanian", "ro"], ["Russian", "ru"], ["Sango", "sg"], ["Sanskrit", "sa"], ["Serbian", "sr"], ["Shona", "sn"], ["Slovak", "sk"], ["Slovenian", "sl"], ["Somali", "so"], ["Spanish", "es"], ["Swahili", "sw"], ["Swedish", "sv"], ["Tagalog", "tl"], ["Tamil", "ta"], ["Telugu", "te"], ["Thai", "th"], ["Tibetan", "bo"], ["Tigrinya", "ti"], ["Turkish", "tr"], ["Ukrainian", "uk"], ["Urdu", "ur"], ["Vietnamese", "vi"], ["Welsh", "cy"], ["Yiddish", "yi"], ["Zulu", "zu"]]);
+ if (LanguageCode.has(language)) appendElement("LanguageISO", LanguageCode.get(language));
+ }
+ var characters = infoObj["Tags"].filter(tag => tag.startsWith("character:"));
+ if (characters.length != 0) {
+ appendElement("Characters", characters.map(tag => tag.slice(10)).join(','));
+ } else {
+ characters = infoObj["Tags"].filter(tag => tag.startsWith("角色:"));
+ if (characters.length != 0) appendElement("Characters", characters.map(tag => tag.slice(3)).join(','));
+ }
+ appendElement("EHD_info", infoStr);
+ doc.appendChild(ComicInfo);
+ const serializer = new XMLSerializer();
+ zip.file('ComicInfo.xml', serializer.serializeToString(doc)); // ComicInfo.xml must be at top-level
}
}
@@ -1230,7 +1280,7 @@ function fetchOriginalImage(index, nodeList) {
if (byteLength === 28) { // 'An error has occurred. (403)' Length
console.log('[EHD] #' + (index + 1) + ': An error has occurred. (403)');
console.log('[EHD] #' + (index + 1) + ': RealIndex >', imageList[index]['realIndex'], ' | ReadyState >', res.readyState, ' | Status >', res.status, ' | StatusText >', res.statusText + '\nRequest URL >', requestURL, '\nFinal URL >', res.finalUrl, '\nResposeHeaders >' + res.responseHeaders);
-
+
updateProgress(nodeList, {
status: 'Failed! (Error 403)',
progress: '0',
@@ -1442,7 +1492,7 @@ If you want to reset your limits by paying your GPs or credits right now, or exc
for (var i in res) {
delete res[i];
}
-
+
if (setting['force-resized'] || confirm('Your account has been suspended.\n\n\
Your account is suspended by E-Hentai, and you can check your unblock time on E-Hentai forum. At this time, you cannot access to any user-related page and download original images.\n\
You can still access to resized images, would you like to switch to download resized images?')) {
@@ -1872,7 +1922,7 @@ function getAllPagesURL() {
pushDialog('Succeed!');
curPage++;
-
+
if (!pagesLength) { // can't get pagesLength correctly before
pagesLength = responseText.match(ehDownloadRegex.pagesLength)[1] - 0;
}
@@ -1952,6 +2002,7 @@ function initEHDownload() {
isPausing = false;
zip = new JSZip();
infoStr = '';
+ infoObj = {};
fetchPagesXHR.abort();
if (setting['recheck-file-name']) {
@@ -2001,7 +2052,7 @@ function initEHDownload() {
// Chrome can use about 10% of free space of disk where Chrome User Data stored in as TEMPORARY File System Storage.
if (navigator.webkitTemporaryStorage) { // if support navigator.webkitTemporaryStorage to check usable space
- // use `queryUsageAndQuota` instead of `requestQuota` to check storage space,
+ // use `queryUsageAndQuota` instead of `requestQuota` to check storage space,
// because `requestQuota` is incorrect when harddisk is full, says have about 5GB storage
navigator.webkitTemporaryStorage.queryUsageAndQuota(function (usage, quota) {
console.log('[EHD] Free TEMPORARY File System Space >', quota - usage);
@@ -2032,6 +2083,8 @@ function initEHDownload() {
// Array.prototype.some() is a bit ugly, so we use toString().indexOf() lol
var infoNeeds = setting['save-info-list'].toString();
if (infoNeeds.indexOf('title') >= 0) {
+ infoObj["Title"] = document.getElementById('gn').textContent;
+ infoObj["SubTitle"] = document.getElementById('gj').textContent;
infoStr += replaceHTMLEntites(
document.getElementById('gn').textContent + '\n' +
document.getElementById('gj').textContent + '\n' +
@@ -2040,8 +2093,10 @@ function initEHDownload() {
}
if (infoNeeds.indexOf('metas') >= 0) {
- infoStr += 'Category: ' + document.querySelector('#gdc .cs').textContent.trim() + '\n' +
- 'Uploader: ' + replaceHTMLEntites(document.querySelector('#gdn').textContent) + '\n';
+ infoObj["Category"] = document.querySelector('#gdc .cs').textContent.trim()
+ infoObj["Uploader"] = replaceHTMLEntites(document.querySelector('#gdn').textContent)
+ infoStr += 'Category: ' + infoObj["Category"] + '\n' +
+ 'Uploader: ' + infoObj["Uploader"] + '\n';
}
var metaNodes = document.querySelectorAll('#gdd tr');
for (var i = 0; i < metaNodes.length; i++) {
@@ -2052,6 +2107,7 @@ function initEHDownload() {
if (infoNeeds.indexOf('metas') >= 0) infoStr += 'Rating: ' + unsafeWindow.average_rating + '\n\n';
if (infoNeeds.indexOf('tags') >= 0) {
+ infoObj["Tags"] = [];
infoStr += 'Tags:\n';
var tagsList = document.querySelectorAll('#taglist tr');
@@ -2060,6 +2116,9 @@ function initEHDownload() {
infoStr += '> ' + tds[0].textContent + ' ';
var tags = tds[1].querySelectorAll('a');
+ for (var tag of tags) {
+ infoObj["Tags"].push(tds[0].textContent + tag.textContent);
+ }
infoStr += Array.prototype.map.call(tags, function(e){
return e.textContent;
}).join(', ') + '\n';
@@ -2069,7 +2128,8 @@ function initEHDownload() {
}
if (infoNeeds.indexOf('uploader-comment') >= 0 && document.getElementById('comment_0')) {
- infoStr += 'Uploader Comment:\n' + document.getElementById('comment_0').innerHTML.replace(/
|
/gi, '\n') + '\n\n';
+ infoObj["Uploader Comment"] = document.getElementById('comment_0').innerHTML.replace(/
|
/gi, '\n');
+ infoStr += 'Uploader Comment:\n' + infoObj["Uploader Comment"] + '\n\n';
}
isDownloading = true;
pushDialog(infoStr);
@@ -2089,7 +2149,7 @@ function initEHDownload() {
function initVisibilityListener() {
var hidden, visibilityChange;
- if (typeof document.hidden !== 'undefined') { // Opera 12.10 and Firefox 18 and later support
+ if (typeof document.hidden !== 'undefined') { // Opera 12.10 and Firefox 18 and later support
hidden = 'hidden';
visibilityChange = 'visibilitychange';
}
@@ -2146,7 +2206,7 @@ function initProgressTable(){
function requestDownload(ignoreFailed){
if (isPausing) return;
-
+
if (setting['delay-request']) {
var curTime = Date.now();
if (delayTime < curTime) {
@@ -2354,7 +2414,7 @@ function getPageData(index) {
});
fetchCount--;
imageData[index] = null;
-
+
updateTotalStatus();
}
else {
@@ -2474,7 +2534,7 @@ function showSettings() {
\
(4)
\
(5)
\
- \
+ \
...which includes
\
\
\