Greasy Fork

Greasy Fork is available in English.

Google Scholar to Sci-Hub

Adds Sci-Hub, LibGen, and LibSTC buttons to Google Scholar results

当前为 2025-02-03 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

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