= 0) {
2035 | console.log('[EHD] Page 1 URL > ' + pagesURL[0] + ' , use MPV fetch');
2036 | pushDialog('Pages URL is MPV link\n');
2037 |
2038 | getPagesURLFromMPV();
2039 | return;
2040 | }
2041 |
2042 | for (var i = 0; i < pagesURL.length; i++) {
2043 | pageURLsList.push(replaceHTMLEntites(pagesURL[i].split('"')[1]));
2044 | }
2045 | pushDialog('Succeed!');
2046 |
2047 | curPage++;
2048 |
2049 | if (!pagesLength) { // can't get pagesLength correctly before
2050 | pagesLength = responseText.match(ehDownloadRegex.pagesLength)[1] - 0;
2051 | }
2052 |
2053 | if (curPage === pagesLength) {
2054 | getAllPagesURLFin = true;
2055 | var wrongPages = pagesRange.filter(function(elem){ return elem > pageURLsList.length; });
2056 | if (wrongPages.length !== 0) {
2057 | pagesRange = pagesRange.filter(function(elem){ return elem <= pageURLsList.length; });
2058 | pushDialog('\nPage ' + wrongPages.join(', ') + (wrongPages.length > 1 ? ' are' : ' is') + ' not exist, and will be ignored.\n');
2059 | if (pagesRange.length === 0) {
2060 | pushDialog('Nothing matches provided pages range, stop downloading.');
2061 | alert('Nothing matches provided pages range, stop downloading.');
2062 | insertCloseButton();
2063 | return;
2064 | }
2065 | }
2066 | totalCount = pagesRange.length || pageURLsList.length;
2067 | pushDialog('\n\n');
2068 | initProgressTable();
2069 | requestDownload();
2070 | }
2071 | else {
2072 | xhr.open('GET', location.origin + location.pathname + '?p=' + curPage);
2073 | xhr.send();
2074 | pushDialog('\nFetching Gallery Pages URL (' + (curPage + 1) + '/' + pagesLength + ') ... ');
2075 | }
2076 | };
2077 | xhr.ontimeout = xhr.onerror = function(){
2078 | if (retryCount < (setting['retry-count'] !== undefined ? setting['retry-count'] : 3)) {
2079 | pushDialog('Failed! Retrying... ');
2080 | retryCount++;
2081 | xhr.open('GET', location.origin + location.pathname + '?p=' + curPage);
2082 | xhr.timeout = 30000;
2083 | xhr.send();
2084 | }
2085 | else {
2086 | pushDialog('Failed!\nFetch Pages\' URL failed, Please try again later.');
2087 | isDownloading = false;
2088 | alert('Fetch Pages\' URL failed, Please try again later.');
2089 | }
2090 | };
2091 | xhr.open('GET', location.origin + location.pathname + '?p=' + curPage);
2092 | xhr.timeout = 30000;
2093 | xhr.send();
2094 | pushDialog('\nFetching Gallery Pages URL (' + (curPage + 1) + '/' + (pagesLength || '?') + ') ... ');
2095 | }
2096 | else {
2097 | var wrongPages = pagesRange.filter(function(elem){ return elem > pageURLsList.length; });
2098 | if (wrongPages.length !== 0) {
2099 | pagesRange = pagesRange.filter(function(elem){ return elem <= pageURLsList.length; });
2100 | pushDialog('\nPage ' + wrongPages.join(', ') + (wrongPages.length > 1 ? ' are' : ' is') + ' not exist, and will be ignored.\n');
2101 | if (pagesRange.length === 0) {
2102 | pushDialog('Nothing matches provided pages range, stop downloading.');
2103 | alert('Nothing matches provided pages range, stop downloading.');
2104 | insertCloseButton();
2105 | return;
2106 | }
2107 | }
2108 |
2109 | totalCount = pagesRange.length || pageURLsList.length;
2110 | pushDialog('\n\n');
2111 | initProgressTable();
2112 | requestDownload();
2113 | }
2114 | }
2115 |
2116 | function initEHDownload() {
2117 | for (var i = 0; i < fetchThread.length; i++) {
2118 | if (typeof fetchThread[i] !== 'undefined' && 'abort' in fetchThread[i]) fetchThread[i].abort();
2119 | }
2120 | imageList = [];
2121 | imageData = [];
2122 | fetchThread = [];
2123 | retryCount = [];
2124 | downloadedCount = fetchCount = failedCount = 0;
2125 | isPausing = false;
2126 | zip = new JSZip();
2127 | infoStr = '';
2128 | fetchPagesXHR.abort();
2129 |
2130 | if (setting['recheck-file-name']) {
2131 | var dirNameNode = document.querySelector('.ehD-box-extend-dirname');
2132 | var fileNameNode = document.querySelector('.ehD-box-extend-filename');
2133 |
2134 | if (dirNameNode && dirNameNode.value) {
2135 | dirName = getSafeName(dirNameNode.value, true);
2136 | }
2137 | else {
2138 | dirName = getReplacedName(!setting['dir-name'] ? '{gid}_{token}' : setting['dir-name']);
2139 | }
2140 |
2141 | if (fileNameNode && fileNameNode.value) {
2142 | fileName = getSafeName(fileNameNode.value);
2143 | }
2144 | else {
2145 | fileName = getReplacedName(!setting['file-name'] ? '{title}' : setting['file-name']);
2146 | }
2147 | }
2148 | else {
2149 | dirName = getReplacedName(!setting['dir-name'] ? '{gid}_{token}' : setting['dir-name']);
2150 | fileName = getReplacedName(!setting['file-name'] ? '{title}' : setting['file-name']);
2151 | }
2152 |
2153 | if (dirName.trim() === '/') dirName = '';
2154 | needNumberImages = ehDownloadNumberInput.querySelector('input').checked;
2155 |
2156 | var requiredBytes = Math.ceil(getFileSizeAndLength().size + 100 * 1024);
2157 | var requiredMBs = getFileSizeAndLength().sizeMB + 0.1;
2158 |
2159 | var fsErrorHandler = function (error) {
2160 | ehDownloadFS.errorHandler(error);
2161 |
2162 | // roll back and use Blob to handle file
2163 | ehDownloadFS.needFileSystem = false;
2164 | alert('An error occured when requesting FileSystem.\n' +
2165 | 'Error Name: ' + (e.name || 'Unknown Error') + '\n' +
2166 | 'Error Message: ' + e.message + '\n\n' +
2167 | 'Roll back and use Blob to handle file.');
2168 | };
2169 |
2170 | 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;
2171 | else if (setting['store-in-fs'] && requestFileSystem && requiredMBs >= (setting['fs-size'] !== undefined ? setting['fs-size'] : 200)) {
2172 | ehDownloadFS.needFileSystem = true;
2173 | console.log('[EHD] Required File System Space >', requiredBytes);
2174 |
2175 | // Chrome can use about 10% of free space of disk where Chrome User Data stored in as TEMPORARY File System Storage.
2176 | if (navigator.webkitTemporaryStorage) { // if support navigator.webkitTemporaryStorage to check usable space
2177 | // use `queryUsageAndQuota` instead of `requestQuota` to check storage space,
2178 | // because `requestQuota` is incorrect when harddisk is full, says have about 5GB storage
2179 | navigator.webkitTemporaryStorage.queryUsageAndQuota(function (usage, quota) {
2180 | console.log('[EHD] Free TEMPORARY File System Space >', quota - usage);
2181 | if (quota - usage < requiredBytes) {
2182 | console.log('[EHD] Free TEMPORARY File System Space is not enough.');
2183 |
2184 | // free space is not enough, then use persistent space
2185 | // in fact, free space of persisent file storage is always 10GiB, even free disk space is not enough
2186 | navigator.webkitPersistentStorage.queryUsageAndQuota(function (usage, quota) {
2187 | console.log('[EHD] Free PERSISTENT File System Space >', quota - usage);
2188 | if (quota - usage < requiredBytes) {
2189 | // roll back and use Blob to handle file
2190 | ehDownloadFS.needFileSystem = false;
2191 | 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.');
2192 | }
2193 | else {
2194 | pushDialog('\n
Please allow storing large content if the browser asked for it. \n');
2195 | requestFileSystem(window.PERSISTENT, requiredBytes, ehDownloadFS.initHandler, fsErrorHandler);
2196 | }
2197 | }, fsErrorHandler);
2198 | }
2199 | else requestFileSystem(window.TEMPORARY, requiredBytes, ehDownloadFS.initHandler, fsErrorHandler);
2200 | }, fsErrorHandler);
2201 | }
2202 | else requestFileSystem(window.TEMPORARY, requiredBytes, ehDownloadFS.initHandler, fsErrorHandler);
2203 | }
2204 |
2205 | // Array.prototype.some() is a bit ugly, so we use toString().indexOf() lol
2206 | var infoNeeds = setting['save-info-list'].toString();
2207 | if (infoNeeds.indexOf('title') >= 0) {
2208 | infoStr += replaceHTMLEntites(
2209 | document.getElementById('gn').textContent + '\n' +
2210 | document.getElementById('gj').textContent + '\n' +
2211 | window.location.href + '\n\n'
2212 | );
2213 | }
2214 |
2215 | if (infoNeeds.indexOf('metas') >= 0) {
2216 | infoStr += 'Category: ' + document.querySelector('#gdc .cs').textContent.trim() + '\n' +
2217 | 'Uploader: ' + replaceHTMLEntites(document.querySelector('#gdn').textContent) + '\n';
2218 | }
2219 | var metaNodes = document.querySelectorAll('#gdd tr');
2220 | for (var i = 0; i < metaNodes.length; i++) {
2221 | var c1 = replaceHTMLEntites(metaNodes[i].getElementsByClassName('gdt1')[0].textContent);
2222 | var c2 = replaceHTMLEntites(metaNodes[i].getElementsByClassName('gdt2')[0].textContent);
2223 | if (infoNeeds.indexOf('metas') >= 0) infoStr += c1 + ' ' + c2 + '\n';
2224 | }
2225 | if (infoNeeds.indexOf('metas') >= 0) infoStr += 'Rating: ' + unsafeWindow.average_rating + '\n\n';
2226 |
2227 | if (infoNeeds.indexOf('tags') >= 0) {
2228 | infoStr += 'Tags:\n';
2229 |
2230 | var tagsList = document.querySelectorAll('#taglist tr');
2231 | Array.prototype.forEach.call(tagsList, function(elem){
2232 | var tds = elem.getElementsByTagName('td');
2233 | infoStr += '> ' + tds[0].textContent + ' ';
2234 |
2235 | var tags = tds[1].querySelectorAll('a');
2236 | infoStr += Array.prototype.map.call(tags, function(e){
2237 | return e.textContent;
2238 | }).join(', ') + '\n';
2239 | });
2240 |
2241 | infoStr += '\n';
2242 | }
2243 |
2244 | if (infoNeeds.indexOf('uploader-comment') >= 0 && document.getElementById('comment_0')) {
2245 | infoStr += 'Uploader Comment:\n' + document.getElementById('comment_0').innerHTML.replace(/
|
/gi, '\n') + '\n\n';
2246 | }
2247 | isDownloading = true;
2248 | pushDialog(infoStr);
2249 |
2250 | pushDialog('Start downloading at ' + new Date() + '\n');
2251 | ehDownloadDialog.appendChild(ehDownloadStatus);
2252 |
2253 | // get all pages url to fix 403 forbidden (download request was timed out)
2254 | getAllPagesURL();
2255 |
2256 | // init playing music
2257 | if (setting['play-silent-music'] && !emptyAudio) {
2258 | emptyAudio = new Audio(emptyAudioFile);
2259 | emptyAudio.loop = true;
2260 | }
2261 | }
2262 |
2263 | function initVisibilityListener() {
2264 | var hidden, visibilityChange;
2265 | if (typeof document.hidden !== 'undefined') { // Opera 12.10 and Firefox 18 and later support
2266 | hidden = 'hidden';
2267 | visibilityChange = 'visibilitychange';
2268 | }
2269 | else if (typeof document.mozHidden !== 'undefined') {
2270 | hidden = 'mozHidden';
2271 | visibilityChange = 'mozvisibilitychange';
2272 | }
2273 | else if (typeof document.webkitHidden !== 'undefined') {
2274 | hidden = 'webkitHidden';
2275 | visibilityChange = 'webkitvisibilitychange';
2276 | }
2277 |
2278 | var visibilityChangeHandler = function (isHidden) {
2279 | if (typeof isHidden !== 'boolean') {
2280 | isHidden = document[hidden];
2281 | }
2282 | visibleState = !isHidden;
2283 | if (!emptyAudio) {
2284 | return;
2285 | }
2286 | if (isHidden && ((isDownloading && !isPausing) || isSaving)) {
2287 | emptyAudio.play();
2288 | }
2289 | else {
2290 | emptyAudio.pause();
2291 | loadImageLimits();
2292 | }
2293 | };
2294 |
2295 | if (visibilityChange) {
2296 | window.addEventListener(visibilityChange, visibilityChangeHandler);
2297 | }
2298 | else {
2299 | window.addEventListener('focus', function () {
2300 | visibilityChangeHandler(false);
2301 | });
2302 | window.addEventListener('blur', function () {
2303 | visibilityChangeHandler(true);
2304 | });
2305 | }
2306 |
2307 | visibilityChangeHandler();
2308 | }
2309 |
2310 | function initProgressTable(){
2311 | progressTable = document.createElement('table');
2312 | progressTable.className = 'ehD-pt';
2313 | ehDownloadDialog.style.display = 'block';
2314 | ehDownloadDialog.appendChild(progressTable);
2315 | ehDownloadDialog.appendChild(forceDownloadTips);
2316 | ehDownloadDialog.appendChild(ehDownloadPauseBtn);
2317 | ehDownloadDialog.scrollTop = ehDownloadDialog.scrollHeight;
2318 | }
2319 |
2320 | function requestDownload(ignoreFailed){
2321 | if (isPausing) return;
2322 |
2323 | if (setting['delay-request']) {
2324 | var curTime = Date.now();
2325 | if (delayTime < curTime) {
2326 | delayTime = curTime;
2327 | }
2328 | }
2329 |
2330 | var j = 0;
2331 | for (var i = fetchCount; i < (setting['thread-count'] !== undefined ? setting['thread-count'] : 5); i++) {
2332 | for (/*var j = 0*/; j < totalCount; j++) {
2333 | if (imageData[j] == null && (ignoreFailed || (retryCount[j] || 0) <= (setting['retry-count'] !== undefined ? setting['retry-count'] : 3))) {
2334 | imageData[j] = 'Fetching';
2335 | if (imageList[j] && setting['never-new-url']) fetchOriginalImage(j);
2336 | else if (setting['delay-request']) {
2337 | setTimeout(function(j) {
2338 | if (isPausing || fetchCount >= (setting['thread-count'] !== undefined ? setting['thread-count'] : 5)) {
2339 | imageData[j] = null;
2340 | return;
2341 | }
2342 | getPageData(j);
2343 | fetchCount++;
2344 | }, delayTime - curTime + setting['delay-request'] * 1000, j);
2345 | delayTime += setting['delay-request'] * 1000;
2346 | }
2347 | else {
2348 | getPageData(j);
2349 | fetchCount++;
2350 | }
2351 | break;
2352 | }
2353 | }
2354 | }
2355 |
2356 | }
2357 |
2358 | function getPageData(index) {
2359 | if (isPausing) return;
2360 |
2361 | if (pagesRange.length) var realIndex = pagesRange[index];
2362 | else var realIndex = index + 1;
2363 |
2364 | var needScrollIntoView = ehDownloadDialog.clientHeight + ehDownloadDialog.scrollTop >= ehDownloadDialog.scrollHeight - 5;
2365 |
2366 | var node = progressTable.querySelector('tr[data-index="' + index + '"]');
2367 | if (!node) {
2368 | node = document.createElement('tr');
2369 | node.className = 'ehD-pt-item';
2370 | node.setAttribute('data-index', index);
2371 | node.innerHTML = '\
2372 |
#' + realIndex + ' \
2373 |
\
2374 | \
2375 | \
2376 | \
2377 |
\
2378 | Pending... \
2379 | Force Abort \
2380 | ';
2381 | progressTable.appendChild(node);
2382 | }
2383 | if (needScrollIntoView) {
2384 | ehDownloadDialog.scrollTop = ehDownloadDialog.scrollHeight;
2385 | }
2386 |
2387 | var nodeList = {
2388 | current: node,
2389 | fileName: node.getElementsByTagName('td')[0],
2390 | status: node.getElementsByTagName('td')[2],
2391 | statusText: node.getElementsByClassName('ehD-pt-status-text')[0],
2392 | progress: node.getElementsByTagName('progress')[0],
2393 | progressText: node.getElementsByTagName('span')[0],
2394 | abort: node.getElementsByClassName('ehD-pt-abort')[0]
2395 | };
2396 |
2397 | retryCount[index] = 0;
2398 | var fetchURL = replaceHTMLEntites(imageList[index] ? (
2399 | imageList[index]['pageURL'] + (
2400 | (!setting['never-send-nl'] && imageList[index]['nextNL']) ? (
2401 | imageList[index]['pageURL'].indexOf('?') >= 0 ? '&' : '?'
2402 | ) + 'nl=' + imageList[index]['nextNL'] : ''
2403 | )
2404 | ) : pageURLsList[realIndex - 1])/*.replace(/^https?:/, '')*/;
2405 |
2406 | // assign to fetchThread, so that we can abort them and all GM_xhr by one command fetchThread[i].abort()
2407 | var xhr = fetchThread[index] = new XMLHttpRequest();
2408 | xhr.onload = function() {
2409 | var responseText = xhr.responseText;
2410 | if (xhr.status !== 200 || !responseText) {
2411 | if (retryCount[index] < (setting['retry-count'] !== undefined ? setting['retry-count'] : 3)) {
2412 | retryCount[index]++;
2413 |
2414 | updateProgress(nodeList, {
2415 | status: 'Retrying (' + retryCount[index] + '/' + (setting['retry-count'] !== undefined ? setting['retry-count'] : 3) + ')...',
2416 | progress: '',
2417 | progressText: '',
2418 | class: 'ehD-pt-warning'
2419 | });
2420 |
2421 | xhr.open('GET', fetchURL);
2422 | xhr.timeout = 30000;
2423 | xhr.send();
2424 | }
2425 | else {
2426 | failedCount++;
2427 | fetchCount--;
2428 |
2429 | console.error('[EHD] #' + realIndex + ': Failed getting image URL');
2430 | updateProgress(nodeList, {
2431 | status: 'Failed getting URL',
2432 | progress: '0',
2433 | progressText: '',
2434 | class: 'ehD-pt-failed'
2435 | });
2436 | updateTotalStatus();
2437 |
2438 | checkFailed();
2439 | }
2440 |
2441 | return;
2442 | }
2443 |
2444 | try {
2445 | var imageURL = replaceHTMLEntites(
2446 | (
2447 | (unsafeWindow.apiuid !== -1 || setting['force-as-login'])
2448 | && ehDownloadRegex.imageURL[0].test(responseText)
2449 | && !setting['force-resized']
2450 | ) ? responseText.match(ehDownloadRegex.imageURL[0])[1] : (
2451 | responseText.indexOf('id="img"') > -1
2452 | ? responseText.match(ehDownloadRegex.imageURL[1])[1]
2453 | : responseText.match(ehDownloadRegex.imageURL[2])[1]
2454 | )
2455 | );
2456 | // append nl to original image in case it fails to load from H@H (wtf it's valid?!)
2457 | if (ehDownloadRegex.originalImagePattern.test(imageURL)) {
2458 | imageURL = imageURL + (
2459 | (imageList[index] && !setting['never-send-nl'] && imageList[index]['nextNL']) ? (
2460 | imageURL.indexOf('?') >= 0 ? '&' : '?'
2461 | ) + 'nl=' + imageList[index]['nextNL'] : ''
2462 | );
2463 | }
2464 | var fileName = replaceHTMLEntites(responseText.match(ehDownloadRegex.fileName)[1]);
2465 | var nextNL = ehDownloadRegex.nl.test(responseText) ? responseText.match(ehDownloadRegex.nl)[1] : null;
2466 | }
2467 | catch (error) {
2468 | console.error('[EHD] Response content is not correct!', error);
2469 | if (retryCount[index] < (setting['retry-count'] !== undefined ? setting['retry-count'] : 3)) {
2470 | retryCount[index]++;
2471 |
2472 | updateProgress(nodeList, {
2473 | status: 'Retrying (' + retryCount[index] + '/' + (setting['retry-count'] !== undefined ? setting['retry-count'] : 3) + ')...',
2474 | progress: '',
2475 | progressText: '',
2476 | class: 'ehD-pt-warning'
2477 | });
2478 |
2479 | xhr.open('GET', fetchURL);
2480 | xhr.timeout = 30000;
2481 | xhr.send();
2482 | }
2483 | else {
2484 | failedCount++;
2485 | fetchCount--;
2486 |
2487 | console.error('[EHD] #' + realIndex + ': Can\'t get request content from response content');
2488 | updateProgress(nodeList, {
2489 | status: 'Response Error',
2490 | progress: '0',
2491 | progressText: '',
2492 | class: 'ehD-pt-failed'
2493 | });
2494 | updateTotalStatus();
2495 | //alert('We can\'t get request content from response content. It\'s possible that E-Hentai changes source code format so that we can\'t find them, or your ISP modifies (or say hijacks) the page content. If it\'s sure that you can access to any pages of E-Hentai, including current page: ' + fetchURL + ' , please report a bug.');
2496 |
2497 | checkFailed();
2498 | }
2499 | return;
2500 | }
2501 |
2502 | var imageNumber = '';
2503 | if (needNumberImages) {
2504 | // Number images, thanks to JingJang@GitHub, source: https://github.com/JingJang/E-Hentai-Downloader
2505 | if (!setting['number-real-index'] && pagesRange.length) { // if pages range was set and number original index is not required
2506 | var len = pagesRange.length.toString().length,
2507 | padding = new Array(len < 3 ? len + 1 : len).join('0');
2508 | imageNumber = (padding + (index + 1)).slice(0 - len);
2509 | }
2510 | else { // pages range was not set (download all pages, so index + 1 === realIndex) or number original index is required
2511 | var len = pageURLsList.length.toString().length,
2512 | padding = new Array(len < 3 ? len + 1 : len).join('0');
2513 | imageNumber = (padding + realIndex).slice(0 - len);
2514 | }
2515 | }
2516 |
2517 | //imageList.push(new PageData(fetchURL, imageURL, fileName, nextNL, realIndex));
2518 | imageList[index] = new PageData(fetchURL, imageURL, fileName, nextNL, realIndex, imageNumber);
2519 |
2520 | if (isPausing) {
2521 | updateProgress(nodeList, {
2522 | name: '#' + realIndex + ': ' + fileName,
2523 | status: 'Auto Paused',
2524 | progress: '',
2525 | progressText: '',
2526 | class: 'ehD-pt-failed'
2527 | });
2528 | fetchCount--;
2529 | imageData[index] = null;
2530 |
2531 | updateTotalStatus();
2532 | }
2533 | else {
2534 | fetchOriginalImage(index, nodeList);
2535 | }
2536 |
2537 | };
2538 | xhr.onerror = xhr.ontimeout = function() {
2539 | if (retryCount[index] < (setting['retry-count'] !== undefined ? setting['retry-count'] : 3)) {
2540 | retryCount[index]++;
2541 |
2542 | updateProgress(nodeList, {
2543 | status: 'Retrying (' + retryCount[index] + '/' + (setting['retry-count'] !== undefined ? setting['retry-count'] : 3) + ')...',
2544 | progress: '',
2545 | progressText: '',
2546 | class: 'ehD-pt-warning'
2547 | });
2548 |
2549 | xhr.open('GET', fetchURL);
2550 | xhr.timeout = 30000;
2551 | xhr.send();
2552 | }
2553 | else {
2554 | failedCount++;
2555 | fetchCount--;
2556 |
2557 | console.error('[EHD] #' + realIndex + ': Failed getting image URL');
2558 | updateProgress(nodeList, {
2559 | status: 'Failed getting URL',
2560 | progress: '0',
2561 | progressText: '',
2562 | class: 'ehD-pt-failed'
2563 | });
2564 | updateTotalStatus();
2565 |
2566 | checkFailed();
2567 | }
2568 | };
2569 |
2570 | xhr.open('GET', fetchURL);
2571 | xhr.timeout = 30000;
2572 | xhr.send();
2573 |
2574 | nodeList.abort.addEventListener('click', function () {
2575 | if (!isDownloading || imageData[index] instanceof ArrayBuffer) return; // Temporarily fixes #31
2576 |
2577 | if (typeof fetchThread[index] !== 'undefined' && 'abort' in fetchThread[index]) fetchThread[index].abort();
2578 |
2579 | console.log('[EHD] #' + (index + 1) + ': Force Aborted By User');
2580 | updateProgress(nodeList, {
2581 | status: 'Failed! (User Aborted)',
2582 | progress: '0',
2583 | progressText: '',
2584 | class: 'ehD-pt-warning'
2585 | });
2586 |
2587 | failedFetching(index, nodeList);
2588 | });
2589 |
2590 | nodeList.status.setAttribute('data-inited-abort', '1');
2591 | }
2592 |
2593 | function showSettings() {
2594 | var ehDownloadSettingPanel = document.createElement('div');
2595 | ehDownloadSettingPanel.className = 'ehD-setting';
2596 | ehDownloadSettingPanel.setAttribute('data-active-setting', 'basic');
2597 | ehDownloadSettingPanel.innerHTML = '\
2598 |
\
2599 | Basic \
2600 | Advanced \
2601 | \
2602 |
\
2603 | ' + ehDownloadArrow + '
Feedback \
2604 |
GitHub \
2605 |
GreasyFork \
2606 |
\
2607 |
\
2608 |
\
2609 |
\
2639 |
\
2640 |
Set compression level as (0 ~ 9, 0 is only store) (1)
\
2641 |
Stream files and create Zip with file descriptors (2)
\
2642 |
Force download resized image (never download original image)
\
2643 |
Never get new image URL when failed to download image (3)
\
2644 |
Never send "nl" GET parameter when getting new image URL (3)
\
2645 |
Never show warning when it\'s in peak hours now
\
2646 |
Never show warning if image limits will probably used out on starting download
\
2647 |
Never show warning when downloading a large gallery (>= 300 MB)
\
2648 |
Use File System to handle large Zip file when gallery is larger than MB (0 is always) (4)
\
2649 |
Play silent music during the process to avoid downloading freeze (5)
\
2650 |
Record and save gallery info as File info.txt Zip comment None
\
2651 |
...which includes Title & Gallery Link Metadatas Tags Uploader Comment Page Links
\
2652 |
Replace forbidden characters with full-width characters instead of dash (-)
\
2653 |
Force drop downloaded images data when pausing download
\
2654 |
Save as CBZ (Comic book archive) file(6)
\
2655 |
Pass cookies manually when downloading images (7)
\
2656 |
Force as logged in (actual login state: ' + (unsafeWindow.apiuid === -1 ? 'no' : 'yes') + ', uid: ' + unsafeWindow.apiuid + ') (8)
\
2657 |
Download original images from current origin e-hentai.org exhentai.org (9)
\
2658 |
Validate downloaded image checksum (10)
\
2659 |
e >= [5, 3, 2][i]) ? ' style="opacity: 0.5;" title="The patch only applies to Tampermonkey 5.3.2+"' : '') + '> Patch Tampermonkey serialized request for Chrome Manifest v3 Extension (11)
\
2660 |
\
2661 |
\
2662 | (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.\
2663 |
\
2664 |
\
2665 | (2) This may reduce memory usage but some decompress softwares may not support the Zip file. See
JSZip Docs for more info.\
2666 |
\
2667 |
\
2668 | (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.\
2669 |
\
2670 |
\
2671 | (4) If enabled you can save larger Zip files (probably ~1GB).\
2672 |
\
2673 |
\
2674 | (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.\
2675 |
\
2676 |
\
2677 | (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.\
2678 |
\
2679 |
\
2680 | (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.\
2681 |
\
2682 |
\
2683 | (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.\
2684 |
\
2685 |
\
2686 | (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.\
2687 |
\
2688 |
\
2689 | (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.\
2690 |
\
2691 |
\
2692 | (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) .\
2693 |
\
2694 |
\
2695 |
\
2696 |
\
2697 |
\
2698 | ';
2701 | document.body.appendChild(ehDownloadSettingPanel);
2702 |
2703 | for (var i in setting) {
2704 | if (setting[i] instanceof Array) {
2705 | setting[i].forEach(function(elem){
2706 | var element = ehDownloadSettingPanel.querySelector('input[data-ehd-setting="' + i + '[]"][value="' + elem + '"], select[data-ehd-setting="' + i + '[]"] option[value="' + elem + '"]');
2707 | if (!element) return;
2708 |
2709 | if (element.getAttribute('type') === 'checkbox') {
2710 | element.setAttribute('checked', 'checked');
2711 | }
2712 | else if (element.tagName.toLowerCase() === 'option') {
2713 | element.setAttribute('selected', 'selected');
2714 | }
2715 | else element.value = elem;
2716 | });
2717 | }
2718 | else {
2719 | var element = ehDownloadSettingPanel.querySelector('input[data-ehd-setting="' + i + '"], select[data-ehd-setting="' + i + '"]');
2720 | if (!element) continue;
2721 | if (element.getAttribute('type') === 'checkbox') {
2722 | if (setting[i]) element.setAttribute('checked', 'checked');
2723 | }
2724 | else if (element.tagName.toLowerCase() === 'select') {
2725 | element = element.querySelector('option[value="' + setting[i] + '"]');
2726 | if (!element) continue;
2727 | element.setAttribute('selected', 'selected');
2728 | }
2729 | else element.setAttribute('value', setting[i]);
2730 | }
2731 | }
2732 |
2733 | ehDownloadSettingPanel.getElementsByClassName('ehD-setting-tab')[0].addEventListener('click', function(event){
2734 | var target = event.target;
2735 | if (target.tagName.toLowerCase() === 'li') {
2736 | ehDownloadSettingPanel.setAttribute('data-active-setting', target.dataset.targetSetting);
2737 | }
2738 | });
2739 |
2740 | ehDownloadSettingPanel.getElementsByClassName('ehD-setting-footer')[0].addEventListener('click', function(event){
2741 | var target = event.target;
2742 | if (target.tagName.toLowerCase() === 'button') {
2743 | if (target.dataset.action === 'save') {
2744 | var inputs = ehDownloadSettingPanel.querySelectorAll('input[data-ehd-setting], select[data-ehd-setting]');
2745 | setting = {};
2746 | for (var i = 0; i < inputs.length; i++) {
2747 | if (inputs[i].getAttribute('type') !== 'checkbox' && inputs[i].value === '') continue;
2748 |
2749 | var curSettingName = inputs[i].dataset.ehdSetting;
2750 |
2751 | if (inputs[i].getAttribute('type') === 'checkbox') {
2752 | if (inputs[i].checked) {
2753 | if (inputs[i].hasAttribute('value')) {
2754 | if (curSettingName.indexOf('[]') >= 0) {
2755 | curSettingName = curSettingName.split('[]')[0];
2756 | if (!setting[curSettingName]) setting[curSettingName] = [];
2757 | setting[curSettingName].push(inputs[i].getAttribute('value'));
2758 | }
2759 | else {
2760 | setting[curSettingName] = inputs[i].getAttribute('value');
2761 | }
2762 | }
2763 | else {
2764 | setting[curSettingName] = inputs[i].checked;
2765 | }
2766 | }
2767 | else {
2768 | setting[curSettingName] = inputs[i].checked;
2769 | }
2770 | }
2771 | else if (inputs[i].getAttribute('type') === 'number') {
2772 | setting[curSettingName] = Number(inputs[i].value);
2773 | if (isNaN(setting[curSettingName])) {
2774 | setting[curSettingName] = Number(inputs[i].getAttribute('placeholder'));
2775 | }
2776 | }
2777 | else {
2778 | setting[curSettingName] = inputs[i].value;
2779 | }
2780 | }
2781 |
2782 | if (setting['patch-tm-serialized-gm-xhr'] && !serializedRequestPatched) {
2783 | serializedRequestPatched = patchTMSerializedGMXhr();
2784 | if (!serializedRequestPatched) {
2785 | alert('Patch GM_xhr failed, you may need a hard reload to take effect.')
2786 | }
2787 | } else if (!setting['patch-tm-serialized-gm-xhr'] && serializedRequestPatched) {
2788 | serializedRequestPatched = !revertTMSerializedGMXhrPatch();
2789 | if (serializedRequestPatched) {
2790 | alert('Revert GM_xhr patch failed, you may need a hard reload to take effect.')
2791 | }
2792 | }
2793 |
2794 | GM_setValue('ehD-setting', JSON.stringify(setting));
2795 | }
2796 | document.body.removeChild(ehDownloadSettingPanel);
2797 |
2798 | if (document.querySelector('.ehD-box-extend')) {
2799 | toggleFilenameConfirmInput('reset');
2800 | }
2801 | else {
2802 | toggleFilenameConfirmInput(!setting['recheck-file-name']);
2803 | }
2804 |
2805 | // ehDownloadBox.classList[setting['actions-sticky'] ? 'add' : 'remove']('ehD-box-sticky');
2806 |
2807 | try {
2808 | showPreCalcCost();
2809 | }
2810 | catch (e) { }
2811 | }
2812 | });
2813 |
2814 | Array.prototype.forEach.call(ehDownloadSettingPanel.getElementsByClassName('ehD-setting-content'), function(elem) {
2815 | elem.addEventListener('focusin', function(event){
2816 | ehDownloadSettingPanel.setAttribute('data-active-setting', this.dataset.settingPage);
2817 | // prevent auto-scroll from browser
2818 | ehDownloadSettingPanel.scrollLeft = 0;
2819 | }, true);
2820 | });
2821 | }
2822 |
2823 | function getImageLimits() {
2824 | var host = host || location.hostname;
2825 | if (host === 'exhentai.org') {
2826 | host = 'e-hentai.org';
2827 | }
2828 |
2829 | var preData = JSON.parse(localStorage.getItem('ehd-image-limits-' + host) || '{"timestamp":0}');
2830 | return preData;
2831 | }
2832 |
2833 | function loadImageLimits(forced, host){
2834 | if (!visibleState) {
2835 | return;
2836 | }
2837 | var host = host || location.hostname;
2838 | if (host === 'exhentai.org') {
2839 | host = 'e-hentai.org';
2840 | }
2841 | var url = 'https://' + host + '/home.php';
2842 |
2843 | var preData = getImageLimits();
2844 | if (!forced && new Date() - preData.timestamp < 30000) {
2845 | return showImageLimits();
2846 | }
2847 |
2848 | console.log('[EHD] Request Image Limits From ' + host);
2849 |
2850 | GM_xmlhttpRequest({
2851 | method: 'GET',
2852 | url: url,
2853 | timeout: 300000,
2854 | onload: function(res) {
2855 | var responseText = res.responseText;
2856 | if (!responseText) return;
2857 | preData.timestamp = new Date().getTime();
2858 | if (responseText.indexOf('as your account has been suspended') >= 0) {
2859 | preData.suspended = true;
2860 | }
2861 | else if (responseText.indexOf('Your IP address has been temporarily banned') >= 0) {
2862 | preData.ipBanned = true;
2863 | }
2864 | else {
2865 | var data = responseText.match(ehDownloadRegex.imageLimits);
2866 | if (!data || data.length < 3) return;
2867 | preData.cur = +data[1].replace(/,/g, '');
2868 | preData.total = +data[2].replace(/,/g, '');
2869 |
2870 | var donatorPower = responseText.match(ehDownloadRegex.donatorPower);
2871 | if (!donatorPower || donatorPower.length < 2) return;
2872 | preData.donatorPower = +donatorPower[1];
2873 | delete preData.suspended;
2874 | delete preData.ipBanned;
2875 | }
2876 | console.log('[EHD] Image Limits >', JSON.stringify(preData));
2877 | localStorage.setItem('ehd-image-limits-' + host, JSON.stringify(preData));
2878 | showImageLimits();
2879 | }
2880 | });
2881 | }
2882 |
2883 | function showImageLimits(){
2884 | // tor doesn't count to normal account since the ip is dynamic, but not sure if it counts for donator/hath perk account
2885 | // if (isTor) {
2886 | // return;
2887 | // }
2888 |
2889 | var list = Object.keys(localStorage).filter(function(elem){
2890 | return elem.indexOf('ehd-image-limits-') === 0;
2891 | }).sort().map(function(elem){
2892 | var curData = JSON.parse(localStorage.getItem(elem));
2893 | if (curData.suspended) {
2894 | return '
! Account Suspended ! ';
2895 | }
2896 | if (curData.ipBanned) {
2897 | return '
! IP Banned ! ';
2898 | }
2899 | if (+curData.cur >= +curData.total) {
2900 | return '
' + curData.cur + '/' + curData.total + ' '
2901 | }
2902 | return curData.cur + '/' + curData.total;
2903 | });
2904 |
2905 | ehDownloadBox.getElementsByClassName('ehD-box-limit')[0].innerHTML = ' |
Image Limits: ' + list.join('; ') + ' ';
2906 | }
2907 |
2908 | function getFileSizeAndLength() {
2909 | // TODO: use api.php if fails
2910 | var context = (document.getElementById('gdd') || {}).textContent || '';
2911 | var sizeText = ((context.split('File Size:')[1] || '').split('Length:')[0] || '').trim();
2912 | var pageText = ((context.split('Length:')[1] || '').split('page')[0] || '').trim() ||
2913 | ((document.querySelector('.gpc') || {}).textContent.split('of').pop().split('images').shift() || '').trim();
2914 |
2915 | var sizeMB, sizeKB;
2916 | var page = pageText - 0;
2917 |
2918 | if (/Mi?B/.test(sizeText)) {
2919 | sizeMB = parseFloat(sizeText) + 0.01;
2920 | sizeKB = sizeMB * 1024;
2921 | }
2922 | else if (/Gi?B/.test(sizeText)) {
2923 | sizeMB = (parseFloat(sizeText) + 0.01) * 1024;
2924 | sizeKB = sizeMB * 1024;
2925 | }
2926 | else {
2927 | sizeMB = 1;
2928 | sizeKB = parseFloat(sizeText);
2929 | }
2930 |
2931 | var result = {
2932 | sizeMB: sizeMB,
2933 | sizeKB: sizeKB,
2934 | size: sizeKB * 1024,
2935 | page: page
2936 | };
2937 |
2938 | getFileSizeAndLength = function(){
2939 | return result;
2940 | };
2941 |
2942 | return result;
2943 | };
2944 |
2945 | function toggleFilenameConfirmInput(hide){
2946 | var extendNodes = document.querySelector('.ehD-box-extend');
2947 | if (extendNodes) {
2948 | if (hide === 'reset') {
2949 | ehDownloadBox.removeChild(extendNodes);
2950 | if (setting['recheck-file-name']) toggleFilenameConfirmInput();
2951 | }
2952 | else if (hide) {
2953 | extendNodes.style.display = 'none';
2954 | }
2955 | else {
2956 | extendNodes.style.display = 'block';
2957 | }
2958 | }
2959 | else if (!hide) {
2960 | extendNodes = document.createElement('div');
2961 | extendNodes.className = 'ehD-box-extend';
2962 | extendNodes.innerHTML = '
' +
2963 | '
';
2964 | ehDownloadBox.appendChild(extendNodes);
2965 |
2966 | dirName = getReplacedName(!setting['dir-name'] ? '{gid}_{token}' : setting['dir-name']);
2967 | fileName = getReplacedName(!setting['file-name'] ? '{title}' : setting['file-name']);
2968 | extendNodes.getElementsByClassName('ehD-box-extend-filename')[0].value = fileName;
2969 | extendNodes.getElementsByClassName('ehD-box-extend-dirname')[0].value = dirName;
2970 | }
2971 | }
2972 |
2973 | function getResolutionSetting(forced){
2974 | var url = '/uconfig.php';
2975 |
2976 | var preData = JSON.parse(localStorage.getItem('ehd-resolution') || '{"timestamp":0}');
2977 | if (!forced && new Date() - preData.timestamp < 3600e3) {
2978 | return;
2979 | }
2980 |
2981 | // tor site don't have original image feature
2982 | if (isTor) {
2983 | localStorage.setItem('ehd-resolution', JSON.stringify({
2984 | withoutHentaiAtHome: 0,
2985 | resolution: 0,
2986 | timestamp: Date.now()
2987 | }));
2988 | return;
2989 | }
2990 |
2991 | console.log('[EHD] Request Resolution Setting');
2992 |
2993 | var xhr = new XMLHttpRequest();
2994 | xhr.onload = function() {
2995 | var responseText = xhr.responseText;
2996 | if (!responseText) return;
2997 | var preData = {
2998 | withoutHentaiAtHome: +((responseText.match(/id="uh_(\d)" checked/) || [])[1] || 0),
2999 | resolution: +((responseText.match(/id="xr_(\d)" checked/) || [])[1] || 0),
3000 | originalImages: +((responseText.match(/id="oi_(\d)".*? checked/) || [])[1] || 0),
3001 | mpvAvailable: responseText.indexOf('name="qb"') >= 0,
3002 | timestamp: Date.now()
3003 | };
3004 | console.log('[EHD] Resolution Setting >', JSON.stringify(preData));
3005 | localStorage.setItem('ehd-resolution', JSON.stringify(preData));
3006 | try {
3007 | showPreCalcCost();
3008 | }
3009 | catch (e) { }
3010 | };
3011 | xhr.open('GET', url);
3012 | xhr.send();
3013 | }
3014 |
3015 | function preCalculateCost(){
3016 | // tor doesn't count to normal account since the ip is dynamic, but not sure if it counts for donator/hath perk account
3017 | // if (isTor) {
3018 | // return;
3019 | // }
3020 |
3021 | var resolutionSetting = JSON.parse(localStorage.getItem('ehd-resolution') || '{"timestamp":0}');
3022 | var resolutionCost = {
3023 | 0: 1,
3024 | 1: 1,
3025 | 2: 1,
3026 | 3: 1,
3027 | 4: 3,
3028 | 5: 5
3029 | };
3030 | var info = getFileSizeAndLength();
3031 | var size = info.size;
3032 | var page = info.page;
3033 | var perCost = resolutionCost[resolutionSetting.resolution || 0];
3034 | if ((resolutionSetting.withoutHentaiAtHome || 0) > 1) {
3035 | perCost += 10;
3036 | }
3037 | var leastCost = page * perCost;
3038 | // 1 point per 0.1 MB since August 2019, less than 0.1 MB will also be counted, so asumme each image size has the extra < 100 KB
3039 | var normalCost = Math.ceil((size / 1e5) + page * (1 + perCost));
3040 | var cost = leastCost;
3041 | var gp = Math.ceil(size / 1e5) * 2 + page;
3042 | var isUsingGP = false;
3043 | var isUsingOriginal = !setting['force-resized'] && !isTor;
3044 | // var isSourceNexus = isSourceNexusEnabled();
3045 |
3046 | // tor site don't have original image feature
3047 | if (isUsingOriginal) {
3048 | if (isGPRequired()) {
3049 | isUsingGP = true;
3050 | }
3051 | if (!isUsingGP) {
3052 | cost = normalCost;
3053 | } else {
3054 | cost = leastCost + ' + ' + gp + ' GP';
3055 | }
3056 | }
3057 |
3058 | var result = {
3059 | cost: cost,
3060 | normalCost: normalCost,
3061 | leastCost: leastCost,
3062 | perCost: perCost,
3063 | gp: gp,
3064 | isUsingOriginal: isUsingOriginal,
3065 | isUsingGP: isUsingGP,
3066 | };
3067 |
3068 | console.log('[EHD] Pre-calculate estimated cost >', JSON.stringify(result));
3069 | return result;
3070 | }
3071 |
3072 | function showPreCalcCost(){
3073 | var data = preCalculateCost();
3074 | var isUsingOriginal = data.isUsingOriginal;
3075 | var isUsingGP = data.isUsingGP;
3076 | var leastCost = data.leastCost;
3077 | var gp = data.gp;
3078 | var cost = data.cost;
3079 |
3080 | ehDownloadBox.getElementsByClassName('ehD-box-cost')[0].innerHTML = ' | \
3081 |
'
3088 | + 'Estimated Costs: ' + (/* isSourceNexus ? leastCost : */ cost || '???') + ' ';
3089 | }
3090 |
3091 | // EHD Box, thanks to JingJang@GitHub, source: https://github.com/JingJang/E-Hentai-Downloader
3092 | var ehDownloadBox = document.createElement('fieldset');
3093 | ehDownloadBox.className = 'ehD-box';
3094 | var ehDownloadBoxTitle = document.createElement('legend');
3095 | ehDownloadBoxTitle.innerHTML = 'E-Hentai Downloader
';
3096 | if (origin.indexOf('exhentai.org') >= 0) ehDownloadBoxTitle.style.color = '#ffff66';
3097 | ehDownloadBox.appendChild(ehDownloadBoxTitle);
3098 | var ehDownloadStylesheet = document.createElement('style');
3099 | ehDownloadStylesheet.textContent = ehDownloadStyle;
3100 | ehDownloadBox.appendChild(ehDownloadStylesheet);
3101 |
3102 | var extraHint;
3103 | if (isInPeakHours() && !isRecentGallery()) {
3104 | extraHint = document.createElement('a');
3105 | extraHint.setAttribute('title', 'Peak Hours: It\'s in peak hours now, during peak hours, downloading original images of 90 days ago cost GPs');
3106 | extraHint.textContent = '[P]';
3107 | ehDownloadBoxTitle.appendChild(extraHint);
3108 | }
3109 | if (isAncientGallery()) {
3110 | extraHint = document.createElement('a');
3111 | extraHint.setAttribute('title', 'Ancient Gallery: Downloading original images of 1 year ago cost GPs');
3112 | extraHint.textContent = '[A]';
3113 | ehDownloadBoxTitle.appendChild(extraHint);
3114 | }
3115 |
3116 | var ehDownloadArrow = '
';
3117 |
3118 | var ehDownloadAction = document.createElement('div');
3119 | ehDownloadAction.className = 'g2';
3120 | ehDownloadAction.innerHTML = ehDownloadArrow + '
Download Archive ';
3121 | ehDownloadAction.addEventListener('click', function(event){
3122 | event.preventDefault();
3123 |
3124 | var torrentsNode = document.querySelector('#gd5 a[onclick*="gallerytorrents.php"]');
3125 | var torrentsCount = torrentsNode ? torrentsNode.textContent.match(/\d+/)[0] - 0 : 0;
3126 | if (isDownloading && !confirm('E-Hentai Downloader is working now, are you sure to stop downloading and start a new download?')) return;
3127 |
3128 | if (!setting['ignore-torrent'] && torrentsCount > 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)')) {
3129 | return torrentsNode.dispatchEvent(new MouseEvent('click'));
3130 | }
3131 |
3132 | 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;
3133 |
3134 | console.log('[EHD] Is Peak Hours >', isInPeakHours(), ' | Is Recent Gallery >', isRecentGallery(), ' | Is Ancient Gallery >', isAncientGallery(), ' | Is Donator >', isDonator());
3135 |
3136 | if (
3137 | !setting['force-resized'] &&
3138 | !isTor &&
3139 | !setting['never-warn-peak-hours'] &&
3140 | isGPRequired() // &&
3141 | // !isSourceNexusEnabled()
3142 | ) {
3143 | if (isAncientGallery() && isDonator() < 1) {
3144 | 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?')) {
3145 | return;
3146 | }
3147 | } else {
3148 | 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?')) {
3149 | return;
3150 | }
3151 | }
3152 | }
3153 |
3154 | if (!isTor && !setting['never-warn-limits']) {
3155 | var costData = preCalculateCost();
3156 | var limitsData = getImageLimits();
3157 | var totalLimitsCost = +(setting['force-resized'] ? costData.leastCost : costData.normalCost) || 0;
3158 | if (Number.isNaN(totalLimitsCost)) {
3159 | totalLimitsCost = 0;
3160 | }
3161 | var finalLimits = +(limitsData.cur || 0) + totalLimitsCost;
3162 | if (finalLimits > limitsData.total) {
3163 | 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?')) {
3164 | return;
3165 | }
3166 | }
3167 | }
3168 |
3169 | ehDownloadDialog.innerHTML = '';
3170 |
3171 | initEHDownload();
3172 | });
3173 | ehDownloadBox.appendChild(ehDownloadAction);
3174 |
3175 | var ehDownloadNumberInput = document.createElement('div');
3176 | ehDownloadNumberInput.className = 'g2';
3177 | ehDownloadNumberInput.innerHTML = ehDownloadArrow + '
Number Images';
3178 | ehDownloadBox.appendChild(ehDownloadNumberInput);
3179 |
3180 | var ehDownloadRange = document.createElement('div');
3181 | ehDownloadRange.className = 'g2';
3182 | ehDownloadRange.innerHTML = ehDownloadArrow + '
Pages Range ';
3183 | ehDownloadBox.appendChild(ehDownloadRange);
3184 |
3185 | var ehDownloadSetting = document.createElement('div');
3186 | ehDownloadSetting.className = 'g2';
3187 | ehDownloadSetting.innerHTML = ehDownloadArrow + '
Settings ';
3188 | ehDownloadSetting.addEventListener('click', function(event){
3189 | event.preventDefault();
3190 | showSettings();
3191 | });
3192 | ehDownloadBox.appendChild(ehDownloadSetting);
3193 |
3194 | document.body.insertBefore(ehDownloadBox, document.getElementById('asm') || document.querySelector('.gm').nextElementSibling);
3195 |
3196 | var ehDownloadDialog = document.createElement('div');
3197 | ehDownloadDialog.className = 'ehD-dialog';
3198 | document.body.appendChild(ehDownloadDialog);
3199 |
3200 | var ehDownloadStatus = document.createElement('div');
3201 | ehDownloadStatus.className = 'ehD-status';
3202 | ehDownloadStatus.addEventListener('click', function(event){
3203 | event.preventDefault();
3204 | ehDownloadDialog.classList.toggle('hidden');
3205 | });
3206 |
3207 | var ehDownloadPauseBtn = document.createElement('button');
3208 | ehDownloadPauseBtn.className = 'ehD-pause';
3209 | ehDownloadPauseBtn.textContent ='Pause';
3210 | ehDownloadPauseBtn.addEventListener('click', function(event){
3211 | if (!isPausing) {
3212 | isPausing = true;
3213 | ehDownloadPauseBtn.textContent = 'Resume';
3214 |
3215 | if (setting['force-pause']) {
3216 | // waiting Tampermonkey for transfering string to ArrayBuffer, it may stuck for a second
3217 | setTimeout(function(){
3218 | for (var i = 0; i < fetchThread.length; i++) {
3219 | if (typeof fetchThread[i] !== 'undefined' && 'abort' in fetchThread[i]) fetchThread[i].abort();
3220 |
3221 | if (imageData[i] === 'Fetching' && retryCount[i] < (setting['retry-count'] !== undefined ? setting['retry-count'] : 3)) {
3222 | var elem = progressTable.querySelector('tr[data-index="' + i + '"] .ehD-pt-status-text');
3223 | if (elem) elem.textContent = 'Force Paused';
3224 |
3225 | elem = progressTable.querySelector('tr[data-index="' + i + '"] .ehD-pt-progress-text');
3226 | if (elem) elem.textContent = '';
3227 |
3228 | imageData[i] = null;
3229 | //fetchCount = 0; // fixed for async
3230 | fetchCount--;
3231 |
3232 | updateTotalStatus();
3233 | }
3234 | }
3235 | }, 0);
3236 | }
3237 |
3238 | if (emptyAudio) {
3239 | emptyAudio.pause();
3240 | }
3241 | }
3242 | else {
3243 | isPausing = false;
3244 | ehDownloadPauseBtn.textContent = setting['force-pause'] ? 'Pause (Downloading images will be aborted)' : 'Pause (Downloading images will keep downloading)';
3245 |
3246 | checkFailed();
3247 | }
3248 | });
3249 |
3250 | window.addEventListener('focus', function(){
3251 | if (setting['status-in-title'] === 'blur') {
3252 | if (!needTitleStatus) return;
3253 | document.title = pretitle;
3254 | needTitleStatus = false;
3255 | }
3256 | });
3257 |
3258 | window.addEventListener('blur', function(){
3259 | if (isDownloading && setting['status-in-title'] === 'blur') {
3260 | needTitleStatus = true;
3261 | document.title = '[' + (isPausing ? '❙❙' : downloadedCount < totalCount ? '↓ ' + downloadedCount + '/' + totalCount : totalCount === 0 ? '↓' : '√' ) + '] ' + pretitle;
3262 | }
3263 | });
3264 |
3265 | var forceDownloadTips = document.createElement('div');
3266 | forceDownloadTips.className = 'ehD-force-download-tips';
3267 | forceDownloadTips.innerHTML = 'If an error occured and script doesn\'t work, click
here to force get your downloaded images.';
3268 | forceDownloadTips.getElementsByTagName('a')[0].addEventListener('click', function(event){
3269 | // fixed permission denied on GreaseMonkey
3270 | event.preventDefault();
3271 | saveDownloaded(true);
3272 | });
3273 |
3274 | var closeTips = document.createElement('div');
3275 | closeTips.className = 'ehD-close-tips';
3276 | 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.';
3277 |
3278 | unsafeWindow.getzip = window.getzip = function(){
3279 | saveDownloaded(true);
3280 | };
3281 |
3282 | initSetting();
3283 |
3284 | window.addEventListener('storage', showImageLimits);
3285 |
3286 | window.onbeforeunload = unsafeWindow.onbeforeunload = function(){
3287 | function clearRubbish(){
3288 | for (var i = 0; i < fetchThread.length; i++) {
3289 | if (typeof fetchThread[i] !== 'undefined' && 'abort' in fetchThread[i]) fetchThread[i].abort();
3290 | }
3291 | ehDownloadFS.removeFile(unsafeWindow.gid + '.zip');
3292 | }
3293 | if (isDownloading || isPausing || isSaving) {
3294 | document.body.appendChild(closeTips);
3295 |
3296 | setTimeout(function(){
3297 | document.body.removeChild(closeTips);
3298 | }, 100);
3299 |
3300 | return 'E-Hentai Downloader is still running, please don\'t close this tab until it finished downloading.';
3301 | }
3302 | clearRubbish();
3303 | };
3304 |
--------------------------------------------------------------------------------