Infini-Gallery

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

目前為 2023-04-06 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        Infini-Gallery
// @namespace   Violentmonkey Scripts
// @match       *://*.furaffinity.net/*
// @grant       none
// @version     1.3
// @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 matchList = ['net/browse', 'net/gallery', 'net/search', 'net/favorites' ];

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();
}

if (window.parent !== window)
  return;
if (!matchList.some(x => window.location.toString().includes(x)))
  return;

console.info('%cRunning: Infini-Gallery', 'color: blue');


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

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;
}