Greasy Fork 还支持 简体中文。

Infini-Gallery

Makes so that the gallery continues loading the next page when you reach its bottom

Fra 26.03.2023. Se den seneste versjonen.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name        Infini-Gallery
// @namespace   Violentmonkey Scripts
// @match       *://*.furaffinity.net/gallery/*
// @match       *://*.furaffinity.net/favorites/*
// @match       *://*.furaffinity.net/browse/*
// @match       *://*.furaffinity.net/controls/settings
// @grant       none
// @version     1.1
// @author      Midori Dragon
// @description Makes so that the gallery continues loading the next page when you reach its bottom
// @icon        https://www.furaffinity.net/themes/beta/img/banners/fa_logo.png?v2
// @homepageURL https://greasyfork.org/de/scripts/462632-infini-gallery
// @supportURL  https://greasyfork.org/de/scripts/462632-infini-gallery/feedback
// @license     MIT
// ==/UserScript==

// jshint esversion: 8

//User Options:
let showPageSeperator = JSON.parse(localStorage.getItem("igsetting_01"));
if (showPageSeperator == null)
  showPageSeperator = true;
let showDisableButton = JSON.parse(localStorage.getItem("igsetting_02"));
if (showDisableButton == null)
  showDisableButton = true;


const isGallery = window.location.toString().includes('net/gallery');
const isFavorites = window.location.toString().includes('net/favorites');
const isBrowse = window.location.toString().includes('net/browse');
const isSettings = window.location.toString().includes('controls/settings');

let exSettings = JSON.parse(localStorage.getItem("igsettings"));
if (exSettings == null)
  exSettings = false;
addExSettings();
if (isSettings) {
  addExSettingsSidebar();
  if (exSettings)
    createSettings();
}

let allowScan = true;
let nextButtons;
let lastNextButton;
let gallery;
let lastLink;
let lastNextPageButton;
let pageCount;

if (!isSettings) {
  if (isGallery)
    nextButtons = document.querySelectorAll('button[class*="button standard"][type="submit"]');
  else if (isFavorites)
    nextButtons = document.querySelectorAll('a[class*="button mobile-button right"][href]');
  else if (isBrowse)
    nextButtons = document.querySelectorAll('a[class*="button standard"][href]');
  if (!nextButtons || nextButtons.length == 0)
    return;

  if (showDisableButton) {
    let navPage = document.querySelector('userpage-nav-links').querySelector('ul');
    let disableIGButton = document.createElement('button');
    disableIGButton.id = "disableIGButton";
    disableIGButton.type = "button";
    disableIGButton.className = "button standard mobile-fix";
    disableIGButton.textContent = "Disable Infini Gallery";
    disableIGButton.style.marginTop = "8px";
    disableIGButton.style.marginRight = "18px";
    disableIGButton.onclick = function() {
      allowScan = !allowScan;
      if (allowScan) {
        disableIGButton.textContent = "Disable Infini Gallery";
        scan();
      } else
        disableIGButton.textContent = "Enable Infini Gallery";
    };
    navPage.appendChild(disableIGButton);
  }

  lastNextButton = nextButtons[nextButtons.length - 1];
  gallery = document.querySelector('section[id*="gallery"]');
  lastLink = window.location.toString();
  lastNextPageButton = lastNextButton;
  pageCount = 1;
  scan();
}

async function scan() {
  const interval = setInterval(() => {
    if (!allowScan)
      clearInterval(interval);
    if (isElementOnScreen(lastNextButton)) {
      clearInterval(interval);
      loadNextPage();
    }
  }, 100);
}

async function loadNextPage() {
  let figures;
  if (isGallery)
    figures = await getNextPageFiguresGallery();
  else if (isFavorites)
    figures = await getNextPageFiguresFavorites();
  else if (isBrowse)
    figures = await getNextPageFiguresGallery();
  if (!figures || figures.length == 0) {
    lastNextButton.parentNode.removeChild(lastNextButton);
    return;
  }
  pageCount++;
  let nextPageDescContainer = document.createElement('div');
  nextPageDescContainer.className = 'folder-description';
  nextPageDescContainer.style.marginTop = '6px';
  nextPageDescContainer.style.marginBottom = '6px';
  let nextPageDesc = document.createElement('div');
  nextPageDesc.className = 'container-item-top';
  let nextPageDescText = document.createElement('h3');
  nextPageDescText.textContent = 'Page: ' + pageCount;
  nextPageDesc.appendChild(nextPageDescText);
  nextPageDescContainer.appendChild(nextPageDesc);
  gallery.appendChild(nextPageDescContainer);
  for (const figure of figures)
    gallery.appendChild(figure);
  try { window.updateEmbedded(); } catch {} //Embedded Image Viewer Integration
  try { window.updateFastFavoriter(); } catch {} //Fast Favoriter 2 Integration

  await scan();
}

async function getNextPageFiguresGallery() {
  const nextLink = await incrementUrlLastNumber(lastLink);
  console.log(nextLink);
  lastLink = nextLink;
  const nextPage = await getHTML(nextLink);
  const figures = nextPage.querySelectorAll('figure[class*="t"]');
  return figures;
}
async function getNextPageFiguresFavorites() {
  const nextLink = lastNextPageButton.href;
  console.log(nextLink);
  lastLink = nextLink;
  const nextPage = await getHTML(nextLink);
  let currNextPageButton = nextPage.querySelectorAll('a[class="button mobile-button right"][href]');
  lastNextPageButton = currNextPageButton[currNextPageButton.length - 1];
  const figures = nextPage.querySelectorAll('figure[class*="t"]');
  return figures;
}

async function incrementUrlLastNumber(url) {
  if (url.endsWith('/?'))
    url = url.slice(0, -1);
  if (url.endsWith('/'))
    url = url.slice(0, -1);

  var segments = url.split('/');
  var lastSegment = segments[segments.length - 1];

  var match = lastSegment.match(/^\d+/);

  if (match) {
    var nextNumber = parseInt(match[0]) + 1;
    return url.replace(/\d+$/, nextNumber);
  } else
    return url + '/2';
}


function isElementOnScreen(element) {
  var rect = element.getBoundingClientRect();
  var windowHeight = (window.innerHeight || document.documentElement.clientHeight) * 2;
  return (rect.top <= windowHeight) && ((rect.top + rect.height) >= 0);
}

async function getHTML(url) {
  try {
    const response = await fetch(url);
    const html = await response.text();
    const parser = new DOMParser();
    const doc = parser.parseFromString(html, 'text/html');
    return doc;
  } catch (error) {
    console.error(error);
  }
}

async function addExSettings() {
  const settings = document.querySelector('ul[class="navhideonmobile"]').querySelector('a[href="/controls/settings/"]').parentNode;

  if (document.getElementById("extension_settings")) {
    document.getElementById('midori_settings').addEventListener('click', function() { localStorage.setItem("igsettings", true.toString()); });
    return;
  }
  let exSettingsHeader = document.createElement("h3");
  exSettingsHeader.id = "extension_settings";
  exSettingsHeader.textContent = "Extension Settings";
  settings.appendChild(exSettingsHeader);

  let wfsettings = document.createElement("a");
  wfsettings.id = "midori_settings";
  wfsettings.textContent = "Midori's Script Settings";
  wfsettings.style.cursor = "pointer";
  wfsettings.onclick = function() {
    localStorage.setItem("igsettings", true.toString());
    window.location = "https://www.furaffinity.net/controls/settings";
  }
  settings.appendChild(wfsettings);
}

async function addExSettingsSidebar() {
  const settings = document.getElementById('controlpanelnav');

  if (document.getElementById("extension_settings_side")) {
    document.getElementById('midori_settings_side').addEventListener('click', function() { localStorage.setItem("igsettings", true.toString()); });
    return;
  }
  let exSettingsHeader = document.createElement("h3");
  exSettingsHeader.id = "extension_settings_side";
  exSettingsHeader.textContent = "Extension Settings";
  settings.appendChild(exSettingsHeader);

  let wfsettings = document.createElement("a");
  wfsettings.id = "midori_settings_side";
  wfsettings.textContent = "Midori's Script Settings";
  wfsettings.style.cursor = "pointer";
  wfsettings.onclick = function() {
    localStorage.setItem("igsettings", true.toString());
    window.location = "https://www.furaffinity.net/controls/settings";
  }
  settings.appendChild(wfsettings);
}

async function createSettings() {
  localStorage.setItem("igsettings", false.toString());
  const columnPage = document.getElementById("columnpage");
  let content = columnPage.querySelector('div[class="content"]');
  for (const section of content.querySelectorAll('section:not([class="exsettings"])'))
    section.parentNode.removeChild(section);

  let section = document.createElement("section");
  section.className = 'exsettings';
    let headerContainer = document.createElement("div");
    headerContainer.className = "section-header";
      let header = document.createElement("h2");
      header.textContent = "Infini Gallery Settings";
      headerContainer.appendChild(header);
    section.appendChild(headerContainer);
    let bodyContainer = document.createElement("div");
    bodyContainer.className = "section-body";
      let Item1 = document.createElement("div");
      Item1.className = "control-panel-item-container";
        let Item1Name = document.createElement("div");
        Item1Name.className = "control-panel-item-name";
          let Item1NameText = document.createElement("h4");
          Item1NameText.textContent = "Page Seperator";
          Item1Name.appendChild(Item1NameText);
        Item1.appendChild(Item1Name);
        let Item1Desc = document.createElement("div");
        Item1Desc.className = "control-panel-item-description";
          let Item1DescText = document.createTextNode('Sets wether a Page Seperator is shown foreach new Page loaded.');
          Item1Desc.appendChild(Item1DescText);
        Item1.appendChild(Item1Desc);
        let Item1Option = document.createElement("div");
        Item1Option.className = "control-panel-item-options";
          let Item1OptionContainer = document.createElement("div");
            let Item1OptionElem1 = document.createElement("input");
            Item1OptionElem1.id = 'igsettings_01';
            Item1OptionElem1.type = "checkbox";
            Item1OptionElem1.style.cursor = 'pointer';
            Item1OptionElem1.style.marginRight = '4px';
            Item1OptionElem1.addEventListener('change', function() {
              showPageSeperator = Item1OptionElem1.checked;
              localStorage.setItem("igsetting_01", showPageSeperator.toString());
            });
            Item1OptionContainer.appendChild(Item1OptionElem1);
            let Item1OptionElem2 = document.createTextNode('Show Page Seperators');
            Item1OptionContainer.appendChild(Item1OptionElem2);
          Item1Option.appendChild(Item1OptionContainer);
        Item1.appendChild(Item1Option);
      bodyContainer.appendChild(Item1);
        let Item2 = document.createElement("div");
        Item2.className = "control-panel-item-container";
        let Item2Name = document.createElement("div");
        Item2Name.className = "control-panel-item-name";
          let Item2NameText = document.createElement("h4");
          Item2NameText.textContent = "Disable Button";
          Item2Name.appendChild(Item2NameText);
        Item2.appendChild(Item2Name);
        let Item2Desc = document.createElement("div");
        Item2Desc.className = "control-panel-item-description";
          let Item2DescText = document.createTextNode("Sets wether the disable Infini Gallery button is shown in each Gallery");
          Item2Desc.appendChild(Item2DescText);
        Item2.appendChild(Item2Desc);
        let Item2Option = document.createElement("div");
        Item2Option.className = "control-panel-item-options";
          let Item2OptionContainer = document.createElement("div");
            let Item2OptionElem1 = document.createElement("input");
            Item2OptionElem1.id = 'igsettings_02';
            Item2OptionElem1.type = "checkbox";
            Item2OptionElem1.style.cursor = 'pointer';
            Item2OptionElem1.style.marginRight = '4px';
            Item2OptionElem1.addEventListener('change', function() {
              showDisableButton = Item2OptionElem1.checked;
              localStorage.setItem("igsetting_02", showDisableButton.toString());
            });
            Item2OptionContainer.appendChild(Item2OptionElem1);
            let Item2OptionElem2 = document.createTextNode('Show disable Infini Gallery button');
            Item2OptionContainer.appendChild(Item2OptionElem2);
          Item2Option.appendChild(Item2OptionContainer);
        Item2.appendChild(Item2Option);
      bodyContainer.appendChild(Item2);
    section.appendChild(bodyContainer);
  content.appendChild(section);

  fillSettings();
}

async function fillSettings() {
  let setting1 = document.getElementById('igsettings_01');
  setting1.checked = showPageSeperator;

  let setting2 = document.getElementById('igsettings_02');
  setting2.checked = showDisableButton;
}