// ==UserScript== // @name 听歌小助手 // @namespace https://github.com/fan0530 // @version 1.1.2 // @author fanxq // @description 这个脚本主要为Hifini(音乐磁场)网站提供了一个歌曲管理页面(可添加、删除、列表播放歌曲等) // @icon https://cdn.jsdelivr.net/gh/fan0530/music-player/favicon.ico // @match https://hifini.com/* // @match https://www.hifini.com/* // @require https://unpkg.com/vue@3.4.19/dist/vue.global.prod.js // @require data:application/javascript,window.Vue%3DVue%3B // @require https://unpkg.com/element-plus@2.5.6/dist/index.full.min.js // @require https://unpkg.com/idb-keyval@6.2.1/dist/umd.js // @resource element-plus/dist/index.css https://unpkg.com/element-plus@2.5.6/dist/index.css // @resource player.html https://cdn.jsdelivr.net/gh/fan0530/music-player@main/index.v2024122201.html // @connect hifini.com // @connect gitee.com // @grant GM_addStyle // @grant GM_getResourceText // @grant GM_xmlhttpRequest // @grant unsafeWindow // @grant window.focus // @run-at document-end // @downloadURL none // ==/UserScript== (e=>{if(typeof GM_addStyle=="function"){GM_addStyle(e);return}const t=document.createElement("style");t.textContent=e,document.head.append(t)})(" .my-help-dialog{--el-dialog-width: 92% !important;max-width:none;min-width:none}.my-help-dialog .img-wrapper{margin:10px 0;padding:20px;background:#f7f7f7}@media screen and (min-width: 500px){.my-help-dialog{--el-dialog-width: 55% !important;max-width:800px;min-width:500px}}.loading-toast{--el-dialog-width: 140px !important;--el-dialog-border-radius: 10px !important}.loading-toast .el-dialog__header{display:none}.btn-container[data-v-3beef0e1]{position:fixed;bottom:100px;right:20px}.menu-popper .menu-list[data-v-3beef0e1]{list-style:none;margin:0;padding:0}.menu-popper .menu-list li[data-v-3beef0e1]{display:flex;flex-direction:column}.menu-popper .menu-list li .menu-item[data-v-3beef0e1]{display:flex;align-items:center;justify-content:center;color:#666}.menu-popper .menu-list li .menu-item[data-v-3beef0e1]:active{background-color:#80808033} "); (function (vue, elementPlus, idbKeyval) { 'use strict'; var _GM_getResourceText = /* @__PURE__ */ (() => typeof GM_getResourceText != "undefined" ? GM_getResourceText : void 0)(); var _GM_xmlhttpRequest = /* @__PURE__ */ (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)(); var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)(); var DEFAULT_ICON_CONFIGS = { size: "1em", strokeWidth: 4, strokeLinecap: "round", strokeLinejoin: "round", rtl: false, theme: "outline", colors: { outline: { fill: "#333", background: "transparent" }, filled: { fill: "#333", background: "#FFF" }, twoTone: { fill: "#333", twoTone: "#2F88FF" }, multiColor: { outStrokeColor: "#333", outFillColor: "#2F88FF", innerStrokeColor: "#FFF", innerFillColor: "#43CCF8" } }, prefix: "i" }; function guid() { return "icon-" + ((1 + Math.random()) * 4294967296 | 0).toString(16).substring(1); } function IconConverter(id, icon, config) { var fill = typeof icon.fill === "string" ? [icon.fill] : icon.fill || []; var colors = []; var theme = icon.theme || config.theme; switch (theme) { case "outline": colors.push(typeof fill[0] === "string" ? fill[0] : "currentColor"); colors.push("none"); colors.push(typeof fill[0] === "string" ? fill[0] : "currentColor"); colors.push("none"); break; case "filled": colors.push(typeof fill[0] === "string" ? fill[0] : "currentColor"); colors.push(typeof fill[0] === "string" ? fill[0] : "currentColor"); colors.push("#FFF"); colors.push("#FFF"); break; case "two-tone": colors.push(typeof fill[0] === "string" ? fill[0] : "currentColor"); colors.push(typeof fill[1] === "string" ? fill[1] : config.colors.twoTone.twoTone); colors.push(typeof fill[0] === "string" ? fill[0] : "currentColor"); colors.push(typeof fill[1] === "string" ? fill[1] : config.colors.twoTone.twoTone); break; case "multi-color": colors.push(typeof fill[0] === "string" ? fill[0] : "currentColor"); colors.push(typeof fill[1] === "string" ? fill[1] : config.colors.multiColor.outFillColor); colors.push(typeof fill[2] === "string" ? fill[2] : config.colors.multiColor.innerStrokeColor); colors.push(typeof fill[3] === "string" ? fill[3] : config.colors.multiColor.innerFillColor); break; } return { size: icon.size || config.size, strokeWidth: icon.strokeWidth || config.strokeWidth, strokeLinecap: icon.strokeLinecap || config.strokeLinecap, strokeLinejoin: icon.strokeLinejoin || config.strokeLinejoin, colors, id }; } var IconContext = Symbol("icon-context"); function IconWrapper(name, rtl, render) { var options = { name: "icon-" + name, props: ["size", "strokeWidth", "strokeLinecap", "strokeLinejoin", "theme", "fill", "spin"], setup: function setup(props) { var id = guid(); var ICON_CONFIGS = vue.inject(IconContext, DEFAULT_ICON_CONFIGS); return function() { var size = props.size, strokeWidth = props.strokeWidth, strokeLinecap = props.strokeLinecap, strokeLinejoin = props.strokeLinejoin, theme = props.theme, fill = props.fill, spin = props.spin; var svgProps = IconConverter(id, { size, strokeWidth, strokeLinecap, strokeLinejoin, theme, fill }, ICON_CONFIGS); var cls = [ICON_CONFIGS.prefix + "-icon"]; cls.push(ICON_CONFIGS.prefix + "-icon-" + name); if (rtl && ICON_CONFIGS.rtl) { cls.push(ICON_CONFIGS.prefix + "-icon-rtl"); } if (spin) { cls.push(ICON_CONFIGS.prefix + "-icon-spin"); } return vue.createVNode("span", { "class": cls.join(" ") }, [render(svgProps)]); }; } }; return options; } const AddMusic = IconWrapper("add-music", true, function(props) { return vue.createVNode("svg", { "width": props.size, "height": props.size, "viewBox": "0 0 48 48", "fill": "none" }, [vue.createVNode("path", { "d": "M24 44C12.9543 44 4 35.0457 4 24C4 12.9543 12.9543 4 24 4C35.0457 4 44 12.9543 44 24", "stroke": props.colors[0], "stroke-width": props.strokeWidth, "stroke-linecap": props.strokeLinecap, "stroke-linejoin": props.strokeLinejoin }, null), vue.createVNode("path", { "d": "M20 24V17.0718L26 20.5359L32 24L26 27.4641L20 30.9282V24Z", "fill": props.colors[1], "stroke": props.colors[0], "stroke-width": props.strokeWidth, "stroke-linejoin": props.strokeLinejoin }, null), vue.createVNode("path", { "d": "M37.0508 32L37.0508 42", "stroke": props.colors[0], "stroke-width": props.strokeWidth, "stroke-linecap": props.strokeLinecap, "stroke-linejoin": props.strokeLinejoin }, null), vue.createVNode("path", { "d": "M42 36.9497L32 36.9497", "stroke": props.colors[0], "stroke-width": props.strokeWidth, "stroke-linecap": props.strokeLinecap, "stroke-linejoin": props.strokeLinejoin }, null)]); }); const Down = IconWrapper("down", false, function(props) { return vue.createVNode("svg", { "width": props.size, "height": props.size, "viewBox": "0 0 48 48", "fill": "none" }, [vue.createVNode("path", { "d": "M36 18L24 30L12 18", "stroke": props.colors[0], "stroke-width": props.strokeWidth, "stroke-linecap": props.strokeLinecap, "stroke-linejoin": props.strokeLinejoin }, null)]); }); const Help = IconWrapper("help", true, function(props) { return vue.createVNode("svg", { "width": props.size, "height": props.size, "viewBox": "0 0 48 48", "fill": "none" }, [vue.createVNode("path", { "d": "M24 44C29.5228 44 34.5228 41.7614 38.1421 38.1421C41.7614 34.5228 44 29.5228 44 24C44 18.4772 41.7614 13.4772 38.1421 9.85786C34.5228 6.23858 29.5228 4 24 4C18.4772 4 13.4772 6.23858 9.85786 9.85786C6.23858 13.4772 4 18.4772 4 24C4 29.5228 6.23858 34.5228 9.85786 38.1421C13.4772 41.7614 18.4772 44 24 44Z", "fill": props.colors[1], "stroke": props.colors[0], "stroke-width": props.strokeWidth, "stroke-linejoin": props.strokeLinejoin }, null), vue.createVNode("path", { "d": "M24 28.6248V24.6248C27.3137 24.6248 30 21.9385 30 18.6248C30 15.3111 27.3137 12.6248 24 12.6248C20.6863 12.6248 18 15.3111 18 18.6248", "stroke": props.colors[2], "stroke-width": props.strokeWidth, "stroke-linecap": props.strokeLinecap, "stroke-linejoin": props.strokeLinejoin }, null), vue.createVNode("path", { "fill-rule": "evenodd", "clip-rule": "evenodd", "d": "M24 37.6248C25.3807 37.6248 26.5 36.5055 26.5 35.1248C26.5 33.7441 25.3807 32.6248 24 32.6248C22.6193 32.6248 21.5 33.7441 21.5 35.1248C21.5 36.5055 22.6193 37.6248 24 37.6248Z", "fill": props.colors[2] }, null)]); }); const Record = IconWrapper("record", true, function(props) { return vue.createVNode("svg", { "width": props.size, "height": props.size, "viewBox": "0 0 48 48", "fill": "none" }, [vue.createVNode("rect", { "x": "5", "y": "18", "width": "38", "height": "24", "rx": "2", "fill": props.colors[1], "stroke": props.colors[0], "stroke-width": props.strokeWidth, "stroke-linecap": props.strokeLinecap, "stroke-linejoin": props.strokeLinejoin }, null), vue.createVNode("path", { "d": "M8 12H40", "stroke": props.colors[0], "stroke-width": props.strokeWidth, "stroke-linecap": props.strokeLinecap, "stroke-linejoin": props.strokeLinejoin }, null), vue.createVNode("path", { "d": "M15 6L33 6", "stroke": props.colors[0], "stroke-width": props.strokeWidth, "stroke-linecap": props.strokeLinecap, "stroke-linejoin": props.strokeLinejoin }, null), vue.createVNode("path", { "d": "M26 24V30", "stroke": props.colors[2], "stroke-width": props.strokeWidth, "stroke-linecap": props.strokeLinecap, "stroke-linejoin": props.strokeLinejoin }, null), vue.createVNode("path", { "d": "M18 32.7491C18 31.2308 19.2894 30 20.88 30H26V33.2509C26 34.7692 24.7106 36 23.12 36H20.88C19.2894 36 18 34.7692 18 33.2509V32.7491Z", "stroke": props.colors[2], "stroke-width": props.strokeWidth, "stroke-linejoin": props.strokeLinejoin }, null), vue.createVNode("path", { "d": "M31 25L26 24", "stroke": props.colors[2], "stroke-width": props.strokeWidth, "stroke-linecap": props.strokeLinecap, "stroke-linejoin": props.strokeLinejoin }, null)]); }); const RecordPlayer = IconWrapper("record-player", true, function(props) { return vue.createVNode("svg", { "width": props.size, "height": props.size, "viewBox": "0 0 48 48", "fill": "none" }, [vue.createVNode("rect", { "x": "5", "y": "8", "width": "38", "height": "32", "rx": "2", "stroke": props.colors[0], "stroke-width": props.strokeWidth }, null), vue.createVNode("path", { "d": "M13 8V40", "stroke": props.colors[0], "stroke-width": props.strokeWidth, "stroke-linecap": props.strokeLinecap, "stroke-linejoin": props.strokeLinejoin }, null), vue.createVNode("circle", { "cx": "28", "cy": "24", "r": "9", "fill": props.colors[1], "stroke": props.colors[0], "stroke-width": props.strokeWidth }, null), vue.createVNode("circle", { "cx": "28", "cy": "24", "r": "3", "fill": props.colors[2] }, null), vue.createVNode("path", { "d": "M5 16H13", "stroke": props.colors[0], "stroke-width": props.strokeWidth, "stroke-linecap": props.strokeLinecap, "stroke-linejoin": props.strokeLinejoin }, null), vue.createVNode("path", { "d": "M5 24H13", "stroke": props.colors[0], "stroke-width": props.strokeWidth, "stroke-linecap": props.strokeLinecap, "stroke-linejoin": props.strokeLinejoin }, null), vue.createVNode("path", { "d": "M5 32H13", "stroke": props.colors[0], "stroke-width": props.strokeWidth, "stroke-linecap": props.strokeLinecap, "stroke-linejoin": props.strokeLinejoin }, null)]); }); const _hoisted_1$2 = ["id"]; const _hoisted_2$1 = /* @__PURE__ */ vue.createElementVNode("p", null, [ /* @__PURE__ */ vue.createTextVNode("具体使用说明请查看这篇文章: "), /* @__PURE__ */ vue.createElementVNode("a", { target: "_blank", href: "https://mp.weixin.qq.com/s?__biz=Mzg2NDgzMjU1OA==&mid=2247483945&idx=1&sn=cdf6194c875eeeb143c51a7a9cf8f520&chksm=ce621f68f915967e712d03de99b81e6f64f3e28ca4b970815e78d388b4ad76d04d6fd40e69e2#rd" }, " 有用这颗“黑凤梨”听歌的朋友吗?我写了个油猴脚本送给你 ") ], -1); const _hoisted_3$1 = /* @__PURE__ */ vue.createElementVNode("p", null, [ /* @__PURE__ */ vue.createTextVNode("如果在使用该脚本的过程遇到了问题,或者觉得有需要改善的地方,可以在 "), /* @__PURE__ */ vue.createElementVNode("a", { target: "_blank", href: "https://greasyfork.org/zh-CN/scripts/497671-%E5%90%AC%E6%AD%8C%E5%B0%8F%E5%8A%A9%E6%89%8B/feedback" }, " 此处(https://greasyfork.org/zh-CN/scripts/497671-%E5%90%AC%E6%AD%8C%E5%B0%8F%E5%8A%A9%E6%89%8B/feedback) "), /* @__PURE__ */ vue.createTextVNode(" 反馈。 ") ], -1); const _hoisted_4$1 = /* @__PURE__ */ vue.createElementVNode("p", null, "最后,如果这个脚本对你有点帮助的话,可以考虑请我喝瓶快乐水,你的支持将给我动力持续去维护好这个脚本。", -1); const _hoisted_5$1 = /* @__PURE__ */ vue.createElementVNode("p", null, [ /* @__PURE__ */ vue.createElementVNode("img", { src: "https://gitee.com/fanxiqian/music-player/raw/master/code.jpg", alt: "赞赏码", style: { "display": "block", "margin": "0 auto", "width": "100%", "max-width": "320px", "height": "auto" } }) ], -1); const _sfc_main$2 = { __name: "HelpDialog", props: { show: { type: Boolean, default: false } }, emits: ["update:show"], setup(__props, { emit: __emit }) { const emits = __emit; const updateShow = (visible) => { emits("update:show", visible); }; return (_ctx, _cache) => { return vue.openBlock(), vue.createBlock(vue.unref(elementPlus.ElDialog), { "model-value": __props.show, onClose: _cache[0] || (_cache[0] = ($event) => updateShow(false)), class: "my-help-dialog", "align-center": "" }, { header: vue.withCtx(({ titleId, titleClass }) => [ vue.createElementVNode("h4", { id: titleId, class: vue.normalizeClass(titleClass) }, "使用说明", 10, _hoisted_1$2) ]), default: vue.withCtx(() => [ vue.createVNode(vue.unref(elementPlus.ElScrollbar), { height: "70vh" }, { default: vue.withCtx(() => [ _hoisted_2$1, _hoisted_3$1, _hoisted_4$1, _hoisted_5$1 ]), _: 1 }) ]), _: 1 }, 8, ["model-value"]); }; } }; const _hoisted_1$1 = { "element-loading-text": "正在打开...", style: { "height": "108px" } }; const _sfc_main$1 = { __name: "LoadingToast", props: { show: { type: Boolean, default: false } }, emits: ["update:show"], setup(__props, { emit: __emit }) { const emits = __emit; const updateShow = (visible) => { emits("update:show", visible); }; return (_ctx, _cache) => { const _directive_loading = vue.resolveDirective("loading"); return vue.openBlock(), vue.createBlock(vue.unref(elementPlus.ElDialog), { "model-value": __props.show, onClose: _cache[0] || (_cache[0] = ($event) => updateShow(false)), "align-center": "", "show-close": false, modal: false, "close-on-click-modal": false, "close-on-press-escape": false, class: "loading-toast" }, { default: vue.withCtx(() => [ vue.withDirectives(vue.createElementVNode("div", _hoisted_1$1, null, 512), [ [_directive_loading, true] ]) ]), _: 1 }, 8, ["model-value"]); }; } }; const _export_sfc = (sfc, props) => { const target = sfc.__vccOpts || sfc; for (const [key, val] of props) { target[key] = val; } return target; }; const _withScopeId = (n) => (vue.pushScopeId("data-v-3beef0e1"), n = n(), vue.popScopeId(), n); const _hoisted_1 = { style: { "position": "absolute", "top": "5px", "right": "5px" } }; const _hoisted_2 = { style: { "display": "flex", "align-items": "center", "justify-content": "center" } }; const _hoisted_3 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("span", { style: { "margin-left": "8px" } }, "添加至歌单", -1)); const _hoisted_4 = { style: { "display": "flex", "align-items": "center", "justify-content": "center" } }; const _hoisted_5 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("span", { style: { "margin-left": "8px" } }, "添加至", -1)); const _hoisted_6 = { class: "btn-container" }; const _hoisted_7 = { class: "menu-list" }; const _hoisted_8 = ["onClick"]; const _hoisted_9 = { style: { "margin-left": "12px" } }; const _sfc_main = { __name: "App", setup(__props) { const isPlayerExisted = vue.ref(false); const showHelpDialog = vue.ref(false); const isAdding = vue.ref(false); const showLoading = vue.ref(false); let targetWindow = null; const msgHub = []; const menus = vue.ref([ { name: "usage", title: "使用说明", icon: vue.markRaw(Help), handler: () => { showHelpDialog.value = true; } }, { name: "player", title: "打开歌单", icon: vue.markRaw(RecordPlayer), handler: () => { if (!showLoading.value) { showLoading.value = true; } openPlayer(); } } ]); const requestAudioBlobData = (url) => { return new Promise((resolve, reject) => { _GM_xmlhttpRequest({ method: "GET", url, headers: { "referer": "https://hifini.com/" }, responseType: "blob", onload: function(res) { if (!(res == null ? void 0 : res.response)) { resolve(null); } resolve(res.response); }, onerror: function(err) { resolve(null); } }); }); }; const getAudioData = async () => { var _a; let audioItem = null; const targetScript = Array.from(_unsafeWindow.document.querySelectorAll("script")).filter((x) => x.innerHTML).find((x) => x.innerHTML.indexOf("APlayer") !== -1); if (targetScript && targetScript.innerHTML) { const code = targetScript.innerHTML; const matches = code.match(/\[([\s\S]*)\]/igm); if (matches && matches.length) { const musicInfo = matches[0]; const func = new Function(`let a = ${musicInfo}; return a;`); const audioList = func(); if (audioList && audioList.length) { audioItem = audioList[0]; } } } if (audioItem) { audioItem.id = getId(); audioItem.page = _unsafeWindow.location.href; if (/[\u4E00-\u9FFF]+/ig.test(audioItem.url) && ((_a = audioItem.url) == null ? void 0 : _a.startsWith("https"))) { const res = await requestAudioBlobData(audioItem.url); if (res) { audioItem.url = URL.createObjectURL(res); audioItem.storeKey = `no.${audioItem.id}`; idbKeyval.set(audioItem.storeKey, res).catch((err) => { }); } } } return audioItem; }; const getCacheId = () => { let id = null; return () => { if (!id) { id = Date.now(); const result = /(\d+)/.exec(_unsafeWindow.location.pathname); if (result) { id = result[0]; } } return id; }; }; const getId = getCacheId(); const requestPlayerHtmlContent = () => { return new Promise((resolve, reject) => { _GM_xmlhttpRequest({ method: "GET", // url: 'https://gitee.com/fanxiqian/music-player/raw/master/index.txt', url: "https://gitee.com/fanxiqian/music-player/raw/master/home", onload: function(response) { resolve(response.responseText); }, onerror: function(err) { resolve(); } }); }); }; const openPlayerPage = async () => { const playerHtmlFromResource = _GM_getResourceText("player.html"); let fileContent = []; if (playerHtmlFromResource) { fileContent = [playerHtmlFromResource]; } else { const content = await requestPlayerHtmlContent(); if (!content) { elementPlus.ElNotification({ title: "提示", message: "获取播放列表页面出错了,请刷新页面重试", type: "error" }); return; } fileContent = [content]; } const playerBlob = new Blob(fileContent, { type: "text/html" }); const url = URL.createObjectURL(playerBlob); if (!targetWindow) { targetWindow = _unsafeWindow.open(url); } else { if (targetWindow.closed) { targetWindow = _unsafeWindow.open(url); } } targetWindow.focus(); }; const openPlayer = () => { var _a; if (((_a = _unsafeWindow.document.cookie) == null ? void 0 : _a.indexOf("bbs_token")) === -1) { elementPlus.ElNotification({ title: "提示", message: "请先登录 Hifini", type: "warning" }); showLoading.value = false; return; } const channelName = _unsafeWindow.localStorage.getItem("channel"); if (channelName) { if (targetWindow) { targetWindow.focus(); showLoading.value = false; return; } if (!channel) { channel = new BroadcastChannel(channelName); channel.addEventListener("message", (e) => { if (e.data && e.data.from === "player") { msgHub.push(e.data); if (e.data.msg === "heartbeat") { return; } elementPlus.ElNotification({ title: "提示", message: e.data.code === 200 ? "歌曲添加成功" : e.data.msg, type: e.data.code === 200 ? "success" : "warning" }); } }); } const msgId = Date.now(); channel.postMessage({ msg: "heartbeat", msgId }); setTimeout(() => { const idx = msgHub.findIndex((x) => x.msgId == msgId); if (idx !== -1) { msgHub.splice(idx, 1); elementPlus.ElNotification({ title: "提示", message: `歌单页面已存在,请在浏览器标签页或者窗口中查找看看`, type: "info" }); } else { _unsafeWindow.localStorage.removeItem("channel"); channel.close(); channel = null; openPlayer(); } showLoading.value = false; }, 3e3); return; } openPlayerPage(); showLoading.value = false; }; const postAudioDataToPlayer = async (playlistId) => { await openPlayerPage(); if (!targetWindow) { return; } const audioData = await getAudioData(); setTimeout(() => { isAdding.value = false; targetWindow.postMessage({ ...audioData, msgId: Date.now(), playlistId }, "*"); }, 1200); }; const isSongExisted = (id, playlistId) => { var _a, _b; let isExisted = false; try { const storeData = JSON.parse(_unsafeWindow.localStorage.getItem("hifini-helper")); const tPlaylist = (_a = storeData == null ? void 0 : storeData.customPlaylist) == null ? void 0 : _a.find((x) => x.id === playlistId); if ((_b = tPlaylist == null ? void 0 : tPlaylist.songIdList) == null ? void 0 : _b.includes(id)) { isExisted = true; } } catch (error) { } return isExisted; }; let channel = null; const addSong = async (playlistId) => { const id = getId(); if (isSongExisted(id, playlistId)) { elementPlus.ElNotification({ title: "提示", message: "歌曲已存在,请勿重复添加!", type: "warning" }); return; } const channelName = _unsafeWindow.localStorage.getItem("channel"); if (channelName) { isAdding.value = true; if (!channel) { channel = new BroadcastChannel(channelName); channel.addEventListener("message", (e) => { if (e.data && e.data.from === "player") { isAdding.value = false; msgHub.push(e.data); if (e.data.msg === "heartbeat") { return; } elementPlus.ElNotification({ title: "提示", message: e.data.code === 200 ? "歌曲添加成功" : e.data.msg, type: e.data.code === 200 ? "success" : "warning" }); } }); } const audioData2 = await getAudioData(); const msgId = Date.now(); channel.postMessage({ ...audioData2, msgId, playlistId }); setTimeout(() => { isAdding.value = false; const idx = msgHub.findIndex((x) => x.msgId == msgId); if (idx !== -1) { msgHub.splice(idx, 1); } else { _unsafeWindow.localStorage.removeItem("channel"); channel.close(); channel = null; postAudioDataToPlayer(playlistId); } }, 3e3); return; } await openPlayerPage(); if (!targetWindow) { return; } const audioData = await getAudioData(); setTimeout(() => { isAdding.value = false; targetWindow.postMessage({ ...audioData, msgId: Date.now(), playlistId }, "*"); }, 1200); }; _unsafeWindow.addEventListener("message", (e) => { if (e.data === "focus") { window.focus(); } }); const customPlaylist = vue.ref([]); const setCustomPlaylist = () => { var _a; const storeData = JSON.parse(_unsafeWindow.localStorage.getItem("hifini-helper")); const tCustomPlaylist = (_a = storeData == null ? void 0 : storeData.customPlaylist) == null ? void 0 : _a.map((x) => ({ id: x.id, name: x.name })); if ((tCustomPlaylist == null ? void 0 : tCustomPlaylist.length) > 1) { customPlaylist.value = tCustomPlaylist; } else { customPlaylist.value = []; } }; const main = () => { const aplayerElement = document.querySelector(".aplayer"); if (aplayerElement) { isPlayerExisted.value = true; aplayerElement.style.position = "relative"; } setCustomPlaylist(); _unsafeWindow.addEventListener("storage", (event) => { var _a; if ((_a = event.url) == null ? void 0 : _a.startsWith("blob:")) { setCustomPlaylist(); } }); }; main(); return (_ctx, _cache) => { var _a; return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [ isPlayerExisted.value ? (vue.openBlock(), vue.createBlock(vue.Teleport, { key: 0, to: ".aplayer" }, [ vue.createElementVNode("div", _hoisted_1, [ !((_a = customPlaylist.value) == null ? void 0 : _a.length) ? (vue.openBlock(), vue.createBlock(vue.unref(elementPlus.ElButton), { key: 0, style: { "color": "#515151" }, color: "#ffd448", onClick: _cache[0] || (_cache[0] = ($event) => addSong("default")), loading: isAdding.value }, { default: vue.withCtx(() => [ vue.createElementVNode("div", _hoisted_2, [ vue.createVNode(vue.unref(AddMusic), { theme: "outline", size: "22", fill: "#666" }), _hoisted_3 ]) ]), _: 1 }, 8, ["loading"])) : (vue.openBlock(), vue.createBlock(vue.unref(elementPlus.ElDropdown), { key: 1, onCommand: addSong }, { dropdown: vue.withCtx(() => [ vue.createVNode(vue.unref(elementPlus.ElDropdownMenu), null, { default: vue.withCtx(() => [ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(customPlaylist.value, (item, index) => { return vue.openBlock(), vue.createBlock(vue.unref(elementPlus.ElDropdownItem), { key: index, command: item.id }, { default: vue.withCtx(() => [ vue.createTextVNode(vue.toDisplayString(item.name), 1) ]), _: 2 }, 1032, ["command"]); }), 128)) ]), _: 1 }) ]), default: vue.withCtx(() => [ vue.createVNode(vue.unref(elementPlus.ElButton), { style: { "color": "#515151" }, color: "#ffd448", loading: isAdding.value }, { default: vue.withCtx(() => [ vue.createElementVNode("div", _hoisted_4, [ vue.createVNode(vue.unref(AddMusic), { theme: "outline", size: "22", fill: "#666" }), _hoisted_5, vue.createVNode(vue.unref(Down), { style: { "margin-left": "8px" }, theme: "outline", size: "22", fill: "#666" }) ]) ]), _: 1 }, 8, ["loading"]) ]), _: 1 })) ]) ])) : vue.createCommentVNode("", true), vue.createElementVNode("div", _hoisted_6, [ vue.createVNode(vue.unref(elementPlus.ElPopover), { placement: "top-end", trigger: "click", "popper-class": "menu-popper" }, { reference: vue.withCtx(() => [ vue.createVNode(vue.unref(elementPlus.ElButton), { style: { "width": "40px", "height": "40px" }, circle: "" }, { default: vue.withCtx(() => [ vue.createVNode(vue.unref(Record), { theme: "two-tone", size: "30", fill: ["#409c3f", "#ffd448"], strokeWidth: 3 }) ]), _: 1 }) ]), default: vue.withCtx(() => [ vue.createElementVNode("ul", _hoisted_7, [ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(menus.value, (item, index) => { return vue.openBlock(), vue.createElementBlock("li", { key: item.name }, [ vue.createElementVNode("a", { class: "menu-item", onClick: () => item.handler(), href: "javascript: void 0;" }, [ (vue.openBlock(), vue.createBlock(vue.resolveDynamicComponent(item.icon), { size: "22", strokeWidth: 3, fill: "#666", style: { "line-height": "1" } })), vue.createElementVNode("span", _hoisted_9, vue.toDisplayString(item.title), 1) ], 8, _hoisted_8), index !== menus.value.length - 1 ? (vue.openBlock(), vue.createBlock(vue.unref(elementPlus.ElDivider), { key: 0, style: { "margin": "10px 0" } })) : vue.createCommentVNode("", true) ]); }), 128)) ]) ]), _: 1 }) ]), vue.createVNode(_sfc_main$2, { show: showHelpDialog.value, "onUpdate:show": _cache[1] || (_cache[1] = ($event) => showHelpDialog.value = $event) }, null, 8, ["show"]), vue.createVNode(_sfc_main$1, { show: showLoading.value, "onUpdate:show": _cache[2] || (_cache[2] = ($event) => showLoading.value = $event) }, null, 8, ["show"]) ], 64); }; } }; const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-3beef0e1"]]); const cssLoader = (e) => { const t = GM_getResourceText(e); return GM_addStyle(t), t; }; cssLoader("element-plus/dist/index.css"); vue.createApp(App).use(elementPlus.ElLoading).mount( (() => { const app = document.createElement("div"); document.body.append(app); return app; })() ); })(Vue, ElementPlus, idbKeyval);