= 0) {
1862 | console.log('[EHD] Page 1 URL > ' + pagesURL[0] + ' , use MPV fetch');
1863 | pushDialog('Pages URL is MPV link\n');
1864 |
1865 | getPagesURLFromMPV();
1866 | return;
1867 | }
1868 |
1869 | for (var i = 0; i < pagesURL.length; i++) {
1870 | pageURLsList.push(replaceHTMLEntites(pagesURL[i].split('"')[1]));
1871 | }
1872 | pushDialog('Succeed!');
1873 |
1874 | curPage++;
1875 |
1876 | if (!pagesLength) { // can't get pagesLength correctly before
1877 | pagesLength = responseText.match(ehDownloadRegex.pagesLength)[1] - 0;
1878 | }
1879 |
1880 | if (curPage === pagesLength) {
1881 | getAllPagesURLFin = true;
1882 | var wrongPages = pagesRange.filter(function(elem){ return elem > pageURLsList.length; });
1883 | if (wrongPages.length !== 0) {
1884 | pagesRange = pagesRange.filter(function(elem){ return elem <= pageURLsList.length; });
1885 | pushDialog('\nPage ' + wrongPages.join(', ') + (wrongPages.length > 1 ? ' are' : ' is') + ' not exist, and will be ignored.\n');
1886 | if (pagesRange.length === 0) {
1887 | pushDialog('Nothing matches provided pages range, stop downloading.');
1888 | alert('Nothing matches provided pages range, stop downloading.');
1889 | insertCloseButton();
1890 | return;
1891 | }
1892 | }
1893 | totalCount = pagesRange.length || pageURLsList.length;
1894 | pushDialog('\n\n');
1895 | initProgressTable();
1896 | requestDownload();
1897 | }
1898 | else {
1899 | xhr.open('GET', location.origin + location.pathname + '?p=' + curPage);
1900 | xhr.send();
1901 | pushDialog('\nFetching Gallery Pages URL (' + (curPage + 1) + '/' + pagesLength + ') ... ');
1902 | }
1903 | };
1904 | xhr.ontimeout = xhr.onerror = function(){
1905 | if (retryCount < (setting['retry-count'] !== undefined ? setting['retry-count'] : 3)) {
1906 | pushDialog('Failed! Retrying... ');
1907 | retryCount++;
1908 | xhr.open('GET', location.origin + location.pathname + '?p=' + curPage);
1909 | xhr.timeout = 30000;
1910 | xhr.send();
1911 | }
1912 | else {
1913 | pushDialog('Failed!\nFetch Pages\' URL failed, Please try again later.');
1914 | isDownloading = false;
1915 | alert('Fetch Pages\' URL failed, Please try again later.');
1916 | }
1917 | };
1918 | xhr.open('GET', location.origin + location.pathname + '?p=' + curPage);
1919 | xhr.timeout = 30000;
1920 | xhr.send();
1921 | pushDialog('\nFetching Gallery Pages URL (' + (curPage + 1) + '/' + (pagesLength || '?') + ') ... ');
1922 | }
1923 | else {
1924 | var wrongPages = pagesRange.filter(function(elem){ return elem > pageURLsList.length; });
1925 | if (wrongPages.length !== 0) {
1926 | pagesRange = pagesRange.filter(function(elem){ return elem <= pageURLsList.length; });
1927 | pushDialog('\nPage ' + wrongPages.join(', ') + (wrongPages.length > 1 ? ' are' : ' is') + ' not exist, and will be ignored.\n');
1928 | if (pagesRange.length === 0) {
1929 | pushDialog('Nothing matches provided pages range, stop downloading.');
1930 | alert('Nothing matches provided pages range, stop downloading.');
1931 | insertCloseButton();
1932 | return;
1933 | }
1934 | }
1935 |
1936 | totalCount = pagesRange.length || pageURLsList.length;
1937 | pushDialog('\n\n');
1938 | initProgressTable();
1939 | requestDownload();
1940 | }
1941 | }
1942 |
1943 | function initEHDownload() {
1944 | for (var i = 0; i < fetchThread.length; i++) {
1945 | if (typeof fetchThread[i] !== 'undefined' && 'abort' in fetchThread[i]) fetchThread[i].abort();
1946 | }
1947 | imageList = [];
1948 | imageData = [];
1949 | fetchThread = [];
1950 | retryCount = [];
1951 | downloadedCount = fetchCount = failedCount = 0;
1952 | isPausing = false;
1953 | zip = new JSZip();
1954 | infoStr = '';
1955 | fetchPagesXHR.abort();
1956 |
1957 | if (setting['recheck-file-name']) {
1958 | var dirNameNode = document.querySelector('.ehD-box-extend-dirname');
1959 | var fileNameNode = document.querySelector('.ehD-box-extend-filename');
1960 |
1961 | if (dirNameNode && dirNameNode.value) {
1962 | dirName = getSafeName(dirNameNode.value, true);
1963 | }
1964 | else {
1965 | dirName = getReplacedName(!setting['dir-name'] ? '{gid}_{token}' : setting['dir-name']);
1966 | }
1967 |
1968 | if (fileNameNode && fileNameNode.value) {
1969 | fileName = getSafeName(fileNameNode.value);
1970 | }
1971 | else {
1972 | fileName = getReplacedName(!setting['file-name'] ? '{title}' : setting['file-name']);
1973 | }
1974 | }
1975 | else {
1976 | dirName = getReplacedName(!setting['dir-name'] ? '{gid}_{token}' : setting['dir-name']);
1977 | fileName = getReplacedName(!setting['file-name'] ? '{title}' : setting['file-name']);
1978 | }
1979 |
1980 | if (dirName.trim() === '/') dirName = '';
1981 | needNumberImages = ehDownloadNumberInput.querySelector('input').checked;
1982 |
1983 | var requiredBytes = Math.ceil(getFileSizeAndLength().size + 100 * 1024);
1984 | var requiredMBs = getFileSizeAndLength().sizeMB + 0.1;
1985 |
1986 | var fsErrorHandler = function (error) {
1987 | ehDownloadFS.errorHandler(error);
1988 |
1989 | // roll back and use Blob to handle file
1990 | ehDownloadFS.needFileSystem = false;
1991 | alert('An error occured when requesting FileSystem.\n' +
1992 | 'Error Name: ' + (e.name || 'Unknown Error') + '\n' +
1993 | 'Error Message: ' + e.message + '\n\n' +
1994 | 'Roll back and use Blob to handle file.');
1995 | };
1996 |
1997 | if ((!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;
1998 | else if (setting['store-in-fs'] && requestFileSystem && requiredMBs >= (setting['fs-size'] !== undefined ? setting['fs-size'] : 200)) {
1999 | ehDownloadFS.needFileSystem = true;
2000 | console.log('[EHD] Required File System Space >', requiredBytes);
2001 |
2002 | // Chrome can use about 10% of free space of disk where Chrome User Data stored in as TEMPORARY File System Storage.
2003 | if (navigator.webkitTemporaryStorage) { // if support navigator.webkitTemporaryStorage to check usable space
2004 | // use `queryUsageAndQuota` instead of `requestQuota` to check storage space,
2005 | // because `requestQuota` is incorrect when harddisk is full, says have about 5GB storage
2006 | navigator.webkitTemporaryStorage.queryUsageAndQuota(function (usage, quota) {
2007 | console.log('[EHD] Free TEMPORARY File System Space >', quota - usage);
2008 | if (quota - usage < requiredBytes) {
2009 | console.log('[EHD] Free TEMPORARY File System Space is not enough.');
2010 |
2011 | // free space is not enough, then use persistent space
2012 | // in fact, free space of persisent file storage is always 10GiB, even free disk space is not enough
2013 | navigator.webkitPersistentStorage.queryUsageAndQuota(function (usage, quota) {
2014 | console.log('[EHD] Free PERSISTENT File System Space >', quota - usage);
2015 | if (quota - usage < requiredBytes) {
2016 | // roll back and use Blob to handle file
2017 | ehDownloadFS.needFileSystem = false;
2018 | 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.');
2019 | }
2020 | else {
2021 | pushDialog('\n
Please allow storing large content if the browser asked for it. \n');
2022 | requestFileSystem(window.PERSISTENT, requiredBytes, ehDownloadFS.initHandler, fsErrorHandler);
2023 | }
2024 | }, fsErrorHandler);
2025 | }
2026 | else requestFileSystem(window.TEMPORARY, requiredBytes, ehDownloadFS.initHandler, fsErrorHandler);
2027 | }, fsErrorHandler);
2028 | }
2029 | else requestFileSystem(window.TEMPORARY, requiredBytes, ehDownloadFS.initHandler, fsErrorHandler);
2030 | }
2031 |
2032 | // Array.prototype.some() is a bit ugly, so we use toString().indexOf() lol
2033 | var infoNeeds = setting['save-info-list'].toString();
2034 | if (infoNeeds.indexOf('title') >= 0) {
2035 | infoStr += replaceHTMLEntites(
2036 | document.getElementById('gn').textContent + '\n' +
2037 | document.getElementById('gj').textContent + '\n' +
2038 | window.location.href + '\n\n'
2039 | );
2040 | }
2041 |
2042 | if (infoNeeds.indexOf('metas') >= 0) {
2043 | infoStr += 'Category: ' + document.querySelector('#gdc .cs').textContent.trim() + '\n' +
2044 | 'Uploader: ' + replaceHTMLEntites(document.querySelector('#gdn').textContent) + '\n';
2045 | }
2046 | var metaNodes = document.querySelectorAll('#gdd tr');
2047 | for (var i = 0; i < metaNodes.length; i++) {
2048 | var c1 = replaceHTMLEntites(metaNodes[i].getElementsByClassName('gdt1')[0].textContent);
2049 | var c2 = replaceHTMLEntites(metaNodes[i].getElementsByClassName('gdt2')[0].textContent);
2050 | if (infoNeeds.indexOf('metas') >= 0) infoStr += c1 + ' ' + c2 + '\n';
2051 | }
2052 | if (infoNeeds.indexOf('metas') >= 0) infoStr += 'Rating: ' + unsafeWindow.average_rating + '\n\n';
2053 |
2054 | if (infoNeeds.indexOf('tags') >= 0) {
2055 | infoStr += 'Tags:\n';
2056 |
2057 | var tagsList = document.querySelectorAll('#taglist tr');
2058 | Array.prototype.forEach.call(tagsList, function(elem){
2059 | var tds = elem.getElementsByTagName('td');
2060 | infoStr += '> ' + tds[0].textContent + ' ';
2061 |
2062 | var tags = tds[1].querySelectorAll('a');
2063 | infoStr += Array.prototype.map.call(tags, function(e){
2064 | return e.textContent;
2065 | }).join(', ') + '\n';
2066 | });
2067 |
2068 | infoStr += '\n';
2069 | }
2070 |
2071 | if (infoNeeds.indexOf('uploader-comment') >= 0 && document.getElementById('comment_0')) {
2072 | infoStr += 'Uploader Comment:\n' + document.getElementById('comment_0').innerHTML.replace(/
|
/gi, '\n') + '\n\n';
2073 | }
2074 | isDownloading = true;
2075 | pushDialog(infoStr);
2076 |
2077 | pushDialog('Start downloading at ' + new Date() + '\n');
2078 | ehDownloadDialog.appendChild(ehDownloadStatus);
2079 |
2080 | // get all pages url to fix 403 forbidden (download request was timed out)
2081 | getAllPagesURL();
2082 |
2083 | // init playing music
2084 | if (setting['play-silent-music'] && !emptyAudio) {
2085 | emptyAudio = new Audio(emptyAudioFile);
2086 | emptyAudio.loop = true;
2087 | }
2088 | }
2089 |
2090 | function initVisibilityListener() {
2091 | var hidden, visibilityChange;
2092 | if (typeof document.hidden !== 'undefined') { // Opera 12.10 and Firefox 18 and later support
2093 | hidden = 'hidden';
2094 | visibilityChange = 'visibilitychange';
2095 | }
2096 | else if (typeof document.mozHidden !== 'undefined') {
2097 | hidden = 'mozHidden';
2098 | visibilityChange = 'mozvisibilitychange';
2099 | }
2100 | else if (typeof document.webkitHidden !== 'undefined') {
2101 | hidden = 'webkitHidden';
2102 | visibilityChange = 'webkitvisibilitychange';
2103 | }
2104 |
2105 | var visibilityChangeHandler = function (isHidden) {
2106 | if (typeof isHidden !== 'boolean') {
2107 | isHidden = document[hidden];
2108 | }
2109 | visibleState = !isHidden;
2110 | if (!emptyAudio) {
2111 | return;
2112 | }
2113 | if (isHidden && ((isDownloading && !isPausing) || isSaving)) {
2114 | emptyAudio.play();
2115 | }
2116 | else {
2117 | emptyAudio.pause();
2118 | loadImageLimits();
2119 | }
2120 | };
2121 |
2122 | if (visibilityChange) {
2123 | window.addEventListener(visibilityChange, visibilityChangeHandler);
2124 | }
2125 | else {
2126 | window.addEventListener('focus', function () {
2127 | visibilityChangeHandler(false);
2128 | });
2129 | window.addEventListener('blur', function () {
2130 | visibilityChangeHandler(true);
2131 | });
2132 | }
2133 |
2134 | visibilityChangeHandler();
2135 | }
2136 |
2137 | function initProgressTable(){
2138 | progressTable = document.createElement('table');
2139 | progressTable.className = 'ehD-pt';
2140 | ehDownloadDialog.style.display = 'block';
2141 | ehDownloadDialog.appendChild(progressTable);
2142 | ehDownloadDialog.appendChild(forceDownloadTips);
2143 | ehDownloadDialog.appendChild(ehDownloadPauseBtn);
2144 | ehDownloadDialog.scrollTop = ehDownloadDialog.scrollHeight;
2145 | }
2146 |
2147 | function requestDownload(ignoreFailed){
2148 | if (isPausing) return;
2149 |
2150 | if (setting['delay-request']) {
2151 | var curTime = Date.now();
2152 | if (delayTime < curTime) {
2153 | delayTime = curTime;
2154 | }
2155 | }
2156 |
2157 | var j = 0;
2158 | for (var i = fetchCount; i < (setting['thread-count'] !== undefined ? setting['thread-count'] : 5); i++) {
2159 | for (/*var j = 0*/; j < totalCount; j++) {
2160 | if (imageData[j] == null && (ignoreFailed || (retryCount[j] || 0) <= (setting['retry-count'] !== undefined ? setting['retry-count'] : 3))) {
2161 | imageData[j] = 'Fetching';
2162 | if (imageList[j] && setting['never-new-url']) fetchOriginalImage(j);
2163 | else if (setting['delay-request']) {
2164 | setTimeout(function(j) {
2165 | if (isPausing || fetchCount >= (setting['thread-count'] !== undefined ? setting['thread-count'] : 5)) {
2166 | imageData[j] = null;
2167 | return;
2168 | }
2169 | getPageData(j);
2170 | fetchCount++;
2171 | }, delayTime - curTime + setting['delay-request'] * 1000, j);
2172 | delayTime += setting['delay-request'] * 1000;
2173 | }
2174 | else {
2175 | getPageData(j);
2176 | fetchCount++;
2177 | }
2178 | break;
2179 | }
2180 | }
2181 | }
2182 |
2183 | }
2184 |
2185 | function getPageData(index) {
2186 | if (isPausing) return;
2187 |
2188 | if (pagesRange.length) var realIndex = pagesRange[index];
2189 | else var realIndex = index + 1;
2190 |
2191 | var needScrollIntoView = ehDownloadDialog.clientHeight + ehDownloadDialog.scrollTop >= ehDownloadDialog.scrollHeight - 5;
2192 |
2193 | var node = progressTable.querySelector('tr[data-index="' + index + '"]');
2194 | if (!node) {
2195 | node = document.createElement('tr');
2196 | node.className = 'ehD-pt-item';
2197 | node.setAttribute('data-index', index);
2198 | node.innerHTML = '\
2199 |
#' + realIndex + ' \
2200 |
\
2201 | \
2202 | \
2203 | \
2204 |
\
2205 | Pending... \
2206 | Force Abort \
2207 | ';
2208 | progressTable.appendChild(node);
2209 | }
2210 | if (needScrollIntoView) {
2211 | ehDownloadDialog.scrollTop = ehDownloadDialog.scrollHeight;
2212 | }
2213 |
2214 | var nodeList = {
2215 | current: node,
2216 | fileName: node.getElementsByTagName('td')[0],
2217 | status: node.getElementsByTagName('td')[2],
2218 | statusText: node.getElementsByClassName('ehD-pt-status-text')[0],
2219 | progress: node.getElementsByTagName('progress')[0],
2220 | progressText: node.getElementsByTagName('span')[0],
2221 | abort: node.getElementsByClassName('ehD-pt-abort')[0]
2222 | };
2223 |
2224 | retryCount[index] = 0;
2225 | var fetchURL = replaceHTMLEntites(imageList[index] ? (
2226 | imageList[index]['pageURL'] + (
2227 | (!setting['never-send-nl'] && imageList[index]['nextNL']) ? (
2228 | imageList[index]['pageURL'].indexOf('?') >= 0 ? '&' : '?'
2229 | ) + 'nl=' + imageList[index]['nextNL'] : ''
2230 | )
2231 | ) : pageURLsList[realIndex - 1])/*.replace(/^https?:/, '')*/;
2232 |
2233 | // assign to fetchThread, so that we can abort them and all GM_xhr by one command fetchThread[i].abort()
2234 | var xhr = fetchThread[index] = new XMLHttpRequest();
2235 | xhr.onload = function() {
2236 | var responseText = xhr.responseText;
2237 | if (xhr.status !== 200 || !responseText) {
2238 | if (retryCount[index] < (setting['retry-count'] !== undefined ? setting['retry-count'] : 3)) {
2239 | retryCount[index]++;
2240 |
2241 | updateProgress(nodeList, {
2242 | status: 'Retrying (' + retryCount[index] + '/' + (setting['retry-count'] !== undefined ? setting['retry-count'] : 3) + ')...',
2243 | progress: '',
2244 | progressText: '',
2245 | class: 'ehD-pt-warning'
2246 | });
2247 |
2248 | xhr.open('GET', fetchURL);
2249 | xhr.timeout = 30000;
2250 | xhr.send();
2251 | }
2252 | else {
2253 | failedCount++;
2254 | fetchCount--;
2255 |
2256 | console.error('[EHD] #' + realIndex + ': Failed getting image URL');
2257 | updateProgress(nodeList, {
2258 | status: 'Failed getting URL',
2259 | progress: '0',
2260 | progressText: '',
2261 | class: 'ehD-pt-failed'
2262 | });
2263 | updateTotalStatus();
2264 |
2265 | checkFailed();
2266 | }
2267 |
2268 | return;
2269 | }
2270 |
2271 | try {
2272 | var imageURL = replaceHTMLEntites(
2273 | (
2274 | (unsafeWindow.apiuid !== -1 || setting['force-as-login'])
2275 | && ehDownloadRegex.imageURL[0].test(responseText)
2276 | && !setting['force-resized']
2277 | ) ? responseText.match(ehDownloadRegex.imageURL[0])[1] : (
2278 | responseText.indexOf('id="img"') > -1
2279 | ? responseText.match(ehDownloadRegex.imageURL[1])[1]
2280 | : responseText.match(ehDownloadRegex.imageURL[2])[1]
2281 | )
2282 | );
2283 | // append nl to original image in case it fails to load from H@H (wtf it's valid?!)
2284 | if (ehDownloadRegex.originalImagePattern.test(imageURL)) {
2285 | imageURL = imageURL + (
2286 | (imageList[index] && !setting['never-send-nl'] && imageList[index]['nextNL']) ? (
2287 | imageURL.indexOf('?') >= 0 ? '&' : '?'
2288 | ) + 'nl=' + imageList[index]['nextNL'] : ''
2289 | );
2290 | }
2291 | var fileName = replaceHTMLEntites(responseText.match(ehDownloadRegex.fileName)[1]);
2292 | var nextNL = ehDownloadRegex.nl.test(responseText) ? responseText.match(ehDownloadRegex.nl)[1] : null;
2293 | }
2294 | catch (error) {
2295 | console.error('[EHD] Response content is not correct!', error);
2296 | if (retryCount[index] < (setting['retry-count'] !== undefined ? setting['retry-count'] : 3)) {
2297 | retryCount[index]++;
2298 |
2299 | updateProgress(nodeList, {
2300 | status: 'Retrying (' + retryCount[index] + '/' + (setting['retry-count'] !== undefined ? setting['retry-count'] : 3) + ')...',
2301 | progress: '',
2302 | progressText: '',
2303 | class: 'ehD-pt-warning'
2304 | });
2305 |
2306 | xhr.open('GET', fetchURL);
2307 | xhr.timeout = 30000;
2308 | xhr.send();
2309 | }
2310 | else {
2311 | failedCount++;
2312 | fetchCount--;
2313 |
2314 | console.error('[EHD] #' + realIndex + ': Can\'t get request content from response content');
2315 | updateProgress(nodeList, {
2316 | status: 'Response Error',
2317 | progress: '0',
2318 | progressText: '',
2319 | class: 'ehD-pt-failed'
2320 | });
2321 | updateTotalStatus();
2322 | //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.');
2323 |
2324 | checkFailed();
2325 | }
2326 | return;
2327 | }
2328 |
2329 | var imageNumber = '';
2330 | if (needNumberImages) {
2331 | // Number images, thanks to JingJang@GitHub, source: https://github.com/JingJang/E-Hentai-Downloader
2332 | if (!setting['number-real-index'] && pagesRange.length) { // if pages range was set and number original index is not required
2333 | var len = pagesRange.length.toString().length,
2334 | padding = new Array(len < 3 ? len + 1 : len).join('0');
2335 | imageNumber = (padding + (index + 1)).slice(0 - len);
2336 | }
2337 | else { // pages range was not set (download all pages, so index + 1 === realIndex) or number original index is required
2338 | var len = pageURLsList.length.toString().length,
2339 | padding = new Array(len < 3 ? len + 1 : len).join('0');
2340 | imageNumber = (padding + realIndex).slice(0 - len);
2341 | }
2342 | }
2343 |
2344 | //imageList.push(new PageData(fetchURL, imageURL, fileName, nextNL, realIndex));
2345 | imageList[index] = new PageData(fetchURL, imageURL, fileName, nextNL, realIndex, imageNumber);
2346 |
2347 | if (isPausing) {
2348 | updateProgress(nodeList, {
2349 | name: '#' + realIndex + ': ' + fileName,
2350 | status: 'Auto Paused',
2351 | progress: '',
2352 | progressText: '',
2353 | class: 'ehD-pt-failed'
2354 | });
2355 | fetchCount--;
2356 | imageData[index] = null;
2357 |
2358 | updateTotalStatus();
2359 | }
2360 | else {
2361 | fetchOriginalImage(index, nodeList);
2362 | }
2363 |
2364 | };
2365 | xhr.onerror = xhr.ontimeout = function() {
2366 | if (retryCount[index] < (setting['retry-count'] !== undefined ? setting['retry-count'] : 3)) {
2367 | retryCount[index]++;
2368 |
2369 | updateProgress(nodeList, {
2370 | status: 'Retrying (' + retryCount[index] + '/' + (setting['retry-count'] !== undefined ? setting['retry-count'] : 3) + ')...',
2371 | progress: '',
2372 | progressText: '',
2373 | class: 'ehD-pt-warning'
2374 | });
2375 |
2376 | xhr.open('GET', fetchURL);
2377 | xhr.timeout = 30000;
2378 | xhr.send();
2379 | }
2380 | else {
2381 | failedCount++;
2382 | fetchCount--;
2383 |
2384 | console.error('[EHD] #' + realIndex + ': Failed getting image URL');
2385 | updateProgress(nodeList, {
2386 | status: 'Failed getting URL',
2387 | progress: '0',
2388 | progressText: '',
2389 | class: 'ehD-pt-failed'
2390 | });
2391 | updateTotalStatus();
2392 |
2393 | checkFailed();
2394 | }
2395 | };
2396 |
2397 | xhr.open('GET', fetchURL);
2398 | xhr.timeout = 30000;
2399 | xhr.send();
2400 |
2401 | nodeList.abort.addEventListener('click', function () {
2402 | if (!isDownloading || imageData[index] instanceof ArrayBuffer) return; // Temporarily fixes #31
2403 |
2404 | if (typeof fetchThread[index] !== 'undefined' && 'abort' in fetchThread[index]) fetchThread[index].abort();
2405 |
2406 | console.log('[EHD] #' + (index + 1) + ': Force Aborted By User');
2407 | updateProgress(nodeList, {
2408 | status: 'Failed! (User Aborted)',
2409 | progress: '0',
2410 | progressText: '',
2411 | class: 'ehD-pt-warning'
2412 | });
2413 |
2414 | failedFetching(index, nodeList);
2415 | });
2416 |
2417 | nodeList.status.setAttribute('data-inited-abort', '1');
2418 | }
2419 |
2420 | function showSettings() {
2421 | var ehDownloadSettingPanel = document.createElement('div');
2422 | ehDownloadSettingPanel.className = 'ehD-setting';
2423 | ehDownloadSettingPanel.setAttribute('data-active-setting', 'basic');
2424 | ehDownloadSettingPanel.innerHTML = '\
2425 |
\
2426 | Basic \
2427 | Advanced \
2428 | \
2429 |
\
2430 | ' + ehDownloadArrow + '
Feedback \
2431 |
GitHub \
2432 |
GreasyFork \
2433 |
\
2434 |
\
2435 |
\
2436 |
\
2466 |
\
2467 |
Set compression level as (0 ~ 9, 0 is only store) (1)
\
2468 |
Stream files and create Zip with file descriptors (2)
\
2469 |
Force download resized image (never download original image)
\
2470 |
Never get new image URL when failed to download image (3)
\
2471 |
Never send "nl" GET parameter when getting new image URL (3)
\
2472 |
Never show warning when it\'s in peak hours now
\
2473 |
Never show warning if image limits will probably used out on starting download
\
2474 |
Never show warning when downloading a large gallery (>= 300 MB)
\
2475 |
Use File System to handle large Zip file when gallery is larger than MB (0 is always) (4)
\
2476 |
Play silent music during the process to avoid downloading freeze (5)
\
2477 |
Record and save gallery info as File info.txt Zip comment None
\
2478 |
...which includes Title & Gallery Link Metadatas Tags Uploader Comment Page Links
\
2479 |
Replace forbidden characters with full-width characters instead of dash (-)
\
2480 |
Force drop downloaded images data when pausing download
\
2481 |
Save as CBZ (Comic book archive) file(6)
\
2482 |
Pass cookies manually when downloading images (7)
\
2483 |
Force as logged in (actual login state: ' + (unsafeWindow.apiuid === -1 ? 'no' : 'yes') + ', uid: ' + unsafeWindow.apiuid + ') (8)
\
2484 |
Download original images from current origin e-hentai.org exhentai.org (9)
\
2485 |
\
2486 |
\
2487 | (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.\
2488 |
\
2489 |
\
2490 | (2) This may reduce memory usage but some decompress softwares may not support the Zip file. See
JSZip Docs for more info.\
2491 |
\
2492 |
\
2493 | (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.\
2494 |
\
2495 |
\
2496 | (4) If enabled you can save larger Zip files (probably ~1GB).\
2497 |
\
2498 |
\
2499 | (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.\
2500 |
\
2501 |
\
2502 | (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.\
2503 |
\
2504 |
\
2505 | (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.\
2506 |
\
2507 |
\
2508 | (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.\
2509 |
\
2510 |
\
2511 | (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.\
2512 |
\
2513 |
\
2514 |
\
2515 |
\
2516 |
\
2517 | ';
2520 | document.body.appendChild(ehDownloadSettingPanel);
2521 |
2522 | for (var i in setting) {
2523 | if (setting[i] instanceof Array) {
2524 | setting[i].forEach(function(elem){
2525 | var element = ehDownloadSettingPanel.querySelector('input[data-ehd-setting="' + i + '[]"][value="' + elem + '"], select[data-ehd-setting="' + i + '[]"] option[value="' + elem + '"]');
2526 | if (!element) return;
2527 |
2528 | if (element.getAttribute('type') === 'checkbox') {
2529 | element.setAttribute('checked', 'checked');
2530 | }
2531 | else if (element.tagName.toLowerCase() === 'option') {
2532 | element.setAttribute('selected', 'selected');
2533 | }
2534 | else element.value = elem;
2535 | });
2536 | }
2537 | else {
2538 | var element = ehDownloadSettingPanel.querySelector('input[data-ehd-setting="' + i + '"], select[data-ehd-setting="' + i + '"]');
2539 | if (!element) continue;
2540 | if (element.getAttribute('type') === 'checkbox') {
2541 | if (setting[i]) element.setAttribute('checked', 'checked');
2542 | }
2543 | else if (element.tagName.toLowerCase() === 'select') {
2544 | element = element.querySelector('option[value="' + setting[i] + '"]');
2545 | if (!element) continue;
2546 | element.setAttribute('selected', 'selected');
2547 | }
2548 | else element.setAttribute('value', setting[i]);
2549 | }
2550 | }
2551 |
2552 | ehDownloadSettingPanel.getElementsByClassName('ehD-setting-tab')[0].addEventListener('click', function(event){
2553 | var target = event.target;
2554 | if (target.tagName.toLowerCase() === 'li') {
2555 | ehDownloadSettingPanel.setAttribute('data-active-setting', target.dataset.targetSetting);
2556 | }
2557 | });
2558 |
2559 | ehDownloadSettingPanel.getElementsByClassName('ehD-setting-footer')[0].addEventListener('click', function(event){
2560 | var target = event.target;
2561 | if (target.tagName.toLowerCase() === 'button') {
2562 | if (target.dataset.action === 'save') {
2563 | var inputs = ehDownloadSettingPanel.querySelectorAll('input[data-ehd-setting], select[data-ehd-setting]');
2564 | setting = {};
2565 | for (var i = 0; i < inputs.length; i++) {
2566 | if (inputs[i].getAttribute('type') !== 'checkbox' && inputs[i].value === '') continue;
2567 |
2568 | var curSettingName = inputs[i].dataset.ehdSetting;
2569 |
2570 | if (inputs[i].getAttribute('type') === 'checkbox') {
2571 | if (inputs[i].checked) {
2572 | if (inputs[i].hasAttribute('value')) {
2573 | if (curSettingName.indexOf('[]') >= 0) {
2574 | curSettingName = curSettingName.split('[]')[0];
2575 | if (!setting[curSettingName]) setting[curSettingName] = [];
2576 | setting[curSettingName].push(inputs[i].getAttribute('value'));
2577 | }
2578 | else {
2579 | setting[curSettingName] = inputs[i].getAttribute('value');
2580 | }
2581 | }
2582 | else {
2583 | setting[curSettingName] = inputs[i].checked;
2584 | }
2585 | }
2586 | else {
2587 | setting[curSettingName] = inputs[i].checked;
2588 | }
2589 | }
2590 | else if (inputs[i].getAttribute('type') === 'number') {
2591 | setting[curSettingName] = Number(inputs[i].value);
2592 | if (isNaN(setting[curSettingName])) {
2593 | setting[curSettingName] = Number(inputs[i].getAttribute('placeholder'));
2594 | }
2595 | }
2596 | else {
2597 | setting[curSettingName] = inputs[i].value;
2598 | }
2599 | }
2600 | GM_setValue('ehD-setting', JSON.stringify(setting));
2601 | }
2602 | document.body.removeChild(ehDownloadSettingPanel);
2603 |
2604 | if (document.querySelector('.ehD-box-extend')) {
2605 | toggleFilenameConfirmInput('reset');
2606 | }
2607 | else {
2608 | toggleFilenameConfirmInput(!setting['recheck-file-name']);
2609 | }
2610 |
2611 | // ehDownloadBox.classList[setting['actions-sticky'] ? 'add' : 'remove']('ehD-box-sticky');
2612 |
2613 | try {
2614 | showPreCalcCost();
2615 | }
2616 | catch (e) { }
2617 | }
2618 | });
2619 |
2620 | Array.prototype.forEach.call(ehDownloadSettingPanel.getElementsByClassName('ehD-setting-content'), function(elem) {
2621 | elem.addEventListener('focusin', function(event){
2622 | ehDownloadSettingPanel.setAttribute('data-active-setting', this.dataset.settingPage);
2623 | // prevent auto-scroll from browser
2624 | ehDownloadSettingPanel.scrollLeft = 0;
2625 | }, true);
2626 | });
2627 | }
2628 |
2629 | function getImageLimits() {
2630 | var host = host || location.hostname;
2631 | if (host === 'exhentai.org') {
2632 | host = 'e-hentai.org';
2633 | }
2634 |
2635 | var preData = JSON.parse(localStorage.getItem('ehd-image-limits-' + host) || '{"timestamp":0}');
2636 | return preData;
2637 | }
2638 |
2639 | function loadImageLimits(forced, host){
2640 | if (!visibleState) {
2641 | return;
2642 | }
2643 | var host = host || location.hostname;
2644 | if (host === 'exhentai.org') {
2645 | host = 'e-hentai.org';
2646 | }
2647 | var url = 'https://' + host + '/home.php';
2648 |
2649 | var preData = getImageLimits();
2650 | if (!forced && new Date() - preData.timestamp < 30000) {
2651 | return showImageLimits();
2652 | }
2653 |
2654 | console.log('[EHD] Request Image Limits From ' + host);
2655 |
2656 | GM_xmlhttpRequest({
2657 | method: 'GET',
2658 | url: url,
2659 | timeout: 300000,
2660 | onload: function(res) {
2661 | var responseText = res.responseText;
2662 | if (!responseText) return;
2663 | preData.timestamp = new Date().getTime();
2664 | if (responseText.indexOf('as your account has been suspended') >= 0) {
2665 | preData.suspended = true;
2666 | }
2667 | else if (responseText.indexOf('Your IP address has been temporarily banned') >= 0) {
2668 | preData.ipBanned = true;
2669 | }
2670 | else {
2671 | var data = responseText.match(ehDownloadRegex.imageLimits);
2672 | if (!data || data.length < 3) return;
2673 | preData.cur = +data[1].replace(/,/g, '');
2674 | preData.total = +data[2].replace(/,/g, '');
2675 |
2676 | var donatorPower = responseText.match(ehDownloadRegex.donatorPower);
2677 | if (!donatorPower || donatorPower.length < 2) return;
2678 | preData.donatorPower = +donatorPower[1];
2679 | delete preData.suspended;
2680 | delete preData.ipBanned;
2681 | }
2682 | console.log('[EHD] Image Limits >', JSON.stringify(preData));
2683 | localStorage.setItem('ehd-image-limits-' + host, JSON.stringify(preData));
2684 | showImageLimits();
2685 | }
2686 | });
2687 | }
2688 |
2689 | function showImageLimits(){
2690 | // tor doesn't count to normal account since the ip is dynamic, but not sure if it counts for donator/hath perk account
2691 | // if (isTor) {
2692 | // return;
2693 | // }
2694 |
2695 | var list = Object.keys(localStorage).filter(function(elem){
2696 | return elem.indexOf('ehd-image-limits-') === 0;
2697 | }).sort().map(function(elem){
2698 | var curData = JSON.parse(localStorage.getItem(elem));
2699 | if (curData.suspended) {
2700 | return '
! Account Suspended ! ';
2701 | }
2702 | if (curData.ipBanned) {
2703 | return '
! IP Banned ! ';
2704 | }
2705 | if (+curData.cur >= +curData.total) {
2706 | return '
' + curData.cur + '/' + curData.total + ' '
2707 | }
2708 | return curData.cur + '/' + curData.total;
2709 | });
2710 |
2711 | ehDownloadBox.getElementsByClassName('ehD-box-limit')[0].innerHTML = ' |
Image Limits: ' + list.join('; ') + ' ';
2712 | }
2713 |
2714 | function getFileSizeAndLength() {
2715 | // TODO: use api.php if fails
2716 | var context = (document.getElementById('gdd') || {}).textContent || '';
2717 | var sizeText = ((context.split('File Size:')[1] || '').split('Length:')[0] || '').trim();
2718 | var pageText = ((context.split('Length:')[1] || '').split('page')[0] || '').trim() ||
2719 | ((document.querySelector('.gpc') || {}).textContent.split('of').pop().split('images').shift() || '').trim();
2720 |
2721 | var sizeMB, sizeKB;
2722 | var page = pageText - 0;
2723 |
2724 | if (/Mi?B/.test(sizeText)) {
2725 | sizeMB = parseFloat(sizeText) + 0.01;
2726 | sizeKB = sizeMB * 1024;
2727 | }
2728 | else if (/Gi?B/.test(sizeText)) {
2729 | sizeMB = (parseFloat(sizeText) + 0.01) * 1024;
2730 | sizeKB = sizeMB * 1024;
2731 | }
2732 | else {
2733 | sizeMB = 1;
2734 | sizeKB = parseFloat(sizeText);
2735 | }
2736 |
2737 | var result = {
2738 | sizeMB: sizeMB,
2739 | sizeKB: sizeKB,
2740 | size: sizeKB * 1024,
2741 | page: page
2742 | };
2743 |
2744 | getFileSizeAndLength = function(){
2745 | return result;
2746 | };
2747 |
2748 | return result;
2749 | };
2750 |
2751 | function toggleFilenameConfirmInput(hide){
2752 | var extendNodes = document.querySelector('.ehD-box-extend');
2753 | if (extendNodes) {
2754 | if (hide === 'reset') {
2755 | ehDownloadBox.removeChild(extendNodes);
2756 | if (setting['recheck-file-name']) toggleFilenameConfirmInput();
2757 | }
2758 | else if (hide) {
2759 | extendNodes.style.display = 'none';
2760 | }
2761 | else {
2762 | extendNodes.style.display = 'block';
2763 | }
2764 | }
2765 | else if (!hide) {
2766 | extendNodes = document.createElement('div');
2767 | extendNodes.className = 'ehD-box-extend';
2768 | extendNodes.innerHTML = '
' +
2769 | '
';
2770 | ehDownloadBox.appendChild(extendNodes);
2771 |
2772 | dirName = getReplacedName(!setting['dir-name'] ? '{gid}_{token}' : setting['dir-name']);
2773 | fileName = getReplacedName(!setting['file-name'] ? '{title}' : setting['file-name']);
2774 | extendNodes.getElementsByClassName('ehD-box-extend-filename')[0].value = fileName;
2775 | extendNodes.getElementsByClassName('ehD-box-extend-dirname')[0].value = dirName;
2776 | }
2777 | }
2778 |
2779 | function getResolutionSetting(forced){
2780 | var url = '/uconfig.php';
2781 |
2782 | var preData = JSON.parse(localStorage.getItem('ehd-resolution') || '{"timestamp":0}');
2783 | if (!forced && new Date() - preData.timestamp < 3600e3) {
2784 | return;
2785 | }
2786 |
2787 | // tor site don't have original image feature
2788 | if (isTor) {
2789 | localStorage.setItem('ehd-resolution', JSON.stringify({
2790 | withoutHentaiAtHome: 0,
2791 | resolution: 0,
2792 | timestamp: Date.now()
2793 | }));
2794 | return;
2795 | }
2796 |
2797 | console.log('[EHD] Request Resolution Setting');
2798 |
2799 | var xhr = new XMLHttpRequest();
2800 | xhr.onload = function() {
2801 | var responseText = xhr.responseText;
2802 | if (!responseText) return;
2803 | var preData = {
2804 | withoutHentaiAtHome: +((responseText.match(/id="uh_(\d)" checked/) || [])[1] || 0),
2805 | resolution: +((responseText.match(/id="xr_(\d)" checked/) || [])[1] || 0),
2806 | originalImages: +((responseText.match(/id="oi_(\d)".*? checked/) || [])[1] || 0),
2807 | mpvAvailable: responseText.indexOf('name="qb"') >= 0,
2808 | timestamp: Date.now()
2809 | };
2810 | console.log('[EHD] Resolution Setting >', JSON.stringify(preData));
2811 | localStorage.setItem('ehd-resolution', JSON.stringify(preData));
2812 | try {
2813 | showPreCalcCost();
2814 | }
2815 | catch (e) { }
2816 | };
2817 | xhr.open('GET', url);
2818 | xhr.send();
2819 | }
2820 |
2821 | function preCalculateCost(){
2822 | // tor doesn't count to normal account since the ip is dynamic, but not sure if it counts for donator/hath perk account
2823 | // if (isTor) {
2824 | // return;
2825 | // }
2826 |
2827 | var resolutionSetting = JSON.parse(localStorage.getItem('ehd-resolution') || '{"timestamp":0}');
2828 | var resolutionCost = {
2829 | 0: 1,
2830 | 1: 1,
2831 | 2: 1,
2832 | 3: 1,
2833 | 4: 3,
2834 | 5: 5
2835 | };
2836 | var info = getFileSizeAndLength();
2837 | var size = info.size;
2838 | var page = info.page;
2839 | var perCost = resolutionCost[resolutionSetting.resolution || 0];
2840 | if ((resolutionSetting.withoutHentaiAtHome || 0) > 1) {
2841 | perCost += 10;
2842 | }
2843 | var leastCost = page * perCost;
2844 | // 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
2845 | var normalCost = Math.ceil((size / 1e5) + page * (1 + perCost));
2846 | var cost = leastCost;
2847 | var gp = Math.ceil(size / 1e5) * 2 + page;
2848 | var isUsingGP = false;
2849 | var isUsingOriginal = !setting['force-resized'] && !isTor;
2850 | // var isSourceNexus = isSourceNexusEnabled();
2851 |
2852 | // tor site don't have original image feature
2853 | if (isUsingOriginal) {
2854 | if (isGPRequired()) {
2855 | isUsingGP = true;
2856 | }
2857 | if (!isUsingGP) {
2858 | cost = normalCost;
2859 | } else {
2860 | cost = leastCost + ' + ' + gp + ' GP';
2861 | }
2862 | }
2863 |
2864 | var result = {
2865 | cost: cost,
2866 | normalCost: normalCost,
2867 | leastCost: leastCost,
2868 | perCost: perCost,
2869 | gp: gp,
2870 | isUsingOriginal: isUsingOriginal,
2871 | isUsingGP: isUsingGP,
2872 | };
2873 |
2874 | console.log('[EHD] Pre-calculate estimated cost >', JSON.stringify(result));
2875 | return result;
2876 | }
2877 |
2878 | function showPreCalcCost(){
2879 | var data = preCalculateCost();
2880 | var isUsingOriginal = data.isUsingOriginal;
2881 | var isUsingGP = data.isUsingGP;
2882 | var leastCost = data.leastCost;
2883 | var gp = data.gp;
2884 | var cost = data.cost;
2885 |
2886 | ehDownloadBox.getElementsByClassName('ehD-box-cost')[0].innerHTML = ' | \
2887 |
'
2894 | + 'Estimated Costs: ' + (/* isSourceNexus ? leastCost : */ cost || '???') + ' ';
2895 | }
2896 |
2897 | // EHD Box, thanks to JingJang@GitHub, source: https://github.com/JingJang/E-Hentai-Downloader
2898 | var ehDownloadBox = document.createElement('fieldset');
2899 | ehDownloadBox.className = 'ehD-box';
2900 | var ehDownloadBoxTitle = document.createElement('legend');
2901 | ehDownloadBoxTitle.innerHTML = 'E-Hentai Downloader
';
2902 | if (origin.indexOf('exhentai.org') >= 0) ehDownloadBoxTitle.style.color = '#ffff66';
2903 | ehDownloadBox.appendChild(ehDownloadBoxTitle);
2904 | var ehDownloadStylesheet = document.createElement('style');
2905 | ehDownloadStylesheet.textContent = ehDownloadStyle;
2906 | ehDownloadBox.appendChild(ehDownloadStylesheet);
2907 |
2908 | var extraHint;
2909 | if (isInPeakHours() && !isRecentGallery()) {
2910 | extraHint = document.createElement('a');
2911 | extraHint.setAttribute('title', 'Peak Hours: It\'s in peak hours now, during peak hours, downloading original images of 90 days ago cost GPs');
2912 | extraHint.textContent = '[P]';
2913 | ehDownloadBoxTitle.appendChild(extraHint);
2914 | }
2915 | if (isAncientGallery()) {
2916 | extraHint = document.createElement('a');
2917 | extraHint.setAttribute('title', 'Ancient Gallery: Downloading original images of 1 year ago cost GPs');
2918 | extraHint.textContent = '[A]';
2919 | ehDownloadBoxTitle.appendChild(extraHint);
2920 | }
2921 |
2922 | var ehDownloadArrow = '
';
2923 |
2924 | var ehDownloadAction = document.createElement('div');
2925 | ehDownloadAction.className = 'g2';
2926 | ehDownloadAction.innerHTML = ehDownloadArrow + '
Download Archive ';
2927 | ehDownloadAction.addEventListener('click', function(event){
2928 | event.preventDefault();
2929 |
2930 | var torrentsNode = document.querySelector('#gd5 a[onclick*="gallerytorrents.php"]');
2931 | var torrentsCount = torrentsNode ? torrentsNode.textContent.match(/\d+/)[0] - 0 : 0;
2932 | if (isDownloading && !confirm('E-Hentai Downloader is working now, are you sure to stop downloading and start a new download?')) return;
2933 |
2934 | 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)')) {
2935 | return torrentsNode.dispatchEvent(new MouseEvent('click'));
2936 | }
2937 |
2938 | if (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;
2939 |
2940 | console.log('[EHD] Is Peak Hours >', isInPeakHours(), ' | Is Recent Gallery >', isRecentGallery(), ' | Is Ancient Gallery >', isAncientGallery(), ' | Is Donator >', isDonator());
2941 |
2942 | if (
2943 | !setting['force-resized'] &&
2944 | !isTor &&
2945 | !setting['never-warn-peak-hours'] &&
2946 | isGPRequired() // &&
2947 | // !isSourceNexusEnabled()
2948 | ) {
2949 | if (isAncientGallery() && isDonator() < 1) {
2950 | 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?')) {
2951 | return;
2952 | }
2953 | } else {
2954 | 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?')) {
2955 | return;
2956 | }
2957 | }
2958 | }
2959 |
2960 | if (!setting['never-warn-limits']) {
2961 | var costData = preCalculateCost();
2962 | var limitsData = getImageLimits();
2963 | var totalLimitsCost = +(setting['force-resized'] ? costData.leastCost : costData.normalCost) || 0;
2964 | if (Number.isNaN(totalLimitsCost)) {
2965 | totalLimitsCost = 0;
2966 | }
2967 | var finalLimits = +(limitsData.cur || 0) + totalLimitsCost;
2968 | if (finalLimits > limitsData.total) {
2969 | 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?')) {
2970 | return;
2971 | }
2972 | }
2973 | }
2974 |
2975 | ehDownloadDialog.innerHTML = '';
2976 |
2977 | initEHDownload();
2978 | });
2979 | ehDownloadBox.appendChild(ehDownloadAction);
2980 |
2981 | var ehDownloadNumberInput = document.createElement('div');
2982 | ehDownloadNumberInput.className = 'g2';
2983 | ehDownloadNumberInput.innerHTML = ehDownloadArrow + '
Number Images';
2984 | ehDownloadBox.appendChild(ehDownloadNumberInput);
2985 |
2986 | var ehDownloadRange = document.createElement('div');
2987 | ehDownloadRange.className = 'g2';
2988 | ehDownloadRange.innerHTML = ehDownloadArrow + '
Pages Range ';
2989 | ehDownloadBox.appendChild(ehDownloadRange);
2990 |
2991 | var ehDownloadSetting = document.createElement('div');
2992 | ehDownloadSetting.className = 'g2';
2993 | ehDownloadSetting.innerHTML = ehDownloadArrow + '
Settings ';
2994 | ehDownloadSetting.addEventListener('click', function(event){
2995 | event.preventDefault();
2996 | showSettings();
2997 | });
2998 | ehDownloadBox.appendChild(ehDownloadSetting);
2999 |
3000 | document.body.insertBefore(ehDownloadBox, document.getElementById('asm') || document.querySelector('.gm').nextElementSibling);
3001 |
3002 | var ehDownloadDialog = document.createElement('div');
3003 | ehDownloadDialog.className = 'ehD-dialog';
3004 | document.body.appendChild(ehDownloadDialog);
3005 |
3006 | var ehDownloadStatus = document.createElement('div');
3007 | ehDownloadStatus.className = 'ehD-status';
3008 | ehDownloadStatus.addEventListener('click', function(event){
3009 | event.preventDefault();
3010 | ehDownloadDialog.classList.toggle('hidden');
3011 | });
3012 |
3013 | var ehDownloadPauseBtn = document.createElement('button');
3014 | ehDownloadPauseBtn.className = 'ehD-pause';
3015 | ehDownloadPauseBtn.textContent ='Pause';
3016 | ehDownloadPauseBtn.addEventListener('click', function(event){
3017 | if (!isPausing) {
3018 | isPausing = true;
3019 | ehDownloadPauseBtn.textContent = 'Resume';
3020 |
3021 | if (setting['force-pause']) {
3022 | // waiting Tampermonkey for transfering string to ArrayBuffer, it may stuck for a second
3023 | setTimeout(function(){
3024 | for (var i = 0; i < fetchThread.length; i++) {
3025 | if (typeof fetchThread[i] !== 'undefined' && 'abort' in fetchThread[i]) fetchThread[i].abort();
3026 |
3027 | if (imageData[i] === 'Fetching' && retryCount[i] < (setting['retry-count'] !== undefined ? setting['retry-count'] : 3)) {
3028 | var elem = progressTable.querySelector('tr[data-index="' + i + '"] .ehD-pt-status-text');
3029 | if (elem) elem.textContent = 'Force Paused';
3030 |
3031 | elem = progressTable.querySelector('tr[data-index="' + i + '"] .ehD-pt-progress-text');
3032 | if (elem) elem.textContent = '';
3033 |
3034 | imageData[i] = null;
3035 | //fetchCount = 0; // fixed for async
3036 | fetchCount--;
3037 |
3038 | updateTotalStatus();
3039 | }
3040 | }
3041 | }, 0);
3042 | }
3043 |
3044 | if (emptyAudio) {
3045 | emptyAudio.pause();
3046 | }
3047 | }
3048 | else {
3049 | isPausing = false;
3050 | ehDownloadPauseBtn.textContent = setting['force-pause'] ? 'Pause (Downloading images will be aborted)' : 'Pause (Downloading images will keep downloading)';
3051 |
3052 | checkFailed();
3053 | }
3054 | });
3055 |
3056 | window.addEventListener('focus', function(){
3057 | if (setting['status-in-title'] === 'blur') {
3058 | if (!needTitleStatus) return;
3059 | document.title = pretitle;
3060 | needTitleStatus = false;
3061 | }
3062 | });
3063 |
3064 | window.addEventListener('blur', function(){
3065 | if (isDownloading && setting['status-in-title'] === 'blur') {
3066 | needTitleStatus = true;
3067 | document.title = '[' + (isPausing ? '❙❙' : downloadedCount < totalCount ? '↓ ' + downloadedCount + '/' + totalCount : totalCount === 0 ? '↓' : '√' ) + '] ' + pretitle;
3068 | }
3069 | });
3070 |
3071 | var forceDownloadTips = document.createElement('div');
3072 | forceDownloadTips.className = 'ehD-force-download-tips';
3073 | forceDownloadTips.innerHTML = 'If an error occured and script doesn\'t work, click
here to force get your downloaded images.';
3074 | forceDownloadTips.getElementsByTagName('a')[0].addEventListener('click', function(event){
3075 | // fixed permission denied on GreaseMonkey
3076 | event.preventDefault();
3077 | saveDownloaded(true);
3078 | });
3079 |
3080 | var closeTips = document.createElement('div');
3081 | closeTips.className = 'ehD-close-tips';
3082 | 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.';
3083 |
3084 | unsafeWindow.getzip = window.getzip = function(){
3085 | saveDownloaded(true);
3086 | };
3087 |
3088 | initSetting();
3089 |
3090 | window.addEventListener('storage', showImageLimits);
3091 |
3092 | window.onbeforeunload = unsafeWindow.onbeforeunload = function(){
3093 | function clearRubbish(){
3094 | for (var i = 0; i < fetchThread.length; i++) {
3095 | if (typeof fetchThread[i] !== 'undefined' && 'abort' in fetchThread[i]) fetchThread[i].abort();
3096 | }
3097 | ehDownloadFS.removeFile(unsafeWindow.gid + '.zip');
3098 | }
3099 | if (isDownloading || isPausing || isSaving) {
3100 | document.body.appendChild(closeTips);
3101 |
3102 | setTimeout(function(){
3103 | document.body.removeChild(closeTips);
3104 | }, 100);
3105 |
3106 | return 'E-Hentai Downloader is still running, please don\'t close this tab until it finished downloading.';
3107 | }
3108 | clearRubbish();
3109 | };
3110 |
--------------------------------------------------------------------------------