Skip to content

Instantly share code, notes, and snippets.

@sp00n
Last active June 19, 2024 23:11
Show Gist options
  • Save sp00n/e8b91d2f47c471bc0627f7b31d659291 to your computer and use it in GitHub Desktop.
Save sp00n/e8b91d2f47c471bc0627f7b31d659291 to your computer and use it in GitHub Desktop.
Restored Pagination for Google (Disable Continuous / Infinite Scrolling)
// ==UserScript==
// @name Restored Pagination for Google
// @namespace google-pagination.sp00n.net
// @match *://*/search*
// @grant none
// @version 0.2
// @author sp00n
// @description This script restores the paged navigation for the Google Search. It also requires that the "Continuous scrolling" in the Google Search settings is turned off (which infuriatingly does not restore the old Pagination!)
// @downloadURL https://gist.github.com/sp00n/e8b91d2f47c471bc0627f7b31d659291
// ==/UserScript==
// Limit the script execution to only Google pages
// @match only allows wildcards for the TLD in ViolentMonkey, not in TamperMonkey or other alternatives
// @includeGlobs also doesn't work in all addons
// These are all the TLDs that Google runs on
// Taken from https://www.google.com/supported_domains
const supportedTLDs = [
"com", "ad", "ae", "com.af", "com.ag", "al", "am", "co.ao", "com.ar", "as", "at", "com.au", "az", "ba", "com.bd", "be", "bf", "bg", "com.bh", "bi", "bj",
"com.bn", "com.bo", "com.br", "bs", "bt", "co.bw", "by", "com.bz", "ca", "cd", "cf", "cg", "ch", "ci", "co.ck", "cl", "cm", "cn", "com.co", "co.cr",
"com.cu", "cv", "com.cy", "cz", "de", "dj", "dk", "dm", "com.do", "dz", "com.ec", "ee", "com.eg", "es", "com.et", "fi", "com.fj", "fm", "fr", "ga", "ge",
"gg", "com.gh", "com.gi", "gl", "gm", "gr", "com.gt", "gy", "com.hk", "hn", "hr", "ht", "hu", "co.id", "ie", "co.il", "im", "co.in", "iq", "is", "it",
"je", "com.jm", "jo", "co.jp", "co.ke", "com.kh", "ki", "kg", "co.kr", "com.kw", "kz", "la", "com.lb", "li", "lk", "co.ls", "lt", "lu", "lv", "com.ly",
"co.ma", "md", "me", "mg", "mk", "ml", "com.mm", "mn", "com.mt", "mu", "mv", "mw", "com.mx", "com.my", "co.mz", "com.na", "com.ng", "com.ni", "ne", "nl",
"no", "com.np", "nr", "nu", "co.nz", "com.om", "com.pa", "com.pe", "com.pg", "com.ph", "com.pk", "pl", "pn", "com.pr", "ps", "pt", "com.py", "com.qa", "ro",
"ru", "rw", "com.sa", "com.sb", "sc", "se", "com.sg", "sh", "si", "sk", "com.sl", "sn", "so", "sm", "sr", "st", "com.sv", "td", "tg", "co.th", "com.tj",
"tl", "tm", "tn", "to", "com.tr", "tt", "com.tw", "co.tz", "com.ua", "co.ug", "co.uk", "com.uy", "co.uz", "com.vc", "co.ve", "co.vi", "com.vn", "vu", "ws",
"rs", "co.za", "co.zm", "co.zw", "cat"
];
const tldString = supportedTLDs.join("|").replaceAll(".", String.raw`\.`); // Uses String.raw to be able to insert a backslash before the dot. Is there an easier way?
const googleRegEx = new RegExp(`^http(s)?://(www\.)?google\.(${tldString})/search\?.*`, "i");
// No Google, no continue!
if ( !googleRegEx.test(location.href) ) {
return;
}
// Google uses a bunch of parameters, but we only need a couple
// https://www.google.com/search?hl=<LANG>&q=<QUERY>&tbm=isch&sa=X&ved=<UNIQUE_ID>&biw=<WIDTH>&bih=<HEIGHT>&dpr=<DPI_SCALING_INT_OR_DECIMAL>
// Date Filters
// Last Hour https://www.google.com/search?q=abc&tbs=qdr:h
// Last Month https://www.google.com/search?q=abc&tbs=qdr:m
// Last Year https://www.google.com/search?q=abc&tbs=qdr:y
// https://www.google.com/search?q=abc&tbs=cdr%3A1%2Ccd_min%3A01.01.2020%2Ccd_max%3A02.02.2022&tbm=
// Language
// German https://www.google.com/search?q=abc&tbs=lr:lang_1de&lr=lang_de
// Image Search
// https://www.google.com/search?q=abc&tbm=isch
let params = new URL(document.location).searchParams;
let searchQuery = params.get("q");
let currentStartEntries = parseInt(params.get("start")) || 0;
let previousStartEntries = Math.max(0, currentStartEntries - 10);
let nextStartEntries = currentStartEntries + 10; // Can we get the maximum amount of search results?
let currentPage = Math.floor(currentStartEntries / 10) + 1; // Page 1 has start=0, Page 2 start=10, etc
let firstPageToDisplay = 1;
let lastPageToDisplay = 10;
// Very weak detection for the dark mode, but here we go
let isDarkMode = (getComputedStyle(document.body).backgroundColor != "rgb(255, 255, 255)");
// Abort if we're on the image search
if ( params.has("tbm") && params.get("tbm") == "isch" ) {
return;
}
// Build the fixed query string
let fixedQueryParams = new URLSearchParams();
fixedQueryParams.set("q", searchQuery);
if ( params.has("filter") ) {
fixedQueryParams.set("filter", params.get("filter"));
}
if ( params.has("tbs") ) {
fixedQueryParams.set("tbs", params.get("tbs"));
}
if ( params.has("lr") ) {
fixedQueryParams.set("lr", params.get("lr"));
}
let fixedQueryString = fixedQueryParams.toString();
// Determine which pages to display
// Page 1-6: display 1-10
// Page 7: 2-11
// Page 8: 3-12
// etc
// 5 to the left visible, 4 to the right
if ( currentPage >= 7 ) {
firstPageToDisplay = currentPage - 5;
lastPageToDisplay = currentPage + 4;
}
// The entries HTML string
let entriesHTMLString = "";
let entryBgPosTop = ( isDarkMode ) ? -112 : 0;
// Generate the entries
for ( let entryPage = firstPageToDisplay; entryPage <= lastPageToDisplay; entryPage++ ) {
let entryStartEntries = (entryPage - 1) * 10;
let entryBgPosLeft = ( entryPage == 1 ) ? -53 : -74;
let entryTemplate = "";
// The template for an entry in the navigation
if ( entryPage == currentPage ) {
entryTemplate = `
<td class="YyVfkd">
<span class="SJajHc" style="background:url(/images/nav_logo321_hr.webp) no-repeat;background-position:${entryBgPosLeft}px ${entryBgPosTop}px;background-size:167px;width:20px"></span>
${entryPage}
</td>
`;
}
else {
entryTemplate = `
<td>
<a aria-label="Page ${entryPage}" class="fl" href="/search?${fixedQueryString}&amp;start=${entryStartEntries}">
<span class="SJajHc NVbCr" style="background:url(/images/nav_logo321_hr.webp) no-repeat;background-position:${entryBgPosLeft}px ${entryBgPosTop}px;background-size:167px;width:20px"></span>
${entryPage}
</a>
</td>
`;
}
entriesHTMLString += entryTemplate;
}
// The navigation table
let navigationHTMLString = `
<table class="AaVjTc" style="border-collapse:collapse;text-align:left" role="presentation" id="restored-pagination">
<tbody>
<tr jsname="TeSSVd" valign="top">
<td aria-level="3" class="d6cvqb BBwThe" role="heading">
<a href="/search?${fixedQueryString}&amp;start=${previousStartEntries}" id="pnprev">
<span class="SJajHc NVbCr" style="background:url(/images/nav_logo321_hr.webp) no-repeat;background-position:0 ${entryBgPosTop}px;background-size:167px;width:53px;float:right"></span>
<span style="display:block;margin-right:35px;clear:right">Previous</span>
</a>
</td>
`
+ entriesHTMLString +
`
<td aria-level="3" class="d6cvqb BBwThe" role="heading">
<a href="/search?${fixedQueryString}&amp;start=${nextStartEntries}" id="pnnext" style="text-align:left">
<span class="SJajHc NVbCr" style="background:url(/images/nav_logo321_hr.webp) no-repeat;background-position:-96px ${entryBgPosTop}px;background-size:167px;width:71px"></span>
<span style="display:block;margin-left:53px">Next</span>
</a>
</td>
</tr>
</tbody>
</table>
`;
// Insert the table
// Get the old navigation container at the bottom, which is currently empty, but this may change or be removed in the future
const navigationContainer = [...document.querySelectorAll("div[role='navigation']:not([class])")].pop();
navigationContainer.innerHTML = navigationHTMLString;
// And some additional styles
let styles = `
<style type="text/css">
#restored-pagination.AaVjTc {
margin: 30px auto 30px;
}
#restored-pagination.AaVjTc td {
padding: 0;
text-align: center;
}
#restored-pagination.AaVjTc a:link {
color: ${isDarkMode ? "#8ab4f8" : "#4285f4"};
font-weight: normal;
}
#restored-pagination .SJajHc {
background: url(/images/nav_logo321_hr.webp) no-repeat;
background-size: 167px;
overflow: hidden;
background-position: 0 0;
height: 40px;
display: block;
}
#restored-pagination .NVbCr {
cursor: pointer;
}
#restored-pagination .YyVfkd {
color: ${isDarkMode ? "#bdc1c6" : "#202124"};
font-weight: normal;
}
</style>
`;
navigationContainer.innerHTML += styles;
@new-chris
Copy link

This script works fine in 2024-4-6.
Thank you Sir.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment