Greasy Fork

Greasy Fork is available in English.

JS 下载云听电台往期音频 优化版

一键下载当前页面所有录音文件,显示爬取进度和单个文件下载状态

当前为 2023-04-05 提交的版本,查看 最新版本

// ==UserScript==
// @name         JS 下载云听电台往期音频 优化版
// @namespace    https://www.radio.cn/
// @version      1.2
// @description  一键下载当前页面所有录音文件,显示爬取进度和单个文件下载状态
// @match        https://www.radio.cn/*
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    function formatDate(dateStr) {
        const date = new Date(dateStr);
        const year = date.getFullYear();
        const month = date.getMonth() + 1;
        const day = date.getDate();
        return year + '-' + (month < 10 ? '0' : '') + month + '-' + (day < 10 ? '0' : '') + day;
    }

    function downloadAll() {
        const downloadLinks = [];
        for (const a of document.getElementsByTagName('a')) {
            if (!a.hasAttribute('onclick')) continue;
            const onclick = a.getAttribute('onclick');
            const matches = onclick.match(/downLiveRecord\(['"](.*?)['"]/);
            if (matches) {
                let href = matches[1].replace(/\[|\]|"/g, '');
                const dateMatch = href.match(/\/(\d{4})(\d{2})(\d{2})\//);
                if (dateMatch) {
                    const dateStr = dateMatch[1] + '-' + dateMatch[2] + '-' + dateMatch[3];
                    const fileName = formatDate(dateStr) + '.mp3';
                    if (href.startsWith('https://')) {
                        downloadLinks.push({href: href, fileName: fileName});
                    } else {
                        href = 'https://' + href.replace(/^http:\/\//i, '');
                        downloadLinks.push({href: href, fileName: fileName});
                    }
                }
            }
        }

        downloadLinks.sort(function(a, b){
            return a.fileName.localeCompare(b.fileName);
        });

        const progressEl = document.createElement('div');
        progressEl.style.position = 'fixed';
        progressEl.style.bottom = '100px';
        progressEl.style.right = '50px';
        progressEl.style.padding = '10px 20px';
        progressEl.style.fontSize = '16px';
        progressEl.style.borderRadius = '5px';
        progressEl.style.color = '#fff';
        progressEl.style.backgroundColor = '#f00';
        progressEl.style.cursor = 'default';
        document.body.appendChild(progressEl);

        const currentProgressEl = document.createElement('div');
        currentProgressEl.style.position = 'fixed';
        currentProgressEl.style.bottom = '160px';
        currentProgressEl.style.right = '50px';
        currentProgressEl.style.width = '200px';
        currentProgressEl.style.padding = '10px 20px';
        currentProgressEl.style.fontSize = '16px';
        currentProgressEl.style.borderRadius = '5px';
        currentProgressEl.style.color = '#fff';
        currentProgressEl.style.backgroundColor = '#009688';
        currentProgressEl.style.cursor = 'default';
        currentProgressEl.style.display = 'none';
        document.body.appendChild(currentProgressEl);

        let downloadCount = 0;

        function downloadNext() {
            if (downloadCount >= downloadLinks.length) {
                progressEl.textContent = '爬取进度:' + downloadCount + '/' + downloadLinks.length + ',全部完成';
                currentProgressEl.style.display = 'none';
                return;
            }

            const link = downloadLinks[downloadCount];
            const xhr = new XMLHttpRequest();
            xhr.open('GET', link.href);
            xhr.responseType = 'blob';
            xhr.onload = function() {
                if (xhr.status === 200) {
                    downloadCount++;
                    const blob = new Blob([xhr.response], {type: 'audio/mp3'});
                    URL.revokeObjectURL(link.href);
                    const url = URL.createObjectURL(blob);
                    const a = document.createElement('a');
                    a.href = url;
                    a.download = link.fileName;
                    document.body.appendChild(a);
                    a.click();
                    a.remove();
                    progressEl.textContent = '爬取进度:' + downloadCount + '/' + downloadLinks.length;
                    currentProgressEl.style.display = 'none';
                    setTimeout(downloadNext, 500);
                } else {
                    console.log(xhr.statusText);
                    setTimeout(downloadNext, 500);
                }
            };
            xhr.onerror = function() {
                console.log(xhr.statusText);
                setTimeout(downloadNext, 500);
            };

            xhr.onprogress = function(event) {
                if (event.lengthComputable) {
                    const percent = ((event.loaded / event.total) * 100).toFixed(2);
                    const fileName = link ? link.fileName : '';
                    currentProgressEl.textContent = fileName + ': ' + percent + '%';
                    currentProgressEl.style.display = '';
                }
            };

            xhr.send();
        }

        downloadNext();
    }

    const downloadBtn = document.createElement('button');
    downloadBtn.textContent = '下载所有录音文件';
    downloadBtn.style.position = 'fixed';
    downloadBtn.style.bottom = '40px';
    downloadBtn.style.right = '50px';
    downloadBtn.style.padding = '10px 20px';
    downloadBtn.style.fontSize = '16px';
    downloadBtn.style.borderRadius = '5px';
    downloadBtn.style.color = '#fff';
    downloadBtn.style.backgroundColor = '#009688';
    downloadBtn.style.cursor = 'pointer';
    downloadBtn.addEventListener('click', function() {
        downloadAll();
    });
    document.body.appendChild(downloadBtn);
})();