From 3345a2d1815f91aa893fe151ee40e7fac0bc645b Mon Sep 17 00:00:00 2001 From: Specy Date: Tue, 16 Apr 2024 22:12:14 +0200 Subject: [PATCH] Menu refactor --- README.md | 2 +- package-lock.json | 8 +- package.json | 2 +- public/service-worker.js | 2 +- scripts/buildAndPrepareTauriRelease.js | 6 +- src-tauri/src/main.rs | 4 +- src/Config.ts | 2 +- src/{lib/updates.ts => changelog.ts} | 2 +- src/components/AppBase.tsx | 10 +- .../pages/Composer/ComposerCache.ts | 2 +- .../pages/Composer/ComposerCanvas.tsx | 2 +- .../pages/Composer/ComposerKeyboard.tsx | 2 +- .../pages/Composer/ComposerMenu.tsx | 325 +++++++++--------- .../pages/Composer/ComposerNote.tsx | 6 +- .../InstrumentSettingsPopup.tsx | 2 +- .../Composer/InstrumentControls/index.tsx | 2 +- .../pages/Composer/MidiParser/TrackInfo.tsx | 2 +- .../pages/Composer/MidiParser/index.tsx | 6 +- .../pages/Index/HelpTab/ShortcutsHelp.tsx | 2 +- src/components/pages/Index/Home.tsx | 10 +- src/components/pages/Index/Logger.tsx | 5 +- .../pages/Keybinds/ShortcutEditor.tsx | 2 +- src/components/pages/MidiSetup/index.tsx | 6 +- .../pages/Player/PlayerKeyboard.tsx | 8 +- src/components/pages/Player/PlayerMenu.tsx | 66 ++-- src/components/pages/Player/PlayerNote.tsx | 4 +- src/components/pages/Player/PlayerSlider.tsx | 2 +- src/components/pages/Player/menu.css | 159 --------- src/components/pages/SheetVisualizer/Menu.tsx | 56 +-- .../pages/SheetVisualizer/SheetFrame.tsx | 2 +- .../pages/SheetVisualizer/SheetFrame2.tsx | 2 +- src/components/pages/Theme/ThemePropriety.tsx | 2 +- .../VsrgComposer/MultipleOptionSlider.tsx | 2 +- .../pages/VsrgComposer/VsrgComposerCache.ts | 2 +- .../pages/VsrgComposer/VsrgComposerCanvas.tsx | 4 +- .../pages/VsrgComposer/VsrgComposerMenu.tsx | 101 +++--- .../VsrgScrollableTrackRenderer.tsx | 2 +- .../VsrgComposer/VsrgTimelineRenderer.tsx | 2 +- .../pages/VsrgComposer/VsrgTrackRenderer.tsx | 2 +- .../pages/VsrgPlayer/VsrgPlayerCanvas.tsx | 2 +- .../pages/VsrgPlayer/VsrgPlayerMenu.tsx | 74 ++-- .../pages/ZenKeyboard/ZenKeyboardMenu.tsx | 45 +-- .../pages/ZenKeyboard/ZenKeypad.tsx | 2 +- src/components/pages/ZenKeyboard/ZenNote.tsx | 4 +- src/components/pages/blog/BaseBlogPost.tsx | 2 +- src/components/pages/blog/BlogUl.tsx | 2 +- .../shared/Inputs/ComboBox/ComboBox.tsx | 4 +- src/components/shared/Menu/MenuContent.tsx | 68 ++++ src/components/shared/Menu/MenuContext.ts | 25 ++ src/components/shared/Menu/MenuItem.tsx | 52 +++ src/components/shared/Menu/MenuPanel.tsx | 43 +++ src/components/shared/Menu/menu.module.scss | 173 ++++++++++ .../shared/Miscellaneous/BaseNote.tsx | 2 +- .../shared/Miscellaneous/DonateButton.tsx | 2 +- .../shared/Miscellaneous/MenuItem.tsx | 33 -- .../shared/Miscellaneous/PageMeta.tsx | 2 +- .../GeneralProvidersWrapper.tsx | 4 +- .../ProviderWrappers/ThemeProviderWrapper.tsx | 54 +-- src/components/shared/Utility/AsyncPrompt.tsx | 2 +- .../shared/Utility/ErrorBoundaryRedirect.tsx | 2 +- src/components/shared/header/Header.tsx | 2 +- src/components/shared/layout/Card.tsx | 2 +- src/components/shared/layout/Column.tsx | 2 +- src/components/shared/layout/Grid.tsx | 2 +- src/components/shared/layout/Row.tsx | 2 +- src/components/shared/link/AppLink.tsx | 2 +- src/components/shared/pagesLayout/Folder.tsx | 2 +- .../shared/pagesLayout/MenuPanel.tsx | 19 - .../shared/pagesLayout/SimpleMenu.tsx | 40 +-- src/components/shared/separator/Separator.tsx | 2 +- src/lib/{Stats.ts => Analytics.ts} | 0 src/lib/BaseSettings.ts | 2 +- src/lib/Hooks/useConfig.ts | 2 +- ...aceObserver.tsx => useFontFaceObserver.ts} | 0 src/lib/Hooks/useTheme.ts | 2 +- src/lib/Providers/AudioProvider/index.ts | 2 +- src/lib/Providers/MIDIProvider.ts | 2 +- src/lib/Services/FileService.ts | 2 +- src/lib/Services/SongService.ts | 2 +- .../Services/globalServices.ts} | 8 +- src/lib/Songs/ComposedSong.ts | 4 +- src/lib/{ => Songs}/Layer.ts | 2 +- src/lib/Songs/RecordedSong.ts | 4 +- src/lib/Songs/SongClasses.ts | 2 +- src/lib/Songs/VisualSong.ts | 2 +- ...ledEventLoop.tsx => ThrottledEventLoop.ts} | 0 src/lib/{ => audio}/AudioPlayer.ts | 6 +- src/lib/{ => audio}/AudioRecorder.ts | 2 +- src/lib/{ => audio}/BasicPitchLoader.ts | 0 src/lib/{ => audio}/Instrument.ts | 2 +- src/lib/{ => audio}/MediaRecorderPolyfill.ts | 0 src/lib/{ => audio}/Metronome.ts | 2 +- src/lib/needsUpdate.ts | 2 +- src/lib/{ => utils}/UtilTypes.ts | 0 src/lib/{ => utils}/Utilities.ts | 38 +- src/pages/_app.tsx | 4 +- src/pages/backup/index.tsx | 2 +- src/pages/blog/posts/how-to-use-composer.tsx | 2 +- src/pages/changelog/index.tsx | 14 +- src/pages/composer/index.tsx | 12 +- src/pages/delete-cache/index.tsx | 2 +- src/pages/keybinds/index.tsx | 2 +- src/pages/player/index.tsx | 10 +- src/pages/sheet-visualizer/index.tsx | 4 +- src/pages/transfer/index.tsx | 4 +- src/pages/uma-mode/index.tsx | 4 +- src/pages/vsrg-composer/index.tsx | 4 +- src/pages/vsrg-player/index.tsx | 2 +- src/pages/zen-keyboard/index.tsx | 4 +- src/serviceWorkerRegistration.ts | 2 +- src/stores/{History.ts => BrowserHistory.ts} | 2 +- .../{GlobalConfig.ts => GlobalConfigStore.ts} | 8 +- src/stores/PlayerStore.ts | 2 +- src/stores/SongsStore.ts | 2 +- src/stores/ZenKeyboardStore.ts | 2 +- test-songs/ThingsToTest.md | 2 +- 116 files changed, 922 insertions(+), 756 deletions(-) rename src/{lib/updates.ts => changelog.ts} (99%) create mode 100644 src/components/shared/Menu/MenuContent.tsx create mode 100644 src/components/shared/Menu/MenuContext.ts create mode 100644 src/components/shared/Menu/MenuItem.tsx create mode 100644 src/components/shared/Menu/MenuPanel.tsx create mode 100644 src/components/shared/Menu/menu.module.scss delete mode 100644 src/components/shared/Miscellaneous/MenuItem.tsx delete mode 100644 src/components/shared/pagesLayout/MenuPanel.tsx rename src/lib/{Stats.ts => Analytics.ts} (100%) rename src/lib/Hooks/{useFontFaceObserver.tsx => useFontFaceObserver.ts} (100%) rename src/{stores/globalLink.ts => lib/Services/globalServices.ts} (80%) rename src/lib/{ => Songs}/Layer.ts (98%) rename src/lib/{ThrottledEventLoop.tsx => ThrottledEventLoop.ts} (100%) rename src/lib/{ => audio}/AudioPlayer.ts (94%) rename src/lib/{ => audio}/AudioRecorder.ts (96%) rename src/lib/{ => audio}/BasicPitchLoader.ts (100%) rename src/lib/{ => audio}/Instrument.ts (99%) rename src/lib/{ => audio}/MediaRecorderPolyfill.ts (100%) rename src/lib/{ => audio}/Metronome.ts (98%) rename src/lib/{ => utils}/UtilTypes.ts (100%) rename src/lib/{ => utils}/Utilities.ts (90%) rename src/stores/{History.ts => BrowserHistory.ts} (83%) rename src/stores/{GlobalConfig.ts => GlobalConfigStore.ts} (88%) diff --git a/README.md b/README.md index 5acd937d..641356c3 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ You can use the scripts `npm run build:genshin` and `npm run build:sky` which wi # How to build desktop app -The app uses tauri for the desktop bundle which is a sandboxed webview. You can build it by using `npm run build-tauri:genshin`, `npm run build-tauri:sky`, `npm run build-tauri:all`. The config is premade to allow for updates, if you dont have a signing key, the build will fail. If you want to build without updates, go to `src-tauri/tauri.conf.json` and set `updater` to false +The app uses tauri for the desktop bundle which is a sandboxed webview. You can build it by using `npm run build-tauri:genshin`, `npm run build-tauri:sky`, `npm run build-tauri:all`. The config is premade to allow for changelog, if you dont have a signing key, the build will fail. If you want to build without changelog, go to `src-tauri/tauri.conf.json` and set `updater` to false # Documentation diff --git a/package-lock.json b/package-lock.json index 2eee5d4b..bf94c962 100644 --- a/package-lock.json +++ b/package-lock.json @@ -71,7 +71,7 @@ "fs-extra": "^11.1.1", "next-pwa": "^5.6.0", "sass": "^1.68.0", - "typescript": "^5.4.3", + "typescript": "^5.4.5", "url-join": "^5.0.0" }, "engines": { @@ -9817,9 +9817,9 @@ } }, "node_modules/typescript": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", - "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index f76eaa13..aac69bcf 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "fs-extra": "^11.1.1", "next-pwa": "^5.6.0", "sass": "^1.68.0", - "typescript": "^5.4.3", + "typescript": "^5.4.5", "url-join": "^5.0.0" } } diff --git a/public/service-worker.js b/public/service-worker.js index 19251990..cb75fbb9 100644 --- a/public/service-worker.js +++ b/public/service-worker.js @@ -1 +1 @@ -!function(){var e={454:function(e,t,r){"use strict";var n,a;e.exports=(null==(n=r.g.process)?void 0:n.env)&&"object"==typeof(null==(a=r.g.process)?void 0:a.env)?r.g.process:r(663)},663:function(e){!function(){var t={229:function(e){var t,r,n,a=e.exports={};function defaultSetTimout(){throw Error("setTimeout has not been defined")}function defaultClearTimeout(){throw Error("clearTimeout has not been defined")}function runTimeout(e){if(t===setTimeout)return setTimeout(e,0);if((t===defaultSetTimout||!t)&&setTimeout)return t=setTimeout,setTimeout(e,0);try{return t(e,0)}catch(r){try{return t.call(null,e,0)}catch(r){return t.call(this,e,0)}}}!function(){try{t="function"==typeof setTimeout?setTimeout:defaultSetTimout}catch(e){t=defaultSetTimout}try{r="function"==typeof clearTimeout?clearTimeout:defaultClearTimeout}catch(e){r=defaultClearTimeout}}();var o=[],i=!1,s=-1;function cleanUpNextTick(){i&&n&&(i=!1,n.length?o=n.concat(o):s=-1,o.length&&drainQueue())}function drainQueue(){if(!i){var e=runTimeout(cleanUpNextTick);i=!0;for(var t=o.length;t;){for(n=o,o=[];++s1)for(var r=1;r0&&a[a.length-1])&&(6===s[0]||2===s[0])){i=0;continue}if(3===s[0]&&(!a||s[1]>a[0]&&s[1]{let r=e;return t.length>0&&(r+=` :: ${JSON.stringify(t)}`),r};let WorkboxError_WorkboxError=class WorkboxError_WorkboxError extends Error{constructor(e,t){let r=messageGenerator(e,t);super(r),this.name=e,this.details=t}};let t=new Set,r={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!=typeof registration?registration.scope:""},_createCacheName=e=>[r.prefix,e,r.suffix].filter(e=>e&&e.length>0).join("-"),eachCacheNameDetail=e=>{for(let t of Object.keys(r))e(t)},n={updateDetails:e=>{eachCacheNameDetail(t=>{"string"==typeof e[t]&&(r[t]=e[t])})},getGoogleAnalyticsName:e=>e||_createCacheName(r.googleAnalytics),getPrecacheName:e=>e||_createCacheName(r.precache),getPrefix:()=>r.prefix,getRuntimeName:e=>e||_createCacheName(r.runtime),getSuffix:()=>r.suffix};function stripParams(e,t){let r=new URL(e);for(let e of t)r.searchParams.delete(e);return r.href}async function cacheMatchIgnoreParams(e,t,r,n){let a=stripParams(t.url,r);if(t.url===a)return e.match(t,n);let o=Object.assign(Object.assign({},n),{ignoreSearch:!0}),i=await e.keys(t,o);for(let t of i){let o=stripParams(t.url,r);if(a===o)return e.match(t,n)}}let Deferred=class Deferred{constructor(){this.promise=new Promise((e,t)=>{this.resolve=e,this.reject=t})}};async function executeQuotaErrorCallbacks(){for(let e of t)await e()}let getFriendlyURL=e=>{let t=new URL(String(e),location.href);return t.href.replace(RegExp(`^${location.origin}`),"")};__webpack_require__(80);let normalizeHandler=e=>e&&"object"==typeof e?e:{handle:e};let Route_Route=class Route_Route{constructor(e,t,r="GET"){this.handler=normalizeHandler(t),this.match=e,this.method=r}setCatchHandler(e){this.catchHandler=normalizeHandler(e)}};let RegExpRoute=class RegExpRoute extends Route_Route{constructor(e,t,r){super(({url:t})=>{let r=e.exec(t.href);if(r&&(t.origin===location.origin||0===r.index))return r.slice(1)},t,r)}};let Router=class Router{constructor(){this._routes=new Map,this._defaultHandlerMap=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener("fetch",e=>{let{request:t}=e,r=this.handleRequest({request:t,event:e});r&&e.respondWith(r)})}addCacheListener(){self.addEventListener("message",e=>{if(e.data&&"CACHE_URLS"===e.data.type){let{payload:t}=e.data,r=Promise.all(t.urlsToCache.map(t=>{"string"==typeof t&&(t=[t]);let r=new Request(...t);return this.handleRequest({request:r,event:e})}));e.waitUntil(r),e.ports&&e.ports[0]&&r.then(()=>e.ports[0].postMessage(!0))}})}handleRequest({request:e,event:t}){let r;let n=new URL(e.url,location.href);if(!n.protocol.startsWith("http"))return;let a=n.origin===location.origin,{params:o,route:i}=this.findMatchingRoute({event:t,request:e,sameOrigin:a,url:n}),s=i&&i.handler,c=e.method;if(!s&&this._defaultHandlerMap.has(c)&&(s=this._defaultHandlerMap.get(c)),!s)return;try{r=s.handle({url:n,request:e,event:t,params:o})}catch(e){r=Promise.reject(e)}let l=i&&i.catchHandler;return r instanceof Promise&&(this._catchHandler||l)&&(r=r.catch(async r=>{if(l)try{return await l.handle({url:n,request:e,event:t,params:o})}catch(e){e instanceof Error&&(r=e)}if(this._catchHandler)return this._catchHandler.handle({url:n,request:e,event:t});throw r})),r}findMatchingRoute({url:e,sameOrigin:t,request:r,event:n}){let a=this._routes.get(r.method)||[];for(let o of a){let a;let i=o.match({url:e,sameOrigin:t,request:r,event:n});if(i)return Array.isArray(a=i)&&0===a.length?a=void 0:i.constructor===Object&&0===Object.keys(i).length?a=void 0:"boolean"==typeof i&&(a=void 0),{route:o,params:a}}return{}}setDefaultHandler(e,t="GET"){this._defaultHandlerMap.set(t,normalizeHandler(e))}setCatchHandler(e){this._catchHandler=normalizeHandler(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(e){if(!this._routes.has(e.method))throw new WorkboxError_WorkboxError("unregister-route-but-not-found-with-method",{method:e.method});let t=this._routes.get(e.method).indexOf(e);if(t>-1)this._routes.get(e.method).splice(t,1);else throw new WorkboxError_WorkboxError("unregister-route-route-not-registered")}};let getOrCreateDefaultRouter_getOrCreateDefaultRouter=()=>(e||((e=new Router).addFetchListener(),e.addCacheListener()),e);function registerRoute(e,t,r){let n;if("string"==typeof e){let a=new URL(e,location.href);n=new Route_Route(({url:e})=>e.href===a.href,t,r)}else if(e instanceof RegExp)n=new RegExpRoute(e,t,r);else if("function"==typeof e)n=new Route_Route(e,t,r);else if(e instanceof Route_Route)n=e;else throw new WorkboxError_WorkboxError("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});let a=getOrCreateDefaultRouter_getOrCreateDefaultRouter();return a.registerRoute(n),n}function toRequest(e){return"string"==typeof e?new Request(e):e}__webpack_require__(873);let StrategyHandler=class StrategyHandler{constructor(e,t){for(let r of(this._cacheKeys={},Object.assign(this,t),this.event=t.event,this._strategy=e,this._handlerDeferred=new Deferred,this._extendLifetimePromises=[],this._plugins=[...e.plugins],this._pluginStateMap=new Map,this._plugins))this._pluginStateMap.set(r,{});this.event.waitUntil(this._handlerDeferred.promise)}async fetch(e){let{event:t}=this,r=toRequest(e);if("navigate"===r.mode&&t instanceof FetchEvent&&t.preloadResponse){let e=await t.preloadResponse;if(e)return e}let n=this.hasCallback("fetchDidFail")?r.clone():null;try{for(let e of this.iterateCallbacks("requestWillFetch"))r=await e({request:r.clone(),event:t})}catch(e){if(e instanceof Error)throw new WorkboxError_WorkboxError("plugin-error-request-will-fetch",{thrownErrorMessage:e.message})}let a=r.clone();try{let e;for(let n of(e=await fetch(r,"navigate"===r.mode?void 0:this._strategy.fetchOptions),this.iterateCallbacks("fetchDidSucceed")))e=await n({event:t,request:a,response:e});return e}catch(e){throw n&&await this.runCallbacks("fetchDidFail",{error:e,event:t,originalRequest:n.clone(),request:a.clone()}),e}}async fetchAndCachePut(e){let t=await this.fetch(e),r=t.clone();return this.waitUntil(this.cachePut(e,r)),t}async cacheMatch(e){let t;let r=toRequest(e),{cacheName:n,matchOptions:a}=this._strategy,o=await this.getCacheKey(r,"read"),i=Object.assign(Object.assign({},a),{cacheName:n});for(let e of(t=await caches.match(o,i),this.iterateCallbacks("cachedResponseWillBeUsed")))t=await e({cacheName:n,matchOptions:a,cachedResponse:t,request:o,event:this.event})||void 0;return t}async cachePut(e,t){let r=toRequest(e);await new Promise(e=>setTimeout(e,0));let n=await this.getCacheKey(r,"write");if(!t)throw new WorkboxError_WorkboxError("cache-put-with-no-response",{url:getFriendlyURL(n.url)});let a=await this._ensureResponseSafeToCache(t);if(!a)return!1;let{cacheName:o,matchOptions:i}=this._strategy,s=await self.caches.open(o),c=this.hasCallback("cacheDidUpdate"),l=c?await cacheMatchIgnoreParams(s,n.clone(),["__WB_REVISION__"],i):null;try{await s.put(n,c?a.clone():a)}catch(e){if(e instanceof Error)throw"QuotaExceededError"===e.name&&await executeQuotaErrorCallbacks(),e}for(let e of this.iterateCallbacks("cacheDidUpdate"))await e({cacheName:o,oldResponse:l,newResponse:a.clone(),request:n,event:this.event});return!0}async getCacheKey(e,t){let r=`${e.url} | ${t}`;if(!this._cacheKeys[r]){let n=e;for(let e of this.iterateCallbacks("cacheKeyWillBeUsed"))n=toRequest(await e({mode:t,request:n,event:this.event,params:this.params}));this._cacheKeys[r]=n}return this._cacheKeys[r]}hasCallback(e){for(let t of this._strategy.plugins)if(e in t)return!0;return!1}async runCallbacks(e,t){for(let r of this.iterateCallbacks(e))await r(t)}*iterateCallbacks(e){for(let t of this._strategy.plugins)if("function"==typeof t[e]){let r=this._pluginStateMap.get(t),statefulCallback=n=>{let a=Object.assign(Object.assign({},n),{state:r});return t[e](a)};yield statefulCallback}}waitUntil(e){return this._extendLifetimePromises.push(e),e}async doneWaiting(){let e;for(;e=this._extendLifetimePromises.shift();)await e}destroy(){this._handlerDeferred.resolve(null)}async _ensureResponseSafeToCache(e){let t=e,r=!1;for(let e of this.iterateCallbacks("cacheWillUpdate"))if(t=await e({request:this.request,response:t,event:this.event})||void 0,r=!0,!t)break;return!r&&t&&200!==t.status&&(t=void 0),t}};let Strategy_Strategy=class Strategy_Strategy{constructor(e={}){this.cacheName=n.getRuntimeName(e.cacheName),this.plugins=e.plugins||[],this.fetchOptions=e.fetchOptions,this.matchOptions=e.matchOptions}handle(e){let[t]=this.handleAll(e);return t}handleAll(e){e instanceof FetchEvent&&(e={event:e,request:e.request});let t=e.event,r="string"==typeof e.request?new Request(e.request):e.request,n="params"in e?e.params:void 0,a=new StrategyHandler(this,{event:t,request:r,params:n}),o=this._getResponse(a,r,t),i=this._awaitComplete(o,a,r,t);return[o,i]}async _getResponse(e,t,r){let n;await e.runCallbacks("handlerWillStart",{event:r,request:t});try{if(!(n=await this._handle(t,e))||"error"===n.type)throw new WorkboxError_WorkboxError("no-response",{url:t.url})}catch(a){if(a instanceof Error){for(let o of e.iterateCallbacks("handlerDidError"))if(n=await o({error:a,event:r,request:t}))break}if(n);else throw a}for(let a of e.iterateCallbacks("handlerWillRespond"))n=await a({event:r,request:t,response:n});return n}async _awaitComplete(e,t,r,n){let a,o;try{a=await e}catch(e){}try{await t.runCallbacks("handlerDidRespond",{event:n,request:r,response:a}),await t.doneWaiting()}catch(e){e instanceof Error&&(o=e)}if(await t.runCallbacks("handlerDidComplete",{event:n,request:r,response:a,error:o}),t.destroy(),o)throw o}};let a={cacheWillUpdate:async({response:e})=>200===e.status||0===e.status?e:null};var o,i=__webpack_require__(454),s="Genshin",c="".concat(s,"-").concat("2024-4-9_19-24"),l="true"===i.env.NEXT_PUBLIC_IS_TAURI,u="".concat(3,"-precache-").concat(c),h="".concat(3,"-runtime-").concat(c);function forbiddenCachedItems(e){if(e.pathname.includes("service-worker")||e.pathname.includes("manifestData")||e.pathname.endsWith(".json"))return!0}console.log('CACHE NAME: "'.concat(c,'"')),self.addEventListener("activate",()=>self.clients.claim()),console.log("Precached files:",[{'revision':'ec65f60d0c041b46dc185ed96b6aa293','url':'/genshinMusic/_next/../public/service-worker.js'},{'revision':'227d01df3aa4651d','url':'/genshinMusic/_next/static/chunks/1160-227d01df3aa4651d.js'},{'revision':'0112e159b430f18e','url':'/genshinMusic/_next/static/chunks/1240-0112e159b430f18e.js'},{'revision':'dbfad4630a5a3445','url':'/genshinMusic/_next/static/chunks/2dc05096.dbfad4630a5a3445.js'},{'revision':'3a924c2198068ac0','url':'/genshinMusic/_next/static/chunks/3778-3a924c2198068ac0.js'},{'revision':'48016a9b751555be','url':'/genshinMusic/_next/static/chunks/3a2b0ac0.48016a9b751555be.js'},{'revision':'d7c701b16f396082','url':'/genshinMusic/_next/static/chunks/4031-d7c701b16f396082.js'},{'revision':'2207d7ee654c67b6','url':'/genshinMusic/_next/static/chunks/4577d2ec-2207d7ee654c67b6.js'},{'revision':'45d9d4a8eb717fa9','url':'/genshinMusic/_next/static/chunks/5086.45d9d4a8eb717fa9.js'},{'revision':'4965bccea1a83919','url':'/genshinMusic/_next/static/chunks/5744.4965bccea1a83919.js'},{'revision':'ba6f723a4aa3db13','url':'/genshinMusic/_next/static/chunks/5752-ba6f723a4aa3db13.js'},{'revision':'17bf9fcdeb4cb4c4','url':'/genshinMusic/_next/static/chunks/6441-17bf9fcdeb4cb4c4.js'},{'revision':'59e676e500d13414','url':'/genshinMusic/_next/static/chunks/69480c19-59e676e500d13414.js'},{'revision':'e5e399dfd861fb40','url':'/genshinMusic/_next/static/chunks/72acface.e5e399dfd861fb40.js'},{'revision':'0019402f22323af8','url':'/genshinMusic/_next/static/chunks/8427-0019402f22323af8.js'},{'revision':'d7413f2b9f658703','url':'/genshinMusic/_next/static/chunks/85d7bc83-d7413f2b9f658703.js'},{'revision':'a44530900c70cc7c','url':'/genshinMusic/_next/static/chunks/9460-a44530900c70cc7c.js'},{'revision':'19b8c2b4c8fc4d1a','url':'/genshinMusic/_next/static/chunks/9569-19b8c2b4c8fc4d1a.js'},{'revision':'9ff65f4f7ff6f864','url':'/genshinMusic/_next/static/chunks/ab5c09eb.9ff65f4f7ff6f864.js'},{'revision':'33d4ed17f4319fab','url':'/genshinMusic/_next/static/chunks/b1bb7d45.33d4ed17f4319fab.js'},{'revision':'9ae3c879deaea3d8','url':'/genshinMusic/_next/static/chunks/e21e5bbe-9ae3c879deaea3d8.js'},{'revision':'fa51f609d3e75584','url':'/genshinMusic/_next/static/chunks/ebc70433-fa51f609d3e75584.js'},{'revision':'ca706bf673a13738','url':'/genshinMusic/_next/static/chunks/framework-ca706bf673a13738.js'},{'revision':'f1bf07cb7ce8eb0c','url':'/genshinMusic/_next/static/chunks/main-f1bf07cb7ce8eb0c.js'},{'revision':'8ddbde168dca426b','url':'/genshinMusic/_next/static/chunks/pages/404-8ddbde168dca426b.js'},{'revision':'29960e25c3a5c052','url':'/genshinMusic/_next/static/chunks/pages/_app-29960e25c3a5c052.js'},{'revision':'2455c9d048a4b9a2','url':'/genshinMusic/_next/static/chunks/pages/_error-2455c9d048a4b9a2.js'},{'revision':'85cd20e73bba368d','url':'/genshinMusic/_next/static/chunks/pages/backup-85cd20e73bba368d.js'},{'revision':'ab00042c52471de8','url':'/genshinMusic/_next/static/chunks/pages/blog-ab00042c52471de8.js'},{'revision':'4acb2c5ac1d3b7e3','url':'/genshinMusic/_next/static/chunks/pages/blog/posts/connect-midi-device-4acb2c5ac1d3b7e3.js'},{'revision':'17d55fab9969f314','url':'/genshinMusic/_next/static/chunks/pages/blog/posts/how-to-use-composer-17d55fab9969f314.js'},{'revision':'882eada11478795b','url':'/genshinMusic/_next/static/chunks/pages/blog/posts/how-to-use-player-882eada11478795b.js'},{'revision':'92c924218d854224','url':'/genshinMusic/_next/static/chunks/pages/blog/posts/how-to-use-vsrg-composer-92c924218d854224.js'},{'revision':'844a9925e7051e49','url':'/genshinMusic/_next/static/chunks/pages/blog/posts/midi-transpose-844a9925e7051e49.js'},{'revision':'cf65e6de59f587f9','url':'/genshinMusic/_next/static/chunks/pages/blog/posts/video-audio-transpose-cf65e6de59f587f9.js'},{'revision':'2256212b0950e6c9','url':'/genshinMusic/_next/static/chunks/pages/changelog-2256212b0950e6c9.js'},{'revision':'9e6f0c8615df4a3e','url':'/genshinMusic/_next/static/chunks/pages/composer-9e6f0c8615df4a3e.js'},{'revision':'92204d77a20208d7','url':'/genshinMusic/_next/static/chunks/pages/delete-cache-92204d77a20208d7.js'},{'revision':'2d40073cfb685410','url':'/genshinMusic/_next/static/chunks/pages/donate-2d40073cfb685410.js'},{'revision':'b7add8b624660d05','url':'/genshinMusic/_next/static/chunks/pages/error-b7add8b624660d05.js'},{'revision':'72781a8bed557ac9','url':'/genshinMusic/_next/static/chunks/pages/index-72781a8bed557ac9.js'},{'revision':'0a9041c7a5d8158b','url':'/genshinMusic/_next/static/chunks/pages/keybinds-0a9041c7a5d8158b.js'},{'revision':'5c989e84cda0605e','url':'/genshinMusic/_next/static/chunks/pages/partners-5c989e84cda0605e.js'},{'revision':'3cdf58787826192e','url':'/genshinMusic/_next/static/chunks/pages/player-3cdf58787826192e.js'},{'revision':'64b512079afec082','url':'/genshinMusic/_next/static/chunks/pages/privacy-64b512079afec082.js'},{'revision':'51a66d2cf5185010','url':'/genshinMusic/_next/static/chunks/pages/sheet-visualizer-51a66d2cf5185010.js'},{'revision':'1b7e286bfac9df28','url':'/genshinMusic/_next/static/chunks/pages/theme-1b7e286bfac9df28.js'},{'revision':'c45b80b748c4fe10','url':'/genshinMusic/_next/static/chunks/pages/transfer-c45b80b748c4fe10.js'},{'revision':'c7ad53bb931848f7','url':'/genshinMusic/_next/static/chunks/pages/uma-mode-c7ad53bb931848f7.js'},{'revision':'0b4ae81ca472cf1e','url':'/genshinMusic/_next/static/chunks/pages/vsrg-composer-0b4ae81ca472cf1e.js'},{'revision':'5a27f3c80b96b283','url':'/genshinMusic/_next/static/chunks/pages/vsrg-player-5a27f3c80b96b283.js'},{'revision':'03b895f37a25c03d','url':'/genshinMusic/_next/static/chunks/pages/zen-keyboard-03b895f37a25c03d.js'},{'revision':'837c0df77fd5009c9e46d446188ecfd0','url':'/genshinMusic/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js'},{'revision':'263ad9218f708dde','url':'/genshinMusic/_next/static/chunks/webpack-263ad9218f708dde.js'},{'revision':'11208997e14e7ccd','url':'/genshinMusic/_next/static/css/11208997e14e7ccd.css'},{'revision':'227f2ac29f675782','url':'/genshinMusic/_next/static/css/227f2ac29f675782.css'},{'revision':'3b39d44eec6f01be','url':'/genshinMusic/_next/static/css/3b39d44eec6f01be.css'},{'revision':'3b4312c579b5068d','url':'/genshinMusic/_next/static/css/3b4312c579b5068d.css'},{'revision':'47b46a69f6cc55c6','url':'/genshinMusic/_next/static/css/47b46a69f6cc55c6.css'},{'revision':'4861c8de6b3413fc','url':'/genshinMusic/_next/static/css/4861c8de6b3413fc.css'},{'revision':'5756609caf1ad4a4','url':'/genshinMusic/_next/static/css/5756609caf1ad4a4.css'},{'revision':'770712bacc70f896','url':'/genshinMusic/_next/static/css/770712bacc70f896.css'},{'revision':'875a29864bdecc0d','url':'/genshinMusic/_next/static/css/875a29864bdecc0d.css'},{'revision':'9f08e63442acf37d','url':'/genshinMusic/_next/static/css/9f08e63442acf37d.css'},{'revision':'a9be0aa642f73a4b','url':'/genshinMusic/_next/static/css/a9be0aa642f73a4b.css'},{'revision':'add69f5770f6788e','url':'/genshinMusic/_next/static/css/add69f5770f6788e.css'},{'revision':'b193e7857b0c36f9','url':'/genshinMusic/_next/static/css/b193e7857b0c36f9.css'},{'revision':'c18c554d7a5b1241','url':'/genshinMusic/_next/static/css/c18c554d7a5b1241.css'},{'revision':'d7c29bc57861e46e','url':'/genshinMusic/_next/static/css/d7c29bc57861e46e.css'},{'revision':'e065fcfba24b282b','url':'/genshinMusic/_next/static/css/e065fcfba24b282b.css'},{'revision':'f1cf20787c70b484','url':'/genshinMusic/_next/static/css/f1cf20787c70b484.css'},{'revision':'ff4fd350a6266d54','url':'/genshinMusic/_next/static/css/ff4fd350a6266d54.css'},{'revision':'37b99d16','url':'/genshinMusic/_next/static/media/BonoboBold.37b99d16.ttf'},{'revision':'ed9965d379230c2954d2f4b5e6c935e8','url':'/genshinMusic/_next/static/media/Desert_Theme.c1f04f20.jpg'},{'revision':'8f3308316b267718521613d00c4e990f','url':'/genshinMusic/_next/static/media/Legacy_Bg_Theme.88ff5918.png'},{'revision':'71cda29cf7f5185657e3ce5deda6ecd7','url':'/genshinMusic/_next/static/media/Liyue_Theme.c96c416c.jpg'},{'revision':'6e2663ab47dccf54d1b0b31c657058f0','url':'/genshinMusic/_next/static/media/Rainy_Theme.16d15843.png'},{'revision':'1a41fe4a','url':'/genshinMusic/_next/static/media/RobotoSerif-Medium.1a41fe4a.ttf'},{'revision':'587261a63730aeb88abf28abb8dd759f','url':'/genshinMusic/_next/static/media/Snow_Theme.24673ba9.gif'},{'revision':'ba6a5ca14065522fdbac49a670d57cc6','url':'/genshinMusic/_next/static/media/buymeacoffee.36238f63.svg'},{'revision':'5132bddcb9ce0828888c91a08f35a2ec','url':'/genshinMusic/_next/static/media/kofi.bd96742e.png'},{'revision':'8461373793dc7967c3bbee79757ed85c','url':'/genshinMusic/_next/static/media/paypalme.20b31d9a.png'},{'revision':'1b8efd914ffd6543d91066228c75016b','url':'/genshinMusic/_next/static/media/rotate.135a6aec.svg'},{'revision':'cd224bc15d8695ca1d598c66d49f5bba','url':'/genshinMusic/_next/static/media/sky-musician-network.c9e85a08.jpg'},{'revision':'0cb87429103ebddfb9a8b092c75398b9','url':'/genshinMusic/_next/static/media/windsong-db.be5c32c5.jpg'},{'revision':'bea91b3a4ff3c75fa4520b99c6aec90a','url':'/genshinMusic/_next/static/wokm1PChX1vg-n6keV6WK/_buildManifest.js'},{'revision':'b6652df95db52feb4daf4eca35380933','url':'/genshinMusic/_next/static/wokm1PChX1vg-n6keV6WK/_ssgManifest.js'},{'revision':'bc90e8d4fede0ecb146feda1bab149d1','url':'/genshinMusic/assets/audio-midi-model.json'},{'revision':'d6fc1f028c0a6f94abe000906be37060','url':'/genshinMusic/assets/audio/Aurora/0.mp3'},{'revision':'5b81060e34f7712c18369126927a6238','url':'/genshinMusic/assets/audio/Aurora/1.mp3'},{'revision':'8c9689ac74973322bffb99e8096b9fbc','url':'/genshinMusic/assets/audio/Aurora/10.mp3'},{'revision':'824791444fb1f0425035c76566cb51e0','url':'/genshinMusic/assets/audio/Aurora/11.mp3'},{'revision':'b5d70896c0e53ee6b7773925341f5e47','url':'/genshinMusic/assets/audio/Aurora/12.mp3'},{'revision':'f45bab66324c7f8bd49cc264186a5438','url':'/genshinMusic/assets/audio/Aurora/13.mp3'},{'revision':'684d88b95831ddf5596f48f734cd1cdf','url':'/genshinMusic/assets/audio/Aurora/14.mp3'},{'revision':'dc52083eacf9f11561974f64c81ec640','url':'/genshinMusic/assets/audio/Aurora/2.mp3'},{'revision':'34f8b83e2d3051710c5b6a6266a1a998','url':'/genshinMusic/assets/audio/Aurora/3.mp3'},{'revision':'8e730609d21ab750b3a8e69704b2af51','url':'/genshinMusic/assets/audio/Aurora/4.mp3'},{'revision':'8c54cb1a9c0864711839539d1742e3d9','url':'/genshinMusic/assets/audio/Aurora/5.mp3'},{'revision':'de8bb0c3cc8df6f2693bd90c8981d750','url':'/genshinMusic/assets/audio/Aurora/6.mp3'},{'revision':'69e76e6fe22a6f8eccc245bfd26f260f','url':'/genshinMusic/assets/audio/Aurora/7.mp3'},{'revision':'f0c095094f7bddd797f97aed1962dc4f','url':'/genshinMusic/assets/audio/Aurora/8.mp3'},{'revision':'ff0d08f3678cbecf814ad088bca55c0f','url':'/genshinMusic/assets/audio/Aurora/9.mp3'},{'revision':'c406c6e6550df8882fd752d27edf1bae','url':'/genshinMusic/assets/audio/Bells/0.mp3'},{'revision':'15e0ea86719017954f8762d18d227e6b','url':'/genshinMusic/assets/audio/Bells/1.mp3'},{'revision':'606a3c20230b372d314a177d23451cf5','url':'/genshinMusic/assets/audio/Bells/2.mp3'},{'revision':'e89e16e88e17bd747fda34df08882ad5','url':'/genshinMusic/assets/audio/Bells/3.mp3'},{'revision':'d712c045514e0bbba054e50728a1c26c','url':'/genshinMusic/assets/audio/Bells/4.mp3'},{'revision':'6ec9fe6ceaa2e101e64c83d28b5abdae','url':'/genshinMusic/assets/audio/Bells/5.mp3'},{'revision':'77d319cf0137805270334bf15d2f6d2f','url':'/genshinMusic/assets/audio/Bells/6.mp3'},{'revision':'bed2984dc9157b53ea2d06d16d1466ce','url':'/genshinMusic/assets/audio/Bells/7.mp3'},{'revision':'8552c8d2faa0a983e2dc4c6e2648e138','url':'/genshinMusic/assets/audio/Contrabass/0.mp3'},{'revision':'722614eed664e9b8d2ca0a390097f51f','url':'/genshinMusic/assets/audio/Contrabass/1.mp3'},{'revision':'efe5d4bb49c34f06c4504863071b7517','url':'/genshinMusic/assets/audio/Contrabass/10.mp3'},{'revision':'b243eb0a068828805df80e1a5c2aea6c','url':'/genshinMusic/assets/audio/Contrabass/11.mp3'},{'revision':'324691e6998641662055412e1fc408a0','url':'/genshinMusic/assets/audio/Contrabass/12.mp3'},{'revision':'f255ee612c1a997e5fd6fef441f33c9f','url':'/genshinMusic/assets/audio/Contrabass/13.mp3'},{'revision':'02024bf8a1ec85fa62b3615176971d16','url':'/genshinMusic/assets/audio/Contrabass/14.mp3'},{'revision':'629711ac08f287ff8b0d5dd0c4e55439','url':'/genshinMusic/assets/audio/Contrabass/2.mp3'},{'revision':'81fa1a7c8555b83892be966dbbd97e98','url':'/genshinMusic/assets/audio/Contrabass/3.mp3'},{'revision':'743e15ea725e4120d054db6b69aa15ae','url':'/genshinMusic/assets/audio/Contrabass/4.mp3'},{'revision':'46ba1f8707d6aa9fa56be8f82146b5c9','url':'/genshinMusic/assets/audio/Contrabass/5.mp3'},{'revision':'189e846396cdf7f4724a98e71f0cc9c0','url':'/genshinMusic/assets/audio/Contrabass/6.mp3'},{'revision':'490d37df11662be74b7512eff16eb287','url':'/genshinMusic/assets/audio/Contrabass/7.mp3'},{'revision':'364ed198e299ddb25221073efa236dea','url':'/genshinMusic/assets/audio/Contrabass/8.mp3'},{'revision':'1b50740b7c3ba2d9c5d1e3b17a051c9b','url':'/genshinMusic/assets/audio/Contrabass/9.mp3'},{'revision':'394084c049d8d4bc1e2aaff8a036ef09','url':'/genshinMusic/assets/audio/Drum/0.mp3'},{'revision':'236a984762d0ffd410d53dea955aeb56','url':'/genshinMusic/assets/audio/Drum/1.mp3'},{'revision':'9ad7cb1c010d2405e5a9e1b38790fbad','url':'/genshinMusic/assets/audio/Drum/2.mp3'},{'revision':'32d282555a61cd56ed2221c5369470fb','url':'/genshinMusic/assets/audio/Drum/3.mp3'},{'revision':'6440bc55c9b2336e08f1ca2252b7d0aa','url':'/genshinMusic/assets/audio/Drum/4.mp3'},{'revision':'990c71475136235758d33fa96d7e3318','url':'/genshinMusic/assets/audio/Drum/5.mp3'},{'revision':'221607e37a7ea1875765f51a5e3cd307','url':'/genshinMusic/assets/audio/Drum/6.mp3'},{'revision':'e2950c5161d0e08a1e213ec0d88c502a','url':'/genshinMusic/assets/audio/Drum/7.mp3'},{'revision':'bd97a079f2465d14fc2c21eeda33dce7','url':'/genshinMusic/assets/audio/DunDun/0.mp3'},{'revision':'805941ca7074d34e93d3e0883ff3c09d','url':'/genshinMusic/assets/audio/DunDun/1.mp3'},{'revision':'98316ae98a04a436d4d39fe66e1d4ef5','url':'/genshinMusic/assets/audio/DunDun/2.mp3'},{'revision':'45c85d53ed1b1448f95e67251ac911f0','url':'/genshinMusic/assets/audio/DunDun/3.mp3'},{'revision':'3542307ec319ee550325a05d0f8dc7ae','url':'/genshinMusic/assets/audio/DunDun/4.mp3'},{'revision':'2c4e10af10b2253c54dc608998087ac2','url':'/genshinMusic/assets/audio/DunDun/5.mp3'},{'revision':'0ddeb1a5c401374866b714efcce66c73','url':'/genshinMusic/assets/audio/DunDun/6.mp3'},{'revision':'956a892ba10e38e7c7fc58e3ea323243','url':'/genshinMusic/assets/audio/DunDun/7.mp3'},{'revision':'26a3b850279baaa99f51884e6adc4d97','url':'/genshinMusic/assets/audio/Flute/0.mp3'},{'revision':'623b20056879b3d887a347ce1d1fc524','url':'/genshinMusic/assets/audio/Flute/1.mp3'},{'revision':'00fc965b76fdad5594abf5e266686019','url':'/genshinMusic/assets/audio/Flute/10.mp3'},{'revision':'e7c9a3203307599fa98c7ef1c8423e78','url':'/genshinMusic/assets/audio/Flute/11.mp3'},{'revision':'a9285d3c09c6183d629cc399305ff58e','url':'/genshinMusic/assets/audio/Flute/12.mp3'},{'revision':'a5a19657b91eefaf4bacfbfd2eba2578','url':'/genshinMusic/assets/audio/Flute/13.mp3'},{'revision':'9be8189f9c3c4c474ffbc527c5ddd301','url':'/genshinMusic/assets/audio/Flute/14.mp3'},{'revision':'30dfb6820ac54c78bf4246c53b81c0c4','url':'/genshinMusic/assets/audio/Flute/2.mp3'},{'revision':'853b77b82825cbb6f80a120b50cbc5e6','url':'/genshinMusic/assets/audio/Flute/3.mp3'},{'revision':'bf8797d600639e92a4c43f20f32d32c0','url':'/genshinMusic/assets/audio/Flute/4.mp3'},{'revision':'98b888cb1ca4d3c91b11d4b55f7cf864','url':'/genshinMusic/assets/audio/Flute/5.mp3'},{'revision':'a8a63b100c7f7cf3547c21093d4dc6e7','url':'/genshinMusic/assets/audio/Flute/6.mp3'},{'revision':'3c230d55e35c8367769f5678c0cfc51c','url':'/genshinMusic/assets/audio/Flute/7.mp3'},{'revision':'a7765ff838347f41c1a545fb3d40bc24','url':'/genshinMusic/assets/audio/Flute/8.mp3'},{'revision':'485a4f0d28835632502c38b005bb2393','url':'/genshinMusic/assets/audio/Flute/9.mp3'},{'revision':'36a2bd90cb0196df5c93e64b5c73d1eb','url':'/genshinMusic/assets/audio/Guitar/0.mp3'},{'revision':'25052c09ec0c8368e712dbcb432a5b1d','url':'/genshinMusic/assets/audio/Guitar/1.mp3'},{'revision':'ecd04381de2d8f523227c64637cdd842','url':'/genshinMusic/assets/audio/Guitar/10.mp3'},{'revision':'e4d272c2fd9377b0891463e1b111054c','url':'/genshinMusic/assets/audio/Guitar/11.mp3'},{'revision':'718e41f885d4dad506bf32bf1b00f2eb','url':'/genshinMusic/assets/audio/Guitar/12.mp3'},{'revision':'5a9e4d5294f4141670360fe2118f66b1','url':'/genshinMusic/assets/audio/Guitar/13.mp3'},{'revision':'82c7e74a18c5f7449ebe8468b6bdc8d2','url':'/genshinMusic/assets/audio/Guitar/14.mp3'},{'revision':'51c5a04e8d8c8ef6f6217ab5d145aabf','url':'/genshinMusic/assets/audio/Guitar/2.mp3'},{'revision':'ace2fb3f4f34ffdb9eee6386a14c86fa','url':'/genshinMusic/assets/audio/Guitar/3.mp3'},{'revision':'2ce114e864d7b6017c226906b4b4051f','url':'/genshinMusic/assets/audio/Guitar/4.mp3'},{'revision':'1a1491ad2e705a7247fefdc5881b12b2','url':'/genshinMusic/assets/audio/Guitar/5.mp3'},{'revision':'e936e3d8eb56587d0921e0713d848f3b','url':'/genshinMusic/assets/audio/Guitar/6.mp3'},{'revision':'1f4d9c7f872f0b800cc72a1c3033ea21','url':'/genshinMusic/assets/audio/Guitar/7.mp3'},{'revision':'e4e857e1106fe07e9e814292f5cfab42','url':'/genshinMusic/assets/audio/Guitar/8.mp3'},{'revision':'4981178337af6c492bc2fb59d0dfb679','url':'/genshinMusic/assets/audio/Guitar/9.mp3'},{'revision':'53932d2ce2b23cc9c7656c9095e86576','url':'/genshinMusic/assets/audio/HandPan/0.mp3'},{'revision':'6d58e8fd7b0a63ddbfa3f1dc5386346e','url':'/genshinMusic/assets/audio/HandPan/1.mp3'},{'revision':'b652caa603d16b2819b5763ad4422778','url':'/genshinMusic/assets/audio/HandPan/2.mp3'},{'revision':'683ceed827bb041a967ccd5693d5035f','url':'/genshinMusic/assets/audio/HandPan/3.mp3'},{'revision':'f15e36ee54cb54823495503d621d44df','url':'/genshinMusic/assets/audio/HandPan/4.mp3'},{'revision':'55269b05d4558eabe4a999143d1c5d49','url':'/genshinMusic/assets/audio/HandPan/5.mp3'},{'revision':'d456d64bb89f04fb6e5125791fca3512','url':'/genshinMusic/assets/audio/HandPan/6.mp3'},{'revision':'77c231d9a595de6e6792ef80587e8fb1','url':'/genshinMusic/assets/audio/HandPan/7.mp3'},{'revision':'131734a948ff079fb9da55557342b56d','url':'/genshinMusic/assets/audio/Harp/0.mp3'},{'revision':'2b665aadb8dbfc39734d11b460b83d37','url':'/genshinMusic/assets/audio/Harp/1.mp3'},{'revision':'268369258f6f30d72f2a0849e8d71fa0','url':'/genshinMusic/assets/audio/Harp/10.mp3'},{'revision':'81fc73de71a3538025ba04e663d86a68','url':'/genshinMusic/assets/audio/Harp/11.mp3'},{'revision':'035488f1c6481c82373e6ff869bf7871','url':'/genshinMusic/assets/audio/Harp/12.mp3'},{'revision':'e7e3924eb5134d0dc81a1cf424b5ca04','url':'/genshinMusic/assets/audio/Harp/13.mp3'},{'revision':'94ee76027c7bb124d0bef7effb32a0e9','url':'/genshinMusic/assets/audio/Harp/14.mp3'},{'revision':'d495fd0d404432cb0749564acf6b781b','url':'/genshinMusic/assets/audio/Harp/2.mp3'},{'revision':'d997806c96f9ce1bc5802c2082d8d99d','url':'/genshinMusic/assets/audio/Harp/3.mp3'},{'revision':'323f3e319ea507b717f6abc7636eafda','url':'/genshinMusic/assets/audio/Harp/4.mp3'},{'revision':'f8f46511a19a203025e9d8c6bb274775','url':'/genshinMusic/assets/audio/Harp/5.mp3'},{'revision':'b5cd26d2e87fa2273feacfb73065c567','url':'/genshinMusic/assets/audio/Harp/6.mp3'},{'revision':'fa262cf4f6e687e8889e63262cc3cae6','url':'/genshinMusic/assets/audio/Harp/7.mp3'},{'revision':'e091a48cc517a35cc0374f426bb542d8','url':'/genshinMusic/assets/audio/Harp/8.mp3'},{'revision':'b330d26a7a072281f128dff3f8b6a226','url':'/genshinMusic/assets/audio/Harp/9.mp3'},{'revision':'d33f990b5d5cd0f1969fa3fa7f954940','url':'/genshinMusic/assets/audio/Horn/0.mp3'},{'revision':'e7d1cdf166a7ccd6d0d8882328cf7485','url':'/genshinMusic/assets/audio/Horn/1.mp3'},{'revision':'bf9dfe22ec80ac7cac95b9a43366bde9','url':'/genshinMusic/assets/audio/Horn/10.mp3'},{'revision':'23e23b3b785e7ac713360580d6f5e8ca','url':'/genshinMusic/assets/audio/Horn/11.mp3'},{'revision':'3444ef79cfe6db463a2580c8c2bd305a','url':'/genshinMusic/assets/audio/Horn/12.mp3'},{'revision':'e388a2be5bc1b7d967340d8b395e9692','url':'/genshinMusic/assets/audio/Horn/13.mp3'},{'revision':'97e703c22bd3edc046434f4d96fa2de0','url':'/genshinMusic/assets/audio/Horn/14.mp3'},{'revision':'5d0e4459f866f10bd2bd78b8559e082b','url':'/genshinMusic/assets/audio/Horn/2.mp3'},{'revision':'468a6c4a085ec4ff9cdece671f669cfc','url':'/genshinMusic/assets/audio/Horn/3.mp3'},{'revision':'fe7961c6b7bba0f15fd6e1c43a71309f','url':'/genshinMusic/assets/audio/Horn/4.mp3'},{'revision':'0367160860d517ca89826a7a161e6364','url':'/genshinMusic/assets/audio/Horn/5.mp3'},{'revision':'04dde93ea7134190042bef5b97a05ebf','url':'/genshinMusic/assets/audio/Horn/6.mp3'},{'revision':'2b37d35b162e0b18ca87b8ecc952bf5d','url':'/genshinMusic/assets/audio/Horn/7.mp3'},{'revision':'cf7c862e0f27501a221072bb2b5e877b','url':'/genshinMusic/assets/audio/Horn/8.mp3'},{'revision':'25c314b3e74daf4115e91376b9bcfa55','url':'/genshinMusic/assets/audio/Horn/9.mp3'},{'revision':'ed340eb0fde17af485e529938662ed87','url':'/genshinMusic/assets/audio/Kalimba/0.mp3'},{'revision':'a80ad231296e59aa8da2dc27f5b82b2a','url':'/genshinMusic/assets/audio/Kalimba/1.mp3'},{'revision':'b61a590092a51ebfedbe79265cfd2779','url':'/genshinMusic/assets/audio/Kalimba/10.mp3'},{'revision':'d5174d0962d3e2b9b68592e391668086','url':'/genshinMusic/assets/audio/Kalimba/11.mp3'},{'revision':'322d908c030fc5a7a72ffbf79671ad21','url':'/genshinMusic/assets/audio/Kalimba/12.mp3'},{'revision':'719d33c058e4914e51240befe65792d6','url':'/genshinMusic/assets/audio/Kalimba/13.mp3'},{'revision':'912c1433419947dbf474304befb807e4','url':'/genshinMusic/assets/audio/Kalimba/14.mp3'},{'revision':'e308ade9ab8963d9d32f44db1511b96c','url':'/genshinMusic/assets/audio/Kalimba/2.mp3'},{'revision':'2e4795ecab35edc0f4849d7fdf0329f8','url':'/genshinMusic/assets/audio/Kalimba/3.mp3'},{'revision':'72ed8f2199a1872e4fd53376a2b8f6a0','url':'/genshinMusic/assets/audio/Kalimba/4.mp3'},{'revision':'1f76a872273467bdffe9cd251147c40e','url':'/genshinMusic/assets/audio/Kalimba/5.mp3'},{'revision':'3fe7b9238dc3d7ed4abcb31a690b309c','url':'/genshinMusic/assets/audio/Kalimba/6.mp3'},{'revision':'c2fd08f49bf1cf80016bddd04806885f','url':'/genshinMusic/assets/audio/Kalimba/7.mp3'},{'revision':'baaf672f93bd88b20edc14814db7a001','url':'/genshinMusic/assets/audio/Kalimba/8.mp3'},{'revision':'869e84f6a06063ebe8706adc959b6292','url':'/genshinMusic/assets/audio/Kalimba/9.mp3'},{'revision':'8d86ccb344ec5e9e0720fdd81251a8e6','url':'/genshinMusic/assets/audio/LightGuitar/0.mp3'},{'revision':'6988c2855a17ddb683d933bd395d23e9','url':'/genshinMusic/assets/audio/LightGuitar/1.mp3'},{'revision':'d9f8825876d0b69223832050b41ab9bf','url':'/genshinMusic/assets/audio/LightGuitar/10.mp3'},{'revision':'1b906c338eaa1ce155c61ac187bee576','url':'/genshinMusic/assets/audio/LightGuitar/11.mp3'},{'revision':'e6324f2896ce9e315a4599e8cfb5dd0b','url':'/genshinMusic/assets/audio/LightGuitar/12.mp3'},{'revision':'97de9ed2856efde4db1c24c238cb7a65','url':'/genshinMusic/assets/audio/LightGuitar/13.mp3'},{'revision':'ea6010c3aa333bdc600b17039f1c6483','url':'/genshinMusic/assets/audio/LightGuitar/14.mp3'},{'revision':'224224c398ed5a8bd6aa89e8370dbce2','url':'/genshinMusic/assets/audio/LightGuitar/2.mp3'},{'revision':'5a0cf602795f58c1cb2573cc5e9d711d','url':'/genshinMusic/assets/audio/LightGuitar/3.mp3'},{'revision':'04bd286f98a0b3618a2d1e5350aaf8c1','url':'/genshinMusic/assets/audio/LightGuitar/4.mp3'},{'revision':'848ec50f4e775ff54c6c4c10b886a9ac','url':'/genshinMusic/assets/audio/LightGuitar/5.mp3'},{'revision':'6e3865e32be9f3204780cc1b0842f0a4','url':'/genshinMusic/assets/audio/LightGuitar/6.mp3'},{'revision':'c91f21717a314934f052f51cd4e6822b','url':'/genshinMusic/assets/audio/LightGuitar/7.mp3'},{'revision':'f0f3931df82dfce5b0e4fdfb5aaff4ed','url':'/genshinMusic/assets/audio/LightGuitar/8.mp3'},{'revision':'1d6de5c681e7a6ab866470aeebfffc11','url':'/genshinMusic/assets/audio/LightGuitar/9.mp3'},{'revision':'3417daf18bcf63c70c0b06f452c52308','url':'/genshinMusic/assets/audio/Lyre/0.mp3'},{'revision':'cfc035442240515ec7e3e7a75181d585','url':'/genshinMusic/assets/audio/Lyre/1.mp3'},{'revision':'d21dbbf01c72c6f54cff40ae4cd0fc39','url':'/genshinMusic/assets/audio/Lyre/10.mp3'},{'revision':'01dabbedf8ddbfb15becdff5ae24fe68','url':'/genshinMusic/assets/audio/Lyre/11.mp3'},{'revision':'b7de700386e03630c1d010208a942810','url':'/genshinMusic/assets/audio/Lyre/12.mp3'},{'revision':'c142a28ca1f429529ca8d1907a9aca0f','url':'/genshinMusic/assets/audio/Lyre/13.mp3'},{'revision':'093f9fa8129f99493f816e5c95a6f145','url':'/genshinMusic/assets/audio/Lyre/14.mp3'},{'revision':'e1e76ddd5d6d93553abb72e9778aa8b3','url':'/genshinMusic/assets/audio/Lyre/15.mp3'},{'revision':'be0081316c1891fa597aab5fa729688b','url':'/genshinMusic/assets/audio/Lyre/16.mp3'},{'revision':'f29216e6d64cb0778d79396d4f66cba0','url':'/genshinMusic/assets/audio/Lyre/17.mp3'},{'revision':'4e52a2ea84cb96063d3e906843b994b0','url':'/genshinMusic/assets/audio/Lyre/18.mp3'},{'revision':'7ea822f42eeca696b6c6f5836f54b3a3','url':'/genshinMusic/assets/audio/Lyre/19.mp3'},{'revision':'3e6f55fd191a91ba3fb710bde2109799','url':'/genshinMusic/assets/audio/Lyre/2.mp3'},{'revision':'1447ece9690d6a0b7c5385651174c9ea','url':'/genshinMusic/assets/audio/Lyre/20.mp3'},{'revision':'cc1d17a399edee8d6459e4ea94d663a6','url':'/genshinMusic/assets/audio/Lyre/3.mp3'},{'revision':'0a9a1d53557037a494f13f24d5a9cd73','url':'/genshinMusic/assets/audio/Lyre/4.mp3'},{'revision':'62d35d228342896de7d29c48966e8f0b','url':'/genshinMusic/assets/audio/Lyre/5.mp3'},{'revision':'135de63dbc67263ada26dcaab875be03','url':'/genshinMusic/assets/audio/Lyre/6.mp3'},{'revision':'247d2366d22fcb3239f3a7c04ec2f1cc','url':'/genshinMusic/assets/audio/Lyre/7.mp3'},{'revision':'8abc3e7a285815e446aaa74d1aa6b783','url':'/genshinMusic/assets/audio/Lyre/8.mp3'},{'revision':'65b95d500a0c2b76f6acfb0f053c5f5a','url':'/genshinMusic/assets/audio/Lyre/9.mp3'},{'revision':'ecfffc3e4c56c423bd78b5342bf59f71','url':'/genshinMusic/assets/audio/MantaOcarina/0.mp3'},{'revision':'57032325610195477bbfd7718c75cd80','url':'/genshinMusic/assets/audio/MantaOcarina/1.mp3'},{'revision':'fd482d43bb73845068d803b9c0b7bb98','url':'/genshinMusic/assets/audio/MantaOcarina/10.mp3'},{'revision':'ca050aa34ac980ddc44c72aa1b6b850d','url':'/genshinMusic/assets/audio/MantaOcarina/11.mp3'},{'revision':'b48f8cfdfba1b0d56aec8d3e3ab957dd','url':'/genshinMusic/assets/audio/MantaOcarina/12.mp3'},{'revision':'6e54da95cb8589ab81ff80beeacf1874','url':'/genshinMusic/assets/audio/MantaOcarina/13.mp3'},{'revision':'fa509e709b2fdb8d05561ff784844dcf','url':'/genshinMusic/assets/audio/MantaOcarina/14.mp3'},{'revision':'c97e9485a9291c56aeae5ee294a938c3','url':'/genshinMusic/assets/audio/MantaOcarina/2.mp3'},{'revision':'b8ef1846b0c46cabb7a78c3c5d4fc3a2','url':'/genshinMusic/assets/audio/MantaOcarina/3.mp3'},{'revision':'123d94dbb301c8f57cd0ff2219989051','url':'/genshinMusic/assets/audio/MantaOcarina/4.mp3'},{'revision':'3be52ddf427ad1ee041e520c50e87f61','url':'/genshinMusic/assets/audio/MantaOcarina/5.mp3'},{'revision':'1a05d33e75eb9c21f7e415aa9e2bf77d','url':'/genshinMusic/assets/audio/MantaOcarina/6.mp3'},{'revision':'af907399339f5f8f73bfbba8f924a8e7','url':'/genshinMusic/assets/audio/MantaOcarina/7.mp3'},{'revision':'fcbf33e40d7ee627ded6603ce7de711a','url':'/genshinMusic/assets/audio/MantaOcarina/8.mp3'},{'revision':'e1401e475342d5de6f4dc3c976996701','url':'/genshinMusic/assets/audio/MantaOcarina/9.mp3'},{'revision':'2c84009f18e779ea381bf5e94b33da00','url':'/genshinMusic/assets/audio/MetronomeSFX/bar.mp3'},{'revision':'706b180c6de64d552fbb4d313f175697','url':'/genshinMusic/assets/audio/MetronomeSFX/quarter.mp3'},{'revision':'d9f474f504a87c3076852d086d560f15','url':'/genshinMusic/assets/audio/Ocarina/0.mp3'},{'revision':'30557c555e17e61ac0564b60a7616e9a','url':'/genshinMusic/assets/audio/Ocarina/1.mp3'},{'revision':'1c1e222641dc2d5ef33e0b47e187c62b','url':'/genshinMusic/assets/audio/Ocarina/10.mp3'},{'revision':'0a79ffb08477871e6b494f911ab80a23','url':'/genshinMusic/assets/audio/Ocarina/11.mp3'},{'revision':'8ef5f7889a4d930b755b8faf11207923','url':'/genshinMusic/assets/audio/Ocarina/12.mp3'},{'revision':'953a0f4daf8dcddce07f9e3b0a6c64d9','url':'/genshinMusic/assets/audio/Ocarina/13.mp3'},{'revision':'b976839fe3c26d17f7d7e81bd3db36d8','url':'/genshinMusic/assets/audio/Ocarina/14.mp3'},{'revision':'d24d73bf7e3665b233e53363cae3f979','url':'/genshinMusic/assets/audio/Ocarina/2.mp3'},{'revision':'ebc72b2279f94e9da9aaacdf4e26b4fd','url':'/genshinMusic/assets/audio/Ocarina/3.mp3'},{'revision':'67a66d232180c13b746a9147c0b943b1','url':'/genshinMusic/assets/audio/Ocarina/4.mp3'},{'revision':'17209b9eb74ebbf69f7baf3ebbe52647','url':'/genshinMusic/assets/audio/Ocarina/5.mp3'},{'revision':'d31831931d6204a39614c59fa59d8222','url':'/genshinMusic/assets/audio/Ocarina/6.mp3'},{'revision':'4fe0a0084eb9eed3c6465cb70b161d6c','url':'/genshinMusic/assets/audio/Ocarina/7.mp3'},{'revision':'a7a97e6029d21c99d801b9cbc059da83','url':'/genshinMusic/assets/audio/Ocarina/8.mp3'},{'revision':'e4c43ed5c2c13b9b08d14ce8530f5ec7','url':'/genshinMusic/assets/audio/Ocarina/9.mp3'},{'revision':'6b036d0dcd5cad40c485019ef5b292db','url':'/genshinMusic/assets/audio/Old-Zither/0.mp3'},{'revision':'9bc69ec4e46192e6af08f82cced16543','url':'/genshinMusic/assets/audio/Old-Zither/1.mp3'},{'revision':'255c4898a687a13057564655bd3c2697','url':'/genshinMusic/assets/audio/Old-Zither/10.mp3'},{'revision':'57368dc9864301717f7f5e2e54576137','url':'/genshinMusic/assets/audio/Old-Zither/11.mp3'},{'revision':'5e4264ba7054e81004b330d414ba52fa','url':'/genshinMusic/assets/audio/Old-Zither/12.mp3'},{'revision':'91947708ded0a18c724a0ed9303b4bdb','url':'/genshinMusic/assets/audio/Old-Zither/13.mp3'},{'revision':'982a5b29f8a2d691c5314affaf4ebd85','url':'/genshinMusic/assets/audio/Old-Zither/14.mp3'},{'revision':'c3e893fb30d1b25d031fa84d8a14c97f','url':'/genshinMusic/assets/audio/Old-Zither/15.mp3'},{'revision':'e628f0e0147397f515272783dba2dd1e','url':'/genshinMusic/assets/audio/Old-Zither/16.mp3'},{'revision':'971bc950845f0c8d724c804f030ded96','url':'/genshinMusic/assets/audio/Old-Zither/17.mp3'},{'revision':'720e3fb5628d358b5d534784aa80a884','url':'/genshinMusic/assets/audio/Old-Zither/18.mp3'},{'revision':'f9baa950474f917567a51758dd732b5d','url':'/genshinMusic/assets/audio/Old-Zither/19.mp3'},{'revision':'757743bcdda586494503b940ea96ae97','url':'/genshinMusic/assets/audio/Old-Zither/2.mp3'},{'revision':'7b2798a85ec2bef826177bc66f296e66','url':'/genshinMusic/assets/audio/Old-Zither/20.mp3'},{'revision':'b8ca06b22c4f8d8569b2567ab25fff14','url':'/genshinMusic/assets/audio/Old-Zither/3.mp3'},{'revision':'e63dd546204b84b52ce81d539d73ccba','url':'/genshinMusic/assets/audio/Old-Zither/4.mp3'},{'revision':'c3b7957533fcc946b198fb6879986adb','url':'/genshinMusic/assets/audio/Old-Zither/5.mp3'},{'revision':'cc34bb4ee9feacdb914b7b07ff78b8a0','url':'/genshinMusic/assets/audio/Old-Zither/6.mp3'},{'revision':'84e5e6b046cb7c4716ada2bd1bc90945','url':'/genshinMusic/assets/audio/Old-Zither/7.mp3'},{'revision':'62b04b322fd4463d4382fbfdb86c9362','url':'/genshinMusic/assets/audio/Old-Zither/8.mp3'},{'revision':'fd2196e66f672619229663296ee9f387','url':'/genshinMusic/assets/audio/Old-Zither/9.mp3'},{'revision':'608170489f305d0ad04fb7c4b2f554d6','url':'/genshinMusic/assets/audio/Panflute/0.mp3'},{'revision':'4cf76c89adc633f968304b7d2632077b','url':'/genshinMusic/assets/audio/Panflute/1.mp3'},{'revision':'819973bf4e6430776a605f4f29daaf48','url':'/genshinMusic/assets/audio/Panflute/10.mp3'},{'revision':'a0edf5de4c18755979b528fc94798c56','url':'/genshinMusic/assets/audio/Panflute/11.mp3'},{'revision':'83f5a375ce8687b262f4d139dba46a64','url':'/genshinMusic/assets/audio/Panflute/12.mp3'},{'revision':'1b5bcdf01049307b74ee4db7f2191aa8','url':'/genshinMusic/assets/audio/Panflute/13.mp3'},{'revision':'ba766fd855771ffdce5cf99cd6dc75e1','url':'/genshinMusic/assets/audio/Panflute/14.mp3'},{'revision':'b750f4ad37f51a928a6eebaac837c399','url':'/genshinMusic/assets/audio/Panflute/2.mp3'},{'revision':'b46589c0ecafaa279318e226178f8db1','url':'/genshinMusic/assets/audio/Panflute/3.mp3'},{'revision':'4f9471a52c515cfe405519e8ef82fb1b','url':'/genshinMusic/assets/audio/Panflute/4.mp3'},{'revision':'5e4303e8c77f0664442ca24e11a3c6d4','url':'/genshinMusic/assets/audio/Panflute/5.mp3'},{'revision':'796f826d877308053439d885c529da3f','url':'/genshinMusic/assets/audio/Panflute/6.mp3'},{'revision':'506d603a7b55bfa26a72d8614e70425b','url':'/genshinMusic/assets/audio/Panflute/7.mp3'},{'revision':'b1d656061602d1e8a2065be0a2c4f4a9','url':'/genshinMusic/assets/audio/Panflute/8.mp3'},{'revision':'c3db798966fcdf196fb7e67c248748c0','url':'/genshinMusic/assets/audio/Panflute/9.mp3'},{'revision':'eca6eae2f2f81466f26634cd58e78505','url':'/genshinMusic/assets/audio/Piano/0.mp3'},{'revision':'7d7b98424865d433944a84ccf1fbdeec','url':'/genshinMusic/assets/audio/Piano/1.mp3'},{'revision':'10c351400bb980049dc53cf14726b478','url':'/genshinMusic/assets/audio/Piano/10.mp3'},{'revision':'1d43325752520ef35a6c9b1fa7154fdd','url':'/genshinMusic/assets/audio/Piano/11.mp3'},{'revision':'b4297622d166628a8f93bf51c9987dc8','url':'/genshinMusic/assets/audio/Piano/12.mp3'},{'revision':'4a454d37173a3b41ef55ade3d7a36dc7','url':'/genshinMusic/assets/audio/Piano/13.mp3'},{'revision':'7f0b64c27b6407c8c11cb07c741118f4','url':'/genshinMusic/assets/audio/Piano/14.mp3'},{'revision':'14afb46799b4add43dcc2f8dcb40c703','url':'/genshinMusic/assets/audio/Piano/2.mp3'},{'revision':'b28c0861fe85a7de6919d35465401097','url':'/genshinMusic/assets/audio/Piano/3.mp3'},{'revision':'64b6fbe0bdfa6b973d4ad9e45163d1bf','url':'/genshinMusic/assets/audio/Piano/4.mp3'},{'revision':'c9a4314b2fc8a733caf0266ef7fb62be','url':'/genshinMusic/assets/audio/Piano/5.mp3'},{'revision':'e89bfa3d1ca2aef4cca25cda1b70c314','url':'/genshinMusic/assets/audio/Piano/6.mp3'},{'revision':'c931bf6688eab5022b69ba8c2c1e29a8','url':'/genshinMusic/assets/audio/Piano/7.mp3'},{'revision':'76ec1bceb636badd2a6fe223d3eddb43','url':'/genshinMusic/assets/audio/Piano/8.mp3'},{'revision':'ba256691c749dc5b94f1992a690a0839','url':'/genshinMusic/assets/audio/Piano/9.mp3'},{'revision':'0c0cc38fb6dc5701762bfcf9bcc50d10','url':'/genshinMusic/assets/audio/Pipa/0.mp3'},{'revision':'75c81330f65754e30aea7b7403eeef54','url':'/genshinMusic/assets/audio/Pipa/1.mp3'},{'revision':'03ac275bd06e56df426d07655e7c3296','url':'/genshinMusic/assets/audio/Pipa/10.mp3'},{'revision':'5093f500c3ebe0d20f7417d5044aef7c','url':'/genshinMusic/assets/audio/Pipa/11.mp3'},{'revision':'efff67c32812be379eb300d3658f48be','url':'/genshinMusic/assets/audio/Pipa/12.mp3'},{'revision':'0582fe1b88a8640ddbc0b13f68198cda','url':'/genshinMusic/assets/audio/Pipa/13.mp3'},{'revision':'abd24588374815226d58a23fdf0b7c43','url':'/genshinMusic/assets/audio/Pipa/14.mp3'},{'revision':'6e16bd63de59a2cac330ee0fded50c82','url':'/genshinMusic/assets/audio/Pipa/2.mp3'},{'revision':'3a83a6ae3af96def86841a0ff371919b','url':'/genshinMusic/assets/audio/Pipa/3.mp3'},{'revision':'ae730eab58e9544ac2facb7efa26118c','url':'/genshinMusic/assets/audio/Pipa/4.mp3'},{'revision':'177a83bec0e52440908ff84fe0c1dbf6','url':'/genshinMusic/assets/audio/Pipa/5.mp3'},{'revision':'8bb4130815145d9aead03c7820c6e1bf','url':'/genshinMusic/assets/audio/Pipa/6.mp3'},{'revision':'b593078a76e1f2b22f0a5afa66f9533a','url':'/genshinMusic/assets/audio/Pipa/7.mp3'},{'revision':'e32ddf18be20c14538e244a217e2df02','url':'/genshinMusic/assets/audio/Pipa/8.mp3'},{'revision':'6d5fbc594ae1df948317bf0421c6022f','url':'/genshinMusic/assets/audio/Pipa/9.mp3'},{'revision':'08502db4f8a16f3221c5a7872d45daa5','url':'/genshinMusic/assets/audio/SFX_BassSynth/0.mp3'},{'revision':'931c491280e92ae7561435563aec1c03','url':'/genshinMusic/assets/audio/SFX_BassSynth/1.mp3'},{'revision':'1ac0edd2dce5ff57b83191f82f7f52ce','url':'/genshinMusic/assets/audio/SFX_BassSynth/2.mp3'},{'revision':'ce79a9d7f8a3d34d8de756a4566a71fd','url':'/genshinMusic/assets/audio/SFX_BassSynth/3.mp3'},{'revision':'78dba8a82c4e8c603135f85ef86533eb','url':'/genshinMusic/assets/audio/SFX_BassSynth/4.mp3'},{'revision':'70e5510b6685556b957a7ed285e144c9','url':'/genshinMusic/assets/audio/SFX_BassSynth/5.mp3'},{'revision':'d3f9930c6dbdafcac964645dda193762','url':'/genshinMusic/assets/audio/SFX_BassSynth/6.mp3'},{'revision':'488df8c50e93711edd2688b03f087949','url':'/genshinMusic/assets/audio/SFX_BassSynth/7.mp3'},{'revision':'3628435d7ecf440a815057e9decd241a','url':'/genshinMusic/assets/audio/SFX_BirdCall/0.mp3'},{'revision':'171ee0ef36fd5c2829c7dee4b55422d0','url':'/genshinMusic/assets/audio/SFX_BirdCall/1.mp3'},{'revision':'db6662d4d62dd8a11e382cc7a267fbdc','url':'/genshinMusic/assets/audio/SFX_BirdCall/10.mp3'},{'revision':'3eb377a9a6977e2c81492d3e0facb8a5','url':'/genshinMusic/assets/audio/SFX_BirdCall/11.mp3'},{'revision':'1467467b2fbc89948534a855f1b93487','url':'/genshinMusic/assets/audio/SFX_BirdCall/12.mp3'},{'revision':'4d152ecc9b8be2a53df7bfa8ef0b8403','url':'/genshinMusic/assets/audio/SFX_BirdCall/13.mp3'},{'revision':'949881b718f8a91c696f432ce4ec6c6f','url':'/genshinMusic/assets/audio/SFX_BirdCall/14.mp3'},{'revision':'0cef78cd0bf9f111ce016a80d47ec41a','url':'/genshinMusic/assets/audio/SFX_BirdCall/2.mp3'},{'revision':'e3cedc0c64248634c8cab313799a095d','url':'/genshinMusic/assets/audio/SFX_BirdCall/3.mp3'},{'revision':'a0756f7b10e630ecbe2fd70110987ff3','url':'/genshinMusic/assets/audio/SFX_BirdCall/4.mp3'},{'revision':'7c825876e45ee6a899194b1395d4a432','url':'/genshinMusic/assets/audio/SFX_BirdCall/5.mp3'},{'revision':'dd6e019d7f152f44c038d5e367ef19bc','url':'/genshinMusic/assets/audio/SFX_BirdCall/6.mp3'},{'revision':'820dffe2203719c2c8ed2e684f7ce833','url':'/genshinMusic/assets/audio/SFX_BirdCall/7.mp3'},{'revision':'b983101131c6c79a82d6ec05861b47bb','url':'/genshinMusic/assets/audio/SFX_BirdCall/8.mp3'},{'revision':'ac514886f7950ef5c4ea71131af0a41a','url':'/genshinMusic/assets/audio/SFX_BirdCall/9.mp3'},{'revision':'ddc06ffb3f7698fc0b1508effd012786','url':'/genshinMusic/assets/audio/SFX_BirdCall/README.md'},{'revision':'e7d3be52a72a7688df139ab7bafdb0f5','url':'/genshinMusic/assets/audio/SFX_ChimeSynth/0.mp3'},{'revision':'95cf12c586d9d6c82b72d251c2bda2c9','url':'/genshinMusic/assets/audio/SFX_ChimeSynth/1.mp3'},{'revision':'832eb58e73da997287cb406ff7c4f639','url':'/genshinMusic/assets/audio/SFX_ChimeSynth/2.mp3'},{'revision':'4e4db16d81ab424bbafe30d9a79b595b','url':'/genshinMusic/assets/audio/SFX_ChimeSynth/3.mp3'},{'revision':'5453b2030920bb4351c36e64ed47ef64','url':'/genshinMusic/assets/audio/SFX_ChimeSynth/4.mp3'},{'revision':'8463dd78779a02eef213751cf4b6481f','url':'/genshinMusic/assets/audio/SFX_ChimeSynth/5.mp3'},{'revision':'e503e0162e87548d604c95bc6815c8ed','url':'/genshinMusic/assets/audio/SFX_ChimeSynth/6.mp3'},{'revision':'8d98c2bb55a0280c9d3ce513ca47b27c','url':'/genshinMusic/assets/audio/SFX_ChimeSynth/7.mp3'},{'revision':'794f5307d4cf2fc5cb6fe2e6b01fcc90','url':'/genshinMusic/assets/audio/SFX_CrabCall/0.mp3'},{'revision':'68ff0a29e73469b1295fb346d13efba5','url':'/genshinMusic/assets/audio/SFX_CrabCall/1.mp3'},{'revision':'357edf7ea3707834341269ed76176cf0','url':'/genshinMusic/assets/audio/SFX_CrabCall/10.mp3'},{'revision':'f43cc41da5ed09fd16cbe90aa88aec21','url':'/genshinMusic/assets/audio/SFX_CrabCall/11.mp3'},{'revision':'a94d69ffa3d2c5bd1339b1b696c37910','url':'/genshinMusic/assets/audio/SFX_CrabCall/12.mp3'},{'revision':'041b03ec687f8ab07d59c993aec7b6a5','url':'/genshinMusic/assets/audio/SFX_CrabCall/13.mp3'},{'revision':'22c3e3d7936e3eeb4b64ea14d05c559c','url':'/genshinMusic/assets/audio/SFX_CrabCall/14.mp3'},{'revision':'08dca733d822c2c5a04d21d10107be76','url':'/genshinMusic/assets/audio/SFX_CrabCall/2.mp3'},{'revision':'50c8d25382ba3773b5f4a2e24d8df35f','url':'/genshinMusic/assets/audio/SFX_CrabCall/3.mp3'},{'revision':'44fac7273ff770136a1017a457fb07d6','url':'/genshinMusic/assets/audio/SFX_CrabCall/4.mp3'},{'revision':'9f036480ffe26c26b877fe5d7916fca4','url':'/genshinMusic/assets/audio/SFX_CrabCall/5.mp3'},{'revision':'33faa2aa4ffbb9bf0221e8c603f2ef4a','url':'/genshinMusic/assets/audio/SFX_CrabCall/6.mp3'},{'revision':'d3ebcfb3ab778c70256752c287ca83c2','url':'/genshinMusic/assets/audio/SFX_CrabCall/7.mp3'},{'revision':'efb0c0bacffbd3b6f53bc4cd4dcb4ae6','url':'/genshinMusic/assets/audio/SFX_CrabCall/8.mp3'},{'revision':'d83ae2b29b2fbc4468ec9e852b9c02c0','url':'/genshinMusic/assets/audio/SFX_CrabCall/9.mp3'},{'revision':'ddc06ffb3f7698fc0b1508effd012786','url':'/genshinMusic/assets/audio/SFX_CrabCall/README.md'},{'revision':'27dbc9ecca9e5bfff9958c67f985feb0','url':'/genshinMusic/assets/audio/SFX_Dance/0.mp3'},{'revision':'b60ba0559370fdd216e615d20d83cd67','url':'/genshinMusic/assets/audio/SFX_Dance/1.mp3'},{'revision':'396210d9edaca9dcb9ba4cbef580794b','url':'/genshinMusic/assets/audio/SFX_Dance/2.mp3'},{'revision':'b73f0eb3c61cdbbdfded381f8c2e8e6d','url':'/genshinMusic/assets/audio/SFX_Dance/3.mp3'},{'revision':'efb8eefb1c119512cab58c490493aa35','url':'/genshinMusic/assets/audio/SFX_Dance/4.mp3'},{'revision':'dcb3ca13644c1b285f16718ee7d7e528','url':'/genshinMusic/assets/audio/SFX_Dance/5.mp3'},{'revision':'ddc06ffb3f7698fc0b1508effd012786','url':'/genshinMusic/assets/audio/SFX_Dance/README.md'},{'revision':'157164b420bbea9630742019e3b880a3','url':'/genshinMusic/assets/audio/SFX_FishCall/0.mp3'},{'revision':'4fa0ce2a72eedf4334f7472485d9a1d3','url':'/genshinMusic/assets/audio/SFX_FishCall/1.mp3'},{'revision':'097cfc032757017d91c71178b024851c','url':'/genshinMusic/assets/audio/SFX_FishCall/10.mp3'},{'revision':'2aa05ab8a5db6eb0e6f45c5c481d4b7d','url':'/genshinMusic/assets/audio/SFX_FishCall/11.mp3'},{'revision':'1518c2d5c6384bd3f510d44dc9fad87b','url':'/genshinMusic/assets/audio/SFX_FishCall/12.mp3'},{'revision':'e2351a4cb9b8cb8691bf8908f992a251','url':'/genshinMusic/assets/audio/SFX_FishCall/13.mp3'},{'revision':'069cb2b8bb53f2c40a7a9013428dc43e','url':'/genshinMusic/assets/audio/SFX_FishCall/14.mp3'},{'revision':'3c7377439ce905e8ea56aaf197b1263b','url':'/genshinMusic/assets/audio/SFX_FishCall/2.mp3'},{'revision':'ded110e1dd9af0c10c6dbe0741c7f539','url':'/genshinMusic/assets/audio/SFX_FishCall/3.mp3'},{'revision':'fcca45915dcca0a79b1e946a24ec6483','url':'/genshinMusic/assets/audio/SFX_FishCall/4.mp3'},{'revision':'01f5186cb38e3aa283692bebd479fb5a','url':'/genshinMusic/assets/audio/SFX_FishCall/5.mp3'},{'revision':'30866bfec3ab4f37343378872420a83a','url':'/genshinMusic/assets/audio/SFX_FishCall/6.mp3'},{'revision':'b0b1504ba49b716d3b5facfb61f0d510','url':'/genshinMusic/assets/audio/SFX_FishCall/7.mp3'},{'revision':'ed5e5d1ae50148bbcf28888ee22526e2','url':'/genshinMusic/assets/audio/SFX_FishCall/8.mp3'},{'revision':'a3ae8cd571e6c5820779d1a8df85da0a','url':'/genshinMusic/assets/audio/SFX_FishCall/9.mp3'},{'revision':'ddc06ffb3f7698fc0b1508effd012786','url':'/genshinMusic/assets/audio/SFX_FishCall/README.md'},{'revision':'d47988d71a709a32213e355eb17b96e0','url':'/genshinMusic/assets/audio/SFX_JellyCall/0.mp3'},{'revision':'02d3d5658a7e0b7b8d10706dc8793ece','url':'/genshinMusic/assets/audio/SFX_JellyCall/1.mp3'},{'revision':'377a2ec1d31c8041950a6a0fde08052d','url':'/genshinMusic/assets/audio/SFX_JellyCall/10.mp3'},{'revision':'be1c7740bac23343f8dcf5e602e827ed','url':'/genshinMusic/assets/audio/SFX_JellyCall/11.mp3'},{'revision':'f83dfa3cd554fa3b3747f75ddffc1b05','url':'/genshinMusic/assets/audio/SFX_JellyCall/12.mp3'},{'revision':'75444fd6efc9884cf875974463550496','url':'/genshinMusic/assets/audio/SFX_JellyCall/13.mp3'},{'revision':'15340dd0cffdfc13dd8d3c6542dc8e2d','url':'/genshinMusic/assets/audio/SFX_JellyCall/14.mp3'},{'revision':'ebc4b1ce8749319371aef5a2f7d9bae1','url':'/genshinMusic/assets/audio/SFX_JellyCall/2.mp3'},{'revision':'31e37f2af1ffcfc526abd3f425d8dc55','url':'/genshinMusic/assets/audio/SFX_JellyCall/3.mp3'},{'revision':'0c1899bbba0abb94c72e8c9564f2ed98','url':'/genshinMusic/assets/audio/SFX_JellyCall/4.mp3'},{'revision':'3db6a51fad7c568e825fd542a27e45e1','url':'/genshinMusic/assets/audio/SFX_JellyCall/5.mp3'},{'revision':'3fc06508a85b8d7c62ffdc274bb36ded','url':'/genshinMusic/assets/audio/SFX_JellyCall/6.mp3'},{'revision':'72566395c3b26eb5f6ae242c85c5bbfd','url':'/genshinMusic/assets/audio/SFX_JellyCall/7.mp3'},{'revision':'122835fbd4a290646ccd6a3e4db98188','url':'/genshinMusic/assets/audio/SFX_JellyCall/8.mp3'},{'revision':'0ad07d68ff59ffdb95f1c6d9c07a2872','url':'/genshinMusic/assets/audio/SFX_JellyCall/9.mp3'},{'revision':'ddc06ffb3f7698fc0b1508effd012786','url':'/genshinMusic/assets/audio/SFX_JellyCall/README.md'},{'revision':'763e59cc0346d3b5f24f166c836d76ca','url':'/genshinMusic/assets/audio/SFX_MantaCall/0.mp3'},{'revision':'d82c9810cc91a4134855d1624fb22c76','url':'/genshinMusic/assets/audio/SFX_MantaCall/1.mp3'},{'revision':'9f0a625c2450be0a6ea56a6f4b3c1356','url':'/genshinMusic/assets/audio/SFX_MantaCall/10.mp3'},{'revision':'41a909a92c5b0d4f60b8d95a022d7b6c','url':'/genshinMusic/assets/audio/SFX_MantaCall/11.mp3'},{'revision':'26520cd87dc4b17b1c129a3909ba3fc0','url':'/genshinMusic/assets/audio/SFX_MantaCall/12.mp3'},{'revision':'3b4d4f7c736616a033e3aaad8999bd03','url':'/genshinMusic/assets/audio/SFX_MantaCall/13.mp3'},{'revision':'fcfea8af69fefab63afb7e542ae05345','url':'/genshinMusic/assets/audio/SFX_MantaCall/14.mp3'},{'revision':'e72b8204d4e6fd6bddc4a6ad3924e407','url':'/genshinMusic/assets/audio/SFX_MantaCall/2.mp3'},{'revision':'7ef196b620723ffe9e7aa294e378f287','url':'/genshinMusic/assets/audio/SFX_MantaCall/3.mp3'},{'revision':'68073f5a5860ced5a72c971466ee1a08','url':'/genshinMusic/assets/audio/SFX_MantaCall/4.mp3'},{'revision':'413b5156b16af4e6bb022e1d9c34aad0','url':'/genshinMusic/assets/audio/SFX_MantaCall/5.mp3'},{'revision':'50e3c6091f39769a8471fc0f871eab25','url':'/genshinMusic/assets/audio/SFX_MantaCall/6.mp3'},{'revision':'832ab1f1a42825db2166dd027df56d37','url':'/genshinMusic/assets/audio/SFX_MantaCall/7.mp3'},{'revision':'e8410f10df992962237bf73bedb912b6','url':'/genshinMusic/assets/audio/SFX_MantaCall/8.mp3'},{'revision':'c6b7dd06d27dff8e794c04cad6f2ad23','url':'/genshinMusic/assets/audio/SFX_MantaCall/9.mp3'},{'revision':'ddc06ffb3f7698fc0b1508effd012786','url':'/genshinMusic/assets/audio/SFX_MantaCall/README.md'},{'revision':'7ac06ba351203f46c49afd19739304dd','url':'/genshinMusic/assets/audio/SFX_MothCall/0.mp3'},{'revision':'fdc677e6a9f49db2e4369bd93f431c65','url':'/genshinMusic/assets/audio/SFX_MothCall/1.mp3'},{'revision':'030b7999ca958660a79d559cd79ac82c','url':'/genshinMusic/assets/audio/SFX_MothCall/10.mp3'},{'revision':'329192397906a2649c9c1cd7be7f55af','url':'/genshinMusic/assets/audio/SFX_MothCall/11.mp3'},{'revision':'140286b7f5a917f98e34311278a4d285','url':'/genshinMusic/assets/audio/SFX_MothCall/12.mp3'},{'revision':'4f1e8029593a79208d9ee05b3e74ac83','url':'/genshinMusic/assets/audio/SFX_MothCall/13.mp3'},{'revision':'eefa2dd9373c96f988d8cafea9980b6a','url':'/genshinMusic/assets/audio/SFX_MothCall/14.mp3'},{'revision':'9b87c1d36bcab8a0bb18e53d93cfad73','url':'/genshinMusic/assets/audio/SFX_MothCall/2.mp3'},{'revision':'dfd4e223113390d82a0cf0030e947f80','url':'/genshinMusic/assets/audio/SFX_MothCall/3.mp3'},{'revision':'3e546ef46cc1661304dd82d2dff19eb2','url':'/genshinMusic/assets/audio/SFX_MothCall/4.mp3'},{'revision':'de0521d9dd826303636b692314848aa9','url':'/genshinMusic/assets/audio/SFX_MothCall/5.mp3'},{'revision':'7e6a63264b8e7b1cc849a2e979bb2e15','url':'/genshinMusic/assets/audio/SFX_MothCall/6.mp3'},{'revision':'46bbc7c7981020e981f9d6d3acb7fb22','url':'/genshinMusic/assets/audio/SFX_MothCall/7.mp3'},{'revision':'bcbb371b5f5d7556bad5e7c7097a5108','url':'/genshinMusic/assets/audio/SFX_MothCall/8.mp3'},{'revision':'992d55789e05810c4c5f5dbb45040507','url':'/genshinMusic/assets/audio/SFX_MothCall/9.mp3'},{'revision':'ddc06ffb3f7698fc0b1508effd012786','url':'/genshinMusic/assets/audio/SFX_MothCall/README.md'},{'revision':'b2157b0c243cfbe8a86c9a7e5f30b541','url':'/genshinMusic/assets/audio/SFX_SineSynth/0.mp3'},{'revision':'f2fd6188c9db72ef072c6cbc34dc1538','url':'/genshinMusic/assets/audio/SFX_SineSynth/1.mp3'},{'revision':'11aa84b2a7735f6c59529026d684fe56','url':'/genshinMusic/assets/audio/SFX_SineSynth/2.mp3'},{'revision':'e50c03ef2f5437daba10928ed01fc2e2','url':'/genshinMusic/assets/audio/SFX_SineSynth/3.mp3'},{'revision':'75a54bd320ff1ee37989c6df804ff19c','url':'/genshinMusic/assets/audio/SFX_SineSynth/4.mp3'},{'revision':'ccbd4e3f8cc0d304da625a449bae01b7','url':'/genshinMusic/assets/audio/SFX_SineSynth/5.mp3'},{'revision':'05fdaccbade736df6e831e20978fb21b','url':'/genshinMusic/assets/audio/SFX_SineSynth/6.mp3'},{'revision':'f249d2d3ecfe9747e4bef3dce1f2d321','url':'/genshinMusic/assets/audio/SFX_SineSynth/7.mp3'},{'revision':'b53eaf25fbf9518d580d792181a2bf16','url':'/genshinMusic/assets/audio/SFX_SpiritMantaCall/0.mp3'},{'revision':'86ae86f2e40c00095ad7088a8b840e82','url':'/genshinMusic/assets/audio/SFX_SpiritMantaCall/1.mp3'},{'revision':'50bca244e5c4835aed62853d608f9ecd','url':'/genshinMusic/assets/audio/SFX_SpiritMantaCall/10.mp3'},{'revision':'fc9e6561ed54fef3a89bf045e02e4fa1','url':'/genshinMusic/assets/audio/SFX_SpiritMantaCall/11.mp3'},{'revision':'5f451b3cdc6db0f1ed4ab0cc0cf9392e','url':'/genshinMusic/assets/audio/SFX_SpiritMantaCall/12.mp3'},{'revision':'5d2e7c59ad6c2c8c894df497a2ad8d7e','url':'/genshinMusic/assets/audio/SFX_SpiritMantaCall/13.mp3'},{'revision':'365bc9122a4cdae0aba3d92194fc1076','url':'/genshinMusic/assets/audio/SFX_SpiritMantaCall/14.mp3'},{'revision':'9c8ec34397d2b85571aef98cd65ec77b','url':'/genshinMusic/assets/audio/SFX_SpiritMantaCall/2.mp3'},{'revision':'6e9fe01edb766d3b7893aa015aa87907','url':'/genshinMusic/assets/audio/SFX_SpiritMantaCall/3.mp3'},{'revision':'338e9696cfa2f5c064834c3524332538','url':'/genshinMusic/assets/audio/SFX_SpiritMantaCall/4.mp3'},{'revision':'8fc10c935361f96c30bcd669c8ce1934','url':'/genshinMusic/assets/audio/SFX_SpiritMantaCall/5.mp3'},{'revision':'2a9026289f301ed2ff7f2de5b381d8d7','url':'/genshinMusic/assets/audio/SFX_SpiritMantaCall/6.mp3'},{'revision':'51e854fe610676da98058f96d89f38d5','url':'/genshinMusic/assets/audio/SFX_SpiritMantaCall/7.mp3'},{'revision':'1b98865ee2b8a541fda4e53c456c2fa3','url':'/genshinMusic/assets/audio/SFX_SpiritMantaCall/8.mp3'},{'revision':'8db33a9333ad89ca9628c9f2fdfe48c6','url':'/genshinMusic/assets/audio/SFX_SpiritMantaCall/9.mp3'},{'revision':'ddc06ffb3f7698fc0b1508effd012786','url':'/genshinMusic/assets/audio/SFX_SpiritMantaCall/README.md'},{'revision':'4e5b141e9ca5e591e83ec88eeff14bd3','url':'/genshinMusic/assets/audio/SFX_TR-909/0.mp3'},{'revision':'9ce011136e3af6c97eef972269944401','url':'/genshinMusic/assets/audio/SFX_TR-909/1.mp3'},{'revision':'7ea52b09b264c60e67b60c154f19e0ec','url':'/genshinMusic/assets/audio/SFX_TR-909/2.mp3'},{'revision':'1679c7c8c417dceccf01f5af04fc346c','url':'/genshinMusic/assets/audio/SFX_TR-909/3.mp3'},{'revision':'82a14957329630d2870ec92a34903b74','url':'/genshinMusic/assets/audio/SFX_TR-909/4.mp3'},{'revision':'c8e8e4ef90870657c4755865097553f1','url':'/genshinMusic/assets/audio/SFX_TR-909/5.mp3'},{'revision':'bcf42bef228f7b2e3927e2f3d6324e4c','url':'/genshinMusic/assets/audio/SFX_TR-909/6.mp3'},{'revision':'7ab1b6f21b8018468d3408efe495e938','url':'/genshinMusic/assets/audio/SFX_TR-909/7.mp3'},{'revision':'bdd5fbebe33e132b478b856e5ce0bd12','url':'/genshinMusic/assets/audio/ToyUkulele/0.mp3'},{'revision':'9673c076738c70acb1ec2e35e7054fda','url':'/genshinMusic/assets/audio/ToyUkulele/1.mp3'},{'revision':'f8ffef9da0a741ca42688d49c2312d94','url':'/genshinMusic/assets/audio/ToyUkulele/10.mp3'},{'revision':'623c8bd8f004c5a8d97ecef8a19f5a64','url':'/genshinMusic/assets/audio/ToyUkulele/11.mp3'},{'revision':'c88455fcbaf7216fedf0ab1377761e1c','url':'/genshinMusic/assets/audio/ToyUkulele/12.mp3'},{'revision':'578b750af2d95f292fba4c8e8dfba9fe','url':'/genshinMusic/assets/audio/ToyUkulele/13.mp3'},{'revision':'9064558738bd35e00164d8d8752e1b03','url':'/genshinMusic/assets/audio/ToyUkulele/14.mp3'},{'revision':'e17c7bd9bb12816202c70eccacbb900a','url':'/genshinMusic/assets/audio/ToyUkulele/2.mp3'},{'revision':'e69d04d6eabba4ceef14a59929f14888','url':'/genshinMusic/assets/audio/ToyUkulele/3.mp3'},{'revision':'371796a1c139ed02881849dc28568895','url':'/genshinMusic/assets/audio/ToyUkulele/4.mp3'},{'revision':'d0e00fda3d99144d1f6f94f396934a84','url':'/genshinMusic/assets/audio/ToyUkulele/5.mp3'},{'revision':'46b73f312020fe3add83989150c7ce14','url':'/genshinMusic/assets/audio/ToyUkulele/6.mp3'},{'revision':'d65f0dde33e61b89be88b61e049380d7','url':'/genshinMusic/assets/audio/ToyUkulele/7.mp3'},{'revision':'9bd04caec3bf3096b5c1d9686527809b','url':'/genshinMusic/assets/audio/ToyUkulele/8.mp3'},{'revision':'b7ad49319ec80556a6b0ee26b7933060','url':'/genshinMusic/assets/audio/ToyUkulele/9.mp3'},{'revision':'a5d3061d93ba3a29a578ea80345587c1','url':'/genshinMusic/assets/audio/Trumpet/0.mp3'},{'revision':'8b89807e19406d8bcaf6da51ba306ab2','url':'/genshinMusic/assets/audio/Trumpet/1.mp3'},{'revision':'b4898de31c370f52e2c975832ad47d90','url':'/genshinMusic/assets/audio/Trumpet/10.mp3'},{'revision':'9985742467bcdee9d8f5383a9c19c055','url':'/genshinMusic/assets/audio/Trumpet/11.mp3'},{'revision':'e1e95fbcc2b64151fc454a50b1f32c62','url':'/genshinMusic/assets/audio/Trumpet/12.mp3'},{'revision':'46647f9e99b8fd847ab7670a5cc190d5','url':'/genshinMusic/assets/audio/Trumpet/13.mp3'},{'revision':'f6c99ac75d90b808e81f9a3958a51795','url':'/genshinMusic/assets/audio/Trumpet/14.mp3'},{'revision':'0b91cce3b6ceb6a3ffdf0bb4f2fa4c39','url':'/genshinMusic/assets/audio/Trumpet/2.mp3'},{'revision':'99d4aedadbad58319e5f60b317a007ad','url':'/genshinMusic/assets/audio/Trumpet/3.mp3'},{'revision':'cb4e460414923755d0475b8db63839a0','url':'/genshinMusic/assets/audio/Trumpet/4.mp3'},{'revision':'3a8603f82e2cbb8d2aab3811cceb8557','url':'/genshinMusic/assets/audio/Trumpet/5.mp3'},{'revision':'57767b69a5adf43db391f9afa1fdc9f5','url':'/genshinMusic/assets/audio/Trumpet/6.mp3'},{'revision':'211b3d909b89c2cf7a43af1651f98e2e','url':'/genshinMusic/assets/audio/Trumpet/7.mp3'},{'revision':'abb25c4e6b2d15df5b88530448f8259a','url':'/genshinMusic/assets/audio/Trumpet/8.mp3'},{'revision':'7f193efd5abc26abca3c0a8c3dbb38cb','url':'/genshinMusic/assets/audio/Trumpet/9.mp3'},{'revision':'9ddb7f8560513a52ff18d4d36a3d0a06','url':'/genshinMusic/assets/audio/Vintage-Lyre/0.mp3'},{'revision':'fa18434a1ec057e89cff9a16a5ee26e8','url':'/genshinMusic/assets/audio/Vintage-Lyre/1.mp3'},{'revision':'3eaaaf43824414af3f1668ab30bd10c8','url':'/genshinMusic/assets/audio/Vintage-Lyre/10.mp3'},{'revision':'4d84470fe9c4810a41da07c1df752ebe','url':'/genshinMusic/assets/audio/Vintage-Lyre/11.mp3'},{'revision':'26c346cb7d0d9d4a328be2729e6c7784','url':'/genshinMusic/assets/audio/Vintage-Lyre/12.mp3'},{'revision':'cbcc0b56172bd9f96742738f39eb32a6','url':'/genshinMusic/assets/audio/Vintage-Lyre/13.mp3'},{'revision':'f0608686f5234fa8332722c0dbe221ca','url':'/genshinMusic/assets/audio/Vintage-Lyre/14.mp3'},{'revision':'0168de671b88dc8bcda68cad5253c31b','url':'/genshinMusic/assets/audio/Vintage-Lyre/15.mp3'},{'revision':'45a160dc94ba3fb345dec6b678be88cc','url':'/genshinMusic/assets/audio/Vintage-Lyre/16.mp3'},{'revision':'c4ced73613bfc370d70eef1dc7f74fac','url':'/genshinMusic/assets/audio/Vintage-Lyre/17.mp3'},{'revision':'c4a6516d70c283433264b69c1f67da3b','url':'/genshinMusic/assets/audio/Vintage-Lyre/18.mp3'},{'revision':'1e7c24970a11e2d46f849a56748845bf','url':'/genshinMusic/assets/audio/Vintage-Lyre/19.mp3'},{'revision':'1a35e42c409007b31edddd67e1514183','url':'/genshinMusic/assets/audio/Vintage-Lyre/2.mp3'},{'revision':'2c034399d165124b6f5c98f6ffe17461','url':'/genshinMusic/assets/audio/Vintage-Lyre/20.mp3'},{'revision':'5a249ea5b55cdc315c1feb710e2587eb','url':'/genshinMusic/assets/audio/Vintage-Lyre/3.mp3'},{'revision':'5a5d1c6302c8c7653e57ca3bdd4f7c65','url':'/genshinMusic/assets/audio/Vintage-Lyre/4.mp3'},{'revision':'04ef447c96539e2650d9d8e2d3d7e175','url':'/genshinMusic/assets/audio/Vintage-Lyre/5.mp3'},{'revision':'14fb6b9081f5b6c24b34a491e2c4719f','url':'/genshinMusic/assets/audio/Vintage-Lyre/6.mp3'},{'revision':'4e409ab0643ea16d9520e0da4ca4600a','url':'/genshinMusic/assets/audio/Vintage-Lyre/7.mp3'},{'revision':'c92c10d43155b8215a04709c7a187d9c','url':'/genshinMusic/assets/audio/Vintage-Lyre/8.mp3'},{'revision':'42a2341c945ab15fd74469d2f9f54b88','url':'/genshinMusic/assets/audio/Vintage-Lyre/9.mp3'},{'revision':'c9e635e54b77cb131e7436aa4f539334','url':'/genshinMusic/assets/audio/WinterPiano/0.mp3'},{'revision':'a0c5a8fa1e6599285c55e66870428de0','url':'/genshinMusic/assets/audio/WinterPiano/1.mp3'},{'revision':'fa45827097cdf3952758d426ddae8022','url':'/genshinMusic/assets/audio/WinterPiano/10.mp3'},{'revision':'a351b425ae533a525bf99c8459762720','url':'/genshinMusic/assets/audio/WinterPiano/11.mp3'},{'revision':'4010a0576e5de050d9b874aa8c4ef0ac','url':'/genshinMusic/assets/audio/WinterPiano/12.mp3'},{'revision':'68ef44ffe56ca57e938fbbd60809c080','url':'/genshinMusic/assets/audio/WinterPiano/13.mp3'},{'revision':'e0afc996d04c7e1e50daf1ab1c232358','url':'/genshinMusic/assets/audio/WinterPiano/14.mp3'},{'revision':'74855f097002ecb122459badaedb8f54','url':'/genshinMusic/assets/audio/WinterPiano/2.mp3'},{'revision':'d7a19f2ab265e0c8b338b78ea6a42701','url':'/genshinMusic/assets/audio/WinterPiano/3.mp3'},{'revision':'a4f81c763fed5715f72b59458a2775b9','url':'/genshinMusic/assets/audio/WinterPiano/4.mp3'},{'revision':'3eb51e42fe7bb8732d3eb87951e7cce1','url':'/genshinMusic/assets/audio/WinterPiano/5.mp3'},{'revision':'bd8994c2cc6e7f9133971f5ed720ad1f','url':'/genshinMusic/assets/audio/WinterPiano/6.mp3'},{'revision':'7330ed90a92f99fef4cfdf0cde505d89','url':'/genshinMusic/assets/audio/WinterPiano/7.mp3'},{'revision':'f4130e124a2eb97d5cb22ba47714a9da','url':'/genshinMusic/assets/audio/WinterPiano/8.mp3'},{'revision':'c52a5e061bddbf4711b7703d29281d3a','url':'/genshinMusic/assets/audio/WinterPiano/9.mp3'},{'revision':'528ca6e43eb6a8db60fc3d327ae536f0','url':'/genshinMusic/assets/audio/Xylophone/0.mp3'},{'revision':'5d6aef254407677363b4cfb869432ba0','url':'/genshinMusic/assets/audio/Xylophone/1.mp3'},{'revision':'41bf7c0506948fd6c8040bcc5acf8706','url':'/genshinMusic/assets/audio/Xylophone/10.mp3'},{'revision':'4e750a2d52e09977d0ef1744f25465c1','url':'/genshinMusic/assets/audio/Xylophone/11.mp3'},{'revision':'978c21d9203c51f57c8de47e01dabf05','url':'/genshinMusic/assets/audio/Xylophone/12.mp3'},{'revision':'72b355d067c3b798960cb78a3fe2f0fd','url':'/genshinMusic/assets/audio/Xylophone/13.mp3'},{'revision':'b59003e31e0c0c168206677090a4b261','url':'/genshinMusic/assets/audio/Xylophone/14.mp3'},{'revision':'dbcee8e2ad7cb054e579386c18ad79b5','url':'/genshinMusic/assets/audio/Xylophone/2.mp3'},{'revision':'76cb3204fd2026e4f8732121b07963e9','url':'/genshinMusic/assets/audio/Xylophone/3.mp3'},{'revision':'77051772c7035d93c2573da9e536c545','url':'/genshinMusic/assets/audio/Xylophone/4.mp3'},{'revision':'ab4e29dcf6a4fdd3af5d95da5738ad11','url':'/genshinMusic/assets/audio/Xylophone/5.mp3'},{'revision':'6ac64fc5d87057e0acf659c7559c65d8','url':'/genshinMusic/assets/audio/Xylophone/6.mp3'},{'revision':'50667c64fdff79ba4b71ac1fe5f90d1d','url':'/genshinMusic/assets/audio/Xylophone/7.mp3'},{'revision':'1e1eafdfbff5989903bd722a6df16ecf','url':'/genshinMusic/assets/audio/Xylophone/8.mp3'},{'revision':'abc16b06da48ca3a7afcd8724344fa4b','url':'/genshinMusic/assets/audio/Xylophone/9.mp3'},{'revision':'7c206a44131a62000f7d7ec7f09b18f6','url':'/genshinMusic/assets/audio/Zither/0.mp3'},{'revision':'ef2b3f5210c88426565b54d4f6d55a1b','url':'/genshinMusic/assets/audio/Zither/1.mp3'},{'revision':'35fba626140d3da9935a2d9ea95a68c1','url':'/genshinMusic/assets/audio/Zither/10.mp3'},{'revision':'08be6d9fd6cab4beb29dc8fbd3d20c95','url':'/genshinMusic/assets/audio/Zither/11.mp3'},{'revision':'c3c75ccbdf3995ddecc0f837cc03c791','url':'/genshinMusic/assets/audio/Zither/12.mp3'},{'revision':'8b1d22b9cbfada6b6231f00ee0a9b5aa','url':'/genshinMusic/assets/audio/Zither/13.mp3'},{'revision':'104635ee45c153edd29baac494bf1567','url':'/genshinMusic/assets/audio/Zither/14.mp3'},{'revision':'a466f269f2cf1ba8018f05984acbbe46','url':'/genshinMusic/assets/audio/Zither/15.mp3'},{'revision':'3a905bc2d44258f573edbcddccc1353b','url':'/genshinMusic/assets/audio/Zither/16.mp3'},{'revision':'6da338c5a78fdfb304840543c17046e2','url':'/genshinMusic/assets/audio/Zither/17.mp3'},{'revision':'c31c18f1066ba225a30b739ec192350b','url':'/genshinMusic/assets/audio/Zither/18.mp3'},{'revision':'fdc075cc31ed4c768be1350054696e5c','url':'/genshinMusic/assets/audio/Zither/19.mp3'},{'revision':'28bafbb589565dcd2c3e05ff41c513fc','url':'/genshinMusic/assets/audio/Zither/2.mp3'},{'revision':'90027c3a4ae0ebc2ad7fd53e562abfa3','url':'/genshinMusic/assets/audio/Zither/20.mp3'},{'revision':'e642f522ce359e3af2041f6a7aa73188','url':'/genshinMusic/assets/audio/Zither/3.mp3'},{'revision':'c1c4c16c41e1cc2572fad1b064c4b180','url':'/genshinMusic/assets/audio/Zither/4.mp3'},{'revision':'bf0e116847b95f6307e3520fbc9fcc89','url':'/genshinMusic/assets/audio/Zither/5.mp3'},{'revision':'499887434745c1355e62fb9a2745bdc8','url':'/genshinMusic/assets/audio/Zither/6.mp3'},{'revision':'c33f43b66c30accbe4630b47d395c272','url':'/genshinMusic/assets/audio/Zither/7.mp3'},{'revision':'26937cf69c516807d6ad4726f768f43a','url':'/genshinMusic/assets/audio/Zither/8.mp3'},{'revision':'cbe3faabb67d9702881ba820f3c67bad','url':'/genshinMusic/assets/audio/Zither/9.mp3'},{'revision':'491d4458ed4bc57e6fb191fc4666f046','url':'/genshinMusic/assets/audio/reverb4.wav'},{'revision':'dbbdc77f58808f74fb1c30e8a8835236','url':'/genshinMusic/assets/audio/reverb5.wav'},{'revision':'856f3f7a82b9ed3e373592b1d5c1b9eb','url':'/genshinMusic/assets/blog/help-composer-2.webp'},{'revision':'de44f4e535caeb673b498b694e5d2e10','url':'/genshinMusic/assets/blog/help-composer-3.webp'},{'revision':'1a2fc855b801aa9f0d433846f5ea38f7','url':'/genshinMusic/assets/blog/help-composer-4.webp'},{'revision':'73906bd08b1e22bd7d34e14ddfb58610','url':'/genshinMusic/assets/blog/help-composer-5.webp'},{'revision':'9a24e46c74cd1e0cd161d109762d60cd','url':'/genshinMusic/assets/blog/help-composer.webp'},{'revision':'9816eea0ceb8d57febe24250c2a621ab','url':'/genshinMusic/assets/blog/help-player-2.webp'},{'revision':'613825e987929ad0619b07a25949fd24','url':'/genshinMusic/assets/blog/help-player-3.webp'},{'revision':'d4f216c90d34a15f50ab2f5840a4c83d','url':'/genshinMusic/assets/blog/help-player.webp'},{'revision':'5ae5f2521b5f1f297fcba66de8d9cc58','url':'/genshinMusic/assets/blog/help-vsrg-composer-2.webp'},{'revision':'da78f4d2df0e498c6b472b657a42eba1','url':'/genshinMusic/assets/blog/help-vsrg-composer-3.webp'},{'revision':'599c3854b8112ed8a77537265e31b59e','url':'/genshinMusic/assets/blog/help-vsrg-composer.webp'},{'revision':'d8d23cc536c191edce976db044f0c2b0','url':'/genshinMusic/assets/blog/midi-1.webp'},{'revision':'610b3cef8d13e688629df48fa4670fe8','url':'/genshinMusic/assets/blog/midi-2.webp'},{'revision':'dc583c33fa201752e26ca4c09f2c47c4','url':'/genshinMusic/assets/blog/midi-btn.webp'},{'revision':'e7fe0e77de8c844624a0b1451b04002c','url':'/genshinMusic/assets/blog/zen-keyboard.webp'},{'revision':'02a0b873d020e14fc020057317cf7a23','url':'/genshinMusic/assets/group1-shard1of1.bin'},{'revision':'53f4ce1456b8382d020c2edf51f9a06d','url':'/genshinMusic/assets/icons/addCell.svg'},{'revision':'402a59b143ba2f536f1329381ecded94','url':'/genshinMusic/assets/icons/full.png'},{'revision':'a26e2db34e420c66ea2e2825c5358837','url':'/genshinMusic/assets/icons/keys/cr.svg'},{'revision':'82bb8594400afbde232b338b23ed8475','url':'/genshinMusic/assets/icons/keys/dm.svg'},{'revision':'5e75d39869cd9f7cb1ab1755b29664ac','url':'/genshinMusic/assets/icons/keys/dmcr.svg'},{'revision':'5defb9bbcd25db4d8f6d52b68fa300bb','url':'/genshinMusic/assets/icons/keys/do.svg'},{'revision':'42a6d2a3ffa29d79ffd67be6a862cf1e','url':'/genshinMusic/assets/icons/keys/fa.svg'},{'revision':'ca84e98beda8a6fd44e2d962ab25467d','url':'/genshinMusic/assets/icons/keys/la.svg'},{'revision':'fb7400b3b1a92815ec26e8f84e30ca9d','url':'/genshinMusic/assets/icons/keys/mi.svg'},{'revision':'90f0406cacb3066e17dc064814108cc7','url':'/genshinMusic/assets/icons/keys/old icons/do.svg'},{'revision':'c3d05b2158e6a68c1a4266cf9ed34a1c','url':'/genshinMusic/assets/icons/keys/old icons/fa.svg'},{'revision':'79a07070d71e0f8964208484875c2077','url':'/genshinMusic/assets/icons/keys/old icons/la.svg'},{'revision':'2b696be94489c3bc05c3d6dfcae0abda','url':'/genshinMusic/assets/icons/keys/old icons/mi.svg'},{'revision':'c04694b0eafd03b1cb1ceb27b8c398b1','url':'/genshinMusic/assets/icons/keys/old icons/re.svg'},{'revision':'4d9956557b9a08caeef36380780f800e','url':'/genshinMusic/assets/icons/keys/old icons/so.svg'},{'revision':'633a68b89e9a8c10889e25c8d182fb63','url':'/genshinMusic/assets/icons/keys/old icons/ti.svg'},{'revision':'8e092afc024c163a36bd50218ac7244b','url':'/genshinMusic/assets/icons/keys/re.svg'},{'revision':'defa67bc736bfafdac607c26625f7692','url':'/genshinMusic/assets/icons/keys/so.svg'},{'revision':'bdebf640d1b40c6834ff7ac44d47db91','url':'/genshinMusic/assets/icons/keys/ti.svg'},{'revision':'0bbd13d3a10ecefca257a13c69b1f83a','url':'/genshinMusic/assets/icons/loadingApp.svg'},{'revision':'991f6d8b4165138c3ddf828aa09b4200','url':'/genshinMusic/assets/icons/removeCell.svg'},{'revision':'67c290cd00303a68fbd735cd15601bc7','url':'/genshinMusic/assets/icons/rounded.png'},{'revision':'b4b41b256ec7a31789f4b236ee97e64d','url':'/genshinMusic/assets/icons/star_decoration.svg'},{'revision':'ac9ebe4205087b85a26484759e218d49','url':'/genshinMusic/assets/images/specy.png'},{'revision':'4f083bfac6c911881db3329b1e0219c4','url':'/genshinMusic/favicon.ico'},{'revision':'8bc84b3a8ddc880832ef306445759b52','url':'/genshinMusic/logo192.png'},{'revision':'0eddb37f5be247733d6af3c944e8b514','url':'/genshinMusic/logo512.png'},{'revision':'9609fe54e8452f1228bb8962a74d179a','url':'/genshinMusic/manifest.json'},{'revision':'386eca79726a4313c9a9443d5b50a637','url':'/genshinMusic/manifestData/composer.png'},{'revision':'77d9d552f7c4bbed06f6b9ed05506516','url':'/genshinMusic/manifestData/composer.webp'},{'revision':'3f4bd40fbddb8af00e266da876efe0bb','url':'/genshinMusic/manifestData/composerIcon.png'},{'revision':'6c67a688686d129a12bf1fe07c873499','url':'/genshinMusic/manifestData/help-composer.png'},{'revision':'212cec943fe59d085b413590309601af','url':'/genshinMusic/manifestData/main.png'},{'revision':'9848a07edc2ef69c9261c0c410400001','url':'/genshinMusic/manifestData/main.webp'},{'revision':'bf54c056ec9d3244f317aac5c9ed7dd7','url':'/genshinMusic/manifestData/player.webp'},{'revision':'14dbab1fca99e153a1f178b6797252d6','url':'/genshinMusic/manifestData/zenkeyboard.webp'},{'revision':'61c27d2cd39a713f7829422c3d9edcc7','url':'/genshinMusic/robots.txt'},{'revision':'5dd3c7438c24c9f991201846e02e76e1','url':'/genshinMusic/updates.json'}].filter(function(e){return!(e.url.includes(".mp3")||e.url.includes(".md")||e.url.includes(".json")||e.url.includes("media")||e.url.includes("manifestData")||e.url.includes("service-worker")||e.url.includes(".bin"))}).map(function(e){return e.revision&&e.url.includes(e.revision)&&(e.revision=null),e})),l||(n.updateDetails({prefix:"",suffix:"",precache:u,runtime:h}),console.log("registering routes"),registerRoute(function(e){var t=e.url;try{if(forbiddenCachedItems(new URL(t)))return!1}catch(e){console.error("Error caching",e)}return!0},new class extends Strategy_Strategy{constructor(e={}){super(e),this.plugins.some(e=>"cacheWillUpdate"in e)||this.plugins.unshift(a),this._networkTimeoutSeconds=e.networkTimeoutSeconds||0}async _handle(e,t){let r;let n=[],a=[];if(this._networkTimeoutSeconds){let{id:o,promise:i}=this._getTimeoutPromise({request:e,logs:n,handler:t});r=o,a.push(i)}let o=this._getNetworkPromise({timeoutId:r,request:e,logs:n,handler:t});a.push(o);let i=await t.waitUntil((async()=>await t.waitUntil(Promise.race(a))||await o)());if(!i)throw new WorkboxError_WorkboxError("no-response",{url:e.url});return i}_getTimeoutPromise({request:e,logs:t,handler:r}){let n;let a=new Promise(t=>{let onNetworkTimeout=async()=>{t(await r.cacheMatch(e))};n=setTimeout(onNetworkTimeout,1e3*this._networkTimeoutSeconds)});return{promise:a,id:n}}async _getNetworkPromise({timeoutId:e,request:t,logs:r,handler:n}){let a,o;try{o=await n.fetchAndCachePut(t)}catch(e){e instanceof Error&&(a=e)}return e&&clearTimeout(e),(a||!o)&&(o=await n.cacheMatch(t)),o}}({cacheName:h})),registerRoute(function(e){var t=e.url;try{if(forbiddenCachedItems(new URL(t)))return!1;if(t.pathname.endsWith(".mp3")||t.pathname.endsWith(".wav"))return!0}catch(e){console.error("Error caching",e)}return!1},new class extends Strategy_Strategy{async _handle(e,t){let r,n=await t.cacheMatch(e);if(!n)try{n=await t.fetchAndCachePut(e)}catch(e){e instanceof Error&&(r=e)}if(!n)throw new WorkboxError_WorkboxError("no-response",{url:e.url,error:r});return n}}({cacheName:h}))),self.addEventListener("message",function(e){e.data&&"SKIP_WAITING"===e.data.type&&(console.log("[ServiceWorker] skip waiting"),self.skipWaiting())}),self.addEventListener("install",(o=_async_to_generator(function(e){var t,r;return __generator(this,function(e){switch(e.label){case 0:return[4,caches.keys()];case 1:if(!(t=e.sent()).length||!(r=t.filter(function(e){return e.includes(s)})).length)return[2,console.log("Fresh install")];if(0!==r.filter(function(e){return e.startsWith("".concat(3))}).length)return[3,4];return console.log("Major version change, skipping waiting and refreshing all tabs"),[4,self.skipWaiting()];case 2:return e.sent(),[4,self.clients.claim()];case 3:e.sent(),self.clients.matchAll({type:"window"}).then(function(e){e.forEach(function(e){e.navigate(e.url)})}),e.label=4;case 4:return[2]}})}),function(e){return o.apply(this,arguments)})),self.addEventListener("activate",function(e){var t;console.log("[ServiceWorker] Activate"),e.waitUntil(caches.keys().then((t=_async_to_generator(function(e){var t;return __generator(this,function(r){switch(r.label){case 0:return[4,Promise.all(e.map(function(e){return s?(console.log('Verifying cache "'.concat(e,'"')),e.includes(s))?e.includes("precache")?e!==u?(console.log('[ServiceWorker] Removing old precache: "'.concat(e,'"')),caches.delete(e)):Promise.resolve():e.includes("runtime")?e!==h?(console.log('[ServiceWorker] Removing old runtime cache: "'.concat(e,'"')),caches.delete(e)):Promise.resolve():(console.log('[ServiceWorker] Removing old unknown cache: "'.concat(e,'"')),caches.delete(e)):e.includes("workbox")?(console.log('[ServiceWorker] Removing old workbox cache: "'.concat(e,'"')),caches.delete(e)):Promise.resolve():console.error("APP_NAME is not defined")}))];case 1:return console.log("[ServiceWorker] Finished removing old caches",t=r.sent()),[2,t]}})}),function(e){return t.apply(this,arguments)}))),self.clients.claim()})}()}(); \ No newline at end of file +!function(){var e={454:function(e,t,r){"use strict";var n,a;e.exports=(null==(n=r.g.process)?void 0:n.env)&&"object"==typeof(null==(a=r.g.process)?void 0:a.env)?r.g.process:r(663)},663:function(e){!function(){var t={229:function(e){var t,r,n,a=e.exports={};function defaultSetTimout(){throw Error("setTimeout has not been defined")}function defaultClearTimeout(){throw Error("clearTimeout has not been defined")}function runTimeout(e){if(t===setTimeout)return setTimeout(e,0);if((t===defaultSetTimout||!t)&&setTimeout)return t=setTimeout,setTimeout(e,0);try{return t(e,0)}catch(r){try{return t.call(null,e,0)}catch(r){return t.call(this,e,0)}}}!function(){try{t="function"==typeof setTimeout?setTimeout:defaultSetTimout}catch(e){t=defaultSetTimout}try{r="function"==typeof clearTimeout?clearTimeout:defaultClearTimeout}catch(e){r=defaultClearTimeout}}();var o=[],i=!1,s=-1;function cleanUpNextTick(){i&&n&&(i=!1,n.length?o=n.concat(o):s=-1,o.length&&drainQueue())}function drainQueue(){if(!i){var e=runTimeout(cleanUpNextTick);i=!0;for(var t=o.length;t;){for(n=o,o=[];++s1)for(var r=1;r0&&a[a.length-1])&&(6===s[0]||2===s[0])){i=0;continue}if(3===s[0]&&(!a||s[1]>a[0]&&s[1]{let r=e;return t.length>0&&(r+=` :: ${JSON.stringify(t)}`),r};let WorkboxError_WorkboxError=class WorkboxError_WorkboxError extends Error{constructor(e,t){let r=messageGenerator(e,t);super(r),this.name=e,this.details=t}};let t=new Set,r={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!=typeof registration?registration.scope:""},_createCacheName=e=>[r.prefix,e,r.suffix].filter(e=>e&&e.length>0).join("-"),eachCacheNameDetail=e=>{for(let t of Object.keys(r))e(t)},n={updateDetails:e=>{eachCacheNameDetail(t=>{"string"==typeof e[t]&&(r[t]=e[t])})},getGoogleAnalyticsName:e=>e||_createCacheName(r.googleAnalytics),getPrecacheName:e=>e||_createCacheName(r.precache),getPrefix:()=>r.prefix,getRuntimeName:e=>e||_createCacheName(r.runtime),getSuffix:()=>r.suffix};function stripParams(e,t){let r=new URL(e);for(let e of t)r.searchParams.delete(e);return r.href}async function cacheMatchIgnoreParams(e,t,r,n){let a=stripParams(t.url,r);if(t.url===a)return e.match(t,n);let o=Object.assign(Object.assign({},n),{ignoreSearch:!0}),i=await e.keys(t,o);for(let t of i){let o=stripParams(t.url,r);if(a===o)return e.match(t,n)}}let Deferred=class Deferred{constructor(){this.promise=new Promise((e,t)=>{this.resolve=e,this.reject=t})}};async function executeQuotaErrorCallbacks(){for(let e of t)await e()}let getFriendlyURL=e=>{let t=new URL(String(e),location.href);return t.href.replace(RegExp(`^${location.origin}`),"")};__webpack_require__(80);let normalizeHandler=e=>e&&"object"==typeof e?e:{handle:e};let Route_Route=class Route_Route{constructor(e,t,r="GET"){this.handler=normalizeHandler(t),this.match=e,this.method=r}setCatchHandler(e){this.catchHandler=normalizeHandler(e)}};let RegExpRoute=class RegExpRoute extends Route_Route{constructor(e,t,r){super(({url:t})=>{let r=e.exec(t.href);if(r&&(t.origin===location.origin||0===r.index))return r.slice(1)},t,r)}};let Router=class Router{constructor(){this._routes=new Map,this._defaultHandlerMap=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener("fetch",e=>{let{request:t}=e,r=this.handleRequest({request:t,event:e});r&&e.respondWith(r)})}addCacheListener(){self.addEventListener("message",e=>{if(e.data&&"CACHE_URLS"===e.data.type){let{payload:t}=e.data,r=Promise.all(t.urlsToCache.map(t=>{"string"==typeof t&&(t=[t]);let r=new Request(...t);return this.handleRequest({request:r,event:e})}));e.waitUntil(r),e.ports&&e.ports[0]&&r.then(()=>e.ports[0].postMessage(!0))}})}handleRequest({request:e,event:t}){let r;let n=new URL(e.url,location.href);if(!n.protocol.startsWith("http"))return;let a=n.origin===location.origin,{params:o,route:i}=this.findMatchingRoute({event:t,request:e,sameOrigin:a,url:n}),s=i&&i.handler,c=e.method;if(!s&&this._defaultHandlerMap.has(c)&&(s=this._defaultHandlerMap.get(c)),!s)return;try{r=s.handle({url:n,request:e,event:t,params:o})}catch(e){r=Promise.reject(e)}let l=i&&i.catchHandler;return r instanceof Promise&&(this._catchHandler||l)&&(r=r.catch(async r=>{if(l)try{return await l.handle({url:n,request:e,event:t,params:o})}catch(e){e instanceof Error&&(r=e)}if(this._catchHandler)return this._catchHandler.handle({url:n,request:e,event:t});throw r})),r}findMatchingRoute({url:e,sameOrigin:t,request:r,event:n}){let a=this._routes.get(r.method)||[];for(let o of a){let a;let i=o.match({url:e,sameOrigin:t,request:r,event:n});if(i)return Array.isArray(a=i)&&0===a.length?a=void 0:i.constructor===Object&&0===Object.keys(i).length?a=void 0:"boolean"==typeof i&&(a=void 0),{route:o,params:a}}return{}}setDefaultHandler(e,t="GET"){this._defaultHandlerMap.set(t,normalizeHandler(e))}setCatchHandler(e){this._catchHandler=normalizeHandler(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(e){if(!this._routes.has(e.method))throw new WorkboxError_WorkboxError("unregister-route-but-not-found-with-method",{method:e.method});let t=this._routes.get(e.method).indexOf(e);if(t>-1)this._routes.get(e.method).splice(t,1);else throw new WorkboxError_WorkboxError("unregister-route-route-not-registered")}};let getOrCreateDefaultRouter_getOrCreateDefaultRouter=()=>(e||((e=new Router).addFetchListener(),e.addCacheListener()),e);function registerRoute(e,t,r){let n;if("string"==typeof e){let a=new URL(e,location.href);n=new Route_Route(({url:e})=>e.href===a.href,t,r)}else if(e instanceof RegExp)n=new RegExpRoute(e,t,r);else if("function"==typeof e)n=new Route_Route(e,t,r);else if(e instanceof Route_Route)n=e;else throw new WorkboxError_WorkboxError("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});let a=getOrCreateDefaultRouter_getOrCreateDefaultRouter();return a.registerRoute(n),n}function toRequest(e){return"string"==typeof e?new Request(e):e}__webpack_require__(873);let StrategyHandler=class StrategyHandler{constructor(e,t){for(let r of(this._cacheKeys={},Object.assign(this,t),this.event=t.event,this._strategy=e,this._handlerDeferred=new Deferred,this._extendLifetimePromises=[],this._plugins=[...e.plugins],this._pluginStateMap=new Map,this._plugins))this._pluginStateMap.set(r,{});this.event.waitUntil(this._handlerDeferred.promise)}async fetch(e){let{event:t}=this,r=toRequest(e);if("navigate"===r.mode&&t instanceof FetchEvent&&t.preloadResponse){let e=await t.preloadResponse;if(e)return e}let n=this.hasCallback("fetchDidFail")?r.clone():null;try{for(let e of this.iterateCallbacks("requestWillFetch"))r=await e({request:r.clone(),event:t})}catch(e){if(e instanceof Error)throw new WorkboxError_WorkboxError("plugin-error-request-will-fetch",{thrownErrorMessage:e.message})}let a=r.clone();try{let e;for(let n of(e=await fetch(r,"navigate"===r.mode?void 0:this._strategy.fetchOptions),this.iterateCallbacks("fetchDidSucceed")))e=await n({event:t,request:a,response:e});return e}catch(e){throw n&&await this.runCallbacks("fetchDidFail",{error:e,event:t,originalRequest:n.clone(),request:a.clone()}),e}}async fetchAndCachePut(e){let t=await this.fetch(e),r=t.clone();return this.waitUntil(this.cachePut(e,r)),t}async cacheMatch(e){let t;let r=toRequest(e),{cacheName:n,matchOptions:a}=this._strategy,o=await this.getCacheKey(r,"read"),i=Object.assign(Object.assign({},a),{cacheName:n});for(let e of(t=await caches.match(o,i),this.iterateCallbacks("cachedResponseWillBeUsed")))t=await e({cacheName:n,matchOptions:a,cachedResponse:t,request:o,event:this.event})||void 0;return t}async cachePut(e,t){let r=toRequest(e);await new Promise(e=>setTimeout(e,0));let n=await this.getCacheKey(r,"write");if(!t)throw new WorkboxError_WorkboxError("cache-put-with-no-response",{url:getFriendlyURL(n.url)});let a=await this._ensureResponseSafeToCache(t);if(!a)return!1;let{cacheName:o,matchOptions:i}=this._strategy,s=await self.caches.open(o),c=this.hasCallback("cacheDidUpdate"),l=c?await cacheMatchIgnoreParams(s,n.clone(),["__WB_REVISION__"],i):null;try{await s.put(n,c?a.clone():a)}catch(e){if(e instanceof Error)throw"QuotaExceededError"===e.name&&await executeQuotaErrorCallbacks(),e}for(let e of this.iterateCallbacks("cacheDidUpdate"))await e({cacheName:o,oldResponse:l,newResponse:a.clone(),request:n,event:this.event});return!0}async getCacheKey(e,t){let r=`${e.url} | ${t}`;if(!this._cacheKeys[r]){let n=e;for(let e of this.iterateCallbacks("cacheKeyWillBeUsed"))n=toRequest(await e({mode:t,request:n,event:this.event,params:this.params}));this._cacheKeys[r]=n}return this._cacheKeys[r]}hasCallback(e){for(let t of this._strategy.plugins)if(e in t)return!0;return!1}async runCallbacks(e,t){for(let r of this.iterateCallbacks(e))await r(t)}*iterateCallbacks(e){for(let t of this._strategy.plugins)if("function"==typeof t[e]){let r=this._pluginStateMap.get(t),statefulCallback=n=>{let a=Object.assign(Object.assign({},n),{state:r});return t[e](a)};yield statefulCallback}}waitUntil(e){return this._extendLifetimePromises.push(e),e}async doneWaiting(){let e;for(;e=this._extendLifetimePromises.shift();)await e}destroy(){this._handlerDeferred.resolve(null)}async _ensureResponseSafeToCache(e){let t=e,r=!1;for(let e of this.iterateCallbacks("cacheWillUpdate"))if(t=await e({request:this.request,response:t,event:this.event})||void 0,r=!0,!t)break;return!r&&t&&200!==t.status&&(t=void 0),t}};let Strategy_Strategy=class Strategy_Strategy{constructor(e={}){this.cacheName=n.getRuntimeName(e.cacheName),this.plugins=e.plugins||[],this.fetchOptions=e.fetchOptions,this.matchOptions=e.matchOptions}handle(e){let[t]=this.handleAll(e);return t}handleAll(e){e instanceof FetchEvent&&(e={event:e,request:e.request});let t=e.event,r="string"==typeof e.request?new Request(e.request):e.request,n="params"in e?e.params:void 0,a=new StrategyHandler(this,{event:t,request:r,params:n}),o=this._getResponse(a,r,t),i=this._awaitComplete(o,a,r,t);return[o,i]}async _getResponse(e,t,r){let n;await e.runCallbacks("handlerWillStart",{event:r,request:t});try{if(!(n=await this._handle(t,e))||"error"===n.type)throw new WorkboxError_WorkboxError("no-response",{url:t.url})}catch(a){if(a instanceof Error){for(let o of e.iterateCallbacks("handlerDidError"))if(n=await o({error:a,event:r,request:t}))break}if(n);else throw a}for(let a of e.iterateCallbacks("handlerWillRespond"))n=await a({event:r,request:t,response:n});return n}async _awaitComplete(e,t,r,n){let a,o;try{a=await e}catch(e){}try{await t.runCallbacks("handlerDidRespond",{event:n,request:r,response:a}),await t.doneWaiting()}catch(e){e instanceof Error&&(o=e)}if(await t.runCallbacks("handlerDidComplete",{event:n,request:r,response:a,error:o}),t.destroy(),o)throw o}};let a={cacheWillUpdate:async({response:e})=>200===e.status||0===e.status?e:null};var o,i=__webpack_require__(454),s=i.env.NEXT_PUBLIC_APP_NAME,c="".concat(s,"-").concat(i.env.NEXT_PUBLIC_SW_VERSION),l="true"===i.env.NEXT_PUBLIC_IS_TAURI,u="".concat(3,"-precache-").concat(c),h="".concat(3,"-runtime-").concat(c);function forbiddenCachedItems(e){if(e.pathname.includes("service-worker")||e.pathname.includes("manifestData")||e.pathname.endsWith(".json"))return!0}console.log('CACHE NAME: "'.concat(c,'"')),self.addEventListener("activate",()=>self.clients.claim()),console.log("Precached files:",[{'revision':'b65804a2a23076c8a0c024abd6b9e059','url':'/_next/static/723DWep6V8WMwBc5vLdYa/_buildManifest.js'},{'revision':'b6652df95db52feb4daf4eca35380933','url':'/_next/static/723DWep6V8WMwBc5vLdYa/_ssgManifest.js'},{'revision':'227d01df3aa4651d','url':'/_next/static/chunks/1160-227d01df3aa4651d.js'},{'revision':'a910e344a956a7e3','url':'/_next/static/chunks/1240-a910e344a956a7e3.js'},{'revision':'dbfad4630a5a3445','url':'/_next/static/chunks/2dc05096.dbfad4630a5a3445.js'},{'revision':'3c430b895be8c5fd','url':'/_next/static/chunks/3302-3c430b895be8c5fd.js'},{'revision':'3a924c2198068ac0','url':'/_next/static/chunks/3778-3a924c2198068ac0.js'},{'revision':'48016a9b751555be','url':'/_next/static/chunks/3a2b0ac0.48016a9b751555be.js'},{'revision':'2207d7ee654c67b6','url':'/_next/static/chunks/4577d2ec-2207d7ee654c67b6.js'},{'revision':'45d9d4a8eb717fa9','url':'/_next/static/chunks/5086.45d9d4a8eb717fa9.js'},{'revision':'4965bccea1a83919','url':'/_next/static/chunks/5744.4965bccea1a83919.js'},{'revision':'faa16dab6f1984a8','url':'/_next/static/chunks/5752-faa16dab6f1984a8.js'},{'revision':'605d9fff8acfcf42','url':'/_next/static/chunks/6543-605d9fff8acfcf42.js'},{'revision':'59e676e500d13414','url':'/_next/static/chunks/69480c19-59e676e500d13414.js'},{'revision':'e5e399dfd861fb40','url':'/_next/static/chunks/72acface.e5e399dfd861fb40.js'},{'revision':'9775bd93d113a7dc','url':'/_next/static/chunks/7831-9775bd93d113a7dc.js'},{'revision':'147e1839331d6680','url':'/_next/static/chunks/8427-147e1839331d6680.js'},{'revision':'d7413f2b9f658703','url':'/_next/static/chunks/85d7bc83-d7413f2b9f658703.js'},{'revision':'19b8c2b4c8fc4d1a','url':'/_next/static/chunks/9569-19b8c2b4c8fc4d1a.js'},{'revision':'9ff65f4f7ff6f864','url':'/_next/static/chunks/ab5c09eb.9ff65f4f7ff6f864.js'},{'revision':'33d4ed17f4319fab','url':'/_next/static/chunks/b1bb7d45.33d4ed17f4319fab.js'},{'revision':'9ae3c879deaea3d8','url':'/_next/static/chunks/e21e5bbe-9ae3c879deaea3d8.js'},{'revision':'fa51f609d3e75584','url':'/_next/static/chunks/ebc70433-fa51f609d3e75584.js'},{'revision':'ca706bf673a13738','url':'/_next/static/chunks/framework-ca706bf673a13738.js'},{'revision':'c021438e074b4205','url':'/_next/static/chunks/main-c021438e074b4205.js'},{'revision':'b6c22f6da8d6a041','url':'/_next/static/chunks/pages/404-b6c22f6da8d6a041.js'},{'revision':'ee6ef38d67f072d2','url':'/_next/static/chunks/pages/_app-ee6ef38d67f072d2.js'},{'revision':'2455c9d048a4b9a2','url':'/_next/static/chunks/pages/_error-2455c9d048a4b9a2.js'},{'revision':'185fc6da700c5a19','url':'/_next/static/chunks/pages/backup-185fc6da700c5a19.js'},{'revision':'be3a9ebb48aeb47f','url':'/_next/static/chunks/pages/blog-be3a9ebb48aeb47f.js'},{'revision':'4acb2c5ac1d3b7e3','url':'/_next/static/chunks/pages/blog/posts/connect-midi-device-4acb2c5ac1d3b7e3.js'},{'revision':'17d55fab9969f314','url':'/_next/static/chunks/pages/blog/posts/how-to-use-composer-17d55fab9969f314.js'},{'revision':'882eada11478795b','url':'/_next/static/chunks/pages/blog/posts/how-to-use-player-882eada11478795b.js'},{'revision':'92c924218d854224','url':'/_next/static/chunks/pages/blog/posts/how-to-use-vsrg-composer-92c924218d854224.js'},{'revision':'844a9925e7051e49','url':'/_next/static/chunks/pages/blog/posts/midi-transpose-844a9925e7051e49.js'},{'revision':'cf65e6de59f587f9','url':'/_next/static/chunks/pages/blog/posts/video-audio-transpose-cf65e6de59f587f9.js'},{'revision':'dea3c7d7bbb58a7d','url':'/_next/static/chunks/pages/changelog-dea3c7d7bbb58a7d.js'},{'revision':'8add748bbf8f5f28','url':'/_next/static/chunks/pages/composer-8add748bbf8f5f28.js'},{'revision':'cb58eb92409fc40a','url':'/_next/static/chunks/pages/delete-cache-cb58eb92409fc40a.js'},{'revision':'d23e7e2d683f414d','url':'/_next/static/chunks/pages/donate-d23e7e2d683f414d.js'},{'revision':'82069e10f7f7acb4','url':'/_next/static/chunks/pages/error-82069e10f7f7acb4.js'},{'revision':'d02889852b4f77a7','url':'/_next/static/chunks/pages/index-d02889852b4f77a7.js'},{'revision':'6cd6ce7399eea91f','url':'/_next/static/chunks/pages/keybinds-6cd6ce7399eea91f.js'},{'revision':'b375058512131337','url':'/_next/static/chunks/pages/partners-b375058512131337.js'},{'revision':'028dd911d277a61c','url':'/_next/static/chunks/pages/player-028dd911d277a61c.js'},{'revision':'e22482bb0ada75fe','url':'/_next/static/chunks/pages/privacy-e22482bb0ada75fe.js'},{'revision':'6b4b2901fc4f7db0','url':'/_next/static/chunks/pages/sheet-visualizer-6b4b2901fc4f7db0.js'},{'revision':'82d648e8fa201147','url':'/_next/static/chunks/pages/theme-82d648e8fa201147.js'},{'revision':'96df0fc271b26b85','url':'/_next/static/chunks/pages/transfer-96df0fc271b26b85.js'},{'revision':'014d31ab4dd7a999','url':'/_next/static/chunks/pages/uma-mode-014d31ab4dd7a999.js'},{'revision':'d212ad5c221b14ce','url':'/_next/static/chunks/pages/vsrg-composer-d212ad5c221b14ce.js'},{'revision':'2b1106b97586e51a','url':'/_next/static/chunks/pages/vsrg-player-2b1106b97586e51a.js'},{'revision':'f2f0aee0b6e826af','url':'/_next/static/chunks/pages/zen-keyboard-f2f0aee0b6e826af.js'},{'revision':'837c0df77fd5009c9e46d446188ecfd0','url':'/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js'},{'revision':'e1aff18e7b94282c','url':'/_next/static/chunks/webpack-e1aff18e7b94282c.js'},{'revision':'227f2ac29f675782','url':'/_next/static/css/227f2ac29f675782.css'},{'revision':'3b39d44eec6f01be','url':'/_next/static/css/3b39d44eec6f01be.css'},{'revision':'3b4312c579b5068d','url':'/_next/static/css/3b4312c579b5068d.css'},{'revision':'47b46a69f6cc55c6','url':'/_next/static/css/47b46a69f6cc55c6.css'},{'revision':'4861c8de6b3413fc','url':'/_next/static/css/4861c8de6b3413fc.css'},{'revision':'5756609caf1ad4a4','url':'/_next/static/css/5756609caf1ad4a4.css'},{'revision':'770712bacc70f896','url':'/_next/static/css/770712bacc70f896.css'},{'revision':'875a29864bdecc0d','url':'/_next/static/css/875a29864bdecc0d.css'},{'revision':'9f08e63442acf37d','url':'/_next/static/css/9f08e63442acf37d.css'},{'revision':'a9be0aa642f73a4b','url':'/_next/static/css/a9be0aa642f73a4b.css'},{'revision':'add69f5770f6788e','url':'/_next/static/css/add69f5770f6788e.css'},{'revision':'b193e7857b0c36f9','url':'/_next/static/css/b193e7857b0c36f9.css'},{'revision':'bec52517dba76a23','url':'/_next/static/css/bec52517dba76a23.css'},{'revision':'c18c554d7a5b1241','url':'/_next/static/css/c18c554d7a5b1241.css'},{'revision':'d7c29bc57861e46e','url':'/_next/static/css/d7c29bc57861e46e.css'},{'revision':'e065fcfba24b282b','url':'/_next/static/css/e065fcfba24b282b.css'},{'revision':'f1cf20787c70b484','url':'/_next/static/css/f1cf20787c70b484.css'},{'revision':'ff4fd350a6266d54','url':'/_next/static/css/ff4fd350a6266d54.css'},{'revision':'37b99d16','url':'/_next/static/media/BonoboBold.37b99d16.ttf'},{'revision':'ed9965d379230c2954d2f4b5e6c935e8','url':'/_next/static/media/Desert_Theme.c1f04f20.jpg'},{'revision':'8f3308316b267718521613d00c4e990f','url':'/_next/static/media/Legacy_Bg_Theme.88ff5918.png'},{'revision':'71cda29cf7f5185657e3ce5deda6ecd7','url':'/_next/static/media/Liyue_Theme.c96c416c.jpg'},{'revision':'6e2663ab47dccf54d1b0b31c657058f0','url':'/_next/static/media/Rainy_Theme.16d15843.png'},{'revision':'1a41fe4a','url':'/_next/static/media/RobotoSerif-Medium.1a41fe4a.ttf'},{'revision':'587261a63730aeb88abf28abb8dd759f','url':'/_next/static/media/Snow_Theme.24673ba9.gif'},{'revision':'ba6a5ca14065522fdbac49a670d57cc6','url':'/_next/static/media/buymeacoffee.36238f63.svg'},{'revision':'5132bddcb9ce0828888c91a08f35a2ec','url':'/_next/static/media/kofi.bd96742e.png'},{'revision':'8461373793dc7967c3bbee79757ed85c','url':'/_next/static/media/paypalme.20b31d9a.png'},{'revision':'1b8efd914ffd6543d91066228c75016b','url':'/_next/static/media/rotate.135a6aec.svg'},{'revision':'cd224bc15d8695ca1d598c66d49f5bba','url':'/_next/static/media/sky-musician-network.c9e85a08.jpg'},{'revision':'0cb87429103ebddfb9a8b092c75398b9','url':'/_next/static/media/windsong-db.be5c32c5.jpg'},{'revision':'bc90e8d4fede0ecb146feda1bab149d1','url':'/assets/audio-midi-model.json'},{'revision':'d6fc1f028c0a6f94abe000906be37060','url':'/assets/audio/Aurora/0.mp3'},{'revision':'5b81060e34f7712c18369126927a6238','url':'/assets/audio/Aurora/1.mp3'},{'revision':'8c9689ac74973322bffb99e8096b9fbc','url':'/assets/audio/Aurora/10.mp3'},{'revision':'824791444fb1f0425035c76566cb51e0','url':'/assets/audio/Aurora/11.mp3'},{'revision':'b5d70896c0e53ee6b7773925341f5e47','url':'/assets/audio/Aurora/12.mp3'},{'revision':'f45bab66324c7f8bd49cc264186a5438','url':'/assets/audio/Aurora/13.mp3'},{'revision':'684d88b95831ddf5596f48f734cd1cdf','url':'/assets/audio/Aurora/14.mp3'},{'revision':'dc52083eacf9f11561974f64c81ec640','url':'/assets/audio/Aurora/2.mp3'},{'revision':'34f8b83e2d3051710c5b6a6266a1a998','url':'/assets/audio/Aurora/3.mp3'},{'revision':'8e730609d21ab750b3a8e69704b2af51','url':'/assets/audio/Aurora/4.mp3'},{'revision':'8c54cb1a9c0864711839539d1742e3d9','url':'/assets/audio/Aurora/5.mp3'},{'revision':'de8bb0c3cc8df6f2693bd90c8981d750','url':'/assets/audio/Aurora/6.mp3'},{'revision':'69e76e6fe22a6f8eccc245bfd26f260f','url':'/assets/audio/Aurora/7.mp3'},{'revision':'f0c095094f7bddd797f97aed1962dc4f','url':'/assets/audio/Aurora/8.mp3'},{'revision':'ff0d08f3678cbecf814ad088bca55c0f','url':'/assets/audio/Aurora/9.mp3'},{'revision':'c406c6e6550df8882fd752d27edf1bae','url':'/assets/audio/Bells/0.mp3'},{'revision':'15e0ea86719017954f8762d18d227e6b','url':'/assets/audio/Bells/1.mp3'},{'revision':'606a3c20230b372d314a177d23451cf5','url':'/assets/audio/Bells/2.mp3'},{'revision':'e89e16e88e17bd747fda34df08882ad5','url':'/assets/audio/Bells/3.mp3'},{'revision':'d712c045514e0bbba054e50728a1c26c','url':'/assets/audio/Bells/4.mp3'},{'revision':'6ec9fe6ceaa2e101e64c83d28b5abdae','url':'/assets/audio/Bells/5.mp3'},{'revision':'77d319cf0137805270334bf15d2f6d2f','url':'/assets/audio/Bells/6.mp3'},{'revision':'bed2984dc9157b53ea2d06d16d1466ce','url':'/assets/audio/Bells/7.mp3'},{'revision':'8552c8d2faa0a983e2dc4c6e2648e138','url':'/assets/audio/Contrabass/0.mp3'},{'revision':'722614eed664e9b8d2ca0a390097f51f','url':'/assets/audio/Contrabass/1.mp3'},{'revision':'efe5d4bb49c34f06c4504863071b7517','url':'/assets/audio/Contrabass/10.mp3'},{'revision':'b243eb0a068828805df80e1a5c2aea6c','url':'/assets/audio/Contrabass/11.mp3'},{'revision':'324691e6998641662055412e1fc408a0','url':'/assets/audio/Contrabass/12.mp3'},{'revision':'f255ee612c1a997e5fd6fef441f33c9f','url':'/assets/audio/Contrabass/13.mp3'},{'revision':'02024bf8a1ec85fa62b3615176971d16','url':'/assets/audio/Contrabass/14.mp3'},{'revision':'629711ac08f287ff8b0d5dd0c4e55439','url':'/assets/audio/Contrabass/2.mp3'},{'revision':'81fa1a7c8555b83892be966dbbd97e98','url':'/assets/audio/Contrabass/3.mp3'},{'revision':'743e15ea725e4120d054db6b69aa15ae','url':'/assets/audio/Contrabass/4.mp3'},{'revision':'46ba1f8707d6aa9fa56be8f82146b5c9','url':'/assets/audio/Contrabass/5.mp3'},{'revision':'189e846396cdf7f4724a98e71f0cc9c0','url':'/assets/audio/Contrabass/6.mp3'},{'revision':'490d37df11662be74b7512eff16eb287','url':'/assets/audio/Contrabass/7.mp3'},{'revision':'364ed198e299ddb25221073efa236dea','url':'/assets/audio/Contrabass/8.mp3'},{'revision':'1b50740b7c3ba2d9c5d1e3b17a051c9b','url':'/assets/audio/Contrabass/9.mp3'},{'revision':'394084c049d8d4bc1e2aaff8a036ef09','url':'/assets/audio/Drum/0.mp3'},{'revision':'236a984762d0ffd410d53dea955aeb56','url':'/assets/audio/Drum/1.mp3'},{'revision':'9ad7cb1c010d2405e5a9e1b38790fbad','url':'/assets/audio/Drum/2.mp3'},{'revision':'32d282555a61cd56ed2221c5369470fb','url':'/assets/audio/Drum/3.mp3'},{'revision':'6440bc55c9b2336e08f1ca2252b7d0aa','url':'/assets/audio/Drum/4.mp3'},{'revision':'990c71475136235758d33fa96d7e3318','url':'/assets/audio/Drum/5.mp3'},{'revision':'221607e37a7ea1875765f51a5e3cd307','url':'/assets/audio/Drum/6.mp3'},{'revision':'e2950c5161d0e08a1e213ec0d88c502a','url':'/assets/audio/Drum/7.mp3'},{'revision':'bd97a079f2465d14fc2c21eeda33dce7','url':'/assets/audio/DunDun/0.mp3'},{'revision':'805941ca7074d34e93d3e0883ff3c09d','url':'/assets/audio/DunDun/1.mp3'},{'revision':'98316ae98a04a436d4d39fe66e1d4ef5','url':'/assets/audio/DunDun/2.mp3'},{'revision':'45c85d53ed1b1448f95e67251ac911f0','url':'/assets/audio/DunDun/3.mp3'},{'revision':'3542307ec319ee550325a05d0f8dc7ae','url':'/assets/audio/DunDun/4.mp3'},{'revision':'2c4e10af10b2253c54dc608998087ac2','url':'/assets/audio/DunDun/5.mp3'},{'revision':'0ddeb1a5c401374866b714efcce66c73','url':'/assets/audio/DunDun/6.mp3'},{'revision':'956a892ba10e38e7c7fc58e3ea323243','url':'/assets/audio/DunDun/7.mp3'},{'revision':'26a3b850279baaa99f51884e6adc4d97','url':'/assets/audio/Flute/0.mp3'},{'revision':'623b20056879b3d887a347ce1d1fc524','url':'/assets/audio/Flute/1.mp3'},{'revision':'00fc965b76fdad5594abf5e266686019','url':'/assets/audio/Flute/10.mp3'},{'revision':'e7c9a3203307599fa98c7ef1c8423e78','url':'/assets/audio/Flute/11.mp3'},{'revision':'a9285d3c09c6183d629cc399305ff58e','url':'/assets/audio/Flute/12.mp3'},{'revision':'a5a19657b91eefaf4bacfbfd2eba2578','url':'/assets/audio/Flute/13.mp3'},{'revision':'9be8189f9c3c4c474ffbc527c5ddd301','url':'/assets/audio/Flute/14.mp3'},{'revision':'30dfb6820ac54c78bf4246c53b81c0c4','url':'/assets/audio/Flute/2.mp3'},{'revision':'853b77b82825cbb6f80a120b50cbc5e6','url':'/assets/audio/Flute/3.mp3'},{'revision':'bf8797d600639e92a4c43f20f32d32c0','url':'/assets/audio/Flute/4.mp3'},{'revision':'98b888cb1ca4d3c91b11d4b55f7cf864','url':'/assets/audio/Flute/5.mp3'},{'revision':'a8a63b100c7f7cf3547c21093d4dc6e7','url':'/assets/audio/Flute/6.mp3'},{'revision':'3c230d55e35c8367769f5678c0cfc51c','url':'/assets/audio/Flute/7.mp3'},{'revision':'a7765ff838347f41c1a545fb3d40bc24','url':'/assets/audio/Flute/8.mp3'},{'revision':'485a4f0d28835632502c38b005bb2393','url':'/assets/audio/Flute/9.mp3'},{'revision':'36a2bd90cb0196df5c93e64b5c73d1eb','url':'/assets/audio/Guitar/0.mp3'},{'revision':'25052c09ec0c8368e712dbcb432a5b1d','url':'/assets/audio/Guitar/1.mp3'},{'revision':'ecd04381de2d8f523227c64637cdd842','url':'/assets/audio/Guitar/10.mp3'},{'revision':'e4d272c2fd9377b0891463e1b111054c','url':'/assets/audio/Guitar/11.mp3'},{'revision':'718e41f885d4dad506bf32bf1b00f2eb','url':'/assets/audio/Guitar/12.mp3'},{'revision':'5a9e4d5294f4141670360fe2118f66b1','url':'/assets/audio/Guitar/13.mp3'},{'revision':'82c7e74a18c5f7449ebe8468b6bdc8d2','url':'/assets/audio/Guitar/14.mp3'},{'revision':'51c5a04e8d8c8ef6f6217ab5d145aabf','url':'/assets/audio/Guitar/2.mp3'},{'revision':'ace2fb3f4f34ffdb9eee6386a14c86fa','url':'/assets/audio/Guitar/3.mp3'},{'revision':'2ce114e864d7b6017c226906b4b4051f','url':'/assets/audio/Guitar/4.mp3'},{'revision':'1a1491ad2e705a7247fefdc5881b12b2','url':'/assets/audio/Guitar/5.mp3'},{'revision':'e936e3d8eb56587d0921e0713d848f3b','url':'/assets/audio/Guitar/6.mp3'},{'revision':'1f4d9c7f872f0b800cc72a1c3033ea21','url':'/assets/audio/Guitar/7.mp3'},{'revision':'e4e857e1106fe07e9e814292f5cfab42','url':'/assets/audio/Guitar/8.mp3'},{'revision':'4981178337af6c492bc2fb59d0dfb679','url':'/assets/audio/Guitar/9.mp3'},{'revision':'53932d2ce2b23cc9c7656c9095e86576','url':'/assets/audio/HandPan/0.mp3'},{'revision':'6d58e8fd7b0a63ddbfa3f1dc5386346e','url':'/assets/audio/HandPan/1.mp3'},{'revision':'b652caa603d16b2819b5763ad4422778','url':'/assets/audio/HandPan/2.mp3'},{'revision':'683ceed827bb041a967ccd5693d5035f','url':'/assets/audio/HandPan/3.mp3'},{'revision':'f15e36ee54cb54823495503d621d44df','url':'/assets/audio/HandPan/4.mp3'},{'revision':'55269b05d4558eabe4a999143d1c5d49','url':'/assets/audio/HandPan/5.mp3'},{'revision':'d456d64bb89f04fb6e5125791fca3512','url':'/assets/audio/HandPan/6.mp3'},{'revision':'77c231d9a595de6e6792ef80587e8fb1','url':'/assets/audio/HandPan/7.mp3'},{'revision':'131734a948ff079fb9da55557342b56d','url':'/assets/audio/Harp/0.mp3'},{'revision':'2b665aadb8dbfc39734d11b460b83d37','url':'/assets/audio/Harp/1.mp3'},{'revision':'268369258f6f30d72f2a0849e8d71fa0','url':'/assets/audio/Harp/10.mp3'},{'revision':'81fc73de71a3538025ba04e663d86a68','url':'/assets/audio/Harp/11.mp3'},{'revision':'035488f1c6481c82373e6ff869bf7871','url':'/assets/audio/Harp/12.mp3'},{'revision':'e7e3924eb5134d0dc81a1cf424b5ca04','url':'/assets/audio/Harp/13.mp3'},{'revision':'94ee76027c7bb124d0bef7effb32a0e9','url':'/assets/audio/Harp/14.mp3'},{'revision':'d495fd0d404432cb0749564acf6b781b','url':'/assets/audio/Harp/2.mp3'},{'revision':'d997806c96f9ce1bc5802c2082d8d99d','url':'/assets/audio/Harp/3.mp3'},{'revision':'323f3e319ea507b717f6abc7636eafda','url':'/assets/audio/Harp/4.mp3'},{'revision':'f8f46511a19a203025e9d8c6bb274775','url':'/assets/audio/Harp/5.mp3'},{'revision':'b5cd26d2e87fa2273feacfb73065c567','url':'/assets/audio/Harp/6.mp3'},{'revision':'fa262cf4f6e687e8889e63262cc3cae6','url':'/assets/audio/Harp/7.mp3'},{'revision':'e091a48cc517a35cc0374f426bb542d8','url':'/assets/audio/Harp/8.mp3'},{'revision':'b330d26a7a072281f128dff3f8b6a226','url':'/assets/audio/Harp/9.mp3'},{'revision':'d33f990b5d5cd0f1969fa3fa7f954940','url':'/assets/audio/Horn/0.mp3'},{'revision':'e7d1cdf166a7ccd6d0d8882328cf7485','url':'/assets/audio/Horn/1.mp3'},{'revision':'bf9dfe22ec80ac7cac95b9a43366bde9','url':'/assets/audio/Horn/10.mp3'},{'revision':'23e23b3b785e7ac713360580d6f5e8ca','url':'/assets/audio/Horn/11.mp3'},{'revision':'3444ef79cfe6db463a2580c8c2bd305a','url':'/assets/audio/Horn/12.mp3'},{'revision':'e388a2be5bc1b7d967340d8b395e9692','url':'/assets/audio/Horn/13.mp3'},{'revision':'97e703c22bd3edc046434f4d96fa2de0','url':'/assets/audio/Horn/14.mp3'},{'revision':'5d0e4459f866f10bd2bd78b8559e082b','url':'/assets/audio/Horn/2.mp3'},{'revision':'468a6c4a085ec4ff9cdece671f669cfc','url':'/assets/audio/Horn/3.mp3'},{'revision':'fe7961c6b7bba0f15fd6e1c43a71309f','url':'/assets/audio/Horn/4.mp3'},{'revision':'0367160860d517ca89826a7a161e6364','url':'/assets/audio/Horn/5.mp3'},{'revision':'04dde93ea7134190042bef5b97a05ebf','url':'/assets/audio/Horn/6.mp3'},{'revision':'2b37d35b162e0b18ca87b8ecc952bf5d','url':'/assets/audio/Horn/7.mp3'},{'revision':'cf7c862e0f27501a221072bb2b5e877b','url':'/assets/audio/Horn/8.mp3'},{'revision':'25c314b3e74daf4115e91376b9bcfa55','url':'/assets/audio/Horn/9.mp3'},{'revision':'ed340eb0fde17af485e529938662ed87','url':'/assets/audio/Kalimba/0.mp3'},{'revision':'a80ad231296e59aa8da2dc27f5b82b2a','url':'/assets/audio/Kalimba/1.mp3'},{'revision':'b61a590092a51ebfedbe79265cfd2779','url':'/assets/audio/Kalimba/10.mp3'},{'revision':'d5174d0962d3e2b9b68592e391668086','url':'/assets/audio/Kalimba/11.mp3'},{'revision':'322d908c030fc5a7a72ffbf79671ad21','url':'/assets/audio/Kalimba/12.mp3'},{'revision':'719d33c058e4914e51240befe65792d6','url':'/assets/audio/Kalimba/13.mp3'},{'revision':'912c1433419947dbf474304befb807e4','url':'/assets/audio/Kalimba/14.mp3'},{'revision':'e308ade9ab8963d9d32f44db1511b96c','url':'/assets/audio/Kalimba/2.mp3'},{'revision':'2e4795ecab35edc0f4849d7fdf0329f8','url':'/assets/audio/Kalimba/3.mp3'},{'revision':'72ed8f2199a1872e4fd53376a2b8f6a0','url':'/assets/audio/Kalimba/4.mp3'},{'revision':'1f76a872273467bdffe9cd251147c40e','url':'/assets/audio/Kalimba/5.mp3'},{'revision':'3fe7b9238dc3d7ed4abcb31a690b309c','url':'/assets/audio/Kalimba/6.mp3'},{'revision':'c2fd08f49bf1cf80016bddd04806885f','url':'/assets/audio/Kalimba/7.mp3'},{'revision':'baaf672f93bd88b20edc14814db7a001','url':'/assets/audio/Kalimba/8.mp3'},{'revision':'869e84f6a06063ebe8706adc959b6292','url':'/assets/audio/Kalimba/9.mp3'},{'revision':'8d86ccb344ec5e9e0720fdd81251a8e6','url':'/assets/audio/LightGuitar/0.mp3'},{'revision':'6988c2855a17ddb683d933bd395d23e9','url':'/assets/audio/LightGuitar/1.mp3'},{'revision':'d9f8825876d0b69223832050b41ab9bf','url':'/assets/audio/LightGuitar/10.mp3'},{'revision':'1b906c338eaa1ce155c61ac187bee576','url':'/assets/audio/LightGuitar/11.mp3'},{'revision':'e6324f2896ce9e315a4599e8cfb5dd0b','url':'/assets/audio/LightGuitar/12.mp3'},{'revision':'97de9ed2856efde4db1c24c238cb7a65','url':'/assets/audio/LightGuitar/13.mp3'},{'revision':'ea6010c3aa333bdc600b17039f1c6483','url':'/assets/audio/LightGuitar/14.mp3'},{'revision':'224224c398ed5a8bd6aa89e8370dbce2','url':'/assets/audio/LightGuitar/2.mp3'},{'revision':'5a0cf602795f58c1cb2573cc5e9d711d','url':'/assets/audio/LightGuitar/3.mp3'},{'revision':'04bd286f98a0b3618a2d1e5350aaf8c1','url':'/assets/audio/LightGuitar/4.mp3'},{'revision':'848ec50f4e775ff54c6c4c10b886a9ac','url':'/assets/audio/LightGuitar/5.mp3'},{'revision':'6e3865e32be9f3204780cc1b0842f0a4','url':'/assets/audio/LightGuitar/6.mp3'},{'revision':'c91f21717a314934f052f51cd4e6822b','url':'/assets/audio/LightGuitar/7.mp3'},{'revision':'f0f3931df82dfce5b0e4fdfb5aaff4ed','url':'/assets/audio/LightGuitar/8.mp3'},{'revision':'1d6de5c681e7a6ab866470aeebfffc11','url':'/assets/audio/LightGuitar/9.mp3'},{'revision':'3417daf18bcf63c70c0b06f452c52308','url':'/assets/audio/Lyre/0.mp3'},{'revision':'cfc035442240515ec7e3e7a75181d585','url':'/assets/audio/Lyre/1.mp3'},{'revision':'d21dbbf01c72c6f54cff40ae4cd0fc39','url':'/assets/audio/Lyre/10.mp3'},{'revision':'01dabbedf8ddbfb15becdff5ae24fe68','url':'/assets/audio/Lyre/11.mp3'},{'revision':'b7de700386e03630c1d010208a942810','url':'/assets/audio/Lyre/12.mp3'},{'revision':'c142a28ca1f429529ca8d1907a9aca0f','url':'/assets/audio/Lyre/13.mp3'},{'revision':'093f9fa8129f99493f816e5c95a6f145','url':'/assets/audio/Lyre/14.mp3'},{'revision':'e1e76ddd5d6d93553abb72e9778aa8b3','url':'/assets/audio/Lyre/15.mp3'},{'revision':'be0081316c1891fa597aab5fa729688b','url':'/assets/audio/Lyre/16.mp3'},{'revision':'f29216e6d64cb0778d79396d4f66cba0','url':'/assets/audio/Lyre/17.mp3'},{'revision':'4e52a2ea84cb96063d3e906843b994b0','url':'/assets/audio/Lyre/18.mp3'},{'revision':'7ea822f42eeca696b6c6f5836f54b3a3','url':'/assets/audio/Lyre/19.mp3'},{'revision':'3e6f55fd191a91ba3fb710bde2109799','url':'/assets/audio/Lyre/2.mp3'},{'revision':'1447ece9690d6a0b7c5385651174c9ea','url':'/assets/audio/Lyre/20.mp3'},{'revision':'cc1d17a399edee8d6459e4ea94d663a6','url':'/assets/audio/Lyre/3.mp3'},{'revision':'0a9a1d53557037a494f13f24d5a9cd73','url':'/assets/audio/Lyre/4.mp3'},{'revision':'62d35d228342896de7d29c48966e8f0b','url':'/assets/audio/Lyre/5.mp3'},{'revision':'135de63dbc67263ada26dcaab875be03','url':'/assets/audio/Lyre/6.mp3'},{'revision':'247d2366d22fcb3239f3a7c04ec2f1cc','url':'/assets/audio/Lyre/7.mp3'},{'revision':'8abc3e7a285815e446aaa74d1aa6b783','url':'/assets/audio/Lyre/8.mp3'},{'revision':'65b95d500a0c2b76f6acfb0f053c5f5a','url':'/assets/audio/Lyre/9.mp3'},{'revision':'ecfffc3e4c56c423bd78b5342bf59f71','url':'/assets/audio/MantaOcarina/0.mp3'},{'revision':'57032325610195477bbfd7718c75cd80','url':'/assets/audio/MantaOcarina/1.mp3'},{'revision':'fd482d43bb73845068d803b9c0b7bb98','url':'/assets/audio/MantaOcarina/10.mp3'},{'revision':'ca050aa34ac980ddc44c72aa1b6b850d','url':'/assets/audio/MantaOcarina/11.mp3'},{'revision':'b48f8cfdfba1b0d56aec8d3e3ab957dd','url':'/assets/audio/MantaOcarina/12.mp3'},{'revision':'6e54da95cb8589ab81ff80beeacf1874','url':'/assets/audio/MantaOcarina/13.mp3'},{'revision':'fa509e709b2fdb8d05561ff784844dcf','url':'/assets/audio/MantaOcarina/14.mp3'},{'revision':'c97e9485a9291c56aeae5ee294a938c3','url':'/assets/audio/MantaOcarina/2.mp3'},{'revision':'b8ef1846b0c46cabb7a78c3c5d4fc3a2','url':'/assets/audio/MantaOcarina/3.mp3'},{'revision':'123d94dbb301c8f57cd0ff2219989051','url':'/assets/audio/MantaOcarina/4.mp3'},{'revision':'3be52ddf427ad1ee041e520c50e87f61','url':'/assets/audio/MantaOcarina/5.mp3'},{'revision':'1a05d33e75eb9c21f7e415aa9e2bf77d','url':'/assets/audio/MantaOcarina/6.mp3'},{'revision':'af907399339f5f8f73bfbba8f924a8e7','url':'/assets/audio/MantaOcarina/7.mp3'},{'revision':'fcbf33e40d7ee627ded6603ce7de711a','url':'/assets/audio/MantaOcarina/8.mp3'},{'revision':'e1401e475342d5de6f4dc3c976996701','url':'/assets/audio/MantaOcarina/9.mp3'},{'revision':'2c84009f18e779ea381bf5e94b33da00','url':'/assets/audio/MetronomeSFX/bar.mp3'},{'revision':'706b180c6de64d552fbb4d313f175697','url':'/assets/audio/MetronomeSFX/quarter.mp3'},{'revision':'d9f474f504a87c3076852d086d560f15','url':'/assets/audio/Ocarina/0.mp3'},{'revision':'30557c555e17e61ac0564b60a7616e9a','url':'/assets/audio/Ocarina/1.mp3'},{'revision':'1c1e222641dc2d5ef33e0b47e187c62b','url':'/assets/audio/Ocarina/10.mp3'},{'revision':'0a79ffb08477871e6b494f911ab80a23','url':'/assets/audio/Ocarina/11.mp3'},{'revision':'8ef5f7889a4d930b755b8faf11207923','url':'/assets/audio/Ocarina/12.mp3'},{'revision':'953a0f4daf8dcddce07f9e3b0a6c64d9','url':'/assets/audio/Ocarina/13.mp3'},{'revision':'b976839fe3c26d17f7d7e81bd3db36d8','url':'/assets/audio/Ocarina/14.mp3'},{'revision':'d24d73bf7e3665b233e53363cae3f979','url':'/assets/audio/Ocarina/2.mp3'},{'revision':'ebc72b2279f94e9da9aaacdf4e26b4fd','url':'/assets/audio/Ocarina/3.mp3'},{'revision':'67a66d232180c13b746a9147c0b943b1','url':'/assets/audio/Ocarina/4.mp3'},{'revision':'17209b9eb74ebbf69f7baf3ebbe52647','url':'/assets/audio/Ocarina/5.mp3'},{'revision':'d31831931d6204a39614c59fa59d8222','url':'/assets/audio/Ocarina/6.mp3'},{'revision':'4fe0a0084eb9eed3c6465cb70b161d6c','url':'/assets/audio/Ocarina/7.mp3'},{'revision':'a7a97e6029d21c99d801b9cbc059da83','url':'/assets/audio/Ocarina/8.mp3'},{'revision':'e4c43ed5c2c13b9b08d14ce8530f5ec7','url':'/assets/audio/Ocarina/9.mp3'},{'revision':'6b036d0dcd5cad40c485019ef5b292db','url':'/assets/audio/Old-Zither/0.mp3'},{'revision':'9bc69ec4e46192e6af08f82cced16543','url':'/assets/audio/Old-Zither/1.mp3'},{'revision':'255c4898a687a13057564655bd3c2697','url':'/assets/audio/Old-Zither/10.mp3'},{'revision':'57368dc9864301717f7f5e2e54576137','url':'/assets/audio/Old-Zither/11.mp3'},{'revision':'5e4264ba7054e81004b330d414ba52fa','url':'/assets/audio/Old-Zither/12.mp3'},{'revision':'91947708ded0a18c724a0ed9303b4bdb','url':'/assets/audio/Old-Zither/13.mp3'},{'revision':'982a5b29f8a2d691c5314affaf4ebd85','url':'/assets/audio/Old-Zither/14.mp3'},{'revision':'c3e893fb30d1b25d031fa84d8a14c97f','url':'/assets/audio/Old-Zither/15.mp3'},{'revision':'e628f0e0147397f515272783dba2dd1e','url':'/assets/audio/Old-Zither/16.mp3'},{'revision':'971bc950845f0c8d724c804f030ded96','url':'/assets/audio/Old-Zither/17.mp3'},{'revision':'720e3fb5628d358b5d534784aa80a884','url':'/assets/audio/Old-Zither/18.mp3'},{'revision':'f9baa950474f917567a51758dd732b5d','url':'/assets/audio/Old-Zither/19.mp3'},{'revision':'757743bcdda586494503b940ea96ae97','url':'/assets/audio/Old-Zither/2.mp3'},{'revision':'7b2798a85ec2bef826177bc66f296e66','url':'/assets/audio/Old-Zither/20.mp3'},{'revision':'b8ca06b22c4f8d8569b2567ab25fff14','url':'/assets/audio/Old-Zither/3.mp3'},{'revision':'e63dd546204b84b52ce81d539d73ccba','url':'/assets/audio/Old-Zither/4.mp3'},{'revision':'c3b7957533fcc946b198fb6879986adb','url':'/assets/audio/Old-Zither/5.mp3'},{'revision':'cc34bb4ee9feacdb914b7b07ff78b8a0','url':'/assets/audio/Old-Zither/6.mp3'},{'revision':'84e5e6b046cb7c4716ada2bd1bc90945','url':'/assets/audio/Old-Zither/7.mp3'},{'revision':'62b04b322fd4463d4382fbfdb86c9362','url':'/assets/audio/Old-Zither/8.mp3'},{'revision':'fd2196e66f672619229663296ee9f387','url':'/assets/audio/Old-Zither/9.mp3'},{'revision':'608170489f305d0ad04fb7c4b2f554d6','url':'/assets/audio/Panflute/0.mp3'},{'revision':'4cf76c89adc633f968304b7d2632077b','url':'/assets/audio/Panflute/1.mp3'},{'revision':'819973bf4e6430776a605f4f29daaf48','url':'/assets/audio/Panflute/10.mp3'},{'revision':'a0edf5de4c18755979b528fc94798c56','url':'/assets/audio/Panflute/11.mp3'},{'revision':'83f5a375ce8687b262f4d139dba46a64','url':'/assets/audio/Panflute/12.mp3'},{'revision':'1b5bcdf01049307b74ee4db7f2191aa8','url':'/assets/audio/Panflute/13.mp3'},{'revision':'ba766fd855771ffdce5cf99cd6dc75e1','url':'/assets/audio/Panflute/14.mp3'},{'revision':'b750f4ad37f51a928a6eebaac837c399','url':'/assets/audio/Panflute/2.mp3'},{'revision':'b46589c0ecafaa279318e226178f8db1','url':'/assets/audio/Panflute/3.mp3'},{'revision':'4f9471a52c515cfe405519e8ef82fb1b','url':'/assets/audio/Panflute/4.mp3'},{'revision':'5e4303e8c77f0664442ca24e11a3c6d4','url':'/assets/audio/Panflute/5.mp3'},{'revision':'796f826d877308053439d885c529da3f','url':'/assets/audio/Panflute/6.mp3'},{'revision':'506d603a7b55bfa26a72d8614e70425b','url':'/assets/audio/Panflute/7.mp3'},{'revision':'b1d656061602d1e8a2065be0a2c4f4a9','url':'/assets/audio/Panflute/8.mp3'},{'revision':'c3db798966fcdf196fb7e67c248748c0','url':'/assets/audio/Panflute/9.mp3'},{'revision':'eca6eae2f2f81466f26634cd58e78505','url':'/assets/audio/Piano/0.mp3'},{'revision':'7d7b98424865d433944a84ccf1fbdeec','url':'/assets/audio/Piano/1.mp3'},{'revision':'10c351400bb980049dc53cf14726b478','url':'/assets/audio/Piano/10.mp3'},{'revision':'1d43325752520ef35a6c9b1fa7154fdd','url':'/assets/audio/Piano/11.mp3'},{'revision':'b4297622d166628a8f93bf51c9987dc8','url':'/assets/audio/Piano/12.mp3'},{'revision':'4a454d37173a3b41ef55ade3d7a36dc7','url':'/assets/audio/Piano/13.mp3'},{'revision':'7f0b64c27b6407c8c11cb07c741118f4','url':'/assets/audio/Piano/14.mp3'},{'revision':'14afb46799b4add43dcc2f8dcb40c703','url':'/assets/audio/Piano/2.mp3'},{'revision':'b28c0861fe85a7de6919d35465401097','url':'/assets/audio/Piano/3.mp3'},{'revision':'64b6fbe0bdfa6b973d4ad9e45163d1bf','url':'/assets/audio/Piano/4.mp3'},{'revision':'c9a4314b2fc8a733caf0266ef7fb62be','url':'/assets/audio/Piano/5.mp3'},{'revision':'e89bfa3d1ca2aef4cca25cda1b70c314','url':'/assets/audio/Piano/6.mp3'},{'revision':'c931bf6688eab5022b69ba8c2c1e29a8','url':'/assets/audio/Piano/7.mp3'},{'revision':'76ec1bceb636badd2a6fe223d3eddb43','url':'/assets/audio/Piano/8.mp3'},{'revision':'ba256691c749dc5b94f1992a690a0839','url':'/assets/audio/Piano/9.mp3'},{'revision':'0c0cc38fb6dc5701762bfcf9bcc50d10','url':'/assets/audio/Pipa/0.mp3'},{'revision':'75c81330f65754e30aea7b7403eeef54','url':'/assets/audio/Pipa/1.mp3'},{'revision':'03ac275bd06e56df426d07655e7c3296','url':'/assets/audio/Pipa/10.mp3'},{'revision':'5093f500c3ebe0d20f7417d5044aef7c','url':'/assets/audio/Pipa/11.mp3'},{'revision':'efff67c32812be379eb300d3658f48be','url':'/assets/audio/Pipa/12.mp3'},{'revision':'0582fe1b88a8640ddbc0b13f68198cda','url':'/assets/audio/Pipa/13.mp3'},{'revision':'abd24588374815226d58a23fdf0b7c43','url':'/assets/audio/Pipa/14.mp3'},{'revision':'6e16bd63de59a2cac330ee0fded50c82','url':'/assets/audio/Pipa/2.mp3'},{'revision':'3a83a6ae3af96def86841a0ff371919b','url':'/assets/audio/Pipa/3.mp3'},{'revision':'ae730eab58e9544ac2facb7efa26118c','url':'/assets/audio/Pipa/4.mp3'},{'revision':'177a83bec0e52440908ff84fe0c1dbf6','url':'/assets/audio/Pipa/5.mp3'},{'revision':'8bb4130815145d9aead03c7820c6e1bf','url':'/assets/audio/Pipa/6.mp3'},{'revision':'b593078a76e1f2b22f0a5afa66f9533a','url':'/assets/audio/Pipa/7.mp3'},{'revision':'e32ddf18be20c14538e244a217e2df02','url':'/assets/audio/Pipa/8.mp3'},{'revision':'6d5fbc594ae1df948317bf0421c6022f','url':'/assets/audio/Pipa/9.mp3'},{'revision':'08502db4f8a16f3221c5a7872d45daa5','url':'/assets/audio/SFX_BassSynth/0.mp3'},{'revision':'931c491280e92ae7561435563aec1c03','url':'/assets/audio/SFX_BassSynth/1.mp3'},{'revision':'1ac0edd2dce5ff57b83191f82f7f52ce','url':'/assets/audio/SFX_BassSynth/2.mp3'},{'revision':'ce79a9d7f8a3d34d8de756a4566a71fd','url':'/assets/audio/SFX_BassSynth/3.mp3'},{'revision':'78dba8a82c4e8c603135f85ef86533eb','url':'/assets/audio/SFX_BassSynth/4.mp3'},{'revision':'70e5510b6685556b957a7ed285e144c9','url':'/assets/audio/SFX_BassSynth/5.mp3'},{'revision':'d3f9930c6dbdafcac964645dda193762','url':'/assets/audio/SFX_BassSynth/6.mp3'},{'revision':'488df8c50e93711edd2688b03f087949','url':'/assets/audio/SFX_BassSynth/7.mp3'},{'revision':'3628435d7ecf440a815057e9decd241a','url':'/assets/audio/SFX_BirdCall/0.mp3'},{'revision':'171ee0ef36fd5c2829c7dee4b55422d0','url':'/assets/audio/SFX_BirdCall/1.mp3'},{'revision':'db6662d4d62dd8a11e382cc7a267fbdc','url':'/assets/audio/SFX_BirdCall/10.mp3'},{'revision':'3eb377a9a6977e2c81492d3e0facb8a5','url':'/assets/audio/SFX_BirdCall/11.mp3'},{'revision':'1467467b2fbc89948534a855f1b93487','url':'/assets/audio/SFX_BirdCall/12.mp3'},{'revision':'4d152ecc9b8be2a53df7bfa8ef0b8403','url':'/assets/audio/SFX_BirdCall/13.mp3'},{'revision':'949881b718f8a91c696f432ce4ec6c6f','url':'/assets/audio/SFX_BirdCall/14.mp3'},{'revision':'0cef78cd0bf9f111ce016a80d47ec41a','url':'/assets/audio/SFX_BirdCall/2.mp3'},{'revision':'e3cedc0c64248634c8cab313799a095d','url':'/assets/audio/SFX_BirdCall/3.mp3'},{'revision':'a0756f7b10e630ecbe2fd70110987ff3','url':'/assets/audio/SFX_BirdCall/4.mp3'},{'revision':'7c825876e45ee6a899194b1395d4a432','url':'/assets/audio/SFX_BirdCall/5.mp3'},{'revision':'dd6e019d7f152f44c038d5e367ef19bc','url':'/assets/audio/SFX_BirdCall/6.mp3'},{'revision':'820dffe2203719c2c8ed2e684f7ce833','url':'/assets/audio/SFX_BirdCall/7.mp3'},{'revision':'b983101131c6c79a82d6ec05861b47bb','url':'/assets/audio/SFX_BirdCall/8.mp3'},{'revision':'ac514886f7950ef5c4ea71131af0a41a','url':'/assets/audio/SFX_BirdCall/9.mp3'},{'revision':'ddc06ffb3f7698fc0b1508effd012786','url':'/assets/audio/SFX_BirdCall/README.md'},{'revision':'e7d3be52a72a7688df139ab7bafdb0f5','url':'/assets/audio/SFX_ChimeSynth/0.mp3'},{'revision':'95cf12c586d9d6c82b72d251c2bda2c9','url':'/assets/audio/SFX_ChimeSynth/1.mp3'},{'revision':'832eb58e73da997287cb406ff7c4f639','url':'/assets/audio/SFX_ChimeSynth/2.mp3'},{'revision':'4e4db16d81ab424bbafe30d9a79b595b','url':'/assets/audio/SFX_ChimeSynth/3.mp3'},{'revision':'5453b2030920bb4351c36e64ed47ef64','url':'/assets/audio/SFX_ChimeSynth/4.mp3'},{'revision':'8463dd78779a02eef213751cf4b6481f','url':'/assets/audio/SFX_ChimeSynth/5.mp3'},{'revision':'e503e0162e87548d604c95bc6815c8ed','url':'/assets/audio/SFX_ChimeSynth/6.mp3'},{'revision':'8d98c2bb55a0280c9d3ce513ca47b27c','url':'/assets/audio/SFX_ChimeSynth/7.mp3'},{'revision':'794f5307d4cf2fc5cb6fe2e6b01fcc90','url':'/assets/audio/SFX_CrabCall/0.mp3'},{'revision':'68ff0a29e73469b1295fb346d13efba5','url':'/assets/audio/SFX_CrabCall/1.mp3'},{'revision':'357edf7ea3707834341269ed76176cf0','url':'/assets/audio/SFX_CrabCall/10.mp3'},{'revision':'f43cc41da5ed09fd16cbe90aa88aec21','url':'/assets/audio/SFX_CrabCall/11.mp3'},{'revision':'a94d69ffa3d2c5bd1339b1b696c37910','url':'/assets/audio/SFX_CrabCall/12.mp3'},{'revision':'041b03ec687f8ab07d59c993aec7b6a5','url':'/assets/audio/SFX_CrabCall/13.mp3'},{'revision':'22c3e3d7936e3eeb4b64ea14d05c559c','url':'/assets/audio/SFX_CrabCall/14.mp3'},{'revision':'08dca733d822c2c5a04d21d10107be76','url':'/assets/audio/SFX_CrabCall/2.mp3'},{'revision':'50c8d25382ba3773b5f4a2e24d8df35f','url':'/assets/audio/SFX_CrabCall/3.mp3'},{'revision':'44fac7273ff770136a1017a457fb07d6','url':'/assets/audio/SFX_CrabCall/4.mp3'},{'revision':'9f036480ffe26c26b877fe5d7916fca4','url':'/assets/audio/SFX_CrabCall/5.mp3'},{'revision':'33faa2aa4ffbb9bf0221e8c603f2ef4a','url':'/assets/audio/SFX_CrabCall/6.mp3'},{'revision':'d3ebcfb3ab778c70256752c287ca83c2','url':'/assets/audio/SFX_CrabCall/7.mp3'},{'revision':'efb0c0bacffbd3b6f53bc4cd4dcb4ae6','url':'/assets/audio/SFX_CrabCall/8.mp3'},{'revision':'d83ae2b29b2fbc4468ec9e852b9c02c0','url':'/assets/audio/SFX_CrabCall/9.mp3'},{'revision':'ddc06ffb3f7698fc0b1508effd012786','url':'/assets/audio/SFX_CrabCall/README.md'},{'revision':'27dbc9ecca9e5bfff9958c67f985feb0','url':'/assets/audio/SFX_Dance/0.mp3'},{'revision':'b60ba0559370fdd216e615d20d83cd67','url':'/assets/audio/SFX_Dance/1.mp3'},{'revision':'396210d9edaca9dcb9ba4cbef580794b','url':'/assets/audio/SFX_Dance/2.mp3'},{'revision':'b73f0eb3c61cdbbdfded381f8c2e8e6d','url':'/assets/audio/SFX_Dance/3.mp3'},{'revision':'efb8eefb1c119512cab58c490493aa35','url':'/assets/audio/SFX_Dance/4.mp3'},{'revision':'dcb3ca13644c1b285f16718ee7d7e528','url':'/assets/audio/SFX_Dance/5.mp3'},{'revision':'ddc06ffb3f7698fc0b1508effd012786','url':'/assets/audio/SFX_Dance/README.md'},{'revision':'157164b420bbea9630742019e3b880a3','url':'/assets/audio/SFX_FishCall/0.mp3'},{'revision':'4fa0ce2a72eedf4334f7472485d9a1d3','url':'/assets/audio/SFX_FishCall/1.mp3'},{'revision':'097cfc032757017d91c71178b024851c','url':'/assets/audio/SFX_FishCall/10.mp3'},{'revision':'2aa05ab8a5db6eb0e6f45c5c481d4b7d','url':'/assets/audio/SFX_FishCall/11.mp3'},{'revision':'1518c2d5c6384bd3f510d44dc9fad87b','url':'/assets/audio/SFX_FishCall/12.mp3'},{'revision':'e2351a4cb9b8cb8691bf8908f992a251','url':'/assets/audio/SFX_FishCall/13.mp3'},{'revision':'069cb2b8bb53f2c40a7a9013428dc43e','url':'/assets/audio/SFX_FishCall/14.mp3'},{'revision':'3c7377439ce905e8ea56aaf197b1263b','url':'/assets/audio/SFX_FishCall/2.mp3'},{'revision':'ded110e1dd9af0c10c6dbe0741c7f539','url':'/assets/audio/SFX_FishCall/3.mp3'},{'revision':'fcca45915dcca0a79b1e946a24ec6483','url':'/assets/audio/SFX_FishCall/4.mp3'},{'revision':'01f5186cb38e3aa283692bebd479fb5a','url':'/assets/audio/SFX_FishCall/5.mp3'},{'revision':'30866bfec3ab4f37343378872420a83a','url':'/assets/audio/SFX_FishCall/6.mp3'},{'revision':'b0b1504ba49b716d3b5facfb61f0d510','url':'/assets/audio/SFX_FishCall/7.mp3'},{'revision':'ed5e5d1ae50148bbcf28888ee22526e2','url':'/assets/audio/SFX_FishCall/8.mp3'},{'revision':'a3ae8cd571e6c5820779d1a8df85da0a','url':'/assets/audio/SFX_FishCall/9.mp3'},{'revision':'ddc06ffb3f7698fc0b1508effd012786','url':'/assets/audio/SFX_FishCall/README.md'},{'revision':'d47988d71a709a32213e355eb17b96e0','url':'/assets/audio/SFX_JellyCall/0.mp3'},{'revision':'02d3d5658a7e0b7b8d10706dc8793ece','url':'/assets/audio/SFX_JellyCall/1.mp3'},{'revision':'377a2ec1d31c8041950a6a0fde08052d','url':'/assets/audio/SFX_JellyCall/10.mp3'},{'revision':'be1c7740bac23343f8dcf5e602e827ed','url':'/assets/audio/SFX_JellyCall/11.mp3'},{'revision':'f83dfa3cd554fa3b3747f75ddffc1b05','url':'/assets/audio/SFX_JellyCall/12.mp3'},{'revision':'75444fd6efc9884cf875974463550496','url':'/assets/audio/SFX_JellyCall/13.mp3'},{'revision':'15340dd0cffdfc13dd8d3c6542dc8e2d','url':'/assets/audio/SFX_JellyCall/14.mp3'},{'revision':'ebc4b1ce8749319371aef5a2f7d9bae1','url':'/assets/audio/SFX_JellyCall/2.mp3'},{'revision':'31e37f2af1ffcfc526abd3f425d8dc55','url':'/assets/audio/SFX_JellyCall/3.mp3'},{'revision':'0c1899bbba0abb94c72e8c9564f2ed98','url':'/assets/audio/SFX_JellyCall/4.mp3'},{'revision':'3db6a51fad7c568e825fd542a27e45e1','url':'/assets/audio/SFX_JellyCall/5.mp3'},{'revision':'3fc06508a85b8d7c62ffdc274bb36ded','url':'/assets/audio/SFX_JellyCall/6.mp3'},{'revision':'72566395c3b26eb5f6ae242c85c5bbfd','url':'/assets/audio/SFX_JellyCall/7.mp3'},{'revision':'122835fbd4a290646ccd6a3e4db98188','url':'/assets/audio/SFX_JellyCall/8.mp3'},{'revision':'0ad07d68ff59ffdb95f1c6d9c07a2872','url':'/assets/audio/SFX_JellyCall/9.mp3'},{'revision':'ddc06ffb3f7698fc0b1508effd012786','url':'/assets/audio/SFX_JellyCall/README.md'},{'revision':'763e59cc0346d3b5f24f166c836d76ca','url':'/assets/audio/SFX_MantaCall/0.mp3'},{'revision':'d82c9810cc91a4134855d1624fb22c76','url':'/assets/audio/SFX_MantaCall/1.mp3'},{'revision':'9f0a625c2450be0a6ea56a6f4b3c1356','url':'/assets/audio/SFX_MantaCall/10.mp3'},{'revision':'41a909a92c5b0d4f60b8d95a022d7b6c','url':'/assets/audio/SFX_MantaCall/11.mp3'},{'revision':'26520cd87dc4b17b1c129a3909ba3fc0','url':'/assets/audio/SFX_MantaCall/12.mp3'},{'revision':'3b4d4f7c736616a033e3aaad8999bd03','url':'/assets/audio/SFX_MantaCall/13.mp3'},{'revision':'fcfea8af69fefab63afb7e542ae05345','url':'/assets/audio/SFX_MantaCall/14.mp3'},{'revision':'e72b8204d4e6fd6bddc4a6ad3924e407','url':'/assets/audio/SFX_MantaCall/2.mp3'},{'revision':'7ef196b620723ffe9e7aa294e378f287','url':'/assets/audio/SFX_MantaCall/3.mp3'},{'revision':'68073f5a5860ced5a72c971466ee1a08','url':'/assets/audio/SFX_MantaCall/4.mp3'},{'revision':'413b5156b16af4e6bb022e1d9c34aad0','url':'/assets/audio/SFX_MantaCall/5.mp3'},{'revision':'50e3c6091f39769a8471fc0f871eab25','url':'/assets/audio/SFX_MantaCall/6.mp3'},{'revision':'832ab1f1a42825db2166dd027df56d37','url':'/assets/audio/SFX_MantaCall/7.mp3'},{'revision':'e8410f10df992962237bf73bedb912b6','url':'/assets/audio/SFX_MantaCall/8.mp3'},{'revision':'c6b7dd06d27dff8e794c04cad6f2ad23','url':'/assets/audio/SFX_MantaCall/9.mp3'},{'revision':'ddc06ffb3f7698fc0b1508effd012786','url':'/assets/audio/SFX_MantaCall/README.md'},{'revision':'7ac06ba351203f46c49afd19739304dd','url':'/assets/audio/SFX_MothCall/0.mp3'},{'revision':'fdc677e6a9f49db2e4369bd93f431c65','url':'/assets/audio/SFX_MothCall/1.mp3'},{'revision':'030b7999ca958660a79d559cd79ac82c','url':'/assets/audio/SFX_MothCall/10.mp3'},{'revision':'329192397906a2649c9c1cd7be7f55af','url':'/assets/audio/SFX_MothCall/11.mp3'},{'revision':'140286b7f5a917f98e34311278a4d285','url':'/assets/audio/SFX_MothCall/12.mp3'},{'revision':'4f1e8029593a79208d9ee05b3e74ac83','url':'/assets/audio/SFX_MothCall/13.mp3'},{'revision':'eefa2dd9373c96f988d8cafea9980b6a','url':'/assets/audio/SFX_MothCall/14.mp3'},{'revision':'9b87c1d36bcab8a0bb18e53d93cfad73','url':'/assets/audio/SFX_MothCall/2.mp3'},{'revision':'dfd4e223113390d82a0cf0030e947f80','url':'/assets/audio/SFX_MothCall/3.mp3'},{'revision':'3e546ef46cc1661304dd82d2dff19eb2','url':'/assets/audio/SFX_MothCall/4.mp3'},{'revision':'de0521d9dd826303636b692314848aa9','url':'/assets/audio/SFX_MothCall/5.mp3'},{'revision':'7e6a63264b8e7b1cc849a2e979bb2e15','url':'/assets/audio/SFX_MothCall/6.mp3'},{'revision':'46bbc7c7981020e981f9d6d3acb7fb22','url':'/assets/audio/SFX_MothCall/7.mp3'},{'revision':'bcbb371b5f5d7556bad5e7c7097a5108','url':'/assets/audio/SFX_MothCall/8.mp3'},{'revision':'992d55789e05810c4c5f5dbb45040507','url':'/assets/audio/SFX_MothCall/9.mp3'},{'revision':'ddc06ffb3f7698fc0b1508effd012786','url':'/assets/audio/SFX_MothCall/README.md'},{'revision':'b2157b0c243cfbe8a86c9a7e5f30b541','url':'/assets/audio/SFX_SineSynth/0.mp3'},{'revision':'f2fd6188c9db72ef072c6cbc34dc1538','url':'/assets/audio/SFX_SineSynth/1.mp3'},{'revision':'11aa84b2a7735f6c59529026d684fe56','url':'/assets/audio/SFX_SineSynth/2.mp3'},{'revision':'e50c03ef2f5437daba10928ed01fc2e2','url':'/assets/audio/SFX_SineSynth/3.mp3'},{'revision':'75a54bd320ff1ee37989c6df804ff19c','url':'/assets/audio/SFX_SineSynth/4.mp3'},{'revision':'ccbd4e3f8cc0d304da625a449bae01b7','url':'/assets/audio/SFX_SineSynth/5.mp3'},{'revision':'05fdaccbade736df6e831e20978fb21b','url':'/assets/audio/SFX_SineSynth/6.mp3'},{'revision':'f249d2d3ecfe9747e4bef3dce1f2d321','url':'/assets/audio/SFX_SineSynth/7.mp3'},{'revision':'b53eaf25fbf9518d580d792181a2bf16','url':'/assets/audio/SFX_SpiritMantaCall/0.mp3'},{'revision':'86ae86f2e40c00095ad7088a8b840e82','url':'/assets/audio/SFX_SpiritMantaCall/1.mp3'},{'revision':'50bca244e5c4835aed62853d608f9ecd','url':'/assets/audio/SFX_SpiritMantaCall/10.mp3'},{'revision':'fc9e6561ed54fef3a89bf045e02e4fa1','url':'/assets/audio/SFX_SpiritMantaCall/11.mp3'},{'revision':'5f451b3cdc6db0f1ed4ab0cc0cf9392e','url':'/assets/audio/SFX_SpiritMantaCall/12.mp3'},{'revision':'5d2e7c59ad6c2c8c894df497a2ad8d7e','url':'/assets/audio/SFX_SpiritMantaCall/13.mp3'},{'revision':'365bc9122a4cdae0aba3d92194fc1076','url':'/assets/audio/SFX_SpiritMantaCall/14.mp3'},{'revision':'9c8ec34397d2b85571aef98cd65ec77b','url':'/assets/audio/SFX_SpiritMantaCall/2.mp3'},{'revision':'6e9fe01edb766d3b7893aa015aa87907','url':'/assets/audio/SFX_SpiritMantaCall/3.mp3'},{'revision':'338e9696cfa2f5c064834c3524332538','url':'/assets/audio/SFX_SpiritMantaCall/4.mp3'},{'revision':'8fc10c935361f96c30bcd669c8ce1934','url':'/assets/audio/SFX_SpiritMantaCall/5.mp3'},{'revision':'2a9026289f301ed2ff7f2de5b381d8d7','url':'/assets/audio/SFX_SpiritMantaCall/6.mp3'},{'revision':'51e854fe610676da98058f96d89f38d5','url':'/assets/audio/SFX_SpiritMantaCall/7.mp3'},{'revision':'1b98865ee2b8a541fda4e53c456c2fa3','url':'/assets/audio/SFX_SpiritMantaCall/8.mp3'},{'revision':'8db33a9333ad89ca9628c9f2fdfe48c6','url':'/assets/audio/SFX_SpiritMantaCall/9.mp3'},{'revision':'ddc06ffb3f7698fc0b1508effd012786','url':'/assets/audio/SFX_SpiritMantaCall/README.md'},{'revision':'4e5b141e9ca5e591e83ec88eeff14bd3','url':'/assets/audio/SFX_TR-909/0.mp3'},{'revision':'9ce011136e3af6c97eef972269944401','url':'/assets/audio/SFX_TR-909/1.mp3'},{'revision':'7ea52b09b264c60e67b60c154f19e0ec','url':'/assets/audio/SFX_TR-909/2.mp3'},{'revision':'1679c7c8c417dceccf01f5af04fc346c','url':'/assets/audio/SFX_TR-909/3.mp3'},{'revision':'82a14957329630d2870ec92a34903b74','url':'/assets/audio/SFX_TR-909/4.mp3'},{'revision':'c8e8e4ef90870657c4755865097553f1','url':'/assets/audio/SFX_TR-909/5.mp3'},{'revision':'bcf42bef228f7b2e3927e2f3d6324e4c','url':'/assets/audio/SFX_TR-909/6.mp3'},{'revision':'7ab1b6f21b8018468d3408efe495e938','url':'/assets/audio/SFX_TR-909/7.mp3'},{'revision':'bdd5fbebe33e132b478b856e5ce0bd12','url':'/assets/audio/ToyUkulele/0.mp3'},{'revision':'9673c076738c70acb1ec2e35e7054fda','url':'/assets/audio/ToyUkulele/1.mp3'},{'revision':'f8ffef9da0a741ca42688d49c2312d94','url':'/assets/audio/ToyUkulele/10.mp3'},{'revision':'623c8bd8f004c5a8d97ecef8a19f5a64','url':'/assets/audio/ToyUkulele/11.mp3'},{'revision':'c88455fcbaf7216fedf0ab1377761e1c','url':'/assets/audio/ToyUkulele/12.mp3'},{'revision':'578b750af2d95f292fba4c8e8dfba9fe','url':'/assets/audio/ToyUkulele/13.mp3'},{'revision':'9064558738bd35e00164d8d8752e1b03','url':'/assets/audio/ToyUkulele/14.mp3'},{'revision':'e17c7bd9bb12816202c70eccacbb900a','url':'/assets/audio/ToyUkulele/2.mp3'},{'revision':'e69d04d6eabba4ceef14a59929f14888','url':'/assets/audio/ToyUkulele/3.mp3'},{'revision':'371796a1c139ed02881849dc28568895','url':'/assets/audio/ToyUkulele/4.mp3'},{'revision':'d0e00fda3d99144d1f6f94f396934a84','url':'/assets/audio/ToyUkulele/5.mp3'},{'revision':'46b73f312020fe3add83989150c7ce14','url':'/assets/audio/ToyUkulele/6.mp3'},{'revision':'d65f0dde33e61b89be88b61e049380d7','url':'/assets/audio/ToyUkulele/7.mp3'},{'revision':'9bd04caec3bf3096b5c1d9686527809b','url':'/assets/audio/ToyUkulele/8.mp3'},{'revision':'b7ad49319ec80556a6b0ee26b7933060','url':'/assets/audio/ToyUkulele/9.mp3'},{'revision':'a5d3061d93ba3a29a578ea80345587c1','url':'/assets/audio/Trumpet/0.mp3'},{'revision':'8b89807e19406d8bcaf6da51ba306ab2','url':'/assets/audio/Trumpet/1.mp3'},{'revision':'b4898de31c370f52e2c975832ad47d90','url':'/assets/audio/Trumpet/10.mp3'},{'revision':'9985742467bcdee9d8f5383a9c19c055','url':'/assets/audio/Trumpet/11.mp3'},{'revision':'e1e95fbcc2b64151fc454a50b1f32c62','url':'/assets/audio/Trumpet/12.mp3'},{'revision':'46647f9e99b8fd847ab7670a5cc190d5','url':'/assets/audio/Trumpet/13.mp3'},{'revision':'f6c99ac75d90b808e81f9a3958a51795','url':'/assets/audio/Trumpet/14.mp3'},{'revision':'0b91cce3b6ceb6a3ffdf0bb4f2fa4c39','url':'/assets/audio/Trumpet/2.mp3'},{'revision':'99d4aedadbad58319e5f60b317a007ad','url':'/assets/audio/Trumpet/3.mp3'},{'revision':'cb4e460414923755d0475b8db63839a0','url':'/assets/audio/Trumpet/4.mp3'},{'revision':'3a8603f82e2cbb8d2aab3811cceb8557','url':'/assets/audio/Trumpet/5.mp3'},{'revision':'57767b69a5adf43db391f9afa1fdc9f5','url':'/assets/audio/Trumpet/6.mp3'},{'revision':'211b3d909b89c2cf7a43af1651f98e2e','url':'/assets/audio/Trumpet/7.mp3'},{'revision':'abb25c4e6b2d15df5b88530448f8259a','url':'/assets/audio/Trumpet/8.mp3'},{'revision':'7f193efd5abc26abca3c0a8c3dbb38cb','url':'/assets/audio/Trumpet/9.mp3'},{'revision':'9ddb7f8560513a52ff18d4d36a3d0a06','url':'/assets/audio/Vintage-Lyre/0.mp3'},{'revision':'fa18434a1ec057e89cff9a16a5ee26e8','url':'/assets/audio/Vintage-Lyre/1.mp3'},{'revision':'3eaaaf43824414af3f1668ab30bd10c8','url':'/assets/audio/Vintage-Lyre/10.mp3'},{'revision':'4d84470fe9c4810a41da07c1df752ebe','url':'/assets/audio/Vintage-Lyre/11.mp3'},{'revision':'26c346cb7d0d9d4a328be2729e6c7784','url':'/assets/audio/Vintage-Lyre/12.mp3'},{'revision':'cbcc0b56172bd9f96742738f39eb32a6','url':'/assets/audio/Vintage-Lyre/13.mp3'},{'revision':'f0608686f5234fa8332722c0dbe221ca','url':'/assets/audio/Vintage-Lyre/14.mp3'},{'revision':'0168de671b88dc8bcda68cad5253c31b','url':'/assets/audio/Vintage-Lyre/15.mp3'},{'revision':'45a160dc94ba3fb345dec6b678be88cc','url':'/assets/audio/Vintage-Lyre/16.mp3'},{'revision':'c4ced73613bfc370d70eef1dc7f74fac','url':'/assets/audio/Vintage-Lyre/17.mp3'},{'revision':'c4a6516d70c283433264b69c1f67da3b','url':'/assets/audio/Vintage-Lyre/18.mp3'},{'revision':'1e7c24970a11e2d46f849a56748845bf','url':'/assets/audio/Vintage-Lyre/19.mp3'},{'revision':'1a35e42c409007b31edddd67e1514183','url':'/assets/audio/Vintage-Lyre/2.mp3'},{'revision':'2c034399d165124b6f5c98f6ffe17461','url':'/assets/audio/Vintage-Lyre/20.mp3'},{'revision':'5a249ea5b55cdc315c1feb710e2587eb','url':'/assets/audio/Vintage-Lyre/3.mp3'},{'revision':'5a5d1c6302c8c7653e57ca3bdd4f7c65','url':'/assets/audio/Vintage-Lyre/4.mp3'},{'revision':'04ef447c96539e2650d9d8e2d3d7e175','url':'/assets/audio/Vintage-Lyre/5.mp3'},{'revision':'14fb6b9081f5b6c24b34a491e2c4719f','url':'/assets/audio/Vintage-Lyre/6.mp3'},{'revision':'4e409ab0643ea16d9520e0da4ca4600a','url':'/assets/audio/Vintage-Lyre/7.mp3'},{'revision':'c92c10d43155b8215a04709c7a187d9c','url':'/assets/audio/Vintage-Lyre/8.mp3'},{'revision':'42a2341c945ab15fd74469d2f9f54b88','url':'/assets/audio/Vintage-Lyre/9.mp3'},{'revision':'c9e635e54b77cb131e7436aa4f539334','url':'/assets/audio/WinterPiano/0.mp3'},{'revision':'a0c5a8fa1e6599285c55e66870428de0','url':'/assets/audio/WinterPiano/1.mp3'},{'revision':'fa45827097cdf3952758d426ddae8022','url':'/assets/audio/WinterPiano/10.mp3'},{'revision':'a351b425ae533a525bf99c8459762720','url':'/assets/audio/WinterPiano/11.mp3'},{'revision':'4010a0576e5de050d9b874aa8c4ef0ac','url':'/assets/audio/WinterPiano/12.mp3'},{'revision':'68ef44ffe56ca57e938fbbd60809c080','url':'/assets/audio/WinterPiano/13.mp3'},{'revision':'e0afc996d04c7e1e50daf1ab1c232358','url':'/assets/audio/WinterPiano/14.mp3'},{'revision':'74855f097002ecb122459badaedb8f54','url':'/assets/audio/WinterPiano/2.mp3'},{'revision':'d7a19f2ab265e0c8b338b78ea6a42701','url':'/assets/audio/WinterPiano/3.mp3'},{'revision':'a4f81c763fed5715f72b59458a2775b9','url':'/assets/audio/WinterPiano/4.mp3'},{'revision':'3eb51e42fe7bb8732d3eb87951e7cce1','url':'/assets/audio/WinterPiano/5.mp3'},{'revision':'bd8994c2cc6e7f9133971f5ed720ad1f','url':'/assets/audio/WinterPiano/6.mp3'},{'revision':'7330ed90a92f99fef4cfdf0cde505d89','url':'/assets/audio/WinterPiano/7.mp3'},{'revision':'f4130e124a2eb97d5cb22ba47714a9da','url':'/assets/audio/WinterPiano/8.mp3'},{'revision':'c52a5e061bddbf4711b7703d29281d3a','url':'/assets/audio/WinterPiano/9.mp3'},{'revision':'528ca6e43eb6a8db60fc3d327ae536f0','url':'/assets/audio/Xylophone/0.mp3'},{'revision':'5d6aef254407677363b4cfb869432ba0','url':'/assets/audio/Xylophone/1.mp3'},{'revision':'41bf7c0506948fd6c8040bcc5acf8706','url':'/assets/audio/Xylophone/10.mp3'},{'revision':'4e750a2d52e09977d0ef1744f25465c1','url':'/assets/audio/Xylophone/11.mp3'},{'revision':'978c21d9203c51f57c8de47e01dabf05','url':'/assets/audio/Xylophone/12.mp3'},{'revision':'72b355d067c3b798960cb78a3fe2f0fd','url':'/assets/audio/Xylophone/13.mp3'},{'revision':'b59003e31e0c0c168206677090a4b261','url':'/assets/audio/Xylophone/14.mp3'},{'revision':'dbcee8e2ad7cb054e579386c18ad79b5','url':'/assets/audio/Xylophone/2.mp3'},{'revision':'76cb3204fd2026e4f8732121b07963e9','url':'/assets/audio/Xylophone/3.mp3'},{'revision':'77051772c7035d93c2573da9e536c545','url':'/assets/audio/Xylophone/4.mp3'},{'revision':'ab4e29dcf6a4fdd3af5d95da5738ad11','url':'/assets/audio/Xylophone/5.mp3'},{'revision':'6ac64fc5d87057e0acf659c7559c65d8','url':'/assets/audio/Xylophone/6.mp3'},{'revision':'50667c64fdff79ba4b71ac1fe5f90d1d','url':'/assets/audio/Xylophone/7.mp3'},{'revision':'1e1eafdfbff5989903bd722a6df16ecf','url':'/assets/audio/Xylophone/8.mp3'},{'revision':'abc16b06da48ca3a7afcd8724344fa4b','url':'/assets/audio/Xylophone/9.mp3'},{'revision':'7c206a44131a62000f7d7ec7f09b18f6','url':'/assets/audio/Zither/0.mp3'},{'revision':'ef2b3f5210c88426565b54d4f6d55a1b','url':'/assets/audio/Zither/1.mp3'},{'revision':'35fba626140d3da9935a2d9ea95a68c1','url':'/assets/audio/Zither/10.mp3'},{'revision':'08be6d9fd6cab4beb29dc8fbd3d20c95','url':'/assets/audio/Zither/11.mp3'},{'revision':'c3c75ccbdf3995ddecc0f837cc03c791','url':'/assets/audio/Zither/12.mp3'},{'revision':'8b1d22b9cbfada6b6231f00ee0a9b5aa','url':'/assets/audio/Zither/13.mp3'},{'revision':'104635ee45c153edd29baac494bf1567','url':'/assets/audio/Zither/14.mp3'},{'revision':'a466f269f2cf1ba8018f05984acbbe46','url':'/assets/audio/Zither/15.mp3'},{'revision':'3a905bc2d44258f573edbcddccc1353b','url':'/assets/audio/Zither/16.mp3'},{'revision':'6da338c5a78fdfb304840543c17046e2','url':'/assets/audio/Zither/17.mp3'},{'revision':'c31c18f1066ba225a30b739ec192350b','url':'/assets/audio/Zither/18.mp3'},{'revision':'fdc075cc31ed4c768be1350054696e5c','url':'/assets/audio/Zither/19.mp3'},{'revision':'28bafbb589565dcd2c3e05ff41c513fc','url':'/assets/audio/Zither/2.mp3'},{'revision':'90027c3a4ae0ebc2ad7fd53e562abfa3','url':'/assets/audio/Zither/20.mp3'},{'revision':'e642f522ce359e3af2041f6a7aa73188','url':'/assets/audio/Zither/3.mp3'},{'revision':'c1c4c16c41e1cc2572fad1b064c4b180','url':'/assets/audio/Zither/4.mp3'},{'revision':'bf0e116847b95f6307e3520fbc9fcc89','url':'/assets/audio/Zither/5.mp3'},{'revision':'499887434745c1355e62fb9a2745bdc8','url':'/assets/audio/Zither/6.mp3'},{'revision':'c33f43b66c30accbe4630b47d395c272','url':'/assets/audio/Zither/7.mp3'},{'revision':'26937cf69c516807d6ad4726f768f43a','url':'/assets/audio/Zither/8.mp3'},{'revision':'cbe3faabb67d9702881ba820f3c67bad','url':'/assets/audio/Zither/9.mp3'},{'revision':'491d4458ed4bc57e6fb191fc4666f046','url':'/assets/audio/reverb4.wav'},{'revision':'dbbdc77f58808f74fb1c30e8a8835236','url':'/assets/audio/reverb5.wav'},{'revision':'856f3f7a82b9ed3e373592b1d5c1b9eb','url':'/assets/blog/help-composer-2.webp'},{'revision':'de44f4e535caeb673b498b694e5d2e10','url':'/assets/blog/help-composer-3.webp'},{'revision':'1a2fc855b801aa9f0d433846f5ea38f7','url':'/assets/blog/help-composer-4.webp'},{'revision':'73906bd08b1e22bd7d34e14ddfb58610','url':'/assets/blog/help-composer-5.webp'},{'revision':'9a24e46c74cd1e0cd161d109762d60cd','url':'/assets/blog/help-composer.webp'},{'revision':'9816eea0ceb8d57febe24250c2a621ab','url':'/assets/blog/help-player-2.webp'},{'revision':'613825e987929ad0619b07a25949fd24','url':'/assets/blog/help-player-3.webp'},{'revision':'d4f216c90d34a15f50ab2f5840a4c83d','url':'/assets/blog/help-player.webp'},{'revision':'5ae5f2521b5f1f297fcba66de8d9cc58','url':'/assets/blog/help-vsrg-composer-2.webp'},{'revision':'da78f4d2df0e498c6b472b657a42eba1','url':'/assets/blog/help-vsrg-composer-3.webp'},{'revision':'599c3854b8112ed8a77537265e31b59e','url':'/assets/blog/help-vsrg-composer.webp'},{'revision':'d8d23cc536c191edce976db044f0c2b0','url':'/assets/blog/midi-1.webp'},{'revision':'610b3cef8d13e688629df48fa4670fe8','url':'/assets/blog/midi-2.webp'},{'revision':'dc583c33fa201752e26ca4c09f2c47c4','url':'/assets/blog/midi-btn.webp'},{'revision':'e7fe0e77de8c844624a0b1451b04002c','url':'/assets/blog/zen-keyboard.webp'},{'revision':'02a0b873d020e14fc020057317cf7a23','url':'/assets/group1-shard1of1.bin'},{'revision':'53f4ce1456b8382d020c2edf51f9a06d','url':'/assets/icons/addCell.svg'},{'revision':'402a59b143ba2f536f1329381ecded94','url':'/assets/icons/full.png'},{'revision':'a26e2db34e420c66ea2e2825c5358837','url':'/assets/icons/keys/cr.svg'},{'revision':'82bb8594400afbde232b338b23ed8475','url':'/assets/icons/keys/dm.svg'},{'revision':'5e75d39869cd9f7cb1ab1755b29664ac','url':'/assets/icons/keys/dmcr.svg'},{'revision':'5defb9bbcd25db4d8f6d52b68fa300bb','url':'/assets/icons/keys/do.svg'},{'revision':'42a6d2a3ffa29d79ffd67be6a862cf1e','url':'/assets/icons/keys/fa.svg'},{'revision':'ca84e98beda8a6fd44e2d962ab25467d','url':'/assets/icons/keys/la.svg'},{'revision':'fb7400b3b1a92815ec26e8f84e30ca9d','url':'/assets/icons/keys/mi.svg'},{'revision':'90f0406cacb3066e17dc064814108cc7','url':'/assets/icons/keys/old icons/do.svg'},{'revision':'c3d05b2158e6a68c1a4266cf9ed34a1c','url':'/assets/icons/keys/old icons/fa.svg'},{'revision':'79a07070d71e0f8964208484875c2077','url':'/assets/icons/keys/old icons/la.svg'},{'revision':'2b696be94489c3bc05c3d6dfcae0abda','url':'/assets/icons/keys/old icons/mi.svg'},{'revision':'c04694b0eafd03b1cb1ceb27b8c398b1','url':'/assets/icons/keys/old icons/re.svg'},{'revision':'4d9956557b9a08caeef36380780f800e','url':'/assets/icons/keys/old icons/so.svg'},{'revision':'633a68b89e9a8c10889e25c8d182fb63','url':'/assets/icons/keys/old icons/ti.svg'},{'revision':'8e092afc024c163a36bd50218ac7244b','url':'/assets/icons/keys/re.svg'},{'revision':'defa67bc736bfafdac607c26625f7692','url':'/assets/icons/keys/so.svg'},{'revision':'bdebf640d1b40c6834ff7ac44d47db91','url':'/assets/icons/keys/ti.svg'},{'revision':'0bbd13d3a10ecefca257a13c69b1f83a','url':'/assets/icons/loadingApp.svg'},{'revision':'991f6d8b4165138c3ddf828aa09b4200','url':'/assets/icons/removeCell.svg'},{'revision':'67c290cd00303a68fbd735cd15601bc7','url':'/assets/icons/rounded.png'},{'revision':'b4b41b256ec7a31789f4b236ee97e64d','url':'/assets/icons/star_decoration.svg'},{'revision':'ac9ebe4205087b85a26484759e218d49','url':'/assets/images/specy.png'},{'revision':'417dd6adc15cbaec0163e937d1c6d773','url':'/favicon.ico'},{'revision':'cbe325b0c62c395d843eb94e33e2c1c8','url':'/logo192.png'},{'revision':'0ab09d434e81d3a0f7f2bb5ec057fe11','url':'/logo512.png'},{'revision':'6c6528c107bca46bd8b674adaae5aa87','url':'/manifest.json'},{'revision':'386eca79726a4313c9a9443d5b50a637','url':'/manifestData/composer.png'},{'revision':'a0cc4f0afc752de90ac54505334231af','url':'/manifestData/composer.webp'},{'revision':'3f4bd40fbddb8af00e266da876efe0bb','url':'/manifestData/composerIcon.png'},{'revision':'6c67a688686d129a12bf1fe07c873499','url':'/manifestData/help-composer.png'},{'revision':'212cec943fe59d085b413590309601af','url':'/manifestData/main.png'},{'revision':'9848a07edc2ef69c9261c0c410400001','url':'/manifestData/main.webp'},{'revision':'6ed03c485d0adad82f6be4e43f1707b6','url':'/manifestData/player.webp'},{'revision':'666340bfaf1c4801ec811e24c250b57e','url':'/manifestData/zenkeyboard.webp'},{'revision':'61c27d2cd39a713f7829422c3d9edcc7','url':'/robots.txt'},{'revision':'a97fc99a3cfeac97967e43557da08f3b','url':'/service-worker.js'},{'revision':'5dd3c7438c24c9f991201846e02e76e1','url':'/updates.json'}].filter(function(e){return!(e.url.includes(".mp3")||e.url.includes(".md")||e.url.includes(".json")||e.url.includes("media")||e.url.includes("manifestData")||e.url.includes("service-worker")||e.url.includes(".bin"))}).map(function(e){return e.revision&&e.url.includes(e.revision)&&(e.revision=null),e})),l||(n.updateDetails({prefix:"",suffix:"",precache:u,runtime:h}),console.log("registering routes"),registerRoute(function(e){var t=e.url;try{if(forbiddenCachedItems(new URL(t)))return!1}catch(e){console.error("Error caching",e)}return!0},new class extends Strategy_Strategy{constructor(e={}){super(e),this.plugins.some(e=>"cacheWillUpdate"in e)||this.plugins.unshift(a),this._networkTimeoutSeconds=e.networkTimeoutSeconds||0}async _handle(e,t){let r;let n=[],a=[];if(this._networkTimeoutSeconds){let{id:o,promise:i}=this._getTimeoutPromise({request:e,logs:n,handler:t});r=o,a.push(i)}let o=this._getNetworkPromise({timeoutId:r,request:e,logs:n,handler:t});a.push(o);let i=await t.waitUntil((async()=>await t.waitUntil(Promise.race(a))||await o)());if(!i)throw new WorkboxError_WorkboxError("no-response",{url:e.url});return i}_getTimeoutPromise({request:e,logs:t,handler:r}){let n;let a=new Promise(t=>{let onNetworkTimeout=async()=>{t(await r.cacheMatch(e))};n=setTimeout(onNetworkTimeout,1e3*this._networkTimeoutSeconds)});return{promise:a,id:n}}async _getNetworkPromise({timeoutId:e,request:t,logs:r,handler:n}){let a,o;try{o=await n.fetchAndCachePut(t)}catch(e){e instanceof Error&&(a=e)}return e&&clearTimeout(e),(a||!o)&&(o=await n.cacheMatch(t)),o}}({cacheName:h})),registerRoute(function(e){var t=e.url;try{if(forbiddenCachedItems(new URL(t)))return!1;if(t.pathname.endsWith(".mp3")||t.pathname.endsWith(".wav"))return!0}catch(e){console.error("Error caching",e)}return!1},new class extends Strategy_Strategy{async _handle(e,t){let r,n=await t.cacheMatch(e);if(!n)try{n=await t.fetchAndCachePut(e)}catch(e){e instanceof Error&&(r=e)}if(!n)throw new WorkboxError_WorkboxError("no-response",{url:e.url,error:r});return n}}({cacheName:h}))),self.addEventListener("message",function(e){e.data&&"SKIP_WAITING"===e.data.type&&(console.log("[ServiceWorker] skip waiting"),self.skipWaiting())}),self.addEventListener("install",(o=_async_to_generator(function(e){var t,r;return __generator(this,function(e){switch(e.label){case 0:return[4,caches.keys()];case 1:if(!(t=e.sent()).length||!(r=t.filter(function(e){return e.includes(s)})).length)return[2,console.log("Fresh install")];if(0!==r.filter(function(e){return e.startsWith("".concat(3))}).length)return[3,4];return console.log("Major version change, skipping waiting and refreshing all tabs"),[4,self.skipWaiting()];case 2:return e.sent(),[4,self.clients.claim()];case 3:e.sent(),self.clients.matchAll({type:"window"}).then(function(e){e.forEach(function(e){e.navigate(e.url)})}),e.label=4;case 4:return[2]}})}),function(e){return o.apply(this,arguments)})),self.addEventListener("activate",function(e){var t;console.log("[ServiceWorker] Activate"),e.waitUntil(caches.keys().then((t=_async_to_generator(function(e){var t;return __generator(this,function(r){switch(r.label){case 0:return[4,Promise.all(e.map(function(e){return s?(console.log('Verifying cache "'.concat(e,'"')),e.includes(s))?e.includes("precache")?e!==u?(console.log('[ServiceWorker] Removing old precache: "'.concat(e,'"')),caches.delete(e)):Promise.resolve():e.includes("runtime")?e!==h?(console.log('[ServiceWorker] Removing old runtime cache: "'.concat(e,'"')),caches.delete(e)):Promise.resolve():(console.log('[ServiceWorker] Removing old unknown cache: "'.concat(e,'"')),caches.delete(e)):e.includes("workbox")?(console.log('[ServiceWorker] Removing old workbox cache: "'.concat(e,'"')),caches.delete(e)):Promise.resolve():console.error("APP_NAME is not defined")}))];case 1:return console.log("[ServiceWorker] Finished removing old caches",t=r.sent()),[2,t]}})}),function(e){return t.apply(this,arguments)}))),self.clients.claim()})}()}(); \ No newline at end of file diff --git a/scripts/buildAndPrepareTauriRelease.js b/scripts/buildAndPrepareTauriRelease.js index af30e275..f95b2bb6 100644 --- a/scripts/buildAndPrepareTauriRelease.js +++ b/scripts/buildAndPrepareTauriRelease.js @@ -106,7 +106,7 @@ async function run() { .replace("{zip-name}", buildZip), signature: buildSignature } - //saves the results to both the folder of the build data and updates the repository one + //saves the results to both the folder of the build data and changelog the repository one await fs.writeFile(`./src-tauri/tauri-${app}.update.json`, JSON.stringify(appUpdate, null, 2)) //copies all the built files to the final release folder await fs.mkdir(folders.windowsRelease, { recursive: true }) @@ -148,7 +148,7 @@ async function run() { .replace("{zip-name}", buildZip), signature: buildSignature } - //saves the results to both the folder of the build data and updates the repository one + //saves the results to both the folder of the build data and changelog the repository one await fs.writeFile(`./src-tauri/tauri-${app}.update.json`, JSON.stringify(appUpdate, null, 2)) //copies all the update files await fs.mkdir(folders.macosRelease, { recursive: true }) @@ -201,7 +201,7 @@ async function run() { .replace("{zip-name}", buildZip), signature: buildSignature } - //saves the results to both the folder of the build data and updates the repository one + //saves the results to both the folder of the build data and changelog the repository one await fs.writeFile(`./src-tauri/tauri-${app}.update.json`, JSON.stringify(appUpdate, null, 2)) //copies all the update files await fs.mkdir(folders.linuxRelease, { recursive: true }) diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index f07796ba..8a4058de 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -7,9 +7,9 @@ fn main() { let context = tauri::generate_context!(); tauri::Builder::default() .menu(if cfg!(target_os = "macos") { - tauri::Menu::os_default(&context.package_info().name) + tauri::MenuContext::os_default(&context.package_info().name) } else { - tauri::Menu::default() + tauri::MenuContext::default() }) .run(context) .expect("error while running tauri application"); diff --git a/src/Config.ts b/src/Config.ts index 073afab1..86d88eb7 100644 --- a/src/Config.ts +++ b/src/Config.ts @@ -23,7 +23,7 @@ export const UPDATE_MESSAGE = (APP_NAME === 'Genshin' `).trim() export const UPDATE_URL = process.env.NODE_ENV === 'development' - ? '/updates.json' + ? '/changelog.json' : 'https://raw.githubusercontent.com/Specy/genshin-music/main/public/updates.json' diff --git a/src/lib/updates.ts b/src/changelog.ts similarity index 99% rename from src/lib/updates.ts rename to src/changelog.ts index d1771ad6..06f0fe0c 100644 --- a/src/lib/updates.ts +++ b/src/changelog.ts @@ -5,7 +5,7 @@ type Update = { changes: string[] } -export const updates: Update[] = [ +export const CHANGELOG: Update[] = [ { version: '3.3.0', title: "Audio/Video transcription, reverb", diff --git a/src/components/AppBase.tsx b/src/components/AppBase.tsx index 4ce9b5be..ac643ce3 100644 --- a/src/components/AppBase.tsx +++ b/src/components/AppBase.tsx @@ -1,16 +1,16 @@ import {useCallback, useEffect, useState} from 'react'; -import Analytics from '$lib/Stats'; +import Analytics from '$lib/Analytics'; import Home from '$cmp/pages/Index/Home'; import {homeStore} from '$stores/HomeStore'; import {logger} from '$stores/LoggerStore'; -import {delay} from "$lib/Utilities" +import {delay} from "$lib/utils/Utilities" import {APP_NAME, APP_VERSION, UPDATE_MESSAGE} from "$config" import rotateImg from "$/assets/icons/rotate.svg" -import {historyTracker} from '$stores/History'; +import {browserHistory} from '$stores/BrowserHistory'; import {FaExpandAlt} from 'react-icons/fa'; import {checkIfneedsUpdate} from '$lib/needsUpdate'; import {settingsService} from '$lib/Services/SettingsService'; -import {linkServices} from '$stores/globalLink'; +import {linkServices} from '$lib/Services/globalServices'; import {useRouter} from 'next/router'; import Image from 'next/image'; import isMobile from 'is-mobile'; @@ -138,7 +138,7 @@ function AppBase() { Analytics.pageView({ page_title: path.pathName as string }) - historyTracker.addPage(path.pathName) + browserHistory.addPage(path.pathName) }) }, [router]) return <> diff --git a/src/components/pages/Composer/ComposerCache.ts b/src/components/pages/Composer/ComposerCache.ts index 8028d513..4f1bf8e2 100644 --- a/src/components/pages/Composer/ComposerCache.ts +++ b/src/components/pages/Composer/ComposerCache.ts @@ -2,7 +2,7 @@ import {CACHE_DATA, NOTES_PER_COLUMN, TEMPO_CHANGERS} from "$config" import Color from "color" import {LINE_SCALE_MODE, settings, SmoothGraphics as Graphics} from '@pixi/graphics-smooth'; import {Application, Rectangle, SCALE_MODES, Texture} from 'pixi.js' -import {NoteLayer} from "$lib/Layer"; +import {NoteLayer} from "$lib/Songs/Layer"; settings.LINE_SCALE_MODE = LINE_SCALE_MODE.NORMAL const {horizontalLineBreak, standards, layersCombination, breakpoints} = CACHE_DATA diff --git a/src/components/pages/Composer/ComposerCanvas.tsx b/src/components/pages/Composer/ComposerCanvas.tsx index dec981e6..acf9bded 100644 --- a/src/components/pages/Composer/ComposerCanvas.tsx +++ b/src/components/pages/Composer/ComposerCanvas.tsx @@ -16,7 +16,7 @@ import {ComposerCache} from "$cmp/pages/Composer/ComposerCache" import {APP_NAME} from "$config" import Memoized from '$cmp/shared/Utility/Memoized'; import {ThemeProvider} from '$stores/ThemeStore/ThemeProvider'; -import {clamp, colorToRGB, nearestEven} from '$lib/Utilities'; +import {clamp, colorToRGB, nearestEven} from '$lib/utils/Utilities'; import type {NoteColumn} from '$lib/Songs/SongClasses'; import type {ComposerSettingsDataType} from '$lib/BaseSettings'; import {isColumnVisible, RenderColumn} from '$cmp/pages/Composer/RenderColumn'; diff --git a/src/components/pages/Composer/ComposerKeyboard.tsx b/src/components/pages/Composer/ComposerKeyboard.tsx index 4f87e9b3..bddf0781 100644 --- a/src/components/pages/Composer/ComposerKeyboard.tsx +++ b/src/components/pages/Composer/ComposerKeyboard.tsx @@ -1,7 +1,7 @@ import ComposerNote from "$cmp/pages/Composer/ComposerNote" import {NoteColumn, InstrumentData} from "$lib/Songs/SongClasses" import {NoteNameType, Pitch, TEMPO_CHANGERS} from "$config" -import {Instrument, ObservableNote} from "$lib/Instrument" +import {Instrument, ObservableNote} from "$lib/audio/Instrument" import {ComposerSettingsDataType} from "$lib/BaseSettings" import {FaChevronLeft, FaChevronRight} from "react-icons/fa" import {useTheme} from "$lib/Hooks/useTheme" diff --git a/src/components/pages/Composer/ComposerMenu.tsx b/src/components/pages/Composer/ComposerMenu.tsx index 540676dd..2d614ad6 100644 --- a/src/components/pages/Composer/ComposerMenu.tsx +++ b/src/components/pages/Composer/ComposerMenu.tsx @@ -15,11 +15,11 @@ import { FaTrash } from 'react-icons/fa'; import {APP_NAME} from '$config' -import {MenuItem} from '$cmp/shared/Miscellaneous/MenuItem' -import MenuPanel from '$cmp/shared/pagesLayout/MenuPanel' +import {MenuButton, MenuItem} from '$cmp/shared/Menu/MenuItem' +import {MenuPanel, MenuPanelWrapper} from '$cmp/shared/Menu/MenuPanel' import DonateButton from '$cmp/shared/Miscellaneous/DonateButton' import Memoized from '$cmp/shared/Utility/Memoized'; -import Analytics from '$lib/Stats'; +import Analytics from '$lib/Analytics'; import {logger} from '$stores/LoggerStore'; import {AppButton} from '$cmp/shared/Inputs/AppButton'; import {SongMenu} from '$cmp/shared/pagesLayout/SongMenu'; @@ -50,7 +50,8 @@ import {FileElement, FilePicker} from '$cmp/shared/Inputs/FilePicker'; import isMobile from 'is-mobile'; import Link from 'next/link'; import {useConfig} from '$lib/Hooks/useConfig'; -import {isAudioFormat, isMidiFormat, isVideoFormat} from '$lib/Utilities'; +import {isAudioFormat, isMidiFormat, isVideoFormat} from '$lib/utils/Utilities'; +import {MenuContextProvider, MenuSidebar} from "$cmp/shared/Menu/MenuContent"; interface MenuProps { data: { @@ -126,16 +127,6 @@ function Menu({data, functions, inPreview}: MenuProps) { folderStore.createFolder(name) }, []) - const selectSideMenu = useCallback((selection?: MenuTabs) => { - if (selection === selectedMenu && isOpen) { - return setOpen(false) - } - setOpen(true) - if (selection) { - setSelectedMenu(selection) - Analytics.UIEvent('menu', {tab: selection}) - } - }, [isOpen, selectedMenu]) const importFile = useCallback(async (files: FileElement[]) => { for (const file of files) { try { @@ -178,7 +169,6 @@ function Menu({data, functions, inPreview}: MenuProps) { logger.error('Error downloading song') } }, []) - const sideClass = (isOpen && isVisible) ? "side-menu menu-open" : "side-menu" const songFunctions = { loadSong, removeSong, @@ -186,166 +176,177 @@ function Menu({data, functions, inPreview}: MenuProps) { downloadSong, renameSong } - const hasUnsaved = data.hasChanges ? "margin-top-auto not-saved" : "margin-top-auto" - const menuClass = isVisible ? "menu menu-visible" : "menu" - return <> -
setVisible(!isVisible)}> + return +
setVisible(!isVisible)}>
-
-
- toggleMenu()} className='close-menu' ariaLabel='Close menu'> - - - - - - - - selectSideMenu("Songs")} isActive={isOpen && selectedMenu === "Songs"} - ariaLabel='Song menu'> - - - - - selectSideMenu("Settings")} isActive={isOpen && selectedMenu === "Settings"} - ariaLabel='Settings menu'> - - - - - changePage('Home')} ariaLabel='Open home menu' - style={{border: "solid 0.1rem var(--secondary)"}}> - - - - -
-
- -
- -
    -
  • Click the song name to load it
  • -
  • You can use different instruments and pitch for each layer
  • -
  • Tempo changers help you make faster parts of a song without having very high bpm -
  • -
  • You can quickly create a song by importing a MIDI file and editing it, not all songs - are convertable directly, you might need to edit it a bit. -
  • -
  • You can also quickly create a song from audio / video, this is an experimental - feature and not very accurate -
  • -
  • - You can add breakpoints to the timeline (the bar below the composer) to quickly jump - between parts of a song -
  • -
-
- { - changeMidiVisibility(true); + + toggleMenu()} className='close-menu' ariaLabel='Close menu'> + + + + + + + + + + + + + + + + + + changePage('Home')} + ariaLabel='Open home menu' + style={{border: "solid 0.1rem var(--secondary)"}} + > + + + + + + + +
+ +
    +
  • Click the song name to load it
  • +
  • You can use different instruments and pitch for each layer
  • +
  • Tempo changers help you make faster parts of a song without having very high bpm +
  • +
  • You can quickly create a song by importing a MIDI file and editing it, not all songs + are convertable directly, you might need to edit it a bit. +
  • +
  • You can also quickly create a song from audio / video, this is an experimental + feature and not very accurate +
  • +
  • + You can add breakpoints to the timeline (the bar below the composer) to quickly jump + between parts of a song +
  • +
+
+ { + changeMidiVisibility(true); + toggleMenu() + }} + style={{marginLeft: 'auto'}} + > + Create from MIDI/Audio + + + Create new song + +
+ + songs={songs} + exclude={excludedSongs} + SongComponent={SongRow} + style={{marginTop: '0.6rem'}} + onCreateFolder={createFolder} + componentProps={{ + theme, + folders, + functions: songFunctions + }} + /> +
+ + onPick={importFile} + onError={(e, files) => { + if (e) console.error(e) + if (files?.length > 0) { + const file = files![0] + const name = file.name + if (isMidiFormat(name)) logger.warn(`Opening the midi importer to import a MIDI file, please reselect the file`, 6000) + else if (isVideoFormat(name)) logger.warn(`Opening the midi importer to import a video file, please reselect the file. Video conversion is not very accurate`, 6000) + else if (isAudioFormat(name)) logger.warn(`Opening the midi importer to import an audio file, please reselect the file. Audio conversion is not very accurate`, 6000) + else return logger.error(`Error importing file, invalid format`, 8000) + changeMidiVisibility(true) toggleMenu() - }} - style={{marginLeft: 'auto'}} - > - Create from MIDI/Audio - - - Create new song - -
- - songs={songs} - exclude={excludedSongs} - SongComponent={SongRow} - style={{marginTop: '0.6rem'}} - onCreateFolder={createFolder} - componentProps={{ - theme, - folders, - functions: songFunctions + } else { + logger.error( + `Error importing file, invalid format, if it's a MIDI,Video or audio file, use the "Create from MIDI" button`, + 8000 + ) + } }} - /> -
- - onPick={importFile} - onError={(e, files) => { - if (e) console.error(e) - if (files?.length > 0) { - const file = files![0] - const name = file.name - if (isMidiFormat(name)) logger.warn(`Opening the midi importer to import a MIDI file, please reselect the file`, 6000) - else if (isVideoFormat(name)) logger.warn(`Opening the midi importer to import a video file, please reselect the file. Video conversion is not very accurate`, 6000) - else if (isAudioFormat(name)) logger.warn(`Opening the midi importer to import an audio file, please reselect the file. Audio conversion is not very accurate`, 6000) - else return logger.error(`Error importing file, invalid format`, 8000) - changeMidiVisibility(true) - toggleMenu() - } else { - logger.error( - `Error importing file, invalid format, if it's a MIDI,Video or audio file, use the "Create from MIDI" button`, - 8000 - ) - } - }} - as='json' - multiple={true} - > - - Import song sheet - - -
-
- { - setOpen(false) - setTimeout(() => { - functions.startRecordingAudio(!data.isRecordingAudio) - }, 300) - }} - toggled={data.isRecordingAudio} - > - {data.isRecordingAudio ? "Stop recording audio" : "Start recording audio"} + as='json' + multiple={true} + > + + Import song sheet -
-
- - -
- {IS_MIDI_AVAILABLE && - - - Connect MIDI keyboard - - - - } - e.preventDefault()}> + +
+
+ { + setOpen(false) + setTimeout(() => { + functions.startRecordingAudio(!data.isRecordingAudio) + }, 300) + }} + toggled={data.isRecordingAudio} + > + {data.isRecordingAudio ? "Stop recording audio" : "Start recording audio"} + +
+
+ + +
+ {IS_MIDI_AVAILABLE && + changePage('theme')} style={{width: 'fit-content'}} > - Change app theme + Connect MIDI keyboard -
- -
-
-
- + } + e.preventDefault()}> + changePage('theme')} + style={{width: 'fit-content'}} + > + Change app theme + + + +
+ + + +
+ } diff --git a/src/components/pages/Composer/ComposerNote.tsx b/src/components/pages/Composer/ComposerNote.tsx index 1a2b7094..7682df64 100644 --- a/src/components/pages/Composer/ComposerNote.tsx +++ b/src/components/pages/Composer/ComposerNote.tsx @@ -3,10 +3,10 @@ import {APP_NAME, INSTRUMENTS_DATA, NOTES_CSS_CLASSES} from "$config" import GenshinNoteBorder from '$cmp/shared/Miscellaneous/GenshinNoteBorder' import SvgNote, {NoteImage} from '$cmp/shared/SvgNotes' import {Theme, ThemeProvider} from '$stores/ThemeStore/ThemeProvider' -import {ObservableNote} from '$lib/Instrument' +import {ObservableNote} from '$lib/audio/Instrument' import {InstrumentName} from '$types/GeneralTypes' -import {LayerStatus} from '$lib/Layer' -import {preventDefault} from "$lib/Utilities"; +import {LayerStatus} from '$lib/Songs/Layer' +import {preventDefault} from "$lib/utils/Utilities"; export type ComposedNoteStatus = 0 | 1 | 2 | 3 diff --git a/src/components/pages/Composer/InstrumentControls/InstrumentSettingsPopup.tsx b/src/components/pages/Composer/InstrumentControls/InstrumentSettingsPopup.tsx index 2a9ce681..53adb964 100644 --- a/src/components/pages/Composer/InstrumentControls/InstrumentSettingsPopup.tsx +++ b/src/components/pages/Composer/InstrumentControls/InstrumentSettingsPopup.tsx @@ -5,7 +5,7 @@ import {HelpTooltip} from "$cmp/shared/Utility/HelpTooltip" import useClickOutside from "$lib/Hooks/useClickOutside" import {InstrumentNoteIcon} from "$lib/Songs/ComposedSong" import {InstrumentData} from "$lib/Songs/SongClasses" -import {capitalize, prettyPrintInstrumentName} from "$lib/Utilities" +import {capitalize, prettyPrintInstrumentName} from "$lib/utils/Utilities" import {FaArrowDown, FaArrowUp, FaTrash, FaVolumeMute, FaVolumeUp} from "react-icons/fa" import {InstrumentSelect} from "$cmp/shared/Inputs/InstrumentSelect" import s from '$cmp/shared/Settings/Settings.module.css' diff --git a/src/components/pages/Composer/InstrumentControls/index.tsx b/src/components/pages/Composer/InstrumentControls/index.tsx index 64dfcfd1..3a30c02b 100644 --- a/src/components/pages/Composer/InstrumentControls/index.tsx +++ b/src/components/pages/Composer/InstrumentControls/index.tsx @@ -7,7 +7,7 @@ import {BiSquareRounded} from "react-icons/bi"; import {Theme} from "$stores/ThemeStore/ThemeProvider"; import {InstrumentSettingsPopup} from "./InstrumentSettingsPopup"; -import {prettyPrintInstrumentName} from "$lib/Utilities"; +import {prettyPrintInstrumentName} from "$lib/utils/Utilities"; interface InstrumentControlsProps { diff --git a/src/components/pages/Composer/MidiParser/TrackInfo.tsx b/src/components/pages/Composer/MidiParser/TrackInfo.tsx index 19f10a58..437ea956 100644 --- a/src/components/pages/Composer/MidiParser/TrackInfo.tsx +++ b/src/components/pages/Composer/MidiParser/TrackInfo.tsx @@ -7,7 +7,7 @@ import {Select} from '$cmp/shared/Inputs/Select' import {Theme} from '$stores/ThemeStore/ThemeProvider' import {hasTooltip, Tooltip} from '$cmp/shared/Utility/Tooltip' import {NumericalInput} from './Numericalinput' -import {prettyPrintInstrumentName} from '$lib/Utilities' +import {prettyPrintInstrumentName} from '$lib/utils/Utilities' import {Column} from "$cmp/shared/layout/Column"; import {Row} from "$cmp/shared/layout/Row"; diff --git a/src/components/pages/Composer/MidiParser/index.tsx b/src/components/pages/Composer/MidiParser/index.tsx index d326b5d0..db801dec 100644 --- a/src/components/pages/Composer/MidiParser/index.tsx +++ b/src/components/pages/Composer/MidiParser/index.tsx @@ -1,7 +1,7 @@ import {Component} from 'react' import {FileElement, FilePicker} from '$cmp/shared/Inputs/FilePicker' import {Midi, Track} from '@tonejs/midi' -import {delay, groupNotesByIndex, isAudioFormat, isVideoFormat, mergeLayers} from '$lib/Utilities' +import {delay, groupNotesByIndex, isAudioFormat, isVideoFormat, mergeLayers} from '$lib/utils/Utilities' import {NoteColumn, ColumnNote, InstrumentData, MidiNote} from '$lib/Songs/SongClasses' import {ComposedSong} from '$lib/Songs/ComposedSong' import {BASE_PATH, Pitch, PITCHES} from '$config' @@ -9,13 +9,13 @@ import {logger} from '$stores/LoggerStore' import {Theme, ThemeProvider} from '$stores/ThemeStore/ThemeProvider' import {observe} from 'mobx' import Switch from '$cmp/shared/Inputs/Switch' -import {NoteLayer} from '$lib/Layer' +import {NoteLayer} from '$lib/Songs/Layer' import {HelpTooltip} from '$cmp/shared/Utility/HelpTooltip' import {PitchSelect} from '$cmp/shared/Inputs/PitchSelect' import {DecoratedCard} from '$cmp/shared/layout/DecoratedCard' import {TrackInfo} from './TrackInfo' import {NumericalInput} from './Numericalinput' -import {basicPitchLoader} from '$lib/BasicPitchLoader' +import {basicPitchLoader} from '$lib/audio/BasicPitchLoader' import {Row} from "$cmp/shared/layout/Row"; import {Column} from "$cmp/shared/layout/Column"; diff --git a/src/components/pages/Index/HelpTab/ShortcutsHelp.tsx b/src/components/pages/Index/HelpTab/ShortcutsHelp.tsx index ba110a2b..1aad4889 100644 --- a/src/components/pages/Index/HelpTab/ShortcutsHelp.tsx +++ b/src/components/pages/Index/HelpTab/ShortcutsHelp.tsx @@ -1,6 +1,6 @@ import {Shortcut} from '$stores/KeybindsStore' import sh from '$cmp/pages/Index/HelpTab/HelpTab.module.css' -import {Stylable} from "$lib/UtilTypes"; +import {Stylable} from "$lib/utils/UtilTypes"; interface KeyProps { children: React.ReactNode diff --git a/src/components/pages/Index/Home.tsx b/src/components/pages/Index/Home.tsx index 6379a3a2..b8fa23fd 100644 --- a/src/components/pages/Index/Home.tsx +++ b/src/components/pages/Index/Home.tsx @@ -4,7 +4,7 @@ import {APP_NAME, BASE_PATH, IS_BETA} from "$config" import {useEffect, useState} from 'react' import Link from 'next/link' import {useTheme} from '$lib/Hooks/useTheme' -import {MenuItem} from '$cmp/shared/Miscellaneous/MenuItem' +import {MenuButton} from '$cmp/shared/Menu/MenuItem' import {KeyboardProvider} from '$lib/Providers/KeyboardProvider' import {AppButton} from '$cmp/shared/Inputs/AppButton' import {VsrgIcon} from '$cmp/shared/icons/VsrgIcon' @@ -12,7 +12,7 @@ import {VsrgComposerIcon} from '$cmp/shared/icons/VsrgComposerIcon' import {useObservableObject} from '$lib/Hooks/useObservable' import {homeStore} from '$stores/HomeStore' import {useRouter} from 'next/router' -import {clearClientCache, isTWA} from '$lib/Utilities' +import {clearClientCache, isTWA} from '$lib/utils/Utilities' import {useConfig} from '$lib/Hooks/useConfig' import {asyncConfirm} from '$cmp/shared/Utility/AsyncPrompts' import {MdOutlinePiano} from "react-icons/md"; @@ -39,7 +39,7 @@ export default function Home({askForStorage, hasVisited, setDontShowHome, closeW const [theme] = useTheme() async function clearCache() { - if(!await asyncConfirm("Are you sure you want to clear the cache? The page will reload")) return + if (!await asyncConfirm("Are you sure you want to clear the cache? The page will reload")) return clearClientCache() .then(() => { logger.success("Cache Cleared") @@ -91,13 +91,13 @@ export default function Home({askForStorage, hasVisited, setDontShowHome, closeW overflowX: 'hidden' }} > - - +
{(breakpoint || !hasVisited) &&
diff --git a/src/components/pages/Index/Logger.tsx b/src/components/pages/Index/Logger.tsx index 25f8839e..6c89d541 100644 --- a/src/components/pages/Index/Logger.tsx +++ b/src/components/pages/Index/Logger.tsx @@ -1,7 +1,7 @@ import {logger, LoggerStatus, ToastState} from "$stores/LoggerStore" import {FaCheckCircle, FaExclamationTriangle, FaTimesCircle} from "react-icons/fa" import {useObservableArray, useObservableObject} from "$lib/Hooks/useObservable" -import {DecoratedCard} from "../../shared/layout/DecoratedCard" +import {DecoratedCard} from "$cmp/shared/layout/DecoratedCard"; export default function FloatingMessage() { const toasts = useObservableArray(logger.toasts) @@ -29,8 +29,7 @@ interface ToastProps { function Toast({toast}: ToastProps) { - const observableToast = useObservableObject(toast) - const {text, type, id, timeout, visible} = observableToast + const {text, type, id, timeout, visible} = useObservableObject(toast) const isBig = text.length > 150 return -
+ + return + {isOpen && - + - + } - selectSideMenu("Help")} className="margin-top-auto" - isActive={selectedMenu === "Help" && isOpen} ariaLabel='Open info menu'> + - selectSideMenu("Library")} isActive={selectedMenu === "Library" && isOpen} - ariaLabel='Open library menu'> + - selectSideMenu("Songs")} isActive={selectedMenu === "Songs" && isOpen} - ariaLabel='Open songs menu'> + - selectSideMenu("Settings")} isActive={selectedMenu === "Settings" && isOpen} - ariaLabel='Open settings'> + - + - -
-
- + + + + Select a menu - +
    @@ -328,7 +336,7 @@ function Menu({functions, data, inPreview}: MenuProps) {
- + - +
Here you can find songs to learn, they are provided by the sky-music library.
@@ -431,7 +439,7 @@ function Menu({functions, data, inPreview}: MenuProps) {
- + -
+ + } diff --git a/src/components/pages/Player/PlayerNote.tsx b/src/components/pages/Player/PlayerNote.tsx index a0e914a8..2d6db2c5 100644 --- a/src/components/pages/Player/PlayerNote.tsx +++ b/src/components/pages/Player/PlayerNote.tsx @@ -4,11 +4,11 @@ import GenshinNoteBorder from '$cmp/shared/Miscellaneous/GenshinNoteBorder' import SvgNote from '$cmp/shared/SvgNotes' import {observe} from 'mobx' import {ThemeProvider} from '$stores/ThemeStore/ThemeProvider' -import type {ObservableNote} from '$lib/Instrument' +import type {ObservableNote} from '$lib/audio/Instrument' import type {InstrumentName, NoteStatus} from '$types/GeneralTypes' import type {ApproachingNote} from '$lib/Songs/SongClasses' import {useObservableObject} from '$lib/Hooks/useObservable' -import {preventDefault} from "$lib/Utilities"; +import {preventDefault} from "$lib/utils/Utilities"; function getTextColor() { const noteBg = ThemeProvider.get('note_background') diff --git a/src/components/pages/Player/PlayerSlider.tsx b/src/components/pages/Player/PlayerSlider.tsx index 59e70053..ac50ba2b 100644 --- a/src/components/pages/Player/PlayerSlider.tsx +++ b/src/components/pages/Player/PlayerSlider.tsx @@ -1,7 +1,7 @@ import {DEFAULT_DOM_RECT} from "$config" import Memoized from "$cmp/shared/Utility/Memoized" import {useObservableObject} from "$lib/Hooks/useObservable" -import {clamp} from "$lib/Utilities" +import {clamp} from "$lib/utils/Utilities" import {memo, useEffect, useRef, useState} from "react" import {BsTriangleFill} from "react-icons/bs" import {playerControlsStore} from "$stores/PlayerControlsStore" diff --git a/src/components/pages/Player/menu.css b/src/components/pages/Player/menu.css index 1db6f391..5dc2e42e 100644 --- a/src/components/pages/Player/menu.css +++ b/src/components/pages/Player/menu.css @@ -3,32 +3,6 @@ --panel-size: 40vw; } -.menu { - width: var(--menu-size); - background-color: var(--primary); - height: 100%; - border-right: solid 2px var(--secondary); - gap: 0.5rem; - border-left: solid 2px var(--secondary); - align-items: center; - flex-direction: column; - padding: 0.4rem 0; - max-height: 100%; - overflow-y: auto; - z-index: 15; - display: flex; - margin-left: -4rem; - transition: all 0.3s; -} - -.menu-visible { - margin-left: 0; -} - -.margin-top-auto { - margin-top: auto; -} - .menu-main-page { opacity: 0.9; } @@ -91,21 +65,6 @@ border-radius: 1rem; } -.menu-wrapper { - position: fixed; - left: 0; - top: 0; - height: 100%; - min-height: 100%; - display: flex; - flex-direction: row; - z-index: 11; -} - -.menu-wrapper-absolute { - position: absolute; -} - .library-search-result-text { width: 100%; height: 100%; @@ -114,44 +73,6 @@ display: flex; } -.side-menu { - width: var(--panel-size); - border-radius: 0.3rem; - border-top-left-radius: unset; - border-bottom-left-radius: unset; - height: 100%; - background-color: var(--menu-background); - color: var(--menu-background-text); - transform: scale(0.9) translateX(0); - transition: all 0.3s; - opacity: 0; - padding: 1rem; - display: flex; - left: calc(var(--panel-size) * -1); - position: fixed; -} - -.menu-open { - transform: scale(1) translateX(calc(var(--panel-size) + var(--menu-size))); - opacity: 1; - --backdrop-amount: 4px; - animation: delayBackdrop calc(0.3s * 1.2); - animation-fill-mode: forwards; -} - -.menu-panel { - width: 100%; - display: none; - flex: 1; - flex-direction: column; - -} - -.menu-panel-visible { - display: flex; - animation: appearLeft 0.3s; -} - .songs-buttons-wrapper { display: flex; width: 100%; @@ -264,15 +185,6 @@ transition: all 0.2s; } -.panel-content-wrapper { - display: flex; - flex-direction: column; - flex: 1; - overflow-y: scroll; - overflow-x: hidden; - margin-right: -0.5rem; - padding-right: 0.5rem; -} .song-button { display: flex; @@ -368,87 +280,16 @@ align-items: center; } -.menu-title { - font-size: 2rem; - width: 100%; - display: flex; - justify-content: center; - margin-bottom: 1rem; -} - -.menu::-webkit-scrollbar-thumb { - background: var(--icon-color); - border-radius: 2px; -} - -.menu::-webkit-scrollbar { - width: 3px; -} - -.menu-item { - background-color: var(--primary); - border: none; - width: 2.8rem; - height: 2.8rem; - min-height: 2.8rem; - border-radius: 0.5rem; - display: flex; - justify-content: center; - align-items: center; - color: var(--icon-color); - cursor: pointer; - transition: all 0.3s; -} - -.menu-item a { - color: var(--icon-color); - display: flex; - width: 100%; - height: 100%; - justify-content: center; - align-items: center; -} - -.menu-item:hover { - filter: brightness(1.2); -} @media only screen and (max-width: 920px) { :root { --menu-size: 3.6rem; } - .side-menu { - padding: 0.5rem; - --panel-size: 60vw; - } - - .menu-title { - display: none; - font-size: 1rem; - margin-bottom: 0.5rem; - justify-content: flex-start; - } - - .menu { - width: var(--menu-size); - gap: 0.4rem; - padding: 0.3rem 0; - } - - .menu-item { - width: 2.8rem; - height: 2.8rem; - } - .tab-selector-wrapper { margin-top: 0.5rem; } - .panel-content-wrapper { - margin-right: -0.3rem; - padding-right: 0.2rem; - } } @media screen and (orientation: portrait) { diff --git a/src/components/pages/SheetVisualizer/Menu.tsx b/src/components/pages/SheetVisualizer/Menu.tsx index b5b44da1..3d7a0e17 100644 --- a/src/components/pages/SheetVisualizer/Menu.tsx +++ b/src/components/pages/SheetVisualizer/Menu.tsx @@ -1,16 +1,17 @@ import {useState} from 'react' import {SongMenu} from '$cmp/shared/pagesLayout/SongMenu' import {useSongs} from '$lib/Hooks/useSongs' -import {historyTracker} from '$stores/History' -import {MenuItem} from '$cmp/shared/Miscellaneous/MenuItem' +import {browserHistory} from '$stores/BrowserHistory' +import {MenuButton, MenuItem} from '$cmp/shared/Menu/MenuItem' import {FaArrowLeft, FaHome, FaMusic, FaTimes} from 'react-icons/fa' import {homeStore} from '$stores/HomeStore' -import MenuPanel from '$cmp/shared/pagesLayout/MenuPanel' +import {MenuPanel, MenuPanelWrapper} from '$cmp/shared/Menu/MenuPanel' import {SerializedSong, SongStorable} from '$lib/Songs/Song' import useClickOutside from '$lib/Hooks/useClickOutside' import {songService} from '$lib/Services/SongService' import {logger} from '$stores/LoggerStore' import {useRouter} from 'next/router' +import {MenuContextProvider, MenuSidebar} from "$cmp/shared/Menu/MenuContent"; interface SheetVisualiserMenuProps { currentSong: SerializedSong | null, @@ -21,14 +22,20 @@ export function SheetVisualiserMenu({currentSong, onSongLoaded}: SheetVisualiser const [songs] = useSongs() const history = useRouter() const [selectedPage, setSelectedPage] = useState("") - const sideClass = selectedPage === 'Songs' ? "side-menu menu-open" : "side-menu" + const [open, setOpen] = useState(false) const menuRef = useClickOutside(() => { - setSelectedPage("") + setOpen(false) }, {ignoreFocusable: true, active: selectedPage !== ""}) - return
-
- {(historyTracker.hasNavigated && selectedPage === "") && - + + {(browserHistory.hasNavigated && selectedPage === "") && + { @@ -36,31 +43,27 @@ export function SheetVisualiserMenu({currentSong, onSongLoaded}: SheetVisualiser }} > - + } {selectedPage !== "" && - setSelectedPage("")} + onClick={() => setOpen(false)} > - + } - { - setSelectedPage(selectedPage === "Songs" ? "" : "Songs") - }} ariaLabel='Open songs menu'> + - - - + - -
-
- + + + + songs={songs} className='noprint' @@ -72,8 +75,9 @@ export function SheetVisualiserMenu({currentSong, onSongLoaded}: SheetVisualiser }} /> -
-
+ + + } interface SongRowProps { diff --git a/src/components/pages/SheetVisualizer/SheetFrame.tsx b/src/components/pages/SheetVisualizer/SheetFrame.tsx index dfc8671f..cb5892a2 100644 --- a/src/components/pages/SheetVisualizer/SheetFrame.tsx +++ b/src/components/pages/SheetVisualizer/SheetFrame.tsx @@ -2,7 +2,7 @@ import {APP_NAME, NoteNameType} from "$config" import {Chunk} from "$lib/Songs/VisualSong" import {memo, useEffect, useState} from "react" import {Theme} from "$stores/ThemeStore/ThemeProvider" -import {Instrument} from '$lib/Instrument' +import {Instrument} from '$lib/audio/Instrument' import s from "./SheetFrame.module.css" diff --git a/src/components/pages/SheetVisualizer/SheetFrame2.tsx b/src/components/pages/SheetVisualizer/SheetFrame2.tsx index 95965585..8e2f3046 100644 --- a/src/components/pages/SheetVisualizer/SheetFrame2.tsx +++ b/src/components/pages/SheetVisualizer/SheetFrame2.tsx @@ -2,7 +2,7 @@ import {APP_NAME, NoteNameType} from "$config" import {TempoChunk} from "$lib/Songs/VisualSong" import {memo, useEffect, useState} from "react" import {Theme} from "$stores/ThemeStore/ThemeProvider" -import {Instrument} from '$lib/Instrument' +import {Instrument} from '$lib/audio/Instrument' import s from "./SheetFrame.module.css" diff --git a/src/components/pages/Theme/ThemePropriety.tsx b/src/components/pages/Theme/ThemePropriety.tsx index e67212ca..6ac20937 100644 --- a/src/components/pages/Theme/ThemePropriety.tsx +++ b/src/components/pages/Theme/ThemePropriety.tsx @@ -1,6 +1,6 @@ import {useEffect, useState} from "react"; import {ThemeKeys, ThemeProvider} from "$stores/ThemeStore/ThemeProvider"; -import {capitalize} from "$lib/Utilities"; +import {capitalize} from "$lib/utils/Utilities"; import Color from "color"; import {HexAlphaColorPicker, HexColorInput} from "react-colorful"; import {BASE_THEME_CONFIG} from "$config"; diff --git a/src/components/pages/VsrgComposer/MultipleOptionSlider.tsx b/src/components/pages/VsrgComposer/MultipleOptionSlider.tsx index f336e070..c22efc98 100644 --- a/src/components/pages/VsrgComposer/MultipleOptionSlider.tsx +++ b/src/components/pages/VsrgComposer/MultipleOptionSlider.tsx @@ -1,4 +1,4 @@ -import {capitalize} from "$lib/Utilities" +import {capitalize} from "$lib/utils/Utilities" import React, {useEffect, useRef, useState} from "react" export type Option = { diff --git a/src/components/pages/VsrgComposer/VsrgComposerCache.ts b/src/components/pages/VsrgComposer/VsrgComposerCache.ts index a3b33fc5..3603ba81 100644 --- a/src/components/pages/VsrgComposer/VsrgComposerCache.ts +++ b/src/components/pages/VsrgComposer/VsrgComposerCache.ts @@ -2,7 +2,7 @@ import Color from "color" import {LINE_SCALE_MODE, settings, SmoothGraphics as Graphics} from '@pixi/graphics-smooth'; import {Application, Rectangle, SCALE_MODES, Texture,} from 'pixi.js' import {VsrgCanvasColors, VsrgCanvasSizes} from "./VsrgComposerCanvas"; -import {clamp} from "$lib/Utilities"; +import {clamp} from "$lib/utils/Utilities"; import isMobile from "is-mobile"; settings.LINE_SCALE_MODE = LINE_SCALE_MODE.NORMAL diff --git a/src/components/pages/VsrgComposer/VsrgComposerCanvas.tsx b/src/components/pages/VsrgComposer/VsrgComposerCanvas.tsx index 6f6513ff..3bd75c20 100644 --- a/src/components/pages/VsrgComposer/VsrgComposerCanvas.tsx +++ b/src/components/pages/VsrgComposer/VsrgComposerCanvas.tsx @@ -15,8 +15,8 @@ import {VsrgCanvasCache} from "./VsrgComposerCache" import {VsrgKeysRenderer} from "./VsrgKeysRenderer" import {VsrgScrollableTrackRenderer} from "./VsrgScrollableTrackRenderer" import {VsrgTimelineRenderer} from "./VsrgTimelineRenderer" -import {getNearestTo} from "$lib/Utilities" -import {globalConfigStore} from "$stores/GlobalConfig" +import {getNearestTo} from "$lib/utils/Utilities" +import {globalConfigStore} from "$stores/GlobalConfigStore" export type VsrgCanvasSizes = { diff --git a/src/components/pages/VsrgComposer/VsrgComposerMenu.tsx b/src/components/pages/VsrgComposer/VsrgComposerMenu.tsx index e9a8e093..53e782e8 100644 --- a/src/components/pages/VsrgComposer/VsrgComposerMenu.tsx +++ b/src/components/pages/VsrgComposer/VsrgComposerMenu.tsx @@ -1,16 +1,14 @@ import {AppButton} from "$cmp/shared/Inputs/AppButton"; import {SongActionButton} from "$cmp/shared/Inputs/SongActionButton"; -import MenuPanel from "$cmp/shared/pagesLayout/MenuPanel"; +import {MenuPanel, MenuPanelWrapper} from "$cmp/shared/Menu/MenuPanel"; import {SongMenu} from "$cmp/shared/pagesLayout/SongMenu"; -import {MenuItem} from "$cmp/shared/Miscellaneous/MenuItem"; +import {MenuButton, MenuItem} from "$cmp/shared/Menu/MenuItem"; import {SettingsPane} from "$cmp/shared/Settings/SettingsPane"; import {asyncConfirm} from "$cmp/shared/Utility/AsyncPrompts"; import {FloatingDropdown, FloatingDropdownRow, FloatingDropdownText} from "$cmp/shared/Utility/FloatingDropdown"; import {HelpTooltip} from "$cmp/shared/Utility/HelpTooltip"; import Memoized from "$cmp/shared/Utility/Memoized"; import {hasTooltip, Tooltip} from "$cmp/shared/Utility/Tooltip"; -import isMobile from "is-mobile"; -import Analytics from "$lib/Stats"; import {VsrgComposerSettingsDataType} from "$lib/BaseSettings"; import {Folder} from "$lib/Folder"; import useClickOutside from "$lib/Hooks/useClickOutside"; @@ -22,7 +20,7 @@ import {songService} from "$lib/Services/SongService"; import {RecordedSong} from "$lib/Songs/RecordedSong"; import {SerializedSong, SongStorable} from "$lib/Songs/Song"; import {VsrgSong, VsrgTrackModifier} from "$lib/Songs/VsrgSong"; -import {memo, useCallback, useEffect, useState} from "react"; +import {memo, useEffect, useState} from "react"; import { FaBars, FaCog, @@ -46,6 +44,7 @@ import {VsrgComposerHelp} from "./VsrgComposerHelp"; import {logger} from "$stores/LoggerStore"; import ss from "$cmp/shared/Settings/Settings.module.css" import {APP_NAME} from "$config"; +import {MenuContextProvider, MenuSidebar} from "$cmp/shared/Menu/MenuContent"; type MenuTabs = 'Songs' | 'Settings' | 'Help' @@ -82,46 +81,39 @@ function VsrgMenu({ const [songs] = useSongs() const [theme] = useTheme() const menuRef = useClickOutside((e) => { - setOpen(false) - if (isMobile()) setVisible(false) + setVisible(false) }, {active: (isOpen && isVisible), ignoreFocusable: true}) - const toggleMenu = useCallback((override?: boolean) => { - if (typeof override !== "boolean") override = undefined - setVisible((old) => override !== undefined ? override : !old) - }, []) - const selectSideMenu = useCallback((selection?: MenuTabs) => { - if (selection === selectedMenu && isOpen) { - return setOpen(false) - } - setOpen(true) - if (selection) { - setSelectedMenu(selection) - Analytics.UIEvent('menu', {tab: selection}) - } - }, [isOpen, selectedMenu]) - const menuClass = isVisible ? "menu menu-visible" : "menu" - const sideClass = (isOpen && isVisible) ? "side-menu menu-open" : "side-menu" return <> -
setVisible(!isVisible)}> - - - -
-
-
- toggleMenu(false)} className='close-menu' ariaLabel='Close menu'> + +
setVisible(!isVisible)}> + + + +
+ + setVisible(!isVisible)} className='close-menu' ariaLabel='Close menu'> -
- + + - + selectSideMenu("Help")} - isActive={isOpen && selectedMenu === "Help"} + id={'Help'} ariaLabel='Help' > @@ -129,33 +121,33 @@ function VsrgMenu({ selectSideMenu("Songs")} - isActive={isOpen && selectedMenu === "Songs"} + id={'Songs'} ariaLabel='Song menu' > - selectSideMenu("Settings")} isActive={isOpen && selectedMenu === "Settings"} - ariaLabel='Settings menu'> + - + - - -
-
- + + + + - +
Create song @@ -171,12 +163,12 @@ function VsrgMenu({ folders, functions: { onClick: onSongOpen, - toggleMenu + toggleMenu: setVisible } }} /> - + -
-
+ + + } @@ -300,7 +293,7 @@ interface SongRowProps { folders: Folder[] functions: { onClick: (song: VsrgSong) => void - toggleMenu: (override?: boolean) => void + toggleMenu: (override: boolean) => void } } diff --git a/src/components/pages/VsrgComposer/VsrgScrollableTrackRenderer.tsx b/src/components/pages/VsrgComposer/VsrgScrollableTrackRenderer.tsx index a6c95566..acc4f62f 100644 --- a/src/components/pages/VsrgComposer/VsrgScrollableTrackRenderer.tsx +++ b/src/components/pages/VsrgComposer/VsrgScrollableTrackRenderer.tsx @@ -1,6 +1,6 @@ import {Container, Sprite, Text,} from "@pixi/react"; import {VsrgHitObject, VsrgSong} from "$lib/Songs/VsrgSong"; -import {parseMouseClick} from "$lib/Utilities"; +import {parseMouseClick} from "$lib/utils/Utilities"; import {ClickType} from "$types/GeneralTypes" import {FederatedPointerEvent, type Sprite as SpriteType, TextStyle} from "pixi.js"; diff --git a/src/components/pages/VsrgComposer/VsrgTimelineRenderer.tsx b/src/components/pages/VsrgComposer/VsrgTimelineRenderer.tsx index fe091cdf..ea47974d 100644 --- a/src/components/pages/VsrgComposer/VsrgTimelineRenderer.tsx +++ b/src/components/pages/VsrgComposer/VsrgTimelineRenderer.tsx @@ -3,7 +3,7 @@ import {PIXI_VERTICAL_ALIGN} from "$config"; import {RecordedSong} from "$lib/Songs/RecordedSong"; import {RecordedNote} from "$lib/Songs/SongClasses"; import {VsrgSong} from "$lib/Songs/VsrgSong"; -import {clamp} from "$lib/Utilities"; +import {clamp} from "$lib/utils/Utilities"; import {type FederatedPointerEvent, Rectangle} from "pixi.js"; import {useCallback, useEffect, useState} from "react"; import {VsrgCanvasColors, VsrgCanvasSizes} from "./VsrgComposerCanvas"; diff --git a/src/components/pages/VsrgComposer/VsrgTrackRenderer.tsx b/src/components/pages/VsrgComposer/VsrgTrackRenderer.tsx index a4d12812..eb7cf0d3 100644 --- a/src/components/pages/VsrgComposer/VsrgTrackRenderer.tsx +++ b/src/components/pages/VsrgComposer/VsrgTrackRenderer.tsx @@ -1,7 +1,7 @@ import {Container, Sprite} from "@pixi/react"; import {PIXI_CENTER_X_END_Y} from "$config"; import {VsrgHitObject, VsrgTrack} from "$lib/Songs/VsrgSong"; -import {parseMouseClick} from "$lib/Utilities"; +import {parseMouseClick} from "$lib/utils/Utilities"; import {ClickType} from "$types/GeneralTypes" import {Fragment} from "react"; diff --git a/src/components/pages/VsrgPlayer/VsrgPlayerCanvas.tsx b/src/components/pages/VsrgPlayer/VsrgPlayerCanvas.tsx index 6af6b62e..ac1c026a 100644 --- a/src/components/pages/VsrgPlayer/VsrgPlayerCanvas.tsx +++ b/src/components/pages/VsrgPlayer/VsrgPlayerCanvas.tsx @@ -2,7 +2,7 @@ import {Stage} from "@pixi/react"; import {subscribeTheme} from "$lib/Hooks/useTheme"; import {VsrgAccuracyBounds, VsrgHitObject, VsrgSong} from "$lib/Songs/VsrgSong"; import {ThrottledEventLoop} from "$lib/ThrottledEventLoop"; -import {isNumberCloseTo} from "$lib/Utilities"; +import {isNumberCloseTo} from "$lib/utils/Utilities"; import {Application} from "pixi.js"; import {Component, createRef} from "react"; import {keyBinds} from "$stores/KeybindsStore"; diff --git a/src/components/pages/VsrgPlayer/VsrgPlayerMenu.tsx b/src/components/pages/VsrgPlayer/VsrgPlayerMenu.tsx index e1539c41..e1d46ecd 100644 --- a/src/components/pages/VsrgPlayer/VsrgPlayerMenu.tsx +++ b/src/components/pages/VsrgPlayer/VsrgPlayerMenu.tsx @@ -1,13 +1,12 @@ import {AppButton} from "$cmp/shared/Inputs/AppButton"; -import MenuPanel from "$cmp/shared/pagesLayout/MenuPanel"; +import {MenuPanel, MenuPanelWrapper} from "$cmp/shared/Menu/MenuPanel"; import {SongMenu} from "$cmp/shared/pagesLayout/SongMenu"; -import {MenuItem} from "$cmp/shared/Miscellaneous/MenuItem"; +import {MenuButton, MenuItem} from "$cmp/shared/Menu/MenuItem"; import {SettingsPane} from "$cmp/shared/Settings/SettingsPane"; import {asyncConfirm} from "$cmp/shared/Utility/AsyncPrompts"; import {FloatingDropdown, FloatingDropdownRow, FloatingDropdownText} from "$cmp/shared/Utility/FloatingDropdown"; import Memoized from "$cmp/shared/Utility/Memoized"; import {hasTooltip, Tooltip} from "$cmp/shared/Utility/Tooltip"; -import Analytics from "$lib/Stats"; import {VsrgPlayerSettingsDataType} from "$lib/BaseSettings"; import {Folder} from "$lib/Folder"; import useClickOutside from "$lib/Hooks/useClickOutside"; @@ -19,7 +18,7 @@ import {songService} from "$lib/Services/SongService"; import {SongStorable} from "$lib/Songs/Song"; import {VsrgSong} from "$lib/Songs/VsrgSong"; import {VsrgSongSelectType} from "$pages/vsrg-player"; -import {memo, useCallback, useEffect, useState} from "react"; +import {memo, useEffect, useState} from "react"; import { FaBars, FaCog, @@ -33,7 +32,6 @@ import { FaTrash } from "react-icons/fa"; import Link from "next/link"; -import {homeStore} from "$stores/HomeStore"; import {songsStore} from "$stores/SongsStore"; import {Theme} from "$stores/ThemeStore/ThemeProvider"; import {SettingUpdate} from "$types/SettingsPropriety"; @@ -41,6 +39,8 @@ import {logger} from "$stores/LoggerStore"; import isMobile from "is-mobile"; import {useConfig} from "$lib/Hooks/useConfig"; import {APP_NAME} from "$config"; +import {MenuContextProvider, MenuSidebar} from "$cmp/shared/Menu/MenuContent"; +import {homeStore} from "$stores/HomeStore"; type MenuTabs = 'Songs' | 'Settings' @@ -60,66 +60,61 @@ function VsrgMenu({onSongSelect, settings, onSettingsUpdate}: VsrgMenuProps) { const [theme] = useTheme() const {IS_MOBILE} = useConfig() const menuRef = useClickOutside((e) => { - if (isMobile()) return setIsVisible(false) - setOpen(false) + setIsVisible(false) }, {active: isOpen && isVisible, ignoreFocusable: true}) - const selectSideMenu = useCallback((selection?: MenuTabs) => { - if (selection === selectedMenu && isOpen) { - return setOpen(false) - } - setOpen(true) - if (selection) { - setSelectedMenu(selection) - Analytics.UIEvent('menu', {tab: selection}) - } - }, [isOpen, selectedMenu]) - - const sideClass = (isOpen && isVisible) ? "side-menu menu-open" : "side-menu" return <> -
+
setIsVisible(!isVisible)} + onClick={() => setIsVisible(true)} >
-
- + { setIsVisible(false) }} - ariaLabel="Close Menu" + ariaLabel="Close MenuContext" > - + selectSideMenu("Songs")} - isActive={isOpen && selectedMenu === "Songs"} + id={'Songs'} ariaLabel='Song menu' > - selectSideMenu("Settings")} isActive={isOpen && selectedMenu === "Settings"} - ariaLabel='Settings menu'> + + - + - -
-
- - + + + +
@@ -143,7 +138,7 @@ function VsrgMenu({onSongSelect, settings, onSettingsUpdate}: VsrgMenuProps) { }} /> - + }
-
-
-
+ + } diff --git a/src/components/pages/ZenKeyboard/ZenKeyboardMenu.tsx b/src/components/pages/ZenKeyboard/ZenKeyboardMenu.tsx index e3bb66e6..a9bfc964 100644 --- a/src/components/pages/ZenKeyboard/ZenKeyboardMenu.tsx +++ b/src/components/pages/ZenKeyboard/ZenKeyboardMenu.tsx @@ -1,8 +1,8 @@ import useClickOutside from "$lib/Hooks/useClickOutside" import {homeStore} from "$stores/HomeStore" import {FaBars, FaCog, FaHome, FaTimes} from "react-icons/fa" -import MenuPanel from "$cmp/shared/pagesLayout/MenuPanel" -import {MenuItem} from "$cmp/shared/Miscellaneous/MenuItem" +import {MenuPanel, MenuPanelWrapper} from "$cmp/shared/Menu/MenuPanel" +import {MenuButton, MenuItem} from "$cmp/shared/Menu/MenuItem" import {useState} from 'react' import {ZenKeyboardSettingsDataType} from "$lib/BaseSettings" import {SettingUpdate, SettingVolumeUpdate} from "$types/SettingsPropriety" @@ -15,6 +15,7 @@ import {MdPiano} from "react-icons/md"; import {IoMdMusicalNote} from "react-icons/io"; import {GiMetronome} from "react-icons/gi"; import {IconType} from "react-icons"; +import {MenuContextProvider, MenuSidebar} from "$cmp/shared/Menu/MenuContent"; interface ZenKeyboardMenuProps { settings: ZenKeyboardSettingsDataType @@ -38,7 +39,6 @@ export function ZenKeyboardMenu({ const menuRef = useClickOutside(() => { setIsVisible(false) }, {ignoreFocusable: true, active: selectedPage !== ""}) - const sideClass = (isOpen && isVisible) ? "side-menu menu-open" : "side-menu" function toggleMenu() { setIsOpen(!isOpen) @@ -102,9 +102,14 @@ export function ZenKeyboardMenu({ })} />
- -
- +
setIsVisible(!isVisible)} @@ -113,39 +118,35 @@ export function ZenKeyboardMenu({
-
- + setIsVisible(!isVisible)} > - + { - setSelectedPage("Settings") - toggleMenu() - }} - isActive={selectedPage === "Settings" && isOpen} + id={"Settings"} ariaLabel='Open settings' > - + - -
-
- + + + + -
-
+ + } diff --git a/src/components/pages/ZenKeyboard/ZenKeypad.tsx b/src/components/pages/ZenKeyboard/ZenKeypad.tsx index 7d728cc0..3f8e0984 100644 --- a/src/components/pages/ZenKeyboard/ZenKeypad.tsx +++ b/src/components/pages/ZenKeyboard/ZenKeypad.tsx @@ -1,5 +1,5 @@ import {useObservableArray} from "$lib/Hooks/useObservable"; -import {Instrument, ObservableNote} from "$lib/Instrument" +import {Instrument, ObservableNote} from "$lib/audio/Instrument" import {zenKeyboardStore} from "$stores/ZenKeyboardStore"; import {ZenNote} from "./ZenNote"; import {useEffect} from 'react' diff --git a/src/components/pages/ZenKeyboard/ZenNote.tsx b/src/components/pages/ZenKeyboard/ZenNote.tsx index e692db7f..a3bfe675 100644 --- a/src/components/pages/ZenKeyboard/ZenNote.tsx +++ b/src/components/pages/ZenKeyboard/ZenNote.tsx @@ -1,13 +1,13 @@ import {APP_NAME, BASE_THEME_CONFIG, INSTRUMENTS_DATA, NOTES_CSS_CLASSES} from "$config" import {subscribeObeservableObject} from "$lib/Hooks/useObservable" -import {ObservableNote} from "$lib/Instrument" +import {ObservableNote} from "$lib/audio/Instrument" import SvgNote, {NoteImage} from "$cmp/shared/SvgNotes" import {useCallback, useEffect, useRef, useState} from "react" import {ThemeProvider} from "$stores/ThemeStore/ThemeProvider" import GenshinNoteBorder from '$cmp/shared/Miscellaneous/GenshinNoteBorder' import {InstrumentName, NoteStatus} from "$types/GeneralTypes" import s from "./ZenKeyboard.module.css" -import {preventDefault} from "$lib/Utilities"; +import {preventDefault} from "$lib/utils/Utilities"; interface ZenKeyboardProps { note: ObservableNote diff --git a/src/components/pages/blog/BaseBlogPost.tsx b/src/components/pages/blog/BaseBlogPost.tsx index b1adec89..cde4f499 100644 --- a/src/components/pages/blog/BaseBlogPost.tsx +++ b/src/components/pages/blog/BaseBlogPost.tsx @@ -1,6 +1,6 @@ import {BlogAuthor, BlogMetadata} from "$cmp/pages/blog/types"; import {DefaultPage} from "$cmp/shared/pagesLayout/DefaultPage"; -import {MaybeChildren} from "$lib/UtilTypes"; +import {MaybeChildren} from "$lib/utils/UtilTypes"; import s from './blog.module.scss' import {Header} from "$cmp/shared/header/Header"; import {PageMeta} from "$cmp/shared/Miscellaneous/PageMeta"; diff --git a/src/components/pages/blog/BlogUl.tsx b/src/components/pages/blog/BlogUl.tsx index 42cf692a..a25cab58 100644 --- a/src/components/pages/blog/BlogUl.tsx +++ b/src/components/pages/blog/BlogUl.tsx @@ -1,4 +1,4 @@ -import {MaybeChildren, Stylable} from "$lib/UtilTypes"; +import {MaybeChildren, Stylable} from "$lib/utils/UtilTypes"; import s from './blog.module.scss' export function BlogUl({children, ...rest}: MaybeChildren) { diff --git a/src/components/shared/Inputs/ComboBox/ComboBox.tsx b/src/components/shared/Inputs/ComboBox/ComboBox.tsx index 2ed6f24e..69060fea 100644 --- a/src/components/shared/Inputs/ComboBox/ComboBox.tsx +++ b/src/components/shared/Inputs/ComboBox/ComboBox.tsx @@ -1,8 +1,8 @@ import {CSSProperties, ReactNode, useState} from "react"; import useClickOutside from "$lib/Hooks/useClickOutside"; import s from './combobox.module.scss' -import {MaybeChildren, Stylable} from "$lib/UtilTypes"; -import {cn} from "$lib/Utilities"; +import {MaybeChildren, Stylable} from "$lib/utils/UtilTypes"; +import {cn} from "$lib/utils/Utilities"; interface ComboBoxItemData { item: T diff --git a/src/components/shared/Menu/MenuContent.tsx b/src/components/shared/Menu/MenuContent.tsx new file mode 100644 index 00000000..fc2e15b0 --- /dev/null +++ b/src/components/shared/Menu/MenuContent.tsx @@ -0,0 +1,68 @@ +import {MaybeChildren, Stylable} from "$lib/utils/UtilTypes"; +import s from './menu.module.scss' +import {MenuContext, MenuContextState, useMenuContext} from "$cmp/shared/Menu/MenuContext"; +import {cn} from "$lib/utils/Utilities"; +import {ForwardedRef, forwardRef, ReactNode} from "react"; + +export interface MenuProps extends Stylable { + opacity?: number +} + +export function MenuSidebar({ + style, + className, + opacity, + children + }: MaybeChildren) { + const {visible} = useMenuContext() + return
+ {children} +
+} + +export interface MenuContextProviderProps extends Partial>, Stylable { +} + +function _MenuContextProvider({ + children, + className, + style, + current, + open, + setOpen, + setCurrent, + visible, + setVisible + }: MaybeChildren>, + ref: ForwardedRef) { + + return { + }), + open: open ?? false, + setOpen: setOpen ?? (() => { + }), + visible: visible ?? true, + setVisible: setVisible ?? (() => { + }) + }} + > +
+ {children} +
+
+} + +//TODO for some reason react doesn't infer the generics properly in forwardRef +export const MenuContextProvider = forwardRef(_MenuContextProvider) as (props: MaybeChildren & Stylable> & { + ref?: ForwardedRef +}) => ReactNode diff --git a/src/components/shared/Menu/MenuContext.ts b/src/components/shared/Menu/MenuContext.ts new file mode 100644 index 00000000..e62dea6b --- /dev/null +++ b/src/components/shared/Menu/MenuContext.ts @@ -0,0 +1,25 @@ +import {createContext, useContext} from "react"; + + +export type MenuContextState = { + current: T, + setCurrent: (current: NoInfer) => void + open: boolean, + setOpen: (open: boolean) => void + visible: boolean, + setVisible?: (visible: boolean) => void +} + + +export const MenuContext = createContext>({ + current: "", + setCurrent: () => {}, + open: false, + setOpen: () => {}, + visible: true +} satisfies MenuContextState) + + +export function useMenuContext() { + return useContext(MenuContext) as unknown as MenuContextState +} \ No newline at end of file diff --git a/src/components/shared/Menu/MenuItem.tsx b/src/components/shared/Menu/MenuItem.tsx new file mode 100644 index 00000000..cb655160 --- /dev/null +++ b/src/components/shared/Menu/MenuItem.tsx @@ -0,0 +1,52 @@ +import {blurEvent} from "$lib/utils/Utilities" +import s from './menu.module.scss' +import {MaybeChildren, Stylable} from "$lib/utils/UtilTypes"; +import {useMenuContext} from "$cmp/shared/Menu/MenuContext"; + + +interface MenuItemProps extends Stylable { + onClick?: () => void + ariaLabel: string, + id: string +} + +export function MenuItem({className, style, onClick, children, ariaLabel, id}: MaybeChildren) { + const {current, open, visible, setCurrent, setOpen} = useMenuContext() + const isActive = current === id && open && visible + return +} + +interface MenuButtonProps extends Stylable { + onClick?: () => void + ariaLabel: string, +} + +export function MenuButton({className, style, onClick, children, ariaLabel}: MaybeChildren) { + return +} \ No newline at end of file diff --git a/src/components/shared/Menu/MenuPanel.tsx b/src/components/shared/Menu/MenuPanel.tsx new file mode 100644 index 00000000..749d7e4c --- /dev/null +++ b/src/components/shared/Menu/MenuPanel.tsx @@ -0,0 +1,43 @@ +import s from './menu.module.scss' +import {cn} from "$lib/utils/Utilities"; +import {MaybeChildren} from "$lib/utils/UtilTypes"; +import {useMenuContext} from "$cmp/shared/Menu/MenuContext"; + + +export function MenuPanelWrapper({children}: MaybeChildren) { + const {open, visible} = useMenuContext() + + return
+ {children} +
+} + + +interface MenuPanelProps { + title?: string, + id: T, +} + +export function MenuPanel({title, children, id}: MaybeChildren>) { + const {current} = useMenuContext() + return
+ {title && +
+ {title} +
+ } +
+ {children} +
+
+} \ No newline at end of file diff --git a/src/components/shared/Menu/menu.module.scss b/src/components/shared/Menu/menu.module.scss new file mode 100644 index 00000000..ebff8d2c --- /dev/null +++ b/src/components/shared/Menu/menu.module.scss @@ -0,0 +1,173 @@ +//--menu--// +.menu { + width: var(--menu-size); + background-color: var(--primary); + height: 100%; + border-right: solid 2px var(--secondary); + gap: 0.5rem; + border-left: solid 2px var(--secondary); + align-items: center; + flex-direction: column; + padding: 0.4rem 0; + max-height: 100%; + overflow-y: auto; + z-index: 15; + display: flex; + margin-left: -4rem; + transition: all 0.3s; +} + +.menu-visible { + margin-left: 0; +} + +.menu::-webkit-scrollbar-thumb { + background: var(--icon-color); + border-radius: 2px; +} + +.menu::-webkit-scrollbar { + width: 3px; +} + + +//--side menu--// + +.side-menu { + width: var(--panel-size); + border-radius: 0.3rem; + border-top-left-radius: unset; + border-bottom-left-radius: unset; + height: 100%; + background-color: var(--menu-background); + color: var(--menu-background-text); + transform: scale(0.9) translateX(0); + transition: all 0.3s; + opacity: 0; + padding: 1rem; + display: flex; + left: calc(var(--panel-size) * -1); + position: fixed; +} + +.side-menu-open { + transform: scale(1) translateX(calc(var(--panel-size) + var(--menu-size))); + opacity: 1; + --backdrop-amount: 4px; + animation: delayBackdrop calc(0.3s * 1.2); + animation-fill-mode: forwards; +} + +//--menu item--// +.menu-item { + background-color: var(--primary); + border: none; + width: 2.8rem; + height: 2.8rem; + min-height: 2.8rem; + border-radius: 0.5rem; + display: flex; + justify-content: center; + align-items: center; + color: var(--icon-color); + cursor: pointer; + transition: all 0.3s; +} + +.menu-item a { + color: var(--icon-color); + display: flex; + width: 100%; + height: 100%; + justify-content: center; + align-items: center; +} + +.menu-item:hover { + background-color: var(--primary-layer-15); +} + +.menu-item-active { + background-color: var(--primary-layer-20); +} + +.menu-panel { + width: 100%; + display: none; + flex: 1; + flex-direction: column; +} + +.menu-panel-visible { + display: flex; + animation: appearLeft 0.3s; +} + +.menu-title { + font-size: 2rem; + width: 100%; + display: flex; + justify-content: center; + margin-bottom: 1rem; +} + +.panel-content-wrapper { + display: flex; + flex-direction: column; + flex: 1; + overflow-y: scroll; + overflow-x: hidden; + margin-right: -0.5rem; + padding-right: 0.5rem; +} + +.menu-wrapper { + position: fixed; + left: 0; + top: 0; + height: 100%; + min-height: 100%; + display: flex; + flex-direction: row; + z-index: 11; +} + +@media only screen and (max-width: 920px) { + + .menu { + width: var(--menu-size); + gap: 0.4rem; + padding: 0.3rem 0; + } + .side-menu { + padding: 0.5rem; + --panel-size: 60vw; + } + .menu-item { + width: 2.8rem; + height: 2.8rem; + } + + .menu-title { + display: none; + font-size: 1rem; + margin-bottom: 0.5rem; + justify-content: flex-start; + } + .panel-content-wrapper { + margin-right: -0.3rem; + padding-right: 0.2rem; + } +} + +@keyframes appearLeft { + from { + transform: translateX(-0.5rem) var(--existing-transform,); + opacity: 0.6; + } + + to { + transform: translateX(0) var(--existing-transform,); + opacity: 1; + } +} \ No newline at end of file diff --git a/src/components/shared/Miscellaneous/BaseNote.tsx b/src/components/shared/Miscellaneous/BaseNote.tsx index f2bc80a5..7b61e88e 100644 --- a/src/components/shared/Miscellaneous/BaseNote.tsx +++ b/src/components/shared/Miscellaneous/BaseNote.tsx @@ -4,7 +4,7 @@ import {observe} from "mobx" import {useEffect, useState} from "react" import {ThemeProvider} from "$stores/ThemeStore/ThemeProvider" import SvgNotes, {NoteImage} from "$cmp/shared/SvgNotes" -import {preventDefault} from "$lib/Utilities"; +import {preventDefault} from "$lib/utils/Utilities"; type BaseNoteData = { diff --git a/src/components/shared/Miscellaneous/DonateButton.tsx b/src/components/shared/Miscellaneous/DonateButton.tsx index fb0dfef3..f8857980 100644 --- a/src/components/shared/Miscellaneous/DonateButton.tsx +++ b/src/components/shared/Miscellaneous/DonateButton.tsx @@ -1,4 +1,4 @@ -import {isTWA} from '$lib/Utilities' +import {isTWA} from '$lib/utils/Utilities' import Link from 'next/link' import {useEffect, useState} from 'react' diff --git a/src/components/shared/Miscellaneous/MenuItem.tsx b/src/components/shared/Miscellaneous/MenuItem.tsx deleted file mode 100644 index e628a18b..00000000 --- a/src/components/shared/Miscellaneous/MenuItem.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import {useTheme} from "$lib/Hooks/useTheme" -import {blurEvent} from "$lib/Utilities" - -interface MenuItemProps { - className?: string, - onClick?: (data?: T) => void - children?: React.ReactNode, - data?: T, - ariaLabel: string, - current?: string, - style?: React.CSSProperties - isActive?: boolean -} - -export function MenuItem({className = "", onClick, children, data, style, isActive, ariaLabel}: MenuItemProps) { - const [theme] = useTheme() - return -} diff --git a/src/components/shared/Miscellaneous/PageMeta.tsx b/src/components/shared/Miscellaneous/PageMeta.tsx index eb03e4f0..8f21ea3c 100644 --- a/src/components/shared/Miscellaneous/PageMeta.tsx +++ b/src/components/shared/Miscellaneous/PageMeta.tsx @@ -1,5 +1,5 @@ import Head from "next/head"; -import {MaybeChildren} from "$lib/UtilTypes"; +import {MaybeChildren} from "$lib/utils/UtilTypes"; interface PageMetaProps { diff --git a/src/components/shared/ProviderWrappers/GeneralProvidersWrapper.tsx b/src/components/shared/ProviderWrappers/GeneralProvidersWrapper.tsx index d6891590..1359b322 100644 --- a/src/components/shared/ProviderWrappers/GeneralProvidersWrapper.tsx +++ b/src/components/shared/ProviderWrappers/GeneralProvidersWrapper.tsx @@ -4,11 +4,11 @@ import {KeyboardProvider} from "$lib/Providers/KeyboardProvider"; import {useEffect} from "react" import {songsStore} from "$stores/SongsStore"; import {folderStore} from "$stores/FoldersStore"; -import {metronome} from "$lib/Metronome"; +import {metronome} from "$lib/audio/Metronome"; import {keyBinds} from "$stores/KeybindsStore"; import {themeStore} from "$stores/ThemeStore/ThemeStore"; import {ThemeProvider} from "$stores/ThemeStore/ThemeProvider"; -import {globalConfigStore} from "$stores/GlobalConfig"; +import {globalConfigStore} from "$stores/GlobalConfigStore"; import Logger from '$cmp/pages/Index/Logger' import {AsyncPromptWrapper} from '$cmp/shared/Utility/AsyncPrompt'; import {setupProtocol} from "$lib/Hooks/useWindowProtocol"; diff --git a/src/components/shared/ProviderWrappers/ThemeProviderWrapper.tsx b/src/components/shared/ProviderWrappers/ThemeProviderWrapper.tsx index 5d2a715f..aed2d8ea 100644 --- a/src/components/shared/ProviderWrappers/ThemeProviderWrapper.tsx +++ b/src/components/shared/ProviderWrappers/ThemeProviderWrapper.tsx @@ -1,7 +1,7 @@ import {useTheme} from '$lib/Hooks/useTheme' -import {useEffect, useState} from 'react'; +import {useEffect, useMemo, useState} from 'react'; import {ThemeProvider} from '$stores/ThemeStore/ThemeProvider'; -import {colorToRGB} from '$lib/Utilities'; +import {colorToRGB} from '$lib/utils/Utilities'; import Head from 'next/head'; import {TEMPO_CHANGERS} from '$config'; import Color from 'color'; @@ -17,31 +17,33 @@ export function ThemeProviderWrapper({children}: Props) { ThemeProvider.load() }, []) const [theme] = useTheme() - const clickColor = theme.get('accent').isDark() - ? theme.get('accent').mix(theme.get("note_background")).lighten(0.1) - : theme.get('accent').mix(theme.get("note_background")).lighten(0.2) - const backgroundDesaturate = ThemeProvider.get('note_background').desaturate(0.6) - const borderFill = backgroundDesaturate.isDark() - ? backgroundDesaturate.lighten(0.50).toString() - : backgroundDesaturate.darken(0.18).toString() + const obj = useMemo(() => { + const clickColor = theme.get('accent').isDark() + ? theme.get('accent').mix(theme.get("note_background")).lighten(0.1) + : theme.get('accent').mix(theme.get("note_background")).lighten(0.2) + const backgroundDesaturate = ThemeProvider.get('note_background').desaturate(0.6) + const borderFill = backgroundDesaturate.isDark() + ? backgroundDesaturate.lighten(0.50).toString() + : backgroundDesaturate.darken(0.18).toString() - const map = new Map() - map.set('--clicked-note', clickColor.toString()) - map.set('--note-border-fill', borderFill.toString()) - theme.toArray().forEach(e => { - const layers = [10, 20] - const layersMore = [10, 15, 20] - map.set(`--${e.css}`, e.value) - map.set(`--${e.css}-rgb`, colorToRGB(theme.get(e.name)).join(',')) - map.set(`--${e.css}-text`, e.text) - layers.forEach(v => map.set(`--${e.css}-darken-${v}`, theme.get(e.name).darken(v / 100).toString())) - layers.forEach(v => map.set(`--${e.css}-lighten-${v}`, theme.get(e.name).lighten(v / 100).toString())) - layersMore.forEach(v => map.set(`--${e.css}-layer-${v}`, theme.layer(e.name, v / 100).toString())) - }) - TEMPO_CHANGERS.forEach(t => { - map.set(`--tempo-changer-${t.id}`, Color(t.color).toString()) - }) - const obj = Object.fromEntries(map) + const map = new Map() + map.set('--clicked-note', clickColor.toString()) + map.set('--note-border-fill', borderFill.toString()) + theme.toArray().forEach(e => { + const layers = [10, 20] + const layersMore = [10, 15, 20] + map.set(`--${e.css}`, e.value) + map.set(`--${e.css}-rgb`, colorToRGB(theme.get(e.name)).join(',')) + map.set(`--${e.css}-text`, e.text) + layers.forEach(v => map.set(`--${e.css}-darken-${v}`, theme.get(e.name).darken(v / 100).toString())) + layers.forEach(v => map.set(`--${e.css}-lighten-${v}`, theme.get(e.name).lighten(v / 100).toString())) + layersMore.forEach(v => map.set(`--${e.css}-layer-${v}`, theme.layer(e.name, v / 100).toString())) + }) + TEMPO_CHANGERS.forEach(t => { + map.set(`--tempo-changer-${t.id}`, Color(t.color).toString()) + }) + return Object.fromEntries(map) + }, [theme]) return <> diff --git a/src/components/shared/Utility/AsyncPrompt.tsx b/src/components/shared/Utility/AsyncPrompt.tsx index 86106217..aa7b4ab7 100644 --- a/src/components/shared/Utility/AsyncPrompt.tsx +++ b/src/components/shared/Utility/AsyncPrompt.tsx @@ -3,7 +3,7 @@ import {AsyncConfirmState, AsyncPromptState, asyncPromptStore} from "./AsyncProm import {useEffect, useRef, useState} from 'react' import {DecoratedCard} from "../layout/DecoratedCard" import {useTheme} from "$lib/Hooks/useTheme" -import {cn} from "$lib/Utilities" +import {cn} from "$lib/utils/Utilities" import {KeyboardProvider} from "$lib/Providers/KeyboardProvider" import {IGNORE_CLICK_CLASS} from "$lib/Hooks/useClickOutside" import isMobile from "is-mobile" diff --git a/src/components/shared/Utility/ErrorBoundaryRedirect.tsx b/src/components/shared/Utility/ErrorBoundaryRedirect.tsx index 41045dd6..e10a8dfb 100644 --- a/src/components/shared/Utility/ErrorBoundaryRedirect.tsx +++ b/src/components/shared/Utility/ErrorBoundaryRedirect.tsx @@ -1,4 +1,4 @@ -import {routeChangeBugFix} from "$lib/Utilities"; +import {routeChangeBugFix} from "$lib/utils/Utilities"; import {NextRouter, useRouter} from "next/router"; import {Component, ReactElement} from "react"; diff --git a/src/components/shared/header/Header.tsx b/src/components/shared/header/Header.tsx index bfe304ae..358416c0 100644 --- a/src/components/shared/header/Header.tsx +++ b/src/components/shared/header/Header.tsx @@ -1,5 +1,5 @@ import type {CSSProperties} from "react"; -import {MaybeChildren} from "$lib/UtilTypes"; +import {MaybeChildren} from "$lib/utils/UtilTypes"; export const HEADER_TYPES = ["h1", "h2", "h3", "h4", "h5", "h6"] as const type HeaderType = typeof HEADER_TYPES[number] diff --git a/src/components/shared/layout/Card.tsx b/src/components/shared/layout/Card.tsx index 7e3d75b4..b412e62a 100644 --- a/src/components/shared/layout/Card.tsx +++ b/src/components/shared/layout/Card.tsx @@ -1,4 +1,4 @@ -import {MaybeChildren, Stylable} from "$lib/UtilTypes"; +import {MaybeChildren, Stylable} from "$lib/utils/UtilTypes"; export interface CardProps extends Stylable { diff --git a/src/components/shared/layout/Column.tsx b/src/components/shared/layout/Column.tsx index 207a41f2..dc3dd049 100644 --- a/src/components/shared/layout/Column.tsx +++ b/src/components/shared/layout/Column.tsx @@ -1,4 +1,4 @@ -import {MaybeChildren, Stylable} from "$lib/UtilTypes"; +import {MaybeChildren, Stylable} from "$lib/utils/UtilTypes"; import {Justify, justifyMap} from "$cmp/shared/layout/layoutConstants"; diff --git a/src/components/shared/layout/Grid.tsx b/src/components/shared/layout/Grid.tsx index 5f0ed848..fa767f4e 100644 --- a/src/components/shared/layout/Grid.tsx +++ b/src/components/shared/layout/Grid.tsx @@ -1,4 +1,4 @@ -import {MaybeChildren, Stylable} from "$lib/UtilTypes"; +import {MaybeChildren, Stylable} from "$lib/utils/UtilTypes"; interface GridProps extends Stylable { diff --git a/src/components/shared/layout/Row.tsx b/src/components/shared/layout/Row.tsx index a1e2c684..0f35243b 100644 --- a/src/components/shared/layout/Row.tsx +++ b/src/components/shared/layout/Row.tsx @@ -1,4 +1,4 @@ -import {MaybeChildren, Stylable} from "$lib/UtilTypes"; +import {MaybeChildren, Stylable} from "$lib/utils/UtilTypes"; import {Justify, justifyMap} from "$cmp/shared/layout/layoutConstants"; diff --git a/src/components/shared/link/AppLink.tsx b/src/components/shared/link/AppLink.tsx index 00539818..2003c5ec 100644 --- a/src/components/shared/link/AppLink.tsx +++ b/src/components/shared/link/AppLink.tsx @@ -1,5 +1,5 @@ import Link, {LinkProps} from "next/link"; -import {MaybeChildren, Stylable} from "$lib/UtilTypes"; +import {MaybeChildren, Stylable} from "$lib/utils/UtilTypes"; interface AppLinkProps extends LinkProps { diff --git a/src/components/shared/pagesLayout/Folder.tsx b/src/components/shared/pagesLayout/Folder.tsx index 7a7cda98..3729dadb 100644 --- a/src/components/shared/pagesLayout/Folder.tsx +++ b/src/components/shared/pagesLayout/Folder.tsx @@ -9,7 +9,7 @@ import {asyncConfirm} from "$cmp/shared/Utility/AsyncPrompts" import {FloatingDropdown, FloatingDropdownRow, FloatingDropdownText} from "$cmp/shared/Utility/FloatingDropdown" import {SerializedSongKind} from "$types/SongTypes" import {APP_NAME, FOLDER_FILTER_TYPES} from "$config" -import {capitalize} from "$lib/Utilities" +import {capitalize} from "$lib/utils/Utilities" import {songService} from "$lib/Services/SongService" diff --git a/src/components/shared/pagesLayout/MenuPanel.tsx b/src/components/shared/pagesLayout/MenuPanel.tsx deleted file mode 100644 index 3ba148ea..00000000 --- a/src/components/shared/pagesLayout/MenuPanel.tsx +++ /dev/null @@ -1,19 +0,0 @@ -interface MenuPanelProps { - title?: string, - current?: T, - id?: T, - children: React.ReactNode -} - -export default function MenuPanel({title, current, children, id}: MenuPanelProps) { - return
- {title && -
- {title} -
- } -
- {children} -
-
-} \ No newline at end of file diff --git a/src/components/shared/pagesLayout/SimpleMenu.tsx b/src/components/shared/pagesLayout/SimpleMenu.tsx index d34b056b..ecb9626f 100644 --- a/src/components/shared/pagesLayout/SimpleMenu.tsx +++ b/src/components/shared/pagesLayout/SimpleMenu.tsx @@ -1,23 +1,20 @@ import {FaArrowLeft, FaDiscord, FaHome} from 'react-icons/fa'; -import {MenuItem} from '$cmp/shared/Miscellaneous/MenuItem' -import {historyTracker} from '$stores/History'; +import {MenuButton} from '$cmp/shared/Menu/MenuItem' +import {browserHistory} from '$stores/BrowserHistory'; import {homeStore} from '$stores/HomeStore'; import {useRouter} from 'next/router'; import Link from 'next/link'; import {asyncConfirm} from '$cmp/shared/Utility/AsyncPrompts'; +import {MenuContextProvider, MenuSidebar} from "$cmp/shared/Menu/MenuContent"; +import {MaybeChildren, Stylable} from "$lib/utils/UtilTypes"; -interface SimpleMenuProps { - children?: React.ReactNode, - className?: string -} - -export function SimpleMenu({children = undefined, className = ''}: SimpleMenuProps) { +export function SimpleMenu({children, className, style}: MaybeChildren) { const history = useRouter() - return
-
- {historyTracker.hasNavigated && - + + {browserHistory.hasNavigated && + { history.back() @@ -25,7 +22,7 @@ export function SimpleMenu({children = undefined, className = ''}: SimpleMenuPro ariaLabel='Go back' > - + } {children} - + - + - + - -
-
+ + + } \ No newline at end of file diff --git a/src/components/shared/separator/Separator.tsx b/src/components/shared/separator/Separator.tsx index d89dd2e3..b25845de 100644 --- a/src/components/shared/separator/Separator.tsx +++ b/src/components/shared/separator/Separator.tsx @@ -1,6 +1,6 @@ import type {CSSProperties} from "react"; import s from './separator.module.scss' -import {MaybeChildren} from "$lib/UtilTypes"; +import {MaybeChildren} from "$lib/utils/UtilTypes"; interface SeparatorProps { background?: string diff --git a/src/lib/Stats.ts b/src/lib/Analytics.ts similarity index 100% rename from src/lib/Stats.ts rename to src/lib/Analytics.ts diff --git a/src/lib/BaseSettings.ts b/src/lib/BaseSettings.ts index 8da20904..46fbcbef 100644 --- a/src/lib/BaseSettings.ts +++ b/src/lib/BaseSettings.ts @@ -9,7 +9,7 @@ import { Pitch, PITCHES } from "$config" -import {MIDIShortcut} from "./Utilities" +import {MIDIShortcut} from "./utils/Utilities" import { SettingsCheckbox, SettingsInstrument, diff --git a/src/lib/Hooks/useConfig.ts b/src/lib/Hooks/useConfig.ts index c59681e6..53ca2d67 100644 --- a/src/lib/Hooks/useConfig.ts +++ b/src/lib/Hooks/useConfig.ts @@ -1,4 +1,4 @@ -import {globalConfigStore} from "$stores/GlobalConfig"; +import {globalConfigStore} from "$stores/GlobalConfigStore"; import {useObservableObject} from "./useObservable"; export function useConfig() { diff --git a/src/lib/Hooks/useFontFaceObserver.tsx b/src/lib/Hooks/useFontFaceObserver.ts similarity index 100% rename from src/lib/Hooks/useFontFaceObserver.tsx rename to src/lib/Hooks/useFontFaceObserver.ts diff --git a/src/lib/Hooks/useTheme.ts b/src/lib/Hooks/useTheme.ts index b688224c..ae79a092 100644 --- a/src/lib/Hooks/useTheme.ts +++ b/src/lib/Hooks/useTheme.ts @@ -1,7 +1,7 @@ import {Theme, ThemeProvider} from "$stores/ThemeStore/ThemeProvider"; import {useEffect, useState} from "react"; import {observe} from "mobx"; -import {createDebouncer} from "$lib/Utilities"; +import {createDebouncer} from "$lib/utils/Utilities"; type UseTheme = [Theme, (theme: Theme) => void] diff --git a/src/lib/Providers/AudioProvider/index.ts b/src/lib/Providers/AudioProvider/index.ts index 8ef06c4b..10c15c54 100644 --- a/src/lib/Providers/AudioProvider/index.ts +++ b/src/lib/Providers/AudioProvider/index.ts @@ -1,5 +1,5 @@ import {BASE_PATH} from "$config" -import AudioRecorder from "$lib/AudioRecorder" +import AudioRecorder from "$lib/audio/AudioRecorder" export type AppAudioNode = { diff --git a/src/lib/Providers/MIDIProvider.ts b/src/lib/Providers/MIDIProvider.ts index 51aac377..07c9aef6 100644 --- a/src/lib/Providers/MIDIProvider.ts +++ b/src/lib/Providers/MIDIProvider.ts @@ -1,6 +1,6 @@ import {settingsService} from "$lib/Services/SettingsService" import {MIDISettings} from "../BaseSettings" -import {createDebouncer, debounce, MIDINote, MIDINoteStatus} from "$lib/Utilities"; +import {createDebouncer, debounce, MIDINote, MIDINoteStatus} from "$lib/utils/Utilities"; import {MIDI_PRESETS, MIDIPreset} from "$config"; export enum PresetMidi { diff --git a/src/lib/Services/FileService.ts b/src/lib/Services/FileService.ts index 440670e2..1faf0eba 100644 --- a/src/lib/Services/FileService.ts +++ b/src/lib/Services/FileService.ts @@ -1,6 +1,6 @@ import {ComposedSong, OldFormatComposed, UnknownSerializedComposedSong} from "$lib/Songs/ComposedSong" import {OldFormatRecorded, RecordedSong, UnknownSerializedRecordedSong} from "$lib/Songs/RecordedSong" -import {FileDownloader} from "$lib/Utilities" +import {FileDownloader} from "$lib/utils/Utilities" import {songsStore} from "$stores/SongsStore" import toWav from 'audiobuffer-to-wav' import {SerializedSong, Song} from "$lib/Songs/Song" diff --git a/src/lib/Services/SongService.ts b/src/lib/Services/SongService.ts index a642320c..4acdcf0b 100644 --- a/src/lib/Services/SongService.ts +++ b/src/lib/Services/SongService.ts @@ -3,7 +3,7 @@ import {ComposedSong} from "$lib/Songs/ComposedSong" import {RecordedSong} from "$lib/Songs/RecordedSong" import {extractStorable, SerializedSong, Song, SongStorable} from "$lib/Songs/Song" import {VsrgSong} from "$lib/Songs/VsrgSong" -import {getSongType} from "$lib/Utilities" +import {getSongType} from "$lib/utils/Utilities" import {AppError} from "../Errors" import {DbInstance} from "./Database/Database" import {settingsService} from "./SettingsService" diff --git a/src/stores/globalLink.ts b/src/lib/Services/globalServices.ts similarity index 80% rename from src/stores/globalLink.ts rename to src/lib/Services/globalServices.ts index 2c6dca50..153c2bd4 100644 --- a/src/stores/globalLink.ts +++ b/src/lib/Services/globalServices.ts @@ -3,10 +3,10 @@ import {songService} from "$lib/Services/SongService"; import {settingsService} from "$lib/Services/SettingsService"; import {_themeService} from "$lib/Services/ThemeService"; import {_folderService} from "$lib/Services/FolderService"; -import {songsStore} from "./SongsStore"; -import {themeStore} from "./ThemeStore/ThemeStore"; -import {logsStore} from "./LogsStore"; -import {keyBinds} from "./KeybindsStore"; +import {songsStore} from "$stores/SongsStore"; +import {themeStore} from "$stores/ThemeStore/ThemeStore"; +import {logsStore} from "$stores/LogsStore"; +import {keyBinds} from "$stores/KeybindsStore"; export function linkServices() { //exposes services to the global scope to be used in the console diff --git a/src/lib/Songs/ComposedSong.ts b/src/lib/Songs/ComposedSong.ts index 1c492c62..24d45ad3 100644 --- a/src/lib/Songs/ComposedSong.ts +++ b/src/lib/Songs/ComposedSong.ts @@ -10,11 +10,11 @@ import { } from "$config" import {InstrumentName} from "$types/GeneralTypes" import {_LegacySongInstruments, OldFormat} from "$types/SongTypes" -import {NoteLayer} from "../Layer" +import {NoteLayer} from "./Layer" import {RecordedSong} from "./RecordedSong" import {NoteColumn, ColumnNote, InstrumentData, RecordedNote, SerializedColumn} from "./SongClasses" import {SerializedSong, Song} from "./Song" -import {clamp} from "../Utilities"; +import {clamp} from "../utils/Utilities"; interface OldFormatNoteType { key: string, diff --git a/src/lib/Layer.ts b/src/lib/Songs/Layer.ts similarity index 98% rename from src/lib/Layer.ts rename to src/lib/Songs/Layer.ts index b51088d5..f027e056 100644 --- a/src/lib/Layer.ts +++ b/src/lib/Songs/Layer.ts @@ -1,5 +1,5 @@ import {BASE_LAYER_LIMIT, HAS_BIGINT} from "$config" -import {InstrumentData} from "./Songs/SongClasses" +import {InstrumentData} from "./SongClasses" //map of the possible combinations of instruments, in binary, export type LayerStatus = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 diff --git a/src/lib/Songs/RecordedSong.ts b/src/lib/Songs/RecordedSong.ts index 3d6a18af..aaa01f26 100644 --- a/src/lib/Songs/RecordedSong.ts +++ b/src/lib/Songs/RecordedSong.ts @@ -1,9 +1,9 @@ import {APP_NAME, IMPORT_NOTE_POSITIONS, INSTRUMENTS_DATA, PITCHES} from "$config" import {NoteColumn, ColumnNote, InstrumentData, RecordedNote, SerializedRecordedNote} from "./SongClasses" import {ComposedSong, defaultInstrumentMap} from "./ComposedSong" -import {groupByNotes, groupNotesByIndex, mergeLayers} from "$lib/Utilities"; +import {groupByNotes, groupNotesByIndex, mergeLayers} from "$lib/utils/Utilities"; import clonedeep from 'lodash.clonedeep' -import {NoteLayer} from "../Layer" +import {NoteLayer} from "./Layer" import {Midi} from "@tonejs/midi" import {InstrumentName} from "$types/GeneralTypes" import {SerializedSong, Song} from "./Song" diff --git a/src/lib/Songs/SongClasses.ts b/src/lib/Songs/SongClasses.ts index f5d23c49..32c7f939 100644 --- a/src/lib/Songs/SongClasses.ts +++ b/src/lib/Songs/SongClasses.ts @@ -9,7 +9,7 @@ import { TempoChanger } from "$config" import {InstrumentName} from "$types/GeneralTypes" -import {NoteLayer} from "../Layer" +import {NoteLayer} from "./Layer" import {InstrumentNoteIcon} from "./ComposedSong" export type SerializedColumn = [tempoChanger: number, notes: SerializedColumnNote[]] diff --git a/src/lib/Songs/VisualSong.ts b/src/lib/Songs/VisualSong.ts index 4cdd8858..637612d2 100644 --- a/src/lib/Songs/VisualSong.ts +++ b/src/lib/Songs/VisualSong.ts @@ -2,7 +2,7 @@ import {APP_NAME, NoteNameType} from "$config" import {ComposedSong} from "$lib/Songs/ComposedSong" import {RecordedSong} from "$lib/Songs/RecordedSong" import {NoteColumn, ColumnNote, RecordedNote} from "$lib/Songs/SongClasses" -import {Instrument} from '$lib/Instrument' +import {Instrument} from '$lib/audio/Instrument' import {Song} from "./Song" const THRESHOLDS = { diff --git a/src/lib/ThrottledEventLoop.tsx b/src/lib/ThrottledEventLoop.ts similarity index 100% rename from src/lib/ThrottledEventLoop.tsx rename to src/lib/ThrottledEventLoop.ts diff --git a/src/lib/AudioPlayer.ts b/src/lib/audio/AudioPlayer.ts similarity index 94% rename from src/lib/AudioPlayer.ts rename to src/lib/audio/AudioPlayer.ts index ac4114ad..c73992c8 100644 --- a/src/lib/AudioPlayer.ts +++ b/src/lib/audio/AudioPlayer.ts @@ -1,7 +1,7 @@ import {Pitch} from "$config"; -import {Instrument} from '$lib/Instrument' -import {AudioProvider} from "./Providers/AudioProvider"; -import {InstrumentData} from "./Songs/SongClasses"; +import {Instrument} from '$lib/audio/Instrument' +import {AudioProvider} from "../Providers/AudioProvider"; +import {InstrumentData} from "../Songs/SongClasses"; export class AudioPlayer { diff --git a/src/lib/AudioRecorder.ts b/src/lib/audio/AudioRecorder.ts similarity index 96% rename from src/lib/AudioRecorder.ts rename to src/lib/audio/AudioRecorder.ts index e77d24ac..633e1bf0 100644 --- a/src/lib/AudioRecorder.ts +++ b/src/lib/audio/AudioRecorder.ts @@ -1,5 +1,5 @@ import {createAudioRecorderPolyfill} from "./MediaRecorderPolyfill"; -import {fileService} from "./Services/FileService"; +import {fileService} from "../Services/FileService"; export default class AudioRecorder { node: MediaStreamAudioDestinationNode | null diff --git a/src/lib/BasicPitchLoader.ts b/src/lib/audio/BasicPitchLoader.ts similarity index 100% rename from src/lib/BasicPitchLoader.ts rename to src/lib/audio/BasicPitchLoader.ts diff --git a/src/lib/Instrument.ts b/src/lib/audio/Instrument.ts similarity index 99% rename from src/lib/Instrument.ts rename to src/lib/audio/Instrument.ts index 7aa6f5d1..93485d8f 100644 --- a/src/lib/Instrument.ts +++ b/src/lib/audio/Instrument.ts @@ -12,7 +12,7 @@ import { } from "$config" import {makeObservable, observable} from "mobx" import {InstrumentName, NoteStatus} from "$types/GeneralTypes" -import {getPitchChanger} from "./Utilities" +import {getPitchChanger} from "../utils/Utilities" import {NoteImage} from "$cmp/shared/SvgNotes" type Layouts = { diff --git a/src/lib/MediaRecorderPolyfill.ts b/src/lib/audio/MediaRecorderPolyfill.ts similarity index 100% rename from src/lib/MediaRecorderPolyfill.ts rename to src/lib/audio/MediaRecorderPolyfill.ts diff --git a/src/lib/Metronome.ts b/src/lib/audio/Metronome.ts similarity index 98% rename from src/lib/Metronome.ts rename to src/lib/audio/Metronome.ts index 35f43e6b..3797c90d 100644 --- a/src/lib/Metronome.ts +++ b/src/lib/audio/Metronome.ts @@ -1,6 +1,6 @@ import {BASE_PATH} from "$config"; import {fetchAudioBuffer} from "./Instrument"; -import {delay} from "./Utilities"; +import {delay} from "../utils/Utilities"; class Metronome { diff --git a/src/lib/needsUpdate.ts b/src/lib/needsUpdate.ts index 62f819e7..8adf1b5f 100644 --- a/src/lib/needsUpdate.ts +++ b/src/lib/needsUpdate.ts @@ -2,7 +2,7 @@ import {APP_NAME, APP_VERSION, IS_TAURI, UPDATE_URL} from "$config" import {logger} from "$stores/LoggerStore" import semverLt from 'semver/functions/lt' import semverCoerce from 'semver/functions/coerce' -import {delay} from "./Utilities" +import {delay} from "./utils/Utilities" type AppUpdateSchema = { version: string, diff --git a/src/lib/UtilTypes.ts b/src/lib/utils/UtilTypes.ts similarity index 100% rename from src/lib/UtilTypes.ts rename to src/lib/utils/UtilTypes.ts diff --git a/src/lib/Utilities.ts b/src/lib/utils/Utilities.ts similarity index 90% rename from src/lib/Utilities.ts rename to src/lib/utils/Utilities.ts index 7d576ece..a3e6cf23 100644 --- a/src/lib/Utilities.ts +++ b/src/lib/utils/Utilities.ts @@ -1,12 +1,13 @@ import {BASE_PATH, Pitch, PITCHES, TEMPO_CHANGERS} from "$config" import * as workerTimers from 'worker-timers'; -import {NoteColumn, ColumnNote, RecordedNote} from "./Songs/SongClasses"; -import {NoteLayer} from "./Layer"; -import {Song} from "./Songs/Song"; -import {ComposedSong} from "./Songs/ComposedSong"; -import {RecordedSong} from "./Songs/RecordedSong"; +import {ColumnNote, NoteColumn, RecordedNote} from "../Songs/SongClasses"; +import {NoteLayer} from "../Songs/Layer"; +import {Song} from "../Songs/Song"; +import {ComposedSong} from "../Songs/ComposedSong"; +import {RecordedSong} from "../Songs/RecordedSong"; import {ClickType, Timer} from "$types/GeneralTypes" import Color from "color"; +import {CSSProperties} from "react"; export function preventDefault(e: React.MouseEvent) { @@ -210,16 +211,29 @@ function getSongType(song: any): 'oldSky' | 'none' | 'newComposed' | 'newRecorde return "none" } -type ConditionalClass = [condition: boolean, trueClass: string, falseClass?: string] | string +type Booleany = boolean | string | number | null | undefined -export function cn(...args: ConditionalClass[]) { - const result = args.map(a => { - if (typeof a === 'string') return a - return a[0] ? a[1] : (a[2] ?? '') - }).join(' ') - return result +type ConditionalElement = [condition: Booleany, trueClass: T, falseClass?: T] | T + +export function cn(...args: ConditionalElement[]) { + return args.map(a => { + if (Array.isArray(a)) return a[0] ? a[1] : (a[2] ?? ""); + if (!a) return ""; + return a; + + }).join(" "); } +export function cs(...args: ConditionalElement[]) { + const parsed = args.map(a => { + if (typeof a === "object" && !Array.isArray(a)) return a; + if (!a) return {}; + return a[0] ? a[1] : (a[2] ?? {}); + }); + return Object.assign({}, ...parsed); +} + + function groupByNotes(notes: RecordedNote[], threshold: number) { const result = [] while (notes.length > 0) { diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 7c2667e1..7a2b2cba 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -16,7 +16,7 @@ import '$pages/vsrg-composer/VsrgComposer.css'; import type {AppProps} from "next/app"; import AppBase from "$cmp/AppBase"; import {NextComponentType, NextPageContext} from "next"; -import {delay, setIfInTWA} from "$lib/Utilities"; +import {delay, setIfInTWA} from "$lib/utils/Utilities"; import * as serviceWorker from "$/serviceWorkerRegistration" import {BASE_PATH, IS_TAURI} from "$config"; import ErrorBoundaryRedirect from "$cmp/shared/Utility/ErrorBoundaryRedirect"; @@ -98,7 +98,7 @@ export default function App({Component, pageProps}: AppProps) { } } - console.log("Checking for updates...") + console.log("Checking for changelog...") registerSw() }, []) // @ts-ignore diff --git a/src/pages/backup/index.tsx b/src/pages/backup/index.tsx index 85f74a22..601c9fbd 100644 --- a/src/pages/backup/index.tsx +++ b/src/pages/backup/index.tsx @@ -15,7 +15,7 @@ import {fileService, UnknownFileTypes} from "$lib/Services/FileService"; import {Folder, SerializedFolder} from "$lib/Folder"; import {APP_NAME} from "$config"; import {FileElement, FilePicker} from "$cmp/shared/Inputs/FilePicker"; -import {delay} from "$lib/Utilities"; +import {delay} from "$lib/utils/Utilities"; import {useSongs} from "$lib/Hooks/useSongs"; import {useObservableArray} from "$lib/Hooks/useObservable"; import {themeStore} from "$stores/ThemeStore/ThemeStore"; diff --git a/src/pages/blog/posts/how-to-use-composer.tsx b/src/pages/blog/posts/how-to-use-composer.tsx index b04f7eb6..b5687c41 100644 --- a/src/pages/blog/posts/how-to-use-composer.tsx +++ b/src/pages/blog/posts/how-to-use-composer.tsx @@ -9,7 +9,7 @@ import {ShortcutsTable} from "$cmp/pages/Index/HelpTab/ShortcutsHelp"; import {useConfig} from "$lib/Hooks/useConfig"; import {useObservableMap} from "$lib/Hooks/useObservable"; import {keyBinds} from "$stores/KeybindsStore"; -import {NoteLayer} from "$lib/Layer"; +import {NoteLayer} from "$lib/Songs/Layer"; export const _composerTutorialMetadata: BlogMetadata = { title: "📀 How to use the composer", diff --git a/src/pages/changelog/index.tsx b/src/pages/changelog/index.tsx index c119f059..21af52b5 100644 --- a/src/pages/changelog/index.tsx +++ b/src/pages/changelog/index.tsx @@ -1,15 +1,15 @@ import {SimpleMenu} from '$cmp/shared/pagesLayout/SimpleMenu' -import {MenuItem} from '$cmp/shared/Miscellaneous/MenuItem' +import {MenuButton} from '$cmp/shared/Menu/MenuItem' import {FaGithub} from 'react-icons/fa' import {ChangelogRow} from '$cmp/pages/Changelog/ChangelogRow' -import {updates} from '$lib/updates' +import {CHANGELOG} from '$/changelog' import {APP_VERSION, BASE_PATH} from '$config' import {PageMeta} from '$cmp/shared/Miscellaneous/PageMeta' import {DefaultPage} from '$cmp/shared/pagesLayout/DefaultPage' import {AppButton} from '$cmp/shared/Inputs/AppButton' import Link from 'next/link' import s from './Changelog.module.css' -import {clearClientCache} from "$lib/Utilities"; +import {clearClientCache} from "$lib/utils/Utilities"; import {logger} from "$stores/LoggerStore"; const cacheVersion = process.env.NEXT_PUBLIC_SW_VERSION @@ -35,15 +35,15 @@ export default function ChangelogPage() { - + - + } > + description={`Changelog V${APP_VERSION}\n${CHANGELOG[0]?.changes.join(";")}`}/>
Changelog @@ -63,7 +63,7 @@ export default function ChangelogPage() {
- {updates.map(data => )} diff --git a/src/pages/composer/index.tsx b/src/pages/composer/index.tsx index 84b5cc5f..3f3c6082 100644 --- a/src/pages/composer/index.tsx +++ b/src/pages/composer/index.tsx @@ -11,12 +11,12 @@ import Menu from "$cmp/pages/Composer/ComposerMenu" import Memoized, {MemoizedIcon} from '$cmp/shared/Utility/Memoized'; import {asyncConfirm, asyncPrompt} from "$cmp/shared/Utility/AsyncPrompts" import {ComposerSettingsDataType} from "$lib/BaseSettings" -import {Instrument, ObservableNote} from "$lib/Instrument" -import {calculateSongLength, delay, formatMs, routeChangeBugFix} from "$lib/Utilities" +import {Instrument, ObservableNote} from "$lib/audio/Instrument" +import {calculateSongLength, delay, formatMs, routeChangeBugFix} from "$lib/utils/Utilities" import {ComposedSong, UnknownSerializedComposedSong} from '$lib/Songs/ComposedSong'; import {NoteColumn, InstrumentData} from '$lib/Songs/SongClasses'; -import AudioRecorder from '$lib/AudioRecorder' -import Analytics from '$lib/Stats'; +import AudioRecorder from '$lib/audio/AudioRecorder' +import Analytics from '$lib/Analytics'; import {homeStore} from '$stores/HomeStore'; import {logger} from '$stores/LoggerStore'; import {RecordedSong, SerializedRecordedSong} from '$lib/Songs/RecordedSong'; @@ -37,8 +37,8 @@ import {songService} from '$lib/Services/SongService'; import {NextRouter, useRouter} from 'next/router'; import {AppBackground} from '$cmp/shared/pagesLayout/AppBackground'; import {createKeyboardListener, createShortcutListener, ShortcutListener} from '$/stores/KeybindsStore'; -import {NoteLayer} from "$lib/Layer"; -import {globalConfigStore} from '$stores/GlobalConfig'; +import {NoteLayer} from "$lib/Songs/Layer"; +import {globalConfigStore} from '$stores/GlobalConfigStore'; interface ComposerState { layers: Instrument[] diff --git a/src/pages/delete-cache/index.tsx b/src/pages/delete-cache/index.tsx index 8cd324f4..2327e937 100644 --- a/src/pages/delete-cache/index.tsx +++ b/src/pages/delete-cache/index.tsx @@ -1,5 +1,5 @@ import {useEffect} from "react"; -import {clearClientCache} from "$lib/Utilities"; +import {clearClientCache} from "$lib/utils/Utilities"; import {logger} from "$stores/LoggerStore"; import {DefaultPage} from "$cmp/shared/pagesLayout/DefaultPage"; import {Header} from "$cmp/shared/header/Header"; diff --git a/src/pages/keybinds/index.tsx b/src/pages/keybinds/index.tsx index 6591bfe4..a4121ffc 100644 --- a/src/pages/keybinds/index.tsx +++ b/src/pages/keybinds/index.tsx @@ -8,7 +8,7 @@ import {KeyboardProvider} from "$lib/Providers/KeyboardProvider"; import {VsrgSongKeys} from "$lib/Songs/VsrgSong"; import {Fragment, useEffect, useState} from "react"; import {keyBinds} from "$stores/KeybindsStore"; -import {Instrument} from '$lib/Instrument' +import {Instrument} from '$lib/audio/Instrument' import {logger} from "$/stores/LoggerStore"; import {ShortcutEditor} from "$cmp/pages/Keybinds/ShortcutEditor"; import {useConfig} from "$/lib/Hooks/useConfig"; diff --git a/src/pages/player/index.tsx b/src/pages/player/index.tsx index a5b146f4..0c48eee9 100644 --- a/src/pages/player/index.tsx +++ b/src/pages/player/index.tsx @@ -6,10 +6,10 @@ import {RecordedSong} from '$lib/Songs/RecordedSong'; import {ComposedSong} from '$lib/Songs/ComposedSong'; import {InstrumentData, Recording} from '$lib/Songs/SongClasses'; import {PlayerSettingsDataType} from "$lib/BaseSettings" -import {Instrument} from '$lib/Instrument' -import AudioRecorder from '$lib/AudioRecorder'; +import {Instrument} from '$lib/audio/Instrument' +import AudioRecorder from '$lib/audio/AudioRecorder'; import {asyncConfirm, asyncPrompt} from "$cmp/shared/Utility/AsyncPrompts" -import Analytics from '$lib/Stats'; +import Analytics from '$lib/Analytics'; import {logger} from '$stores/LoggerStore'; import {SettingUpdate, SettingVolumeUpdate} from '$types/SettingsPropriety'; import {InstrumentName} from '$types/GeneralTypes'; @@ -18,9 +18,9 @@ import {AudioProvider} from '$lib/Providers/AudioProvider'; import {settingsService} from '$lib/Services/SettingsService'; import {songsStore} from '$stores/SongsStore'; import {PageMeta} from '$cmp/shared/Miscellaneous/PageMeta'; -import {metronome} from '$lib/Metronome'; +import {metronome} from '$lib/audio/Metronome'; import {Lambda} from 'mobx'; -import {NoteLayer} from '$lib/Layer'; +import {NoteLayer} from '$lib/Songs/Layer'; import {subscribeObeservableObject} from '$lib/Hooks/useObservable'; import {INSTRUMENTS, SPEED_CHANGERS} from '$config'; import {playerControlsStore} from '$stores/PlayerControlsStore'; diff --git a/src/pages/sheet-visualizer/index.tsx b/src/pages/sheet-visualizer/index.tsx index 2e73151e..4c3c0c75 100644 --- a/src/pages/sheet-visualizer/index.tsx +++ b/src/pages/sheet-visualizer/index.tsx @@ -1,8 +1,8 @@ import {useCallback, useEffect, useRef, useState} from 'react' import {APP_NAME, NOTE_NAME_TYPES, NoteNameType} from '$config' -import {isComposedOrRecorded} from '$lib/Utilities' +import {isComposedOrRecorded} from '$lib/utils/Utilities' import Switch from '$cmp/shared/Inputs/Switch' -import Analytics from '$lib/Stats' +import Analytics from '$lib/Analytics' import {AppButton} from '$cmp/shared/Inputs/AppButton' import {logger} from '$stores/LoggerStore' import {SerializedSong} from '$lib/Songs/Song' diff --git a/src/pages/transfer/index.tsx b/src/pages/transfer/index.tsx index b55637ee..6bb4a248 100644 --- a/src/pages/transfer/index.tsx +++ b/src/pages/transfer/index.tsx @@ -6,7 +6,7 @@ import {protocol, setupProtocol} from "$lib/Hooks/useWindowProtocol"; import {logger} from "$stores/LoggerStore"; import {useCallback, useEffect, useState} from "react"; import s from "./transfer.module.css" -import {cn} from "$lib/Utilities"; +import {cn} from "$lib/utils/Utilities"; import {fileService, UnknownFileTypes} from "$lib/Services/FileService"; import {PageMeta} from "$cmp/shared/Miscellaneous/PageMeta"; @@ -41,7 +41,7 @@ export default function TransferData() { const data = await protocol.ask("getAppData", undefined) setImportedData(Array.isArray(data) ? data : [data]) } catch (e) { - logger.error("Error connecting, please visit the domain, there might be updates. ") + logger.error("Error connecting, please visit the domain, there might be changelog. ") setError(`Error fetching: ${e}`) } logger.hidePill() diff --git a/src/pages/uma-mode/index.tsx b/src/pages/uma-mode/index.tsx index 02b795fd..db21fb60 100644 --- a/src/pages/uma-mode/index.tsx +++ b/src/pages/uma-mode/index.tsx @@ -3,8 +3,8 @@ import {PageMeta} from "$cmp/shared/Miscellaneous/PageMeta"; import {asyncConfirm, asyncPrompt} from "$cmp/shared/Utility/AsyncPrompts"; import {APP_NAME} from "$config"; import {useConfig} from "$lib/Hooks/useConfig"; -import {cn} from "$lib/Utilities"; -import {globalConfigStore} from "$stores/GlobalConfig"; +import {cn} from "$lib/utils/Utilities"; +import {globalConfigStore} from "$stores/GlobalConfigStore"; import {logger} from "$stores/LoggerStore"; import s from "./UmaMode.module.scss"; import {CSSProperties, useEffect, useRef, useState} from "react"; diff --git a/src/pages/vsrg-composer/index.tsx b/src/pages/vsrg-composer/index.tsx index 76bd1eca..21744a07 100644 --- a/src/pages/vsrg-composer/index.tsx +++ b/src/pages/vsrg-composer/index.tsx @@ -10,14 +10,14 @@ import {VsrgComposerSettingsDataType} from "$lib/BaseSettings"; import {settingsService} from "$lib/Services/SettingsService"; import {SettingUpdate} from "$types/SettingsPropriety"; import {vsrgComposerStore} from "$stores/VsrgComposerStore"; -import {AudioPlayer} from "$lib/AudioPlayer"; +import {AudioPlayer} from "$lib/audio/AudioPlayer"; import {KeyboardEventData, KeyboardProvider} from "$lib/Providers/KeyboardProvider"; import {songsStore} from "$stores/SongsStore"; import {RecordedSong} from "$lib/Songs/RecordedSong"; import {SerializedSong} from "$lib/Songs/Song"; import {songService} from "$lib/Services/SongService"; import {ComposedSong} from "$lib/Songs/ComposedSong"; -import {clamp, isFocusable, routeChangeBugFix} from "$lib/Utilities"; +import {clamp, isFocusable, routeChangeBugFix} from "$lib/utils/Utilities"; import {DEFAULT_VSRG_KEYS_MAP} from "$config"; import {ClickType} from "$types/GeneralTypes" import {RecordedNote} from "$lib/Songs/SongClasses"; diff --git a/src/pages/vsrg-player/index.tsx b/src/pages/vsrg-player/index.tsx index e00951ee..f3511921 100644 --- a/src/pages/vsrg-player/index.tsx +++ b/src/pages/vsrg-player/index.tsx @@ -3,7 +3,7 @@ import VsrgPlayerMenu from "$cmp/pages/VsrgPlayer/VsrgPlayerMenu"; import {VsrgHitObject, VsrgSong} from "$lib/Songs/VsrgSong"; import {settingsService} from "$lib/Services/SettingsService"; import {VsrgPlayerSettingsDataType} from "$lib/BaseSettings"; -import {AudioPlayer} from "$lib/AudioPlayer"; +import {AudioPlayer} from "$lib/audio/AudioPlayer"; import {VsrgPlayerKeyboard} from "$cmp/pages/VsrgPlayer/VsrgPlayerKeyboard"; import {vsrgPlayerStore} from "$stores/VsrgPlayerStore"; import {defaultVsrgPlayerSizes, VsrgPlayerCanvas, VsrgPlayerCanvasSizes} from "$cmp/pages/VsrgPlayer/VsrgPlayerCanvas"; diff --git a/src/pages/zen-keyboard/index.tsx b/src/pages/zen-keyboard/index.tsx index d9ba9bab..32da4e0a 100644 --- a/src/pages/zen-keyboard/index.tsx +++ b/src/pages/zen-keyboard/index.tsx @@ -1,8 +1,8 @@ import {ZenKeypad} from "$cmp/pages/ZenKeyboard/ZenKeypad" import {ZenKeyboardMenu} from "$cmp/pages/ZenKeyboard/ZenKeyboardMenu" import {ZenKeyboardSettings, ZenKeyboardSettingsDataType} from "$lib/BaseSettings" -import {Instrument, ObservableNote} from "$lib/Instrument" -import {metronome} from "$lib/Metronome" +import {Instrument, ObservableNote} from "$lib/audio/Instrument" +import {metronome} from "$lib/audio/Metronome" import {AudioProvider} from "$lib/Providers/AudioProvider" import {settingsService} from "$lib/Services/SettingsService" import {logger} from "$stores/LoggerStore" diff --git a/src/serviceWorkerRegistration.ts b/src/serviceWorkerRegistration.ts index e6a3578e..fc89cf19 100644 --- a/src/serviceWorkerRegistration.ts +++ b/src/serviceWorkerRegistration.ts @@ -3,7 +3,7 @@ // This lets the app load faster on subsequent visits in production, and gives // it offline capabilities. However, it also means that developers (and users) -// will only see deployed updates on subsequent visits to a page, after all the +// will only see deployed changelog on subsequent visits to a page, after all the // existing tabs open on the page have been closed, since previously cached // resources are updated in the background. diff --git a/src/stores/History.ts b/src/stores/BrowserHistory.ts similarity index 83% rename from src/stores/History.ts rename to src/stores/BrowserHistory.ts index 574a3150..60b9391a 100644 --- a/src/stores/History.ts +++ b/src/stores/BrowserHistory.ts @@ -15,4 +15,4 @@ class HistoryTracker { } -export const historyTracker = new HistoryTracker(); +export const browserHistory = new HistoryTracker(); diff --git a/src/stores/GlobalConfig.ts b/src/stores/GlobalConfigStore.ts similarity index 88% rename from src/stores/GlobalConfig.ts rename to src/stores/GlobalConfigStore.ts index da5d54ab..e957087d 100644 --- a/src/stores/GlobalConfig.ts +++ b/src/stores/GlobalConfigStore.ts @@ -1,9 +1,9 @@ import {APP_NAME, BASE_LAYER_LIMIT} from "$config"; -import {NoteLayer} from "$lib/Layer"; +import {NoteLayer} from "$lib/Songs/Layer"; import isMobile from "is-mobile"; import {makeObservable, observable} from "mobx"; -type GlobalConfig = { +type GlobalConfigStoreState = { PLAY_BAR_OFFSET: number, IS_MOBILE: boolean, IS_MIDI_AVAILABLE: boolean, @@ -13,7 +13,7 @@ type GlobalConfig = { class GlobalConfigStore { @observable - state: GlobalConfig = { + state: GlobalConfigStoreState = { PLAY_BAR_OFFSET: 200, IS_MOBILE: false, IS_MIDI_AVAILABLE: true, @@ -24,7 +24,7 @@ class GlobalConfigStore { makeObservable(this) } - setState = (state: Partial) => { + setState = (state: Partial) => { Object.assign(this.state, state) } setUmaMode = (isOn: boolean) => { diff --git a/src/stores/PlayerStore.ts b/src/stores/PlayerStore.ts index d8bf0e70..2e73764a 100644 --- a/src/stores/PlayerStore.ts +++ b/src/stores/PlayerStore.ts @@ -1,5 +1,5 @@ import {APP_NAME} from "$config"; -import {NoteDataState, ObservableNote} from "$lib/Instrument"; +import {NoteDataState, ObservableNote} from "$lib/audio/Instrument"; import {ComposedSong} from "$lib/Songs/ComposedSong"; import {RecordedSong} from "$lib/Songs/RecordedSong"; import {action, makeObservable, observable} from "mobx"; diff --git a/src/stores/SongsStore.ts b/src/stores/SongsStore.ts index 73da7ad1..f8de5c7e 100644 --- a/src/stores/SongsStore.ts +++ b/src/stores/SongsStore.ts @@ -1,4 +1,4 @@ -import {createDebouncer} from "$lib/Utilities" +import {createDebouncer} from "$lib/utils/Utilities" import {songService} from "$lib/Services/SongService" import {extractStorable, SerializedSong, Song, SongStorable} from "$lib/Songs/Song" import {makeObservable, observable} from "mobx" diff --git a/src/stores/ZenKeyboardStore.ts b/src/stores/ZenKeyboardStore.ts index b1cd89aa..83c9513b 100644 --- a/src/stores/ZenKeyboardStore.ts +++ b/src/stores/ZenKeyboardStore.ts @@ -1,5 +1,5 @@ import {APP_NAME} from "$config" -import {NoteDataState, ObservableNote} from "$lib/Instrument" +import {NoteDataState, ObservableNote} from "$lib/audio/Instrument" import {NoteStatus} from "$/types/GeneralTypes" import {makeObservable, observable} from "mobx" diff --git a/test-songs/ThingsToTest.md b/test-songs/ThingsToTest.md index 1ae10bd9..2264491c 100644 --- a/test-songs/ThingsToTest.md +++ b/test-songs/ThingsToTest.md @@ -1,4 +1,4 @@ -## Things to test before updates +## Things to test before changelog - Download of a song in composer and player - Import of a song in player, with old and new format, in sky and genshin - Import of a MIDI song