在您安装前,Greasy Fork镜像 希望您知道此脚本包含可能不受欢迎的功能,也许会帮助脚本作者获利,而不能给你带来任何收益。
这个脚本含有追踪您的操作的代码。
脚本作者的说明:
使用 Google Analytics 了解使用情況
自由轉調、輕鬆練歌,打造 91 譜的最佳體驗!
// ==UserScript== // @name 91 Plus // @namespace https://github.com/DonkeyBear // @version 1.8.4 // @author DonkeyBear // @description 自由轉調、輕鬆練歌,打造 91 譜的最佳體驗! // @icon https://www.91pu.com.tw/icons/favicon-32x32.png // @match *://www.91pu.com.tw/m/* // @match *://www.91pu.com.tw/song/* // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.prod.js // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/zipson.min.js // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/html2canvas.min.js // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/vexchords.dev.min.js // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @grant unsafeWindow // @antifeature tracking 使用 Google Analytics 了解使用情況 // ==/UserScript== (e=>{if(typeof GM_addStyle=="function"){GM_addStyle(e);return}const a=document.createElement("style");a.textContent=e,document.head.append(a)})(' @import"https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css";#trigger-overlay[data-v-658df74c]{position:fixed;top:0;left:0;right:0;bottom:0;z-index:500}.bi[data-v-6e52047a]{color:var(--2b53b793);font-size:var(--4bbf91d1);-webkit-text-stroke:var(--5ab9f408) var(--2b53b793)}.bi[data-v-6e52047a]:before{transition:text-shadow .2s}.bi[active=true][data-v-6e52047a]:before{text-shadow:0 0 .5rem rgb(75,156,169)}.toolbar-icon[data-v-3dbcd695]{cursor:pointer;padding:.25rem .75rem;display:flex;flex-direction:column;align-items:center;gap:.15rem}.toolbar-icon-text[data-v-3dbcd695]{color:color-mix(in srgb,var(--52bb32ad) 70%,rgba(75,156,169,.65));font-size:.5rem;letter-spacing:.15rem;margin-right:-.15rem}.adjust-widget[data-v-cb8ab81d]{display:flex}.adjust-widget .adjust-button[data-v-cb8ab81d]{border:0;border-radius:.25rem;background:transparent}.adjust-widget .adjust-button[data-v-cb8ab81d]:hover{background:rgba(0,0,0,.025)}.adjust-widget .adjust-button[data-v-cb8ab81d]:disabled{opacity:.25}.adjust-widget .adjust-button.adjust-button-middle[data-v-cb8ab81d]{flex-grow:1;color:var(--13e75dc8);font-size:calc(var(--10392328) * .75);font-weight:700}.adjust-widget .adjust-button.adjust-button-left[data-v-cb8ab81d]{padding-right:1rem}.adjust-widget .adjust-button.adjust-button-right[data-v-cb8ab81d]{padding-left:1rem}.slide-and-fade-enter-active[data-v-f161c46c],.slide-and-fade-leave-active[data-v-f161c46c]{transition:all .2s}.slide-and-fade-enter-from[data-v-f161c46c],.slide-and-fade-leave-to[data-v-f161c46c]{transform:translateY(10%);opacity:0}#plus91-sheet-popup[data-v-f161c46c]{position:absolute;left:0;right:0;bottom:100%;background:#fafafa;border:1px solid lightgray;padding:1rem 2rem;border-radius:1rem;margin:.5rem 1rem;max-height:50vh;overflow-y:scroll}#plus91-sheet-popup[data-v-f161c46c]::-webkit-scrollbar{display:none}.transpose-range-container[data-v-f161c46c]{margin-top:1rem}.transpose-range-container input[type=range][data-v-f161c46c]{width:100%}.instrument-select-container[data-v-f161c46c]{display:flex;border:1px solid lightgray;border-radius:.25rem;margin-top:1rem;background:white}.instrument-select-container .instrument-select-button[data-v-f161c46c]{width:33.3333333333%;border:0;border-right:1px solid lightgray;background:transparent;color:#666;padding:.5rem;font-size:.65rem;font-weight:700;cursor:pointer!important}.instrument-select-container .instrument-select-button[data-v-f161c46c]:last-child{border:0;border-radius:0 .25rem .25rem 0}.instrument-select-container .instrument-select-button[data-v-f161c46c]:first-child{border-radius:.25rem 0 0 .25rem}.instrument-select-container .instrument-select-button[data-v-f161c46c]:hover{background:whitesmoke}.chord-container .chord-name[data-v-735734f6]{font-size:.5rem;font-weight:900;color:#666;text-align:center}.chord-container .chord-chart[data-v-735734f6]{margin:-.6rem 0 -.25rem}.slide-and-fade-enter-active[data-v-2210cdf0],.slide-and-fade-leave-active[data-v-2210cdf0]{transition:all .2s}.slide-and-fade-enter-from[data-v-2210cdf0],.slide-and-fade-leave-to[data-v-2210cdf0]{transform:translateY(10%);opacity:0}#plus91-chord-popup[data-v-2210cdf0]{position:absolute;left:0;right:0;bottom:100%;background:#fafafa;border:1px solid lightgray;border-radius:1rem;margin:.5rem 1rem;max-height:50vh;overflow-y:scroll;padding:1rem}#plus91-chord-popup[data-v-2210cdf0]::-webkit-scrollbar{display:none}#plus91-chord-popup .banner[data-v-2210cdf0]{display:flex;align-items:center;background:rgba(75,156,169,.25);color:color-mix(in srgb,rgba(75,156,169,.65) 50%,black 50%);border-radius:.5rem;padding:.5rem .75rem;margin-bottom:.25rem}#plus91-chord-popup .banner section[data-v-2210cdf0]{flex-grow:1;margin-left:.5rem}#plus91-chord-popup .chord-popup-container[data-v-2210cdf0]{display:grid;grid-template-columns:repeat(6,1fr);column-gap:.5rem;padding-top:.4rem}#plus91-chord-popup.banner-only .banner[data-v-2210cdf0]{margin-bottom:0;background:rgba(246,210,102,.25);color:color-mix(in srgb,#f6d266 50%,black 35%)}#plus91-chord-popup.banner-only .chord-popup-container[data-v-2210cdf0]{padding-top:0}.slide-and-fade-enter-active[data-v-eff17405],.slide-and-fade-leave-active[data-v-eff17405]{transition:all .2s}.slide-and-fade-enter-from[data-v-eff17405],.slide-and-fade-leave-to[data-v-eff17405]{transform:translateY(10%);opacity:0}#plus91-font-popup[data-v-eff17405]{position:absolute;left:0;right:0;bottom:100%;background:#fafafa;border:1px solid lightgray;padding:1rem 2rem;border-radius:1rem;margin:.5rem 1rem;max-height:50vh;overflow-y:scroll}#plus91-font-popup[data-v-eff17405]::-webkit-scrollbar{display:none}.slide-and-fade-enter-active[data-v-e329f5af],.slide-and-fade-leave-active[data-v-e329f5af]{transition:all .2s}.slide-and-fade-enter-from[data-v-e329f5af],.slide-and-fade-leave-to[data-v-e329f5af]{transform:translateY(10%);opacity:0}#plus91-settings-popup[data-v-e329f5af]{position:absolute;left:0;right:0;bottom:100%;background:#fafafa;border:1px solid lightgray;border-radius:1rem;margin:.5rem 1rem;max-height:50vh;overflow-y:scroll;padding:1rem}#plus91-settings-popup[data-v-e329f5af]::-webkit-scrollbar{display:none}#plus91-settings-popup .setting-item[data-v-e329f5af]{display:flex;align-items:center;justify-content:space-between;padding:.5rem 1rem;border-radius:.5rem;cursor:pointer}#plus91-settings-popup .setting-item[data-v-e329f5af]:hover{background:rgba(0,0,0,.05)}.icon-button[data-v-e9902592]{display:flex;flex-direction:column;align-items:center;cursor:pointer;padding:0 .6rem .4rem;border-radius:.25rem}.icon-button[data-v-e9902592]:hover{background:rgba(0,0,0,.025)}.icon-button .button-text[data-v-e9902592]{font-size:.5rem;color:var(--9047bc34)}.slide-and-fade-enter-active[data-v-47af8eb5],.slide-and-fade-leave-active[data-v-47af8eb5]{transition:all .2s}.slide-and-fade-enter-from[data-v-47af8eb5],.slide-and-fade-leave-to[data-v-47af8eb5]{transform:translateY(10%);opacity:0}#plus91-menu-popup[data-v-47af8eb5]{position:absolute;left:0;right:0;bottom:100%;background:#fafafa;border:1px solid lightgray;padding:1rem 2rem;border-radius:1rem;margin:.5rem 1rem;max-height:50vh;overflow-y:scroll}#plus91-menu-popup[data-v-47af8eb5]::-webkit-scrollbar{display:none}#plus91-menu-popup .menu-popup-container[data-v-47af8eb5]{display:flex;justify-content:space-around}.hotkey-item[data-v-3c43f6cf]{display:flex;justify-content:space-between;align-items:center;padding:0 .25rem;border-radius:.25rem;height:1.4rem}.hotkey-item[data-v-3c43f6cf]:nth-child(odd){background:rgba(0,0,0,.025)}.desc.title[data-v-3c43f6cf]{font-size:.55rem;color:#999}.hotkeys[data-v-3c43f6cf]{display:flex}.hr[data-v-3c43f6cf]{display:flex;flex-grow:1;border-top:1px solid lightgray;margin-left:.25rem}kbd[data-v-3c43f6cf]{font-size:.6rem;border:solid lightgray;border-width:1px .1rem .15rem;border-radius:.2rem;padding:0 .2rem;letter-spacing:-.025rem;color:#666;margin-left:.15rem}.slide-and-fade-enter-active[data-v-eb86b87c],.slide-and-fade-leave-active[data-v-eb86b87c]{transition:all .2s}.slide-and-fade-enter-from[data-v-eb86b87c],.slide-and-fade-leave-to[data-v-eb86b87c]{transform:translateY(10%);opacity:0}#plus91-hotkey-popup[data-v-eb86b87c]{position:absolute;left:0;right:0;bottom:100%;background:#fafafa;border:1px solid lightgray;padding:1rem 2rem;border-radius:1rem;margin:.5rem 1rem;max-height:50vh;overflow-y:scroll}#plus91-hotkey-popup[data-v-eb86b87c]::-webkit-scrollbar{display:none}#plus91-hotkey-popup .hotkey-popup-container[data-v-eb86b87c]{display:flex;color:#444}#plus91-hotkey-popup section[data-v-eb86b87c]{flex-grow:1;width:50%;margin:-.1rem 0}#plus91-hotkey-popup section.left-part[data-v-eb86b87c]{border-right:1px solid lightgray;margin-left:-.5rem;padding-right:.5rem}#plus91-hotkey-popup section.right-part[data-v-eb86b87c]{padding-left:.5rem;margin-right:-.5rem}#plus91-hotkey-popup kbd[data-v-eb86b87c]{font-size:.65rem;border:solid lightgray;border-width:1px .1rem .15rem;border-radius:.2rem;padding:0 .2rem;letter-spacing:-.025rem;color:#666}.slide-enter-active[data-v-4e274b3c],.slide-leave-active[data-v-4e274b3c]{transition:transform .2s}.slide-enter-from[data-v-4e274b3c],.slide-leave-to[data-v-4e274b3c]{transform:translateY(100%)}#plus91-footer[data-v-4e274b3c]{z-index:1000;display:flex;justify-content:center;position:fixed;left:0;right:0;bottom:0}.footer-container[data-v-4e274b3c]{width:min(100vw,768px);background:rgba(75,156,169,.65);-webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);padding:.25rem .75rem .75rem;display:flex;justify-content:space-between;align-items:center;border-top:1px solid rgb(90,140,160)}@media (min-width: 768px){.footer-container[data-v-4e274b3c]{border-radius:1rem 1rem 0 0}}.slide-enter-active[data-v-5ddafe3d],.slide-leave-active[data-v-5ddafe3d]{transition:transform .2s}.slide-enter-from[data-v-5ddafe3d],.slide-leave-to[data-v-5ddafe3d]{transform:translateY(-100%)}#plus91-header[data-v-5ddafe3d]{z-index:1000;display:flex;justify-content:center;position:fixed;left:0;right:0;top:0}.header-container[data-v-5ddafe3d]{width:min(100vw,768px);background:rgba(75,156,169,.65);-webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);padding:.25rem .75rem;display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid rgb(90,140,160)}@media (min-width: 768px){.header-container[data-v-5ddafe3d]{border-radius:0 0 1rem 1rem}}.header-container input[data-v-5ddafe3d]{flex-grow:1;width:100%;border-radius:50rem;border:0;font-size:.8rem;font-weight:700;padding:.35rem 1.25rem;background:rgba(255,255,255,.6666666667);color:#0009;opacity:.5;transition:all .2s}.header-container input[data-v-5ddafe3d]:focus-visible{outline:0;opacity:1}.fade-enter-active[data-v-6cf58435],.fade-leave-active[data-v-6cf58435]{transition:opacity .2s}.fade-enter-from[data-v-6cf58435],.fade-leave-to[data-v-6cf58435]{opacity:0}#dark-mode-overlay[data-v-6cf58435]{position:fixed;top:0;left:0;right:0;bottom:0;z-index:800;-webkit-backdrop-filter:invert(1) hue-rotate(145deg) saturate(.75);backdrop-filter:invert(1) hue-rotate(145deg) saturate(.75);pointer-events:none}html{background:#fafafa url(/templets/pu/images/tone-bg.gif)}#vue-91plus{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif}.tfunc2{margin:10px}#mtitle{font-family:system-ui}input[type=range],input[type=range]::-webkit-slider-thumb,input[type=range]::-webkit-slider-runnable-track{-webkit-appearance:none;box-shadow:none}input[type=range]::-webkit-slider-thumb,input[type=range]::-webkit-slider-runnable-track{border:1px solid rgba(68,68,68,.25)}input[type=range]::-webkit-slider-thumb{background:#60748d}#viptoneWindow.window,#bottomad,.update_vip_bar,.wmask,header,footer,.autoscroll,.backplace,.set .keys,.set .plays,.set .clear,.setint .hr:nth-child(4),.setint .hr:nth-child(5),.setint .hr:nth-child(6),.adsbygoogle,[class^=AD2M],[id^=adGeek]{display:none!important} '); (function (vue, zipson, vexchords, html2canvas) { 'use strict'; var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var __accessCheck = (obj, member, msg) => { if (!member.has(obj)) throw TypeError("Cannot " + msg); }; var __privateGet = (obj, member, getter) => { __accessCheck(obj, member, "read from private field"); return getter ? getter.call(obj) : member.get(obj); }; var __privateAdd = (obj, member, value) => { if (member.has(obj)) throw TypeError("Cannot add the same private member more than once"); member instanceof WeakSet ? member.add(obj) : member.set(obj, value); }; var __privateSet = (obj, member, value, setter) => { __accessCheck(obj, member, "write to private field"); setter ? setter.call(obj, value) : member.set(obj, value); return value; }; var __privateMethod = (obj, member, method) => { __accessCheck(obj, member, "access private method"); return method; }; var _unformat, unformat_fn, _store, _watchTranspose, watchTranspose_fn, _watchFontSize, watchFontSize_fn; var isVue2 = false; /*! * pinia v2.1.7 * (c) 2023 Eduardo San Martin Morote * @license MIT */ let activePinia; const setActivePinia = (pinia2) => activePinia = pinia2; const piniaSymbol = ( /* istanbul ignore next */ Symbol() ); function isPlainObject(o) { return o && typeof o === "object" && Object.prototype.toString.call(o) === "[object Object]" && typeof o.toJSON !== "function"; } var MutationType; (function(MutationType2) { MutationType2["direct"] = "direct"; MutationType2["patchObject"] = "patch object"; MutationType2["patchFunction"] = "patch function"; })(MutationType || (MutationType = {})); function createPinia() { const scope = vue.effectScope(true); const state = scope.run(() => vue.ref({})); let _p = []; let toBeInstalled = []; const pinia2 = vue.markRaw({ install(app) { setActivePinia(pinia2); { pinia2._a = app; app.provide(piniaSymbol, pinia2); app.config.globalProperties.$pinia = pinia2; toBeInstalled.forEach((plugin) => _p.push(plugin)); toBeInstalled = []; } }, use(plugin) { if (!this._a && !isVue2) { toBeInstalled.push(plugin); } else { _p.push(plugin); } return this; }, _p, // it's actually undefined here // @ts-expect-error _a: null, _e: scope, _s: /* @__PURE__ */ new Map(), state }); return pinia2; } const noop = () => { }; function addSubscription(subscriptions, callback, detached, onCleanup = noop) { subscriptions.push(callback); const removeSubscription = () => { const idx = subscriptions.indexOf(callback); if (idx > -1) { subscriptions.splice(idx, 1); onCleanup(); } }; if (!detached && vue.getCurrentScope()) { vue.onScopeDispose(removeSubscription); } return removeSubscription; } function triggerSubscriptions(subscriptions, ...args) { subscriptions.slice().forEach((callback) => { callback(...args); }); } const fallbackRunWithContext = (fn) => fn(); function mergeReactiveObjects(target, patchToApply) { if (target instanceof Map && patchToApply instanceof Map) { patchToApply.forEach((value, key) => target.set(key, value)); } if (target instanceof Set && patchToApply instanceof Set) { patchToApply.forEach(target.add, target); } for (const key in patchToApply) { if (!patchToApply.hasOwnProperty(key)) continue; const subPatch = patchToApply[key]; const targetValue = target[key]; if (isPlainObject(targetValue) && isPlainObject(subPatch) && target.hasOwnProperty(key) && !vue.isRef(subPatch) && !vue.isReactive(subPatch)) { target[key] = mergeReactiveObjects(targetValue, subPatch); } else { target[key] = subPatch; } } return target; } const skipHydrateSymbol = ( /* istanbul ignore next */ Symbol() ); function shouldHydrate(obj) { return !isPlainObject(obj) || !obj.hasOwnProperty(skipHydrateSymbol); } const { assign } = Object; function isComputed(o) { return !!(vue.isRef(o) && o.effect); } function createOptionsStore(id, options, pinia2, hot) { const { state, actions, getters } = options; const initialState = pinia2.state.value[id]; let store; function setup() { if (!initialState && true) { { pinia2.state.value[id] = state ? state() : {}; } } const localState = vue.toRefs(pinia2.state.value[id]); return assign(localState, actions, Object.keys(getters || {}).reduce((computedGetters, name) => { computedGetters[name] = vue.markRaw(vue.computed(() => { setActivePinia(pinia2); const store2 = pinia2._s.get(id); return getters[name].call(store2, store2); })); return computedGetters; }, {})); } store = createSetupStore(id, setup, options, pinia2, hot, true); return store; } function createSetupStore($id, setup, options = {}, pinia2, hot, isOptionsStore) { let scope; const optionsForPlugin = assign({ actions: {} }, options); const $subscribeOptions = { deep: true // flush: 'post', }; let isListening; let isSyncListening; let subscriptions = []; let actionSubscriptions = []; let debuggerEvents; const initialState = pinia2.state.value[$id]; if (!isOptionsStore && !initialState && true) { { pinia2.state.value[$id] = {}; } } vue.ref({}); let activeListener; function $patch(partialStateOrMutator) { let subscriptionMutation; isListening = isSyncListening = false; if (typeof partialStateOrMutator === "function") { partialStateOrMutator(pinia2.state.value[$id]); subscriptionMutation = { type: MutationType.patchFunction, storeId: $id, events: debuggerEvents }; } else { mergeReactiveObjects(pinia2.state.value[$id], partialStateOrMutator); subscriptionMutation = { type: MutationType.patchObject, payload: partialStateOrMutator, storeId: $id, events: debuggerEvents }; } const myListenerId = activeListener = Symbol(); vue.nextTick().then(() => { if (activeListener === myListenerId) { isListening = true; } }); isSyncListening = true; triggerSubscriptions(subscriptions, subscriptionMutation, pinia2.state.value[$id]); } const $reset = isOptionsStore ? function $reset2() { const { state } = options; const newState = state ? state() : {}; this.$patch(($state) => { assign($state, newState); }); } : ( /* istanbul ignore next */ noop ); function $dispose() { scope.stop(); subscriptions = []; actionSubscriptions = []; pinia2._s.delete($id); } function wrapAction(name, action) { return function() { setActivePinia(pinia2); const args = Array.from(arguments); const afterCallbackList = []; const onErrorCallbackList = []; function after(callback) { afterCallbackList.push(callback); } function onError(callback) { onErrorCallbackList.push(callback); } triggerSubscriptions(actionSubscriptions, { args, name, store, after, onError }); let ret; try { ret = action.apply(this && this.$id === $id ? this : store, args); } catch (error) { triggerSubscriptions(onErrorCallbackList, error); throw error; } if (ret instanceof Promise) { return ret.then((value) => { triggerSubscriptions(afterCallbackList, value); return value; }).catch((error) => { triggerSubscriptions(onErrorCallbackList, error); return Promise.reject(error); }); } triggerSubscriptions(afterCallbackList, ret); return ret; }; } const partialStore = { _p: pinia2, // _s: scope, $id, $onAction: addSubscription.bind(null, actionSubscriptions), $patch, $reset, $subscribe(callback, options2 = {}) { const removeSubscription = addSubscription(subscriptions, callback, options2.detached, () => stopWatcher()); const stopWatcher = scope.run(() => vue.watch(() => pinia2.state.value[$id], (state) => { if (options2.flush === "sync" ? isSyncListening : isListening) { callback({ storeId: $id, type: MutationType.direct, events: debuggerEvents }, state); } }, assign({}, $subscribeOptions, options2))); return removeSubscription; }, $dispose }; const store = vue.reactive(partialStore); pinia2._s.set($id, store); const runWithContext = pinia2._a && pinia2._a.runWithContext || fallbackRunWithContext; const setupStore = runWithContext(() => pinia2._e.run(() => (scope = vue.effectScope()).run(setup))); for (const key in setupStore) { const prop = setupStore[key]; if (vue.isRef(prop) && !isComputed(prop) || vue.isReactive(prop)) { if (!isOptionsStore) { if (initialState && shouldHydrate(prop)) { if (vue.isRef(prop)) { prop.value = initialState[key]; } else { mergeReactiveObjects(prop, initialState[key]); } } { pinia2.state.value[$id][key] = prop; } } } else if (typeof prop === "function") { const actionValue = wrapAction(key, prop); { setupStore[key] = actionValue; } optionsForPlugin.actions[key] = prop; } else ; } { assign(store, setupStore); assign(vue.toRaw(store), setupStore); } Object.defineProperty(store, "$state", { get: () => pinia2.state.value[$id], set: (state) => { $patch(($state) => { assign($state, state); }); } }); pinia2._p.forEach((extender) => { { assign(store, scope.run(() => extender({ store, app: pinia2._a, pinia: pinia2, options: optionsForPlugin }))); } }); if (initialState && isOptionsStore && options.hydrate) { options.hydrate(store.$state, initialState); } isListening = true; isSyncListening = true; return store; } function defineStore(idOrOptions, setup, setupOptions) { let id; let options; const isSetupStore = typeof setup === "function"; if (typeof idOrOptions === "string") { id = idOrOptions; options = isSetupStore ? setupOptions : setup; } else { options = idOrOptions; id = idOrOptions.id; } function useStore2(pinia2, hot) { const hasContext = vue.hasInjectionContext(); pinia2 = // in test mode, ignore the argument provided as we can always retrieve a // pinia instance with getActivePinia() pinia2 || (hasContext ? vue.inject(piniaSymbol, null) : null); if (pinia2) setActivePinia(pinia2); pinia2 = activePinia; if (!pinia2._s.has(id)) { if (isSetupStore) { createSetupStore(id, setup, options, pinia2); } else { createOptionsStore(id, options, pinia2); } } const store = pinia2._s.get(id); return store; } useStore2.$id = id; return useStore2; } function isObject(v) { return typeof v === "object" && v !== null; } function normalizeOptions(options, factoryOptions) { options = isObject(options) ? options : /* @__PURE__ */ Object.create(null); return new Proxy(options, { get(target, key, receiver) { if (key === "key") return Reflect.get(target, key, receiver); return Reflect.get(target, key, receiver) || Reflect.get(factoryOptions, key, receiver); } }); } function get(state, path) { return path.reduce((obj, p) => { return obj == null ? void 0 : obj[p]; }, state); } function set(state, path, val) { return path.slice(0, -1).reduce((obj, p) => { if (/^(__proto__)$/.test(p)) return {}; else return obj[p] = obj[p] || {}; }, state)[path[path.length - 1]] = val, state; } function pick(baseState, paths) { return paths.reduce((substate, path) => { const pathArray = path.split("."); return set(substate, pathArray, get(baseState, pathArray)); }, {}); } function hydrateStore(store, { storage, serializer, key, debug }) { try { const fromStorage = storage == null ? void 0 : storage.getItem(key); if (fromStorage) store.$patch(serializer == null ? void 0 : serializer.deserialize(fromStorage)); } catch (error) { if (debug) console.error(error); } } function persistState(state, { storage, serializer, key, paths, debug }) { try { const toStore = Array.isArray(paths) ? pick(state, paths) : state; storage.setItem(key, serializer.serialize(toStore)); } catch (error) { if (debug) console.error(error); } } function createPersistedState(factoryOptions = {}) { return (context) => { const { auto = false } = factoryOptions; const { options: { persist = auto }, store, pinia: pinia2 } = context; if (!persist) return; if (!(store.$id in pinia2.state.value)) { const original_store = pinia2._s.get(store.$id.replace("__hot:", "")); if (original_store) Promise.resolve().then(() => original_store.$persist()); return; } const persistences = (Array.isArray(persist) ? persist.map((p) => normalizeOptions(p, factoryOptions)) : [normalizeOptions(persist, factoryOptions)]).map( ({ storage = localStorage, beforeRestore = null, afterRestore = null, serializer = { serialize: JSON.stringify, deserialize: JSON.parse }, key = store.$id, paths = null, debug = false }) => { var _a; return { storage, beforeRestore, afterRestore, serializer, key: ((_a = factoryOptions.key) != null ? _a : (k) => k)(typeof key == "string" ? key : key(store.$id)), paths, debug }; } ); store.$persist = () => { persistences.forEach((persistence) => { persistState(store.$state, persistence); }); }; store.$hydrate = ({ runHooks = true } = {}) => { persistences.forEach((persistence) => { const { beforeRestore, afterRestore } = persistence; if (runHooks) beforeRestore == null ? void 0 : beforeRestore(context); hydrateStore(store, persistence); if (runHooks) afterRestore == null ? void 0 : afterRestore(context); }); }; persistences.forEach((persistence) => { const { beforeRestore, afterRestore } = persistence; beforeRestore == null ? void 0 : beforeRestore(context); hydrateStore(store, persistence); afterRestore == null ? void 0 : afterRestore(context); store.$subscribe( (_mutation, state) => { persistState(state, persistence); }, { detached: true } ); }); }; } var src_default = createPersistedState(); const _export_sfc = (sfc, props) => { const target = sfc.__vccOpts || sfc; for (const [key, val] of props) { target[key] = val; } return target; }; const _sfc_main$g = {}; const _hoisted_1$f = { id: "trigger-overlay" }; function _sfc_render(_ctx, _cache) { return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$f); } const TriggerOverlay = /* @__PURE__ */ _export_sfc(_sfc_main$g, [["render", _sfc_render], ["__scopeId", "data-v-658df74c"]]); const _Chord = class _Chord { /** @param {string} chordString */ constructor(chordString) { this.chordString = chordString; } /** * @param {number} delta * @returns {Chord} */ transpose(delta) { this.chordString = this.chordString.replaceAll(/[A-G][#b]?/g, (note) => { const isSharp = _Chord.sharps.includes(note); const scale = isSharp ? _Chord.sharps : _Chord.flats; const noteIndex = scale.indexOf(note); const transposedIndex = (noteIndex + delta + 12) % 12; const transposedNote = scale[transposedIndex]; return transposedNote; }); return this; } /** @returns {Chord} */ switchModifier() { this.chordString = this.chordString.replaceAll(/[A-G][#b]/g, (note) => { const scale = note.includes("#") ? _Chord.sharps : _Chord.flats; const newScale = note.includes("#") ? _Chord.flats : _Chord.sharps; const noteIndex = scale.indexOf(note); return newScale[noteIndex]; }); return this; } /** @returns {Chord} */ useSharpModifier() { this.chordString = this.chordString.replaceAll(/[A-G]b/g, (note) => { const noteIndex = _Chord.flats.indexOf(note); return _Chord.sharps[noteIndex]; }); return this; } /** @returns {Chord} */ useFlatModifier() { this.chordString = this.chordString.replaceAll(/[A-G]#/g, (note) => { const noteIndex = _Chord.sharps.indexOf(note); return _Chord.flats[noteIndex]; }); return this; } /** @returns {string} */ toString() { return this.chordString; } /** @returns {string} */ toFormattedString() { return this.chordString.replaceAll( /[#b]/g, /* html */ `<sup>$&</sup>` ); } }; __publicField(_Chord, "sharps", ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]); __publicField(_Chord, "flats", ["C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"]); let Chord = _Chord; var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)(); var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)(); var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)(); class MonkeyStorage { /** * @param {String} key * @returns {String|null} */ static getItem(key) { if (_GM_getValue) { return _GM_getValue(key, null); } else { return localStorage.getItem(key); } } /** * @param {String} key * @param {String} value * @returns {void} */ static setItem(key, value) { if (_GM_setValue) { _GM_setValue(key, value); } else { localStorage.setItem(key, value); } } } const useStore = defineStore("store", { state() { return { // #################### // 元件相關狀態 // #################### isDarkMode: false, isToolbarsShow: false, isPopupShow: { sheet: false, chord: false, font: false, settings: false, menu: false, // 選單內功能 hotkey: false }, // #################### // 偏好設定相關狀態 // #################### agreeToArchiveSheet: true, // #################### // 譜面相關狀態 // #################### transpose: 0, /** 在 `StoreHandler` 裡賦值 */ originalCapo: 0, /** 在 `StoreHandler` 裡賦值,HTML 格式 */ originalKey: "", /** `font-size` 的變化值 */ fontSizeDelta: 0, /** 在 `StoreHandler` 裡賦值,單位為 px */ originalFontSize: 0, /** 在 `StoreHandler` 裡賦值,單位為 px */ originalLineHeight: 0 }; }, persist: { key: "plus91-preferences", storage: MonkeyStorage, deserialize: zipson.parse, serialize: zipson.stringify, paths: ["isDarkMode", "agreeToArchiveSheet"], beforeRestore() { console.log("[91 Plus] 讀取偏好設置中"); }, afterRestore() { console.log("[91 Plus] 偏好設置讀取完畢"); }, debug: true }, getters: { currentCapo() { return this.originalCapo + this.transpose; }, currentKey() { return new Chord(this.originalKey).transpose(-this.transpose).toFormattedString(); } }, actions: { toggleToolbars() { if (this.isToolbarsShow) { this.closePopups(); } else { this.isPopupShow.sheet = true; } this.isToolbarsShow = !this.isToolbarsShow; }, closePopups() { for (const popup in this.isPopupShow) { this.isPopupShow[popup] = false; } }, /** @param {'sheet'|'chord'|'font'|'settings'|'menu'|'hotkey'} name */ togglePopup(name) { for (const popup in this.isPopupShow) { if (popup === name) { this.isPopupShow[popup] = !this.isPopupShow[popup]; } else { this.isPopupShow[popup] = false; } } }, plusTranspose(numberToPlus) { let newTranspose = this.transpose + numberToPlus; const newCapo = this.originalCapo + newTranspose; if (newCapo === 12 || newCapo === -12) { newTranspose = -this.originalCapo; } this.transpose = newTranspose; } } }); const _hoisted_1$e = ["active"]; const _sfc_main$f = { __name: "BootstrapIcon", props: { icon: { type: String, required: true }, color: { type: String, default: "whitesmoke" }, size: { type: String, default: "1rem" }, stroke: { type: String, default: "0" }, active: { type: Boolean, default: false } }, setup(__props) { vue.useCssVars((_ctx) => ({ "2b53b793": __props.color, "4bbf91d1": __props.size, "5ab9f408": __props.stroke })); const props = __props; return (_ctx, _cache) => { return vue.openBlock(), vue.createElementBlock("i", { class: vue.normalizeClass(`bi bi-${props.icon}`), active: props.active }, null, 10, _hoisted_1$e); }; } }; const BootstrapIcon = /* @__PURE__ */ _export_sfc(_sfc_main$f, [["__scopeId", "data-v-6e52047a"]]); const _hoisted_1$d = { class: "toolbar-icon" }; const _hoisted_2$c = { class: "toolbar-icon-text" }; const _sfc_main$e = { __name: "ToolbarIcon", props: { icon: { type: String, required: true }, text: { type: String, required: true }, stroke: { type: String, default: "0" }, active: { type: Boolean, default: false }, color: { type: String, default: "whitesmoke" } }, setup(__props) { vue.useCssVars((_ctx) => ({ "52bb32ad": __props.color })); const props = __props; return (_ctx, _cache) => { return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$d, [ vue.createVNode(BootstrapIcon, { size: "1.3rem", icon: props.icon, color: props.color, stroke: props.stroke, active: props.active }, null, 8, ["icon", "color", "stroke", "active"]), vue.createElementVNode("div", _hoisted_2$c, vue.toDisplayString(props.text), 1) ]); }; } }; const ToolbarIcon = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["__scopeId", "data-v-3dbcd695"]]); const _hoisted_1$c = { class: "adjust-widget" }; const _hoisted_2$b = ["disabled"]; const _hoisted_3$5 = ["disabled"]; const _hoisted_4$3 = ["disabled"]; const _sfc_main$d = { __name: "AdjustWidget", props: { iconLeft: { type: String, default: "caret-left-fill" }, iconRight: { type: String, default: "caret-right-fill" }, disabledLeft: { type: Boolean, default: false }, disabledMiddle: { type: Boolean, default: false }, disabledRight: { type: Boolean, default: false }, color: { type: String, default: "#444" }, size: { type: String, default: "1.25rem" }, onclickLeft: Function, onclickMiddle: Function, onclickRight: Function }, setup(__props) { vue.useCssVars((_ctx) => ({ "13e75dc8": __props.color, "10392328": __props.size })); const props = __props; return (_ctx, _cache) => { return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$c, [ vue.createElementVNode("button", { class: "adjust-button adjust-button-left", onClick: _cache[0] || (_cache[0] = (...args) => props.onclickLeft && props.onclickLeft(...args)), disabled: props.disabledLeft }, [ vue.createVNode(BootstrapIcon, { icon: props.iconLeft, color: props.color, size: props.size }, null, 8, ["icon", "color", "size"]) ], 8, _hoisted_2$b), vue.createElementVNode("button", { class: "adjust-button adjust-button-middle", onClick: _cache[1] || (_cache[1] = (...args) => props.onclickMiddle && props.onclickMiddle(...args)), disabled: props.disabledMiddle }, [ vue.renderSlot(_ctx.$slots, "default", {}, void 0, true) ], 8, _hoisted_3$5), vue.createElementVNode("button", { class: "adjust-button adjust-button-right", onClick: _cache[2] || (_cache[2] = (...args) => props.onclickRight && props.onclickRight(...args)), disabled: props.disabledRight }, [ vue.createVNode(BootstrapIcon, { icon: props.iconRight, color: props.color, size: props.size }, null, 8, ["icon", "color", "size"]) ], 8, _hoisted_4$3) ]); }; } }; const AdjustWidget = /* @__PURE__ */ _export_sfc(_sfc_main$d, [["__scopeId", "data-v-cb8ab81d"]]); class ChordSheetElement { /** @param {HTMLElement} chordSheetElement */ constructor(chordSheetElement) { /** @param {NodeList} nodeList */ __privateAdd(this, _unformat); this.chordSheetElement = chordSheetElement; } /** * 將 Header 和譜上的和弦移調,並實質修改於 DOM * @param {number} delta 相對於當前調的移調值 */ static transposeSheet(delta) { $("#tone_z .tf").each(function() { const chord = new Chord($(this).text()); const newChordHTML = chord.transpose(-delta).toFormattedString(); $(this).html(newChordHTML); }); } /** @returns {ChordSheetElement} */ formatUnderlines() { const underlineEl = this.chordSheetElement.querySelectorAll("u"); const doubleUnderlineEl = this.chordSheetElement.querySelectorAll("abbr"); underlineEl.forEach((el) => { el.innerText = `{_${el.innerText}_}`; }); doubleUnderlineEl.forEach((el) => { el.innerText = `{=${el.innerText}=}`; }); return this; } /** @returns {ChordSheetElement} */ unformatUnderlines() { const underlineEl = this.chordSheetElement.querySelectorAll("u"); const doubleUnderlineEl = this.chordSheetElement.querySelectorAll("abbr"); __privateMethod(this, _unformat, unformat_fn).call(this, underlineEl); __privateMethod(this, _unformat, unformat_fn).call(this, doubleUnderlineEl); return this; } } _unformat = new WeakSet(); unformat_fn = function(nodeList) { nodeList.forEach((el) => { el.innerHTML = el.innerText.replaceAll(/{_|{=|=}|_}/g, "").replaceAll( /[a-zA-Z0-9#/]+/g, /* html */ `<span class="tf">$&</span>` ); }); }; class ChordSheetDocument { constructor() { this.el = { mtitle: document.getElementById("mtitle"), tkinfo: document.querySelector(".tkinfo"), capoSelect: document.querySelector(".capo .select"), tinfo: document.querySelector(".tinfo"), tone_z: document.getElementById("tone_z") }; } getId() { const urlParams = new URLSearchParams(window.location.search); return Number(urlParams.get("id")); } getTitle() { return this.el.mtitle.innerText.trim(); } getKey() { var _a; const match = (_a = this.el.tkinfo) == null ? void 0 : _a.innerText.match(new RegExp("(?<=原調:)\\w*")); return match ? match[0].trim() : ""; } getPlay() { var _a; const match = (_a = this.el.capoSelect) == null ? void 0 : _a.innerText.split(/\s*\/\s*/); return match ? match[1].trim() : ""; } getCapo() { var _a; const match = (_a = this.el.capoSelect) == null ? void 0 : _a.innerText.split(/\s*\/\s*/); return match ? Number(match[0]) : 0; } getSinger() { var _a; const match = (_a = this.el.tinfo) == null ? void 0 : _a.innerText.match(new RegExp("(?<=演唱:).*(?=\\n|$)")); return match ? match[0].trim() : ""; } getComposer() { var _a; const match = (_a = this.el.tinfo) == null ? void 0 : _a.innerText.match(new RegExp("(?<=曲:).*?(?=詞:|$)")); return match ? match[0].trim() : ""; } getLyricist() { var _a; const match = (_a = this.el.tinfo) == null ? void 0 : _a.innerText.match(new RegExp("(?<=詞:).*?(?=曲:|$)")); return match ? match[0].trim() : ""; } getBpm() { var _a; const match = (_a = this.el.tkinfo) == null ? void 0 : _a.innerText.match(/\d+/); return match ? Number(match[0]) : 0; } getSheetText() { const formattedChordSheet = this.el.tone_z.innerText.replaceAll(/\s+?\n/g, "\n").replaceAll("\n\n", "\n").trim().replaceAll(/\s+/g, (match) => { return `{%${match.length}%}`; }); return formattedChordSheet; } } class StoreHandler { constructor() { /** 當 `#store.transpose` 變動時,將譜面上的和弦進行移調 */ __privateAdd(this, _watchTranspose); __privateAdd(this, _watchFontSize); // 命 `#store` 為私有屬性,在建立實例時再賦值,避免衝突 __privateAdd(this, _store, void 0); __privateSet(this, _store, useStore()); } initState() { const capoSelected = $(".capo .select").eq(0).text().trim(); const originalCapo = +capoSelected.split(/\s*\/\s*/)[0]; const originalKey = capoSelected.split(/\s*\/\s*/)[1]; __privateGet(this, _store).originalCapo = originalCapo; __privateGet(this, _store).originalKey = originalKey; const fontSize = +$("#tone_z").css("font-size").match(/^\d+/)[0]; const lineHeight = +$("#tone_z > p").css("line-height").match(/^\d+/)[0]; __privateGet(this, _store).originalFontSize = fontSize; __privateGet(this, _store).originalLineHeight = lineHeight; const params = getQueryParams(); if (params.transpose) { __privateGet(this, _store).transpose = params.transpose; } } start() { __privateMethod(this, _watchTranspose, watchTranspose_fn).call(this); __privateMethod(this, _watchFontSize, watchFontSize_fn).call(this); return this; } static handleKeydown(key) { const store = useStore(); switch (key) { case " ": { store.toggleToolbars(); break; } case "/": { if (!store.isToolbarsShow) { store.toggleToolbars(); store.closePopups(); } setTimeout(() => { $("#plus91-header input").get(0).focus(); }, 0); break; } case "Escape": { if (store.isToolbarsShow) { store.toggleToolbars(); } break; } } if (store.isPopupShow.sheet) { switch (key) { case "ArrowLeft": { store.plusTranspose(-1); break; } case "ArrowRight": { store.plusTranspose(1); break; } case "ArrowDown": { store.transpose = 0; break; } } } } } _store = new WeakMap(); _watchTranspose = new WeakSet(); watchTranspose_fn = function() { vue.watch(() => { return __privateGet(this, _store).transpose; }, (newValue, oldValue) => { ChordSheetElement.transposeSheet((newValue - oldValue) % 12); }); }; _watchFontSize = new WeakSet(); watchFontSize_fn = function() { vue.watch(() => { return __privateGet(this, _store).fontSizeDelta; }, (newValue) => { const oFontSize = __privateGet(this, _store).originalFontSize; const oLineHeight = __privateGet(this, _store).originalLineHeight; $("#tone_z").css("font-size", `${oFontSize + newValue}px`); $("#tone_z > p").css("line-height", `${oLineHeight + newValue}px`); }); }; var LIBVERSION = "2.0.0-beta.3", EMPTY = "", UNKNOWN = "?", FUNC_TYPE = "function", UNDEF_TYPE = "undefined", OBJ_TYPE = "object", STR_TYPE = "string", MAJOR = "major", MODEL = "model", NAME = "name", TYPE = "type", VENDOR = "vendor", VERSION = "version", ARCHITECTURE = "architecture", CONSOLE = "console", MOBILE = "mobile", TABLET = "tablet", SMARTTV = "smarttv", WEARABLE = "wearable", XR = "xr", EMBEDDED = "embedded", USER_AGENT = "user-agent", UA_MAX_LENGTH = 500, BRANDS = "brands", FORMFACTORS = "formFactors", FULLVERLIST = "fullVersionList", PLATFORM = "platform", PLATFORMVER = "platformVersion", BITNESS = "bitness", CH_HEADER = "sec-ch-ua", CH_HEADER_FULL_VER_LIST = CH_HEADER + "-full-version-list", CH_HEADER_ARCH = CH_HEADER + "-arch", CH_HEADER_BITNESS = CH_HEADER + "-" + BITNESS, CH_HEADER_FORM_FACTORS = CH_HEADER + "-form-factors", CH_HEADER_MOBILE = CH_HEADER + "-" + MOBILE, CH_HEADER_MODEL = CH_HEADER + "-" + MODEL, CH_HEADER_PLATFORM = CH_HEADER + "-" + PLATFORM, CH_HEADER_PLATFORM_VER = CH_HEADER_PLATFORM + "-version", CH_ALL_VALUES = [BRANDS, FULLVERLIST, MOBILE, MODEL, PLATFORM, PLATFORMVER, ARCHITECTURE, FORMFACTORS, BITNESS], UA_BROWSER = "browser", UA_CPU = "cpu", UA_DEVICE = "device", UA_ENGINE = "engine", UA_OS = "os", UA_RESULT = "result", AMAZON = "Amazon", APPLE = "Apple", ASUS = "ASUS", BLACKBERRY = "BlackBerry", GOOGLE = "Google", HUAWEI = "Huawei", LENOVO = "Lenovo", LG = "LG", MICROSOFT = "Microsoft", MOTOROLA = "Motorola", SAMSUNG = "Samsung", SHARP = "Sharp", SONY = "Sony", XIAOMI = "Xiaomi", ZEBRA = "Zebra", PREFIX_MOBILE = "Mobile ", SUFFIX_BROWSER = " Browser", CHROME = "Chrome", EDGE = "Edge", FIREFOX = "Firefox", OPERA = "Opera", FACEBOOK = "Facebook", SOGOU = "Sogou", WINDOWS = "Windows"; var isWindow = typeof window !== UNDEF_TYPE, NAVIGATOR = isWindow && window.navigator ? window.navigator : void 0, NAVIGATOR_UADATA = NAVIGATOR && NAVIGATOR.userAgentData ? NAVIGATOR.userAgentData : void 0; var extend = function(defaultRgx, extensions) { var mergedRgx = {}; var extraRgx = extensions; if (!isExtensions(extensions)) { extraRgx = {}; for (var i in extensions) { for (var j in extensions[i]) { extraRgx[j] = extensions[i][j].concat(extraRgx[j] ? extraRgx[j] : []); } } } for (var k in defaultRgx) { mergedRgx[k] = extraRgx[k] && extraRgx[k].length % 2 === 0 ? extraRgx[k].concat(defaultRgx[k]) : defaultRgx[k]; } return mergedRgx; }, enumerize = function(arr) { var enums = {}; for (var i = 0; i < arr.length; i++) { enums[arr[i].toUpperCase()] = arr[i]; } return enums; }, has = function(str1, str2) { if (typeof str1 === OBJ_TYPE && str1.length > 0) { for (var i in str1) { if (lowerize(str1[i]) == lowerize(str2)) return true; } return false; } return isString(str1) ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false; }, isExtensions = function(obj, deep) { for (var prop in obj) { return /^(browser|cpu|device|engine|os)$/.test(prop) || (deep ? isExtensions(obj[prop]) : false); } }, isString = function(val) { return typeof val === STR_TYPE; }, itemListToArray = function(header) { if (!header) return void 0; var arr = []; var tokens = strip(/\\?\"/g, header).split(","); for (var i = 0; i < tokens.length; i++) { if (tokens[i].indexOf(";") > -1) { var token = trim(tokens[i]).split(";v="); arr[i] = { brand: token[0], version: token[1] }; } else { arr[i] = trim(tokens[i]); } } return arr; }, lowerize = function(str) { return isString(str) ? str.toLowerCase() : str; }, majorize = function(version) { return isString(version) ? strip(/[^\d\.]/g, version).split(".")[0] : void 0; }, setProps = function(arr) { for (var i in arr) { var propName = arr[i]; if (typeof propName == OBJ_TYPE && propName.length == 2) { this[propName[0]] = propName[1]; } else { this[propName] = void 0; } } return this; }, strip = function(pattern, str) { return isString(str) ? str.replace(pattern, EMPTY) : str; }, stripQuotes = function(str) { return strip(/\\?\"/g, str); }, trim = function(str, len) { if (isString(str)) { str = strip(/^\s\s*/, str); return typeof len === UNDEF_TYPE ? str : str.substring(0, UA_MAX_LENGTH); } }; var rgxMapper = function(ua, arrays) { if (!ua || !arrays) return; var i = 0, j, k, p, q, matches, match; while (i < arrays.length && !matches) { var regex = arrays[i], props = arrays[i + 1]; j = k = 0; while (j < regex.length && !matches) { if (!regex[j]) { break; } matches = regex[j++].exec(ua); if (!!matches) { for (p = 0; p < props.length; p++) { match = matches[++k]; q = props[p]; if (typeof q === OBJ_TYPE && q.length > 0) { if (q.length === 2) { if (typeof q[1] == FUNC_TYPE) { this[q[0]] = q[1].call(this, match); } else { this[q[0]] = q[1]; } } else if (q.length === 3) { if (typeof q[1] === FUNC_TYPE && !(q[1].exec && q[1].test)) { this[q[0]] = match ? q[1].call(this, match, q[2]) : void 0; } else { this[q[0]] = match ? match.replace(q[1], q[2]) : void 0; } } else if (q.length === 4) { this[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : void 0; } } else { this[q] = match ? match : void 0; } } } } i += 2; } }, strMapper = function(str, map) { for (var i in map) { if (typeof map[i] === OBJ_TYPE && map[i].length > 0) { for (var j = 0; j < map[i].length; j++) { if (has(map[i][j], str)) { return i === UNKNOWN ? void 0 : i; } } } else if (has(map[i], str)) { return i === UNKNOWN ? void 0 : i; } } return map.hasOwnProperty("*") ? map["*"] : str; }; var windowsVersionMap = { "ME": "4.90", "NT 3.11": "NT3.51", "NT 4.0": "NT4.0", "2000": "NT 5.0", "XP": ["NT 5.1", "NT 5.2"], "Vista": "NT 6.0", "7": "NT 6.1", "8": "NT 6.2", "8.1": "NT 6.3", "10": ["NT 6.4", "NT 10.0"], "RT": "ARM" }, formFactorsMap = { "embedded": "Automotive", "mobile": "Mobile", "tablet": ["Tablet", "EInk"], "smarttv": "TV", "wearable": "Watch", "xr": ["VR", "XR"], "?": ["Desktop", "Unknown"], "*": void 0 }; var defaultRegexes = { browser: [ [ // Most common regardless engine /\b(?:crmo|crios)\/([\w\.]+)/i // Chrome for Android/iOS ], [VERSION, [NAME, PREFIX_MOBILE + "Chrome"]], [ /edg(?:e|ios|a)?\/([\w\.]+)/i // Microsoft Edge ], [VERSION, [NAME, "Edge"]], [ // Presto based /(opera mini)\/([-\w\.]+)/i, // Opera Mini /(opera [mobiletab]{3,6})\b.+version\/([-\w\.]+)/i, // Opera Mobi/Tablet /(opera)(?:.+version\/|[\/ ]+)([\w\.]+)/i // Opera ], [NAME, VERSION], [ /opios[\/ ]+([\w\.]+)/i // Opera mini on iphone >= 8.0 ], [VERSION, [NAME, OPERA + " Mini"]], [ /\bop(?:rg)?x\/([\w\.]+)/i // Opera GX ], [VERSION, [NAME, OPERA + " GX"]], [ /\bopr\/([\w\.]+)/i // Opera Webkit ], [VERSION, [NAME, OPERA]], [ // Mixed /\bb[ai]*d(?:uhd|[ub]*[aekoprswx]{5,6})[\/ ]?([\w\.]+)/i // Baidu ], [VERSION, [NAME, "Baidu"]], [ /(kindle)\/([\w\.]+)/i, // Kindle /(lunascape|maxthon|netfront|jasmine|blazer|sleipnir)[\/ ]?([\w\.]*)/i, // Lunascape/Maxthon/Netfront/Jasmine/Blazer/Sleipnir // Trident based /(avant|iemobile|slim)\s?(?:browser)?[\/ ]?([\w\.]*)/i, // Avant/IEMobile/SlimBrowser /(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer // Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|duckduckgo|klar)\/([-\w\.]+)/i, // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo/Klar /(heytap|ovi)browser\/([\d\.]+)/i, // HeyTap/Ovi /(weibo)__([\d\.]+)/i // Weibo ], [NAME, VERSION], [ /\bddg\/([\w\.]+)/i // DuckDuckGo ], [VERSION, [NAME, "DuckDuckGo"]], [ /(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i // UCBrowser ], [VERSION, [NAME, "UCBrowser"]], [ /microm.+\bqbcore\/([\w\.]+)/i, // WeChat Desktop for Windows Built-in Browser /\bqbcore\/([\w\.]+).+microm/i, /micromessenger\/([\w\.]+)/i // WeChat ], [VERSION, [NAME, "WeChat"]], [ /konqueror\/([\w\.]+)/i // Konqueror ], [VERSION, [NAME, "Konqueror"]], [ /trident.+rv[: ]([\w\.]{1,9})\b.+like gecko/i // IE11 ], [VERSION, [NAME, "IE"]], [ /ya(?:search)?browser\/([\w\.]+)/i // Yandex ], [VERSION, [NAME, "Yandex"]], [ /slbrowser\/([\w\.]+)/i // Smart Lenovo Browser ], [VERSION, [NAME, "Smart " + LENOVO + SUFFIX_BROWSER]], [ /(avast|avg)\/([\w\.]+)/i // Avast/AVG Secure Browser ], [[NAME, /(.+)/, "$1 Secure" + SUFFIX_BROWSER], VERSION], [ /\bfocus\/([\w\.]+)/i // Firefox Focus ], [VERSION, [NAME, FIREFOX + " Focus"]], [ /\bopt\/([\w\.]+)/i // Opera Touch ], [VERSION, [NAME, OPERA + " Touch"]], [ /coc_coc\w+\/([\w\.]+)/i // Coc Coc Browser ], [VERSION, [NAME, "Coc Coc"]], [ /dolfin\/([\w\.]+)/i // Dolphin ], [VERSION, [NAME, "Dolphin"]], [ /coast\/([\w\.]+)/i // Opera Coast ], [VERSION, [NAME, OPERA + " Coast"]], [ /miuibrowser\/([\w\.]+)/i // MIUI Browser ], [VERSION, [NAME, "MIUI" + SUFFIX_BROWSER]], [ /fxios\/([\w\.-]+)/i // Firefox for iOS ], [VERSION, [NAME, PREFIX_MOBILE + FIREFOX]], [ /\bqihu|(qi?ho?o?|360)browser/i // 360 ], [[NAME, "360" + SUFFIX_BROWSER]], [ /\b(qq)\/([\w\.]+)/i // QQ ], [[NAME, /(.+)/, "$1Browser"], VERSION], [ /(oculus|sailfish|huawei|vivo|pico)browser\/([\w\.]+)/i ], [[NAME, /(.+)/, "$1" + SUFFIX_BROWSER], VERSION], [ // Oculus/Sailfish/HuaweiBrowser/VivoBrowser/PicoBrowser /samsungbrowser\/([\w\.]+)/i // Samsung Internet ], [VERSION, [NAME, SAMSUNG + " Internet"]], [ /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon ], [[NAME, /_/g, " "], VERSION], [ /metasr[\/ ]?([\d\.]+)/i // Sogou Explorer ], [VERSION, [NAME, SOGOU + " Explorer"]], [ /(sogou)mo\w+\/([\d\.]+)/i // Sogou Mobile ], [[NAME, SOGOU + " Mobile"], VERSION], [ /(electron)\/([\w\.]+) safari/i, // Electron-based App /(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w\.]+))/i, // Tesla /m?(qqbrowser|2345Explorer)[\/ ]?([\w\.]+)/i // QQBrowser/2345 Browser ], [NAME, VERSION], [ /(lbbrowser|rekonq)/i, // LieBao Browser/Rekonq /\[(linkedin)app\]/i // LinkedIn App for iOS & Android ], [NAME], [ // WebView /((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w\.]+);)/i // Facebook App for iOS & Android ], [[NAME, FACEBOOK], VERSION], [ /(Klarna)\/([\w\.]+)/i, // Klarna Shopping Browser for iOS & Android /(kakao(?:talk|story))[\/ ]([\w\.]+)/i, // Kakao App /(naver)\(.*?(\d+\.[\w\.]+).*\)/i, // Naver InApp /safari (line)\/([\w\.]+)/i, // Line App for iOS /\b(line)\/([\w\.]+)\/iab/i, // Line App for Android /(alipay)client\/([\w\.]+)/i, // Alipay /(twitter)(?:and| f.+e\/([\w\.]+))/i, // Twitter /(chromium|instagram|snapchat)[\/ ]([-\w\.]+)/i // Chromium/Instagram/Snapchat ], [NAME, VERSION], [ /\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS ], [VERSION, [NAME, "GSA"]], [ /musical_ly(?:.+app_?version\/|_)([\w\.]+)/i // TikTok ], [VERSION, [NAME, "TikTok"]], [ /headlesschrome(?:\/([\w\.]+)| )/i // Chrome Headless ], [VERSION, [NAME, CHROME + " Headless"]], [ / wv\).+(chrome)\/([\w\.]+)/i // Chrome WebView ], [[NAME, CHROME + " WebView"], VERSION], [ /droid.+ version\/([\w\.]+)\b.+(?:mobile safari|safari)/i // Android Browser ], [VERSION, [NAME, "Android" + SUFFIX_BROWSER]], [ /chrome\/([\w\.]+) mobile/i // Chrome Mobile ], [VERSION, [NAME, PREFIX_MOBILE + "Chrome"]], [ /(chrome|omniweb|arora|[tizenoka]{5} ?browser)\/v?([\w\.]+)/i // Chrome/OmniWeb/Arora/Tizen/Nokia ], [NAME, VERSION], [ /version\/([\w\.\,]+) .*mobile(?:\/\w+ | ?)safari/i // Safari Mobile ], [VERSION, [NAME, PREFIX_MOBILE + "Safari"]], [ /iphone .*mobile(?:\/\w+ | ?)safari/i ], [[NAME, PREFIX_MOBILE + "Safari"]], [ /version\/([\w\.\,]+) .*(safari)/i // Safari ], [VERSION, NAME], [ /webkit.+?(mobile ?safari|safari)(\/[\w\.]+)/i // Safari < 3.0 ], [NAME, [VERSION, "1"]], [ /(webkit|khtml)\/([\w\.]+)/i ], [NAME, VERSION], [ // Gecko based /(?:mobile|tablet);.*(firefox)\/([\w\.-]+)/i // Firefox Mobile ], [[NAME, PREFIX_MOBILE + FIREFOX], VERSION], [ /(navigator|netscape\d?)\/([-\w\.]+)/i // Netscape ], [[NAME, "Netscape"], VERSION], [ /(wolvic)\/([\w\.]+)/i // Wolvic ], [NAME, VERSION], [ /mobile vr; rv:([\w\.]+)\).+firefox/i // Firefox Reality ], [VERSION, [NAME, FIREFOX + " Reality"]], [ /ekiohf.+(flow)\/([\w\.]+)/i, // Flow /(swiftfox)/i, // Swiftfox /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror)[\/ ]?([\w\.\+]+)/i, // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror /(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([-\w\.]+)$/i, // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix /(firefox)\/([\w\.]+)/i, // Other Firefox-based /(mozilla)\/([\w\.]+) .+rv\:.+gecko\/\d+/i, // Mozilla // Other /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i, // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Obigo/Mosaic/Go/ICE/UP.Browser /(links) \(([\w\.]+)/i // Links ], [NAME, [VERSION, /_/g, "."]], [ /(cobalt)\/([\w\.]+)/i // Cobalt ], [NAME, [VERSION, /[^\d\.]+./, EMPTY]] ], cpu: [ [ /\b(?:(amd|x|x86[-_]?|wow|win)64)\b/i // AMD64 (x64) ], [[ARCHITECTURE, "amd64"]], [ /(ia32(?=;))/i, // IA32 (quicktime) /((?:i[346]|x)86)[;\)]/i // IA32 (x86) ], [[ARCHITECTURE, "ia32"]], [ /\b(aarch64|arm(v?8e?l?|_?64))\b/i // ARM64 ], [[ARCHITECTURE, "arm64"]], [ /\b(arm(?:v[67])?ht?n?[fl]p?)\b/i // ARMHF ], [[ARCHITECTURE, "armhf"]], [ // PocketPC mistakenly identified as PowerPC /windows (ce|mobile); ppc;/i ], [[ARCHITECTURE, "arm"]], [ /((?:ppc|powerpc)(?:64)?)(?: mac|;|\))/i // PowerPC ], [[ARCHITECTURE, /ower/, EMPTY, lowerize]], [ /(sun4\w)[;\)]/i // SPARC ], [[ARCHITECTURE, "sparc"]], [ /((?:avr32|ia64(?=;))|68k(?=\))|\barm(?=v(?:[1-7]|[5-7]1)l?|;|eabi)|(?=atmel )avr|(?:irix|mips|sparc)(?:64)?\b|pa-risc)/i // IA64, 68K, ARM/64, AVR/32, IRIX/64, MIPS/64, SPARC/64, PA-RISC ], [[ARCHITECTURE, lowerize]] ], device: [ [ ////////////////////////// // MOBILES & TABLETS ///////////////////////// // Samsung /\b(sch-i[89]0\d|shw-m380s|sm-[ptx]\w{2,4}|gt-[pn]\d{2,4}|sgh-t8[56]9|nexus 10)/i ], [MODEL, [VENDOR, SAMSUNG], [TYPE, TABLET]], [ /\b((?:s[cgp]h|gt|sm)-\w+|sc[g-]?[\d]+a?|galaxy nexus)/i, /samsung[- ]([-\w]+)/i, /sec-(sgh\w+)/i ], [MODEL, [VENDOR, SAMSUNG], [TYPE, MOBILE]], [ // Apple /(?:\/|\()(ip(?:hone|od)[\w, ]*)(?:\/|;)/i // iPod/iPhone ], [MODEL, [VENDOR, APPLE], [TYPE, MOBILE]], [ /\((ipad);[-\w\),; ]+apple/i, // iPad /applecoremedia\/[\w\.]+ \((ipad)/i, /\b(ipad)\d\d?,\d\d?[;\]].+ios/i ], [MODEL, [VENDOR, APPLE], [TYPE, TABLET]], [ /(macintosh);/i ], [MODEL, [VENDOR, APPLE]], [ // Sharp /\b(sh-?[altvz]?\d\d[a-ekm]?)/i ], [MODEL, [VENDOR, SHARP], [TYPE, MOBILE]], [ // Huawei /\b((?:ag[rs][23]?|bah2?|sht?|btv)-a?[lw]\d{2})\b(?!.+d\/s)/i ], [MODEL, [VENDOR, HUAWEI], [TYPE, TABLET]], [ /(?:huawei|honor)([-\w ]+)[;\)]/i, /\b(nexus 6p|\w{2,4}e?-[atu]?[ln][\dx][012359c][adn]?)\b(?!.+d\/s)/i ], [MODEL, [VENDOR, HUAWEI], [TYPE, MOBILE]], [ // Xiaomi /\b(poco[\w ]+|m2\d{3}j\d\d[a-z]{2})(?: bui|\))/i, // Xiaomi POCO /\b; (\w+) build\/hm\1/i, // Xiaomi Hongmi 'numeric' models /\b(hm[-_ ]?note?[_ ]?(?:\d\w)?) bui/i, // Xiaomi Hongmi /\b(redmi[\-_ ]?(?:note|k)?[\w_ ]+)(?: bui|\))/i, // Xiaomi Redmi /oid[^\)]+; (m?[12][0-389][01]\w{3,6}[c-y])( bui|; wv|\))/i, // Xiaomi Redmi 'numeric' models /\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note lte|max|cc)?[_ ]?(?:\d?\w?)[_ ]?(?:plus|se|lite)?)(?: bui|\))/i // Xiaomi Mi ], [[MODEL, /_/g, " "], [VENDOR, XIAOMI], [TYPE, MOBILE]], [ /oid[^\)]+; (2\d{4}(283|rpbf)[cgl])( bui|\))/i, // Redmi Pad /\b(mi[-_ ]?(?:pad)(?:[\w_ ]+))(?: bui|\))/i // Mi Pad tablets ], [[MODEL, /_/g, " "], [VENDOR, XIAOMI], [TYPE, TABLET]], [ // OPPO /; (\w+) bui.+ oppo/i, /\b(cph[12]\d{3}|p(?:af|c[al]|d\w|e[ar])[mt]\d0|x9007|a101op)\b/i ], [MODEL, [VENDOR, "OPPO"], [TYPE, MOBILE]], [ /\b(opd2\d{3}a?) bui/i ], [MODEL, [VENDOR, "OPPO"], [TYPE, TABLET]], [ // Vivo /vivo (\w+)(?: bui|\))/i, /\b(v[12]\d{3}\w?[at])(?: bui|;)/i ], [MODEL, [VENDOR, "Vivo"], [TYPE, MOBILE]], [ // Realme /\b(rmx[1-3]\d{3})(?: bui|;|\))/i ], [MODEL, [VENDOR, "Realme"], [TYPE, MOBILE]], [ // Motorola /\b(milestone|droid(?:[2-4x]| (?:bionic|x2|pro|razr))?:?( 4g)?)\b[\w ]+build\//i, /\bmot(?:orola)?[- ](\w*)/i, /((?:moto[\w\(\) ]+|xt\d{3,4}|nexus 6)(?= bui|\)))/i ], [MODEL, [VENDOR, MOTOROLA], [TYPE, MOBILE]], [ /\b(mz60\d|xoom[2 ]{0,2}) build\//i ], [MODEL, [VENDOR, MOTOROLA], [TYPE, TABLET]], [ // LG /((?=lg)?[vl]k\-?\d{3}) bui| 3\.[-\w; ]{10}lg?-([06cv9]{3,4})/i ], [MODEL, [VENDOR, LG], [TYPE, TABLET]], [ /(lm(?:-?f100[nv]?|-[\w\.]+)(?= bui|\))|nexus [45])/i, /\blg[-e;\/ ]+((?!browser|netcast|android tv)\w+)/i, /\blg-?([\d\w]+) bui/i ], [MODEL, [VENDOR, LG], [TYPE, MOBILE]], [ // Lenovo /(ideatab[-\w ]+)/i, /lenovo ?(s[56]000[-\w]+|tab(?:[\w ]+)|yt[-\d\w]{6}|tb[-\d\w]{6})/i ], [MODEL, [VENDOR, LENOVO], [TYPE, TABLET]], [ // Nokia /(?:maemo|nokia).*(n900|lumia \d+)/i, /nokia[-_ ]?([-\w\.]*)/i ], [[MODEL, /_/g, " "], [VENDOR, "Nokia"], [TYPE, MOBILE]], [ // Google /(pixel c)\b/i // Google Pixel C ], [MODEL, [VENDOR, GOOGLE], [TYPE, TABLET]], [ /droid.+; (pixel[\daxl ]{0,6})(?: bui|\))/i // Google Pixel ], [MODEL, [VENDOR, GOOGLE], [TYPE, MOBILE]], [ // Sony /droid.+ (a?\d[0-2]{2}so|[c-g]\d{4}|so[-gl]\w+|xq-a\w[4-7][12])(?= bui|\).+chrome\/(?![1-6]{0,1}\d\.))/i ], [MODEL, [VENDOR, SONY], [TYPE, MOBILE]], [ /sony tablet [ps]/i, /\b(?:sony)?sgp\w+(?: bui|\))/i ], [[MODEL, "Xperia Tablet"], [VENDOR, SONY], [TYPE, TABLET]], [ // OnePlus / (kb2005|in20[12]5|be20[12][59])\b/i, /(?:one)?(?:plus)? (a\d0\d\d)(?: b|\))/i ], [MODEL, [VENDOR, "OnePlus"], [TYPE, MOBILE]], [ // Amazon /(alexa)webm/i, /(kf[a-z]{2}wi|aeo[c-r]{2})( bui|\))/i, // Kindle Fire without Silk / Echo Show /(kf[a-z]+)( bui|\)).+silk\//i // Kindle Fire HD ], [MODEL, [VENDOR, AMAZON], [TYPE, TABLET]], [ /((?:sd|kf)[0349hijorstuw]+)( bui|\)).+silk\//i // Fire Phone ], [[MODEL, /(.+)/g, "Fire Phone $1"], [VENDOR, AMAZON], [TYPE, MOBILE]], [ // BlackBerry /(playbook);[-\w\),; ]+(rim)/i // BlackBerry PlayBook ], [MODEL, VENDOR, [TYPE, TABLET]], [ /\b((?:bb[a-f]|st[hv])100-\d)/i, /\(bb10; (\w+)/i // BlackBerry 10 ], [MODEL, [VENDOR, BLACKBERRY], [TYPE, MOBILE]], [ // Asus /(?:\b|asus_)(transfo[prime ]{4,10} \w+|eeepc|slider \w+|nexus 7|padfone|p00[cj])/i ], [MODEL, [VENDOR, ASUS], [TYPE, TABLET]], [ / (z[bes]6[027][012][km][ls]|zenfone \d\w?)\b/i ], [MODEL, [VENDOR, ASUS], [TYPE, MOBILE]], [ // HTC /(nexus 9)/i // HTC Nexus 9 ], [MODEL, [VENDOR, "HTC"], [TYPE, TABLET]], [ /(htc)[-;_ ]{1,2}([\w ]+(?=\)| bui)|\w+)/i, // HTC // ZTE /(zte)[- ]([\w ]+?)(?: bui|\/|\))/i, /(alcatel|geeksphone|nexian|panasonic(?!(?:;|\.))|sony(?!-bra))[-_ ]?([-\w]*)/i // Alcatel/GeeksPhone/Nexian/Panasonic/Sony ], [VENDOR, [MODEL, /_/g, " "], [TYPE, MOBILE]], [ // Acer /droid.+; ([ab][1-7]-?[0178a]\d\d?)/i ], [MODEL, [VENDOR, "Acer"], [TYPE, TABLET]], [ // Meizu /droid.+; (m[1-5] note) bui/i, /\bmz-([-\w]{2,})/i ], [MODEL, [VENDOR, "Meizu"], [TYPE, MOBILE]], [ // Ulefone /; ((?:power )?armor(?:[\w ]{0,8}))(?: bui|\))/i ], [MODEL, [VENDOR, "Ulefone"], [TYPE, MOBILE]], [ // MIXED /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron|infinix|tecno)[-_ ]?([-\w]*)/i, // BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron /(hp) ([\w ]+\w)/i, // HP iPAQ /(asus)-?(\w+)/i, // Asus /(microsoft); (lumia[\w ]+)/i, // Microsoft Lumia /(lenovo)[-_ ]?([-\w]+)/i, // Lenovo /(jolla)/i, // Jolla /(oppo) ?([\w ]+) bui/i // OPPO ], [VENDOR, MODEL, [TYPE, MOBILE]], [ /(kobo)\s(ereader|touch)/i, // Kobo /(archos) (gamepad2?)/i, // Archos /(hp).+(touchpad(?!.+tablet)|tablet)/i, // HP TouchPad /(kindle)\/([\w\.]+)/i // Kindle ], [VENDOR, MODEL, [TYPE, TABLET]], [ /(surface duo)/i // Surface Duo ], [MODEL, [VENDOR, MICROSOFT], [TYPE, TABLET]], [ /droid [\d\.]+; (fp\du?)(?: b|\))/i // Fairphone ], [MODEL, [VENDOR, "Fairphone"], [TYPE, MOBILE]], [ /(shield[\w ]+) b/i // Nvidia Shield Tablets ], [MODEL, [VENDOR, "Nvidia"], [TYPE, TABLET]], [ /(sprint) (\w+)/i // Sprint Phones ], [VENDOR, MODEL, [TYPE, MOBILE]], [ /(kin\.[onetw]{3})/i // Microsoft Kin ], [[MODEL, /\./g, " "], [VENDOR, MICROSOFT], [TYPE, MOBILE]], [ /droid.+; ([c6]+|et5[16]|mc[239][23]x?|vc8[03]x?)\)/i // Zebra ], [MODEL, [VENDOR, ZEBRA], [TYPE, TABLET]], [ /droid.+; (ec30|ps20|tc[2-8]\d[kx])\)/i ], [MODEL, [VENDOR, ZEBRA], [TYPE, MOBILE]], [ /////////////////// // SMARTTVS /////////////////// /smart-tv.+(samsung)/i // Samsung ], [VENDOR, [TYPE, SMARTTV]], [ /hbbtv.+maple;(\d+)/i ], [[MODEL, /^/, "SmartTV"], [VENDOR, SAMSUNG], [TYPE, SMARTTV]], [ /(nux; netcast.+smarttv|lg (netcast\.tv-201\d|android tv))/i // LG SmartTV ], [[VENDOR, LG], [TYPE, SMARTTV]], [ /(apple) ?tv/i // Apple TV ], [VENDOR, [MODEL, APPLE + " TV"], [TYPE, SMARTTV]], [ /crkey/i // Google Chromecast ], [[MODEL, CHROME + "cast"], [VENDOR, GOOGLE], [TYPE, SMARTTV]], [ /droid.+aft(\w+)( bui|\))/i // Fire TV ], [MODEL, [VENDOR, AMAZON], [TYPE, SMARTTV]], [ /\(dtv[\);].+(aquos)/i, /(aquos-tv[\w ]+)\)/i // Sharp ], [MODEL, [VENDOR, SHARP], [TYPE, SMARTTV]], [ /(bravia[\w ]+)( bui|\))/i // Sony ], [MODEL, [VENDOR, SONY], [TYPE, SMARTTV]], [ /(mitv-\w{5}) bui/i // Xiaomi ], [MODEL, [VENDOR, XIAOMI], [TYPE, SMARTTV]], [ /Hbbtv.*(technisat) (.*);/i // TechniSAT ], [VENDOR, MODEL, [TYPE, SMARTTV]], [ /\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i, // Roku /hbbtv\/\d+\.\d+\.\d+ +\([\w\+ ]*; *([\w\d][^;]*);([^;]*)/i // HbbTV devices ], [[VENDOR, trim], [MODEL, trim], [TYPE, SMARTTV]], [ /\b(android tv|smart[- ]?tv|opera tv|tv; rv:)\b/i // SmartTV from Unidentified Vendors ], [[TYPE, SMARTTV]], [ /////////////////// // CONSOLES /////////////////// /(ouya)/i, // Ouya /(nintendo) (\w+)/i // Nintendo ], [VENDOR, MODEL, [TYPE, CONSOLE]], [ /droid.+; (shield) bui/i // Nvidia ], [MODEL, [VENDOR, "Nvidia"], [TYPE, CONSOLE]], [ /(playstation \w+)/i // Playstation ], [MODEL, [VENDOR, SONY], [TYPE, CONSOLE]], [ /\b(xbox(?: one)?(?!; xbox))[\); ]/i // Microsoft Xbox ], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [ /////////////////// // WEARABLES /////////////////// /((pebble))app/i // Pebble ], [VENDOR, MODEL, [TYPE, WEARABLE]], [ /(watch)(?: ?os[,\/]|\d,\d\/)[\d\.]+/i // Apple Watch ], [MODEL, [VENDOR, APPLE], [TYPE, WEARABLE]], [ /droid.+; (wt63?0{2,3})\)/i ], [MODEL, [VENDOR, ZEBRA], [TYPE, WEARABLE]], [ /////////////////// // XR /////////////////// /droid.+; (glass) \d/i // Google Glass ], [MODEL, [VENDOR, GOOGLE], [TYPE, XR]], [ /(quest( \d| pro)?)/i // Oculus Quest ], [MODEL, [VENDOR, FACEBOOK], [TYPE, XR]], [ /////////////////// // EMBEDDED /////////////////// /(tesla)(?: qtcarbrowser|\/[-\w\.]+)/i // Tesla ], [VENDOR, [TYPE, EMBEDDED]], [ /(aeobc)\b/i // Echo Dot ], [MODEL, [VENDOR, AMAZON], [TYPE, EMBEDDED]], [ //////////////////// // MIXED (GENERIC) /////////////////// /droid .+?; ([^;]+?)(?: bui|; wv\)|\) applew).+? mobile safari/i // Android Phones from Unidentified Vendors ], [MODEL, [TYPE, MOBILE]], [ /droid .+?; ([^;]+?)(?: bui|\) applew).+?(?! mobile) safari/i // Android Tablets from Unidentified Vendors ], [MODEL, [TYPE, TABLET]], [ /\b((tablet|tab)[;\/]|focus\/\d(?!.+mobile))/i // Unidentifiable Tablet ], [[TYPE, TABLET]], [ /(phone|mobile(?:[;\/]| [ \w\/\.]*safari)|pda(?=.+windows ce))/i // Unidentifiable Mobile ], [[TYPE, MOBILE]], [ /(android[-\w\. ]{0,9});.+buil/i // Generic Android Device ], [MODEL, [VENDOR, "Generic"]] ], engine: [ [ /windows.+ edge\/([\w\.]+)/i // EdgeHTML ], [VERSION, [NAME, EDGE + "HTML"]], [ /webkit\/537\.36.+chrome\/(?!27)([\w\.]+)/i // Blink ], [VERSION, [NAME, "Blink"]], [ /(presto)\/([\w\.]+)/i, // Presto /(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m/Goanna /ekioh(flow)\/([\w\.]+)/i, // Flow /(khtml|tasman|links)[\/ ]\(?([\w\.]+)/i, // KHTML/Tasman/Links /(icab)[\/ ]([23]\.[\d\.]+)/i, // iCab /\b(libweb)/i ], [NAME, VERSION], [ /rv\:([\w\.]{1,9})\b.+(gecko)/i // Gecko ], [VERSION, NAME] ], os: [ [ // Windows /microsoft (windows) (vista|xp)/i // Windows (iTunes) ], [NAME, VERSION], [ /(windows (?:phone(?: os)?|mobile))[\/ ]?([\d\.\w ]*)/i // Windows Phone ], [NAME, [VERSION, strMapper, windowsVersionMap]], [ /windows nt 6\.2; (arm)/i, // Windows RT /windows[\/ ]?([ntce\d\. ]+\w)(?!.+xbox)/i, /(?:win(?=3|9|n)|win 9x )([nt\d\.]+)/i ], [[VERSION, strMapper, windowsVersionMap], [NAME, WINDOWS]], [ // iOS/macOS /ip[honead]{2,4}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS /(?:ios;fbsv\/|iphone.+ios[\/ ])([\d\.]+)/i, /cfnetwork\/.+darwin/i ], [[VERSION, /_/g, "."], [NAME, "iOS"]], [ /(mac os x) ?([\w\. ]*)/i, /(macintosh|mac_powerpc\b)(?!.+haiku)/i // Mac OS ], [[NAME, "macOS"], [VERSION, /_/g, "."]], [ // Mobile OSes /droid ([\w\.]+)\b.+(android[- ]x86|harmonyos)/i // Android-x86/HarmonyOS ], [VERSION, NAME], [ // Android/WebOS/QNX/Bada/RIM/Maemo/MeeGo/Sailfish OS /(android|webos|qnx|bada|rim tablet os|maemo|meego|sailfish)[-\/ ]?([\w\.]*)/i, /(blackberry)\w*\/([\w\.]*)/i, // Blackberry /(tizen|kaios)[\/ ]([\w\.]+)/i, // Tizen/KaiOS /\((series40);/i // Series 40 ], [NAME, VERSION], [ /\(bb(10);/i // BlackBerry 10 ], [VERSION, [NAME, BLACKBERRY]], [ /(?:symbian ?os|symbos|s60(?=;)|series60)[-\/ ]?([\w\.]*)/i // Symbian ], [VERSION, [NAME, "Symbian"]], [ /mozilla\/[\d\.]+ \((?:mobile|tablet|tv|mobile; [\w ]+); rv:.+ gecko\/([\w\.]+)/i // Firefox OS ], [VERSION, [NAME, FIREFOX + " OS"]], [ /web0s;.+rt(tv)/i, /\b(?:hp)?wos(?:browser)?\/([\w\.]+)/i // WebOS ], [VERSION, [NAME, "webOS"]], [ /watch(?: ?os[,\/]|\d,\d\/)([\d\.]+)/i // watchOS ], [VERSION, [NAME, "watchOS"]], [ // Google Chromecast /crkey\/([\d\.]+)/i // Google Chromecast ], [VERSION, [NAME, CHROME + "cast"]], [ /(cros) [\w]+(?:\)| ([\w\.]+)\b)/i // Chromium OS ], [[NAME, "Chrome OS"], VERSION], [ // Smart TVs /panasonic;(viera)/i, // Panasonic Viera /(netrange)mmh/i, // Netrange /(nettv)\/(\d+\.[\w\.]+)/i, // NetTV // Console /(nintendo|playstation) (\w+)/i, // Nintendo/Playstation /(xbox); +xbox ([^\);]+)/i, // Microsoft Xbox (360, One, X, S, Series X, Series S) // Other /\b(joli|palm)\b ?(?:os)?\/?([\w\.]*)/i, // Joli/Palm /(mint)[\/\(\) ]?(\w*)/i, // Mint /(mageia|vectorlinux)[; ]/i, // Mageia/VectorLinux /([kxln]?ubuntu|debian|suse|opensuse|gentoo|arch(?= linux)|slackware|fedora|mandriva|centos|pclinuxos|red ?hat|zenwalk|linpus|raspbian|plan 9|minix|risc os|contiki|deepin|manjaro|elementary os|sabayon|linspire)(?: gnu\/linux)?(?: enterprise)?(?:[- ]linux)?(?:-gnu)?[-\/ ]?(?!chrom|package)([-\w\.]*)/i, // Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware/Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus/Raspbian/Plan9/Minix/RISCOS/Contiki/Deepin/Manjaro/elementary/Sabayon/Linspire /(hurd|linux) ?([\w\.]*)/i, // Hurd/Linux /(gnu) ?([\w\.]*)/i, // GNU /\b([-frentopcghs]{0,5}bsd|dragonfly)[\/ ]?(?!amd|[ix346]{1,2}86)([\w\.]*)/i, // FreeBSD/NetBSD/OpenBSD/PC-BSD/GhostBSD/DragonFly /(haiku) (\w+)/i // Haiku ], [NAME, VERSION], [ /(sunos) ?([\w\.\d]*)/i // Solaris ], [[NAME, "Solaris"], VERSION], [ /((?:open)?solaris)[-\/ ]?([\w\.]*)/i, // Solaris /(aix) ((\d)(?=\.|\)| )[\w\.])*/i, // AIX /\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux|serenityos)/i, // BeOS/OS2/AmigaOS/MorphOS/OpenVMS/Fuchsia/HP-UX/SerenityOS /(unix) ?([\w\.]*)/i // UNIX ], [NAME, VERSION] ] }; var defaultProps = function() { var props = { init: {}, isIgnore: {}, isIgnoreRgx: {}, toString: {} }; setProps.call(props.init, [ [UA_BROWSER, [NAME, VERSION, MAJOR, TYPE]], [UA_CPU, [ARCHITECTURE]], [UA_DEVICE, [TYPE, MODEL, VENDOR]], [UA_ENGINE, [NAME, VERSION]], [UA_OS, [NAME, VERSION]] ]); setProps.call(props.isIgnore, [ [UA_BROWSER, [VERSION, MAJOR]], [UA_ENGINE, [VERSION]], [UA_OS, [VERSION]] ]); setProps.call(props.isIgnoreRgx, [ [UA_BROWSER, / ?browser$/i], [UA_OS, / ?os$/i] ]); setProps.call(props.toString, [ [UA_BROWSER, [NAME, VERSION]], [UA_CPU, [ARCHITECTURE]], [UA_DEVICE, [VENDOR, MODEL]], [UA_ENGINE, [NAME, VERSION]], [UA_OS, [NAME, VERSION]] ]); return props; }(); var createIData = function(item, itemType) { var init_props = defaultProps.init[itemType], is_ignoreProps = defaultProps.isIgnore[itemType] || 0, is_ignoreRgx = defaultProps.isIgnoreRgx[itemType] || 0, toString_props = defaultProps.toString[itemType] || 0; function IData() { setProps.call(this, init_props); } IData.prototype.getItem = function() { return item; }; IData.prototype.withClientHints = function() { if (!NAVIGATOR_UADATA) { return item.parseCH().get(); } return NAVIGATOR_UADATA.getHighEntropyValues(CH_ALL_VALUES).then(function(res) { return item.setCH(new UACHData(res, false)).parseCH().get(); }); }; IData.prototype.withFeatureCheck = function() { return item.detectFeature().get(); }; if (itemType != UA_RESULT) { IData.prototype.is = function(strToCheck) { var is = false; for (var i in this) { if (this.hasOwnProperty(i) && !has(is_ignoreProps, i) && lowerize(is_ignoreRgx ? strip(is_ignoreRgx, this[i]) : this[i]) == lowerize(is_ignoreRgx ? strip(is_ignoreRgx, strToCheck) : strToCheck)) { is = true; if (strToCheck != UNDEF_TYPE) break; } else if (strToCheck == UNDEF_TYPE && is) { is = !is; break; } } return is; }; IData.prototype.toString = function() { var str = EMPTY; for (var i in toString_props) { if (typeof this[toString_props[i]] !== UNDEF_TYPE) { str += (str ? " " : EMPTY) + this[toString_props[i]]; } } return str || UNDEF_TYPE; }; } if (!NAVIGATOR_UADATA) { IData.prototype.then = function(cb) { var that = this; var IDataResolve = function() { for (var prop in that) { if (that.hasOwnProperty(prop)) { this[prop] = that[prop]; } } }; IDataResolve.prototype = { is: IData.prototype.is, toString: IData.prototype.toString }; var resolveData = new IDataResolve(); cb(resolveData); return resolveData; }; } return new IData(); }; function UACHData(uach, isHttpUACH) { uach = uach || {}; setProps.call(this, CH_ALL_VALUES); if (isHttpUACH) { setProps.call(this, [ [BRANDS, itemListToArray(uach[CH_HEADER])], [FULLVERLIST, itemListToArray(uach[CH_HEADER_FULL_VER_LIST])], [MOBILE, /\?1/.test(uach[CH_HEADER_MOBILE])], [MODEL, stripQuotes(uach[CH_HEADER_MODEL])], [PLATFORM, stripQuotes(uach[CH_HEADER_PLATFORM])], [PLATFORMVER, stripQuotes(uach[CH_HEADER_PLATFORM_VER])], [ARCHITECTURE, stripQuotes(uach[CH_HEADER_ARCH])], [FORMFACTORS, itemListToArray(uach[CH_HEADER_FORM_FACTORS])], [BITNESS, stripQuotes(uach[CH_HEADER_BITNESS])] ]); } else { for (var prop in uach) { if (this.hasOwnProperty(prop) && typeof uach[prop] !== UNDEF_TYPE) this[prop] = uach[prop]; } } } function UAItem(itemType, ua, rgxMap, uaCH) { this.get = function(prop) { if (!prop) return this.data; return this.data.hasOwnProperty(prop) ? this.data[prop] : void 0; }; this.set = function(prop, val) { this.data[prop] = val; return this; }; this.setCH = function(ch) { this.uaCH = ch; return this; }; this.detectFeature = function() { if (NAVIGATOR && NAVIGATOR.userAgent == this.ua) { switch (this.itemType) { case UA_BROWSER: if (NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == FUNC_TYPE) { this.set(NAME, "Brave"); } break; case UA_DEVICE: if (!this.get(TYPE) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[MOBILE]) { this.set(TYPE, MOBILE); } if (this.get(MODEL) == "Macintosh" && NAVIGATOR && typeof NAVIGATOR.standalone !== UNDEF_TYPE && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 2) { this.set(MODEL, "iPad").set(TYPE, TABLET); } break; case UA_OS: if (!this.get(NAME) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[PLATFORM]) { this.set(NAME, NAVIGATOR_UADATA[PLATFORM]); } break; case UA_RESULT: var data = this.data; var detect = function(itemType2) { return data[itemType2].getItem().detectFeature().get(); }; this.set(UA_BROWSER, detect(UA_BROWSER)).set(UA_CPU, detect(UA_CPU)).set(UA_DEVICE, detect(UA_DEVICE)).set(UA_ENGINE, detect(UA_ENGINE)).set(UA_OS, detect(UA_OS)); } } return this; }; this.parseUA = function() { if (this.itemType != UA_RESULT) { rgxMapper.call(this.data, this.ua, this.rgxMap); } if (this.itemType == UA_BROWSER) { this.set(MAJOR, majorize(this.get(VERSION))); } return this; }; this.parseCH = function() { var uaCH2 = this.uaCH, rgxMap2 = this.rgxMap; switch (this.itemType) { case UA_BROWSER: var brands = uaCH2[FULLVERLIST] || uaCH2[BRANDS], prevName; if (brands) { for (var i in brands) { var brandName = strip(/(Google|Microsoft) /, brands[i].brand || brands[i]), brandVersion = brands[i].version; if (!/not.a.brand/i.test(brandName) && (!prevName || /chrom/i.test(prevName) && !/chromi/i.test(brandName))) { this.set(NAME, brandName).set(VERSION, brandVersion).set(MAJOR, majorize(brandVersion)); prevName = brandName; } } } break; case UA_CPU: var archName = uaCH2[ARCHITECTURE]; if (archName) { if (archName && uaCH2[BITNESS] == "64") archName += "64"; rgxMapper.call(this.data, archName + ";", rgxMap2); } break; case UA_DEVICE: if (uaCH2[MOBILE]) { this.set(TYPE, MOBILE); } if (uaCH2[MODEL]) { this.set(MODEL, uaCH2[MODEL]); } if (uaCH2[MODEL] == "Xbox") { this.set(TYPE, CONSOLE).set(VENDOR, MICROSOFT); } if (uaCH2[FORMFACTORS]) { var ff; if (typeof uaCH2[FORMFACTORS] !== "string") { var idx = 0; while (!ff && idx < uaCH2[FORMFACTORS].length) { ff = strMapper(uaCH2[FORMFACTORS][idx++], formFactorsMap); } } else { ff = strMapper(uaCH2[FORMFACTORS], formFactorsMap); } this.set(TYPE, ff); } break; case UA_OS: var osName = uaCH2[PLATFORM]; if (osName) { var osVersion = uaCH2[PLATFORMVER]; if (osName == WINDOWS) osVersion = parseInt(majorize(osVersion), 10) >= 13 ? "11" : "10"; this.set(NAME, osName).set(VERSION, osVersion); } if (this.get(NAME) == WINDOWS && uaCH2[MODEL] == "Xbox") { this.set(NAME, "Xbox").set(VERSION, void 0); } break; case UA_RESULT: var data = this.data; var parse2 = function(itemType2) { return data[itemType2].getItem().setCH(uaCH2).parseCH().get(); }; this.set(UA_BROWSER, parse2(UA_BROWSER)).set(UA_CPU, parse2(UA_CPU)).set(UA_DEVICE, parse2(UA_DEVICE)).set(UA_ENGINE, parse2(UA_ENGINE)).set(UA_OS, parse2(UA_OS)); } return this; }; setProps.call(this, [ ["itemType", itemType], ["ua", ua], ["uaCH", uaCH], ["rgxMap", rgxMap], ["data", createIData(this, itemType)] ]); return this; } function UAParser(ua, extensions, headers) { if (typeof ua === OBJ_TYPE) { if (isExtensions(ua, true)) { if (typeof extensions === OBJ_TYPE) { headers = extensions; } extensions = ua; } else { headers = ua; extensions = void 0; } ua = void 0; } else if (typeof ua === STR_TYPE && !isExtensions(extensions, true)) { headers = extensions; extensions = void 0; } if (!(this instanceof UAParser)) { return new UAParser(ua, extensions, headers).getResult(); } var userAgent2 = typeof ua === STR_TYPE ? ua : ( // Passed user-agent string NAVIGATOR && NAVIGATOR.userAgent ? NAVIGATOR.userAgent : ( // navigator.userAgent headers && headers[USER_AGENT] ? headers[USER_AGENT] : ( // User-Agent from passed headers EMPTY ) ) ), httpUACH = new UACHData(headers, true), regexMap = extensions ? extend(defaultRegexes, extensions) : defaultRegexes, createItemFunc = function(itemType) { if (itemType == UA_RESULT) { return function() { return new UAItem(itemType, userAgent2, regexMap, httpUACH).set("ua", userAgent2).set(UA_BROWSER, this.getBrowser()).set(UA_CPU, this.getCPU()).set(UA_DEVICE, this.getDevice()).set(UA_ENGINE, this.getEngine()).set(UA_OS, this.getOS()).get(); }; } else { return function() { return new UAItem(itemType, userAgent2, regexMap[itemType], httpUACH).parseUA().get(); }; } }; setProps.call(this, [ ["getBrowser", createItemFunc(UA_BROWSER)], ["getCPU", createItemFunc(UA_CPU)], ["getDevice", createItemFunc(UA_DEVICE)], ["getEngine", createItemFunc(UA_ENGINE)], ["getOS", createItemFunc(UA_OS)], ["getResult", createItemFunc(UA_RESULT)], ["getUA", function() { return userAgent2; }], ["setUA", function(ua2) { if (isString(ua2)) userAgent2 = ua2.length > UA_MAX_LENGTH ? trim(ua2, UA_MAX_LENGTH) : ua2; return this; }] ]).setUA(userAgent2); return this; } UAParser.VERSION = LIBVERSION; UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR, TYPE]); UAParser.CPU = enumerize([ARCHITECTURE]); UAParser.DEVICE = enumerize([MODEL, VENDOR, TYPE, CONSOLE, MOBILE, SMARTTV, TABLET, WEARABLE, EMBEDDED]); UAParser.ENGINE = UAParser.OS = enumerize([NAME, VERSION]); function redirect() { const currentUrl = window.location.href; if (/\/song\//.test(currentUrl)) { const sheetId = currentUrl.match(new RegExp("(?<=\\/)\\d+(?=\\.)"))[0]; const newUrl = `https://www.91pu.com.tw/m/tone.shtml?id=${sheetId}`; window.location.replace(newUrl); } } function injectGtag() { const newScript = document.createElement("script"); newScript.src = "https://www.googletagmanager.com/gtag/js?id=G-JF4S3HZY31"; newScript.async = true; document.head.appendChild(newScript); newScript.onload = () => { window.dataLayer = window.dataLayer || []; function gtag() { window.dataLayer.push(arguments); } gtag("js", /* @__PURE__ */ new Date()); gtag("config", "G-JF4S3HZY31"); }; } function getQueryParams() { const url = new URL(window.location.href); const params = { transpose: +url.searchParams.get("transpose"), darkMode: !!url.searchParams.get("darkmode") }; return params; } function changeTitle() { const newTitle = $("#mtitle").text().trim(); document.title = `${newTitle} | 91+`; } function archiveChordSheet() { const sheet = document.getElementById("tone_z"); const chordSheetDocument = new ChordSheetDocument(); try { const chordSheetElement = new ChordSheetElement(sheet); chordSheetElement.formatUnderlines(); const formBody = { id: chordSheetDocument.getId(), title: chordSheetDocument.getTitle(), key: chordSheetDocument.getKey(), play: chordSheetDocument.getPlay(), capo: chordSheetDocument.getCapo(), singer: chordSheetDocument.getSinger(), composer: chordSheetDocument.getComposer(), lyricist: chordSheetDocument.getLyricist(), bpm: chordSheetDocument.getBpm(), sheet_text: chordSheetDocument.getSheetText() }; chordSheetElement.unformatUnderlines(); fetch("https://91-plus-plus-api.fly.dev/archive", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(formBody) }).then((response) => { console.log("[91 Plus] 雲端樂譜備份成功:", response); }).catch((error) => { console.error("[91 Plus] 雲端樂譜備份失敗:", error); }); } catch { console.warn("[91 Plus] 樂譜解析失敗,無法備份"); fetch( `https://91-plus-plus-api.fly.dev/report?id=${chordSheetDocument.getId()}` ); } } function initMutationObserver() { return new MutationObserver((records, observer) => { const isMutationDone = !!document.querySelector("#tone_z").childElementCount; if (!isMutationDone) { return; } $("body").trigger("mutation.done"); observer.disconnect(); }).observe(document.body, { childList: true, subtree: true }); } function onDomReady(callback) { $("body").on("mutation.done", callback); } function handleEvents() { $("html").on("keydown", (event) => { const excludedTags = ["input"]; const tagName = event.target.tagName.toLowerCase(); if (excludedTags.includes(tagName)) { return; } StoreHandler.handleKeydown(event.key); }); } function switchInstrument(instrument) { switch (instrument) { case "guitar": { $(".schord").trigger("click"); break; } case "ukulele": { $(".ukschord").trigger("click"); break; } default: { $(".nsChord").trigger("click"); break; } } } function getChordShapes() { const chordShapes = _unsafeWindow.chord_shapes; return chordShapes; } function getChordList() { const chordList = []; $("#tone_z .tf").each(function() { chordList.push($(this).text()); }); return [...new Set(chordList)]; } function convertChordName(chordName) { const root = chordName.match(/^[A-G]#?/)[0]; const rest = chordName.replace(/^[A-G]#?/, ""); return `${rest} ${root}`; } const userAgent = UAParser(navigator.userAgent); const _hoisted_1$b = { id: "plus91-sheet-popup" }; const _hoisted_2$a = { class: "sheet-popup-container" }; const _hoisted_3$4 = { class: "text-capo" }; const _hoisted_4$2 = ["innerHTML"]; const _hoisted_5$1 = { class: "transpose-range-container" }; const _hoisted_6$1 = ["value"]; const _hoisted_7 = { class: "instrument-select-container" }; const _sfc_main$c = { __name: "SheetPopup", setup(__props) { const store = useStore(); return (_ctx, _cache) => { return vue.openBlock(), vue.createBlock(vue.Transition, { name: "slide-and-fade" }, { default: vue.withCtx(() => [ vue.withDirectives(vue.createElementVNode("div", _hoisted_1$b, [ vue.createElementVNode("div", _hoisted_2$a, [ vue.createVNode(AdjustWidget, { "onclick-left": () => { vue.unref(store).plusTranspose(-1); }, "onclick-middle": () => { vue.unref(store).transpose = 0; }, "onclick-right": () => { vue.unref(store).plusTranspose(1); } }, { default: vue.withCtx(() => [ vue.createTextVNode(" CAPO:"), vue.createElementVNode("span", _hoisted_3$4, vue.toDisplayString(vue.unref(store).currentCapo), 1), vue.createTextVNode(" ("), vue.createElementVNode("span", { class: "text-key", innerHTML: vue.unref(store).currentKey }, null, 8, _hoisted_4$2), vue.createTextVNode(") ") ]), _: 1 }, 8, ["onclick-left", "onclick-middle", "onclick-right"]), vue.createElementVNode("div", _hoisted_5$1, [ vue.createElementVNode("input", { type: "range", min: "-11", max: "11", value: vue.unref(store).currentCapo, onInput: _cache[0] || (_cache[0] = ($event) => { vue.unref(store).transpose = $event.target.value - vue.unref(store).originalCapo; }) }, null, 40, _hoisted_6$1) ]), vue.createElementVNode("div", _hoisted_7, [ vue.createElementVNode("button", { class: "instrument-select-button", onClick: _cache[1] || (_cache[1] = () => { vue.unref(switchInstrument)(""); }) }, " 無 "), vue.createElementVNode("button", { class: "instrument-select-button", onClick: _cache[2] || (_cache[2] = () => { vue.unref(switchInstrument)("guitar"); }) }, " 吉他 "), vue.createElementVNode("button", { class: "instrument-select-button", onClick: _cache[3] || (_cache[3] = () => { vue.unref(switchInstrument)("ukulele"); }) }, " 烏克莉莉 ") ]) ]) ], 512), [ [vue.vShow, vue.unref(store).isPopupShow.sheet] ]) ]), _: 1 }); }; } }; const SheetPopup = /* @__PURE__ */ _export_sfc(_sfc_main$c, [["__scopeId", "data-v-f161c46c"]]); const _hoisted_1$a = { key: 0, class: "chord-container" }; const _hoisted_2$9 = { class: "chord-name" }; const _hoisted_3$3 = ["chord-name"]; const _sfc_main$b = { __name: "ChordChart", props: { chord: String }, setup(__props) { const props = __props; const chordRef = vue.ref(void 0); const chordShapes = getChordShapes(); const isChordExist = vue.ref(true); vue.onMounted(() => { var _a; const formattedChordKey = convertChordName(props.chord); const chordShape = chordShapes[formattedChordKey]; if (!chordShape) { return isChordExist.value = false; } const chordObject = { ...chordShape, // position: chordShape.position, // positionText: chordShape.position_text, barres: (_a = chordShape.bars) == null ? void 0 : _a.map((barre) => { return { ...barre, fromString: barre.from_string, toString: barre.to_string }; }), chord: chordShape.chord.map(([stringNum, fretNum]) => { const raw = [stringNum, fretNum]; if (isNaN(+fretNum)) { return raw; } let newFretNum = fretNum; newFretNum += chordShape.position || 0; newFretNum -= chordShape.position_text || 0; return [stringNum, newFretNum]; }) }; vue.nextTick(() => { const width = chordRef.value.clientWidth; const chordBoxSelector = `.chord-chart[chord-name="${props.chord}"]`; const chordBox = new vexchords.ChordBox(chordBoxSelector, { width, height: width * 1.25, circleRadius: 5, numStrings: 6, numFrets: 5, showTuning: false, defaultColor: "#444", bgColor: "transparent" }); chordBox.draw(chordObject); }); }); return (_ctx, _cache) => { return isChordExist.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$a, [ vue.createElementVNode("div", _hoisted_2$9, vue.toDisplayString(props.chord), 1), vue.createElementVNode("div", { class: "chord-chart", "chord-name": props.chord, ref_key: "chordRef", ref: chordRef }, null, 8, _hoisted_3$3) ])) : vue.createCommentVNode("", true); }; } }; const ChordChart = /* @__PURE__ */ _export_sfc(_sfc_main$b, [["__scopeId", "data-v-735734f6"]]); const _hoisted_1$9 = { class: "banner" }; const _hoisted_2$8 = { class: "chord-popup-container" }; const _sfc_main$a = { __name: "ChordPopup", setup(__props) { const store = useStore(); const canShowChord = vue.ref(true); if (userAgent.browser.name === "Mobile Safari") { canShowChord.value = false; } const bannerText = vue.ref(""); const bannerTextList = [ "此處的和弦圖示僅供參考!由於技術問題,目前尚無法準確繪製,尤其在把位較常出現錯誤,請注意。", "在 91 譜中沒有資料的和弦是畫不出來的呦!" ]; const randomIndex = vue.ref(0); const refreshBanner = () => { if (!canShowChord.value) { bannerText.value = "很抱歉,由於技術問題,你所使用的瀏覽器目前尚無法繪製出和弦圖,開發者正在試著修正這個問題,敬請期待更新。"; } else { randomIndex.value = Math.floor(Math.random() * bannerTextList.length); bannerText.value = bannerTextList[randomIndex.value]; } }; const chordList = vue.ref([]); vue.watch(store.isPopupShow, () => { if (!store.isPopupShow.chord) { return; } refreshBanner(); chordList.value = getChordList(); }); return (_ctx, _cache) => { return vue.openBlock(), vue.createBlock(vue.Transition, { name: "slide-and-fade" }, { default: vue.withCtx(() => [ vue.withDirectives(vue.createElementVNode("div", { id: "plus91-chord-popup", class: vue.normalizeClass({ "banner-only": !chordList.value.length }) }, [ vue.createElementVNode("div", _hoisted_1$9, [ vue.createVNode(BootstrapIcon, { icon: "info-circle-fill", color: "inherit", size: "inherit" }), vue.createElementVNode("section", null, vue.toDisplayString(bannerText.value), 1) ]), vue.createElementVNode("div", _hoisted_2$8, [ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(chordList.value, (chord) => { return vue.openBlock(), vue.createBlock(ChordChart, { key: `${chord}_${( new Date()).getTime()}`, chord }, null, 8, ["chord"]); }), 128)) ]) ], 2), [ [vue.vShow, vue.unref(store).isPopupShow.chord] ]) ]), _: 1 }); }; } }; const ChordPopup = /* @__PURE__ */ _export_sfc(_sfc_main$a, [["__scopeId", "data-v-2210cdf0"]]); const _hoisted_1$8 = { id: "plus91-font-popup" }; const _hoisted_2$7 = { class: "font-popup-container" }; const _sfc_main$9 = { __name: "FontSizePopup", setup(__props) { const store = useStore(); const getFontSize = vue.computed(() => { return store.originalFontSize + store.fontSizeDelta; }); return (_ctx, _cache) => { return vue.openBlock(), vue.createBlock(vue.Transition, { name: "slide-and-fade" }, { default: vue.withCtx(() => [ vue.withDirectives(vue.createElementVNode("div", _hoisted_1$8, [ vue.createElementVNode("div", _hoisted_2$7, [ vue.createVNode(AdjustWidget, { "onclick-left": () => { vue.unref(store).fontSizeDelta--; }, "onclick-middle": () => { vue.unref(store).fontSizeDelta = 0; }, "onclick-right": () => { vue.unref(store).fontSizeDelta++; }, "disabled-left": getFontSize.value <= 8, "disabled-right": getFontSize.value >= 30 }, { default: vue.withCtx(() => [ vue.createTextVNode(vue.toDisplayString(getFontSize.value) + "px ", 1) ]), _: 1 }, 8, ["onclick-left", "onclick-middle", "onclick-right", "disabled-left", "disabled-right"]) ]) ], 512), [ [vue.vShow, vue.unref(store).isPopupShow.font] ]) ]), _: 1 }); }; } }; const FontSizePopup = /* @__PURE__ */ _export_sfc(_sfc_main$9, [["__scopeId", "data-v-eff17405"]]); const _withScopeId = (n) => (vue.pushScopeId("data-v-e329f5af"), n = n(), vue.popScopeId(), n); const _hoisted_1$7 = { id: "plus91-settings-popup" }; const _hoisted_2$6 = { class: "settings-popup-container" }; const _hoisted_3$2 = { class: "setting-item" }; const _hoisted_4$1 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("span", null, "深色模式", -1)); const _hoisted_5 = { class: "setting-item" }; const _hoisted_6 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("span", null, "協助測試雲端備份樂譜功能", -1)); const _sfc_main$8 = { __name: "SettingsPopup", setup(__props) { const store = useStore(); return (_ctx, _cache) => { return vue.openBlock(), vue.createBlock(vue.Transition, { name: "slide-and-fade" }, { default: vue.withCtx(() => [ vue.withDirectives(vue.createElementVNode("div", _hoisted_1$7, [ vue.createElementVNode("div", _hoisted_2$6, [ vue.createElementVNode("label", _hoisted_3$2, [ _hoisted_4$1, vue.withDirectives(vue.createElementVNode("input", { type: "checkbox", "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => vue.unref(store).isDarkMode = $event) }, null, 512), [ [vue.vModelCheckbox, vue.unref(store).isDarkMode] ]) ]), vue.createElementVNode("label", _hoisted_5, [ _hoisted_6, vue.withDirectives(vue.createElementVNode("input", { type: "checkbox", "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => vue.unref(store).agreeToArchiveSheet = $event) }, null, 512), [ [vue.vModelCheckbox, vue.unref(store).agreeToArchiveSheet] ]) ]) ]) ], 512), [ [vue.vShow, vue.unref(store).isPopupShow.settings] ]) ]), _: 1 }); }; } }; const SettingsPopup = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["__scopeId", "data-v-e329f5af"]]); const _hoisted_1$6 = { class: "icon-button" }; const _hoisted_2$5 = { class: "button-text" }; const _sfc_main$7 = { __name: "MenuButton", props: { icon: String, name: String, color: String }, setup(__props) { vue.useCssVars((_ctx) => ({ "9047bc34": __props.color })); const props = __props; return (_ctx, _cache) => { return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$6, [ vue.createVNode(ToolbarIcon, { icon: props.icon, color: props.color }, null, 8, ["icon", "color"]), vue.createElementVNode("div", _hoisted_2$5, vue.toDisplayString(props.name), 1) ]); }; } }; const MenuButton = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__scopeId", "data-v-e9902592"]]); const _hoisted_1$5 = { id: "plus91-menu-popup" }; const _hoisted_2$4 = { class: "menu-popup-container" }; const BUTTON_COLOR = "#555"; const _sfc_main$6 = { __name: "MenuPopup", setup(__props) { const store = useStore(); const captureAsImage = () => { const content = document.querySelector("section.content"); html2canvas(content).then((canvas) => { const newWindow = window.open(); newWindow.document.write(`<img src="${canvas.toDataURL()}" />`); }); }; const searchOnYoutube = () => { const chordSheetDocument = new ChordSheetDocument(); const title = chordSheetDocument.getTitle(); const artist = chordSheetDocument.getSinger(); const url = `https://www.youtube.com/results?search_query=${title}+${artist}`; window.open(url, "_blank").focus(); }; const goToGithubPage = () => { const url = "https://github.com/DonkeyBear/91Plus/blob/main/README.md"; window.open(url, "_blank").focus(); }; return (_ctx, _cache) => { return vue.openBlock(), vue.createBlock(vue.Transition, { name: "slide-and-fade" }, { default: vue.withCtx(() => [ vue.withDirectives(vue.createElementVNode("div", _hoisted_1$5, [ vue.createElementVNode("div", _hoisted_2$4, [ vue.createVNode(MenuButton, { icon: "keyboard", name: "快捷鍵", color: BUTTON_COLOR, onClick: _cache[0] || (_cache[0] = () => { vue.unref(store).togglePopup("hotkey"); }) }), vue.createVNode(MenuButton, { icon: "file-earmark-image", name: "擷取為圖片", color: BUTTON_COLOR, onClick: captureAsImage }), vue.createVNode(MenuButton, { icon: "youtube", name: "搜尋 YouTube", color: BUTTON_COLOR, onClick: searchOnYoutube }), vue.createVNode(MenuButton, { icon: "github", name: "關於 91 Plus", color: BUTTON_COLOR, onClick: goToGithubPage }) ]) ], 512), [ [vue.vShow, vue.unref(store).isPopupShow.menu] ]) ]), _: 1 }); }; } }; const MenuPopup = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["__scopeId", "data-v-47af8eb5"]]); const _hoisted_1$4 = { class: "hotkey-item" }; const _hoisted_2$3 = { key: 0, class: "hotkeys" }; const _hoisted_3$1 = { key: 1, class: "hr" }; const _sfc_main$5 = { __name: "HotkeyItem", props: { hotkey: { type: String, required: false }, desc: String }, setup(__props) { const props = __props; const hotkeyList = props.hotkey.split(" "); return (_ctx, _cache) => { return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$4, [ vue.createElementVNode("div", { class: vue.normalizeClass(["desc", { "title": !__props.hotkey }]) }, vue.toDisplayString(__props.desc), 3), __props.hotkey ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_2$3, [ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(hotkeyList), (key) => { return vue.openBlock(), vue.createElementBlock("kbd", { key: `${key}_${__props.hotkey}_${__props.desc}` }, vue.toDisplayString(key), 1); }), 128)) ])) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_3$1)) ]); }; } }; const HotkeyItem = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-3c43f6cf"]]); const hotkeysLeft = [ { hotkey: "空白鍵", desc: "開啟 / 關閉功能選單" }, { hotkey: "ESC", desc: "關閉功能選單" }, { hotkey: "/", desc: "切換至搜尋框" } ]; const hotkeysRight = [ { hotkey: "", desc: "移調選單開啟時" }, { hotkey: "← →", desc: "移調" }, { hotkey: "↓", desc: "移回初始調" }, { hotkey: "", desc: "在搜尋框內" }, { hotkey: "Enter", desc: "搜尋" }, { hotkey: "ESC", desc: "跳出搜尋框" } ]; const hotkeyData = { hotkeysLeft, hotkeysRight }; const _hoisted_1$3 = { id: "plus91-hotkey-popup" }; const _hoisted_2$2 = { class: "hotkey-popup-container" }; const _hoisted_3 = { class: "left-part" }; const _hoisted_4 = { class: "right-part" }; const _sfc_main$4 = { __name: "HotkeyPopup", setup(__props) { const store = useStore(); return (_ctx, _cache) => { return vue.openBlock(), vue.createBlock(vue.Transition, { name: "slide-and-fade" }, { default: vue.withCtx(() => [ vue.withDirectives(vue.createElementVNode("div", _hoisted_1$3, [ vue.createElementVNode("div", _hoisted_2$2, [ vue.createElementVNode("section", _hoisted_3, [ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(hotkeyData).hotkeysLeft, (item, index) => { return vue.openBlock(), vue.createBlock(HotkeyItem, { key: `${item.hotkey}_${item.desc}_${index}`, hotkey: item.hotkey, desc: item.desc }, null, 8, ["hotkey", "desc"]); }), 128)) ]), vue.createElementVNode("section", _hoisted_4, [ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(hotkeyData).hotkeysRight, (item, index) => { return vue.openBlock(), vue.createBlock(HotkeyItem, { key: `${item.hotkey}_${item.desc}_${index}`, hotkey: item.hotkey, desc: item.desc }, null, 8, ["hotkey", "desc"]); }), 128)) ]) ]) ], 512), [ [vue.vShow, vue.unref(store).isPopupShow.hotkey] ]) ]), _: 1 }); }; } }; const HotkeyPopup = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__scopeId", "data-v-eb86b87c"]]); const _hoisted_1$2 = { id: "plus91-footer" }; const _hoisted_2$1 = { class: "footer-container" }; const _sfc_main$3 = { __name: "AppFooter", props: { active: Boolean }, setup(__props) { const store = useStore(); const props = __props; return (_ctx, _cache) => { return vue.openBlock(), vue.createBlock(vue.Transition, { name: "slide" }, { default: vue.withCtx(() => [ vue.withDirectives(vue.createElementVNode("div", _hoisted_1$2, [ vue.createElementVNode("div", _hoisted_2$1, [ vue.createVNode(ToolbarIcon, { icon: "music-note-beamed", text: "譜面", stroke: ".05rem", active: vue.unref(store).isPopupShow.sheet, onClick: _cache[0] || (_cache[0] = ($event) => vue.unref(store).togglePopup("sheet")) }, null, 8, ["active"]), vue.createVNode(ToolbarIcon, { icon: "table", text: "和弦", active: vue.unref(store).isPopupShow.chord, onClick: _cache[1] || (_cache[1] = ($event) => vue.unref(store).togglePopup("chord")) }, null, 8, ["active"]), vue.createVNode(ToolbarIcon, { icon: "type", text: "字型", stroke: ".05rem", active: vue.unref(store).isPopupShow.font, onClick: _cache[2] || (_cache[2] = ($event) => vue.unref(store).togglePopup("font")) }, null, 8, ["active"]), vue.createVNode(ToolbarIcon, { icon: "gear-wide-connected", text: "設定", active: vue.unref(store).isPopupShow.settings, onClick: _cache[3] || (_cache[3] = ($event) => vue.unref(store).togglePopup("settings")) }, null, 8, ["active"]), vue.createVNode(ToolbarIcon, { icon: "list", text: "其他", stroke: ".05rem", active: vue.unref(store).isPopupShow.menu, onClick: _cache[4] || (_cache[4] = ($event) => vue.unref(store).togglePopup("menu")) }, null, 8, ["active"]), vue.createVNode(SheetPopup), vue.createVNode(ChordPopup), vue.createVNode(FontSizePopup), vue.createVNode(SettingsPopup), vue.createVNode(MenuPopup), vue.createVNode(HotkeyPopup) ]) ], 512), [ [vue.vShow, props.active] ]) ]), _: 1 }); }; } }; const AppFooter = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-4e274b3c"]]); const _hoisted_1$1 = { id: "plus91-header" }; const _hoisted_2 = { class: "header-container" }; const _sfc_main$2 = { __name: "AppHeader", props: { active: Boolean }, setup(__props) { const props = __props; const searchText = vue.ref(""); const search = () => { if (!searchText.value) { return; } const url = `https://www.91pu.com.tw/plus/search.php?keyword=${searchText.value}`; window.open(url, "_blank").focus(); searchText.value = ""; }; const backToPreviousPage = () => { history.back(); }; return (_ctx, _cache) => { return vue.openBlock(), vue.createBlock(vue.Transition, { name: "slide" }, { default: vue.withCtx(() => [ vue.withDirectives(vue.createElementVNode("div", _hoisted_1$1, [ vue.createElementVNode("div", _hoisted_2, [ vue.createVNode(ToolbarIcon, { icon: "chevron-left", stroke: ".04rem", onClick: backToPreviousPage }), vue.withDirectives(vue.createElementVNode("input", { type: "text", placeholder: "91 Plus", "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => searchText.value = $event), onKeydown: [ vue.withKeys(search, ["enter"]), _cache[1] || (_cache[1] = vue.withKeys((event) => { event.target.blur(); }, ["esc"])) ] }, null, 544), [ [ vue.vModelText, searchText.value, void 0, { trim: true } ] ]), vue.createVNode(ToolbarIcon, { icon: "search", stroke: ".03rem", onClick: _cache[2] || (_cache[2] = ($event) => search()) }) ]) ], 512), [ [vue.vShow, props.active] ]) ]), _: 1 }); }; } }; const AppHeader = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-5ddafe3d"]]); const _hoisted_1 = { id: "dark-mode-overlay" }; const _sfc_main$1 = { __name: "DarkModeOverlay", props: { active: Boolean }, setup(__props) { const props = __props; return (_ctx, _cache) => { return vue.openBlock(), vue.createBlock(vue.Transition, { name: "fade" }, { default: vue.withCtx(() => [ vue.withDirectives(vue.createElementVNode("div", _hoisted_1, null, 512), [ [vue.vShow, props.active] ]) ]), _: 1 }); }; } }; const DarkModeOverlay = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-6cf58435"]]); const _sfc_main = { __name: "App", setup(__props) { const store = useStore(); return (_ctx, _cache) => { return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [ vue.createVNode(TriggerOverlay, { onClick: vue.unref(store).toggleToolbars }, null, 8, ["onClick"]), vue.createVNode(AppHeader, { active: vue.unref(store).isToolbarsShow }, null, 8, ["active"]), vue.createVNode(AppFooter, { active: vue.unref(store).isToolbarsShow }, null, 8, ["active"]), vue.createVNode(DarkModeOverlay, { active: vue.unref(store).isDarkMode }, null, 8, ["active"]) ], 64); }; } }; function init() { redirect(); injectGtag(); initMutationObserver(); handleEvents(); const storeHandler = new StoreHandler().start(); onDomReady(() => { changeTitle(); storeHandler.initState(); const store = useStore(); if (store.agreeToArchiveSheet) { archiveChordSheet(); } }); } const pinia = createPinia(); pinia.use(src_default); vue.createApp(_sfc_main).use(pinia).mount( (() => { const app = document.createElement("div"); app.id = "vue-91plus"; document.body.append(app); return app; })() ); init(); })(Vue, zipson, vexchords, html2canvas);
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址