Facebook 相册一键下载

Bulk download Facebook album photos in full resolution with background support and auto-refresh prevention.

// ==UserScript==
// @name         Facebook 相册一键下载
// @namespace    麦克
// @version      2.1.6
// @description  Bulk download Facebook album photos in full resolution with background support and auto-refresh prevention.
// @author       麦克
// @match        https://www.facebook.com/*/photos/*
// @match        https://www.facebook.com/photo.php?*
// @match        https://www.facebook.com/photo?*
// @match        https://www.facebook.com/photo/*
// @grant        GM_download
// @grant        GM_notification
// @license      GPL-3.0-or-later
// ==/UserScript==

let iter = 0;
let MAXITER = 10000;
let stopDownload = false;

// 防止页面自动刷新
window.addEventListener('beforeunload', function (e) {
    e.preventDefault();
    e.returnValue = '';
});

// 创建 Fetch 按钮
(function () {
    const observer = new MutationObserver(() => {
        if (document.body && !document.querySelector('#fetch-button')) {
            let fetchBtn = document.createElement("div");
            fetchBtn.id = "fetch-button";
            fetchBtn.textContent = "⇩ Fetch Photos";
            fetchBtn.style.cssText = 'position:fixed;top:10px;right:10px;z-index:9999;padding:8px;background-color:#4caf50;color:white;border-radius:5px;cursor:pointer;';
            fetchBtn.onclick = startBatchDownload;
            document.body.appendChild(fetchBtn);
        }
    });
    observer.observe(document.body, { childList: true, subtree: true });
})();

// 获取当前图片 URL
function getImageUrl() {
    const imgElement = document.querySelector('img[src*="scontent"]');
    return imgElement ? imgElement.src : null;
}

// 点击“下一张”按钮
function clickNextImage() {
    const nextBtn = document.querySelector('div[aria-label="下一张"], div[aria-label="Next"]');
    if (nextBtn) {
        nextBtn.click();
        return true;
    } else {
        const complexNextBtn = document.querySelector('div[role="button"][tabindex="0"] div[style*="background-image"]');
        if (complexNextBtn) {
            complexNextBtn.click();
            return true;
        }
    }
    return false;
}

// 下载图片的异步函数
async function downloadImage(imgUrl) {
    return new Promise((resolve) => {
        if (imgUrl) {
            const filename = imgUrl.split('?')[0].split('/').pop();
            console.log(`Downloading: ${filename}`);
            GM_download({
                url: imgUrl,
                name: filename,
                saveAs: false,
                onload: () => resolve(true),
                onerror: () => resolve(false),
            });
        } else {
            console.error('Failed to fetch image URL.');
            resolve(false);
        }
    });
}

// 批量下载的递归函数
async function batchDownload() {
    if (iter >= MAXITER || stopDownload) {
        console.log('Download process completed or stopped.');
        GM_notification({
            text: `Download completed: ${iter} photos`,
            title: 'Facebook Bulk Downloader',
            timeout: 5000
        });
        return;
    }

    const imgUrl = getImageUrl();
    if (imgUrl) {
        const success = await downloadImage(imgUrl);
        iter++;
        if (success && clickNextImage()) {
            console.log(`Moving to image ${iter + 1}`);
            setTimeout(batchDownload, 1000); // 等待 1 秒后继续下载
        } else {
            console.log('No more images found or failed to click next.');
            GM_notification({
                text: `Download completed: ${iter} photos`,
                title: 'Facebook Bulk Downloader',
                timeout: 5000
            });
        }
    } else {
        console.error('Retry fetching image...');
        setTimeout(batchDownload, 1000);
    }
}

// 开始批量下载
function startBatchDownload() {
    iter = 0;
    stopDownload = false;
    const input = parseInt(prompt("Enter the number of photos to download:", "10000"));
    MAXITER = isNaN(input) ? 10000 : input;
    console.log(`Starting download of ${MAXITER} photos...`);
    GM_notification({
        text: 'Download started...',
        title: 'Facebook Bulk Downloader',
        timeout: 3000
    });
    batchDownload();
}

// 用户按下 Escape 键可随时停止下载
document.addEventListener('keydown', function (e) {
    if (e.key === 'Escape') {
        stopDownload = true;
        console.log('Download stopped by user.');
        GM_notification({
            text: 'Download stopped by user.',
            title: 'Facebook Bulk Downloader',
            timeout: 3000
        });
    }
});

// 监听页面刷新和导航更改,防止下载中断
window.addEventListener('visibilitychange', function () {
    if (document.visibilityState === 'hidden' && !stopDownload) {
        console.log('Attempting to prevent tab from unloading...');
        window.stop(); // 阻止页面刷新或导航
    }
});