From ed05b14ce726461f51a096432086070b8b850c35 Mon Sep 17 00:00:00 2001 From: aionui Date: Tue, 1 Sep 2026 22:07:08 +0800 Subject: [PATCH] =?UTF-8?q?ui:=20=E9=BB=98=E8=AE=A4=E5=B0=86=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=E9=9D=A2=E6=9D=BF=E6=94=BE=E5=88=B0=E5=B7=A6=E4=B8=8B?= =?UTF-8?q?=E8=A7=92,=E5=B9=B6=E5=B0=86=E5=8F=82=E8=80=83=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E6=9C=AC=E5=9C=B0=E5=8C=96=E4=B8=BA=E4=B8=AD=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - get-pre-download-infos.js: 面板 CSS 默认 right:16px 改为 left:16px - main.go: handleGalleryCheck 在 exists 时把已有 json 的 pages/total_pages 一并返回,续传场景下 pageURLByKey 不再为空,missing 图片可以正确进入 重试流程(否则 missing 永远补不上) - reference/E-Hentai Downloader-1.36.2.js: 把页面上可见的英文文案翻译成 中文(下载框、设置面板、各类 alert/confirm/pushDialog、状态消息、 控制台日志等),同时修复若干在翻译过程中被误改的变量/函数名 --- get-pre-download-infos.js | 120 ++++- main.go | 21 +- reference/E-Hentai Downloader-1.36.2.js | 596 ++++++++++++------------ 3 files changed, 418 insertions(+), 319 deletions(-) diff --git a/get-pre-download-infos.js b/get-pre-download-infos.js index 0c4dabb..d742459 100644 --- a/get-pre-download-infos.js +++ b/get-pre-download-infos.js @@ -18,11 +18,13 @@ const PANEL_ID = 'ehg-panel'; const BTN_ID = 'ehg-btn'; const CONCURRENCY = 5; + const PAGE_URL_TIMEOUT_MS = 10000; + const IMAGE_FETCH_TIMEOUT_MS = 60000; GM_addStyle(` #${PANEL_ID} { position: fixed; - right: 16px; + left: 16px; bottom: 16px; z-index: 99999; width: 440px; @@ -179,9 +181,10 @@ } function extractImageURL(html) { + // fullimg 通常是原图链接;id="img" 有时只是当前页面预览图。 const patterns = [ - / { - GM_xmlhttpRequest({ + const requestOpts = { method: opts.method || 'GET', url, - anonymous: opts.anonymous !== false, + // 默认按浏览器请求发送 cookie;需要匿名请求时显式传 anonymous: true。 + anonymous: opts.anonymous === true, headers: opts.headers || {}, data: opts.body, responseType: opts.responseType || 'text', + }; + if (opts.timeout !== undefined) requestOpts.timeout = opts.timeout; + + GM_xmlhttpRequest({ + ...requestOpts, onload: (r) => { if (r.status >= 200 && r.status < 300) { resolve({ @@ -440,9 +458,18 @@ })).text); if (checkData.exists) { - // 续传:不再解析单页 URL 列表,直接读后端的 missing 列表 - setStatus('发现已存在JSON,跳过翻页解析,直接续传...'); - return { title, rawTitle, orderedURLs: null, resumed: true }; + // 续传:不再解析单页 URL 列表,直接读后端的 missing 列表。 + // 后端 check 接口会一并返回已有的 pages 映射(0001->单页URL …), + // 我们把它转成 orderedURLs,这样 pageURLByKey 会被填上, + // worker 后续在 pushMissingImages 里才能用单页URL 重新解析图片直链去重试。 + // 否则 pageURLByKey 是空的,worker 拿到 key 查不到 URL 就直接跳过, + // 导致 missing 的图永远补不上。 + const pageMap = checkData.pages || {}; + const orderedURLs = Object.keys(pageMap) + .sort((a, b) => parseInt(a, 10) - parseInt(b, 10)) + .map((k) => pageMap[k]); + setStatus(`发现已存在JSON (共 ${orderedURLs.length} 张),跳过翻页解析,直接续传...`); + return { title, rawTitle, orderedURLs, resumed: true }; } // 全新:解析全部单页 URL,再保存 @@ -473,11 +500,13 @@ let lastErr = null; for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) { try { - const r = await pushOne(title, key, pageURL); + const r = await pushOne(title, key, pageURL, attempt, MAX_ATTEMPTS); return { ok: true, bytes: r.bytes }; } catch (e) { lastErr = e; - console.warn(`[${key}] attempt ${attempt}/${MAX_ATTEMPTS} failed:`, e.message); + console.warn( + `[${key}] attempt ${attempt}/${MAX_ATTEMPTS} failed; pageURL (上一级)=${pageURL}; ${e.message}` + ); if (attempt < MAX_ATTEMPTS) { const wait = 1000 << (attempt - 1); setStatus(`retry ${attempt}/${MAX_ATTEMPTS - 1} ${key} (w${workerId})…`); @@ -488,12 +517,36 @@ return { ok: false, err: lastErr }; } - async function pushOne(title, key, pageURL) { - const pageResp = await gmFetch(pageURL); - const imgURL = extractImageURL(pageResp.text); - if (!imgURL) throw new Error('单页未匹配到图片直链正则'); + async function pushOne(title, key, pageURL, attempt = 1, maxAttempts = 1) { + // 页面和原图请求要带浏览器 cookie;匿名请求拿到的页面/直链可能与浏览器不同。 + const pageResp = await gmFetch(pageURL, { + timeout: PAGE_URL_TIMEOUT_MS, + anonymous: false, + headers: { + Referer: location.href, + 'X-Alt-Referer': location.href, + }, + }); + const rawImgURL = extractImageURL(pageResp.text); + if (!rawImgURL) throw new Error('单页未匹配到图片直链正则'); + const imgURL = resolveURL(pageURL, rawImgURL); - const imgResp = await gmFetch(imgURL, { responseType: 'blob' }); + if (attempt > 1) { + console.warn( + `[${key}] retry ${attempt}/${maxAttempts}; pageURL (上一级)=${pageURL}; directURL=${imgURL}` + ); + } + + const imgResp = await gmFetch(imgURL, { + responseType: 'blob', + timeout: IMAGE_FETCH_TIMEOUT_MS, + anonymous: false, + headers: { + Referer: pageURL, + 'X-Alt-Referer': pageURL, + 'Cache-Control': 'no-cache', + }, + }); const blob = imgResp.blob; if (!blob || blob.size < 1024) { throw new Error(`图片太小 (${blob ? blob.size : 0}B),疑似限流占位`); @@ -551,6 +604,17 @@ if (state.total === 0) { state.total = serverTotal || totalSessionPages || missing.length; } + // 续传场景修复:用户刷新页面 / 中断后重新跑时,state.done 必须从 + // 「后端已经存了 N 张」起算,不能从 0 起算。后端「已下载数量」 + // = total - missing.length。在第一轮初始化一次,后续轮别动它。 + if (round === 1 && totalDone === 0) { + const alreadyDone = Math.max(0, state.total - missing.length); + if (alreadyDone > 0) { + totalDone = alreadyDone; + state.done = totalDone; + setStatus(`retry ${round}: 后端已有 ${alreadyDone} 张,继续补 ${missing.length} 张…`); + } + } if (missing.length === 0) { return { done: totalDone, @@ -609,11 +673,31 @@ failedKeys.forEach((k) => totalFailedKeys.add(k)); state.failed = totalFailedKeys.size; - if (failed === 0 && missing.length === 0) break; - if (failed === 0) break; // 这一轮没失败 → 后端也已经没 missing → 提前结束 + // 每轮结束后显式 GET 后端做完整性确认 —— 单纯靠 "worker 报告全成功" 判断 done + // 不够稳:可能后端响应 200 但实际没存(磁盘满 / race / 响应阶段被前端断开),此时 + // 后端 missing 仍 > 0,如果不验证就 break 会误报 done。后端才是真相来源。 + setStatus(`retry ${round} 结束,问后端确认完整性…`); + const verifyResp = (await gmFetch( + `${API_BASE}/api/galleries/${encodeURIComponent(title)}/missing-images` + )).text; + const verifyObj = JSON.parse(verifyResp); + const stillMissing = (verifyObj.missing || []).length; + if (stillMissing === 0) { + // 后端确认该画廊图片齐全了 → 真的 done + return { + done: totalDone, + failed: 0, + failedKeys: [], + skipped: false, + }; + } - // 还有失败的。等 5 秒再问后端,再下一轮。 - setStatus(`retry ${round} 失败 ${failed} 张,${RETRY_DELAY_MS / 1000}s 后自动重试…`); + // 还有 missing。等 5 秒再下一轮(下一轮开头会重新 GET 最新 missing 列表)。 + if (failed === 0) { + setStatus(`retry ${round} worker 全成功,但后端仍缺 ${stillMissing} 张,${RETRY_DELAY_MS / 1000}s 后重试…`); + } else { + setStatus(`retry ${round} 失败 ${failed} 张,后端仍缺 ${stillMissing} 张,${RETRY_DELAY_MS / 1000}s 后重试…`); + } await new Promise((r) => setTimeout(r, RETRY_DELAY_MS)); } diff --git a/main.go b/main.go index b094c9b..bb4d0a6 100644 --- a/main.go +++ b/main.go @@ -160,7 +160,9 @@ type galleryCheckReq struct { // handleGalleryCheck POST /api/galleries/check — 检查 title 对应的 json 是否已存在。 // 用于前端 JS 弹框「画廊已存在,是否覆盖 / 跳过」之类。 -// 返回 200: {exists: bool, name: } +// 返回 200: {exists: bool, name: , pages?: map, total_pages?: int} +// 当 exists=true 时会一并把已有 json 的 pages/total_pages 返回,让续传场景下前端不必再翻页解析单页 URL, +// 直接用 pageURLByKey 就能精准重试 missing 图片(否则 pageURLByKey 是空的,missing 永远补不上)。 func handleGalleryCheck(w http.ResponseWriter, r *http.Request) { var req galleryCheckReq if err := json.NewDecoder(r.Body).Decode(&req); err != nil { @@ -183,10 +185,23 @@ func handleGalleryCheck(w http.ResponseWriter, r *http.Request) { writeErr(w, err) return } - writeJSON(w, http.StatusOK, map[string]any{ + resp := map[string]any{ "exists": exists, "name": name, - }) + } + if exists { + // 续传场景:把已有的 pages + total_pages 一起返回,前端就不用再翻页解析画廊列表页了。 + // 这样 pageURLByKey 能被正确填上,missing 的图才能真正进入重试流程。 + g, loadErr := store.LoadGallery(name) + if loadErr != nil { + // JSON 文件存在却读不出来(损坏/权限问题),不要静默继续,直接报错让前端看见。 + writeErr(w, loadErr) + return + } + resp["pages"] = g.Pages + resp["total_pages"] = g.TotalPages + } + writeJSON(w, http.StatusOK, resp) } // gallerySaveReq POST /api/galleries/save 请求体。 diff --git a/reference/E-Hentai Downloader-1.36.2.js b/reference/E-Hentai Downloader-1.36.2.js index 15c9466..4983535 100644 --- a/reference/E-Hentai Downloader-1.36.2.js +++ b/reference/E-Hentai Downloader-1.36.2.js @@ -36,9 +36,9 @@ 'use strict'; -console.log('[EHD] E-Hentai Downloader is running.'); -console.log('[EHD] Bugs Report >', 'https://github.com/ccloli/E-Hentai-Downloader/issues | https://greasyfork.org/scripts/10379-e-hentai-downloader/feedback'); -console.log('[EHD] To report a bug, it\'s recommended to provide the logs started with "[EHD]", thanks. =w='); +console.log('[EHD] E-Hentai Downloader 正在运行。'); +console.log('[EHD] Bug 反馈 >', 'https://github.com/ccloli/E-Hentai-Downloader/issues | https://greasyfork.org/scripts/10379-e-hentai-downloader/feedback'); +console.log('[EHD] 反馈 bug 时,建议提供以 “[EHD]” 开头的日志,方便排查,谢谢。=w='); // GreaseMonkey 4.x compatible var loadSetting; @@ -63,14 +63,14 @@ else { // Opera 12- (Presto) doesn't support generating blob url, and if generate as data url, it may cause crashes. if (navigator.userAgent.indexOf('Presto') >= 0) { - alert('Your Opera doesn\'t support E-Hentai Downloader. You need to upgrade it to Opera 15+.'); - console.error('[EHD] Opera 12- (Presto) doesn\'t support E-Hentai Downloader. UserAgent > ' + navigator.userAgent); + alert('你的 Opera 不支持 E-Hentai Downloader。请升级到 Opera 15 或更高版本。'); + console.error('[EHD] Opera 12 及以下(Presto 内核)不支持 E-Hentai Downloader。UserAgent > ' + navigator.userAgent); } // Remove IE support else if (navigator.userAgent.indexOf('Trident') >= 0) { - alert('Your browser doesn\'t support E-Hentai Downloader. You need to switch to other browsers.'); - console.error('[EHD] IE doesn\'t support E-Hentai Downloader. UserAgent > ' + navigator.userAgent); + alert('你的浏览器不支持 E-Hentai Downloader。请切换到其它浏览器。'); + console.error('[EHD] IE 不支持 E-Hentai Downloader。UserAgent > ' + navigator.userAgent); } // GreaseMonkey 3.2 beta 1 and older version can't load content of GM_xhr.response, and this can't be fix. @@ -85,8 +85,8 @@ else if ( ) ) ) { - alert('Your GreaseMonkey doesn\'t support E-Hentai Downloader. The first supported version is GreaseMonkey 3.2 beta 2. Please update your GreaseMonkey to enjoy. =w='); - console.error('[EHD] GreaseMonkey doesn\'t support E-Hentai Downloader. GreaseMonkey Version > ' + GM_info.version); + alert('你的 GreaseMonkey 不支持 E-Hentai Downloader。首个受支持的版本为 GreaseMonkey 3.2 beta 2,请升级 GreaseMonkey 后再使用。=w='); + console.error('[EHD] GreaseMonkey 不支持 E-Hentai Downloader。GreaseMonkey 版本 > ' + GM_info.version); } // GreasyFork doesn't allow obfuscated or minified script, so if you want to see the main function, please see src/main.js at GitHub @@ -5007,7 +5007,7 @@ var Z_DEFLATED = 8; * - `strategy` * - `dictionary` * - * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * [http://zlib.net/manual.html#高级](http://zlib.net/manual.html#高级) * for more information on these. * * Additional options, for internal needs: @@ -5259,7 +5259,7 @@ Deflate.prototype.onEnd = function (status) { * - strategy * - dictionary * - * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * [http://zlib.net/manual.html#高级](http://zlib.net/manual.html#高级) * for more information on these. * * Sugar (options): @@ -5387,7 +5387,7 @@ var toString = Object.prototype.toString; * - `windowBits` * - `dictionary` * - * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * [http://zlib.net/manual.html#高级](http://zlib.net/manual.html#高级) * for more information on these. * * Additional options, for internal needs: @@ -5677,7 +5677,7 @@ Inflate.prototype.onEnd = function (status) { * * - windowBits * - * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * [http://zlib.net/manual.html#高级](http://zlib.net/manual.html#高级) * for more information. * * Sugar (options): @@ -12067,7 +12067,7 @@ var NEW_GM = function (scope, GM) { // Warn if onprogress is used with settings incompatible with fetch mode used in background if (odetails.onprogress || odetails.fetch === false) { - console.warn("Fetch mode does not support onprogress in the background."); + console.warn("Fetch 模式下后台无法触发 onprogress 事件。"); } var _onload = odetails.onload, onloadend = odetails.onloadend, @@ -12179,7 +12179,7 @@ if (HAS_GM && NEW_GM) GM = NEW_GM; // end of gh_2215_make_GM_xhr_more_parallel_again.js var result = !!this.GM_xmlhttpRequestOrig || !!(GM || {}).xmlHttpRequestOrig; -console.info('[EHD] Patch GM_xhr >', result); +console.info('[EHD] 补丁 GM_xhr >', result); return result; }).bind(this); @@ -12205,10 +12205,10 @@ var revertTMSerializedGMXhrPatch = (function() { } } } - console.info('[EHD] Patch GM_xhr >', false); + console.info('[EHD] 还原 GM_xhr 补丁 >', false); return true; } catch (err) { - console.warn('[EHD] Failed to revert GM_xhr patch'); + console.warn('[EHD] 还原 GM_xhr 补丁失败'); } return false; @@ -12236,7 +12236,7 @@ var isSaving = false; var pageURLsList = []; var getAllPagesURLFin = false; var pretitle = document.title; -var needTitleStatus = false; +var needTitle状态 = false; var delayTime = 0; var visibleState = true; var serializedRequestPatched = false; @@ -12299,8 +12299,8 @@ var ehDownloadFS = { ehDownloadFS.removeAllFiles(fs); // It's sure that user have downloaded or ignored temp archive }, errorHandler: function(e) { - var errorMsg = 'File System Request Error > '; - errorMsg += e.name || 'Unknown Error'; + var errorMsg = '文件系统请求错误 > '; + errorMsg += e.name || '未知错误'; console.error('[EHD] ' + errorMsg, e.message); console.error(e); @@ -12315,7 +12315,7 @@ var ehDownloadFS = { a.setAttribute('href', url); a.setAttribute('download', fileName + (setting['save-as-cbz'] ? '.cbz' : '.zip')); a.click(); - pushDialog('\n\nNot download or file is broken? Click here to download\n\n'); + pushDialog('\n\n没有下载或文件损坏?点击此处下载\n\n'); if (!forced) { insertCloseButton(); if (emptyAudio) { @@ -12360,7 +12360,7 @@ var ehDownloadFS = { var value = this.result; if (value === '' || value == null) return; var data = JSON.parse(value); - if (data && confirm('You have an archive that is not downloaded, save it?\n\nFile Name: ' + data.fileName + '\n\n* If you have already downloaded it, click cancel to remove the cached archive file.')) { + if (data && confirm('你有一个尚未下载的压缩包,是否保存?\n\n文件名:' + data.fileName + '\n\n* 如果已经下载,请点击取消删除缓存的压缩包。')) { fileName = data.fileName; dirName = data.dirName; ehDownloadFS.storeTempArchive(data, fs); @@ -12384,7 +12384,7 @@ var ehDownloadFS = { zip = new JSZip(); ehDownloadDialog.style.display = 'block'; ehDownloadDialog.innerHTML = ''; - pushDialog('Preparing......'); + pushDialog('准备中......'); fileReader.onloadend = function() { (data.dirName && !ehDownloadRegex.slashOnly.test(data.dirName) ? zip.folder(data.dirName) : zip).file(entries[index].name, this.result); index++; @@ -12528,7 +12528,7 @@ function initSetting() { // disable single-thread download if (setting['enable-multi-threading'] === false) { delete setting['enable-multi-threading']; - alert('Single-thread download is unavailable now, because its code is too old and it\'s hard to add new features on it.\n\nIf you still need it, please roll back to the last-supported version (1.17.4).\n\nYou can get it at:\n- GitHub: https://github.com/ccloli/E-Hentai-Downloader/releases\n- GreasyFork: https://greasyfork.org/scripts/10379-e-hentai-downloader/versions (requires log in and enable Adult content)\n- SleazyFork: https://sleazyfork.org/scripts/10379-e-hentai-downloader/versions'); + alert('单线程下载功能已不再可用,因为其代码过于陈旧,难以在上面添加新功能。\n\n如仍需使用,请回退到最后一个支持该功能的版本(1.17.4)。\n\n可以在这里获取:\n- GitHub: https://github.com/ccloli/E-Hentai-Downloader/releases\n- GreasyFork: https://greasyfork.org/scripts/10379-e-hentai-downloader/versions (需要登录并启用成人内容)\n- SleazyFork: https://sleazyfork.org/scripts/10379-e-hentai-downloader/versions'); GM_setValue('ehD-setting', JSON.stringify(setting)); } @@ -12538,7 +12538,7 @@ function initSetting() { if (setting['recheck-file-name']) toggleFilenameConfirmInput(); ehDownloadNumberInput.querySelector('input').checked = needNumberImages; - ehDownloadPauseBtn.textContent = setting['force-pause'] ? 'Pause (Downloading images will be aborted)' : 'Pause (Downloading images will keep downloading)'; + ehDownloadPauseBtn.textContent = setting['force-pause'] ? '暂停(将中止正在下载的图片)' : '暂停(正在下载的图片将继续下载)'; if (!setting['hide-image-limits']) { getResolutionSetting(true); @@ -12665,12 +12665,12 @@ function createBlob(abdata, config) { return new Blob(abdata, config); } catch (error) { - pushDialog('An error occurred when generating Blob object.'); - console.error('[EHD] An error occurred when generating Blob object. Error Name >', error.name, '| Error Message >', error.message); - if (confirm('An error occurred when generating Blob object.\n\nError Name: ' + error.name + '\nError Message: ' + error.message + '\n\nTry again?')) return createBlob(abdata, config); + pushDialog('生成 Blob 对象时发生错误。'); + console.error('[EHD] 生成 Blob 对象时发生错误。 Error Name >', error.name, '| Error Message >', error.message); + if (confirm('生成 Blob 对象时发生错误。\n\n错误名称:' + error.name + '\n错误信息:' + error.message + '\n\n是否重试?')) return createBlob(abdata, config); abdata = undefined; - throw new Error('[EHD] An error occurred when generating Blob object, and user refused to retry.'); + throw new Error('[EHD] 生成 Blob 对象时发生错误,且用户已选择不重试。'); } } @@ -12823,7 +12823,7 @@ function PageData(pageURL, imageURL, imageName, nextNL, realIndex, imageNumber) // rename images that have the same name function renameImages() { imageList.forEach(function(elem, index) { - // if Number Images are enabled, filename won't be changed, just numbering + // if 图片编号 are enabled, filename won't be changed, just numbering if (!needNumberImages) { for (var i = 0; i < index; i++) { if (elem !== undefined && imageList[i] !== undefined && elem.imageName.toLowerCase() === imageList[i]['imageName'].toLowerCase()) { @@ -12870,15 +12870,15 @@ function generateZip(isFromFS, fs, isRetry, forced){ infoStr += '\n\nPage ' + elem['realIndex'] + ': ' + elem['pageURL'] + '\nImage ' + elem['realIndex'] + ': ' + elem['imageName'] /*+ '\nImage URL: ' + elem['imageURL']*/; }); } - pushDialog('\nFinish downloading at ' + new Date() + '\n'); - infoStr += '\n\nDownloaded at ' + new Date() + '\n\nGenerated by E-Hentai Downloader. https://github.com/ccloli/E-Hentai-Downloader'; + pushDialog('\n下载完成时间:' + new Date() + '\n'); + infoStr += '\n\n下载时间:' + new Date() + '\n\n由 E-Hentai Downloader 生成。 https://github.com/ccloli/E-Hentai-Downloader'; 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')); } } - pushDialog('\n\nGenerating Zip file...\n'); + pushDialog('\n\n正在生成 Zip 文件...\n'); var fs = fs || ehDownloadFS.fs; @@ -12898,11 +12898,11 @@ function generateZip(isFromFS, fs, isRetry, forced){ ehDownloadFS.errorHandler(error); ehDownloadFS.removeAllFiles(); - if (confirm('An error occured when storing files to FileSystem.\n' + - 'Error Name: ' + (error.name || 'Unknown Error') + '\n' + - 'Error Message: ' + error.message + '\n\n' + - 'Should I try FileSystem again (Yes) or redirect to try using Blob (No)? \n' + - '* If the error message shows there\'s no more free disk space, try removing some files from the drive where Chrome installed (mostly C: on Windows)')) { + if (confirm('将文件存储到文件系统时发生错误。\n' + + '错误名称:' + (error.name || '未知错误') + '\n' + + '错误信息:' + error.message + '\n\n' + + '是否再次尝试使用文件系统(是),还是改用 Blob(否)?\n' + + '* 如果错误信息显示磁盘空间不足,请从安装 Chrome 的磁盘(Windows 上通常是 C: 盘)中删除一些文件')) { saveToFileSystem(abData); } else { @@ -12912,7 +12912,7 @@ function generateZip(isFromFS, fs, isRetry, forced){ }; var fs = fs || ehDownloadFS.fs; - pushDialog('\n\nSlicing and storing Zip file to FileSystem...'); + pushDialog('\n\n正在分块并将 Zip 文件存储到文件系统...'); var data = abData; var dataIndex = 0; var dataLength = data.byteLength; @@ -12955,7 +12955,7 @@ function generateZip(isFromFS, fs, isRetry, forced){ }; var saveToBlob = function(abData){ - curFile.textContent = 'Generating Blob object...'; + curFile.textContent = '正在生成 Blob 对象...'; var save = function() { // rebuild blob object if "File is not exist" occured var blob = createBlob([abData], {type: setting['save-as-cbz'] ? 'application/vnd.comicbook+zip' : 'application/zip'}); @@ -12969,7 +12969,7 @@ function generateZip(isFromFS, fs, isRetry, forced){ save(); var redownloadBtn = document.createElement('button'); - redownloadBtn.textContent = 'Not download? Click here to download'; + redownloadBtn.textContent = '没有下载?点击此处下载'; redownloadBtn.addEventListener('click', save); ehDownloadDialog.appendChild(redownloadBtn); @@ -12985,27 +12985,27 @@ function generateZip(isFromFS, fs, isRetry, forced){ }; var errorHandler = function (error) { - pushDialog('An error occurred when generating Zip file as ArrayBuffer.'); - console.error('[EHD] An error occurred when generating Zip file as ArrayBuffer.'); + pushDialog('将 Zip 文件生成为 ArrayBuffer 时发生错误。'); + console.error('[EHD] 将 Zip 文件生成为 ArrayBuffer 时发生错误。'); console.error(error); - if (confirm('An error occurred when generating Zip file as ArrayBuffer. Try again?')) return generateZip(isFromFS, fs, 1); + if (confirm('将 Zip 文件生成为 ArrayBuffer 时发生错误。 是否重试?')) return generateZip(isFromFS, fs, 1); var fsErrorHandler = function(error) { ehDownloadFS.errorHandler(error); ehDownloadFS.removeAllFiles(); - if (confirm('An error occured when storing files to FileSystem.\n' + - 'Error Name: ' + (error.name || 'Unknown Error') + '\n' + - 'Error Message: ' + error.message + '\n\n' + - 'Should I try again (Yes) or stop it (No, and the downloaded file will be removed)? \n' + - '* If the error message shows there\'s no more free disk space, try removing some files from the drive where Chrome installed (mostly C: on Windows)')) { + if (confirm('将文件存储到文件系统时发生错误。\n' + + '错误名称:' + (error.name || '未知错误') + '\n' + + '错误信息:' + error.message + '\n\n' + + '是否重试(是),还是停止(否,已下载的文件将被删除)?\n' + + '* 如果错误信息显示磁盘空间不足,请从安装 Chrome 的磁盘(Windows 上通常是 C: 盘)中删除一些文件')) { generateZip(isFromFS, fs, isRetry, forced); } }; if (isFromFS || ehDownloadFS.needFileSystem) { // if enabled file system, then store all files into file system - pushDialog('Storing files into File System...'); + pushDialog('正在将文件存储到文件系统...'); var files = zip.file(/.*/); var fileIndex = 0; var filesLength = files.length; @@ -13031,7 +13031,7 @@ function generateZip(isFromFS, fs, isRetry, forced){ fileWriter.write(blob); if ('close' in blob) blob.close(); // File Blob.close() API, not supported by all the browser now blob = null; - pushDialog('Success!\nPlease close this tab and open a new tab to download.\nIf you still can\'t download it, try using HTML5 FileSystem Explorer to save them.'); + pushDialog('成功!\n请关闭此标签页并打开新标签页进行下载。\n如果仍然无法下载,请尝试使用 HTML5 FileSystem Explorer 来保存它们。'); files.forEach(function(elem){ zip.remove(elem.name); @@ -13068,7 +13068,7 @@ function generateZip(isFromFS, fs, isRetry, forced){ } lastMetaTime = thisMetaTime; progress.value = meta.percent / 100; - curFile.textContent = meta.currentFile || 'Calculating extra data...'; + curFile.textContent = meta.currentFile || '正在计算额外数据...'; }; var defaultHandle = function() { @@ -13101,9 +13101,9 @@ function generateZip(isFromFS, fs, isRetry, forced){ var writer; var fsErrorHandler = function (err) { - console.error('[EHD] An error occurred when generating Zip file as stream, fallback to default generate.'); + console.error('[EHD] 以流方式生成 Zip 文件时发生错误,回退到默认方式生成。'); console.error(err); - pushDialog('An error occurred when generating Zip file as stream, fallback to default generate.'); + pushDialog('以流方式生成 Zip 文件时发生错误,回退到默认方式生成。'); stream.pause(); defaultHandle(); }; @@ -13112,7 +13112,7 @@ function generateZip(isFromFS, fs, isRetry, forced){ var done = false; stream.on('data', function (data, meta) { if (!writer) { - throw new Error('FileWriter is not usable.'); + throw new Error('无法使用 FileWriter。'); } onProgress(meta); @@ -13190,7 +13190,7 @@ function updateProgress(nodeList, data) { // update ehDownloadStatus function updateTotalStatus(){ - ehDownloadStatus.textContent = 'Total: ' + totalCount + ' | Downloading: ' + fetchCount + ' | Succeed: ' + downloadedCount + ' | Failed: ' + failedCount; + ehDownloadStatus.textContent = '总计:' + totalCount + ' | 下载中:' + fetchCount + ' | 成功:' + downloadedCount + ' | 失败:' + failedCount; if (needTitleStatus) document.title = '[' + (isPausing ? '❙❙' : downloadedCount < totalCount ? '↓ ' + downloadedCount + '/' + totalCount : totalCount === 0 ? '↓' : '√' ) + '] ' + pretitle; } @@ -13248,7 +13248,7 @@ function checkFailed() { for (var i = 0; i < fetchThread.length; i++) { if (typeof fetchThread[i] !== 'undefined' && 'abort' in fetchThread[i]) fetchThread[i].abort(); } - if (setting['number-auto-retry'] || confirm('Some images failed to download. Would you like to try them again?')) { + if (setting['number-auto-retry'] || confirm('部分图片下载失败。是否要重试?')) { retryAllFailed(); } else { @@ -13258,8 +13258,8 @@ function checkFailed() { failedPages.push(i + 1); } } - pushDialog('\nFetch images failed.\nFailed Pages: ' + failedPages.join(',') + '\n'); - if (setting['auto-download-cancel'] || confirm('Fetch images failed, Please try again later.\n\nWould you like to download downloaded images?')) { + pushDialog('\n图片获取失败。\n失败页面:' + failedPages.join(',') + '\n'); + if (setting['auto-download-cancel'] || confirm('图片获取失败,请稍后重试。\n\n是否下载已下载的图片?')) { saveDownloaded(); } else { @@ -13312,8 +13312,8 @@ function fetchOriginalImage(index, nodeList) { \ \ \ - Pending...\ - Force Abort\ + 等待中...\ + 强制中止\ '; progressTable.appendChild(node); } @@ -13343,7 +13343,7 @@ function fetchOriginalImage(index, nodeList) { if (imageData[index] instanceof ArrayBuffer) { // Has already downloaded updateProgress(nodeList, { name: '#' + imageList[index]['realIndex'] + ': ' + imageList[index]['imageName'], - status: 'Succeed!', + status: '成功!', progress: '1', progressText: '100%', class: 'ehD-pt-succeed' @@ -13354,7 +13354,7 @@ function fetchOriginalImage(index, nodeList) { if (!isDownloading) return; // Temporarily fixes #31 if (isPausing && setting['force-pause']) return; - updateProgress(nodeList, { progressText: '0 KB/s' }); + updateProgress(nodeList, { progressText: '0 KB/秒' }); if (setting['speed-detect'] && speedInfo.expiredDetect === null) { speedInfo.expiredDetect = setTimeout(expiredSpeedHandler, (setting['speed-expired'] ? setting['speed-expired'] : 30) * 1000, res); @@ -13365,7 +13365,7 @@ function fetchOriginalImage(index, nodeList) { if (imageData[index] instanceof ArrayBuffer) { // Has already downloaded updateProgress(nodeList, { name: '#' + imageList[index]['realIndex'] + ': ' + imageList[index]['imageName'], - status: 'Succeed!', + status: '成功!', progress: '1', progressText: '100%', class: 'ehD-pt-succeed' @@ -13379,10 +13379,10 @@ function fetchOriginalImage(index, nodeList) { if (typeof fetchThread[index] !== 'undefined' && 'abort' in fetchThread[index]) fetchThread[index].abort(); console.log('[EHD] #' + (index + 1) + ': Speed Too Low'); - 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); + console.log('[EHD] #' + (index + 1) + ': RealIndex >', imageList[index]['realIndex'], ' | ReadyState >', res.readyState, ' | 状态 >', res.status, ' | StatusText >', res.statusText + '\nRequest URL >', requestURL, '\nFinal URL >', res.finalUrl, '\nResposeHeaders >' + res.responseHeaders); updateProgress(nodeList, { - status: 'Failed! (Low Speed)', + status: '失败! (速度过低)', progress: '0', progressText: '', class: 'ehD-pt-warning' @@ -13446,7 +13446,7 @@ function fetchOriginalImage(index, nodeList) { progress: res.lengthComputable ? res.loaded / (res.total || 1) : '', progressText: speedText, class: '', - status: retryCount[index] === 0 ? 'Downloading...' : 'Retrying (' + retryCount[index] + '/' + (setting['retry-count'] !== undefined ? setting['retry-count'] : 3) + ') ...' + status: retryCount[index] === 0 ? '下载中...' : '重试中(' + retryCount[index] + '/' + (setting['retry-count'] !== undefined ? setting['retry-count'] : 3) + ') ...' }); // set showing speed to 0 @@ -13493,11 +13493,11 @@ function fetchOriginalImage(index, nodeList) { var mime = responseHeaders.match(/Content-Type:/i) ? responseHeaders.split(/Content-Type:/i)[1].split('\n')[0].trim().split('/') : ['', '']; if (!response) { - console.log('[EHD] #' + (index + 1) + ': Empty Response (See: https://github.com/ccloli/E-Hentai-Downloader/issues/16 )'); - 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); + console.log('[EHD] #' + (index + 1) + ': 空响应 (See: https://github.com/ccloli/E-Hentai-Downloader/issues/16 )'); + console.log('[EHD] #' + (index + 1) + ': RealIndex >', imageList[index]['realIndex'], ' | ReadyState >', res.readyState, ' | 状态 >', res.status, ' | StatusText >', res.statusText + '\nRequest URL >', requestURL, '\nFinal URL >', res.finalUrl, '\nResposeHeaders >' + res.responseHeaders); updateProgress(nodeList, { - status: 'Failed! (Empty Response)', + status: '失败! (空响应)', progress: '0', progressText: '', class: 'ehD-pt-warning' @@ -13517,13 +13517,13 @@ function fetchOriginalImage(index, nodeList) { responseText = new TextDecoder().decode(new DataView(response)); } - if (byteLength === 925) { // '403 Access Denied' Image Byte Size + if (byteLength === 925) { // '403 访问被拒绝' Image Byte Size // GM_xhr only support abort() - console.log('[EHD] #' + (index + 1) + ': 403 Access Denied'); - 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); + console.log('[EHD] #' + (index + 1) + ': 403 访问被拒绝'); + console.log('[EHD] #' + (index + 1) + ': RealIndex >', imageList[index]['realIndex'], ' | ReadyState >', res.readyState, ' | 状态 >', res.status, ' | StatusText >', res.statusText + '\nRequest URL >', requestURL, '\nFinal URL >', res.finalUrl, '\nResposeHeaders >' + res.responseHeaders); updateProgress(nodeList, { - status: 'Failed! (Error 403)', + status: '失败! (错误 403)', progress: '0', progressText: '', class: 'ehD-pt-warning' @@ -13534,12 +13534,12 @@ function fetchOriginalImage(index, nodeList) { } return failedFetching(index, nodeList, true); } - 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); + if (byteLength === 28) { // '发生错误。(403)' Length + console.log('[EHD] #' + (index + 1) + ': 发生错误。(403)'); + console.log('[EHD] #' + (index + 1) + ': RealIndex >', imageList[index]['realIndex'], ' | ReadyState >', res.readyState, ' | 状态 >', res.status, ' | StatusText >', res.statusText + '\nRequest URL >', requestURL, '\nFinal URL >', res.finalUrl, '\nResposeHeaders >' + res.responseHeaders); updateProgress(nodeList, { - status: 'Failed! (Error 403)', + status: '失败! (错误 403)', progress: '0', progressText: '', class: 'ehD-pt-warning' @@ -13566,11 +13566,11 @@ function fetchOriginalImage(index, nodeList) { /*for (var i = 0; i < fetchThread.length; i++) { if (typeof fetchThread[i] !== 'undefined' && 'abort' in fetchThread[i]) fetchThread[i].abort(); }*/ - console.log('[EHD] #' + (index + 1) + ': Exceed Image Viewing Limits / 509 Bandwidth Exceeded'); - 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); + console.log('[EHD] #' + (index + 1) + ': 超出图片查看额度 / 509 带宽超限'); + console.log('[EHD] #' + (index + 1) + ': RealIndex >', imageList[index]['realIndex'], ' | ReadyState >', res.readyState, ' | 状态 >', res.status, ' | StatusText >', res.statusText + '\nRequest URL >', requestURL, '\nFinal URL >', res.finalUrl, '\nResposeHeaders >' + res.responseHeaders); updateProgress(nodeList, { - status: 'Failed! (Exceed Limits/GPs)', + status: '失败! (超出额度/GPs)', progress: '0', progressText: '', class: 'ehD-pt-failed' @@ -13586,7 +13586,7 @@ function fetchOriginalImage(index, nodeList) { if (isPausing) return; - pushDialog('You have exceeded your image viewing limits, or you need GP to download.\n'); + pushDialog('你已超出图片浏览额度,或需要 GP 才能下载。\n'); isPausing = true; updateTotalStatus(); if (emptyAudio) { @@ -13597,32 +13597,32 @@ function fetchOriginalImage(index, nodeList) { ehDownloadDialog.removeChild(ehDownloadPauseBtn); } - if (confirm('You have temporarily reached the limit for how many images you can browse.\n\ -If you don\'t have enough limit, or it\'s in site\'s peak hours, or the gallery is uploaded for a long time, you need to use GP to download, but you don\'t have enough GP to add quota.\n\n\ -To increase viewing limits, you can:\n\ -- If you are not signed in, sign in to get quota.\n\ -- Run Hentai@Home to get points which you can pay to increase your limit.\n\ -- Check back in a few hours, and it\'ll slowly recovered (3 points per minute by default).\n\ -- You can reset it by paying your GPs or credits.\n\n\ -To gain GP, you can:\n\ -- Upload galleries and earn GP from visits and users using offical archive download.\n\ -- Run Hentai@Home to earn GP from hit.\n\ -- Upload torrents.\n\ -- Write comments and gain from others voting.\n\ -- Exchange GP with credits or hath, or donation.\n\ -- Wait till your limits recovered or the peak hours passed.\n\n\ -If you want to reset your limits by paying your GPs or credits right now, or exchange GPs, choose YES, and do it in the opened window. Or if you want to wait a few minutes until you have enough free limit, then continue, choose NO.')) { + if (confirm('你已暂时达到可浏览图片额度上限。\n\ +若额度不足,或处于站点高峰期,或画廊上传已久,需要使用 GP 下载,但你的 GP 又不足以补充额度。\n\n\ +要提升浏览额度,你可以:\n\ +- 若尚未登录,请登录以获得额度。\n\ +- 运行 Hentai@Home 获得积分,可用于支付以提升额度。\n\ +- 几小时后再访问,额度会缓慢恢复(默认每分钟 3 点)。\n\ +- 通过支付 GP 或 credits 重置额度。\n\n\ +要获取 GP,你可以:\n\ +- 上传画廊,并通过他人访问或使用官方压缩包下载赚取 GP。\n\ +- 运行 Hentai@Home 赚取命中 GP。\n\ +- 上传种子。\n\ +- 撰写评论,从他人投票中获取。\n\ +- 使用 credits 或 hath 兑换 GP,亦可通过捐赠。\n\ +- 等待额度恢复或高峰时段过去。\n\n\ +若想立即支付 GP 或 credits 重置额度,或兑换 GP,请选择 “是”,在打开的窗口中操作。若想等待几分钟直到有足够可用额度再继续,请选择 “否”。')) { window.open('https://e-hentai.org/home.php'); } var resetButton = document.createElement('a'); - resetButton.innerHTML = ''; + resetButton.innerHTML = ''; resetButton.setAttribute('href', 'https://e-hentai.org/home.php'); resetButton.setAttribute('target', '_blank'); ehDownloadDialog.appendChild(resetButton); var continueButton = document.createElement('button'); - continueButton.innerHTML = 'Continue Download'; + continueButton.innerHTML = '继续下载'; continueButton.addEventListener('click', function(){ //fetchCount = 0; ehDownloadDialog.removeChild(resetButton); @@ -13637,13 +13637,13 @@ If you want to reset your limits by paying your GPs or credits right now, or exc ehDownloadDialog.appendChild(continueButton); var cancelButton = document.createElement('button'); - cancelButton.innerHTML = 'Cancel Download'; + cancelButton.innerHTML = '取消下载'; cancelButton.addEventListener('click', function(){ ehDownloadDialog.removeChild(resetButton); ehDownloadDialog.removeChild(continueButton); ehDownloadDialog.removeChild(cancelButton); - if (setting['auto-download-cancel'] || confirm('You have exceeded your image viewing limits. Would you like to save downloaded images?')) { + if (setting['auto-download-cancel'] || confirm('你的图片浏览额度已超出。是否保存已下载的图片?')) { saveDownloaded(); } else { @@ -13661,11 +13661,11 @@ If you want to reset your limits by paying your GPs or credits right now, or exc // ip banned if (mime[0] === 'text') { if (responseText.indexOf('Your IP address has been temporarily banned') >= 0) { - console.log('[EHD] #' + (index + 1) + ': IP address banned'); - 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); + console.log('[EHD] #' + (index + 1) + ': IP 地址已被封禁'); + console.log('[EHD] #' + (index + 1) + ': RealIndex >', imageList[index]['realIndex'], ' | ReadyState >', res.readyState, ' | 状态 >', res.status, ' | StatusText >', res.statusText + '\nRequest URL >', requestURL, '\nFinal URL >', res.finalUrl, '\nResposeHeaders >' + res.responseHeaders); updateProgress(nodeList, { - status: 'Failed! (IP banned)', + status: '失败! (IP 已被封禁)', progress: '0', progressText: '', class: 'ehD-pt-failed' @@ -13681,7 +13681,7 @@ If you want to reset your limits by paying your GPs or credits right now, or exc if (isPausing) return; - pushDialog('Your IP address has been temporarily banned.\n'); + pushDialog('你的 IP 地址已被暂时封禁。\n'); isPausing = true; updateTotalStatus(); if (emptyAudio) { @@ -13694,14 +13694,14 @@ If you want to reset your limits by paying your GPs or credits right now, or exc var expiredTime = responseText.match(ehDownloadRegex.IPBanExpires); - alert('Your IP address has been temporarily banned. \n\n\ - Make sure your download settings are not configured to download too fast. If you are using conservative rules, check if your computer is infected with malware, or if you are using a shared IP with others.\n\ - If you can change your IP (like using a proxy) or wait until you\'re unblocked, you can then continue your download; or cancel your download and get downloaded images.\n\n' + + alert('你的 IP 地址已被暂时封禁。\n\n\ + 请确认你的下载设置未被配置为下载过快。若使用保守规则,请检查你的电脑是否感染了恶意软件,或者你的 IP 是否在与他人共享。\n\ + 如果可以更换 IP(例如使用代理)或等待解封,之后可继续下载;或者取消下载并保存已下载的图片。\n\n' + (expiredTime ? '\n' + expiredTime[0] : '') ); var continueButton = document.createElement('button'); - continueButton.innerHTML = 'Continue Download'; + continueButton.innerHTML = '继续下载'; continueButton.addEventListener('click', function () { //fetchCount = 0; ehDownloadDialog.removeChild(continueButton); @@ -13715,12 +13715,12 @@ If you want to reset your limits by paying your GPs or credits right now, or exc ehDownloadDialog.appendChild(continueButton); var cancelButton = document.createElement('button'); - cancelButton.innerHTML = 'Cancel Download'; + cancelButton.innerHTML = '取消下载'; cancelButton.addEventListener('click', function () { ehDownloadDialog.removeChild(continueButton); ehDownloadDialog.removeChild(cancelButton); - if (setting['auto-download-cancel'] || confirm('Would you like to save downloaded images?')) { + if (setting['auto-download-cancel'] || confirm('是否保存已下载的图片?')) { saveDownloaded(); } else { @@ -13736,11 +13736,11 @@ If you want to reset your limits by paying your GPs or credits right now, or exc return; } if (responseText.indexOf('as your account has been suspended') >= 0) { - console.log('[EHD] #' + (index + 1) + ': Account Suspended'); - 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); + console.log('[EHD] #' + (index + 1) + ': 账号已暂停'); + console.log('[EHD] #' + (index + 1) + ': RealIndex >', imageList[index]['realIndex'], ' | ReadyState >', res.readyState, ' | 状态 >', res.status, ' | StatusText >', res.statusText + '\nRequest URL >', requestURL, '\nFinal URL >', res.finalUrl, '\nResposeHeaders >' + res.responseHeaders); updateProgress(nodeList, { - status: 'Failed! (Suspended)', + status: '失败! (账号已暂停)', progress: '0', progressText: '', class: 'ehD-pt-failed' @@ -13750,15 +13750,15 @@ If you want to reset your limits by paying your GPs or credits right now, or exc 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?')) { + if (setting['force-resized'] || confirm('你的账号已被封禁。\n\n\ + 你的账号已被 E-Hentai 封禁,你可以在 E-Hentai 论坛查看解封时间。此时你无法访问任何与用户相关的页面,也无法下载原图。\n\ + 你仍然可以访问重采样图片,是否切换到下载重采样图片?')) { setting['force-resized'] = true; getPageData(index); return; } - if (setting['auto-download-cancel'] || confirm('Would you like to save downloaded images?')) { + if (setting['auto-download-cancel'] || confirm('是否保存已下载的图片?')) { saveDownloaded(); } else { @@ -13772,11 +13772,11 @@ If you want to reset your limits by paying your GPs or credits right now, or exc } // res.status should be detected at here, because we should know are we reached image limits at first if (res.status !== 200) { - console.log('[EHD] #' + (index + 1) + ': Wrong Response Status (' + res.status + ')'); - 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); + console.log('[EHD] #' + (index + 1) + ': 错误响应 状态 (' + res.status + ')'); + console.log('[EHD] #' + (index + 1) + ': RealIndex >', imageList[index]['realIndex'], ' | ReadyState >', res.readyState, ' | 状态 >', res.status, ' | StatusText >', res.statusText + '\nRequest URL >', requestURL, '\nFinal URL >', res.finalUrl, '\nResposeHeaders >' + res.responseHeaders); updateProgress(nodeList, { - status: 'Failed! (Status ' + res.status + ')', + status: '失败! (状态 ' + res.status + ')', progress: '0', progressText: '', class: 'ehD-pt-warning' @@ -13789,11 +13789,11 @@ If you want to reset your limits by paying your GPs or credits right now, or exc } // hot fix for new E-Hentai original image server, as it returns an invalid `Content-Type` header (#153) if (['image', 'jpg', 'jpeg', 'gif', 'png', 'bmp', 'tif', 'tiff', 'webp', 'apng'].indexOf(mime[0]) < 0) { - console.log('[EHD] #' + (index + 1) + ': Wrong Content-Type'); - 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); + console.log('[EHD] #' + (index + 1) + ': Content-Type 错误'); + console.log('[EHD] #' + (index + 1) + ': RealIndex >', imageList[index]['realIndex'], ' | ReadyState >', res.readyState, ' | 状态 >', res.status, ' | StatusText >', res.statusText + '\nRequest URL >', requestURL, '\nFinal URL >', res.finalUrl, '\nResposeHeaders >' + res.responseHeaders); updateProgress(nodeList, { - status: 'Failed! (Wrong MIME)', + status: '失败! (MIME 类型错误)', progress: '0', progressText: '', class: 'ehD-pt-warning' @@ -13822,8 +13822,8 @@ If you want to reset your limits by paying your GPs or credits right now, or exc imageList[index]['_imageName'] = imageList[index]['imageName'] = imageName; } catch (error) { - console.log('[EHD] #' + (index + 1) + ': Parse file name failed'); - 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); + console.log('[EHD] #' + (index + 1) + ': 解析文件名失败'); + console.log('[EHD] #' + (index + 1) + ': RealIndex >', imageList[index]['realIndex'], ' | ReadyState >', res.readyState, ' | 状态 >', res.status, ' | StatusText >', res.statusText + '\nRequest URL >', requestURL, '\nFinal URL >', res.finalUrl, '\nResposeHeaders >' + res.responseHeaders); imageList[index]['_imageName'] = imageList[index]['imageName']; } @@ -13841,7 +13841,7 @@ If you want to reset your limits by paying your GPs or credits right now, or exc if (checksum) { updateProgress(nodeList, { name: '#' + imageList[index]['realIndex'] + ': ' + imageList[index]['imageName'], - status: 'Hashing...', + status: '正在校验...', progress: '1', progressText: '100%', }); @@ -13850,17 +13850,17 @@ If you want to reset your limits by paying your GPs or credits right now, or exc // required to be matched at start // hash may be null, which may because the browser doesn't support it if (!hash) { - console.log('[EHD] #' + (index + 1) + ': Checksum is empty'); - 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); + console.log('[EHD] #' + (index + 1) + ': 校验和为空'); + console.log('[EHD] #' + (index + 1) + ': RealIndex >', imageList[index]['realIndex'], ' | ReadyState >', res.readyState, ' | 状态 >', res.status, ' | StatusText >', res.statusText + '\nRequest URL >', requestURL, '\nFinal URL >', res.finalUrl, '\nResposeHeaders >' + res.responseHeaders); console.log('[EHD] #' + (index + 1) + ': Expected Checksum >', checksum, ' | Actual Checksum >', hash); // do not throw error for such case? } else if (hash.indexOf(checksum) !== 0) { - console.log('[EHD] #' + (index + 1) + ': Checksum mismatch'); - 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); + console.log('[EHD] #' + (index + 1) + ': 校验和不匹配'); + console.log('[EHD] #' + (index + 1) + ': RealIndex >', imageList[index]['realIndex'], ' | ReadyState >', res.readyState, ' | 状态 >', res.status, ' | StatusText >', res.statusText + '\nRequest URL >', requestURL, '\nFinal URL >', res.finalUrl, '\nResposeHeaders >' + res.responseHeaders); console.log('[EHD] #' + (index + 1) + ': Expected Checksum >', checksum, ' | Actual Checksum >', hash); updateProgress(nodeList, { - status: 'Failed! (Checksum Mismatch)', + status: '失败! (校验和不匹配)', progress: '0', progressText: '', class: 'ehD-pt-warning' @@ -13875,7 +13875,7 @@ If you want to reset your limits by paying your GPs or credits right now, or exc updateProgress(nodeList, { name: '#' + imageList[index]['realIndex'] + ': ' + imageList[index]['imageName'], - status: 'Succeed!', + status: '成功!', progress: '1', progressText: '100%', class: 'ehD-pt-succeed' @@ -13888,12 +13888,12 @@ If you want to reset your limits by paying your GPs or credits right now, or exc } response = null; }).catch(function (error) { - console.log('[EHD] #' + (index + 1) + ': Checksum failed'); - 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); + console.log('[EHD] #' + (index + 1) + ': 校验失败'); + console.log('[EHD] #' + (index + 1) + ': RealIndex >', imageList[index]['realIndex'], ' | ReadyState >', res.readyState, ' | 状态 >', res.status, ' | StatusText >', res.statusText + '\nRequest URL >', requestURL, '\nFinal URL >', res.finalUrl, '\nResposeHeaders >' + res.responseHeaders); console.error(error); updateProgress(nodeList, { - status: 'Failed! (Checksum Error)', + status: '失败! (校验和错误)', progress: '0', progressText: '', class: 'ehD-pt-failed' @@ -13910,7 +13910,7 @@ If you want to reset your limits by paying your GPs or credits right now, or exc updateProgress(nodeList, { name: '#' + imageList[index]['realIndex'] + ': ' + imageList[index]['imageName'], - status: 'Succeed!', + status: '成功!', progress: '1', progressText: '100%', class: 'ehD-pt-succeed' @@ -13924,12 +13924,12 @@ If you want to reset your limits by paying your GPs or credits right now, or exc response = null; } catch (error) { - console.log('[EHD] #' + (index + 1) + ': Unknown Error (Please send feedback)'); - 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); + console.log('[EHD] #' + (index + 1) + ': 未知错误 (Please send feedback)'); + console.log('[EHD] #' + (index + 1) + ': RealIndex >', imageList[index]['realIndex'], ' | ReadyState >', res.readyState, ' | 状态 >', res.status, ' | StatusText >', res.statusText + '\nRequest URL >', requestURL, '\nFinal URL >', res.finalUrl, '\nResposeHeaders >' + res.responseHeaders); console.error(error); updateProgress(nodeList, { - status: 'Failed! (Unknown)', + status: '失败! (未知)', progress: '0', progressText: '', class: 'ehD-pt-failed' @@ -13945,11 +13945,11 @@ If you want to reset your limits by paying your GPs or credits right now, or exc removeTimerHandler(); if (!isDownloading || imageData[index] instanceof ArrayBuffer) return; // Temporarily fixes #31 - console.log('[EHD] #' + (index + 1) + ': Network Error'); - 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); + console.log('[EHD] #' + (index + 1) + ': 网络错误'); + console.log('[EHD] #' + (index + 1) + ': RealIndex >', imageList[index]['realIndex'], ' | ReadyState >', res.readyState, ' | 状态 >', res.status, ' | StatusText >', res.statusText + '\nRequest URL >', requestURL, '\nFinal URL >', res.finalUrl, '\nResposeHeaders >' + res.responseHeaders); updateProgress(nodeList, { - status: 'Failed! (Network Error)', + status: '失败! (网络错误)', progress: '0', progressText: '', class: 'ehD-pt-warning' @@ -13969,11 +13969,11 @@ If you want to reset your limits by paying your GPs or credits right now, or exc removeTimerHandler(); if (!isDownloading || imageData[index] instanceof ArrayBuffer) return; // Temporarily fixes #31 - console.log('[EHD] #' + (index + 1) + ': Timed Out'); - 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); + console.log('[EHD] #' + (index + 1) + ': 超时'); + console.log('[EHD] #' + (index + 1) + ': RealIndex >', imageList[index]['realIndex'], ' | ReadyState >', res.readyState, ' | 状态 >', res.status, ' | StatusText >', res.statusText + '\nRequest URL >', requestURL, '\nFinal URL >', res.finalUrl, '\nResposeHeaders >' + res.responseHeaders); updateProgress(nodeList, { - status: 'Failed! (Timed Out)', + status: '失败! (超时)', progress: '0', progressText: '', class: 'ehD-pt-warning' @@ -14036,7 +14036,7 @@ function insertCloseButton(handle) { var exitButton = document.createElement('button'); exitButton.style.display = 'block'; exitButton.style.margin = '0 auto'; - exitButton.textContent = 'Close'; + exitButton.textContent = '关闭'; exitButton.onclick = function(){ ehDownloadDialog.removeChild(exitButton); ehDownloadDialog.style.display = 'none'; @@ -14065,32 +14065,32 @@ function getPagesURLFromMPV() { var responseText = xhr.responseText; if (xhr.status !== 200 || !responseText) { if (retryCount < (setting['retry-count'] !== undefined ? setting['retry-count'] : 3)) { - pushDialog('Failed! Retrying... '); + pushDialog('失败! 重试中... '); retryCount++; xhr.open('GET', mpvURL); xhr.timeout = 30000; xhr.send(); } else { - pushDialog('Failed!\nFetch Pages\' URL failed, Please try again later.'); + pushDialog('失败!\n获取页面 URL 失败,请稍后重试。'); isDownloading = false; - alert('Fetch Pages\' URL failed, Please try again later.'); + alert('获取页面 URL 失败,请稍后重试。'); } return; } var listMatch = responseText.match(ehDownloadRegex.mpvKey); if (!listMatch) { - console.error('[EHD] Response content is incorrect!'); + console.error('[EHD] 响应内容不正确!'); if (retryCount < (setting['retry-count'] !== undefined ? setting['retry-count'] : 3)) { - pushDialog('Failed! Retrying... '); + pushDialog('失败! 重试中... '); retryCount++; xhr.open('GET', location.origin + location.pathname + '?p=' + curPage); xhr.timeout = 30000; xhr.send(); } else { - pushDialog('Failed!\nCan\'t get pages URL from response content.'); + pushDialog('失败!\n无法从响应内容中获取页面 URL。'); isDownloading = false; } return; @@ -14102,7 +14102,7 @@ function getPagesURLFromMPV() { var curURL = location.origin + '/s/' + elem.k + '/' + unsafeWindow.gid + '-' + (index + 1); pageURLsList.push(curURL); }); - pushDialog('Succeed!'); + pushDialog('成功!'); // copied from getAllPagesURL(), THAT's UGLY!!! @@ -14111,10 +14111,10 @@ function getPagesURLFromMPV() { var wrongPages = pagesRange.filter(function (elem) { return elem > pageURLsList.length; }); if (wrongPages.length !== 0) { pagesRange = pagesRange.filter(function (elem) { return elem <= pageURLsList.length; }); - pushDialog('\nPage ' + wrongPages.join(', ') + (wrongPages.length > 1 ? ' are' : ' is') + ' not exist, and will be ignored.\n'); + pushDialog('\n页 ' + wrongPages.join(', ') + (wrongPages.length > 1 ? ' 不存在' : ' 不存在') + ',将被忽略。\n'); if (pagesRange.length === 0) { - pushDialog('Nothing matches provided pages range, stop downloading.'); - alert('Nothing matches provided pages range, stop downloading.'); + pushDialog('没有符合所提供页码范围的图片,停止下载。'); + alert('没有符合所提供页码范围的图片,停止下载。'); if (emptyAudio) { emptyAudio.pause(); } @@ -14128,7 +14128,7 @@ function getPagesURLFromMPV() { requestDownload(); }; xhr.send(); - pushDialog('Fetching Gallery Pages URL From MPV...'); + pushDialog('正在从 MPV 获取画廊页面 URL...'); } // /*if pages range is set, then*/ get all pages URL to select needed pages @@ -14138,8 +14138,8 @@ function getAllPagesURL() { var retryCount = 0; if (pagesRangeText) { // if pages range is defined - console.log('[EHD] Pages Range >', pagesRangeText); - if (!ehDownloadRegex.pagesRange.test(pagesRangeText)) return alert('The format of Pages Range is incorrect.'); + console.log('[EHD] 页码范围 >', pagesRangeText); + if (!ehDownloadRegex.pagesRange.test(pagesRangeText)) return alert('页码范围格式不正确。'); // range started with negative range, select all as default if (pagesRangeText[0] === '!') { @@ -14192,7 +14192,7 @@ function getAllPagesURL() { if (isMPVAvailable()) { console.log('[EHD] MPV is available, use MPV to fetch all pages'); - pushDialog('MPV is available, use MPV to fetch all pages.\n'); + pushDialog('MPV 可用,使用 MPV 获取所有页面。\n'); return getPagesURLFromMPV(); } @@ -14213,32 +14213,32 @@ function getAllPagesURL() { var responseText = xhr.responseText; if (xhr.status !== 200 || !responseText) { if (retryCount < (setting['retry-count'] !== undefined ? setting['retry-count'] : 3)) { - pushDialog('Failed! Retrying... '); + pushDialog('失败! 重试中... '); retryCount++; xhr.open('GET', location.origin + location.pathname + '?p=' + curPage); xhr.timeout = 30000; xhr.send(); } else { - pushDialog('Failed!\nFetch Pages\' URL failed, Please try again later.'); + pushDialog('失败!\n获取页面 URL 失败,请稍后重试。'); isDownloading = false; - alert('Fetch Pages\' URL failed, Please try again later.'); + alert('获取页面 URL 失败,请稍后重试。'); } return; } var pagesURL = responseText.split('
= 0) { console.log('[EHD] Page 1 URL > ' + pagesURL[0] + ' , use MPV fetch'); - pushDialog('Pages URL is MPV link\n'); + pushDialog('页面 URL 是 MPV 链接\n'); getPagesURLFromMPV(); return; @@ -14256,7 +14256,7 @@ function getAllPagesURL() { for (var i = 0; i < pagesURL.length; i++) { pageURLsList.push(replaceHTMLEntites(pagesURL[i].split('"')[1])); } - pushDialog('Succeed!'); + pushDialog('成功!'); curPage++; @@ -14269,10 +14269,10 @@ function getAllPagesURL() { var wrongPages = pagesRange.filter(function(elem){ return elem > pageURLsList.length; }); if (wrongPages.length !== 0) { pagesRange = pagesRange.filter(function(elem){ return elem <= pageURLsList.length; }); - pushDialog('\nPage ' + wrongPages.join(', ') + (wrongPages.length > 1 ? ' are' : ' is') + ' not exist, and will be ignored.\n'); + pushDialog('\n页 ' + wrongPages.join(', ') + (wrongPages.length > 1 ? ' 不存在' : ' 不存在') + ',将被忽略。\n'); if (pagesRange.length === 0) { - pushDialog('Nothing matches provided pages range, stop downloading.'); - alert('Nothing matches provided pages range, stop downloading.'); + pushDialog('没有符合所提供页码范围的图片,停止下载。'); + alert('没有符合所提供页码范围的图片,停止下载。'); insertCloseButton(); return; } @@ -14285,36 +14285,36 @@ function getAllPagesURL() { else { xhr.open('GET', location.origin + location.pathname + '?p=' + curPage); xhr.send(); - pushDialog('\nFetching Gallery Pages URL (' + (curPage + 1) + '/' + pagesLength + ') ... '); + pushDialog('\n正在获取画廊页面 URL(' + (curPage + 1) + '/' + pagesLength + ') ... '); } }; xhr.ontimeout = xhr.onerror = function(){ if (retryCount < (setting['retry-count'] !== undefined ? setting['retry-count'] : 3)) { - pushDialog('Failed! Retrying... '); + pushDialog('失败! 重试中... '); retryCount++; xhr.open('GET', location.origin + location.pathname + '?p=' + curPage); xhr.timeout = 30000; xhr.send(); } else { - pushDialog('Failed!\nFetch Pages\' URL failed, Please try again later.'); + pushDialog('失败!\n获取页面 URL 失败,请稍后重试。'); isDownloading = false; - alert('Fetch Pages\' URL failed, Please try again later.'); + alert('获取页面 URL 失败,请稍后重试。'); } }; xhr.open('GET', location.origin + location.pathname + '?p=' + curPage); xhr.timeout = 30000; xhr.send(); - pushDialog('\nFetching Gallery Pages URL (' + (curPage + 1) + '/' + (pagesLength || '?') + ') ... '); + pushDialog('\n正在获取画廊页面 URL(' + (curPage + 1) + '/' + (pagesLength || '?') + ') ... '); } else { var wrongPages = pagesRange.filter(function(elem){ return elem > pageURLsList.length; }); if (wrongPages.length !== 0) { pagesRange = pagesRange.filter(function(elem){ return elem <= pageURLsList.length; }); - pushDialog('\nPage ' + wrongPages.join(', ') + (wrongPages.length > 1 ? ' are' : ' is') + ' not exist, and will be ignored.\n'); + pushDialog('\n页 ' + wrongPages.join(', ') + (wrongPages.length > 1 ? ' 不存在' : ' 不存在') + ',将被忽略。\n'); if (pagesRange.length === 0) { - pushDialog('Nothing matches provided pages range, stop downloading.'); - alert('Nothing matches provided pages range, stop downloading.'); + pushDialog('没有符合所提供页码范围的图片,停止下载。'); + alert('没有符合所提供页码范围的图片,停止下载。'); insertCloseButton(); return; } @@ -14375,13 +14375,13 @@ function initEHDownload() { // roll back and use Blob to handle file ehDownloadFS.needFileSystem = false; - alert('An error occured when requesting FileSystem.\n' + - 'Error Name: ' + (e.name || 'Unknown Error') + '\n' + - 'Error Message: ' + e.message + '\n\n' + - 'Roll back and use Blob to handle file.'); + alert('请求 FileSystem 时发生错误。\n' + + '错误名称:' + (e.name || '未知错误') + '\n' + + '错误信息:' + e.message + '\n\n' + + '回退并使用 Blob 处理文件。'); }; - if ((!isTor && !setting['store-in-fs'] && !setting['never-warn-large-gallery'] && requiredMBs >= 300) && !confirm('This archive is too large (original size), please consider downloading this archive in a different way.\n\nMaximum allowed file size: Chrome 56- 500MB | Chrome 57+ 2 GB | Firefox ~800 MB (depends on your RAM)\n\nPlease also consider your operating system\'s free memory (RAM), it may take about DOUBLE the size of archive file size when generating ZIP file.\n\n* If you continue, you would probably get an error like "Failed - No File" or "Out Of Memory" if you don\'t have enough RAM and can\'t save the file successfully.\n\n* If you are using Chrome, you can try enabling "Request File System to handle large Zip file" on the settings page.\n\n* You can set Pages Range to download this archive in parts. If you have already enabled it, please ignore this message.\n\nAre you sure to continue downloading?')) return; + if ((!isTor && !setting['store-in-fs'] && !setting['never-warn-large-gallery'] && requiredMBs >= 300) && !confirm('此压缩包过大(原始大小),请考虑采用其它方式下载此压缩包。\n\n最大允许文件大小:Chrome 56 及以下 500MB | Chrome 57 及以上 2 GB | Firefox 约 800 MB(取决于内存大小)\n\n请同时考虑操作系统可用内存(RAM),生成 ZIP 文件时大约需要压缩包体积两倍的内存。\n\n* 如果继续下载,且你的内存不足,则很可能会出现 “Failed - No File” 或 “Out Of Memory” 等错误,无法成功保存文件。\n\n* 如果你使用的是 Chrome,可以尝试在设置页面启用 “请求 FileSystem 以处理较大的压缩包” 选项。\n\n* 你可以设置 页码范围 来分段下载此压缩包。如果已经启用,请忽略此提示。\n\n确定要继续下载吗?')) return; else if (setting['store-in-fs'] && requestFileSystem && requiredMBs >= (setting['fs-size'] !== undefined ? setting['fs-size'] : 200)) { ehDownloadFS.needFileSystem = true; console.log('[EHD] Required File System Space >', requiredBytes); @@ -14393,7 +14393,7 @@ function initEHDownload() { navigator.webkitTemporaryStorage.queryUsageAndQuota(function (usage, quota) { console.log('[EHD] Free TEMPORARY File System Space >', quota - usage); if (quota - usage < requiredBytes) { - console.log('[EHD] Free TEMPORARY File System Space is not enough.'); + console.log('[EHD] 临时 FileSystem 空间不足。'); // free space is not enough, then use persistent space // in fact, free space of persisent file storage is always 10GiB, even free disk space is not enough @@ -14402,10 +14402,10 @@ function initEHDownload() { if (quota - usage < requiredBytes) { // roll back and use Blob to handle file ehDownloadFS.needFileSystem = false; - alert('You don\'t have enough free space on the drive where Chrome stores user data (Default is system drive, normally it\'s C: ), please delete some files.\n\nNeeds more than ' + (requiredBytes - (quota - usage)) + ' Bytes.\n\nRoll back and use Blob to handle file.'); + alert('Chrome 存储用户数据所在磁盘(默认为系统盘,通常是 C: )可用空间不足,请删除一些文件。\n\n需要额外 ' + (requiredBytes - (quota - usage)) + ' 字节。\n\n已回退并使用 Blob 处理文件。'); } else { - pushDialog('\nPlease allow storing large content if the browser asked for it.\n'); + pushDialog('\n如果浏览器询问,请允许存储大容量内容。\n'); requestFileSystem(window.PERSISTENT, requiredBytes, ehDownloadFS.initHandler, fsErrorHandler); } }, fsErrorHandler); @@ -14427,8 +14427,8 @@ function initEHDownload() { } if (infoNeeds.indexOf('metas') >= 0) { - infoStr += 'Category: ' + document.querySelector('#gdc .cs').textContent.trim() + '\n' + - 'Uploader: ' + replaceHTMLEntites(document.querySelector('#gdn').textContent) + '\n'; + infoStr += '分类: ' + document.querySelector('#gdc .cs').textContent.trim() + '\n' + + '上传者: ' + replaceHTMLEntites(document.querySelector('#gdn').textContent) + '\n'; } var metaNodes = document.querySelectorAll('#gdd tr'); for (var i = 0; i < metaNodes.length; i++) { @@ -14441,7 +14441,7 @@ function initEHDownload() { if (infoNeeds.indexOf('tags') >= 0) { var tagsList = document.querySelectorAll('#taglist tr'); if (tagsList.length && ((tagsList[0] || {}).textContent || '').trim() !== '') { - infoStr += 'Tags:\n'; + infoStr += '标签:\n'; Array.prototype.forEach.call(tagsList, function(elem){ var tds = elem.getElementsByTagName('td'); @@ -14458,12 +14458,12 @@ 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'; + infoStr += '上传者评论:\n' + document.getElementById('comment_0').innerHTML.replace(/
|
/gi, '\n') + '\n\n'; } isDownloading = true; pushDialog(infoStr); - pushDialog('Start downloading at ' + new Date() + '\n'); + pushDialog('开始下载于 ' + new Date() + '\n'); ehDownloadDialog.appendChild(ehDownloadStatus); // get all pages url to fix 403 forbidden (download request was timed out) @@ -14591,8 +14591,8 @@ function getPageData(index) { \ \ \ - Pending...\ - Force Abort\ + 等待中...\ + 强制中止\ '; progressTable.appendChild(node); } @@ -14628,7 +14628,7 @@ function getPageData(index) { retryCount[index]++; updateProgress(nodeList, { - status: 'Retrying (' + retryCount[index] + '/' + (setting['retry-count'] !== undefined ? setting['retry-count'] : 3) + ')...', + status: '重试中(' + retryCount[index] + '/' + (setting['retry-count'] !== undefined ? setting['retry-count'] : 3) + ')...', progress: '', progressText: '', class: 'ehD-pt-warning' @@ -14642,9 +14642,9 @@ function getPageData(index) { failedCount++; fetchCount--; - console.error('[EHD] #' + realIndex + ': Failed getting image URL'); + console.error('[EHD] #' + realIndex + ':获取图片 URL 失败'); updateProgress(nodeList, { - status: 'Failed getting URL', + status: '获取 URL 失败', progress: '0', progressText: '', class: 'ehD-pt-failed' @@ -14681,12 +14681,12 @@ function getPageData(index) { var nextNL = ehDownloadRegex.nl.test(responseText) ? responseText.match(ehDownloadRegex.nl)[1] : null; } catch (error) { - console.error('[EHD] Response content is not correct!', error); + console.error('[EHD] 响应内容不正确!', error); if (retryCount[index] < (setting['retry-count'] !== undefined ? setting['retry-count'] : 3)) { retryCount[index]++; updateProgress(nodeList, { - status: 'Retrying (' + retryCount[index] + '/' + (setting['retry-count'] !== undefined ? setting['retry-count'] : 3) + ')...', + status: '重试中(' + retryCount[index] + '/' + (setting['retry-count'] !== undefined ? setting['retry-count'] : 3) + ')...', progress: '', progressText: '', class: 'ehD-pt-warning' @@ -14700,9 +14700,9 @@ function getPageData(index) { failedCount++; fetchCount--; - console.error('[EHD] #' + realIndex + ': Can\'t get request content from response content'); + console.error('[EHD] #' + realIndex + ':无法从响应内容中获取请求内容'); updateProgress(nodeList, { - status: 'Response Error', + status: '响应错误', progress: '0', progressText: '', class: 'ehD-pt-failed' @@ -14736,7 +14736,7 @@ function getPageData(index) { if (isPausing) { updateProgress(nodeList, { name: '#' + realIndex + ': ' + fileName, - status: 'Auto Paused', + status: '已自动暂停', progress: '', progressText: '', class: 'ehD-pt-failed' @@ -14756,7 +14756,7 @@ function getPageData(index) { retryCount[index]++; updateProgress(nodeList, { - status: 'Retrying (' + retryCount[index] + '/' + (setting['retry-count'] !== undefined ? setting['retry-count'] : 3) + ')...', + status: '重试中(' + retryCount[index] + '/' + (setting['retry-count'] !== undefined ? setting['retry-count'] : 3) + ')...', progress: '', progressText: '', class: 'ehD-pt-warning' @@ -14770,9 +14770,9 @@ function getPageData(index) { failedCount++; fetchCount--; - console.error('[EHD] #' + realIndex + ': Failed getting image URL'); + console.error('[EHD] #' + realIndex + ':获取图片 URL 失败'); updateProgress(nodeList, { - status: 'Failed getting URL', + status: '获取 URL 失败', progress: '0', progressText: '', class: 'ehD-pt-failed' @@ -14792,9 +14792,9 @@ function getPageData(index) { if (typeof fetchThread[index] !== 'undefined' && 'abort' in fetchThread[index]) fetchThread[index].abort(); - console.log('[EHD] #' + (index + 1) + ': Force Aborted By User'); + console.log('[EHD] #' + (index + 1) + ': 强制中止ed By User'); updateProgress(nodeList, { - status: 'Failed! (User Aborted)', + status: '失败! (User Aborted)', progress: '0', progressText: '', class: 'ehD-pt-warning' @@ -14812,107 +14812,107 @@ function showSettings() { ehDownloadSettingPanel.setAttribute('data-active-setting', 'basic'); ehDownloadSettingPanel.innerHTML = '\
    \ -
  • Basic
  • \ -
  • Advanced
  • \ +
  • 基础
  • \ +
  • 高级
  • \
\
\ - ' + ehDownloadArrow + ' Feedback\ + ' + ehDownloadArrow + ' 反馈\ GitHub\ GreasyFork\
\
\
\
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ - \ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ + \
\
\ - * Available templates: \ - {gid} Gallery GID | \ - {token} Gallery token | \ - {title} Gallery title | \ - {subtitle} Gallery sub-title | \ - {tag}, {category} Gallery category | \ - {uploader} Gallery uploader\ + * 可用模板: \ + {gid} 画廊 GID | \ + {token} 画廊令牌 | \ + {title} 画廊标题 | \ + {subtitle} 画廊副标题 | \ + {tag}, {category} 画廊分类 | \ + {uploader} 画廊上传者\
\
\
\
\ -
(1)
\ -
(2)
\ -
\ -
(3)
\ -
(3)
\ -
\ -
\ -
\ -
(4)
\ -
(5)
\ -
\ -
...which includes
\ -
\ -
\ -
\ -
\ -
\ -
\ -
\ -
e >= [5, 3, 2][i]) ? ' style="opacity: 0.5;" title="The patch only applies to Tampermonkey 5.3.2+"' : '') + '>
\ +
(1)
\ +
(2)
\ +
\ +
(3)
\ +
(3)
\ +
\ +
\ +
\ +
(4)
\ +
(5)
\ +
\ +
...其中包括
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
e >= [5, 3, 2][i]) ? ' style="opacity: 0.5;" title="该补丁仅适用于 Tampermonkey 5.3.2+"' : '') + '>
\
\
\ - (1) Higher compression level can get smaller file without lossing any data, but may takes more time. If you have a decent CPU you can set it higher, and if you\'re using macOS set it to at least 1.\ + (1) 更高的压缩级别可以在不损失数据的情况下生成更小的文件,但可能需要更多时间。如果 CPU 性能不错,可以设置得更高;如果你使用 macOS,请至少设置为 1。\
\
\ - (2) This may reduce memory usage but some decompress softwares may not support the Zip file. See JSZip Docs for more info.\ + (2) 这可能减少内存占用,但某些解压软件可能不支持此 Zip 文件。更多信息请参阅 JSZip 文档。\
\
\ - (3) Enable these option will never let you to load from regular image server (or say force loaded from H@H). This may save your image viewing limits (See wiki), but may also cause some download problems, especially if your network cannot connect to specific H@H node.\ + (3) 启用这些选项后,将无法从普通图片服务器加载图片(即强制从 H@H 加载)。这可能节省图片查看额度 (查看 Wiki),但也可能导致下载问题,尤其是网络无法连接到指定 H@H 节点时。\
\
\ - (4) If enabled you can save larger Zip files (probably ~1GB).\ + (4) 启用后可以保存更大的 Zip 文件(可能约 1GB)。\
\
\ - (5) If enabled the script will play slient music to avoid downloading freeze when page is in background (See issue). Only needed if you have the problem, because the audio-playing icon maybe annoying.\ + (5) 启用后,脚本会在页面处于后台时播放静音音乐以避免下载暂停 (查看 Issue)。只有遇到此问题时才需要启用,因为音频播放图标可能很烦人。\
\
\ - (6) Comic book archive is a file type to archive comic images, you can open it with some comic viewer like CDisplay/CDisplayEX, or just extract it as a Zip file. To keep the order of images, you can also enable numbering images.\ + (6) 漫画书归档是一种用于归档漫画图片的文件类型,可以使用 CDisplay/CDisplayEX 等漫画阅读器打开,也可以直接解压为 Zip 文件。若要保持图片顺序,还可以启用图片编号。\
\
\ - (7) If you cannot original images, but you\'ve already logged in and your account is not blocked or used up your limits, it may caused by your cookies is not sent to the server. This feature may helps you to pass your current cookies to the download request, but please enable it ONLY if you cannot download any original images.\ + (7) 如果无法下载原图,但已经登录且账号未被封禁或额度未用尽,可能是 Cookie 没有发送到服务器。此功能可以将当前 Cookie 传递给下载请求,但请仅在无法下载任何原图时启用。\
\
\ - (8) If you have already logged in, but the script detects that you\'re not logged in, you can enable this to skip login check. Please note that if you are not logged in actually, the script will not work as expect.\ + (8) 如果已经登录,但脚本检测到未登录,可以启用此选项跳过登录检查。请注意,如果实际上未登录,脚本将无法正常工作。\
\
\ - (9) If you have problem to download on the same site, like account session is misleading, you can force redirect original download link to another domain. Pass cookies manually may be needed.\ + (9) 如果在同一站点下载时遇到问题(例如账号会话状态异常),可以强制将原图下载链接重定向到另一个域名。可能需要手动传递 Cookie。\
\
\ - (10) Check the image file SHA-1 after downloading, in case the server (mostly H@H server) may return a broken file, or network miscellaneous errors.\ + (10) 下载后检查图片文件的 SHA-1,以防服务器(尤其是 H@H 服务器)返回损坏文件或发生网络异常。\
\
\ - (11) If enabled it may fix the serialized request on latest Chrome (with Manifest V3 extension) + Tampermonkey 5.3.2+, but downloading progress, speed detect and timed out abort may be broken (See issue).\ + (11) 启用后可能修复最新版 Chrome(Manifest V3 扩展)+ Tampermonkey 5.3.2+ 的序列化请求问题,但下载进度、速度检测和超时中止可能失效 (查看 Issue)。\
\
\
\
\
\ '; document.body.appendChild(ehDownloadSettingPanel); @@ -14998,12 +14998,12 @@ function showSettings() { if (setting['patch-tm-serialized-gm-xhr'] && !serializedRequestPatched) { serializedRequestPatched = patchTMSerializedGMXhr(); if (!serializedRequestPatched) { - alert('Patch GM_xhr failed, you may need a hard reload to take effect.') + alert('GM_xhr 补丁失败,可能需要硬刷新(Ctrl+Shift+R / Cmd+Shift+R)才能生效。') } } else if (!setting['patch-tm-serialized-gm-xhr'] && serializedRequestPatched) { serializedRequestPatched = !revertTMSerializedGMXhrPatch(); if (serializedRequestPatched) { - alert('Revert GM_xhr patch failed, you may need a hard reload to take effect.') + alert('还原 GM_xhr 补丁失败,可能需要硬刷新(Ctrl+Shift+R / Cmd+Shift+R)才能生效。') } } @@ -15061,7 +15061,7 @@ function loadImageLimits(forced, host){ return showImageLimits(); } - console.log('[EHD] Request Image Limits From ' + host); + console.log('[EHD] 从 ' + host + ' 请求图片额度'); GM_xmlhttpRequest({ method: 'GET', @@ -15107,7 +15107,7 @@ function showImageLimits(){ }).sort().map(function(elem){ var curData = JSON.parse(localStorage.getItem(elem)); if (curData.suspended) { - return '! Account Suspended !'; + return '! 账号已暂停 !'; } if (curData.ipBanned) { return '! IP Banned !'; @@ -15118,7 +15118,7 @@ function showImageLimits(){ return curData.cur + '/' + curData.total; }); - ehDownloadBox.getElementsByClassName('ehD-box-limit')[0].innerHTML = ' | Image Limits: ' + list.join('; ') + ''; + ehDownloadBox.getElementsByClassName('ehD-box-limit')[0].innerHTML = ' | 图片额度:' + list.join('; ') + ''; } function getFileSizeAndLength() { @@ -15175,8 +15175,8 @@ function toggleFilenameConfirmInput(hide){ else if (!hide) { extendNodes = document.createElement('div'); extendNodes.className = 'ehD-box-extend'; - extendNodes.innerHTML = '
' + ehDownloadArrow + '
' + - '
' + ehDownloadArrow + '
'; + extendNodes.innerHTML = '
' + ehDownloadArrow + '
' + + '
' + ehDownloadArrow + '
'; ehDownloadBox.appendChild(extendNodes); dirName = getReplacedName(!setting['dir-name'] ? '{gid}_{token}' : setting['dir-name']); @@ -15299,9 +15299,9 @@ function showPreCalcCost(){ target="_blank" \ title="' + // (isUsingOriginal && isSourceNexus ? '...or ' + cost + ' if Source Nexus hath perk is not available.\n' : '') + - (isUsingOriginal && !isUsingGP ? '...or ' + leastCost + ' + ' + gp + ' GP if you don\'t have enough viewing limits.\n' : '') + - '1 point per 0.1 MB since August 2019, less than 0.1 MB will also be counted.\nDuring peak hours, downloading original images will cost GPs.\nFor gallery uploaded 1 year ago, downloading original images will cost GPs since July 2023.\nThe GP cost is the same as resetting viewing limits.\nEstimated GP cost is a bit more than using offical archive download, in case the sum of each images will be larger than the packed.">' - + 'Estimated Costs: ' + (/* isSourceNexus ? leastCost : */ cost || '???') + ''; + (isUsingOriginal && !isUsingGP ? '...或在浏览额度不足时,改为消耗 ' + leastCost + ' + ' + gp + ' GP。\n' : '') + + '自 2019 年 8 月起,每 0.1 MB 计 1 点,少于 0.1 MB 也会计入。\n高峰期下载原图将消耗 GP。\n自 2023 年 7 月起,上传满 1 年的画廊下载原图将消耗 GP。\nGP 消耗量与重置浏览额度相同。\n估算的 GP 消耗量比官方压缩包下载略多,因为单张图片之和可能比压缩后的文件更大。">' + + '预计消耗:' + (/* isSourceNexus ? leastCost : */ cost || '???') + ''; } // EHD Box, thanks to JingJang@GitHub, source: https://github.com/JingJang/E-Hentai-Downloader @@ -15318,13 +15318,13 @@ ehDownloadBox.appendChild(ehDownloadStylesheet); var extraHint; if (isInPeakHours() && !isRecentGallery()) { extraHint = document.createElement('a'); - extraHint.setAttribute('title', 'Peak Hours: It\'s in peak hours now, during peak hours, downloading original images of 90 days ago cost GPs'); + extraHint.setAttribute('title', '高峰时段:当前处于高峰时段,在高峰时段下载 90 天前画廊的原图将消耗 GP'); extraHint.textContent = '[P]'; ehDownloadBoxTitle.appendChild(extraHint); } if (isAncientGallery()) { extraHint = document.createElement('a'); - extraHint.setAttribute('title', 'Ancient Gallery: Downloading original images of 1 year ago cost GPs'); + extraHint.setAttribute('title', '老旧画廊:下载 1 年前画廊的原图将消耗 GP'); extraHint.textContent = '[A]'; ehDownloadBoxTitle.appendChild(extraHint); } @@ -15333,19 +15333,19 @@ var ehDownloadArrow = ' 0 && !confirm('There are ' + torrentsCount + ' torrent(s) available for this gallery. You can download the torrent(s) to get a stable and controllable download experience without spending your image limits, or even get bonus content.\n\nContinue downloading with E-Hentai Downloader (Yes) or use torrent(s) directly (No)?\n(You can disable this notification in the Settings)')) { + if (!setting['ignore-torrent'] && torrentsCount > 0 && !confirm('此画廊有 ' + torrentsCount + ' 个种子文件可用。下载种子文件可获得稳定且可控的下载体验,无需消耗图片额度,甚至能获得额外内容。\n\n继续使用 E-Hentai Downloader 下载(是)或直接使用种子(否)?\n(可在 设置 中关闭此提示)')) { return torrentsNode.dispatchEvent(new MouseEvent('click')); } - if (!isTor && unsafeWindow.apiuid === -1 && !setting['force-as-login'] && !confirm('You are not logged in to E-Hentai Forums, so you can\'t download original images.\nIf you\'ve already logged in, please try logout and login again.\nContinue with resized images?')) return; + if (!isTor && unsafeWindow.apiuid === -1 && !setting['force-as-login'] && !confirm('你尚未登录 E-Hentai 论坛,因此无法下载原图。\n若已经登录,请尝试先登出再重新登录。\n是否继续下载重采样图片?')) return; console.log('[EHD] Is Peak Hours >', isInPeakHours(), ' | Is Recent Gallery >', isRecentGallery(), ' | Is Ancient Gallery >', isAncientGallery(), ' | Is Donator >', isDonator()); @@ -15357,11 +15357,11 @@ ehDownloadAction.addEventListener('click', function(event){ // !isSourceNexusEnabled() ) { if (isAncientGallery() && isDonator() < 1) { - if (!confirm('The gallery has been uploaded for a very long time, downloading original images will cost your GPs instead of viewing limits.\nYou can download resized images or disable this notification in script\'s settings.\n\nContinue downloading with original images?')) { + if (!confirm('此画廊上传时间已久,下载原图将消耗你的 GP 而非浏览额度。\n你可以下载重采样图片,或在脚本设置中关闭此提示。\n\n是否继续下载原图?')) { return; } } else { - if (!confirm('It\'s peak hours now, downloading original images will cost your GPs instead of viewing limits.\nYou can download resized images or disable this notification in script\'s settings.\n\nContinue downloading with original images?')) { + if (!confirm('当前处于高峰时段,下载原图将消耗你的 GP 而非浏览额度。\n你可以下载重采样图片,或在脚本设置中关闭此提示。\n\n是否继续下载原图?')) { return; } } @@ -15376,7 +15376,7 @@ ehDownloadAction.addEventListener('click', function(event){ } var finalLimits = +(limitsData.cur || 0) + totalLimitsCost; if (finalLimits > limitsData.total) { - if (!confirm('You may used up your image limits or will run it out, downloading images exceed your limits will cost GPs instead, or credits if you run out of GPs.\nUsed + Estimated = ' + (limitsData.cur || 0) + ' + ' + totalLimitsCost + ' = ' + finalLimits + ' > ' + limitsData.total + '\n\nContinue downloading?')) { + if (!confirm('你可能已用尽或即将用尽图片额度,超额下载将改为消耗 GP;若 GP 不足则会消耗 credits。\n已用 + 预估 = ' + (limitsData.cur || 0) + ' + ' + totalLimitsCost + ' = ' + finalLimits + ' > ' + limitsData.total + '\n\n是否继续下载?')) { return; } } @@ -15390,17 +15390,17 @@ ehDownloadBox.appendChild(ehDownloadAction); var ehDownloadNumberInput = document.createElement('div'); ehDownloadNumberInput.className = 'g2'; -ehDownloadNumberInput.innerHTML = ehDownloadArrow + ' '; +ehDownloadNumberInput.innerHTML = ehDownloadArrow + ' '; ehDownloadBox.appendChild(ehDownloadNumberInput); var ehDownloadRange = document.createElement('div'); ehDownloadRange.className = 'g2'; -ehDownloadRange.innerHTML = ehDownloadArrow + ' '; +ehDownloadRange.innerHTML = ehDownloadArrow + ' '; ehDownloadBox.appendChild(ehDownloadRange); var ehDownloadSetting = document.createElement('div'); ehDownloadSetting.className = 'g2'; -ehDownloadSetting.innerHTML = ehDownloadArrow + ' Settings'; +ehDownloadSetting.innerHTML = ehDownloadArrow + ' 设置'; ehDownloadSetting.addEventListener('click', function(event){ event.preventDefault(); showSettings(); @@ -15422,11 +15422,11 @@ ehDownloadStatus.addEventListener('click', function(event){ var ehDownloadPauseBtn = document.createElement('button'); ehDownloadPauseBtn.className = 'ehD-pause'; -ehDownloadPauseBtn.textContent ='Pause'; +ehDownloadPauseBtn.textContent ='暂停'; ehDownloadPauseBtn.addEventListener('click', function(event){ if (!isPausing) { isPausing = true; - ehDownloadPauseBtn.textContent = 'Resume'; + ehDownloadPauseBtn.textContent = '继续'; if (setting['force-pause']) { // waiting Tampermonkey for transfering string to ArrayBuffer, it may stuck for a second @@ -15436,7 +15436,7 @@ ehDownloadPauseBtn.addEventListener('click', function(event){ if (imageData[i] === 'Fetching' && retryCount[i] < (setting['retry-count'] !== undefined ? setting['retry-count'] : 3)) { var elem = progressTable.querySelector('tr[data-index="' + i + '"] .ehD-pt-status-text'); - if (elem) elem.textContent = 'Force Paused'; + if (elem) elem.textContent = '已强制暂停'; elem = progressTable.querySelector('tr[data-index="' + i + '"] .ehD-pt-progress-text'); if (elem) elem.textContent = ''; @@ -15457,7 +15457,7 @@ ehDownloadPauseBtn.addEventListener('click', function(event){ } else { isPausing = false; - ehDownloadPauseBtn.textContent = setting['force-pause'] ? 'Pause (Downloading images will be aborted)' : 'Pause (Downloading images will keep downloading)'; + ehDownloadPauseBtn.textContent = setting['force-pause'] ? '暂停(将中止正在下载的图片)' : '暂停(正在下载的图片将继续下载)'; checkFailed(); } @@ -15467,20 +15467,20 @@ window.addEventListener('focus', function(){ if (setting['status-in-title'] === 'blur') { if (!needTitleStatus) return; document.title = pretitle; - needTitleStatus = false; + needTitle状态 = false; } }); window.addEventListener('blur', function(){ if (isDownloading && setting['status-in-title'] === 'blur') { - needTitleStatus = true; + needTitle状态 = true; document.title = '[' + (isPausing ? '❙❙' : downloadedCount < totalCount ? '↓ ' + downloadedCount + '/' + totalCount : totalCount === 0 ? '↓' : '√' ) + '] ' + pretitle; } }); var forceDownloadTips = document.createElement('div'); forceDownloadTips.className = 'ehD-force-download-tips'; -forceDownloadTips.innerHTML = 'If an error occured and script doesn\'t work, click here to force get your downloaded images.'; +forceDownloadTips.innerHTML = '若出现错误且脚本无法正常工作,点击 此处 以强制获取已下载的图片。'; forceDownloadTips.getElementsByTagName('a')[0].addEventListener('click', function(event){ // fixed permission denied on GreaseMonkey event.preventDefault(); @@ -15489,7 +15489,7 @@ forceDownloadTips.getElementsByTagName('a')[0].addEventListener('click', functio var closeTips = document.createElement('div'); closeTips.className = 'ehD-close-tips'; -closeTips.innerHTML = 'E-Hentai Downloader is still running, please don\'t close this tab until it finished downloading.

If any bug occured and the script doesn\'t work correctly, you can move your mouse pointer onto the progress box, and force to save downloaded images before you leave.'; +closeTips.innerHTML = 'E-Hentai Downloader 仍在运行中,请勿关闭此标签页,直到下载完成。

若出现 bug 且脚本无法正常工作,可将鼠标移至进度框上,在离开前强制保存已下载的图片。'; unsafeWindow.getzip = window.getzip = function(){ saveDownloaded(true); @@ -15513,7 +15513,7 @@ window.onbeforeunload = unsafeWindow.onbeforeunload = function(){ document.body.removeChild(closeTips); }, 100); - return 'E-Hentai Downloader is still running, please don\'t close this tab until it finished downloading.'; + return 'E-Hentai Downloader 仍在运行中,请勿关闭此标签页,直到下载完成。'; } clearRubbish(); };