alipan

alipan强化播放依赖库

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

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

QingJ © 2025

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