FA Infini-Gallery

Automatically loads the next page of the gallery as you reach the bottom

  1. // ==UserScript==
  2. // @name FA Infini-Gallery
  3. // @namespace Violentmonkey Scripts
  4. // @match *://*.furaffinity.net/*
  5. // @require https://update.greatest.deepsurf.us/scripts/525666/1549449/Furaffinity-Prototype-Extensions.js
  6. // @require https://update.greatest.deepsurf.us/scripts/483952/1549453/Furaffinity-Request-Helper.js
  7. // @require https://update.greatest.deepsurf.us/scripts/485827/1549457/Furaffinity-Match-List.js
  8. // @require https://update.greatest.deepsurf.us/scripts/485153/1549461/Furaffinity-Loading-Animations.js
  9. // @require https://update.greatest.deepsurf.us/scripts/475041/1550020/Furaffinity-Custom-Settings.js
  10. // @grant GM_info
  11. // @version 2.2.3
  12. // @author Midori Dragon
  13. // @description Automatically loads the next page of the gallery as you reach the bottom
  14. // @icon https://www.furaffinity.net/themes/beta/img/banners/fa_logo.png
  15. // @license MIT
  16. // @homepageURL https://greatest.deepsurf.us/scripts/462632-fa-infini-gallery
  17. // @supportURL https://greatest.deepsurf.us/scripts/462632-fa-infini-gallery/feedback
  18. // ==/UserScript==
  19. // jshint esversion: 8
  20. (() => {
  21. "use strict";
  22. var LogLevel, __webpack_require__ = {
  23. d: (exports, definition) => {
  24. for (var key in definition) if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) Object.defineProperty(exports, key, {
  25. enumerable: true,
  26. get: definition[key]
  27. });
  28. },
  29. o: (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop)
  30. };
  31. __webpack_require__.d({}, {
  32. I4: () => pageSeparatorTextSetting,
  33. uL: () => requestHelper,
  34. kG: () => showPageSeparatorSetting
  35. });
  36. function createSeparatorElem(pageNo) {
  37. const nextPageDescContainer = document.createElement("div");
  38. nextPageDescContainer.className = "folder-description";
  39. nextPageDescContainer.style.marginTop = "6px";
  40. nextPageDescContainer.style.marginBottom = "6px";
  41. const nextPageDesc = document.createElement("div");
  42. nextPageDesc.className = "container-item-top";
  43. const nextPageDescText = document.createElement("h3"), pageString = pageSeparatorTextSetting.value.replace(/%page%/g, pageNo.toString());
  44. nextPageDescText.textContent = pageString;
  45. nextPageDesc.appendChild(nextPageDescText);
  46. nextPageDescContainer.appendChild(nextPageDesc);
  47. return nextPageDescContainer;
  48. }
  49. function getFiguresFromPage(page) {
  50. const figures = page.querySelectorAll('figure[class*="t"]');
  51. return null == figures ? [] : Array.from(figures).map((figure => figure));
  52. }
  53. function getUserNameFromUrl(url) {
  54. if (url.includes("?")) url = url.substring(0, url.indexOf("?"));
  55. return (url = url.trimEnd("/")).substring(url.lastIndexOf("/") + 1);
  56. }
  57. !function(LogLevel) {
  58. LogLevel[LogLevel.Error = 1] = "Error";
  59. LogLevel[LogLevel.Warning = 2] = "Warning";
  60. LogLevel[LogLevel.Info = 3] = "Info";
  61. }(LogLevel || (LogLevel = {}));
  62. class Logger {
  63. static log(logLevel = LogLevel.Warning, ...args) {
  64. if (null == window.__FF_GLOBAL_LOG_LEVEL__) window.__FF_GLOBAL_LOG_LEVEL__ = LogLevel.Error;
  65. if (!(logLevel > window.__FF_GLOBAL_LOG_LEVEL__)) switch (logLevel) {
  66. case LogLevel.Error:
  67. console.error(...args);
  68. break;
  69.  
  70. case LogLevel.Warning:
  71. console.warn(...args);
  72. break;
  73.  
  74. case LogLevel.Info:
  75. console.log(...args);
  76. }
  77. }
  78. static setLogLevel(logLevel) {
  79. window.__FF_GLOBAL_LOG_LEVEL__ = logLevel;
  80. }
  81. static logError(...args) {
  82. Logger.log(LogLevel.Error, ...args);
  83. }
  84. static logWarning(...args) {
  85. Logger.log(LogLevel.Warning, ...args);
  86. }
  87. static logInfo(...args) {
  88. Logger.log(LogLevel.Info, ...args);
  89. }
  90. }
  91. var __awaiter = function(thisArg, _arguments, P, generator) {
  92. return new (P || (P = Promise))((function(resolve, reject) {
  93. function fulfilled(value) {
  94. try {
  95. step(generator.next(value));
  96. } catch (e) {
  97. reject(e);
  98. }
  99. }
  100. function rejected(value) {
  101. try {
  102. step(generator.throw(value));
  103. } catch (e) {
  104. reject(e);
  105. }
  106. }
  107. function step(result) {
  108. result.done ? resolve(result.value) : function adopt(value) {
  109. return value instanceof P ? value : new P((function(resolve) {
  110. resolve(value);
  111. }));
  112. }(result.value).then(fulfilled, rejected);
  113. }
  114. step((generator = generator.apply(thisArg, _arguments || [])).next());
  115. }));
  116. };
  117. class BrowsePage {
  118. constructor(pageNo) {
  119. this.pageNo = pageNo;
  120. this.gallery = document.querySelector('section[id*="gallery"]');
  121. }
  122. getPage() {
  123. return __awaiter(this, void 0, void 0, (function*() {
  124. Logger.logInfo(`Getting page BrowsePage '${this.pageNo}'`);
  125. return yield requestHelper.UserRequests.SearchRequests.Browse.getPage(this.pageNo, this.getBrowseOptions());
  126. }));
  127. }
  128. getBrowseOptions() {
  129. var _a, _b, _c, _d;
  130. const currBrowseOptions = requestHelper.UserRequests.SearchRequests.Browse.newBrowseOptions, sideBar = document.getElementById("sidebar-options"), optionContainers = null == sideBar ? void 0 : sideBar.querySelectorAll('div[class*="browse-search-flex-item"]');
  131. for (const optionContainer of Array.from(null != optionContainers ? optionContainers : [])) try {
  132. let optionName = null !== (_c = null === (_b = null === (_a = null == optionContainer ? void 0 : optionContainer.querySelector("strong")) || void 0 === _a ? void 0 : _a.textContent) || void 0 === _b ? void 0 : _b.toLowerCase()) && void 0 !== _c ? _c : "";
  133. optionName = optionName.trimEnd(":");
  134. const optionValue = null === (_d = null == optionContainer ? void 0 : optionContainer.querySelector("option[selected]")) || void 0 === _d ? void 0 : _d.getAttribute("value");
  135. if (null != optionValue) switch (optionName) {
  136. case "category":
  137. currBrowseOptions.category = parseInt(optionValue);
  138. break;
  139.  
  140. case "type":
  141. currBrowseOptions.type = parseInt(optionValue);
  142. break;
  143.  
  144. case "species":
  145. currBrowseOptions.species = parseInt(optionValue);
  146. break;
  147.  
  148. case "gender":
  149. currBrowseOptions.gender = parseInt(optionValue);
  150. break;
  151.  
  152. case "results":
  153. currBrowseOptions.results = parseInt(optionValue);
  154. break;
  155.  
  156. case "ratingGeneral":
  157. currBrowseOptions.ratingGeneral = "true" === optionValue;
  158. break;
  159.  
  160. case "ratingMature":
  161. currBrowseOptions.ratingMature = "true" === optionValue;
  162. break;
  163.  
  164. case "ratingAdult":
  165. currBrowseOptions.ratingAdult = "true" === optionValue;
  166. }
  167. } catch (_e) {}
  168. const checkBoxes = null == sideBar ? void 0 : sideBar.querySelectorAll('input[type="checkbox"]');
  169. for (const checkbox of Array.from(null != checkBoxes ? checkBoxes : [])) switch (checkbox.getAttribute("name")) {
  170. case "rating_general":
  171. currBrowseOptions.ratingGeneral = checkbox.hasAttribute("checked");
  172. break;
  173.  
  174. case "rating_mature":
  175. currBrowseOptions.ratingMature = checkbox.hasAttribute("checked");
  176. break;
  177.  
  178. case "rating_adult":
  179. currBrowseOptions.ratingAdult = checkbox.hasAttribute("checked");
  180. }
  181. return currBrowseOptions;
  182. }
  183. loadPage(prevFigures) {
  184. return __awaiter(this, void 0, void 0, (function*() {
  185. const page = yield this.getPage();
  186. if (null == page) throw new Error("No page found");
  187. null != prevFigures || (prevFigures = []);
  188. const prevSids = prevFigures.map((figure => figure.id));
  189. let figures = getFiguresFromPage(page);
  190. figures = figures.filter((figure => !prevSids.includes(figure.id)));
  191. if (0 !== figures.length) {
  192. if (showPageSeparatorSetting.value) {
  193. const separator = createSeparatorElem(this.pageNo);
  194. this.gallery.appendChild(separator);
  195. }
  196. for (const figure of figures) this.gallery.appendChild(figure);
  197. } else throw new Error("No figures found");
  198. window.dispatchEvent(new CustomEvent("ei-update-embedded"));
  199. return figures;
  200. }));
  201. }
  202. }
  203. var FavoritesPage_awaiter = function(thisArg, _arguments, P, generator) {
  204. return new (P || (P = Promise))((function(resolve, reject) {
  205. function fulfilled(value) {
  206. try {
  207. step(generator.next(value));
  208. } catch (e) {
  209. reject(e);
  210. }
  211. }
  212. function rejected(value) {
  213. try {
  214. step(generator.throw(value));
  215. } catch (e) {
  216. reject(e);
  217. }
  218. }
  219. function step(result) {
  220. result.done ? resolve(result.value) : function adopt(value) {
  221. return value instanceof P ? value : new P((function(resolve) {
  222. resolve(value);
  223. }));
  224. }(result.value).then(fulfilled, rejected);
  225. }
  226. step((generator = generator.apply(thisArg, _arguments || [])).next());
  227. }));
  228. };
  229. class FavoritesPage {
  230. constructor(dataFavId, pageNo) {
  231. this.dataFavId = dataFavId;
  232. this.pageNo = pageNo;
  233. this.gallery = document.querySelector('section[id*="gallery"]');
  234. }
  235. getPage() {
  236. return FavoritesPage_awaiter(this, void 0, void 0, (function*() {
  237. Logger.logInfo(`Getting page FavoritesPage '${this.pageNo}'`);
  238. const username = getUserNameFromUrl(window.location.toString());
  239. return yield requestHelper.UserRequests.GalleryRequests.Favorites.getPage(username, this.dataFavId);
  240. }));
  241. }
  242. loadPage(prevFigures) {
  243. return FavoritesPage_awaiter(this, void 0, void 0, (function*() {
  244. const page = yield this.getPage();
  245. if (null == page) throw new Error("No page found");
  246. null != prevFigures || (prevFigures = []);
  247. const prevSids = prevFigures.map((figure => figure.id));
  248. let figures = getFiguresFromPage(page);
  249. figures = figures.filter((figure => !prevSids.includes(figure.id)));
  250. if (0 !== figures.length) {
  251. if (this.dataFavId === figures[figures.length - 1].getAttribute("data-fav-id")) throw new Error("Last page reached");
  252. if (showPageSeparatorSetting.value) {
  253. const separator = createSeparatorElem(this.pageNo);
  254. this.gallery.appendChild(separator);
  255. }
  256. for (const figure of figures) this.gallery.appendChild(figure);
  257. } else throw new Error("No figures found");
  258. window.dispatchEvent(new CustomEvent("ei-update-embedded"));
  259. return figures;
  260. }));
  261. }
  262. }
  263. var GalleryPage_awaiter = function(thisArg, _arguments, P, generator) {
  264. return new (P || (P = Promise))((function(resolve, reject) {
  265. function fulfilled(value) {
  266. try {
  267. step(generator.next(value));
  268. } catch (e) {
  269. reject(e);
  270. }
  271. }
  272. function rejected(value) {
  273. try {
  274. step(generator.throw(value));
  275. } catch (e) {
  276. reject(e);
  277. }
  278. }
  279. function step(result) {
  280. result.done ? resolve(result.value) : function adopt(value) {
  281. return value instanceof P ? value : new P((function(resolve) {
  282. resolve(value);
  283. }));
  284. }(result.value).then(fulfilled, rejected);
  285. }
  286. step((generator = generator.apply(thisArg, _arguments || [])).next());
  287. }));
  288. };
  289. class GalleryPage {
  290. constructor(pageNo) {
  291. this.pageNo = pageNo;
  292. this.gallery = document.querySelector('section[id*="gallery"]');
  293. this.isInFolder = window.location.toString().includes("/folder/");
  294. }
  295. getPage() {
  296. return GalleryPage_awaiter(this, void 0, void 0, (function*() {
  297. Logger.logInfo(`Getting page GalleryPage '${this.pageNo}'`);
  298. const username = getUserNameFromUrl(window.location.toString());
  299. let page;
  300. if (true === this.isInFolder) {
  301. let folderId;
  302. page = yield requestHelper.UserRequests.GalleryRequests.Gallery.getPageInFolder(username, folderId, this.pageNo);
  303. } else page = yield requestHelper.UserRequests.GalleryRequests.Gallery.getPage(username, this.pageNo);
  304. return page;
  305. }));
  306. }
  307. loadPage(prevFigures) {
  308. return GalleryPage_awaiter(this, void 0, void 0, (function*() {
  309. const page = yield this.getPage();
  310. if (null == page) throw new Error("No page found");
  311. null != prevFigures || (prevFigures = []);
  312. const prevSids = prevFigures.map((figure => figure.id));
  313. let figures = getFiguresFromPage(page);
  314. figures = figures.filter((figure => !prevSids.includes(figure.id)));
  315. if (0 !== figures.length) {
  316. if (showPageSeparatorSetting.value) {
  317. const separator = createSeparatorElem(this.pageNo);
  318. this.gallery.appendChild(separator);
  319. }
  320. for (const figure of figures) this.gallery.appendChild(figure);
  321. } else throw new Error("No figures found");
  322. window.dispatchEvent(new CustomEvent("ei-update-embedded"));
  323. return figures;
  324. }));
  325. }
  326. }
  327. var ScrapsPage_awaiter = function(thisArg, _arguments, P, generator) {
  328. return new (P || (P = Promise))((function(resolve, reject) {
  329. function fulfilled(value) {
  330. try {
  331. step(generator.next(value));
  332. } catch (e) {
  333. reject(e);
  334. }
  335. }
  336. function rejected(value) {
  337. try {
  338. step(generator.throw(value));
  339. } catch (e) {
  340. reject(e);
  341. }
  342. }
  343. function step(result) {
  344. result.done ? resolve(result.value) : function adopt(value) {
  345. return value instanceof P ? value : new P((function(resolve) {
  346. resolve(value);
  347. }));
  348. }(result.value).then(fulfilled, rejected);
  349. }
  350. step((generator = generator.apply(thisArg, _arguments || [])).next());
  351. }));
  352. };
  353. class ScrapsPage {
  354. constructor(pageNo) {
  355. this.pageNo = pageNo;
  356. this.gallery = document.querySelector('section[id*="gallery"]');
  357. }
  358. getPage() {
  359. return ScrapsPage_awaiter(this, void 0, void 0, (function*() {
  360. Logger.logInfo(`Getting page ScrapsPage '${this.pageNo}'`);
  361. const username = getUserNameFromUrl(window.location.toString());
  362. return yield requestHelper.UserRequests.GalleryRequests.Scraps.getPage(username, this.pageNo);
  363. }));
  364. }
  365. loadPage(prevFigures) {
  366. return ScrapsPage_awaiter(this, void 0, void 0, (function*() {
  367. const page = yield this.getPage();
  368. if (null == page) throw new Error("No page found");
  369. null != prevFigures || (prevFigures = []);
  370. const prevSids = prevFigures.map((figure => figure.id));
  371. let figures = getFiguresFromPage(page);
  372. figures = figures.filter((figure => !prevSids.includes(figure.id)));
  373. if (0 !== figures.length) {
  374. if (showPageSeparatorSetting.value) {
  375. const separator = createSeparatorElem(this.pageNo);
  376. this.gallery.appendChild(separator);
  377. }
  378. for (const figure of figures) this.gallery.appendChild(figure);
  379. } else throw new Error("No figures found");
  380. window.dispatchEvent(new CustomEvent("ei-update-embedded"));
  381. return figures;
  382. }));
  383. }
  384. }
  385. var SearchPage_awaiter = function(thisArg, _arguments, P, generator) {
  386. return new (P || (P = Promise))((function(resolve, reject) {
  387. function fulfilled(value) {
  388. try {
  389. step(generator.next(value));
  390. } catch (e) {
  391. reject(e);
  392. }
  393. }
  394. function rejected(value) {
  395. try {
  396. step(generator.throw(value));
  397. } catch (e) {
  398. reject(e);
  399. }
  400. }
  401. function step(result) {
  402. result.done ? resolve(result.value) : function adopt(value) {
  403. return value instanceof P ? value : new P((function(resolve) {
  404. resolve(value);
  405. }));
  406. }(result.value).then(fulfilled, rejected);
  407. }
  408. step((generator = generator.apply(thisArg, _arguments || [])).next());
  409. }));
  410. };
  411. class SearchPage {
  412. constructor(pageNo) {
  413. this.pageNo = pageNo;
  414. this.gallery = document.querySelector('section[id*="gallery"]');
  415. }
  416. getPage() {
  417. return SearchPage_awaiter(this, void 0, void 0, (function*() {
  418. Logger.logInfo(`Getting page SearchPage '${this.pageNo}'`);
  419. return yield requestHelper.UserRequests.SearchRequests.Search.getPage(this.pageNo, this.getSearchOptions());
  420. }));
  421. }
  422. getSearchOptions() {
  423. var _a, _b, _c;
  424. const searchOptions = requestHelper.UserRequests.SearchRequests.Search.newSearchOptions, input = document.getElementById("q");
  425. searchOptions.input = null !== (_a = null == input ? void 0 : input.getAttribute("value")) && void 0 !== _a ? _a : "";
  426. const searchContainer = document.getElementById("search-advanced"), options = null == searchContainer ? void 0 : searchContainer.querySelectorAll("option[selected]");
  427. for (const option of Array.from(null != options ? options : [])) {
  428. const name = option.parentNode.getAttribute("name"), value = option.getAttribute("value");
  429. switch (name) {
  430. case "order-by":
  431. searchOptions.orderBy = null != value ? value : void 0;
  432. break;
  433.  
  434. case "order-direction":
  435. searchOptions.orderDirection = null != value ? value : void 0;
  436. }
  437. }
  438. const radioButtons = null == searchContainer ? void 0 : searchContainer.querySelectorAll('input[type="radio"][checked]');
  439. for (const radioButton of Array.from(null != radioButtons ? radioButtons : [])) {
  440. const name = radioButton.getAttribute("name"), value = radioButton.getAttribute("value");
  441. switch (name) {
  442. case "range":
  443. searchOptions.range = null != value ? value : void 0;
  444. break;
  445.  
  446. case "mode":
  447. searchOptions.matching = null != value ? value : void 0;
  448. }
  449. if ("manual" === value) {
  450. const rangeFrom = null == searchContainer ? void 0 : searchContainer.querySelector('input[type="date"][name="range_from"]');
  451. searchOptions.rangeFrom = null !== (_b = null == rangeFrom ? void 0 : rangeFrom.getAttribute("value")) && void 0 !== _b ? _b : void 0;
  452. const rangeTo = null == searchContainer ? void 0 : searchContainer.querySelector('input[type="date"][name="range_to"]');
  453. searchOptions.rangeTo = null !== (_c = null == rangeTo ? void 0 : rangeTo.getAttribute("value")) && void 0 !== _c ? _c : void 0;
  454. }
  455. }
  456. const checkBoxes = null == searchContainer ? void 0 : searchContainer.querySelectorAll('input[type="checkbox"]');
  457. for (const checkBox of Array.from(null != checkBoxes ? checkBoxes : [])) switch (checkBox.getAttribute("name")) {
  458. case "rating-general":
  459. searchOptions.ratingGeneral = checkBox.hasAttribute("checked");
  460. break;
  461.  
  462. case "rating-mature":
  463. searchOptions.ratingMature = checkBox.hasAttribute("checked");
  464. break;
  465.  
  466. case "rating-adult":
  467. searchOptions.ratingAdult = checkBox.hasAttribute("checked");
  468. break;
  469.  
  470. case "type-art":
  471. searchOptions.typeArt = checkBox.hasAttribute("checked");
  472. break;
  473.  
  474. case "type-music":
  475. searchOptions.typeMusic = checkBox.hasAttribute("checked");
  476. break;
  477.  
  478. case "type-flash":
  479. searchOptions.typeFlash = checkBox.hasAttribute("checked");
  480. break;
  481.  
  482. case "type-story":
  483. searchOptions.typeStory = checkBox.hasAttribute("checked");
  484. break;
  485.  
  486. case "type-photo":
  487. searchOptions.typePhotos = checkBox.hasAttribute("checked");
  488. break;
  489.  
  490. case "type-poetry":
  491. searchOptions.typePoetry = checkBox.hasAttribute("checked");
  492. }
  493. return searchOptions;
  494. }
  495. loadPage(prevFigures) {
  496. return SearchPage_awaiter(this, void 0, void 0, (function*() {
  497. const page = yield this.getPage();
  498. if (null == page) throw new Error("No page found");
  499. null != prevFigures || (prevFigures = []);
  500. const prevSids = prevFigures.map((figure => figure.id));
  501. let figures = getFiguresFromPage(page);
  502. figures = figures.filter((figure => !prevSids.includes(figure.id)));
  503. if (0 !== figures.length) {
  504. if (showPageSeparatorSetting.value) {
  505. const separator = createSeparatorElem(this.pageNo);
  506. this.gallery.appendChild(separator);
  507. }
  508. for (const figure of figures) this.gallery.appendChild(figure);
  509. } else throw new Error("No figures found");
  510. window.dispatchEvent(new CustomEvent("ei-update-embedded"));
  511. return figures;
  512. }));
  513. }
  514. }
  515. var WatchesPage_awaiter = function(thisArg, _arguments, P, generator) {
  516. return new (P || (P = Promise))((function(resolve, reject) {
  517. function fulfilled(value) {
  518. try {
  519. step(generator.next(value));
  520. } catch (e) {
  521. reject(e);
  522. }
  523. }
  524. function rejected(value) {
  525. try {
  526. step(generator.throw(value));
  527. } catch (e) {
  528. reject(e);
  529. }
  530. }
  531. function step(result) {
  532. result.done ? resolve(result.value) : function adopt(value) {
  533. return value instanceof P ? value : new P((function(resolve) {
  534. resolve(value);
  535. }));
  536. }(result.value).then(fulfilled, rejected);
  537. }
  538. step((generator = generator.apply(thisArg, _arguments || [])).next());
  539. }));
  540. };
  541. class WatchesPage {
  542. constructor(pageNo) {
  543. this.pageNo = pageNo;
  544. const columnpage = document.getElementById("columnpage");
  545. this.gallery = columnpage.querySelector('div[class="section-body"]');
  546. this.gallery.style.display = "flex";
  547. this.gallery.style.flexWrap = "wrap";
  548. }
  549. getPage() {
  550. return WatchesPage_awaiter(this, void 0, void 0, (function*() {
  551. Logger.logInfo(`Getting page WatchesPage '${this.pageNo}'`);
  552. return yield requestHelper.PersonalUserRequests.ManageContent.getWatchesPage(this.pageNo);
  553. }));
  554. }
  555. loadPage(prevWatches) {
  556. return WatchesPage_awaiter(this, void 0, void 0, (function*() {
  557. const page = yield this.getPage();
  558. if (null == page) throw new Error("No page found");
  559. null != prevWatches || (prevWatches = []);
  560. const prevHrefs = prevWatches.map((watch => {
  561. var _a;
  562. return null === (_a = watch.querySelector("a[href]")) || void 0 === _a ? void 0 : _a.href;
  563. }));
  564. let watches = function getWatchesFromPage(page) {
  565. try {
  566. const watchList = [], watches = page.getElementById("columnpage").querySelector('div[class="section-body"]').querySelector('div[class="flex-watchlist"]').querySelectorAll('div[class="flex-item-watchlist aligncenter"]');
  567. for (const watch of Array.from(watches).map((elem => elem))) watchList.push(watch);
  568. return watchList;
  569. } catch (_a) {
  570. return [];
  571. }
  572. }(page);
  573. watches = watches.filter((watch => {
  574. var _a;
  575. return !prevHrefs.includes(null === (_a = watch.querySelector("a[href]")) || void 0 === _a ? void 0 : _a.href);
  576. }));
  577. if (0 !== watches.length) {
  578. if (showPageSeparatorSetting.value) {
  579. const separator = createSeparatorElem(this.pageNo);
  580. separator.style.width = "fit-content";
  581. separator.style.margin = "14px auto";
  582. this.gallery.appendChild(document.createElement("br"));
  583. this.gallery.appendChild(separator);
  584. this.gallery.appendChild(document.createElement("br"));
  585. }
  586. const watchesContainer = document.createElement("div");
  587. watchesContainer.className = "flex-watchlist";
  588. this.gallery.appendChild(watchesContainer);
  589. watchesContainer.append(...watches);
  590. } else throw new Error("No watches found");
  591. return watches;
  592. }));
  593. }
  594. }
  595. var GalleryManager_awaiter = function(thisArg, _arguments, P, generator) {
  596. return new (P || (P = Promise))((function(resolve, reject) {
  597. function fulfilled(value) {
  598. try {
  599. step(generator.next(value));
  600. } catch (e) {
  601. reject(e);
  602. }
  603. }
  604. function rejected(value) {
  605. try {
  606. step(generator.throw(value));
  607. } catch (e) {
  608. reject(e);
  609. }
  610. }
  611. function step(result) {
  612. result.done ? resolve(result.value) : function adopt(value) {
  613. return value instanceof P ? value : new P((function(resolve) {
  614. resolve(value);
  615. }));
  616. }(result.value).then(fulfilled, rejected);
  617. }
  618. step((generator = generator.apply(thisArg, _arguments || [])).next());
  619. }));
  620. };
  621. class GalleryManager {
  622. constructor() {
  623. this.pageNo = 1;
  624. this.prevFigures = [];
  625. this.currDataFavId = "";
  626. this.isGallery = window.location.toString().toLowerCase().includes("net/gallery");
  627. this.isFavorites = window.location.toString().toLowerCase().includes("net/favorites");
  628. this.isScraps = window.location.toString().toLowerCase().includes("net/scraps");
  629. this.isBrowse = window.location.toString().toLowerCase().includes("net/browse");
  630. if (this.isBrowse) {
  631. const pageOption = document.getElementById("manual-page");
  632. if (pageOption instanceof HTMLInputElement) this.pageNo = parseInt(pageOption.value);
  633. }
  634. this.isSearch = window.location.toString().toLowerCase().includes("net/search");
  635. this.isWatches = window.location.toString().toLowerCase().includes("net/controls/buddylist");
  636. if (this.isWatches) {
  637. const columnpage = document.getElementById("columnpage"), gallery = null == columnpage ? void 0 : columnpage.querySelector('div[class="section-body"]'), paginationLinks = null == gallery ? void 0 : gallery.querySelector('div[class*="pagination-links"]');
  638. if (null != paginationLinks) {
  639. const paginationLinksElem = paginationLinks;
  640. paginationLinksElem.style.display = "none";
  641. paginationLinksElem.insertBeforeThis(document.createElement("br"));
  642. }
  643. }
  644. }
  645. loadNextPage() {
  646. return GalleryManager_awaiter(this, void 0, void 0, (function*() {
  647. this.pageNo++;
  648. if (this.isFavorites) {
  649. const gallery = document.body.querySelector('section[id*="gallery"]'), figures = null == gallery ? void 0 : gallery.getElementsByTagName("figure");
  650. if (null != figures && 0 !== figures.length) {
  651. const lastFigureFavId = figures[figures.length - 1].getAttribute("data-fav-id");
  652. if (null != lastFigureFavId) this.currDataFavId = lastFigureFavId;
  653. }
  654. }
  655. let nextPage;
  656. if (this.isGallery) nextPage = new GalleryPage(this.pageNo); else if (this.isFavorites) nextPage = new FavoritesPage(this.currDataFavId, this.pageNo); else if (this.isScraps) nextPage = new ScrapsPage(this.pageNo); else if (this.isBrowse) nextPage = new BrowsePage(this.pageNo); else if (this.isSearch) nextPage = new SearchPage(this.pageNo); else if (this.isWatches) nextPage = new WatchesPage(this.pageNo);
  657. if (null != nextPage) {
  658. const spacer = document.createElement("div");
  659. spacer.style.height = "20px";
  660. nextPage.gallery.appendChild(spacer);
  661. const loadingSpinner = new window.FALoadingSpinner(nextPage.gallery);
  662. loadingSpinner.spinnerThickness = 5;
  663. loadingSpinner.size = 50;
  664. loadingSpinner.visible = true;
  665. try {
  666. this.prevFigures = yield nextPage.loadPage(this.prevFigures);
  667. } finally {
  668. loadingSpinner.visible = false;
  669. loadingSpinner.dispose();
  670. nextPage.gallery.removeChild(spacer);
  671. }
  672. }
  673. }));
  674. }
  675. }
  676. var InfiniGallery_awaiter = function(thisArg, _arguments, P, generator) {
  677. return new (P || (P = Promise))((function(resolve, reject) {
  678. function fulfilled(value) {
  679. try {
  680. step(generator.next(value));
  681. } catch (e) {
  682. reject(e);
  683. }
  684. }
  685. function rejected(value) {
  686. try {
  687. step(generator.throw(value));
  688. } catch (e) {
  689. reject(e);
  690. }
  691. }
  692. function step(result) {
  693. result.done ? resolve(result.value) : function adopt(value) {
  694. return value instanceof P ? value : new P((function(resolve) {
  695. resolve(value);
  696. }));
  697. }(result.value).then(fulfilled, rejected);
  698. }
  699. step((generator = generator.apply(thisArg, _arguments || [])).next());
  700. }));
  701. };
  702. class InfiniGallery {
  703. constructor() {
  704. this.scanInterval = -1;
  705. this.scanElem = document.getElementById("footer");
  706. this.galleryManager = new GalleryManager;
  707. window.addEventListener("ig-stop-detection", (() => {
  708. this.stopScrollDetection();
  709. }));
  710. }
  711. startScrollDetection() {
  712. this.scanInterval = setInterval((() => {
  713. if (function isElementOnScreen(element) {
  714. const rect = element.getBoundingClientRect(), windowHeight = 2 * (window.innerHeight || document.documentElement.clientHeight);
  715. return rect.top <= windowHeight && rect.top + rect.height >= 0;
  716. }(this.scanElem)) {
  717. this.stopScrollDetection();
  718. this.loadNextPage();
  719. }
  720. }), 100);
  721. }
  722. stopScrollDetection() {
  723. clearInterval(this.scanInterval);
  724. }
  725. loadNextPage() {
  726. return InfiniGallery_awaiter(this, void 0, void 0, (function*() {
  727. try {
  728. yield this.galleryManager.loadNextPage();
  729. this.startScrollDetection();
  730. } catch (_a) {
  731. this.stopScrollDetection();
  732. }
  733. }));
  734. }
  735. }
  736. const customSettings = new window.FACustomSettings("Midori's Script Settings", "FA Infini-Gallery Settings"), showPageSeparatorSetting = customSettings.newSetting(window.FASettingType.Boolean, "Page Separator");
  737. showPageSeparatorSetting.description = "Set wether a Page Separator is shown for each new Page loaded. Default: Show Page Separators";
  738. showPageSeparatorSetting.defaultValue = true;
  739. const pageSeparatorTextSetting = customSettings.newSetting(window.FASettingType.Text, "Page Separator Text");
  740. pageSeparatorTextSetting.description = "The Text that is displayed when a new Infini-Gallery Page is loaded (if shown). Number of Page gets inserted instead of: %page% .";
  741. pageSeparatorTextSetting.defaultValue = "Infini-Gallery Page: %page%";
  742. pageSeparatorTextSetting.verifyRegex = /%page%/;
  743. customSettings.loadSettings();
  744. const requestHelper = new window.FARequestHelper(2);
  745. if (customSettings.isFeatureEnabled) {
  746. const matchList = new window.FAMatchList(customSettings);
  747. matchList.matches = [ "net/gallery", "net/favorites", "net/scraps", "net/browse", "net/search", "net/controls/buddylist" ];
  748. matchList.runInIFrame = false;
  749. if (matchList.hasMatch) {
  750. (new InfiniGallery).startScrollDetection();
  751. }
  752. }
  753. })();