!async function(){for(;!Spicetify.React||!Spicetify.ReactDOM;)await new Promise(t=>setTimeout(t,10));var t,e,D,a,F,c,U,R,r,$,o,i,n,H,s,J,u,l,g,L,B,K,V,h,f,Y,p,d,W,m,X,q,G,Q,Z,b,tt,et,rt,it,nt,ot,y,v,w,S,st,at;D=Object.create,a=Object.defineProperty,F=Object.getOwnPropertyDescriptor,c=Object.getOwnPropertyNames,U=Object.getPrototypeOf,R=Object.prototype.hasOwnProperty,t={"../../node_modules/pixelmatch/index.js"(t,e){"use strict";var m={threshold:.1,includeAA:!(e.exports=function(r,i,n,o,s,a){if(!b(r)||!b(i)||n&&!b(n))throw new Error("Image data: Uint8Array, Uint8ClampedArray or Buffer expected.");if(r.length!==i.length||n&&n.length!==r.length)throw new Error("Image sizes do not match.");if(r.length!==o*s*4)throw new Error("Image data size does not match width/height.");a=Object.assign({},m,a);var e=o*s,c=new Uint32Array(r.buffer,r.byteOffset,e),u=new Uint32Array(i.buffer,i.byteOffset,e);let l=!0;for(let t=0;th?a.includeAA||!y(r,t,e,o,s,i)&&!y(i,t,e,o,s,r)?(n&&v(n,p,...d<0&&a.diffColorAlt||a.diffColor),f++):n&&!a.diffMask&&v(n,p,...a.aaColor):n&&!a.diffMask&&S(r,p,a.alpha,n)}return f}),alpha:.1,aaColor:[255,255,0],diffColor:[255,0,0],diffColorAlt:null,diffMask:!1};function b(t){return ArrayBuffer.isView(t)&&1===t.constructor.BYTES_PER_ELEMENT}function y(r,i,n,o,t,e){var s=Math.max(i-1,0),a=Math.max(n-1,0),c=Math.min(i+1,o-1),u=Math.min(n+1,t-1),l=4*(n*o+i);let h=i===s||i===c||n===a||n===u?1:0,f=0,p=0,d,m,b,y;for(let e=s;e<=c;e++)for(let t=a;t<=u;t++)if(e!==i||t!==n){var v=w(r,r,l,4*(t*o+e),!0);if(0===v){if(2<++h)return}else vp&&(p=v,b=e,y=t)}return 0!==f&&0!==p&&(g(r,d,m,o,t)&&g(e,d,m,o,t)||g(r,b,y,o,t)&&g(e,b,y,o,t))}function g(r,i,n,o,t){var s=Math.max(i-1,0),a=Math.max(n-1,0),c=Math.min(i+1,o-1),u=Math.min(n+1,t-1),l=4*(n*o+i);let h=i===s||i===c||n===a||n===u?1:0;for(let e=s;e<=c;e++)for(let t=a;t<=u;t++)if(e!==i||t!==n){var f=4*(t*o+e);if(r[l]===r[f]&&r[1+l]===r[1+f]&&r[2+l]===r[2+f]&&r[3+l]===r[3+f]&&h++,2=]*?(\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+))?(?:-([\da-z\-]+(?:\.[\da-z\-]+)*))?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i,o=t=>{if("string"!=typeof t)throw new TypeError("Invalid argument expected string");var e=t.match($);if(e)return e.shift(),e;throw new Error(`Invalid argument not valid semver ('${t}' received)`)},i=t=>"*"===t||"x"===t||"X"===t,n=t=>{var e=parseInt(t,10);return isNaN(e)?t:e},H=(t,e)=>{return i(t)||i(e)?0:([t,e]=(t=n(t),e=n(e),typeof t!=typeof e?[String(t),String(e)]:[t,e]),e{for(let t=0;t{var i=r;if("string"!=typeof i)throw new TypeError("Invalid operator type, expected string but got "+typeof i);if(-1===l.indexOf(i))throw new Error("Invalid operator, expected one of "+l.join("|"));i=e,e=o(e=t),i=o(i),t=e.pop(),n=i.pop();var n,i=0!==(e=s(e,i))?e:t&&n?s(t.split("."),n.split(".")):t||n?t?-1:1:0;return u[r].includes(i)},u={">":[1],">=":[0,1],"=":[0],"<=":[-1,0],"<":[-1],"!=":[-1,1]},l=Object.keys(u),g=class{constructor(t,e,r){this.uri=t,this.name=e,this.image=r,this.artists=[],this.discs=new Map}artists;discs;getTracks(){const r=[];return this.discs.forEach((t,e)=>r.push(...t)),r}getDuration(){return this.getTracks().map(t=>t.duration).reduce((t,e)=>t+e)}},L=class{constructor(t,e){this.name=t,this.image=e,this.uri="spotify:local:"+t}uri},B=class{constructor(t,e,r){this.localTrack=t,this.album=e,this.artists=r}get addedAt(){return this.localTrack.addedAt}get uri(){return this.localTrack.uri}get name(){return this.localTrack.name}get duration(){return this.localTrack.duration.milliseconds}get discNumber(){return this.localTrack.discNumber}get trackNumber(){return this.localTrack.trackNumber}},K=((t,e,r)=>{r=null!=t?D(U(t)):{};var i=!e&&t&&t.__esModule?r:a(r,"default",{value:t,enumerable:!0}),n=t,o=void 0,s=void 0;if(n&&"object"==typeof n||"function"==typeof n)for(let t of c(n))R.call(i,t)||t===o||a(i,t,{get:()=>n[t],enumerable:!(s=F(n,t))||s.enumerable});return i})(r()),V=function(t,e){return(V=Object.setPrototypeOf||({__proto__:[]}instanceof Array?function(t,e){t.__proto__=e}:function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])}))(t,e)},h=ft(function(e){return function(t){e(this),this.message=t?t.length+" errors occurred during unsubscription:\n"+t.map(function(t,e){return e+1+") "+t.toString()}).join("\n "):"",this.name="UnsubscriptionError",this.errors=t}}),I.prototype.unsubscribe=function(){var e,t,r;if(!this.closed){this.closed=!0;var i=this._parentage;if(i)if(this._parentage=null,Array.isArray(i))try{for(var n=ht(i),o=n.next();!o.done;o=n.next())o.value.remove(this)}catch(t){a={error:t}}finally{try{o&&!o.done&&(s=n.return)&&s.call(n)}finally{if(a)throw a.error}}else i.remove(this);var s=this.initialTeardown;if(T(s))try{s()}catch(t){r=t instanceof h?t.errors:[t]}var a=this._finalizers;if(a){this._finalizers=null;try{for(var c=ht(a),u=c.next();!u.done;u=c.next()){var l=u.value;try{mt(l)}catch(t){r=null!=r?r:[],t instanceof h?r=O(O([],k(r)),k(t.errors)):r.push(t)}}}catch(t){e={error:t}}finally{try{u&&!u.done&&(t=c.return)&&t.call(c)}finally{if(e)throw e.error}}}if(r)throw new h(r)}},I.prototype.add=function(t){var e;if(t&&t!==this)if(this.closed)mt(t);else{if(t instanceof I){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=null!=(e=this._finalizers)?e:[]).push(t)}},I.prototype._hasParent=function(t){var e=this._parentage;return e===t||Array.isArray(e)&&e.includes(t)},I.prototype._addParent=function(t){var e=this._parentage;this._parentage=Array.isArray(e)?(e.push(t),e):e?[e,t]:t},I.prototype._removeParent=function(t){var e=this._parentage;e===t?this._parentage=null:Array.isArray(e)&&pt(e,t)},I.prototype.remove=function(t){var e=this._finalizers;e&&pt(e,t),t instanceof I&&t._removeParent(this)},I.EMPTY=((r=new I).closed=!0,r),Y=(f=I).EMPTY,p={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1},d={setTimeout:function(t,e){for(var r=[],i=2;it.artists.some(t=>t.uri===e)).sort((t,e)=>_(t.album.name,e.album.name,"ascending")||_(t.discNumber,e.discNumber,"ascending")||_(t.trackNumber,e.trackNumber,"ascending"))}getDisplayName(t){return""===t?"Untitled":t}albumKeyFromName(t){return"spotify:uri:"+t.toLowerCase().replace(/\s/g,"+")}async clearCache(){this.isInitializedSubject.next(!1),this.storageService.cache=[],this.storageService.hasCache=!0,await this.init()}async reset(){this.isInitializedSubject.next(!1),this.storageService.cache=[],this.storageService.hasCache=!1,await this.init()}async init(){if(!this.isReady&&!this.isInitializing){this.isInitializing=!0,this.tracks=new Map,this.albums=new Map,this.artists=new Map;try{await this.processLocalTracks(),await this.postProcessAlbums()}catch(t){console.error("Error while processing",t);let e="Error while processing local files; clearing the cache";t instanceof Error&&(e+=": "+t.message),Spicetify.showNotification(e,!0,5e3),this.storageService.cache=[],this.storageService.hasCache=!0}this.isInitializedSubject.next(!0),this.isInitializing=!1}}async processLocalTracks(){for(const i of await(await ut("LocalFilesAPI")).getTracks()){let e;var t=this.getDisplayName(i.album.name),r=this.albumKeyFromName(t),t=(this.albums.has(r)?e=this.albums.get(r):(e=new g(r,t,this.getImageUrlFromAlbum(i.album)),this.albums.set(r,e)),i.artists.flatMap(t=>this.getArtistsFromString(t.name,e.image)));for(const n of t)this.artists.has(n.uri)||this.artists.set(n.uri,n),e.artists.some(t=>t.uri===n.uri)||e.artists.push(n);r=new B(i,e,t);this.tracks.set(r.uri,r),e.discs.has(i.discNumber)||e.discs.set(i.discNumber,[]),e.discs.get(i.discNumber)?.push(r)}}async postProcessAlbums(){var t,e,r=this.storageService.hasCache,i=[],n=[],o=[];this.albumCountSubject.next(this.albums.size);let s=0;for([t,e]of this.albums.entries()){this.processedAlbumsSubject.next(s+1),s++;var a=await this.postProcessAlbum(t,e);if(!(a.length<=1)){n.push(t);for(var[c,u]of a.entries())if(0!==u.tracks.length){var l=u.tracks[0],c=this.albumKeyFromName(e.name+" "+c),h=new g(c,e.name,this.getImageUrlFromAlbum(l.localTrack.album));for(const d of l.artists)h.artists.some(t=>t.uri===d.uri)||h.artists.push(d);for(const m of u.tracks)(m.album=h).discs.has(m.localTrack.discNumber)||h.discs.set(m.localTrack.discNumber,[]),h.discs.get(m.localTrack.discNumber)?.push(m);o.push(h)}i.push({uri:t,tracks:a.map(t=>t.tracks.map(t=>t.uri))})}}r||(this.storageService.cache=i,this.storageService.hasCache=!0);for(const b of n)this.albums.delete(b);for(const y of o)this.albums.set(y.uri,y);for(const v of this.albums.values())for(var[f,p]of v.discs.entries())v.discs.set(f,p.toSorted((t,e)=>_(t.trackNumber,e.trackNumber,"ascending")))}async postProcessAlbum(e,t){var r=this.storageService.hasCache,i=this.storageService.cache;let n=[];if(r){r=i.find(t=>t.uri===e);void 0!==r&&(n=r.tracks.map(t=>({cover:null,tracks:t.filter(t=>this.tracks.has(t)).map(t=>this.tracks.get(t))})))}else{if(t.artists.length<=1)return[];i=t.getTracks();if(i.length<=1)return[];var o=new Map;for(const c of i){var s=c.artists.map(t=>t.name).join(", ");o.has(s)?o.get(s)?.push(c):o.set(s,[c])}if(1===o.size)return[];for(const u of o.values()){var a=this.getImageUrlFromAlbum(u[0].localTrack.album);let t;try{t=await this.getImage(a)}catch(t){console.error(`Couldn't load image "${a}"`,t),n.push({tracks:u,cover:null});continue}const l=this.getImageDataFromCanvas(t);a=n.find(t=>0===this.getImageDifferenceWithPixelMatch(t.cover,l));void 0===a?n.push({tracks:u,cover:l}):a.tracks.push(...u)}}return n}getArtistsFromString(t,e){return t.split(/[;,]/).map(t=>new L(this.getDisplayName(t.trim()),e))}async getImage(i){return new Promise((t,e)=>{const r=new Image;r.onload=()=>{t(r)},r.onerror=t=>{e(t)},r.src=i})}getImageDataFromCanvas(t){var e=document.createElement("canvas"),e=(e.width=50,e.height=50,e.style.width="50px",e.style.height="50px",e.getContext("2d"));return e.drawImage(t,0,0,t.width,t.height,0,0,50,50),e.getImageData(0,0,50,50)}getImageDifferenceWithPixelMatch(t,e){return(0,K.default)(t.data,e.data,null,t.width,t.height,{threshold:.1})}getImageUrlFromAlbum(t){return 0===t.images.length?"":t.images[0].url}},(async()=>{for(window.localTracksService=new at;!Spicetify?.Platform;)await new Promise(t=>setTimeout(t,100));await 0;var t=await ut("History");const e=new Spicetify.Menu.Item("Rebuild local album cache",!1,async()=>{await window.localTracksService.reset()}),r=new Spicetify.Menu.Item("Clear local album cache",!1,async()=>{await window.localTracksService.clearCache()}),i=t=>{t.includes("better-local-files")?(e.register(),r.register()):(e.deregister(),r.deregister())};i(t.location.pathname),t.listen(t=>{i(t.pathname)}),async function(t,r){var i=await ut("History");const n=async()=>{await lt(t,r)||Spicetify.showNotification("📢 A new version of the custom app is available.",!1,5e3)};if(i.location.pathname==="/"+r)await n();else{let e=null;e=i.listen(async t=>{t.pathname==="/"+r&&(await n(),e?.())})}}("2.0.2","better-local-files")})();function ct(t){return Spicetify.Platform?.[t]}async function ut(t){return async function(t){let e=t();for(;void 0===e;)await new Promise(t=>setTimeout(t,100)),e=t();return e}(()=>ct(t))}async function lt(t,e){e=await(await(await fetch(`https://raw.githubusercontent.com/Pithaya/spicetify-apps/main/custom-apps/${e}/package.json`)).json()).version;return J(t,e,">=")}function _(t,e,r){r="descending"===r?-1:1;return e=t.length?void 0:t)&&t[i++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")}function k(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var i,n,o=r.call(t),s=[];try{for(;(void 0===e||0