NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Endless Google
// @description Load more results automatically and endlessly.
// @author tumpio
// @namespace tumpio@sci.fi
// @homepageURL https://openuserjs.org/scripts/tumpio/Endless_Google
// @supportURL https://github.com/tumpio/gmscripts/issues
// @icon https://github.com/tumpio/gmscripts/raw/master/Endless_Google/large.png
// @include http://www.google.*
// @include https://www.google.*
// @include https://encrypted.google.*
// @run-at document-start
// @version 0.0.8
// @license MIT
// @noframes
// ==/UserScript==
if (location.href.indexOf("tbm=isch") !== -1) // NOTE: Don't run on image search
return;
if (window.top !== window.self) // NOTE: Do not run on iframes
return;
const centerElement = "#center_col";
const loadWindowSize = 1.6;
const filtersAll = ["#foot", "#bottomads"];
const filtersCol = filtersAll.concat(["#extrares", "#imagebox_bigimages"]);
let msg = "";
const css = `
.page-number {
position: relative;
display: flex;
flex-direction: row-reverse;
align-items: center;
margin-bottom: 2em;
color: #808080;
}
.page-number::before {
content: "";
background-color: #ededed;
height: 1px;
width: 100%;
margin: 1em 3em;
}
.endless-msg {
position:fixed;
bottom:0;
left:0;
padding:5px 10px;
background: darkred;
color: white;
font-size: 11px;
display: none;
}
.endless-msg.shown {
display:block;
}
`;
let pageNumber = 1;
let prevScrollY = 0;
let nextPageLoading = false;
function requestNextPage() {
nextPageLoading = true;
let nextPage = new URL(location.href);
if (!nextPage.searchParams.has("q")) return;
nextPage.searchParams.set("start", String(pageNumber * 10));
!msg.classList.contains("shown") && msg.classList.add("shown");
fetch(nextPage.href)
.then(response => response.text())
.then(text => {
let parser = new DOMParser();
let htmlDocument = parser.parseFromString(text, "text/html");
let docElement = htmlDocument.documentElement;
let content = docElement.querySelector(centerElement);
content.id = "col_" + pageNumber;
filter(content, filtersCol);
content.style.marginLeft = '0';
let pageMarker = document.createElement("div");
pageMarker.textContent = String(pageNumber + 1);
pageMarker.className = "page-number";
let col = document.createElement("div");
col.className = "next-col";
col.appendChild(pageMarker);
// Set images source address
try {
let thumbnails = text.match(/google\.ldi=({.+?})/);
let thumbnailsObj = JSON.parse(thumbnails && thumbnails[1]);
for (let id in thumbnailsObj) {
docElement.querySelector("#"+id).src = unescapeHex(thumbnailsObj[id]);
}
} catch(e) {}
function setImagesSrc({id}) {
let pattern = new RegExp("var\\ss='(\\S+)';var\\sii=\\[[a-z0-9_',]*?'"+id+"'[a-z0-9_',]*?\\];");
let imageSource = text.match(pattern);
if (imageSource != null && imageSource[1]) {
docElement.querySelector("#"+id).src = unescapeHex(imageSource[1]);
}
}
docElement.querySelectorAll('g-img > img[id]').forEach(setImagesSrc);
docElement.querySelectorAll('div > img[id^=dimg_]').forEach(setImagesSrc);
docElement.querySelectorAll('img[data-src]').forEach((img) => {
img.src = img.dataset.src;
img.style.visibility = 'visible';
});
col.appendChild(content);
document.querySelector(centerElement).appendChild(col);
if (!content.querySelector("#rso")) {
// end of results
window.removeEventListener("scroll", onScrollDocumentEnd);
nextPageLoading = false;
msg.classList.contains("shown") && msg.classList.remove("shown");
return;
}
pageNumber++;
nextPageLoading = false;
msg.classList.contains("shown") && msg.classList.remove("shown");
});
}
function unescapeHex(hex) {
if (typeof hex != "string") { return ""; }
return hex.replace(/\\x([0-9a-f]{2})/ig, function(_, chunk) {
return String.fromCharCode(parseInt(chunk, 16));
});
}
function onScrollDocumentEnd() {
let y = window.scrollY;
let delta = y - prevScrollY;
if (!nextPageLoading && delta > 0 && isDocumentEnd(y)) {
requestNextPage();
}
prevScrollY = y;
}
function isDocumentEnd(y) {
return y + window.innerHeight * loadWindowSize >= document.body.clientHeight;
}
function filter(node, filters) {
for (let filter of filters) {
let child = node.querySelector(filter);
if (child) {
child.parentNode.removeChild(child);
}
}
}
function init() {
prevScrollY = window.scrollY;
window.addEventListener("scroll", onScrollDocumentEnd);
filter(document, filtersAll);
let style = document.createElement("style");
style.type = "text/css";
style.appendChild(document.createTextNode(css));
document.head.appendChild(style);
msg = document.createElement("div");
msg.setAttribute("class", "endless-msg");
msg.innerText = "Loading next page...";
document.body.appendChild(msg);
}
document.addEventListener("DOMContentLoaded", init);