once

once1

目前为 2025-03-26 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.gf.qytechs.cn/scripts/530899/1560245/once.js

  1. //test
  2. window.alipanArtPlugins =
  3. (function (t) {
  4. var e = {
  5. version: "1.0.3",
  6. init: (t) =>
  7. Promise.all([
  8. e.readyHls(),
  9. e.readyArtplayer(),
  10. e.readyM3u8Parser(),
  11. ]).then(() => e.initArtplayer(t)),
  12. readyHls: function () {
  13. return window.Hls || unsafeWindow.Hls
  14. ? Promise.resolve()
  15. : e.loadJs("https://unpkg.com/hls.js/dist/hls.min.js");
  16. },
  17. readyArtplayer: function () {
  18. return window.Artplayer || unsafeWindow.Artplayer
  19. ? Promise.resolve()
  20. : e.loadJs("https://unpkg.com/artplayer/dist/artplayer.js");
  21. },
  22. readyM3u8Parser: function () {
  23. return window.m3u8Parser || unsafeWindow.m3u8Parser
  24. ? Promise.resolve()
  25. : e.loadJs("https://unpkg.com/m3u8-parser/dist/m3u8-parser.min.js");
  26. },
  27. initArtplayer: function (n) {
  28. if (
  29. ((n = e.initOption(n)),
  30. !Array.isArray(n.quality) || !n.quality.find((t) => t?.url))
  31. )
  32. return (
  33. alert("获取播放信息失败,请刷新网页重试"),
  34. Promise.reject("No available playUrl")
  35. );
  36. const s = window.Artplayer || unsafeWindow.Artplayer;
  37. Object.assign(s, {
  38. PLAYBACK_RATE: [0.5, 0.75, 1, 1.25, 1.5, 2, 3, 4, 5],
  39. ASPECT_RATIO: ["default", "4:3", "16:9", "自动拉伸"],
  40. });
  41. const i = new s(n, (e) => {
  42. t.length % 8 !== t.length &&
  43. t.forEach((t) => {
  44. e.plugins.add(t());
  45. });
  46. });
  47. return Promise.resolve(i);
  48. },
  49. initOption: function (t) {
  50. const e = {
  51. container: "#artplayer",
  52. url: "",
  53. quality: [],
  54. type: "hls",
  55. autoplay: !0,
  56. autoPlayback: !0,
  57. aspectRatio: !0,
  58. contextmenu: [],
  59. customType: {
  60. hls: function (t, e, n) {
  61. const s = window.Hls || unsafeWindow.Hls;
  62. if (s.isSupported()) {
  63. n.hls && n.hls.destroy();
  64. const i = new s({ maxBufferLength: 60 });
  65. i.loadSource(e),
  66. i.attachMedia(t),
  67. (n.hls = i),
  68. n.on("destroy", () => i.destroy());
  69. } else
  70. t.canPlayType("application/vnd.apple.mpegurl")
  71. ? (t.src = e)
  72. : (n.notice.show = "Unsupported playback format: m3u8");
  73. },
  74. },
  75. flip: !0,
  76. icons: {
  77. loading:
  78. '<img src="https://artplayer.org/assets/img/ploading.gif">',
  79. state:
  80. '<img width="150" heigth="150" src="https://artplayer.org/assets/img/state.svg">',
  81. indicator:
  82. '<img width="16" heigth="16" src="https://artplayer.org/assets/img/indicator.svg">',
  83. },
  84. id: "",
  85. pip: !0,
  86. playbackRate: !0,
  87. screenshot: !0,
  88. setting: !0,
  89. subtitle: {
  90. url: "",
  91. type: "vtt",
  92. style: { color: "#fe9200", fontSize: "25px" },
  93. encoding: "utf-8",
  94. },
  95. subtitleOffset: !1,
  96. hotkey: !0,
  97. fullscreen: !0,
  98. fullscreenWeb: !0,
  99. },
  100. { video_info: n, video_file: s, video_items: i } = t || {},
  101. a = s || {},
  102. o = a.file_id;
  103. o && Object.assign(e, { file: a, id: o });
  104. const {
  105. live_transcoding_subtitle_task_list: r,
  106. live_transcoding_task_list: l,
  107. meta: c,
  108. quick_video_list: u,
  109. quick_video_subtitle_list: p,
  110. } = n?.video_preview_play_info || {},
  111. d = u || l;
  112. if (!Array.isArray(d) || !d.length) return e;
  113. {
  114. const t = {
  115. QHD: "2K 超清",
  116. QHD: "1440 超清",
  117. FHD: "1080 全高清",
  118. HD: "720 高清",
  119. SD: "540 标清",
  120. LD: "360 流畅",
  121. };
  122. d.forEach((e, n) => {
  123. Object.assign(e, {
  124. html:
  125. t[e.template_id] +
  126. (e.description ? "(三方VIP)" : e.url ? "" : "(VIP)"),
  127. type: "hls",
  128. });
  129. }),
  130. d.sort((t, e) => t.template_height - e.template_height),
  131. (d.findLast((t) => t.url).default = !0),
  132. Object.assign(e, { quality: d });
  133. }
  134. const { url: h, type: f } = d.find((t) => t.default) || d[0] || {};
  135. if (!h || !f) return e;
  136. Object.assign(e, { url: h, type: f });
  137. const m = p || r;
  138. if (Array.isArray(m) && m.length) {
  139. const t = { chi: "中文字幕", eng: "英文字幕", jpn: "日文字幕" };
  140. m.forEach(function (e, n) {
  141. Object.assign(e, {
  142. html: (t[e.language] || e.language || "未知语言") + "(vtt)",
  143. name: "内置字幕",
  144. type: "vtt",
  145. });
  146. }),
  147. ((
  148. m.find((t) => ["chi"].includes(t.language)) ||
  149. m.find((t) => t.url) ||
  150. {}
  151. ).default = !0),
  152. Object.assign(e, { subtitlelist: m });
  153. }
  154. const g = i || [];
  155. return (
  156. Array.isArray(g) &&
  157. g.length &&
  158. (((g.find((t) => t.file_id === o) || {}).default = !0),
  159. Object.assign(e, { playlist: g })),
  160. e
  161. );
  162. },
  163. loadJs: function (t) {
  164. return (
  165. window.instances || (window.instances = {}),
  166. window.instances[t] ||
  167. (window.instances[t] = new Promise((e, n) => {
  168. const s = document.createElement("script");
  169. (s.src = t),
  170. (s.type = "text/javascript"),
  171. (s.onload = e),
  172. (s.onerror = n),
  173. Node.prototype.appendChild.call(document.head, s);
  174. })),
  175. window.instances[t]
  176. );
  177. },
  178. };
  179. return e;
  180. })([
  181. function () {
  182. return (t) => {
  183. const e = window.Hls || unsafeWindow.Hls,
  184. { hls: n, option: s, notice: i } = t;
  185. var a = Date.now(),
  186. o = 0;
  187. return (
  188. n.on(e.Events.ERROR, (r, l) => {
  189. if (l.fatal)
  190. switch (
  191. ((i.show = `当前带宽: ${
  192. Math.round((n.bandwidthEstimate / 1024 / 1024 / 8) * 100) /
  193. 100
  194. } MB/s`),
  195. l.type)
  196. ) {
  197. case e.ErrorTypes.NETWORK_ERROR:
  198. l.details === e.ErrorDetails.MANIFEST_LOAD_ERROR ||
  199. l.details === e.ErrorDetails.MANIFEST_LOAD_TIMEOUT ||
  200. l.details === e.ErrorDetails.MANIFEST_PARSING_ERROR
  201. ? n.loadSource(n.url)
  202. : l.details === e.ErrorDetails.FRAG_LOAD_ERROR
  203. ? ++o < 10 &&
  204. (n.loadSource(n.url),
  205. (n.media.currentTime = t.currentTime),
  206. n.media.play())
  207. : n.startLoad();
  208. break;
  209. case e.ErrorTypes.MEDIA_ERROR:
  210. n.recoverMediaError();
  211. break;
  212. default:
  213. (i.show = "视频播放异常,请刷新重试"), n.destroy();
  214. }
  215. else if (l.type === e.ErrorTypes.NETWORK_ERROR)
  216. l.details === e.ErrorDetails.FRAG_LOAD_ERROR &&
  217. (function (t) {
  218. var e =
  219. arguments.length > 1 && void 0 !== arguments[1]
  220. ? arguments[1]
  221. : 6e3,
  222. n = t.match(/&x-oss-expires=(\d+)&/);
  223. return n
  224. ? +"".concat(n[1], "000") - e < Date.now()
  225. : Date.now() - a > 3e5 - e;
  226. })(n.url) &&
  227. ((o = 0),
  228. (a = Date.now()),
  229. n.stopLoad(),
  230. t.emit("reload-start", s.quality));
  231. }),
  232. t.on("reload-can", (e) => {
  233. !(function (e) {
  234. s.quality = e;
  235. const a = (n.url = (
  236. e.find((t) => t.default) ||
  237. e.findLast((t) => t.url) ||
  238. {}
  239. ).url);
  240. fetch(a)
  241. .then((t) => (t.ok ? t.text() : Promise.reject()))
  242. .then((e) => {
  243. const s = new (
  244. window.m3u8Parser || unsafeWindow.m3u8Parser
  245. ).Parser();
  246. s.push(e), s.end();
  247. const i = a.replace(/media.m3u8.+/, ""),
  248. o = s.manifest.segments;
  249. n.bufferController.details.fragments.forEach(function (t, e) {
  250. const n = o[e];
  251. Object.assign(t, {
  252. baseurl: a,
  253. relurl: n.uri,
  254. url: i + n.uri,
  255. });
  256. }),
  257. n.startLoad(t.currentTime);
  258. })
  259. .catch((t) => {
  260. throw ((i.show = t), t);
  261. });
  262. })(e);
  263. }),
  264. { name: "hlsevents" }
  265. );
  266. };
  267. },
  268. function () {
  269. return function (t) {
  270. const { controls: e, option: n, notice: s, i18n: i } = t;
  271. function a() {
  272. const a =
  273. n.quality.find((t) => t.default) ||
  274. n.quality.findLast((t) => t.url);
  275. e.update({
  276. name: "quality",
  277. html: a ? a.html : "",
  278. selector: n.quality,
  279. onSelect: function (e) {
  280. e.url
  281. ? (t.switchQuality(e.url),
  282. (s.show = `${i.get("Switch Video")}: ${e.html}`))
  283. : (s.show = e.description || "视频地址不可用");
  284. },
  285. });
  286. }
  287. return (
  288. a(),
  289. t.on("playlist-switch-can", () => {
  290. setTimeout(a, 1e3);
  291. }),
  292. t.on("reload-can", () => {
  293. setTimeout(a, 1e3);
  294. }),
  295. { name: "quality" }
  296. );
  297. };
  298. },
  299. function () {
  300. return function (t) {
  301. const { option: e, notice: n } = t;
  302. if (!(e.playlist && e.playlist.length > 1)) return;
  303. const s = {
  304. showtext: !0,
  305. icon: '<i class="art-icon"><svg class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="22" height="22"><path d="M810.666667 384H85.333333v85.333333h725.333334V384z m0-170.666667H85.333333v85.333334h725.333334v-85.333334zM85.333333 640h554.666667v-85.333333H85.333333v85.333333z m640-85.333333v256l213.333334-128-213.333334-128z" fill="#ffffff"></path></svg></i>',
  306. onchanged: (n) => {
  307. (e.file = n), t.emit("playlist-switch-start", n);
  308. },
  309. };
  310. var i = e.playlist.findIndex((t) => t.default);
  311. function a(n) {
  312. e.playlist[n]
  313. ? "function" == typeof s.onchanged && s.onchanged(e.playlist[n])
  314. : n >= e.playlist.length && (t.notice.show = "没有下一集了");
  315. }
  316. return (
  317. t.controls.add({
  318. html: s.showtext ? "播放列表" : s.icon,
  319. name: "play-list",
  320. position: "right",
  321. style: { paddingLeft: "10px", paddingRight: "10px" },
  322. selector: e.playlist.map((t, e) => ({
  323. html: t.name,
  324. style: { textAlign: "left" },
  325. index: e,
  326. default: i === e,
  327. })),
  328. onSelect: (t) => (
  329. a((i = t.index)), s.showtext ? "播放列表" : s.icon
  330. ),
  331. }),
  332. t.on("playlist-switch-can", (s) => {
  333. const { file_id: i, name: a } = e.file || {},
  334. {
  335. live_transcoding_subtitle_task_list: o,
  336. live_transcoding_task_list: r,
  337. meta: l,
  338. quick_video_list: c,
  339. quick_video_subtitle_list: u,
  340. } = s?.video_preview_play_info || {},
  341. p = (function (t) {
  342. if (Array.isArray(t) && t.length) {
  343. let e = {
  344. QHD: "2K 超清",
  345. FHD: "1080 全高清",
  346. HD: "720 高清",
  347. SD: "540 标清",
  348. LD: "360 流畅",
  349. };
  350. return (
  351. t.forEach((t, n) => {
  352. Object.assign(t, {
  353. html:
  354. e[t.template_id] +
  355. (t.description
  356. ? "(三方VIP)"
  357. : t.url
  358. ? ""
  359. : "(VIP)"),
  360. type: "hls",
  361. });
  362. }),
  363. t.sort((t, e) => t.template_height - e.template_height),
  364. (t.findLast((t) => t.url).default = !0),
  365. t
  366. );
  367. }
  368. return [];
  369. })(c || r);
  370. if (!p.length) return alert("获取播放信息失败,无法切换视频");
  371. {
  372. const { url: s, type: o } =
  373. p.find((t) => t.default) || p[0] || {};
  374. Object.assign(e, { id: i, quality: p, url: s, type: o }),
  375. t
  376. .switchUrl(s)
  377. .then(() => {
  378. ((
  379. document.querySelector(
  380. "[class^=header-file-name], [class^=header-center] div span"
  381. ) || {}
  382. ).innerText = a),
  383. (n.show = `切换视频: ${a}`);
  384. })
  385. .catch(() => {
  386. n.show = `视频地址不可用: ${a}`;
  387. });
  388. }
  389. e.subtitlelist = (function (t) {
  390. if (Array.isArray(t) && t.length) {
  391. const e = { chi: "中文字幕", eng: "英文字幕", jpn: "日文字幕" };
  392. return (
  393. t.forEach(function (t, n) {
  394. Object.assign(t, {
  395. html:
  396. (e[t.language] || t.language || "未知语言") + "(vtt)",
  397. name: "内置字幕",
  398. type: "vtt",
  399. });
  400. }),
  401. ((
  402. t.find((t) => ["chi"].includes(t.language)) ||
  403. t[0] ||
  404. {}
  405. ).default = !0),
  406. t
  407. );
  408. }
  409. return [];
  410. })(o);
  411. }),
  412. t.on("video:ended", () => {
  413. t.storage.get("auto-next") && i < s.playlist.length && a((i += 1));
  414. }),
  415. { name: "playlist" }
  416. );
  417. };
  418. },
  419. function () {
  420. return function (t) {
  421. const e = t.storage.get("auto-next");
  422. return (
  423. t.setting.add({
  424. html: "自动连播",
  425. name: "auto-next",
  426. icon: '<img width="22" heigth="22" src="https://artplayer.org/assets/img/state.svg">',
  427. tooltip: e ? "开启" : "关闭",
  428. switch: !!e,
  429. onSwitch: function (e) {
  430. return (
  431. (e.tooltip = e.switch ? "关闭" : "开启"),
  432. t.storage.set("auto-next", !e.switch),
  433. (t.notice.show =
  434. "自动连续播放:" + (e.switch ? "关闭" : "开启")),
  435. !e.switch
  436. );
  437. },
  438. }),
  439. { name: "autonext" }
  440. );
  441. };
  442. },
  443. function () {
  444. return (t) => {
  445. const {
  446. controls: e,
  447. subtitle: n,
  448. template: s,
  449. option: i,
  450. notice: a,
  451. } = t,
  452. o = !0,
  453. r =
  454. '<i class="art-icon"><svg xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 48 48"><path d="M0 0h48v48H0z" fill="none"/><path fill="#ffffff" d="M40 8H8c-2.21 0-4 1.79-4 4v24c0 2.21 1.79 4 4 4h32c2.21 0 4-1.79 4-4V12c0-2.21-1.79-4-4-4zM8 24h8v4H8v-4zm20 12H8v-4h20v4zm12 0h-8v-4h8v4zm0-8H20v-4h20v4z"/></svg></i>';
  455. function l(t = []) {
  456. const s = Object.assign(
  457. {},
  458. i.subtitle,
  459. t.find((t) => t.default) || t[0] || {}
  460. ),
  461. { url: l, type: c } = s;
  462. Object.assign(i.subtitle, { url: l, type: c }),
  463. n.init({ ...s }).then(() => {
  464. a.show = "加载字幕成功";
  465. }),
  466. e.update({
  467. html: o ? "字幕列表" : r,
  468. name: "subtitle-list",
  469. position: "right",
  470. style: { paddingLeft: "10px", paddingRight: "10px" },
  471. selector: t.map((t, e) => ({ ...t })),
  472. onSelect: function (t, e) {
  473. const { url: s, type: a } = t;
  474. return (
  475. Object.assign(i.subtitle, { url: s, type: a }),
  476. n.switch(t.url, t),
  477. t.html
  478. );
  479. },
  480. });
  481. }
  482. function c(t) {
  483. return (function (t) {
  484. return new Promise((e, n) => {
  485. var s = new FileReader();
  486. s.readAsText(t, "UTF-8"),
  487. (s.onload = function (n) {
  488. var i = s.result;
  489. return i.indexOf("�") > -1 && !s.markGBK
  490. ? ((s.markGBK = !0), s.readAsText(t, "GBK"))
  491. : i.indexOf("") > -1 && !s.markBIG5
  492. ? ((s.markBIG5 = !0), s.readAsText(t, "BIG5"))
  493. : void e(i);
  494. }),
  495. (s.onerror = function (t) {
  496. n(t);
  497. });
  498. });
  499. })(t).then((t) => {
  500. const e = new Blob([t], { type: "text/plain" });
  501. return URL.createObjectURL(e);
  502. });
  503. }
  504. function u(t, e) {
  505. return (
  506. e instanceof Element
  507. ? Node.prototype.appendChild.call(t, e)
  508. : t.insertAdjacentHTML("beforeend", String(e)),
  509. t.lastElementChild || t.lastChild
  510. );
  511. }
  512. return (
  513. (s.$subtitleLocalFile = u(
  514. s.$container,
  515. '<input class="subtitleLocalFile" type="file" accept="webvtt,.vtt,.srt,.ssa,.ass" style="display: none;">'
  516. )),
  517. t.setting.add({
  518. width: 220,
  519. html: "字幕设置",
  520. name: "subtitle-setting",
  521. tooltip: "显示",
  522. icon: '<img width="22" heigth="22" src="https://artplayer.org/assets/img/subtitle.svg">',
  523. selector: [
  524. {
  525. html: "显示",
  526. tooltip: "显示",
  527. switch: !0,
  528. onSwitch: function (e) {
  529. return (
  530. (e.tooltip = e.switch ? "隐藏" : "显示"),
  531. (t.subtitle.show = !e.switch),
  532. !e.switch
  533. );
  534. },
  535. },
  536. {
  537. html: "字幕偏移",
  538. name: "subtitle-offset",
  539. tooltip: "0s",
  540. range: [0, -5, 5, 0.1],
  541. onChange: (e) => ((t.subtitleOffset = e.range), e.range + "s"),
  542. },
  543. {
  544. html: "字幕位置",
  545. name: "subtitle-bottom",
  546. tooltip: "5%",
  547. range: [5, 1, 90, 1],
  548. onChange: (e) => (
  549. t.subtitle.style({ bottom: e.range + "%" }), e.range + "%"
  550. ),
  551. },
  552. {
  553. html: "字体大小",
  554. name: "subtitle-fontSize",
  555. tooltip: "25px",
  556. range: [25, 10, 60, 1],
  557. onChange: (e) => (
  558. t.subtitle.style({ fontSize: e.range + "px" }), e.range + "px"
  559. ),
  560. },
  561. {
  562. html: "字体粗细",
  563. name: "subtitle-fontWeight",
  564. tooltip: "400",
  565. range: [4, 1, 9, 1],
  566. onChange(e) {
  567. const n = 100 * e.range;
  568. return t.subtitle.style({ fontWeight: n }), n;
  569. },
  570. },
  571. {
  572. html: "字体颜色",
  573. name: "subtitle-color",
  574. tooltip: "",
  575. selector: [
  576. {
  577. name: "color-presets",
  578. html: '<style>.panel-setting-color label{font-size: 0;padding: 6px;display: inline-block;}.panel-setting-color input{display: none;}.panel-setting-color span{width: 22px;height: 22px;display: inline-block;border-radius: 50%;box-sizing: border-box;cursor: pointer;}</style><div class="panel-setting-color"><label><input type="radio" value="#fff"><span style="background: #fff;"></span></label><label><input type="radio" value="#e54256"><span style="background: #e54256"></span></label><label><input type="radio" 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" value="#39ccff"><span style="background: #39ccff"></span></label><label><input type="radio" value="#D500F9"><span style="background: #D500F9"></span></label></div>',
  579. },
  580. { name: "color-default", html: "默认颜色" },
  581. { name: "color-picker", html: "颜色选择器" },
  582. ],
  583. onSelect: function (t, e, i) {
  584. switch (t.name) {
  585. case "color-presets":
  586. "INPUT" === i.target.nodeName &&
  587. n.style({ color: i.target.value });
  588. break;
  589. case "color-default":
  590. n.style({ color: "#FE9200" });
  591. break;
  592. case "color-picker":
  593. s.$colorPicker ||
  594. ((s.$colorPicker = u(
  595. s.$player,
  596. '<input hidden type="color">'
  597. )),
  598. (s.$colorPicker.oninput = (t) => {
  599. n.style({ color: t.target.value });
  600. })),
  601. s.$colorPicker.click();
  602. }
  603. return (
  604. '<label style="display: flex;"><span style="width: 18px;height: 18px;display: inline-block;border-radius: 50%;box-sizing: border-box;cursor: pointer;background: ' +
  605. s.$subtitle.style.color +
  606. ';"></span></label>'
  607. );
  608. },
  609. },
  610. {
  611. html: "字体类型",
  612. name: "subtitle-fontFamily",
  613. selector: [
  614. { html: "默认", text: "" },
  615. {
  616. html: "等宽 衬线",
  617. text: '"Courier New", Courier, "Nimbus Mono L", "Cutive Mono", monospace',
  618. },
  619. {
  620. html: "比例 衬线",
  621. text: '"Times New Roman", Times, Georgia, Cambria, "PT Serif Caption", serif',
  622. },
  623. {
  624. html: "等宽 无衬线",
  625. text: '"Deja Vu Sans Mono", "Lucida Console", Monaco, Consolas, "PT Mono", monospace',
  626. },
  627. {
  628. html: "比例 无衬线",
  629. text: '"YouTube Noto", Roboto, "Arial Unicode Ms", Arial, Helvetica, Verdana, "PT Sans Caption", sans-serif',
  630. },
  631. {
  632. html: "Casual",
  633. text: '"Comic Sans MS", Impact, Handlee, fantasy',
  634. },
  635. {
  636. html: "Cursive",
  637. text: '"Monotype Corsiva", "URW Chancery L", "Apple Chancery", "Dancing Script", cursive',
  638. },
  639. {
  640. html: "Small Capitals",
  641. text: '"Arial Unicode Ms", Arial, Helvetica, Verdana, "Marcellus SC", sans-serif',
  642. },
  643. ],
  644. onSelect: function (e, n, s) {
  645. return t.subtitle.style({ fontFamily: e.text }), e.html;
  646. },
  647. },
  648. {
  649. html: "描边样式",
  650. name: "subtitle-textShadow",
  651. selector: [
  652. {
  653. html: "默认",
  654. text: "rgb(0 0 0) 1px 0 1px, rgb(0 0 0) 0 1px 1px, rgb(0 0 0) -1px 0 1px, rgb(0 0 0) 0 -1px 1px, rgb(0 0 0) 1px 1px 1px, rgb(0 0 0) -1px -1px 1px, rgb(0 0 0) 1px -1px 1px, rgb(0 0 0) -1px 1px 1px",
  655. },
  656. {
  657. html: "重墨",
  658. text: "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",
  659. },
  660. {
  661. html: "描边",
  662. text: "rgb(0, 0, 0) 0px 0px 1px, rgb(0, 0, 0) 0px 0px 1px, rgb(0, 0, 0) 0px 0px 1px",
  663. },
  664. {
  665. html: "45°投影",
  666. text: "rgb(0, 0, 0) 1px 1px 2px, rgb(0, 0, 0) 0px 0px 1px",
  667. },
  668. {
  669. html: "阴影",
  670. text: "rgb(34, 34, 34) 1px 1px 1.4875px, rgb(34, 34, 34) 1px 1px 1.98333px, rgb(34, 34, 34) 1px 1px 2.47917px",
  671. },
  672. { html: "凸起", text: "rgb(34, 34, 34) 1px 1px" },
  673. {
  674. html: "下沉",
  675. text: "rgb(204, 204, 204) 1px 1px, rgb(34, 34, 34) -1px -1px",
  676. },
  677. {
  678. html: "边框",
  679. text: "rgb(34, 34, 34) 0px 0px 1px, rgb(34, 34, 34) 0px 0px 1px, rgb(34, 34, 34) 0px 0px 1px, rgb(34, 34, 34) 0px 0px 1px, rgb(34, 34, 34) 0px 0px 1px",
  680. },
  681. ],
  682. onSelect: function (e, n, s) {
  683. return t.subtitle.style({ textShadow: e.text }), e.html;
  684. },
  685. },
  686. {
  687. name: "subtitle-localfile",
  688. html: "加载本地字幕",
  689. selector: [{ html: "文件", name: "file" }],
  690. onSelect: function (t, e, n) {
  691. var a;
  692. return (
  693. "file" === t.name &&
  694. ((a = s.$subtitleLocalFile),
  695. a.click(),
  696. new Promise(function (t, e) {
  697. a.onchange = (e) => {
  698. if (e.target.files.length) {
  699. const n = e.target.files[0],
  700. s = n.name.split(".").pop().toLowerCase();
  701. c(n).then((e) => {
  702. const i = {
  703. url: e,
  704. type: s,
  705. name: n.name,
  706. html: "本地字幕(" + s + ")",
  707. };
  708. t(i);
  709. });
  710. }
  711. e.target.value = "";
  712. };
  713. })).then((t) => {
  714. (i.subtitlelist = (i.subtitlelist || []).concat([t])),
  715. l(i.subtitlelist);
  716. }),
  717. !1
  718. );
  719. },
  720. },
  721. ],
  722. }),
  723. (i.subtitlelist || []).length && l(i.subtitlelist),
  724. t.on("restart", () => {
  725. (i.subtitlelist || []).length
  726. ? l(i.subtitlelist)
  727. : e["subtitle-list"] && e.remove("subtitle-list");
  728. }),
  729. t.on("subtitlelist-add", (t) => {
  730. (i.subtitlelist = (i.subtitlelist || []).concat(t)),
  731. (i.subtitlelist || []).length && l(i.subtitlelist);
  732. }),
  733. { name: "subtitle" }
  734. );
  735. };
  736. },
  737. function () {
  738. return (t) => {
  739. function e() {
  740. t.libass &&
  741. t.subtitle.show &&
  742. ((t.template.$subtitle.style.display = "none"),
  743. ((t.libass.canvasParent || t.libass._canvasParent).style.display =
  744. "block"),
  745. t.libass.resize());
  746. }
  747. function n() {
  748. t.libass &&
  749. ((t.template.$subtitle.style.display = t.subtitle.show
  750. ? "block"
  751. : "none"),
  752. ((t.libass.canvasParent || t.libass._canvasParent).style.display =
  753. "none"));
  754. }
  755. function s(e) {
  756. let n = "https://unpkg.com/jassub@1.7.17/dist/jassub.umd.js";
  757. return (function (t) {
  758. window.instances || (window.instances = {});
  759. window.instances[t] ||
  760. (window.instances[t] = new Promise((e, n) => {
  761. const s = document.createElement("script");
  762. (s.src = t),
  763. (s.type = "text/javascript"),
  764. (s.onload = e),
  765. (s.onerror = n),
  766. Node.prototype.appendChild.call(document.head, s);
  767. }));
  768. return window.instances[t];
  769. })(n).then(
  770. () => (
  771. Object.assign(e, {
  772. workerUrl: new URL("jassub-worker.js", n).href,
  773. wasmUrl: new URL("jassub-worker.wasm", n).href,
  774. legacyWorkerUrl: new URL("jassub-worker.wasm.js", n).href,
  775. modernWasmUrl: new URL("jassub-worker-modern.wasm", n).href,
  776. }),
  777. (function ({ workerUrl: t }) {
  778. return fetch(t)
  779. .then((t) => t.text())
  780. .then((t) => {
  781. const e = new Blob([t], { type: "text/javascript" }),
  782. n = URL.createObjectURL(e);
  783. return (
  784. setTimeout(() => {
  785. URL.revokeObjectURL(n);
  786. }),
  787. n
  788. );
  789. });
  790. })(e).then((n) => {
  791. (e.workerUrl = n), (t.libass = new unsafeWindow.JASSUB(e));
  792. return (
  793. ((
  794. t.libass.canvasParent || t.libass._canvasParent
  795. ).style.cssText =
  796. "position: absolute;top: 0;left: 0;width: 100%;height: 100%;user-select: none;pointer-events: none;z-index: 20;"),
  797. t.libass
  798. );
  799. })
  800. )
  801. );
  802. }
  803. return (
  804. t.on("subtitle", (t) => {
  805. t ? e() : n();
  806. }),
  807. t.on("subtitleLoad", function () {
  808. return (function () {
  809. if (t.libass) return Promise.resolve(t.libass);
  810. const e = {
  811. video: t.template.$video,
  812. subContent: "[Script Info]\nScriptType: v4.00+",
  813. subUrl: "",
  814. availableFonts: {
  815. 思源黑体:
  816. "https://artplayer.org/assets/misc/SourceHanSansCN-Bold.woff2",
  817. },
  818. };
  819. return (function (t) {
  820. if (unsafeWindow.queryLocalFonts) {
  821. const e = {};
  822. return (
  823. t && (e.postscriptNames = Array.isArray(t) ? t : [t]),
  824. unsafeWindow
  825. .queryLocalFonts(e)
  826. .then((t) => (t && t.length ? t : Promise.reject()))
  827. );
  828. }
  829. return console.warn("Not Local fonts API"), Promise.reject();
  830. })().then(
  831. (t) => {
  832. const n = t.filter((t) =>
  833. t.fullName.match(/[\u4e00-\u9fa5]/)
  834. ),
  835. i =
  836. n.find((t) => ["微软雅黑"].some((e) => t?.fullName === e))
  837. ?.fullName ||
  838. n.sort(() => 0.5 - Math.random())[0]?.fullName;
  839. return (
  840. Object.assign(e, { useLocalFonts: !0, fallbackFont: i }),
  841. s(e)
  842. );
  843. },
  844. () => (
  845. Object.assign(e, {
  846. fallbackFont: Object.keys(e.availableFonts)[0],
  847. }),
  848. s(e)
  849. )
  850. );
  851. })()
  852. .then(() => {
  853. const { url: s, type: i } = t?.option?.subtitle || {};
  854. !s || ("ass" !== i && "ssa" !== i)
  855. ? (n(), t.libass.freeTrack())
  856. : (!(function (e) {
  857. t.libass &&
  858. e &&
  859. (t.libass.freeTrack(), t.libass.setTrackByUrl(e));
  860. })(s),
  861. e());
  862. })
  863. .catch((t) => {
  864. console.error("加载特效字幕组件 错误!", t);
  865. });
  866. }),
  867. t.on("subtitleOffset", (e) => {
  868. !(function (e) {
  869. t.libass && (t.libass.timeOffset = e);
  870. })(e);
  871. }),
  872. t.on("restart", () => {
  873. t.libass && t.libass.freeTrack();
  874. }),
  875. t.once("destroy", function () {
  876. t.libass &&
  877. (t.libass.destroy && t.libass.destroy(),
  878. t.libass.dispose && t.libass.dispose(),
  879. (t.libass = null));
  880. }),
  881. { name: "libass" }
  882. );
  883. };
  884. },
  885. function () {
  886. return (t) => {
  887. const { template: e, setting: n, storage: s, notice: i } = t;
  888. const a = t.storage.get("sound-enhancer");
  889. return (
  890. n.add({
  891. width: 220,
  892. html: "声音设置",
  893. name: "sound-setting",
  894. tooltip: "正常",
  895. icon: '<svg xmlns="http://www.w3.org/2000/svg" height="22" width="22" data-spm-anchor-id="0.0.0.i11.83206c7554HZzm"><path d="M10.188 4.65 6 8H5a2 2 0 0 0-2 2v2a2 2 0 0 0 2 2h1l4.188 3.35a.5.5 0 0 0 .812-.39V5.04a.498.498 0 0 0-.812-.39zm4.258-.872a1 1 0 0 0-.862 1.804 6.002 6.002 0 0 1-.007 10.838 1 1 0 0 0 .86 1.806A8.001 8.001 0 0 0 19 11a8.001 8.001 0 0 0-4.554-7.222z"></path><path d="M15 11a3.998 3.998 0 0 0-2-3.465v6.93A3.998 3.998 0 0 0 15 11z"></path></svg>',
  896. selector: [
  897. {
  898. html: "音质增强",
  899. name: "sound-enhancer",
  900. tooltip: a ? "开启" : "关闭",
  901. switch: !!a,
  902. onSwitch: function (e) {
  903. return (
  904. (e.tooltip = e.switch ? "关闭" : "开启"),
  905. t.storage.set("sound-enhancer", !e.switch),
  906. t.joySound && t.joySound.setEnabled(!e.switch),
  907. (i.show = "音质增强:" + (e.switch ? "关闭" : "开启")),
  908. !e.switch
  909. );
  910. },
  911. },
  912. {
  913. html: "音量增强",
  914. name: "volume-enhancer",
  915. tooltip: "0x",
  916. range: [0, 0, 10, 0.1],
  917. onRange: function (e) {
  918. const n = e.range / 10;
  919. return (
  920. t.joySound && t.joySound.setVolume(n),
  921. (i.show = "音量增强:" + (100 + 100 * n) + "%"),
  922. e.range + "x"
  923. );
  924. },
  925. },
  926. ],
  927. }),
  928. t.once("video:playing", function () {
  929. const s = window.Joysound || unsafeWindow.Joysound;
  930. s &&
  931. s.isSupport() &&
  932. ((t.joySound = t.joySound || new s()),
  933. t.joySound.hasSource() || t.joySound.init(e.$video),
  934. t.storage.get("sound-enhancer") &&
  935. (t.joySound.setEnabled(!0),
  936. n.update({
  937. name: "sound-enhancer",
  938. html: "音质增强",
  939. switch: !0,
  940. })));
  941. }),
  942. { name: "sound" }
  943. );
  944. };
  945. }
  946. ]);

QingJ © 2025

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