UNPKG

@oplayer/danmuku

Version:

Danmuku plugin for oplayer

349 lines (347 loc) 15 kB
import { $ as g } from "@oplayer/core"; function k(r) { switch (r) { case 1: case 2: case 3: return 0; case 4: case 5: return 1; default: return 0; } } function x(r) { const t = r.matchAll(/<d (?:.*? )??p="(?<p>.+?)"(?: .*?)?>(?<text>.+?)<\/d>/gs); return Array.from(t).reduce((e, o) => { var a, s, h, u; const i = (s = (a = o.groups) == null ? void 0 : a.p) == null ? void 0 : s.split(","), p = (u = (h = o.groups) == null ? void 0 : h.text) == null ? void 0 : u.trim(); return i && i.length >= 8 && p ? e.concat({ text: p.replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&"), time: Number(i[0]), mode: k(Number(i[1])), fontSize: Number(i[2]), color: `#${Number(i[3]).toString(16)}`, timestamp: Number(i[4]), pool: Number(i[5]), userID: i[6], rowID: Number(i[7]) }) : e; }, []); } function W(r) { return fetch(r).then((t) => t.text()).then((t) => x(t)); } function $({ target: r, emits: t, clientWidth: e, clientHeight: o, marginBottom: i, marginTop: p, antiOverlap: a }) { var u, m; const s = t.filter((n) => n.mode === r.mode && n.top <= o - i).sort((n, c) => n.top - c.top); if (s.length === 0) return p; s.unshift({ top: 0, left: 0, right: 0, height: p, width: e, speed: 0, distance: e }), s.push({ top: o - i, left: 0, right: 0, height: i, width: e, speed: 0, distance: e }); for (let n = 1; n < s.length; n += 1) { const c = s[n], l = s[n - 1], f = l.top + l.height; if (c.top - f >= r.height) return f; } const h = []; for (let n = 1; n < s.length - 1; n += 1) { const c = s[n]; if (h.length) { const l = h[h.length - 1]; l[0].top === c.top ? l.push(c) : h.push([c]); } else h.push([c]); } if (a) switch (r.mode) { case 0: { const n = h.find((c) => c.every((l) => e < l.distance ? !1 : r.speed < l.speed || l.right / (r.speed - l.speed) > l.time)); return n && n[0] ? n[0].top : -1; } case 1: return -1; default: return -1; } else { switch (r.mode) { case 0: h.sort((n, c) => { const l = Math.min(...c.map((d) => d.right)), f = Math.min(...n.map((d) => d.right)); return l * c.length - f * n.length; }); break; case 1: h.sort((n, c) => { const l = Math.max(...c.map((d) => d.width)); return Math.max(...n.map((d) => d.width)) * n.length - l * c.length; }); break; } return ((m = (u = h[0]) == null ? void 0 : u[0]) == null ? void 0 : m.top) || -1; } } const y = "KGZ1bmN0aW9uKCl7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIGEoe3RhcmdldDpuLGVtaXRzOmcsY2xpZW50V2lkdGg6cCxjbGllbnRIZWlnaHQ6dSxtYXJnaW5Cb3R0b206ZixtYXJnaW5Ub3A6YyxhbnRpT3ZlcmxhcDptfSl7dmFyIGwsZDtjb25zdCBvPWcuZmlsdGVyKGU9PmUubW9kZT09PW4ubW9kZSYmZS50b3A8PXUtZikuc29ydCgoZSx0KT0+ZS50b3AtdC50b3ApO2lmKG8ubGVuZ3RoPT09MClyZXR1cm4gYztvLnVuc2hpZnQoe3RvcDowLGxlZnQ6MCxyaWdodDowLGhlaWdodDpjLHdpZHRoOnAsc3BlZWQ6MCxkaXN0YW5jZTpwfSksby5wdXNoKHt0b3A6dS1mLGxlZnQ6MCxyaWdodDowLGhlaWdodDpmLHdpZHRoOnAsc3BlZWQ6MCxkaXN0YW5jZTpwfSk7Zm9yKGxldCBlPTE7ZTxvLmxlbmd0aDtlKz0xKXtjb25zdCB0PW9bZV0scz1vW2UtMV0saD1zLnRvcCtzLmhlaWdodDtpZih0LnRvcC1oPj1uLmhlaWdodClyZXR1cm4gaH1jb25zdCByPVtdO2ZvcihsZXQgZT0xO2U8by5sZW5ndGgtMTtlKz0xKXtjb25zdCB0PW9bZV07aWYoci5sZW5ndGgpe2NvbnN0IHM9cltyLmxlbmd0aC0xXTtzWzBdLnRvcD09PXQudG9wP3MucHVzaCh0KTpyLnB1c2goW3RdKX1lbHNlIHIucHVzaChbdF0pfWlmKG0pc3dpdGNoKG4ubW9kZSl7Y2FzZSAwOntjb25zdCBlPXIuZmluZCh0PT50LmV2ZXJ5KHM9PnA8cy5kaXN0YW5jZT8hMTpuLnNwZWVkPHMuc3BlZWR8fHMucmlnaHQvKG4uc3BlZWQtcy5zcGVlZCk+cy50aW1lKSk7cmV0dXJuIGUmJmVbMF0/ZVswXS50b3A6LTF9Y2FzZSAxOnJldHVybi0xO2RlZmF1bHQ6cmV0dXJuLTF9ZWxzZXtzd2l0Y2gobi5tb2RlKXtjYXNlIDA6ci5zb3J0KChlLHQpPT57Y29uc3Qgcz1NYXRoLm1pbiguLi50Lm1hcChpPT5pLnJpZ2h0KSksaD1NYXRoLm1pbiguLi5lLm1hcChpPT5pLnJpZ2h0KSk7cmV0dXJuIHMqdC5sZW5ndGgtaCplLmxlbmd0aH0pO2JyZWFrO2Nhc2UgMTpyLnNvcnQoKGUsdCk9Pntjb25zdCBzPU1hdGgubWF4KC4uLnQubWFwKGk9Pmkud2lkdGgpKTtyZXR1cm4gTWF0aC5tYXgoLi4uZS5tYXAoaT0+aS53aWR0aCkpKmUubGVuZ3RoLXMqdC5sZW5ndGh9KTticmVha31yZXR1cm4oKGQ9KGw9clswXSk9PW51bGw/dm9pZCAwOmxbMF0pPT1udWxsP3ZvaWQgMDpkLnRvcCl8fC0xfX1zZWxmLm9ubWVzc2FnZT0oe2RhdGE6bn0pPT57c2VsZi5wb3N0TWVzc2FnZSh7dG9wOmEobiksaWQ6bi5pZH0pfX0pKCk7Ci8vIyBzb3VyY2VNYXBwaW5nVVJMPWFzc2V0cy9kYW5tdWt1Lndvcmtlci5lNTVjMzgzYS5qcy5tYXA=", b = typeof window < "u" && window.Blob && new Blob([atob(y)], { type: "text/javascript;charset=utf-8" }); function Z() { const r = b && (window.URL || window.webkitURL).createObjectURL(b); try { return r ? new Worker(r) : new Worker("data:application/javascript;base64," + y); } finally { r && (window.URL || window.webkitURL).revokeObjectURL(r); } } const T = g.css` position: absolute; white-space: pre; pointer-events: none; perspective: 500px; will-change: transform, top; line-height: 1.125; text-shadow: rgb(0 0 0) 1px 0px 1px, rgb(0 0 0) 0px 1px 1px, rgb(0 0 0) 0px -1px 1px, rgb(0 0 0) -1px 0px 1px; `; class w { constructor(t, e) { this.player = t, this.isStop = !1, this.isHide = !1, this.timer = null, this.queue = [], this.$refs = [], this.$player = t.$root, this.$danmuku = g.create( `div.${g.css`width: 100%; height: 100%; position: absolute; left: 0; top: 0; pointer-events: none;`}` ), this.options = Object.assign( { speed: 5, color: "#fff", mode: 0, margin: [2, 2], antiOverlap: !0, useWorker: !0, synchronousPlayback: !0 }, e ), e.useWorker && (this.worker = new Z(), this.worker.addEventListener("error", (o) => { t.emit("notice", "danmuku-worker:" + o.message); })), t.on(["play", "playing"], this.start.bind(this)), t.on(["pause", "waiting"], this.stop.bind(this)), t.on(["fullscreen", "webfullscreen", "seeking"], this.reset.bind(this)), t.on("destroy", this.destroy.bind(this)), this.fetch(), g.render(this.$danmuku, this.$player); } async fetch() { try { let t = []; typeof this.options.source == "function" ? t = await this.options.source() : typeof this.options.source == "string" ? t = await W(this.options.source) : t = this.options.source, this.player.emit("loadeddanmuku", t), this.load(t); } catch (t) { throw this.player.emit("notice", { text: "danmuku: " + t.message }), t; } } load(t) { this.queue = [], this.$danmuku.innerHTML = "", t.sort((e, o) => e.time - o.time).forEach((e) => { var o; ((o = this.options) == null ? void 0 : o.filter) && this.options.filter(e) || this.queue.push({ color: this.options.color, status: "wait", $ref: null, restTime: 0, lastTime: 0, ...e }); }); } start() { this.isStop = !1, this.continue(), this.update(), this.player.emit("danmuku:start"); } update() { this.timer = window.requestAnimationFrame(async () => { var t, e; if (this.player.isPlaying && !this.isHide && this.queue.length) { this.mapping("emit", (a) => { a.restTime -= (Date.now() - a.lastTime) / 1e3, a.lastTime = Date.now(), a.restTime <= 0 && this.makeWait(a); }); const o = this.getReady(), { clientWidth: i, clientHeight: p } = this.$player; for (let a = 0; a < o.length; a++) { const s = o[a]; s.$ref = this.createItem({ text: s.text, cssText: `left: ${i}px; ${this.options.opacity ? `opacity: ${this.options.opacity};` : ""} ${this.options.fontSize ? `font-size: ${this.options.fontSize}px;` : ""} ${s.color ? `color: ${s.color};` : ""}, ${this.options.fontSize ? `font-size: ${this.options.fontSize}px;` : ""} ${s.border ? `border: 1px solid ${s.color}; background-color: rgb(0 0 0 / 50%);` : ""}` }), this.$danmuku.appendChild(s.$ref), s.lastTime = Date.now(), s.restTime = this.options.synchronousPlayback && this.player.playbackRate ? this.options.speed / this.player.playbackRate : this.options.speed; const h = this.getActiveDanmukusBoundingClientRect(), u = { mode: s.mode, height: s.$ref.clientHeight, speed: (i + s.$ref.clientWidth) / s.restTime }; await this.postMessage({ target: u, emits: h, clientWidth: i, clientHeight: p, antiOverlap: this.options.antiOverlap, marginTop: ((t = this.options.margin) == null ? void 0 : t[0]) || 0, marginBottom: ((e = this.options.margin) == null ? void 0 : e[1]) || 50 }).then(({ top: m }) => { if (!this.isStop && m != -1) switch (s.status = "emit", s.$ref.style.opacity = "1", s.$ref.style.top = `${m}px`, s.mode) { case 0: { const n = i + s.$ref.clientWidth; s.$ref.style.transform = `translate3d(${-n}px, 0, 0)`, s.$ref.style.transition = `transform ${s.restTime}s linear 0s`; break; } case 1: s.$ref.style.left = "50%", s.$ref.style.transform = "translate3d(-50%, 0, 0)"; break; } else s.status = "ready", this.$refs.push(s.$ref), s.$ref = null; }); } this.isStop || this.update(); } }); } continue() { const { clientWidth: t } = this.$player; this.mapping("stop", (e) => { switch (e.status = "emit", e.lastTime = Date.now(), e.mode) { case 0: { const o = t + e.$ref.clientWidth; e.$ref.style.transform = `translate3d(${-o}px, 0, 0)`, e.$ref.style.transition = `transform ${e.restTime}s linear 0s`; break; } } }); } suspend() { const { clientWidth: t } = this.$player; this.mapping("emit", (e) => { switch (e.status = "stop", e.mode) { case 0: { const o = t - (this.getLeft(e.$ref) - this.getLeft(this.$player)); e.$ref.style.transform = `translate3d(${-o}px, 0, 0)`, e.$ref.style.transition = "transform 0s linear 0s"; break; } } }); } mapping(t, e) { this.queue.forEach((o) => o.status === t && e(o)); } getLeft(t) { return t.getBoundingClientRect().left; } createItem({ text: t, cssText: e }) { const o = this.$refs.pop(); if (o) return o; const i = document.createElement("div"); return i.className = T, i.innerText = t, i.style.cssText = e, i; } getReady() { const { currentTime: t } = this.player; return this.queue.filter((e) => e.status === "ready" || e.status === "wait" && t + 0.1 >= e.time && e.time >= t - 0.1); } getActiveDanmukusBoundingClientRect() { const t = [], { clientWidth: e } = this.$player, o = this.getLeft(this.$player); return this.mapping("emit", (i) => { const p = i.$ref.offsetTop, a = this.getLeft(i.$ref) - o, s = i.$ref.clientHeight, h = i.$ref.clientWidth, u = a + h, m = e - u, n = u / i.restTime; t.push({ top: p, left: a, height: s, width: h, right: m, speed: n, distance: u, time: i.restTime, mode: i.mode }); }), t; } postMessage(t = {}) { return new Promise((e) => { if (this.options.useWorker && this.worker && this.worker.postMessage) t.id = Date.now(), this.worker.onmessage = ({ data: o }) => { o.id === t.id && e(o); }, this.worker.postMessage(t); else { const o = $(t); e({ top: o }); } }); } makeWait(t) { t.status = "wait", t.$ref && (t.$ref.style.opacity = "0", t.$ref.style.transform = "translate3d(0, 0, 0)", t.$ref.style.transition = "transform 0s linear 0s", this.$refs.push(t.$ref), t.$ref = null); } reset() { this.queue.forEach((t) => this.makeWait(t)); } emit(t) { this.queue.push({ ...t, status: "wait", $ref: null, restTime: 0, lastTime: 0 }); } stop() { this.isStop = !0, this.suspend(), window.cancelAnimationFrame(this.timer), this.player.emit("danmuku:stop"); } show() { this.isHide = !1, this.start(), this.$danmuku.style.display = "block", this.player.emit("danmuku:show"); } hide() { this.isHide = !0, this.stop(), this.queue.forEach((t) => this.makeWait(t)), this.$danmuku.style.display = "none", this.player.emit("danmuku:hide"); } destroy() { var t, e; this.stop(), (e = (t = this.worker) == null ? void 0 : t.terminate) == null || e.call(t), this.$danmuku.remove(), this.player.emit("danmuku:destroy"); } } const L = '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1659511978567" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2218" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M853.333333 170.666667H170.666667c-46.933333 0-85.333333 38.4-85.333334 85.333333v512c0 46.933333 38.4 85.333333 85.333334 85.333333h682.666666c46.933333 0 85.333333-38.4 85.333334-85.333333V256c0-46.933333-38.4-85.333333-85.333334-85.333333zM213.333333 512h85.333334c23.466667 0 42.666667 19.2 42.666666 42.666667s-19.2 42.666667-42.666666 42.666666H213.333333c-23.466667 0-42.666667-19.2-42.666666-42.666666s19.2-42.666667 42.666666-42.666667z m341.333334 256H213.333333c-23.466667 0-42.666667-19.2-42.666666-42.666667s19.2-42.666667 42.666666-42.666666h341.333334c23.466667 0 42.666667 19.2 42.666666 42.666666s-19.2 42.666667-42.666666 42.666667z m256 0h-85.333334c-23.466667 0-42.666667-19.2-42.666666-42.666667s19.2-42.666667 42.666666-42.666666h85.333334c23.466667 0 42.666667 19.2 42.666666 42.666666s-19.2 42.666667-42.666666 42.666667z m0-170.666667h-341.333334c-23.466667 0-42.666667-19.2-42.666666-42.666666s19.2-42.666667 42.666666-42.666667h341.333334c23.466667 0 42.666667 19.2 42.666666 42.666667s-19.2 42.666667-42.666666 42.666666z"></path></svg>', C = (r) => ({ name: "oplayer-plugin-danmuku", apply: (t) => { let e = new w(t, r); const o = () => { t.emit("addsetting", { name: "Danmuku", type: "switcher", default: !0, key: "danmuku", icon: L, onChange: (i, { isInit: p } = {}) => { i ? (!p && t.emit("notice", { text: "Show danmuku" }), e == null || e.show()) : (!p && t.emit("notice", { text: "Hide danmuku" }), e == null || e.hide()); } }); }; t.on("loadedsetting", o), t.on("danmukusourcechange", ({ payload: i }) => { t.emit("removesetting", "danmuku"), o(), e = new w(t, { ...r, ...i, source: i.source }); }), t.on("videosourcechange", function() { e == null || e.destroy(), e = null, t.emit("removesetting", "danmuku"); }); } }); export { C as default }; //# sourceMappingURL=index.es.js.map