Furaffinity Webcomic Autoloader 2.0

Gives you the option to load all the subsequent comic pages on a FurAffinity comic page automatically. Now with the option to show or hide Page Links.

目前为 2023-02-06 提交的版本。查看 最新版本

// ==UserScript==
// @name     			Furaffinity Webcomic Autoloader 2.0
// @version  			0.3.1
// @description  	Gives you the option to load all the subsequent comic pages on a FurAffinity comic page automatically. Now with the option to show or hide Page Links.
// @grant    			none
// @icon          https://www.furaffinity.net/themes/beta/img/banners/fa_logo.png?v2
// @author   			Midori Dragon
// @match    			*://*.furaffinity.net/view/*
// @namespace     Violentmonkey Scripts
// @license       MIT
// ==/UserScript==

// jshint esversion: 8

let rootHolder = document.getElementById("submissionImg");
let counter = 5;
let showLinks = false;
let startImg = window.location.href;
let pageCounter = 0;
let openedLinks = [document.location.toString()];

function insertAfter(newElement, referenceElement) {
  referenceElement.parentNode.insertBefore(newElement, referenceElement.nextSibling);
}
function insertBreakAfter(referenceElement) {
  let br = document.createElement("br");
  insertAfter(br, referenceElement);
}

function getNextLink(doc) {
  let comicDoc = doc.getElementsByClassName("parsed_nav_links")[0];
  if (comicDoc)
    comicDoc = comicDoc.childNodes;
  else {
    comicDoc = doc.getElementsByClassName("submission-description user-submitted-links")[0];
    if (comicDoc)
      comicDoc = comicDoc.childNodes;
    else
      return;
  }
  let link;
  comicDoc.forEach(function(elem) {
    if (elem.textContent.toLowerCase().includes("next")) {
      try {
        let currImgCalc = elem.href.substring(elem.href.lastIndexOf('/'), elem.href.length);
        let startImgCalc = startImg.substring(0, startImg.length-1);
        startImgCalc = startImgCalc.substring(startImgCalc.lastIndexOf('/'), startImgCalc.length);
        if (currImgCalc != startImgCalc && !openedLinks.includes(elem.href)) {
          link = elem.href;
          openedLinks.push(link);
          pageCounter++;
        }
      } catch {}
      return;
    }
  });
  return link;
}

function loadNextPage(nextLink) {

  if(nextLink) {
    let request = new XMLHttpRequest();
    request.open('GET', nextLink, true);

    request.onload = function() {
      if (this.status >= 200 && this.status < 400) {
        // Success!
        parser = new DOMParser();
        let nextPage = parser.parseFromString(this.response, "text/html");
        let nl = getNextLink(nextPage);
        let img = nextPage.getElementById("submissionImg");

        rootHolder.parentNode.insertBefore(img, rootHolder.nextSibling);
        rootHolder = rootHolder.nextSibling;

        insertBreakAfter(rootHolder);
        rootHolder = rootHolder.nextSibling;
        if (showLinks) {
          let lnk = document.createElement('a');
          let lnkURL = nextLink;
          lnk.innerHTML = lnkURL;
          lnk.href = lnkURL;
          insertAfter(lnk, rootHolder);
          rootHolder = rootHolder.nextSibling;
          insertBreakAfter(rootHolder);
          rootHolder = rootHolder.nextSibling;
        }
        else {
          let br = document.createElement('br');
          insertAfter(br, rootHolder);
          rootHolder = rootHolder.nextSibling;
        }
        loadNextPage(nl);
      } else {
        //We reached our target server, but it returned an error
        console.log("none");
      }
    };

    request.onerror = function() {
      //There was a connection error of some sort
      console.log("error");
    };

    request.send();
  }
}

function loadPages(links, i) {
if (i == links.length)
  return;
let nextLink = links[i];
  if(nextLink) {
    let request = new XMLHttpRequest();
    request.open('GET', nextLink, true);

    request.onload = function() {
      if (this.status >= 200 && this.status < 400) {
        // Success!
        parser = new DOMParser();
        let nextPage = parser.parseFromString(this.response, "text/html");
        let img = nextPage.getElementById("submissionImg");

        rootHolder.parentNode.insertBefore(img, rootHolder.nextSibling);
        rootHolder = rootHolder.nextSibling;

        insertBreakAfter(rootHolder);
        rootHolder = rootHolder.nextSibling;
        if (showLinks) {
          let lnk = document.createElement('a');
          let lnkURL = nextLink;
          lnk.innerHTML = lnkURL;
          lnk.href = lnkURL;
          insertAfter(lnk, rootHolder);
          rootHolder = rootHolder.nextSibling;
          insertBreakAfter(rootHolder);
          rootHolder = rootHolder.nextSibling;
        }
        else {
          let br = document.createElement('br');
          insertAfter(br, rootHolder);
          rootHolder = rootHolder.nextSibling;
        }
        i++;
        loadPages(links, i);
      } else {
        //We reached our target server, but it returned an error
        console.log("none");
      }
    };

    request.onerror = function() {
      //There was a connection error of some sort
      console.log("error");
    };

    request.send();
  }
}

function startAutoloader() {
  let ab = document.getElementById("autoloaderButton");
  ab.parentNode.removeChild(ab);
  let checkbox = document.getElementById("linksCheckbox");
  checkbox.parentNode.removeChild(checkbox);
  let label = document.getElementById("showLinksLabel");
  label.parentNode.removeChild(label);

  insertBreakAfter(rootHolder);
  rootHolder = rootHolder.nextSibling;

  loadNextPage(secondPage);
}

async function searchNextSimularPage() {
  let ab = document.getElementById("morePagesSearch");
  ab.value = "...";
  let checkbox = document.getElementById("linksCheckbox");
  checkbox.parentNode.removeChild(checkbox);
  let label = document.getElementById("showLinksLabel");
  label.parentNode.removeChild(label);

  insertBreakAfter(rootHolder);
  rootHolder = rootHolder.nextSibling;

  const submissionPage = document.getElementById("submission_page");
  const container = submissionPage.querySelector('div[class="submission-id-sub-container"]');
  //const currTitle = container.querySelector('div[class="submission-title"]').querySelector('p').textContent.replace(/[^a-zA-Z\s]/g, "");
  const currTitle = container.querySelector('div[class="submission-title"]').querySelector('p').textContent.replace(/[^a-zA-Z]/g, "");
  const author = container.querySelector('a');
  let galleryLink = author.href.substring(0, author.href.length - 1);

  let currentSubmissionId = window.location.toString().substring(0, window.location.toString().length - 1);
  currentSubmissionId = "sid-" + currentSubmissionId.substring(currentSubmissionId.lastIndexOf("/") + 1);

  galleryLink = galleryLink.substring(galleryLink.lastIndexOf("/") + 1);
  galleryLink = "https://www.furaffinity.net/gallery/" + galleryLink;

  let figures = [];
  let currentFigureIndex = -1;

  let j = 0;
  while (currentFigureIndex == -1) {
    j++;
    gallery = await getHTML(galleryLink + "/" + j);
    let figuresNew = gallery.getElementsByTagName("figure");
    if (!figuresNew || figuresNew.length == 0)
      return false;
    figuresNew = Array.from(figuresNew);
    figures = figures.concat(figuresNew);
    currentFigureIndex = figuresNew.findIndex(figure => figure.id == currentSubmissionId);
    //console.log("j: " + j + "  |  index: " + currentFigureIndex);
  }
  currentFigureIndex = figures.findIndex(figure => figure.id == currentSubmissionId);
  //console.log("total index: " + currentFigureIndex);

  if (currentFigureIndex == 0)
    return false;

  figures = figures.slice(0, currentFigureIndex);

  let pages = [];
  for (let i = figures.length - 1; i >= 0; i--) {
    const titleElem = figures[i].querySelector('figcaption').querySelector('a');
    //const title = titleElem.getAttribute("title").replace(/[^a-zA-Z\s]/g, "");
    const title = titleElem.getAttribute("title").replace(/[^a-zA-Z]/g, "");
    //const words = title.split(" ");
    //console.log('"' + title + '" == "' + currTitle + '"');
    if (title.includes(currTitle))
      pages.push(titleElem.href);
  }
  loadPages(pages, 0);

  ab.parentNode.removeChild(ab);
  return true;
}

function setShowLinks() {
  if (showLinks)
    showLinks = false;
  else
    showLinks = true;
  let checkbox = document.getElementById("linksCheckbox");
  checkbox.checked = showLinks;
}

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

let secondPage = getNextLink(document);
if(secondPage) {
  let img = document.getElementById("submissionImg");
  insertBreakAfter(rootHolder);
  rootHolder = rootHolder.nextSibling;

  pageCounter++;

  let label = document.createElement('a');
  label.id = "showLinksLabel";
  label.innerHTML = "Show Links";
  label.style.cursor = "pointer";
  label.style.marginBottom = "30px";
  label.style.marginLeft = "5px";
  label.onclick = setShowLinks;
  insertAfter(label, rootHolder);

  let checkbox = document.createElement('input');
  checkbox.value = "Show Links";
  checkbox.type = "checkbox";
  checkbox.id = "linksCheckbox";
  checkbox.className = "checkbox standard mobile-fix";
  checkbox.style.cursor = "pointer";
  checkbox.style.marginBottom = "30px";
  checkbox.style.marginLeft = "20px";
  checkbox.onclick = setShowLinks;
  insertAfter(checkbox, rootHolder);

  let button = document.createElement('input');
  button.value = "Enable Comic Autoloader";
  button.type = "button";
  button.id = "autoloaderButton";
  button.className = "button standard mobile-fix";
  button.style.marginTop = "10px";
  button.style.marginBottom = "20px";
  button.onclick = startAutoloader;
  insertAfter(button, rootHolder);
} else {
  let img = document.getElementById("submissionImg");
  insertBreakAfter(rootHolder);
  rootHolder = rootHolder.nextSibling;

  let label = document.createElement('a');
  label.id = "showLinksLabel";
  label.innerHTML = "Show Links";
  label.style.cursor = "pointer";
  label.style.marginBottom = "30px";
  label.style.marginLeft = "5px";
  label.onclick = setShowLinks;
  insertAfter(label, rootHolder);

  let checkbox = document.createElement('input');
  checkbox.value = "Show Links";
  checkbox.type = "checkbox";
  checkbox.id = "linksCheckbox";
  checkbox.className = "checkbox standard mobile-fix";
  checkbox.style.cursor = "pointer";
  checkbox.style.marginBottom = "30px";
  checkbox.style.marginLeft = "20px";
  checkbox.onclick = setShowLinks;
  insertAfter(checkbox, rootHolder);

  let button = document.createElement('input');
  button.value = "Search for more Pages in Series";
  button.type = "button";
  button.id = "morePagesSearch";
  button.className = "button standard mobile-fix";
  button.style.marginTop = "10px";
  button.style.marginBottom = "20px";
  button.onclick = searchNextSimularPage;
  insertAfter(button, rootHolder);
}

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址