爱奇艺字幕下载

下载爱奇艺视频的外挂字幕

目前为 2022-12-23 提交的版本。查看 最新版本

// Copyright 2022 shadows
//
// Distributed under MIT license.
// See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
// ==UserScript==
// @name         爱奇艺字幕下载
// @namespace    http://tampermonkey.net/shadows
// @version      0.1.4
// @description  下载爱奇艺视频的外挂字幕
// @author       shadows
// @license      MIT License
// @copyright    Copyright (c) 2021 shadows
// @match        https://www.iq.com/play/*
// @include      /^https:\/\/www\.iqiyi\.com\/v_(\w+)\.html.*$/
// @icon         https://www.iqiyipic.com/common/images/logo.ico
// @grant        GM_xmlhttpRequest
// @grant        GM.xmlhttpRequest
// @grant        GM_getValue
// @grant        GM.getValue
// @grant        GM_setValue
// @grant        GM.setValue
// @grant        GM_deleteValue
// @grant        GM.deleteValue
// @grant        GM_addValueChangeListener
// @grant        GM_registerMenuCommand
// @grant        GM.registerMenuCommand
// @run-at       document-end
// @require      https://gf.qytechs.cn/scripts/371339-gm-webextpref/code/GM_webextPref.js?version=961539
// @require      https://gcore.jsdelivr.net/npm/[email protected]/dist/FileSaver.min.js
// ==/UserScript==
/* jshint esversion: 6 */
'use strict';
const pref = GM_webextPref({
  default: {
    filetype: "srt",
  },
  body: [
    {
      key: "filetype",
      label: "选择想要下载的文件格式",
      type: "select",
      options: {
        srt: "srt",
        webvtt: "webvtt",
        xml: "xml",
      }
    },
  ]
});
pref.ready();
const extensionDict = {
    srt: "srt",
    webvtt: "vtt",
    xml: "xml",
};

const xhr = option => new Promise((resolve, reject) => {
    GM.xmlHttpRequest({
        ...option,
        onerror: reject,
        onload: (response) => {
            if (response.status >= 200 && response.status < 300) {
                resolve(response);
            } else {
                reject(response);
            }
        },
    });
});

async function download(url,name) {
    await xhr({
        method: "GET",
        url: url,
        responseType: "blob"
    }).then(resp => saveAs(resp.response,name));
}

async function main() {
    const url = new URL(window.location.href);
    const site = websiteRules[url.host];
    if (url.searchParams.get("download_subtitles") == "true") {
        if (await site.hasSubtitles()) {
            console.log("自动下载字幕");
            await site.downloadSubtitles(false);
            console.log("自动下载字幕已完成");
        }
        let nextUrl = site.getNextUrl();
        if (nextUrl) {
            window.location.assign(nextUrl);
        }
        // clear the download_subtitles query param
        url.searchParams.delete("download_subtitles");
        window.history.replaceState(null, '', url);
    }
    // await sleep(500);
    if (await site.hasSubtitles()) {
        await site.addDownloadButton();
    }
}

const websiteRules = {};

websiteRules["www.iqiyi.com"] = {
    hasSubtitles: async function () {
        // check has video pleyer
        console.log("check has video player");
        if (document.querySelector("[data-player-hook]") == null) return false;
        for (let i = 0; i < 100; ++i) {
            await sleep(200);
            if (playerObject._player.package.engine == undefined) continue;
            this.playerData = playerObject._player.package.engine;
            if (this.playerData?.movieinfo.tvid == undefined) continue;
            this.tvid = this.playerData.movieinfo.tvid;
            if (this.playerData.episode.EpisodeStore[this.tvid].movieInfo?.originalData.data == undefined) continue;
            this.data = this.playerData.episode.EpisodeStore[this.tvid].movieInfo.originalData.data;
            // check has subtitles
            if (this.data.program?.stl == undefined) continue;
            if (document.querySelectorAll("[data-player-hook=subtitles_language_list] .iqp-set-zimu").length == 0) continue;
            this.stl = this.data.program.stl;
            return true;
        }
        return false;
    },
    addDownloadButton: async function () {
        console.log("addDownloadButton");
        let parentElement = document.querySelector(".qy-player-title");
        let downloadButton = document.createElement("button");
        downloadButton.innerText = "下载当前字幕";
        downloadButton.style.cssText = buttonCSS;
        downloadButton.id = "download-subtitles";
        parentElement.append(downloadButton);

        document.addEventListener('click', event => {
            if (event.target.id == "download-subtitles") {
                event.stopPropagation();
                this.downloadSubtitles(true);
                return;
            }
        }, true);


        if (this.stl.length > 1) {
            let downloadAllButton = document.createElement("button");
            downloadAllButton.innerText = "下载所有字幕";
            downloadAllButton.style.cssText = buttonCSS;
            downloadAllButton.id = "download-all-subtitles";
            parentElement.append(downloadAllButton);

            document.addEventListener('click', event => {
                if (event.target.id == "download-all-subtitles") {
                    event.stopPropagation();
                    this.downloadSubtitles(false);
                    return;
                }
            }, true);
        }

        let downloadListAllButton = document.createElement("button");
        downloadListAllButton.innerText = "下载所有视频的字幕";
        downloadListAllButton.style.cssText = buttonCSS;
        downloadListAllButton.id = "download-list-all-subtitles";
        parentElement.append(downloadListAllButton);
        document.addEventListener('click', event => {
            if (event.target.id == "download-list-all-subtitles") {
                event.stopPropagation();
                this.downloadSubtitles(false);
                let nextUrl = this.getNextUrl();
                if (nextUrl != null) {
                    window.location.assign(this.getNextUrl());
                }
                return;
            }
        }, true);

        let settingButton = document.createElement("button");
        settingButton.innerText = "设置";
        settingButton.style.cssText = buttonCSS;
        settingButton.addEventListener("click", () => {
            pref.openDialog();
        });
        parentElement.append(settingButton);

    },
    getSubtitles: function (onlySeleted = true) {
        console.log("getSubtitles");
        const prefix = this.data.dstl;
        let subtitles = [];
        const filetype = pref.get("filetype");
        const extension = extensionDict[filetype];
        const videoTitle = document.querySelector(".title-txt").textContent;

        const languages = document.querySelectorAll("[data-player-hook=subtitles_language_list] .iqp-set-zimu");
        for (let i = 0; i < languages.length; ++i) {
            if (onlySeleted && !languages[i].classList.contains("selected")) continue;
            let name = `${videoTitle}_${languages[i].textContent}.${extension}`;
            let url = prefix + this.stl[i][filetype];
            console.log(url);
            subtitles.push({ name, url });
            if (onlySeleted) break;
        }
        return subtitles;
    },
    downloadSubtitles: function (onlySeleted = true) {
        let subtitles = this.getSubtitles(onlySeleted);
        for (let item of subtitles) {
            download(item.url, item.name);
        }
    },
    getNextUrl: function () {
        const nextEpisode = document.querySelector(".qy-episode-tab~[qs-request-id] li.selected~li a");
        if (nextEpisode != null) {
            let url = new URL(nextEpisode.href);
            url.searchParams.set("download_subtitles", "true");
            return url;
        }
        return null;
    },
};

websiteRules["www.iq.com"] = {
    hasSubtitles: async function () {
        for (let i = 0; i < 100; ++i) {
            await sleep(200);
            if (playerObject?._player.package.engine == undefined) continue;
            this.playerData = playerObject._player.package.engine;
            if (this.playerData?.movieinfo.tvid == undefined) continue;
            this.tvid = this.playerData.movieinfo.tvid;
            if (this.playerData.episode.EpisodeStore[this.tvid].movieInfo?.originalData.data == undefined) continue;
            this.data = this.playerData.episode.EpisodeStore[this.tvid].movieInfo.originalData.data;
            // check has subtitles
            if (this.data.program?.stl == undefined) continue;
            if (this.data.program.stl?.length == 0) continue;
            this.stl = this.data.program.stl;
            console.log(this.data);
            return true;
        }
        return false;
    },
    addDownloadButton: async function () {
        console.log("addDownloadButton");
        let parentElement = document.querySelector(".left-section");
        let downloadButton = document.createElement("button");
        downloadButton.innerText = "下载当前字幕";
        downloadButton.style.cssText = buttonCSS;
        downloadButton.addEventListener("click", () => {
            this.downloadSubtitles(true);
        });
        parentElement.append(downloadButton);

        if (this.stl.length > 1) {
            let downloadAllButton = document.createElement("button");
            downloadAllButton.innerText = "下载所有字幕";
            downloadAllButton.style.cssText = buttonCSS;
            downloadAllButton.addEventListener("click", () => { this.downloadSubtitles(false); });
            parentElement.append(downloadAllButton);
        }
        let downloadListAllButton = document.createElement("button");
        downloadListAllButton.innerText = "下载所有视频的字幕";
        downloadListAllButton.style.cssText = buttonCSS;
        downloadListAllButton.addEventListener("click", () => {
            this.downloadSubtitles(false);
            let nextUrl = this.getNextUrl();
            if (nextUrl != null) {
                window.location.assign(this.getNextUrl());
            }
        });
        parentElement.append(downloadListAllButton);

        let settingButton = document.createElement("button");
        settingButton.innerText = "设置";
        settingButton.style.cssText = buttonCSS;
        settingButton.addEventListener("click", () => {
            pref.openDialog();
        });
        parentElement.append(settingButton);
    },
    getSubtitles: function (onlySeleted = true) {
        const prefix = this.data.dstl;
        let subtitles = [];
        const filetype = pref.get("filetype");
        const extension = extensionDict[filetype];
        const videoTitle = document.querySelector('#pageMetaTitle').previousElementSibling.textContent;

        for (let item of this.stl) {
            if (onlySeleted && !item._selected) continue;
            let name = `${videoTitle}_${item._name}.${extension}`;
            let url = prefix + item[filetype];
            subtitles.push({ name, url });
            if (onlySeleted) break;
        }
        return subtitles;
    },
    downloadSubtitles: async function (onlySeleted = true) {
        const subtitles = this.getSubtitles(onlySeleted);
        for (let item of subtitles) {
            download(item.url, item.name);
        }
    },
    getNextUrl: function () {
        const nextEpisode = document.querySelector(".intl-episodes-list li.selected~li a");
        if (nextEpisode) {
            let url = new URL(nextEpisode.href);
            url.searchParams.set("download_subtitles", "true");
            return url.toString();
        }
        return null;
    },
};

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

const buttonCSS = `display: inline-block;
    background: linear-gradient(135deg, #6e8efb, #a777e3);
    color: white;
    padding: 3px 3px;
    margin: 8px 8px;
    text-align: center;
    border-radius: 3px;
    border-width: 0px;`;

window.addEventListener('load', async function () {
    console.log("load");
    await main();
});
window.addEventListener('popstate', async function () {
    console.log("popstate");
    await main();
});

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址