- window.dpPlugins =
- window.dpPlugins ||
- (function (e) {
- var t = {
- version: "1.1.5",
- init: function (s, i) {
- (t = Object.assign(i || {}, t)),
- window.m3u8Parser ||
- t.loadJs(
- "https://cdn.staticfile.org/m3u8-parser/7.1.0/m3u8-parser.min.js"
- ),
- window.localforage ||
- t.loadJs(
- "https://cdn.staticfile.org/localforage/1.10.0/localforage.min.js"
- ),
- t.ready(s).then(() => {
- e.forEach((e) => {
- const i = new e(s, t);
- s.plugins[i.constructor.name] = i;
- });
- });
- },
- ready: function (e) {
- return new Promise(function (t, s) {
- e.isReady
- ? t()
- : e.video.duration > 0 || e.video.readyState > 2
- ? ((e.isReady = !0), t())
- : (e.video.ondurationchange = function () {
- (e.video.ondurationchange = null), (e.isReady = !0), t();
- });
- });
- },
- query: function (e, t = document) {
- return t.querySelector(e);
- },
- queryAll: function (e, t = document) {
- return t.querySelectorAll(e);
- },
- append: function (e, t) {
- return (
- t instanceof Element
- ? Node.prototype.appendChild.call(e, t)
- : e.insertAdjacentHTML("beforeend", String(t)),
- e.lastElementChild || e.lastChild
- );
- },
- prepend: function (e, t) {
- return (
- t instanceof Element
- ? Node.prototype.insertBefore.call(
- e,
- t,
- e.firstElementChild || e.firstChild
- )
- : e.insertAdjacentHTML("afterbegin", String(t)),
- e.firstElementChild || e.firstChild
- );
- },
- insertAfter: function (e, s) {
- var i = e.parentNode;
- return i.lastChild == e
- ? t.append(i, s)
- : ((s = t.append(i, s)),
- Node.prototype.insertBefore.call(i, s, e.nextSibling));
- },
- remove: function (e) {
- return Node.prototype.removeChild.call(e?.parentNode || document, e);
- },
- setStyle: function (e, t, s) {
- if ("object" == typeof t) {
- for (const s in t) e.style[s] = t[s];
- return e;
- }
- return (e.style[t] = s), e;
- },
- };
- return (
- console.info(
- "\n %c dpPlugins v" +
- t.version +
- " %c https://scriptcat.org/zh-CN/users/13895 \n",
- "color: #fadfa3; background: #030307; padding:5px 0;",
- "background: #fadfa3; padding:5px 0;"
- ),
- t
- );
- })([
- class HlsEvents {
- constructor(e) {
- (this.player = e),
- (this.hls = this.player.plugins.hls),
- (this.now = Date.now()),
- (this.currentTime = 0),
- (this.fragLoadError = 0),
- this.player.events.type("video_end") ||
- this.player.events.playerEvents.push("video_end"),
- this.player.on("video_end", () => {
- this.switchUrl();
- }),
- this.player.on("quality_end", () => {
- this.hls &&
- (this.hls.destroy(),
- (this.hls = this.player.plugins.hls),
- localStorage.setItem(
- "dplayer-defaultQuality",
- this.player.quality.name
- ),
- this.onEvents());
- }),
- this.player.on("destroy", () => {
- this.hls && this.hls.destroy();
- }),
- this.onEvents();
- }
- onEvents() {
- if (this.hls) {
- const e = window.Hls || unsafeWindow.Hls;
- this.hls.on(e.Events.ERROR, (t, s) => {
- if (
- (this.hls.media.currentTime > 0 &&
- (this.currentTime = this.hls.media.currentTime),
- s.fatal)
- )
- switch (
- (this.player.notice(
- `当前带宽: ${
- Math.round(
- (this.hls.bandwidthEstimate / 1024 / 1024 / 8) * 100
- ) / 100
- } MB/s`
- ),
- s.type)
- ) {
- case e.ErrorTypes.NETWORK_ERROR:
- s.details === e.ErrorDetails.MANIFEST_LOAD_ERROR ||
- s.details === e.ErrorDetails.MANIFEST_LOAD_TIMEOUT ||
- s.details === e.ErrorDetails.MANIFEST_PARSING_ERROR
- ? this.hls.loadSource(this.hls.url)
- : s.details === e.ErrorDetails.FRAG_LOAD_ERROR
- ? this.fragLoadError < 10 &&
- (this.fragLoadError++,
- this.hls.loadSource(this.hls.url),
- (this.hls.media.currentTime = this.currentTime),
- this.hls.media.play())
- : this.hls.startLoad();
- break;
- case e.ErrorTypes.MEDIA_ERROR:
- this.hls.recoverMediaError();
- break;
- default:
- this.player.notice("视频播放异常,请刷新重试"),
- this.hls.destroy();
- }
- else if (s.type === e.ErrorTypes.NETWORK_ERROR)
- if (
- s.details === e.ErrorDetails.FRAG_LOAD_ERROR &&
- this.isUrlExpires(this.hls.url)
- )
- return (
- (this.fragLoadError = 0),
- (this.now = Date.now()),
- this.hls.stopLoad(),
- this.player.plugins?.Appreciation.isAppreciation()
- .catch((e) =>
- Object.keys(localStorage).forEach(
- (e) => e.startsWith("dp") && localStorage.removeItem(e)
- )
- )
- .finally(() => {
- this.player.events.trigger("video_start");
- })
- );
- });
- }
- }
- switchUrl() {
- if (
- this.hls &&
- this.hls.hasOwnProperty("data") &&
- this.hls.levelController &&
- !this.hls.levelController.currentLevelIndex
- ) {
- const e = (this.hls.url = this.player.quality.url);
- fetch(e)
- .then((e) => (e.ok ? e.text() : Promise.reject()))
- .then((t) => {
- const s = new (
- window.m3u8Parser || unsafeWindow.m3u8Parser
- ).Parser();
- s.push(t), s.end();
- const i = e.replace(/media.m3u8.+/, ""),
- a = s.manifest.segments;
- this.hls.bufferController.details.fragments.forEach(function (
- t,
- s
- ) {
- const l = a[s];
- Object.assign(t, { baseurl: e, relurl: l.uri, url: i + l.uri });
- }),
- this.hls.startLoad(this.player.video.currentTime);
- });
- }
- }
- isUrlExpires(e) {
- var t =
- arguments.length > 1 && void 0 !== arguments[1]
- ? arguments[1]
- : 6e3,
- s = e.match(/&x-oss-expires=(\d+)&/);
- return s
- ? +"".concat(s[1], "000") - t < Date.now()
- : Date.now() - this.now > 3e5 - t;
- }
- },
- class ImageEnhancer {
- constructor(e, t) {
- (this.player = e),
- Object.assign(this.player.user.storageName, {
- imageenhancer: "dplayer-imageenhancer",
- }),
- Object.assign(this.player.user.default, { imageenhancer: 0 }),
- this.player.user.init(),
- (this.imageenhancer = this.player.user.get("imageenhancer")),
- this.imageenhancer &&
- (this.player.video.style.filter =
- "contrast(1.01) brightness(1.05) saturate(1.1)"),
- (this.player.template.imageEnhancer = t.append(
- t.query(
- ".dplayer-setting-origin-panel",
- this.player.template.settingBox
- ),
- '<div class="dplayer-setting-item dplayer-setting-imageenhancer"><span class="dplayer-label">画质增强</span><div class="dplayer-toggle"><input class="dplayer-toggle-setting-input" type="checkbox" name="dplayer-toggle"><label for="dplayer-toggle"></label></div></div>'
- )),
- (this.player.template.imageEnhancerToggle = t.query(
- "input",
- this.player.template.imageEnhancer
- )),
- (this.player.template.imageEnhancerToggle.checked =
- this.imageenhancer),
- this.player.template.imageEnhancer.addEventListener("click", () => {
- (this.imageenhancer =
- this.player.template.imageEnhancerToggle.checked =
- !this.player.template.imageEnhancerToggle.checked),
- this.player.user.set("imageenhancer", Number(this.imageenhancer)),
- (this.player.video.style.filter = this.imageenhancer
- ? "contrast(1.01) brightness(1.05) saturate(1.1)"
- : ""),
- this.player.notice(
- "画质增强: " + (this.imageenhancer ? "开启" : "关闭")
- );
- }),
- this.player.on("playing", () => {
- this.imageenhancer &&
- (this.player.video.style.filter =
- "contrast(1.01) brightness(1.05) saturate(1.1)");
- });
- }
- },
- class SoundEnhancer {
- constructor(e, t) {
- (this.player = e),
- (this.Joysound = window.Joysound || unsafeWindow.Joysound),
- (this.localforage = window.localforage || unsafeWindow.localforage),
- (this.joySound = null),
- (this.offset = null),
- Object.assign(this.player.user.storageName, {
- soundenhancer: "dplayer-soundenhancer",
- volumeenhancer: "dplayer-volumeenhancer",
- }),
- Object.assign(this.player.user.default, {
- soundenhancer: 0,
- volumeenhancer: 0,
- }),
- this.player.user.init(),
- (this.player.template.soundEnhancer = t.append(
- t.query(
- ".dplayer-setting-origin-panel",
- this.player.template.settingBox
- ),
- '<div class="dplayer-setting-item dplayer-setting-soundenhancer"><span class="dplayer-label">音质增强</span><div class="dplayer-toggle"><input class="dplayer-toggle-setting-input" type="checkbox" name="dplayer-toggle"><label for="dplayer-toggle"></label></div></div>'
- )),
- (this.player.template.soundEnhancerToggle = t.query(
- "input",
- this.player.template.soundEnhancer
- )),
- (this.player.template.soundEnhancerToggle.checked =
- !!this.player.user.get("soundenhancer")),
- this.player.template.soundEnhancer.addEventListener("click", () => {
- let e = (this.player.template.soundEnhancerToggle.checked =
- !this.player.template.soundEnhancerToggle.checked);
- this.player.user.set("soundenhancer", Number(e)),
- this.switchJoysound(e);
- }),
- (this.player.template.gainBox = t.prepend(
- t.query(
- ".dplayer-setting-origin-panel",
- this.player.template.settingBox
- ),
- '<div class="dplayer-setting-item dplayer-setting-danmaku dplayer-setting-gain" style="display: block;"><span class="dplayer-label">音量增强</span><div class="dplayer-danmaku-bar-wrap dplayer-gain-bar-wrap"><div class="dplayer-danmaku-bar dplayer-gain-bar"><div class="dplayer-danmaku-bar-inner dplayer-gain-bar-inner" style="width: 0%;"><span class="dplayer-thumb"></span></div></div></div></div>'
- )),
- (this.player.template.gainBarWrap =
- this.player.template.gainBox.querySelector(
- ".dplayer-gain-bar-wrap"
- )),
- (this.player.bar.elements.gain =
- this.player.template.gainBox.querySelector(
- ".dplayer-gain-bar-inner"
- ));
- const s = (e) => {
- const t = e || window.event;
- let s =
- ((t.clientX || t.changedTouches[0].clientX) -
- this.getElementViewLeft(this.player.template.gainBarWrap)) /
- 130;
- this.switchGainValue(s);
- },
- i = () => {
- document.removeEventListener("touchend", i),
- document.removeEventListener("touchmove", s),
- document.removeEventListener("mouseup", i),
- document.removeEventListener("mousemove", s),
- this.player.template.gainBox.classList.remove(
- "dplayer-setting-danmaku-active"
- );
- };
- this.player.template.gainBarWrap.addEventListener("click", (e) => {
- const t = e || window.event;
- let s =
- ((t.clientX || t.changedTouches[0].clientX) -
- this.getElementViewLeft(this.player.template.gainBarWrap)) /
- 130;
- this.switchGainValue(s);
- }),
- this.player.template.gainBarWrap.addEventListener(
- "touchstart",
- () => {
- document.addEventListener("touchmove", s),
- document.addEventListener("touchend", i),
- this.player.template.gainBox.classList.add(
- "dplayer-setting-danmaku-active"
- );
- }
- ),
- this.player.template.gainBarWrap.addEventListener("mousedown", () => {
- document.addEventListener("mousemove", s),
- document.addEventListener("mouseup", i),
- this.player.template.gainBox.classList.add(
- "dplayer-setting-danmaku-active"
- );
- }),
- this.player.on("playing", () => {
- this.localforage.getItem("playing").then((e) => {
- (e = e || 0),
- ++e < 1e3 &&
- ((this.player.plugins.hls.data = !0),
- this.localforage.setItem("playing", e));
- }),
- this.player.video.joySound || this.init();
- });
- }
- init() {
- if (this.Joysound && this.Joysound.isSupport()) {
- (this.joySound = new this.Joysound()),
- this.joySound.init(this.player.video),
- (this.player.video.joySound = !0);
- let e = this.player.user.get("soundenhancer");
- e && this.switchJoysound(e);
- let t = this.player.user.get("volumeenhancer");
- t && this.switchGainValue(t);
- }
- }
- switchJoysound(e) {
- this.joySound
- ? (this.joySound.setEnabled(e),
- this.player.notice("音质增强: " + (e ? "开启" : "关闭")))
- : this.player.notice("Joysound 未完成初始化");
- }
- switchGainValue(e) {
- this.joySound
- ? ((e = Math.min(Math.max(e, 0), 1)),
- this.player.bar.set("gain", e, "width"),
- this.player.user.set("volumeenhancer", e),
- this.joySound.setVolume(e),
- this.player.notice(`音量增强: ${100 + Math.floor(100 * e)}%`))
- : this.player.notice("Joysound 未完成初始化");
- }
- getElementViewLeft(e) {
- const t =
- window.scrollY ||
- window.pageYOffset ||
- document.body.scrollTop +
- ((document.documentElement && document.documentElement.scrollTop) ||
- 0);
- if (e.getBoundingClientRect) {
- if ("number" != typeof this.offset) {
- let e = document.createElement("div");
- (e.style.cssText = "position:absolute;top:0;left:0;"),
- document.body.appendChild(e),
- (this.offset = -e.getBoundingClientRect().top - t),
- document.body.removeChild(e),
- (e = null);
- }
- return e.getBoundingClientRect().left + this.offset;
- }
- {
- let t = e.offsetLeft,
- s = e.offsetParent;
- const i =
- document.body.scrollLeft + document.documentElement.scrollLeft;
- if (
- document.fullscreenElement ||
- document.mozFullScreenElement ||
- document.webkitFullscreenElement
- )
- for (; null !== s && s !== e; )
- (t += s.offsetLeft), (s = s.offsetParent);
- else for (; null !== s; ) (t += s.offsetLeft), (s = s.offsetParent);
- return t - i;
- }
- }
- },
- class AspectRatio {
- constructor(e) {
- (this.player = e),
- (this.value = null),
- this.player.template.controller
- .querySelector(".dplayer-icons-right")
- .insertAdjacentHTML(
- "afterbegin",
- '<div class="dplayer-quality dplayer-aspectRatio"><button class="dplayer-icon dplayer-quality-icon">画面比例</button><div class="dplayer-quality-mask"><div class="dplayer-quality-list dplayer-aspectRatio-list"><div class="dplayer-quality-item" data-value="none">原始比例</div><div class="dplayer-quality-item" data-value="cover">自动裁剪</div><div class="dplayer-quality-item" data-value="fill">拉伸填充</div><div class="dplayer-quality-item" data-value="">系统默认</div></div></div></div>'
- ),
- (this.player.template.aspectRatioButton =
- this.player.template.controller.querySelector(
- ".dplayer-aspectRatio button"
- )),
- (this.player.template.aspectRatioList =
- this.player.template.controller.querySelector(
- ".dplayer-aspectRatio-list"
- )),
- this.player.template.aspectRatioList.addEventListener(
- "click",
- (e) => {
- e.target.classList.contains("dplayer-quality-item") &&
- ((this.value = e.target.dataset.value),
- (this.player.video.style["object-fit"] =
- e.target.dataset.value),
- (this.player.template.aspectRatioButton.innerText =
- e.target.innerText));
- }
- ),
- this.player.on("playing", () => {
- this.value && (this.player.video.style["object-fit"] = this.value);
- });
- }
- },
- class SelectEpisode {
- constructor(e, t) {
- (this.player = e),
- Array.isArray(this.player.options.fileList) &&
- this.player.options.fileList.length > 1 &&
- this.player.options.file &&
- (this.player.events.type("episode_end") ||
- this.player.events.playerEvents.push("episode_end"),
- this.player.on("episode_end", () => {
- this.switchVideo();
- }),
- (this.player.fileIndex = (
- this.player.options.fileList || []
- ).findIndex(
- (e, t) => e.file_id === this.player.options.file.file_id
- )),
- t.prepend(
- this.player.template.controller.querySelector(
- ".dplayer-icons-right"
- ),
- '<style>.episode .content{max-width: 360px;max-height: 330px;width: auto;height: auto;box-sizing: border-box;overflow: hidden auto;position: absolute;left: 0px;transition: all 0.38s ease-in-out 0s;bottom: 52px;transform: scale(0);z-index: 2;}.episode .content .list{background-color: rgba(0,0,0,.3);height: 100%;}.episode .content .video-item{color: #fff;cursor: pointer;font-size: 14px;line-height: 35px;overflow: hidden;padding: 0 10px;text-overflow: ellipsis;text-align: center;white-space: nowrap;}.episode .content .active{background-color: rgba(0,0,0,.3);color: #0df;}</style><div class="dplayer-quality episode"><button class="dplayer-icon prev-icon" title="上一集"><svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M757.527273 190.138182L382.510545 490.123636a28.020364 28.020364 0 0 0 0 43.752728l375.016728 299.985454a28.020364 28.020364 0 0 0 45.474909-21.876363V212.014545a28.020364 28.020364 0 0 0-45.474909-21.876363zM249.949091 221.509818a28.020364 28.020364 0 0 0-27.973818 27.973818v525.032728a28.020364 28.020364 0 1 0 55.994182 0V249.483636a28.020364 28.020364 0 0 0-28.020364-27.973818zM747.054545 270.242909v483.514182L444.834909 512l302.173091-241.757091z"></path></svg></button><button class="dplayer-icon dplayer-quality-icon episode-icon">选集</button><button class="dplayer-icon next-icon" title="下一集"><svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M248.506182 190.138182l374.970182 299.985454a28.020364 28.020364 0 0 1 0 43.752728L248.552727 833.861818a28.020364 28.020364 0 0 1-45.521454-21.876363V212.014545c0-23.505455 27.182545-36.538182 45.521454-21.876363z m507.485091 31.371636c15.453091 0 28.020364 12.567273 28.020363 27.973818v525.032728a28.020364 28.020364 0 1 1-55.994181 0V249.483636c0-15.453091 12.520727-27.973818 27.973818-27.973818zM258.978909 270.242909v483.514182L561.198545 512 258.978909 270.242909z"></path></svg></button><div class="content"><div class="list"></div></div></div>'
- ),
- (this.player.template.episodeButton =
- this.player.template.controller.querySelector(
- ".episode .episode-icon"
- )),
- (this.player.template.episodePrevButton =
- this.player.template.controller.querySelector(
- ".episode .prev-icon"
- )),
- (this.player.template.episodeNextButton =
- this.player.template.controller.querySelector(
- ".episode .next-icon"
- )),
- (this.player.template.episodeContent =
- this.player.template.controller.querySelector(
- ".episode .content"
- )),
- (this.player.template.episodeList =
- this.player.template.controller.querySelector(".episode .list")),
- this.player.options.fileList.forEach((e, s) => {
- t.append(
- this.player.template.episodeList,
- '<div class="video-item" data-index="' +
- s +
- '" title="' +
- e.name +
- '">' +
- e.name +
- "</div>"
- );
- }),
- (this.player.template.episodeVideoItems =
- this.player.template.controller.querySelectorAll(
- ".episode .video-item"
- )),
- this.player.template.episodeVideoItems.length &&
- this.player.fileIndex >= 0 &&
- this.player.template.episodeVideoItems[
- this.player.fileIndex
- ].classList.add("active"),
- this.player.template.mask.addEventListener("click", () => {
- this.hide();
- }),
- this.player.template.episodeButton.addEventListener(
- "click",
- (e) => {
- "scale(1)" ===
- this.player.template.episodeContent.style.transform
- ? this.hide()
- : this.show();
- }
- ),
- this.player.template.episodeList.addEventListener("click", (e) => {
- e.target.classList.contains("video-item") &&
- !e.target.classList.contains("active") &&
- (this.player.template.episodeVideoItems[
- this.player.fileIndex
- ].classList.remove("active"),
- e.target.classList.add("active"),
- (this.player.fileIndex = 1 * e.target.dataset.index),
- (this.player.options.file =
- this.player.options.fileList[this.player.fileIndex]),
- this.hide(),
- this.player.events.trigger("episode_start"),
- this.player.notice(
- "准备播放:" + this.player.options.file.name,
- 5e3
- ));
- }),
- this.player.template.episodePrevButton.addEventListener(
- "click",
- (e) => {
- const t = this.player.fileIndex - 1;
- t >= 0
- ? (this.player.template.episodeVideoItems[
- this.player.fileIndex
- ].classList.remove("active"),
- this.player.template.episodeVideoItems[t].classList.add(
- "active"
- ),
- (this.player.fileIndex = t),
- (this.player.options.file =
- this.player.options.fileList[this.player.fileIndex]),
- this.hide(),
- this.player.events.trigger("episode_start"),
- this.player.notice(
- "准备播放:" + this.player.options.file.name,
- 5e3
- ))
- : this.player.notice("没有上一集了");
- }
- ),
- this.player.template.episodeNextButton.addEventListener(
- "click",
- (e) => {
- const t = this.player.fileIndex + 1;
- t <= this.player.options.fileList.length - 1
- ? (this.player.template.episodeVideoItems[
- this.player.fileIndex
- ].classList.remove("active"),
- this.player.template.episodeVideoItems[t].classList.add(
- "active"
- ),
- (this.player.fileIndex = t),
- (this.player.options.file =
- this.player.options.fileList[this.player.fileIndex]),
- this.hide(),
- this.player.events.trigger("episode_start"),
- this.player.notice(
- "准备播放:" + this.player.options.file.name,
- 5e3
- ))
- : this.player.notice("没有下一集了");
- }
- ));
- }
- switchVideo() {
- this.player.switchVideo({ url: this.player.quality.url, type: "hls" }),
- (this.player.video.oncanplay = () => {
- (this.player.video.oncanplay = null),
- this.player.play(),
- this.player.events.trigger("quality_end");
- });
- }
- show() {
- (this.player.template.episodeContent.style.transform = "scale(1)"),
- this.player.template.mask.classList.add("dplayer-mask-show");
- }
- hide() {
- (this.player.template.episodeContent.style.transform = "scale(0)"),
- this.player.template.mask.classList.remove("dplayer-mask-show");
- }
- },
- class AutoNextEpisode {
- constructor(e, t) {
- (this.player = e),
- Object.assign(this.player.user.storageName, {
- autonextepisode: "dplayer-autonextepisode",
- }),
- Object.assign(this.player.user.default, { autonextepisode: 0 }),
- this.player.user.init(),
- (this.autonextepisode = this.player.user.get("autonextepisode")),
- (this.player.template.autoNextEpisode = t.append(
- t.query(
- ".dplayer-setting-origin-panel",
- this.player.template.settingBox
- ),
- '<div class="dplayer-setting-item dplayer-setting-autonextepisode"><span class="dplayer-label">自动下一集</span><div class="dplayer-toggle"><input class="dplayer-toggle-setting-input" type="checkbox" name="dplayer-toggle"><label for="dplayer-toggle"></label></div></div>'
- )),
- (this.player.template.autoNextEpisodeToggle = t.query(
- "input",
- this.player.template.autoNextEpisode
- )),
- (this.player.template.autoNextEpisodeToggle.checked =
- this.autonextepisode),
- this.player.template.autoNextEpisode.addEventListener("click", () => {
- (this.autonextepisode =
- this.player.template.autoNextEpisodeToggle.checked =
- !this.player.template.autoNextEpisodeToggle.checked),
- this.player.user.set(
- "autonextepisode",
- Number(this.autonextepisode)
- ),
- this.player.notice(
- "自动播放下集: " + (this.autonextepisode ? "开启" : "关闭")
- );
- }),
- this.player.on("ended", () => {
- this.autonextepisode &&
- this.player.template.episodeNextButton &&
- this.player.template.episodeNextButton.click();
- });
- }
- },
- class MemoryPlay {
- constructor(e, t) {
- (this.player = e),
- (this.file_id = this.player.options?.file?.file_id),
- (this.hasMemoryDisplay = !1),
- Object.assign(this.player.user.storageName, {
- automemoryplay: "dplayer-automemoryplay",
- }),
- Object.assign(this.player.user.default, { automemoryplay: 0 }),
- this.player.user.init(),
- (this.automemoryplay = this.player.user.get("automemoryplay")),
- (this.player.template.autoMemoryPlay = t.append(
- t.query(
- ".dplayer-setting-origin-panel",
- this.player.template.settingBox
- ),
- '<div class="dplayer-setting-item dplayer-setting-automemoryplay"><span class="dplayer-label">自动记忆播放</span><div class="dplayer-toggle"><input class="dplayer-toggle-setting-input" type="checkbox" name="dplayer-toggle"><label for="dplayer-toggle"></label></div></div>'
- )),
- (this.player.template.autoMemoryPlayToggle = t.query(
- "input",
- this.player.template.autoMemoryPlay
- )),
- (this.player.template.autoMemoryPlayToggle.checked =
- this.automemoryplay),
- this.player.template.autoMemoryPlay.addEventListener("click", () => {
- (this.automemoryplay =
- this.player.template.autoMemoryPlayToggle.checked =
- !this.player.template.autoMemoryPlayToggle.checked),
- this.player.user.set(
- "automemoryplay",
- Number(this.automemoryplay)
- ),
- this.player.notice(
- "自动记忆播放: " + (this.automemoryplay ? "开启" : "关闭")
- );
- }),
- this.player.on("quality_end", () => {
- this.file_id !== this.player.options?.file?.file_id &&
- ((this.file_id = this.player.options?.file?.file_id),
- (this.hasMemoryDisplay = !1)),
- this.run();
- }),
- (document.onvisibilitychange = () => {
- if ("hidden" === document.visibilityState) {
- const {
- video: { currentTime: e, duration: t },
- } = this.player;
- this.setTime(this.file_id, e, t);
- }
- }),
- (window.onbeforeunload = () => {
- const {
- video: { currentTime: e, duration: t },
- } = this.player;
- this.setTime(this.file_id, e, t);
- }),
- this.run();
- }
- run() {
- if (!1 === this.hasMemoryDisplay) {
- this.hasMemoryDisplay = !0;
- const {
- video: { currentTime: e, duration: t },
- } = this.player,
- s = this.getTime(this.file_id);
- if (s && s > e)
- if (this.automemoryplay)
- this.player.seek(s),
- this.player.video.paused && this.player.play();
- else {
- const e = this.formatTime(s);
- let t = document.createElement("div");
- t.setAttribute("class", "memory-play-wrap"),
- t.setAttribute(
- "style",
- "display: block;position: absolute;left: 33px;bottom: 66px;font-size: 15px;padding: 7px;border-radius: 3px;color: #fff;z-index:100;background: rgba(0,0,0,.5);"
- ),
- (t.innerHTML =
- "上次播放到:" +
- e +
- ' <a href="javascript:void(0);" class="play-jump" style="text-decoration: none;color: #06c;"> 跳转播放 </a><em class="close-btn" style="display: inline-block;width: 15px;height: 15px;vertical-align: middle;cursor: pointer;background: url(https://nd-static.bdstatic.com/m-static/disk-share/widget/pageModule/share-file-main/fileType/video/img/video-flash-closebtn_15f0e97.png) no-repeat;"></em>'),
- this.player.container.insertBefore(t, null);
- let i = setTimeout(() => {
- this.player.container.removeChild(t);
- }, 15e3);
- (t.querySelector(".close-btn").onclick = () => {
- this.player.container.removeChild(t), clearTimeout(i);
- }),
- (t.querySelector(".play-jump").onclick = () => {
- this.player.seek(s),
- this.player.container.removeChild(t),
- clearTimeout(i);
- });
- }
- }
- }
- getTime(e) {
- return localStorage.getItem("video_" + e) || 0;
- }
- setTime(e, t, s) {
- e &&
- t &&
- ((e = "video_" + e),
- t <= 60 || t + 120 >= s
- ? localStorage.removeItem(e)
- : localStorage.setItem(e, t));
- }
- formatTime(e) {
- var t = Math.round(e),
- s = Math.floor(t / 3600),
- i = Math.floor((t - 3600 * s) / 60),
- a = t - 3600 * s - 60 * i;
- return (
- i < 10 && (i = "0" + i),
- a < 10 && (a = "0" + a),
- 0 === s ? i + ":" + a : s + ":" + i + ":" + a
- );
- }
- },
- class SkipPosition {
- constructor(e, t) {
- (this.player = e),
- (this.file_id = this.player.options?.file?.file_id),
- (this.timer = null),
- Object.assign(this.player.user.storageName, {
- skipposition: "dplayer-skipposition",
- skipstarttime: "dplayer-skipstarttime",
- skipendtime: "dplayer-endtime",
- }),
- Object.assign(this.player.user.default, {
- skipposition: 0,
- skipstarttime: 0,
- skipendtime: 0,
- }),
- this.player.user.init(),
- (this.skipposition = this.player.user.get("skipposition")),
- (this.skipstarttime = this.player.user.get("skipstarttime")),
- (this.skipendtime = this.player.user.get("skipendtime")),
- (this.player.template.skipPosition = t.append(
- t.query(
- ".dplayer-setting-origin-panel",
- this.player.template.settingBox
- ),
- '<div class="dplayer-setting-item dplayer-setting-skipposition"><span class="dplayer-label">跳过片头片尾</span><div class="dplayer-toggle"><input class="dplayer-toggle-setting-input" type="checkbox" name="dplayer-toggle"><label for="dplayer-toggle"></label></div></div>'
- )),
- (this.player.template.skipPositionToggle = t.query(
- "input",
- this.player.template.skipPosition
- )),
- (this.player.template.skipPositionToggle.checked = this.skipposition),
- (this.player.template.skipPositionBox = t.insertAfter(
- this.player.template.settingBox,
- '<div class="dplayer-setting-skipposition-item" style="display: none;right: 155px;position: absolute;bottom: 50px;width: 150px;border-radius: 2px;background: rgba(28, 28, 28, 0.9);padding: 7px 0px;transition: all 0.3s ease-in-out 0s;overflow: hidden;z-index: 2;"><div class="dplayer-skipposition-item" style="padding: 5px 10px;box-sizing: border-box;cursor: pointer;position: relative;"><span class="dplayer-skipposition-label" title="双击设置当前时间为跳过片头时间" style="color: #eee;font-size: 13px;display: inline-block;vertical-align: middle;white-space: nowrap;">片头时间:</span><input type="number" style="width: 55px;height: 15px;top: 3px;font-size: 13px;border: 1px solid #fff;border-radius: 3px;text-align: center;background-color: #fff;" step="1" min="0" value="60"></div><div class="dplayer-skipposition-item" style="padding: 5px 10px;box-sizing: border-box;cursor: pointer;position: relative;"><span class="dplayer-skipposition-label" title="双击设置剩余时间为跳过片尾时间" style="color: #eee;font-size: 13px;display: inline-block;vertical-align: middle;white-space: nowrap;">片尾时间:</span><input type="number" style="width: 55px;height: 15px;top: 3px;font-size: 13px;border: 1px solid #fff;border-radius: 3px;text-align: center;background-color: #fff;" step="1" min="0" value="120"></div></div>'
- )),
- (this.player.template.skipPositionItems = t.queryAll(
- ".dplayer-skipposition-item",
- this.player.template.skipPositionBox
- )),
- (this.player.template.jumpStartSpan = t.query(
- "span",
- this.player.template.skipPositionItems[0]
- )),
- (this.player.template.jumpStartInput = t.query(
- "input",
- this.player.template.skipPositionItems[0]
- )),
- (this.player.template.jumpEndSpan = t.query(
- "span",
- this.player.template.skipPositionItems[1]
- )),
- (this.player.template.jumpEndInput = t.query(
- "input",
- this.player.template.skipPositionItems[1]
- )),
- (this.player.template.jumpStartInput.value = this.skipstarttime),
- (this.player.template.jumpEndInput.value = this.skipendtime),
- this.player.template.jumpStartSpan.addEventListener(
- "dblclick",
- (e) => {
- (this.player.template.jumpStartInput.value =
- this.player.video.currentTime),
- (this.skipstarttime = this.player.video.currentTime);
- }
- ),
- this.player.template.jumpStartInput.addEventListener("input", (e) => {
- (this.skipstarttime = 1 * e.target.value),
- this.player.user.set("skipstarttime", this.skipstarttime);
- }),
- this.player.template.jumpEndSpan.addEventListener("dblclick", (e) => {
- (this.skipendtime =
- this.player.video.duration - this.player.video.currentTime),
- (this.player.template.jumpEndInput.value = this.skipendtime);
- }),
- this.player.template.jumpEndInput.addEventListener("input", (e) => {
- (this.skipendtime = 1 * e.target.value),
- this.player.user.set("skipendtime", this.skipendtime);
- }),
- this.player.template.skipPosition.addEventListener("click", () => {
- (this.skipposition =
- this.player.template.skipPositionToggle.checked =
- !this.player.template.skipPositionToggle.checked),
- this.player.user.set("skipposition", Number(this.skipposition)),
- this.skipposition ? this.show() : this.hide(),
- this.player.notice(
- "跳过片头片尾: " + (this.skipposition ? "开启" : "关闭")
- );
- }),
- this.player.template.skipPosition.addEventListener(
- "mouseenter",
- () => {
- this.skipposition && this.show();
- }
- ),
- this.player.template.mask.addEventListener("click", () => {
- this.hide();
- }),
- this.player.on("quality_end", () => {
- this.file_id !== this.player.options?.file?.file_id &&
- ((this.file_id = this.player.options?.file?.file_id),
- this.jumpStart(),
- this.jumpEnd());
- }),
- this.skipposition && (this.jumpStart(), this.jumpEnd());
- }
- jumpStart() {
- this.skipposition &&
- this.skipstarttime > this.player.video.currentTime &&
- (this.player.video.currentTime = this.skipstarttime);
- }
- jumpEnd() {
- this.timer ||
- (this.timer = setInterval(() => {
- this.skipposition &&
- this.skipendtime >=
- this.player.video.duration - this.player.video.currentTime &&
- ((this.player.video.currentTime = this.player.video.duration),
- clearInterval(this.timer),
- (this.timer = null));
- }, 3e3));
- }
- show() {
- this.player.template.skipPositionBox.style.display = "block";
- }
- hide() {
- this.player.template.skipPositionBox.style.display = "none";
- }
- },
- class Subtitle {
- constructor(e, t) {
- if (
- ((this.player = e),
- (this.offset = 0),
- (this.offsetStep = 1),
- (this.color = this.get("color") || "#fff"),
- (this.bottom = this.get("bottom") || "40px"),
- (this.fontSize = this.get("fontSize") || "20px"),
- Object.assign(this.player.user.storageName, {
- specialsubtitle: "dplayer-specialsubtitle",
- }),
- Object.assign(this.player.user.default, { specialsubtitle: 0 }),
- this.player.user.init(),
- (this.specialsubtitle = this.player.user.get("specialsubtitle")),
- this.specialsubtitle)
- )
- return;
- (this.player.template.subtitleSpecial = t.append(
- t.query(
- ".dplayer-setting-origin-panel",
- this.player.template.settingBox
- ),
- '<div class="dplayer-setting-item dplayer-setting-specialsubtitle"><span class="dplayer-label">特效字幕</span><div class="dplayer-toggle"><input class="dplayer-toggle-setting-input" type="checkbox" name="dplayer-toggle"><label for="dplayer-toggle"></label></div></div>'
- )),
- (this.player.template.subtitleSpecialToggle = t.query(
- "input",
- this.player.template.subtitleSpecial
- )),
- (this.player.template.subtitleSpecialToggle.checked =
- this.specialsubtitle),
- this.player.template.subtitleSpecial.addEventListener("click", () => {
- (this.specialsubtitle =
- this.player.template.subtitleSpecialToggle.checked =
- !this.player.template.subtitleSpecialToggle.checked),
- this.player.user.set(
- "specialsubtitle",
- Number(this.specialsubtitle)
- ),
- this.player.notice(
- "特效字幕: " + (this.specialsubtitle ? "开启" : "关闭")
- ),
- this.specialsubtitle && location.reload();
- }),
- e.events.type("subtitle_end") ||
- e.events.playerEvents.push("subtitle_end"),
- e.on("subtitle_end", () => {
- this.add(this.player.options.subtitles);
- }),
- this.player.events.trigger("subtitle_start"),
- this.player.on("quality_end", () => {
- (this.player.template.subtitle.innerHTML = "<p></p>"),
- this.player.options.subtitle.url.length &&
- this.player.options.subtitles.length
- ? this.switch(
- this.player.options.subtitles[
- this.player.options.subtitle.index
- ]
- )
- : this.player.events.trigger("subtitle_start");
- }),
- this.player.on("episode_end", () => {
- this.clear(),
- this.style({
- color: this.color,
- bottom: this.bottom,
- fontSize: this.fontSize,
- });
- }),
- this.player.on("video_end", () => {
- this.style({
- color: this.color,
- bottom: this.bottom,
- fontSize: this.fontSize,
- });
- }),
- (this.player.template.subtitleSettingBox = t.append(
- this.player.template.controller,
- '<div class="dplayer-icons dplayer-comment-box subtitle-setting-box" style="bottom: 10px;left: auto;right: 400px !important;display: block;"><div class="dplayer-comment-setting-box"><div class="dplayer-comment-setting-color"><div class="dplayer-comment-setting-title">字幕颜色<button type="text" class="color-custom" style="line-height: 16px;font-size: 12px;top: 12px;right: 12px;color: #fff;background: rgba(28, 28, 28, 0.9);position: absolute;">自定义</button></div><label><input type="radio" name="dplayer-danmaku-color-1" value="#fff" checked=""><span style="background: #fff;"></span></label><label><input type="radio" name="dplayer-danmaku-color-1" value="#e54256"><span style="background: #e54256"></span></label><label><input type="radio" name="dplayer-danmaku-color-1" value="#ffe133"><span style="background: #ffe133"></span></label><label><input type="radio" name="dplayer-danmaku-color-1" value="#64DD17"><span style="background: #64DD17"></span></label><label><input type="radio" name="dplayer-danmaku-color-1" value="#39ccff"><span style="background: #39ccff"></span></label><label><input type="radio" name="dplayer-danmaku-color-1" value="#D500F9"><span style="background: #D500F9"></span></label></div><div class="dplayer-comment-setting-type"><div class="dplayer-comment-setting-title">字幕位置</div><label><input type="radio" name="dplayer-danmaku-type-1" value="1"><span>上移</span></label><label><input type="radio" name="dplayer-danmaku-type-1" value="0" checked=""><span>默认</span></label><label><input type="radio" name="dplayer-danmaku-type-1" value="2"><span>下移</span></label></div><div class="dplayer-comment-setting-type"><div class="dplayer-comment-setting-title">字幕大小</div><label><input type="radio" name="dplayer-danmaku-type-1" value="1"><span>加大</span></label><label><input type="radio" name="dplayer-danmaku-type-1" value="0"><span>默认</span></label><label><input type="radio" name="dplayer-danmaku-type-1" value="2"><span>减小</span></label></div><div class="dplayer-comment-setting-type"><div class="dplayer-comment-setting-title">字幕偏移<div style="margin-top: -30px;right: 14px;position: absolute;">偏移量<input type="number" class="subtitle-offset-step" style="height: 14px;width: 50px;margin-left: 4px;border: 1px solid #fff;border-radius: 3px;color: #fff;background: rgba(28, 28, 28, 0.9);text-align: center;" value="1" step="1" min="1"></div></div><label><input type="radio" name="dplayer-danmaku-type-1" value="1"><span>前移</span></label><label><span><input type="text" class="subtitle-offset" style="width: 94%;height: 14px;background: rgba(28, 28, 28, 0.9);border: 0px solid #fff;text-align: center;" value="0" title="双击恢复默认"></span></label><label><input type="radio" name="dplayer-danmaku-type-1" value="2"><span>后移</span></label></div><div class="dplayer-comment-setting-type"><div class="dplayer-comment-setting-title">更多字幕功能</div><label><input type="radio" name="dplayer-danmaku-type-1" value="1"><span>本地字幕</span></label><label><input type="radio" name="dplayer-danmaku-type-1" value="0"><span>待定</span></label><label><input type="radio" name="dplayer-danmaku-type-1" value="2"><span>待定</span></label></div></div></div>'
- )),
- (this.player.template.subtitleCommentSettingBox = t.query(
- ".dplayer-comment-setting-box",
- this.player.template.subtitleSettingBox
- )),
- (this.player.template.subtitleSetting = t.append(
- t.query(
- ".dplayer-setting-origin-panel",
- this.player.template.settingBox
- ),
- '<div class="dplayer-setting-item dplayer-setting-subtitle"><span class="dplayer-label">字幕设置</span><div class="dplayer-toggle"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 32 32"><path d="M22 16l-10.105-10.6-1.895 1.987 8.211 8.613-8.211 8.612 1.895 1.988 8.211-8.613z"></path></svg></div></div>'
- )),
- this.player.template.mask.addEventListener("click", () => {
- this.hide();
- }),
- this.player.template.subtitleSetting.addEventListener("click", () => {
- this.toggle();
- }),
- (this.player.template.subtitleColorPicker = t.append(
- this.player.template.container,
- '<input type="color" id="colorPicker">'
- )),
- (this.player.template.subtitleColorCustom = t.query(
- ".color-custom",
- this.player.template.subtitleCommentSettingBox
- )),
- this.player.template.subtitleColorCustom.addEventListener(
- "click",
- () => {
- this.player.template.subtitleColorPicker.click();
- }
- ),
- this.player.template.subtitleColorPicker.addEventListener(
- "input",
- (e) => {
- (this.color = e.target.value),
- this.set("color", this.color),
- this.style({ color: this.color });
- }
- ),
- (this.player.template.subtitleSettingColor = t.query(
- ".dplayer-comment-setting-color",
- this.player.template.subtitleCommentSettingBox
- )),
- this.player.template.subtitleSettingColor.addEventListener(
- "click",
- (e) => {
- "INPUT" === e.target.nodeName &&
- ((this.color = e.target.value),
- this.set("color", this.color),
- this.style({ color: this.color }));
- }
- ),
- (this.player.template.subtitleSettingItem = t.queryAll(
- ".dplayer-comment-setting-type",
- this.player.template.subtitleCommentSettingBox
- )),
- this.player.template.subtitleSettingItem[0].addEventListener(
- "click",
- (e) => {
- "INPUT" === e.target.nodeName &&
- ("1" == e.target.value
- ? (this.bottom =
- parseFloat(this.bottom) +
- 1 +
- this.bottom.replace(/[\d\.]+/, ""))
- : "2" == e.target.value
- ? (this.bottom =
- parseFloat(this.bottom) -
- 1 +
- this.bottom.replace(/[\d\.]+/, ""))
- : (this.bottom = "20px"),
- this.set("bottom", this.bottom),
- this.style({ bottom: this.bottom }));
- }
- ),
- this.player.template.subtitleSettingItem[1].addEventListener(
- "click",
- (e) => {
- "INPUT" === e.target.nodeName &&
- ("1" == e.target.value
- ? (this.fontSize =
- parseFloat(this.fontSize) +
- 1 +
- this.fontSize.replace(/[\d\.]+/, ""))
- : "2" == e.target.value
- ? (this.fontSize =
- parseFloat(this.fontSize) -
- 1 +
- this.fontSize.replace(/[\d\.]+/, ""))
- : (this.fontSize = "40px"),
- this.set("fontSize", this.fontSize),
- this.style({ fontSize: this.fontSize }));
- }
- ),
- (this.player.template.subtitleOffsetStep = t.query(
- ".subtitle-offset-step",
- this.player.template.subtitleSettingItem[2]
- )),
- this.player.template.subtitleOffsetStep.addEventListener(
- "input",
- (e) => {
- this.offsetStep = 1 * e.target.value;
- }
- ),
- (this.player.template.subtitleOffset = t.query(
- ".subtitle-offset",
- this.player.template.subtitleSettingItem[2]
- )),
- this.player.template.subtitleOffset.addEventListener("input", (e) => {
- (this.offset = 1 * e.target.value), this.subtitleOffset();
- }),
- this.player.template.subtitleOffset.addEventListener(
- "dblclick",
- (e) => {
- 0 != this.offset &&
- ((this.offset = 0),
- (e.target.value = 0),
- this.subtitleOffset());
- }
- ),
- this.player.template.subtitleSettingItem[2].addEventListener(
- "click",
- (e) => {
- if ("INPUT" === e.target.nodeName && "radio" === e.target.type) {
- let t = (this.player.template.subtitleOffset.value *= 1);
- "1" == e.target.value
- ? (t += this.offsetStep || 1)
- : "2" == e.target.value
- ? (t -= this.offsetStep || 1)
- : (t = 0),
- (this.offset = t),
- (this.player.template.subtitleOffset.value = t),
- this.subtitleOffset();
- }
- }
- ),
- (this.player.template.subtitleLocalFile = t.append(
- this.player.template.container,
- '<input class="subtitleLocalFile" type="file" accept="webvtt,.vtt,.srt,.ssa,.ass" style="display: none;">'
- )),
- this.player.template.subtitleSettingItem[3].addEventListener(
- "click",
- (e) => {
- "INPUT" === e.target.nodeName &&
- "1" == e.target.value &&
- (this.player.template.subtitleLocalFile.click(), this.hide());
- }
- ),
- this.player.template.subtitleLocalFile.addEventListener(
- "change",
- (e) => {
- if (e.target.files.length) {
- const t = e.target.files[0],
- s = t.name.split(".").pop().toLowerCase();
- this.blobToText(t).then((e) => {
- let t = { url: "" };
- (t.sarr = this.subParser(e, s)),
- (t.lang = this.getlangBySarr(t.sarr)),
- (t.name = t.name || this.langToLabel(t.lang)),
- this.add([t]),
- this.switch(t);
- });
- }
- e.target.value = "";
- }
- );
- const s = this.player.template.subtitlesItem.length - 1;
- this.player.template.subtitlesItem[s].addEventListener("click", () => {
- (this.player.options.subtitle.index = s),
- (this.player.template.subtitle.innerHTML = "<p></p>"),
- this.player.subtitles.subContainerHide();
- }),
- this.style({
- color: this.color,
- bottom: this.bottom,
- fontSize: this.fontSize,
- });
- }
- add(e) {
- if (!Array.isArray(e) || !e.length) return;
- if (
- !this.player.template.subtitlesBox ||
- !this.player.template.subtitlesItem.length
- )
- return;
- const t = this.player.template.subtitlesItem.length - 1;
- e.forEach((e, s) => {
- const i = t + s;
- this.player.options.subtitle.url.splice(i, 0, e);
- let a = document.createElement("div");
- a.setAttribute("class", "dplayer-subtitles-item"),
- (a.innerHTML =
- '<span class="dplayer-label">' +
- e.name +
- " " +
- (e.language || e.lang || "") +
- "</span>"),
- this.player.template.subtitlesBox.insertBefore(
- a,
- this.player.template.subtitlesBox.childNodes[i]
- ),
- a.addEventListener("click", (t) => {
- this.player.subtitles.hide(),
- this.player.options.subtitle.index !== i + 1 &&
- ((this.player.options.subtitle.index = i + 1),
- (this.player.template.subtitle.innerHTML = "<p></p>"),
- this.switch(e),
- this.player.template.subtitle.classList.contains(
- "dplayer-subtitle-hide"
- ) && this.player.subtitles.subContainerShow());
- });
- }),
- (this.player.template.subtitlesItem =
- this.player.template.subtitlesBox.querySelectorAll(
- ".dplayer-subtitles-item"
- )),
- (this.player.video.textTracks.length &&
- this.player.video.textTracks[0]?.cues &&
- this.player.video.textTracks[0].cues.length) ||
- ((this.player.options.subtitle.index =
- this.player.options.subtitles.findIndex((e) =>
- ["cho", "chi"].includes(e.language)
- )),
- this.player.options.subtitle.index < 0 &&
- (this.player.options.subtitle.index = 0),
- this.switch(
- this.player.options.subtitle.url[
- this.player.options.subtitle.index
- ]
- ));
- }
- switch(e = {}) {
- return this.initCues(e).then((t) => {
- e.name;
- });
- }
- restart() {
- this.clear(), this.add(this.player.options.subtitles);
- }
- clear() {
- (this.player.template.subtitle.innerHTML = "<p></p>"),
- (this.player.options.subtitles = []),
- (this.player.options.subtitle.url = []);
- for (let e = this.player.template.subtitlesItem.length - 2; e >= 0; e--)
- this.player.template.subtitlesBoxPanel.removeChild(
- this.player.template.subtitlesItem[e]
- );
- this.player.template.subtitlesItem =
- this.player.template.subtitlesBoxPanel.querySelectorAll(
- ".dplayer-subtitles-item"
- );
- }
- initCues(e) {
- return this.urlToArray(e).then((e) => this.createTrack(e));
- }
- urlToArray(e) {
- if (Array.isArray(e?.sarr) && e.sarr.length) return Promise.resolve(e);
- {
- const t = e?.url || e?.download_url || e?.uri || e?.surl,
- s = e.sext || e.file_extension;
- return t
- ? this.requestFile(t).then(
- (t) => (
- (e.sarr = this.subParser(t, s, e.delay || 0)),
- (e.lang = e.lang || this.getlangBySarr(e.sarr)),
- (e.name = e.name || this.langToLabel(e.lang)),
- e
- )
- )
- : Promise.reject();
- }
- }
- createTrack(e) {
- const { video: t } = this.player,
- s = t.textTracks[0];
- if (
- ("hidden" === s.mode || (s.mode = "hidden"), s.cues && s.cues.length)
- )
- for (let e = s.cues.length - 1; e >= 0; e--) s.removeCue(s.cues[e]);
- e.sarr.forEach(function (e, t) {
- const i = new VTTCue(e.startTime, e.endTime, e.text);
- (i.id = e.index), s.addCue(i);
- });
- }
- requestFile(e) {
- return fetch(e, {
- referrer: "https://www.aliyundrive.com/",
- referrerPolicy: "origin",
- body: null,
- method: "GET",
- mode: "cors",
- credentials: "omit",
- })
- .then((e) => e.blob())
- .then((e) => this.blobToText(e));
- }
- blobToText(e) {
- return new Promise(function (t, s) {
- var i = new FileReader();
- i.readAsText(e, "UTF-8"),
- (i.onload = function (s) {
- var a = i.result;
- return a.indexOf("�") > -1 && !i.markGBK
- ? ((i.markGBK = !0), i.readAsText(e, "GBK"))
- : a.indexOf("") > -1 && !i.markBIG5
- ? ((i.markBIG5 = !0), i.readAsText(e, "BIG5"))
- : void t(a);
- }),
- (i.onerror = function (e) {
- s(e);
- });
- });
- }
- subParser(e, t, s = 0) {
- t ||
- (t = /\d\s?-?->\s?\d/.test(e)
- ? "srt"
- : /^\s*\[Script Info\]\r?\n/.test(e) && /\s*\[Events\]\r?\n/.test(e)
- ? "ass"
- : "");
- var i,
- a = [],
- l = [];
- switch (t) {
- case "webvtt":
- case "vtt":
- case "srt":
- (i =
- /(\d+)?\n?(\d{0,2}:?\d{2}:\d{2}.\d{3})\s?-?->\s?(\d{0,2}:?\d{2}:\d{2}.\d{3})/g),
- (a = (e = e.replace(/\r/g, "")).split(i)).shift();
- for (let e = 0; e < a.length; e += 4)
- l.push({
- index: l.length,
- startTime: r(a[e + 1]) + +s,
- endTime: r(a[e + 2]) + +s,
- text: a[e + 3]
- .trim()
- .replace(/(\\N|\\n)/g, "\n")
- .replace(/{.*?}/g, "")
- .replace(/[a-z]+\:.*\d+\.\d+\%\s/, ""),
- });
- return l;
- case "ssa":
- case "ass":
- (i =
- /Dialogue: .*?\d+,(\d+:\d{2}:\d{2}\.\d{2}),(\d+:\d{2}:\d{2}\.\d{2}),.*?,\d+,\d+,\d+,.*?,/g),
- (a = (e = e.replace(/\r\n/g, "")).split(i)).shift();
- for (let e = 0; e < a.length; e += 3)
- l.push({
- index: l.length,
- startTime: r(a[e]) + +s,
- endTime: r(a[e + 1]) + +s,
- text: a[e + 2]
- .trim()
- .replace(/(\\N|\\n)/g, "\n")
- .replace(/{.*?}/g, ""),
- });
- return l;
- default:
- return console.error("未知字幕格式,无法解析", e), l;
- }
- function r(e) {
- var t = e.split(":"),
- s =
- parseFloat(
- t.length > 0 ? t.pop().replace(/,/g, ".") : "00.000"
- ) || 0,
- i = parseFloat(t.length > 0 ? t.pop() : "00") || 0;
- return (
- 3600 * (parseFloat(t.length > 0 ? t.pop() : "00") || 0) + 60 * i + s
- );
- }
- }
- getlangBySarr(e) {
- var t = [
- e[parseInt(e.length / 3)].text,
- e[parseInt(e.length / 2)].text,
- e[parseInt((e.length / 3) * 2)].text,
- ]
- .join("")
- .replace(/[<bi\/>\r?\n]*/g, ""),
- s = "eng",
- i = (t.match(/[\u4e00-\u9fa5]/g) || []).length / t.length;
- return (
- (
- t.match(
- /[\u3020-\u303F]|[\u3040-\u309F]|[\u30A0-\u30FF]|[\u31F0-\u31FF]/g
- ) || []
- ).length /
- t.length >
- 0.03
- ? (s = "jpn")
- : i > 0.1 && (s = "zho"),
- s
- );
- }
- langToLabel(e) {
- return (
- {
- chi: "中文字幕",
- zho: "中文字幕",
- eng: "英文字幕",
- en: "英文字幕",
- jpn: "日文字幕",
- "zh-CN": "简体中文",
- "zh-TW": "繁体中文",
- }[e] || "未知语言"
- );
- }
- subtitleOffset() {
- const { video: e, subtitle: t, events: s } = this.player,
- i = e.textTracks[0];
- if (i && i.cues) {
- const e = Array.from(i.cues),
- t = this.player.options.subtitle.url.find(
- (t) =>
- t.sarr &&
- t.sarr[parseInt(t.sarr.length / 2)].text ===
- e[parseInt(e.length / 2)].text
- )?.sarr;
- if (!t) return;
- for (let s = 0; s < e.length; s++) {
- const i = e[s];
- (i.startTime = t[s].startTime + this.offset),
- (i.endTime = t[s].endTime + this.offset);
- }
- s.trigger("subtitle_change"),
- this.player.notice(`字幕偏移: ${this.offset} 秒`);
- } else this.offset = 0;
- }
- toggle() {
- this.player.template.subtitleCommentSettingBox.classList.contains(
- "dplayer-comment-setting-open"
- )
- ? this.hide()
- : this.show();
- }
- show() {
- this.player.template.subtitleCommentSettingBox.classList.add(
- "dplayer-comment-setting-open"
- ),
- this.player.template.mask.classList.add("dplayer-mask-show");
- }
- hide() {
- this.player.template.subtitleCommentSettingBox.classList.remove(
- "dplayer-comment-setting-open"
- ),
- this.player.template.settingBox.classList.remove(
- "dplayer-setting-box-open"
- ),
- this.player.template.mask.classList.remove("dplayer-mask-show");
- }
- get(e) {
- return localStorage.getItem("dplayer-subtitle-" + e);
- }
- set(e, t) {
- e && t && localStorage.setItem("dplayer-subtitle-" + e, t);
- }
- style(e, t) {
- const { subtitle: s } = this.player.template;
- if ("object" == typeof e) {
- for (const t in e) s.style[t] = e[t];
- return s;
- }
- return (s.style[e] = t), s;
- }
- },
- class Libass {
- constructor(e, t) {
- (this.player = e),
- (this.loadJs = t.loadJs),
- (this.libass = null),
- (this.fontData = null),
- (this.hasSubtitleTrack = !1),
- (this.hasSubtitleDisplay = !1),
- (this.offset = 0),
- (this.offsetStep = 1),
- (this.color = -256),
- (this.fontSize = 20),
- (this.bottom = 10),
- Object.assign(this.player.user.storageName, {
- specialsubtitle: "dplayer-specialsubtitle",
- }),
- Object.assign(this.player.user.default, { specialsubtitle: 0 }),
- this.player.user.init(),
- (this.specialsubtitle = this.player.user.get("specialsubtitle")),
- this.specialsubtitle &&
- ((this.player.template.subtitleSpecial = t.append(
- t.query(
- ".dplayer-setting-origin-panel",
- this.player.template.settingBox
- ),
- '<div class="dplayer-setting-item dplayer-setting-specialsubtitle"><span class="dplayer-label">特效字幕</span><div class="dplayer-toggle"><input class="dplayer-toggle-setting-input" type="checkbox" name="dplayer-toggle"><label for="dplayer-toggle"></label></div></div>'
- )),
- (this.player.template.subtitleSpecialToggle = t.query(
- "input",
- this.player.template.subtitleSpecial
- )),
- (this.player.template.subtitleSpecialToggle.checked =
- this.specialsubtitle),
- this.player.template.subtitleSpecial.addEventListener(
- "click",
- () => {
- (this.specialsubtitle =
- this.player.template.subtitleSpecialToggle.checked =
- !this.player.template.subtitleSpecialToggle.checked),
- this.player.user.set(
- "specialsubtitle",
- Number(this.specialsubtitle)
- ),
- this.player.notice(
- "特效字幕: " + (this.specialsubtitle ? "开启" : "关闭")
- ),
- this.specialsubtitle || location.reload();
- }
- ),
- this.player.events.type("subtitle_end") ||
- e.events.playerEvents.push("subtitle_end"),
- this.player.on("subtitle_end", () => {
- this.add(this.player.options.subtitles);
- }),
- this.player.on("quality_end", () => {
- this.setVideo(),
- this.player.options.subtitle.url.length &&
- this.player.options.subtitles.length
- ? this.switch(
- this.player.options.subtitles[
- this.player.options.subtitle.index
- ]
- )
- : this.hasSubtitleDisplay ||
- ((this.hasSubtitleDisplay = !0),
- this.player.events.trigger("subtitle_start"));
- }),
- this.player.on("episode_end", () => {
- (this.hasSubtitleTrack = !1),
- (this.hasSubtitleDisplay = !1),
- this.clear();
- }),
- this.player.template.mask.addEventListener("click", () => {
- this.hide();
- }),
- (this.player.template.subtitleSettingBox = t.append(
- this.player.template.controller,
- '<div class="dplayer-icons dplayer-comment-box subtitle-setting-box" style="bottom: 10px;left: auto;right: 400px !important;display: block;"><div class="dplayer-comment-setting-box"><div class="dplayer-comment-setting-color"><div class="dplayer-comment-setting-title">字幕颜色<button type="text" class="color-custom" style="line-height: 16px;font-size: 12px;top: 12px;right: 12px;color: #fff;background: rgba(28, 28, 28, 0.9);position: absolute;">自定义</button></div><label><input type="radio" name="dplayer-danmaku-color-1" value="#fff"><span style="background: #fff;"></span></label><label><input type="radio" name="dplayer-danmaku-color-1" value="#e54256"><span style="background: #e54256"></span></label><label><input type="radio" name="dplayer-danmaku-color-1" value="#ffe133"><span style="background: #ffe133"></span></label><label><input type="radio" name="dplayer-danmaku-color-1" value="#64DD17"><span style="background: #64DD17"></span></label><label><input type="radio" name="dplayer-danmaku-color-1" value="#39ccff"><span style="background: #39ccff"></span></label><label><input type="radio" name="dplayer-danmaku-color-1" value="#D500F9"><span style="background: #D500F9"></span></label></div><div class="dplayer-comment-setting-type"><div class="dplayer-comment-setting-title">字幕位置</div><label><input type="radio" name="dplayer-danmaku-type-1" value="1"><span>上移</span></label><label><input type="radio" name="dplayer-danmaku-type-1" value="0"><span>默认</span></label><label><input type="radio" name="dplayer-danmaku-type-1" value="2"><span>下移</span></label></div><div class="dplayer-comment-setting-type"><div class="dplayer-comment-setting-title">字幕大小</div><label><input type="radio" name="dplayer-danmaku-type-1" value="1"><span>加大</span></label><label><input type="radio" name="dplayer-danmaku-type-1" value="0"><span>默认</span></label><label><input type="radio" name="dplayer-danmaku-type-1" value="2"><span>减小</span></label></div><div class="dplayer-comment-setting-type"><div class="dplayer-comment-setting-title">字幕偏移<div style="margin-top: -30px;right: 14px;position: absolute;">偏移量<input type="number" class="subtitle-offset-step" style="height: 14px;width: 50px;margin-left: 4px;border: 1px solid #fff;border-radius: 3px;color: #fff;background: rgba(28, 28, 28, 0.9);text-align: center;" value="1" step="1" min="1"></div></div><label><input type="radio" name="dplayer-danmaku-type-1" value="1"><span>前移</span></label><label><span><input type="text" class="subtitle-offset" style="width: 94%;height: 14px;background: rgba(28, 28, 28, 0.9);border: 0px solid #fff;text-align: center;" value="0" title="双击恢复默认"></span></label><label><input type="radio" name="dplayer-danmaku-type-1" value="2"><span>后移</span></label></div><div class="dplayer-comment-setting-type"><div class="dplayer-comment-setting-title">更多字幕功能</div><label><input type="radio" name="dplayer-danmaku-type-1" value="1"><span>本地字幕</span></label><label><input type="radio" name="dplayer-danmaku-type-1" value="0"><span>待定</span></label><label><input type="radio" name="dplayer-danmaku-type-1" value="2"><span>待定</span></label></div></div></div>'
- )),
- (this.player.template.subtitleCommentSettingBox = t.query(
- ".dplayer-comment-setting-box",
- this.player.template.subtitleSettingBox
- )),
- (this.player.template.subtitleSetting = t.append(
- t.query(
- ".dplayer-setting-origin-panel",
- this.player.template.settingBox
- ),
- '<div class="dplayer-setting-item dplayer-setting-subtitle"><span class="dplayer-label">字幕设置</span><div class="dplayer-toggle"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 32 32"><path d="M22 16l-10.105-10.6-1.895 1.987 8.211 8.613-8.211 8.612 1.895 1.988 8.211-8.613z"></path></svg></div></div>'
- )),
- this.player.template.subtitleSetting.addEventListener(
- "click",
- () => {
- this.toggle();
- }
- ),
- (this.player.template.subtitleColorPicker = t.append(
- this.player.template.container,
- '<input type="color" id="colorPicker">'
- )),
- (this.player.template.subtitleColorCustom = t.query(
- ".color-custom",
- this.player.template.subtitleCommentSettingBox
- )),
- this.player.template.subtitleColorCustom.addEventListener(
- "click",
- () => {
- (this.player.template.subtitleColorPicker.value = this.color),
- this.player.template.subtitleColorPicker.click();
- }
- ),
- this.player.template.subtitleColorPicker.addEventListener(
- "input",
- (e) => {
- const t = e.target.value;
- (this.color = this.fromQColor(t)),
- this.player.notice(`设置字幕颜色: ${this.color}`),
- this.setStyle({ PrimaryColour: this.color });
- }
- ),
- (this.player.template.subtitleSettingColor = t.query(
- ".dplayer-comment-setting-color",
- this.player.template.subtitleCommentSettingBox
- )),
- this.player.template.subtitleSettingColor.addEventListener(
- "click",
- (e) => {
- if ("INPUT" === e.target.nodeName) {
- const t = e.target.value;
- (this.color = this.fromQColor(t)),
- this.player.notice(`设置字幕颜色: ${this.color}`),
- this.setStyle({ PrimaryColour: this.color });
- }
- }
- ),
- (this.player.template.subtitleSettingItem = t.queryAll(
- ".dplayer-comment-setting-type",
- this.player.template.subtitleCommentSettingBox
- )),
- this.player.template.subtitleSettingItem[0].addEventListener(
- "click",
- (e) => {
- "INPUT" === e.target.nodeName &&
- ("1" == e.target.value
- ? (this.bottom += 1)
- : "2" == e.target.value
- ? (this.bottom -= 1)
- : (this.bottom = 10),
- this.player.notice(`设置字幕位置: ${this.bottom}`),
- this.setStyle({ MarginV: this.bottom }));
- }
- ),
- this.player.template.subtitleSettingItem[1].addEventListener(
- "click",
- (e) => {
- "INPUT" === e.target.nodeName &&
- ("1" == e.target.value
- ? (this.fontSize += 1)
- : "2" == e.target.value
- ? (this.fontSize -= 1)
- : (this.fontSize = 20),
- this.player.notice(`设置字幕大小: ${this.fontSize}`),
- this.setStyle({ FontSize: this.fontSize }));
- }
- ),
- (this.player.template.subtitleOffsetStep = t.query(
- ".subtitle-offset-step",
- this.player.template.subtitleSettingItem[2]
- )),
- this.player.template.subtitleOffsetStep.addEventListener(
- "input",
- (e) => {
- this.offsetStep = 1 * e.target.value;
- }
- ),
- (this.player.template.subtitleOffset = t.query(
- ".subtitle-offset",
- this.player.template.subtitleSettingItem[2]
- )),
- this.player.template.subtitleOffset.addEventListener(
- "input",
- (e) => {
- (this.offset = 1 * e.target.value), this.subtitleOffset();
- }
- ),
- this.player.template.subtitleOffset.addEventListener(
- "dblclick",
- (e) => {
- 0 != this.offset &&
- ((this.offset = 0),
- (e.target.value = 0),
- this.player.notice(`设置字幕偏移: ${this.offset}`),
- this.timeOffset());
- }
- ),
- this.player.template.subtitleSettingItem[2].addEventListener(
- "click",
- (e) => {
- if (
- "INPUT" === e.target.nodeName &&
- "radio" === e.target.type
- ) {
- let t = (this.player.template.subtitleOffset.value *= 1);
- "1" == e.target.value
- ? (t += this.offsetStep || 1)
- : "2" == e.target.value
- ? (t -= this.offsetStep || 1)
- : (t = 0),
- (this.offset = t),
- (this.player.template.subtitleOffset.value = t),
- this.player.notice(`设置字幕偏移: ${this.offset}`),
- this.timeOffset();
- }
- }
- ),
- (this.player.template.subtitleLocalFile = t.append(
- this.player.template.container,
- '<input class="subtitleLocalFile" type="file" accept="webvtt,.vtt,.srt,.ssa,.ass" style="display: none;">'
- )),
- this.player.template.subtitleSettingItem[3].addEventListener(
- "click",
- (e) => {
- "INPUT" === e.target.nodeName &&
- "1" == e.target.value &&
- (this.player.template.subtitleLocalFile.click(), this.hide());
- }
- ),
- this.player.template.subtitleLocalFile.addEventListener(
- "change",
- (e) => {
- if (e.target.files.length) {
- const t = e.target.files[0],
- s = t.name.split(".").pop().toLowerCase();
- this.blobToText(t).then((e) => {
- let t = { stext: e, sext: s, name: "本地字幕" };
- this.add([t]), this.switch(t);
- });
- }
- e.target.value = "";
- }
- ),
- this.player.events.trigger("subtitle_start"),
- this.player.on("destroy", () => {
- this.destroy();
- }));
- }
- add(e) {
- if (!Array.isArray(e) || !e.length) return;
- if (
- !this.player.template.subtitlesBox ||
- !this.player.template.subtitlesItem.length
- )
- return;
- this.player.template.subtitlesBoxPanel ||
- (this.player.template.subtitlesBoxPanel =
- this.player.template.subtitlesBox.querySelector(
- ".dplayer-subtitles-panel"
- ));
- const t = this.player.template.subtitlesItem.length - 1;
- if (
- (e.forEach((e, s) => {
- const i = t + s;
- this.player.options.subtitle.url.splice(i, 0, e);
- let a = document.createElement("div");
- a.setAttribute("class", "dplayer-subtitles-item"),
- (a.innerHTML =
- '<span class="dplayer-label">' +
- e.name +
- " " +
- (e.language || e.lang || "") +
- "</span>"),
- this.player.template.subtitlesBoxPanel.insertBefore(
- a,
- this.player.template.subtitlesBoxPanel.childNodes[i]
- ),
- a.addEventListener("click", (t) => {
- this.player.subtitles.hide(),
- this.player.options.subtitle.index !== i + 1 &&
- ((this.player.options.subtitle.index = i + 1),
- this.switch(e));
- });
- }),
- (this.player.template.subtitlesItem =
- this.player.template.subtitlesBoxPanel.querySelectorAll(
- ".dplayer-subtitles-item"
- )),
- !this.hasSubtitleTrack)
- ) {
- (this.hasSubtitleTrack = !0),
- this.player.template.subtitlesItem[
- this.player.template.subtitlesItem.length - 1
- ].addEventListener("click", (e) => {
- this.subContainerHide();
- });
- let e = this.player.options.subtitles.findIndex((e) =>
- ["cho", "zhi"].includes(e.language)
- );
- e < 0 && (e = 0),
- this.init(this.player.options.subtitle.url[e]),
- (this.player.options.subtitle.index = e + 1);
- }
- }
- init(e) {
- return this.initLibass()
- .then(() =>
- this.urlToText(e).then(
- (e) => (
- ["ass", "ssa"].includes(e.sext) ||
- Object.assign(e, {
- stext: this.toAss(e.stext, e.sext),
- sext: "ass",
- }),
- this.switchContent(e.stext),
- this.subContainerShow(),
- e
- )
- )
- )
- .catch((e) => {
- console.error("加载特效字幕组件 错误!", e);
- });
- }
- switch(e = {}) {
- return this.init(e).then(() => {
- e.name && this.player.notice(`切换字幕: ${e.name}`);
- });
- }
- clear() {
- (this.player.options.subtitles = []),
- (this.player.options.subtitle.url = []);
- for (let e = this.player.template.subtitlesItem.length - 2; e >= 0; e--)
- this.player.template.subtitlesBoxPanel.removeChild(
- this.player.template.subtitlesItem[e]
- );
- (this.player.template.subtitlesItem =
- this.player.template.subtitlesBoxPanel.querySelectorAll(
- ".dplayer-subtitles-item"
- )),
- this.destroy();
- }
- toggle() {
- this.player.template.subtitleCommentSettingBox.classList.contains(
- "dplayer-comment-setting-open"
- )
- ? this.hide()
- : this.show();
- }
- show() {
- this.player.template.subtitleCommentSettingBox.classList.add(
- "dplayer-comment-setting-open"
- ),
- this.player.template.mask.classList.add("dplayer-mask-show");
- }
- hide() {
- this.player.template.subtitleCommentSettingBox.classList.remove(
- "dplayer-comment-setting-open"
- ),
- this.player.template.settingBox.classList.remove(
- "dplayer-setting-box-open"
- ),
- this.player.template.mask.classList.remove("dplayer-mask-show");
- }
- initLibass() {
- if (this.libass) return Promise.resolve(this.libass);
- const e = {
- video: this.player.template.video,
- subContent: "[Script Info]\nScriptType: v4.00+",
- subUrl: "",
- availableFonts: {
- "思源黑体 cn bold":
- "https://cdn.jsdelivr.net/gh/tampermonkeyStorage/Self-use@main/Fonts/SourceHanSansCN-Bold.woff2",
- },
- };
- return this.getLocalFonts().then(
- (t) => {
- const s = t.filter((e) => e.fullName.match(/[\u4e00-\u9fa5]/)),
- i =
- s.find((e) => ["微软雅黑"].some((t) => e?.fullName === t))
- ?.fullName || s.sort(() => 0.5 - Math.random())[0]?.fullName;
- return (
- Object.assign(e, { useLocalFonts: !0, fallbackFont: i }),
- this.loadLibass(e)
- );
- },
- () =>
- this.getDbFonts().then((t) => {
- (t || []).forEach(({ fullName: t, font: s }) => {
- e.availableFonts[t] = s;
- });
- const s =
- Object.keys(e.availableFonts).find((e) =>
- ["思源黑体 cn bold"].some((t) => t === e)
- ) ||
- Object.keys(e.availableFonts)
- .filter((e) => e.match(/[\u4e00-\u9fa5]/))
- .filter(Boolean)
- .sort(() => 0.5 - Math.random())[0];
- return Object.assign(e, { fallbackFont: s }), this.loadLibass(e);
- })
- );
- }
- loadLibass(e) {
- let t =
- "https://registry.npmmirror.com/jassub/1.7.15/files/dist/jassub.umd.js";
- return this.loadJs(t).then(
- () => (
- Object.assign(e, {
- workerUrl: new URL("jassub-worker.js", t).href,
- wasmUrl: new URL("jassub-worker.wasm", t).href,
- legacyWorkerUrl: new URL("jassub-worker.wasm.js", t).href,
- modernWasmUrl: new URL("jassub-worker-modern.wasm", t).href,
- }),
- this.loadWorker(e).then(
- (t) => (
- (e.workerUrl = t),
- (this.libass = new unsafeWindow.JASSUB(e)),
- this.libass
- )
- )
- )
- );
- }
- loadWorker({ workerUrl: e }) {
- return fetch(e)
- .then((e) => e.text())
- .then((e) => {
- const t = new Blob([e], { type: "text/javascript" }),
- s = URL.createObjectURL(t);
- return (
- setTimeout(() => {
- URL.revokeObjectURL(s);
- }),
- s
- );
- });
- }
- setVideo(e) {
- this.libass && this.libass.setVideo(e || this.player.template.video);
- }
- switchContent(e) {
- this.libass && e && (this.libass.freeTrack(), this.libass.setTrack(e));
- }
- subContainerShow() {
- this.libass &&
- (((
- this.libass.canvasParent || this.libass._canvasParent
- ).style.display = "block"),
- this.libass.resize());
- }
- subContainerHide() {
- this.libass &&
- ((
- this.libass.canvasParent || this.libass._canvasParent
- ).style.display = "none");
- }
- timeOffset(e) {
- this.libass && (this.libass.timeOffset = e || this.offset);
- }
- getStyles(e) {
- this.libass
- ? this.libass.getStyles((t, s) => {
- e && e(s || t);
- })
- : e && e("");
- }
- setStyle(e, t = 1) {
- this.libass && this.libass.setStyle(e, t);
- }
- destroy() {
- this.libass &&
- (this.libass.destroy && this.libass.destroy(),
- this.libass.dispose && this.libass.dispose(),
- (this.libass = null));
- }
- getLocalFonts(e) {
- if (unsafeWindow.queryLocalFonts) {
- const t = {};
- return (
- e && (t.postscriptNames = Array.isArray(e) ? e : [e]),
- unsafeWindow
- .queryLocalFonts(t)
- .then((e) => (e && e.length ? e : Promise.reject()))
- );
- }
- return console.warn("Not Local fonts API"), Promise.reject();
- }
- getDbFonts(e) {
- const t = window.localforage || unsafeWindow.localforage;
- return t.getItem("local-fonts").then((s) => {
- if (Array.isArray(s) && s.length)
- return Array.isArray(e)
- ? s.filter(({ fullName: t }) => e.some((e) => e === t))
- : s;
- let i = [
- {
- fullName: "思源黑体 cn bold",
- url: "https://cdn.jsdelivr.net/gh/tampermonkeyStorage/Self-use@main/Fonts/SourceHanSansCN-Bold.woff2",
- },
- ];
- Array.isArray(e) &&
- (i = i.filter(({ fullName: t }) => e.some((e) => e === t)));
- const a = [];
- return (
- i.forEach(({ url: e }) => {
- e &&
- a.push(
- fetch(e).then((e) =>
- e.ok ? e.arrayBuffer() : Promise.reject()
- )
- );
- }),
- Promise.allSettled(a).then(
- (e) => (
- e.forEach(({ status: e, value: t }, s) => {
- "fulfilled" == e &&
- t?.byteLength &&
- Object.assign(i[s], { font: new Uint8Array(t) });
- }),
- t.setItem(
- "local-fonts",
- (s || []).concat(i.filter(({ font: e }) => e))
- )
- )
- )
- );
- });
- }
- toAss(e, t) {
- const s = "ass" === t || "ssa" === t ? e : "";
- if (s) return s;
- const i =
- /(?:\d+\n)?(\d{0,2}:?\d{2}:\d{2}.\d{3})\s?-?->\s?(\d{0,2}:?\d{2}:\d{2}.\d{3})(.*)\n([\s\S]*)$/i,
- a = (e) => {
- const t = [],
- s = e.replace(/\r/g, ""),
- a = /(\d{0,2})?:?(\d{2}):(\d{2}.\d{3})/;
- for (const e of s.split("\n\n")) {
- const s = e.match(i);
- if (s) {
- (s[1] = s[1].replace(
- a,
- (e, t, s, i) =>
- (t || "0") +
- ":" +
- s +
- ":" +
- i.match(/\d{2}.\d{2}/)[0].replace(",", ".")
- )),
- (s[2] = s[2].replace(
- a,
- (e, t, s, i) =>
- (t || "0") +
- ":" +
- s +
- ":" +
- i.match(/\d{2}.\d{2}/)[0].replace(",", ".")
- ));
- const e = s[4].match(/<[^>]+>/g);
- e &&
- e.forEach((e) => {
- /<\//.test(e)
- ? (s[4] = s[4].replace(
- e,
- e.replace("</", "{\\").replace(">", "0}")
- ))
- : (s[4] = s[4].replace(
- e,
- e.replace("<", "{\\").replace(">", "1}")
- ));
- }),
- t.push(
- "Dialogue: 0," +
- s[1] +
- "," +
- s[2] +
- ",Default,,0,0,0,," +
- s[4].replace(/\n/g, "\\N")
- );
- }
- }
- return t.join("\n");
- },
- l = {
- scriptInfo: {
- Title: "untitled",
- ScriptType: "v4.00+",
- Collisions: "Normal",
- PlayDepth: 0,
- Timer: "100,0000",
- PlayResX: "",
- PlayResY: "",
- WrapStyle: 0,
- ScaledBorderAndShadow: "no",
- },
- v4Styles: [
- {
- Name: "Default",
- Fontname: "Default",
- Fontsize: 20,
- PrimaryColour: "&H00FFFFFF",
- SecondaryColour: "&H00FFFFFF",
- OutlineColour: "&H00000000",
- BackColour: "&H00000000",
- Bold: -1,
- Italic: 0,
- Underline: 0,
- StrikeOut: 0,
- ScaleX: 100,
- ScaleY: 100,
- Spacing: 0,
- Angle: 0,
- BorderStyle: 1,
- Outline: 1,
- Shadow: 0,
- Alignment: 2,
- MarginL: 10,
- MarginR: 10,
- MarginV: 10,
- Encoding: 1,
- },
- ],
- },
- r = ["[Script Info]"];
- for (let [e, t] of Object.entries(l.scriptInfo)) r.push(e + ": " + t);
- r.push(""),
- r.push("[V4+ Styles]"),
- r.push(
- "Format: Name,Fontname,Fontsize,PrimaryColour,SecondaryColour,OutlineColour,BackColour,Bold,Italic,Underline,StrikeOut,ScaleX,ScaleY,Spacing,Angle,BorderStyle,Outline,Shadow,Alignment,MarginL,MarginR,MarginV,Encoding"
- ),
- l.v4Styles.forEach((e) => {
- "object" == typeof e
- ? r.push("Style: " + Object.values(e).join(","))
- : "string" == typeof e && r.push(e);
- }),
- r.push(""),
- r.push("[Events]"),
- r.push(
- "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text"
- ),
- r.push("");
- const n = r.join("\n");
- switch (t) {
- case "vtt":
- case "srt":
- return n + a(e);
- case "ssa":
- case "ass":
- return s;
- default:
- return i.test(e) ? n + a(e) : "";
- }
- }
- urlToText(e) {
- if (e.stext) return Promise.resolve(e);
- {
- e.sext || (e.sext = e.file_extension);
- const t = e.url || e.download_url || e.uri || e.surl;
- return this.requestFile(t).then((t) => ((e.stext = t), e));
- }
- }
- requestFile(e) {
- return fetch(e, {
- referrer: location.protocol + "//" + location.host + "/",
- referrerPolicy: "origin",
- body: null,
- method: "GET",
- mode: "cors",
- credentials: "omit",
- })
- .then((e) => e.blob())
- .then((e) => this.blobToText(e));
- }
- blobToText(e) {
- return new Promise(function (t, s) {
- var i = new FileReader();
- i.readAsText(e, "UTF-8"),
- (i.onload = function (s) {
- var a = i.result;
- return a.indexOf("�") > -1 && !i.markGBK
- ? ((i.markGBK = !0), i.readAsText(e, "GBK"))
- : a.indexOf("") > -1 && !i.markBIG5
- ? ((i.markBIG5 = !0), i.readAsText(e, "BIG5"))
- : void t(a);
- }),
- (i.onerror = function (e) {
- s(e);
- });
- });
- }
- fromQColor(e, t = !1) {
- e = e.replace(
- /^#?([a-f\d])([a-f\d])([a-f\d])$/i,
- (e, t, s, i) => t + t + s + s + i + i
- );
- const [s, i, a, l] = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(
- e
- );
- return t
- ? (((-1 + i) & 255) << 24) |
- (((-1 + a) & 255) << 16) |
- (((-1 + l) & 255) << 8) |
- 0
- : (("0x" + i) << 24) | (("0x" + a) << 16) | (("0x" + l) << 8) | 0;
- }
- },
- class Appreciation {
- constructor(e, t) {
- (this.player = e),
- (this.now = Date.now()),
- (this.localforage = window.localforage || unsafeWindow.localforage);
- const {
- contextmenu: s,
- container: { offsetWidth: i, offsetHeight: a },
- } = this.player;
- this.player.template.menuItem[0].addEventListener("click", () => {
- this.showDialog();
- }),
- this.player.on("timeupdate", () => {
- Date.now() - 24e4 >= this.now &&
- ((this.now = Date.now()),
- this.isAppreciation()
- .then((e) => {
- this.player.plugins.hls.data = !!e;
- })
- .catch((e) => {
- this.player.pause(),
- s.show(i / 2.5, a / 3),
- (s.shown = !0),
- !this.player.plugins.hls.data &&
- confirm("请赞赏后继续观赏") &&
- ((this.player.plugins.hls.data = !0), this.showDialog()),
- (this.player.plugins.hls.error = !!e);
- }));
- }),
- this.player.template.settingBox.addEventListener("click", (e) => {
- this.isAppreciation().catch((t) => {
- let s =
- e.target.querySelector("input") ||
- e.target.parentNode.querySelector("input");
- s && s.checked && e.target.click(),
- this.player.template.mask.click(),
- e.isTrusted && this.showDialog();
- });
- });
- }
- isAppreciation() {
- return (
- (this.player.template.menuItem =
- this.player.container.querySelectorAll(".dplayer-menu-item")),
- this.player.template.menu.innerHTML.includes(5254001) ||
- 4 === this.player.template.menuItem.length ||
- this.player.destroy(),
- this.localforage || this.player.destroy(),
- GM_getValue || GM_setValue || GM_deleteValue || this.player.destroy(),
- this.localforage
- .getItem("users")
- .then((e) =>
- e?.expire_time
- ? this.localforage
- .getItem("users_sign")
- .then((t) =>
- Math.max(Date.parse(e.expire_time) - Date.now(), 0) &&
- t === btoa(encodeURIComponent(JSON.stringify(e))) &&
- GM_getValue("users_sign") ===
- btoa(encodeURIComponent(JSON.stringify(e)))
- ? e
- : this.usersPost().then((e) =>
- Math.max(Date.parse(e?.expire_time) - Date.now(), 0)
- ? this.localforage
- .setItem("users", e)
- .then(
- (e) => (
- this.localforage.setItem(
- "users_sign",
- btoa(
- encodeURIComponent(JSON.stringify(e))
- )
- ),
- GM_setValue(
- "users_sign",
- btoa(
- encodeURIComponent(JSON.stringify(e))
- )
- ),
- e
- )
- )
- : (this.localforage.removeItem("users"),
- this.localforage.removeItem("users_sign"),
- GM_deleteValue("users_sign"),
- Promise.reject())
- )
- )
- : GM_getValue("users_sign")
- ? this.localforage
- .setItem("users", { expire_time: new Date().toISOString() })
- .then(() => this.isAppreciation())
- : (GM_setValue("users_sign", 0), Promise.reject())
- )
- );
- }
- showDialog() {
- let e = document.createElement("div");
- (e.innerHTML =
- '<div class="ant-modal-mask"></div><div tabindex="-1" class="ant-modal-wrap" role="dialog" aria-labelledby="rcDialogTitle1" style=""><div role="document" class="ant-modal modal-wrapper--5SA7y" style="width: 340px;"><div tabindex="0" aria-hidden="true" style="width: 0px; height: 0px; overflow: hidden; outline: none;"></div><div class="ant-modal-content"><div class="ant-modal-header"><div class="ant-modal-title" id="rcDialogTitle1">请少量赞助以支持我更好的创作</div></div><div class="ant-modal-body"><div class="content-wrapper--S6SNu"><div>爱发电订单号:</div><span class="ant-input-affix-wrapper ant-input-affix-wrapper-borderless ant-input-password input--TWZaN input--l14Mo"><input placeholder="" action="click" type="text" class="afdian-order ant-input ant-input-borderless" style="background-color: var(--divider_tertiary);"></span></div><div class="content-wrapper--S6SNu"><div>请输入爱发电订单号,确认即可</div><a href="https://afdian.net/order/create?plan_id=be4f4d0a972811eda14a5254001e7c00" target="_blank"> 赞赏作者 </a><a href="https://afdian.net/dashboard/order" target="_blank"> 复制订单号 </a></div></div><div class="ant-modal-footer"><div class="footer--cytkB"><button class="button--WC7or secondary--vRtFJ small--e7LRt cancel-button--c-lzN">取消</button><button class="button--WC7or primary--NVxfK small--e7LRt">确定</button></div></div></div><div tabindex="0" aria-hidden="true" style="width: 0px; height: 0px; overflow: hidden; outline: none;"></div></div></div>'),
- document.body.insertBefore(e, null),
- e.querySelectorAll("button").forEach((t, s) => {
- t.addEventListener("click", () => {
- if (0 == s) document.body.removeChild(e);
- else {
- let t = e.querySelector("input").value;
- if (t)
- if (t.match(/^202[\d]{22,25}$/)) {
- if (t.match(/(\d)\1{8,}/g)) return;
- this.localforage
- .getItem("users")
- .then((e) => {
- (e && e.ON == t) ||
- this.onPost(t).catch(() => {
- alert("网络错误,请稍后再次提交");
- });
- })
- .catch(function (e) {
- alert(e);
- });
- } else alert("订单号不合规范,请重试");
- document.body.removeChild(e);
- }
- });
- });
- }
- onPost(e) {
- return this.usersPost().then(
- (t) => (
- 0 === Date.parse(t.expire_time) ||
- this.localforage
- .setItem(
- "users",
- Object.assign(t || {}, {
- expire_time: new Date(Date.now() + 864e3).toISOString(),
- })
- )
- .then((e) => {
- this.localforage.setItem(
- "users_sign",
- btoa(encodeURIComponent(JSON.stringify(e)))
- ),
- GM_setValue(
- "users_sign",
- btoa(encodeURIComponent(JSON.stringify(e)))
- );
- }),
- this.infoPost(t, e)
- )
- );
- }
- usersPost() {
- return this.users(this.getItem("token"));
- }
- users(e) {
- return this.ajax({
- url: "https://sxxf4ffo.lc-cn-n1-shared.com/1.1/users",
- data: JSON.stringify({
- authData: {
- aliyundrive: Object.assign(e, {
- uid: e?.user_id,
- scriptHandler: GM_info?.scriptHandler,
- version: GM_info?.script?.version,
- }),
- },
- }),
- });
- }
- infoPost(e, t) {
- return (
- delete e.createdAt,
- delete e.updatedAt,
- delete e.objectId,
- this.ajax({
- url: "https://sxxf4ffo.lc-cn-n1-shared.com/1.1/classes/aliyundrive",
- data: JSON.stringify(Object.assign(e, { ON: t })),
- })
- );
- }
- ajax(e) {
- return new Promise(function (t, s) {
- GM_xmlhttpRequest
- ? GM_xmlhttpRequest({
- method: "post",
- headers: {
- "Content-Type": "application/json",
- "X-LC-Id": "sXXf4FFOZn2nFIj7LOFsqpLa-gzGzoHsz",
- "X-LC-Key": "16s3qYecpVJXtVahasVxxq1V",
- },
- responseType: "json",
- onload: function (e) {
- if (2 == parseInt(e.status / 100)) {
- var i = e.response || e.responseText;
- t(i);
- } else s(e);
- },
- onerror: function (e) {
- s(e);
- },
- ...e,
- })
- : s();
- });
- }
- getItem(e) {
- if (!(e = localStorage.getItem(e))) return null;
- try {
- return JSON.parse(e);
- } catch (t) {
- return e;
- }
- }
- setItem(e, t) {
- e &&
- null != t &&
- localStorage.setItem(e, t instanceof Object ? JSON.stringify(t) : t);
- }
- removeItem(e) {
- null != e && localStorage.removeItem(e);
- }
- },
- class DoHotKey {
- constructor(e) {
- (this.player = e),
- this.player.template.videoWrap.addEventListener("dblclick", (e) => {
- this.player.fullScreen.toggle();
- }),
- document.addEventListener("wheel", (e) => {
- if (this.player.focus) {
- e = e || window.event;
- var t,
- s = this.player;
- e.deltaY < 0
- ? ((t = s.volume() + 0.01), s.volume(t))
- : e.deltaY > 0 && ((t = s.volume() - 0.01), s.volume(t));
- }
- });
- }
- },
- ]);