Makes so that the gallery continues loading the next page when you reach its bottom
当前为
// ==UserScript==
// @name Infini-Gallery
// @namespace Violentmonkey Scripts
// @match *://*.furaffinity.net/*
// @grant none
// @version 1.7.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_1"));
if (showPageSeperator == null || showPageSeperator == undefined)
showPageSeperator = true;
let showDisableButton = JSON.parse(localStorage.getItem("igsetting_2"));
if (showDisableButton == null || showDisableButton == undefined)
showDisableButton = true;
const matchList = ['net/browse', 'net/gallery', 'net/search', 'net/favorites', 'net/scraps', 'net/msg/pms' ];
let settingsCount = 0;
const isClassicTheme = document.head.querySelector('script[type="text/javascript"][src*="themes/classic"]') != null;
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;
let color = "color: blue";
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches)
color = "color: aqua";
console.info(`%cRunning: ${GM_info.script.name} v${GM_info.script.version} (Settings: "PageSeperator = ${showPageSeperator}", "DisableButton = ${showDisableButton}")`, color);
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 isScraps = window.location.toString().includes('net/scraps');
const isNotes = window.location.toString().includes('net/msg/pms');
let allowScan = true;
let nextButtons;
let lastNextButton;
let gallery;
let lastLink;
let lastNextPageButton;
let pageCount;
if (!isSettings) {
if (isClassicTheme) {
if (isGallery)
nextButtons = document.querySelectorAll('a[class*="button-link"][href]');
else if (isFavorites)
nextButtons = document.querySelectorAll('a[class*="button-link"][href]');
else if (isBrowse)
nextButtons = document.querySelectorAll('button[class*="button"][type="submit"]');
else if (isScraps)
nextButtons = document.querySelectorAll('a[class*="button-link"][href]');
else if (isNotes)
nextButtons = document.querySelectorAll('a[class*="button-link"][href]');
} else {
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]');
else if (isScraps)
nextButtons = document.querySelectorAll('form[action][method="get"]');
}
if (!nextButtons || nextButtons.length == 0)
return;
if (showDisableButton) {
let navPage;
if (isClassicTheme)
navPage = document.querySelector('input[type="button"][class="button toggle_titles"]').parentNode; //document.querySelector('div[class="page-options"]');
else
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";
if (isClassicTheme)
disableIGButton.style.marginLeft = "8px";
else
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 (isClassicTheme) {
if (isGallery)
figures = await getNextPageFiguresGallery();
else if (isFavorites)
figures = await getNextPageFiguresGallery();
else if (isBrowse)
figures = await getNextPageFiguresGallery();
else if (isScraps)
figures = await getNextPageFiguresGallery();
else if (isNotes)
figures = await getNextPageFiguresGallery();
} else {
if (isGallery)
figures = await getNextPageFiguresGallery();
else if (isFavorites)
figures = await getNextPageFiguresFavorites();
else if (isBrowse)
figures = await getNextPageFiguresGallery();
else if (isScraps)
figures = await getNextPageFiguresGallery();
}
if (!figures || figures.length == 0) {
lastNextButton.parentNode.removeChild(lastNextButton);
return;
}
pageCount++;
if (!isNotes) {
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;
if (isClassicTheme) {
nextPageDescText.style.color = "#c4e9ff";
nextPageDescText.style.fontSize = "18px";
nextPageDescText.style.lineHeight = "22px";
nextPageDescText.style.fontWeight = "600";
nextPageDescText.style.paddingTop = "3px";
nextPageDescText.style.paddingBottom = "2px";
nextPageDescText.style.paddingRight = "0";
nextPageDescText.style.paddingLeft = "0";
nextPageDescText.style.margin = "0";
}
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
} else {
let table = document.getElementById("notes-list");
let tbody = table.querySelector(tbody);
for (const figure of figures)
tbody.appendChild(figure);
}
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 getNextPageFiguresNotes() {
const nextLink = await incrementUrlLastNumber(lastLink);
console.log(nextLink);
lastLink = nextLink;
const nextPage = await getHTML(nextLink);
const notes = nextPage.querySelectorAll('tr[class*="note"]');
return notes;
}
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);
}
}
// ------------------------------ //
// ---------- SETTINGS ---------- //
// ------------------------------ //
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");
const content = columnPage.querySelector('div[class="content"]');
for (const section of content.querySelectorAll('section:not([class="exsettings"])'))
section.parentNode.removeChild(section);
const section = document.createElement("section");
section.className = 'exsettings';
const headerContainer = document.createElement("div");
headerContainer.className = "section-header";
const header = document.createElement("h2");
header.textContent = "Infini Gallery Settings";
headerContainer.appendChild(header);
section.appendChild(headerContainer);
const bodyContainer = document.createElement("div");
bodyContainer.className = "section-body";
// Page Seperator Setting
const pageSeperatorSetting = createSetting("Page Seperator", "Sets wether a Page Seperator is shown foreach new Page loaded", "boolean", "Show Page Seperators", (target) => {
showPageSeperator = target.checked;
localStorage.setItem(target.id, showPageSeperator.toString());
});
pageSeperatorSetting.querySelector('[id*="setting"]').checked = showPageSeperator;
bodyContainer.appendChild(pageSeperatorSetting);
// Disable Button Setting
const disableButtonSetting = createSetting("Disable Button", "Sets wether the disable Infini Gallery button is shown in each Gallery", "boolean", "Show disable Infini Gallery button", (target) => {
showDisableButton = target.checked;
localStorage.setItem(target.id, showDisableButton.toString());
});
disableButtonSetting.querySelector('[id*="setting"]').checked = showDisableButton;
bodyContainer.appendChild(disableButtonSetting);
section.appendChild(bodyContainer);
content.appendChild(section);
}
function createSetting(name, description, type, typeDescription, executeFunction) {
const settingContainer = document.createElement("div");
settingContainer.className = "control-panel-item-container";
const settingName = document.createElement("div");
settingName.className = "control-panel-item-name";
const settingNameText = document.createElement("h4");
settingNameText.textContent = name;
settingName.appendChild(settingNameText);
settingContainer.appendChild(settingName);
const settingDesc = document.createElement("div");
settingDesc.className = "control-panel-item-description";
const settingDescText = document.createTextNode(description);
settingDesc.appendChild(settingDescText);
settingContainer.appendChild(settingDesc);
const settingOption = document.createElement("div");
settingOption.className = "control-panel-item-options";
if (type === "number") {
settingsCount++;
const settingInput = document.createElement("input");
settingInput.id = "igsetting_" + settingsCount;
settingInput.type = "text";
settingInput.className = "textbox";
settingInput.addEventListener("keydown", (event) => {
const currentValue = parseInt(settingInput.value) || 0;
if (event.key === "ArrowUp") {
settingInput.value = (currentValue + 1).toString();
executeFunction(settingInput);
} else if (event.key === "ArrowDown") {
if (currentValue != 0)
settingInput.value = (currentValue - 1).toString();
executeFunction(settingInput);
}
});
settingInput.addEventListener("input", () => {
settingInput.value = settingInput.value.replace(/[^0-9]/g, "");
if (settingInput.value < 0)
settingInput.value = 0;
});
settingInput.addEventListener("input", () => executeFunction(settingInput));
settingOption.appendChild(settingInput);
} else if (type === "boolean") {
settingsCount++;
const settingCheckbox = document.createElement("input");
settingCheckbox.id = "wfsetting_" + settingsCount;
settingCheckbox.type = "checkbox";
settingCheckbox.style.cursor = "pointer";
settingCheckbox.style.marginRight = "4px";
settingCheckbox.addEventListener("change", () => executeFunction(settingCheckbox));
settingOption.appendChild(settingCheckbox);
const settingOptionLabel = document.createElement("label");
settingOptionLabel.textContent = typeDescription;
settingOptionLabel.style.cursor = "pointer";
settingOptionLabel.addEventListener("click", () => {
settingCheckbox.checked = !settingCheckbox.checked;
executeFunction(settingCheckbox);
});
settingOption.appendChild(settingOptionLabel);
} else if (type === "action") {
settingsCount++;
const settingButton = document.createElement("button");
settingButton.id = "wfsetting_" + settingsCount;
settingButton.type = "button";
settingButton.className = "button standard mobile-fix";
settingButton.textContent = typeDescription;
settingButton.addEventListener("click", () => executeFunction(settingButton));
settingOption.appendChild(settingButton);
}
settingContainer.appendChild(settingOption);
return settingContainer;
}