// 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.2 // @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_download // @run-at document-end // @downloadURL none // ==/UserScript== /* jshint esversion: 6 */ 'use strict'; 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); }, getSubtitles: function (onlySeleted = true) { console.log("getSubtitles"); const prefix = this.data.dstl; let subtitles = []; 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}.srt`; let url = prefix + this.stl[i].srt; 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) { GM_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; 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); }, getSubtitles: function (onlySeleted = true) { const prefix = this.data.dstl; let subtitles = []; const videoTitle = document.querySelector('#pageMetaTitle').previousElementSibling.textContent; for (let item of this.stl) { if (onlySeleted && !item._selected) continue; let name = `${videoTitle}_${item._name}.srt`; let url = prefix + item.srt; subtitles.push({ name, url }); if (onlySeleted) break; } return subtitles; }, downloadSubtitles: async function (onlySeleted = true) { const subtitles = this.getSubtitles(onlySeleted); for (let item of subtitles) { GM_download(item.url, item.name); await sleep(100); } }, 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(); });