Greasy Fork is available in English.
Adds Sci-Hub, LibGen, and LibSTC buttons to Google Scholar results
当前为
// ==UserScript==
// @name Google Scholar to Sci-Hub
// @namespace ScholarToSciHub
// @version 1.3
// @description Adds Sci-Hub, LibGen, and LibSTC buttons to Google Scholar results
// @author Bui Quoc Dung (modified)
// @include https://scholar.google.*/*
// @license AGPL-3.0-or-later
// @grant GM_xmlhttpRequest
// ==/UserScript==
const SCIHUB_URL = 'https://www.tesble.com/';
const LIBGEN_URL = 'https://libgen.li/index.php?req=';
const LIBSTC_BASE_URL = 'https://hub.libstc.cc/';
// Regular expression for matching DOI
const DOI_REGEX = /\b(10\.\d{4,}(?:\.\d+)*\/(?:(?!["&'<>])\S)+)\b/gi;
function extractYear(element) {
const yearMatch = element.textContent.match(/\d{4}/);
return yearMatch ? parseInt(yearMatch[0]) : 0;
}
function checkPDFExistence(url, callback) {
GM_xmlhttpRequest({
method: 'HEAD',
url: url,
onload: function(response) {
const isPDF = response.status === 200 &&
response.responseHeaders.toLowerCase().includes('application/pdf');
callback(isPDF);
},
onerror: function() {
callback(false);
}
});
}
function checkLibGenPDF(title, buttonContainer) {
GM_xmlhttpRequest({
method: 'GET',
url: LIBGEN_URL + encodeURIComponent(title),
onload: function(response) {
// Parse the response text into a DOM object
const parser = new DOMParser();
const doc = parser.parseFromString(response.responseText, 'text/html');
// Check if there is any element with the class 'table table-striped'
const hasTable = doc.querySelector('.table.table-striped') !== null;
const libGenLink = document.createElement('a');
libGenLink.textContent = hasTable ? '[PDF] LibGen' : '[NoPDF] LibGen';
libGenLink.href = LIBGEN_URL + encodeURIComponent(title);
libGenLink.target = '_blank';
buttonContainer.appendChild(libGenLink);
},
onerror: function(error) {
console.error('Error checking LibGen:', error);
const libGenLink = document.createElement('a');
libGenLink.textContent = '[NoPDF] LibGen';
libGenLink.href = LIBGEN_URL + encodeURIComponent(title);
libGenLink.target = '_blank';
buttonContainer.appendChild(libGenLink);
}
});
}
function checkSciHubPDF(url, buttonContainer, callback) {
GM_xmlhttpRequest({
method: 'GET',
url: SCIHUB_URL + url,
onload: function(response) {
// Check if response contains PDF embed or download link
const hasPDF = response.responseText.includes('iframe') ||
response.responseText.includes('pdf') ||
response.responseText.includes('embed');
const sciHubLink = document.createElement('a');
sciHubLink.textContent = hasPDF ? '[PDF] Sci-Hub' : '[NoPDF] Sci-Hub';
sciHubLink.href = SCIHUB_URL + url;
sciHubLink.target = '_blank';
buttonContainer.appendChild(sciHubLink);
if (callback) callback(hasPDF);
},
onerror: function(error) {
console.error('Error checking Sci-Hub:', error);
const sciHubLink = document.createElement('a');
sciHubLink.textContent = '[NoPDF] Sci-Hub';
sciHubLink.href = SCIHUB_URL + url;
sciHubLink.target = '_blank';
buttonContainer.appendChild(sciHubLink);
if (callback) callback(false);
}
});
}
function fetchDOIAndAddButtonLibSTC(titleLink, buttonContainer) {
GM_xmlhttpRequest({
method: 'GET',
url: titleLink.href,
onload: function(response) {
const matches = response.responseText.match(DOI_REGEX);
if (matches && matches.length > 0) {
const firstDOI = matches[0];
const pdfURL = LIBSTC_BASE_URL + firstDOI + '.pdf';
const libstcLink = document.createElement('a');
libstcLink.href = pdfURL;
libstcLink.target = '_blank';
checkPDFExistence(pdfURL, function(exists) {
libstcLink.textContent = exists ? '[PDF] LibSTC' : '[NoPDF] LibSTC';
buttonContainer.appendChild(libstcLink);
});
}
},
onerror: function(error) {
console.error('Error fetching DOI:', error);
}
});
}
function addButtons() {
const results = document.querySelectorAll('#gs_res_ccl_mid .gs_r.gs_or.gs_scl');
results.forEach(result => {
const titleLink = result.querySelector('.gs_rt a');
const yearElement = result.querySelector('.gs_a');
if (!titleLink || !yearElement) return;
const year = extractYear(yearElement);
let buttonContainer = result.querySelector('.gs_or_ggsm');
if (!buttonContainer) {
const div = document.createElement('div');
div.className = 'gs_ggs gs_fl';
div.innerHTML = '<div class="gs_ggsd"><div class="gs_or_ggsm"></div></div>';
result.insertBefore(div, result.firstChild);
buttonContainer = div.querySelector('.gs_or_ggsm');
// Add Sci-Hub button with AJAX check
checkSciHubPDF(titleLink.href, buttonContainer);
// Add LibGen button with AJAX check
checkLibGenPDF(titleLink.textContent, buttonContainer);
// Add LibSTC button only for papers after 2020
if (year > 2020) {
fetchDOIAndAddButtonLibSTC(titleLink, buttonContainer);
}
}
});
}
// Initial setup
addButtons();
// Watch for dynamic content changes
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.addedNodes.length) {
addButtons();
}
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});