Sleazy Fork is available in English.

Exhentai Flow Viewer

This scripts helps you to view a gallery in a single page, from up to down.

  1. // ==UserScript==
  2. // @name Exhentai Flow Viewer
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.2.1
  5. // @author MrJohnnY20
  6. // @match https://exhentai.org/s/*
  7. // @description This scripts helps you to view a gallery in a single page, from up to down.
  8. // @locale en
  9. // ==/UserScript==
  10.  
  11. var container; // The <div> to hold images, intending to inherit it's style.
  12. var parser;
  13.  
  14. function getNext(currURL, currDOC) {
  15. 'use strict';
  16. var nextURL = currDOC.getElementById('next').href;
  17.  
  18. // The last page has the next url directing to itself.
  19. if (currURL === nextURL) {
  20. console.log('Reach the last page');
  21. return;
  22. }
  23.  
  24. // Prepare http request for the next page.
  25. var nextPage = new XMLHttpRequest();
  26. nextPage.onreadystatechange = function () {
  27. if (nextPage.readyState !== 4) {
  28. return;
  29. }
  30.  
  31. if (nextPage.status !== 200) {
  32. console.log('Failed to fetch ' + nextURL + ': ' + nextPage.status);
  33. return;
  34. }
  35.  
  36. var doc = parser.parseFromString(nextPage.responseText, 'text/html');
  37. var img = doc.getElementById('img');
  38.  
  39. const originalImgOnError = img.getAttribute('onerror');
  40.  
  41. // Originally a method 'nl' (in ehg_show.c.js) will be called on image fetch fail to change the url with a query `?nl=xxxx-xxxx`. This uses a backup server with different img URL.
  42. // Stop ehg_c from refreshing the page and use the backup img URL directly.
  43. img.onerror = () => {
  44. // This will cause an error log in browser console.
  45. console.log('Error loading img. Try uses backup img instead.');
  46. const regex = /'([^']*)'/g;
  47. let suffix = '';
  48. try {
  49. suffix = regex.exec(originalImgOnError)[1];
  50. } catch (e) {
  51. console.log(
  52. 'Extract the nl parameter fails. Loading backup image fails.'
  53. );
  54. return;
  55. }
  56. const backupPageURL = nextURL + '?nl=' + suffix;
  57.  
  58. // Fetch backup img url.
  59. const backupPage = new XMLHttpRequest();
  60. backupPage.onreadystatechange = () => {
  61. if (backupPage.readyState !== 4 || backupPage.status !== 200) {
  62. return;
  63. }
  64.  
  65. const backupImgURL = parser
  66. .parseFromString(backupPage.responseText, 'text/html')
  67. .getElementById('img')
  68. .getAttribute('src');
  69.  
  70. img.src = backupImgURL;
  71. };
  72. backupPage.open('GET', backupPageURL, false);
  73. backupPage.send();
  74. };
  75.  
  76. img.style.paddingTop = '1em';
  77. container.append(img);
  78. setTimeout(getNext, 500, nextURL, doc);
  79. };
  80.  
  81. nextPage.open('GET', nextURL, false);
  82. nextPage.send();
  83. }
  84.  
  85. (function () {
  86. parser = new DOMParser();
  87. container = document.getElementById('i3');
  88. getNext(document.URL, document);
  89. })();