const app = window.app ??= {} const view = window.view ??= {} import * as device from 'device' import Store from 'store' // TODO: decouple from app.browser and add loading bar export let covers export const Start = async () => { covers = await Store.Open('cover', 'data') } export const Init = async () => { view.loadingStatus = document.getElementById('loading-status') app.trackCount = 0 app.index = await Entries() } export const Entries = async (hHandle, eParent) => { let dirE = await device.Entries(hHandle) let out = [] for(let [ n, h ] of dirE) { let e = await Create(n, h, eParent) if(e != undefined) { out.push(e) displayTrackFound(e) } } return out } export const displayTrackFound = (entry) => { app.trackCount++ view.loadingStatus.innerText = `${entry.handle.name}\n(${app.trackCount})` } export const trackFiletypes = [ '.mp3', '.ogg', '.wav', '.flac' ] export const Create = async (sName, hHandle, eParent) => { let e = { handle: hHandle } if(eParent) { e.parent = eParent } switch(hHandle.kind) { case 'directory': e.entries = await Entries(hHandle, e) e.name = sName break case 'file': let ext = sName.slice(sName.lastIndexOf('.')) if(trackFiletypes.includes(ext)) { await Track(e) } else { return } } e.order = e.trackNumber ?? 0 return e } const Track = async e => { let md = await Metadata(e) e.album = md.album e.name = md.title e.artist = md.artist ?? "Unknown Artist" e.trackNumber = md.track ? parseInt(md.track) : Infinity e.lyrics = md.lyrics?.lyrics && new Map([ [ 0, md.lyrics?.lyrics ] ]) e.coverId = md.picture && await IndexCover(md.picture) } export const IndexCover = async ({ format, data }) => { let id = format + '-' + data.length // TODO: don't get, just check if has let c = await covers.Get(id) .catch(err => {}) if(c == null) { c = new Blob([ new Uint8Array(data) ], { type: format }) await covers.Set(id, c) } return id } export const GetCover = (eTrack) => { return covers.Get(eTrack.coverId) } const Metadata = async e => { let d = await device.Open(e.handle).then(mediaTags) .catch(e => console.error(e)) if(!d) { return /((?\d+)\s+)?((?.+)-\s*)?\s*(?.+)\s*\.\w+/ .exec(e.handle.name) .groups } else { return d.tags } } const mediaTags = blob => new Promise((resolve, reject) => { jsmediatags.read(blob, { onSuccess(tags) { resolve(tags) }, onError(err) { reject(err) } }) })