audio-vis/out/js/worker.js
2020-08-06 23:44:37 +02:00

217 lines
6 KiB
JavaScript

class EventHandler {
constructor(worker) {
this.events = {};
this.worker = worker;
this.worker.addEventListener('message', this.handleEvent.bind(this));
}
addEvent(name, cb) {
this.events[name] = cb;
}
sendData(name, status, data) {
this.worker.postMessage({
cmd: name,
status: status,
data: data
});
}
handleEvent(event) {
let data = event.data;
if (!data.cmd) {
return;
}
if (this.events[data.cmd]) {
this.events[data.cmd](data.data);
}
}
}
class Database {
constructor(name, version) {
this.isInit = false;
this.name = name;
this.version = version;
this.errored = false;
this.db;
this.prepareDB();
}
async prepareDB() {
if (this.isInit || this.errored) {
return;
}
let req = this.db = indexedDB.open(this.name, this.version);
req.onerror = DatabaseHandler.onError.bind(this);
req.onsuccess = DatabaseHandler.onSuccess.bind(this);
req.onupgradeneeded = DatabaseHandler.onUpgrade.bind(this);
req.onblocked = DatabaseHandler.onBlocked.bind(this);
}
async set(key, data, store) {
data['key'] = key;
return await this.run('put', data, store);
}
async get(key, store) {
return await this.run('get', key, store);
}
async remove(key, store) {
return await this.run('delete', key, store);
}
check() {
return !(!this.isInit || this.errored);
}
async getTX(store) {
return await this.db.transaction([store], "readwrite")
}
async getObjectStore(tx, store) {
return await tx.objectStore(store)
}
async run(action, key, store) {
if (this.check()) {
let tx = await this.getTX(store);
let obj = await this.getObjectStore(tx, store);
let data = await this.request(obj[action](key));
await tx.complete
return await data;
}
return null;
}
request(req) {
return new Promise((resolve, reject) => {
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
}
}
class DatabaseHandler {
static onError(e) {
this.errored = true;
eventHandler.sendData("databaseError", "error", e.message);
}
static onSuccess(e) {
this.db = this.db.result;
this.isInit = true;
eventHandler.sendData("databaseCreated", "success", "");
eventHandler.handleEvent({
data: {
cmd: 'dbReady-' + this.name,
data: this.db
}
});
}
static onUpgrade(e) {
eventHandler.sendData("databaseUpgradeNeeded", "info", e.message);
eventHandler.handleEvent({
data: {
cmd: 'dbUpgrade-' + this.name,
data: this.db
}
});
}
static onBlocked(e) {
eventHandler.sendData("databaseBlocked", "error", e.message);
}
}
self.importScripts('jsmediatags.min.js');
class Tagger {
constructor(worker) {
this.db = new Database("SongLib", 1);
}
static prepareName(data) {
let name = data.name || '';
return name.replace(/[^\w\s]/gi, '').split(" ").join("")
}
init() {
eventHandler.addEvent('getData', this.getData.bind(this));
eventHandler.addEvent('removeData', this.getData.bind(this));
eventHandler.addEvent('setData', this.getData.bind(this));
eventHandler.addEvent('dbReady-SongLib', this.ready.bind(this));
eventHandler.addEvent('dbUpgrade-SongLib', this.upgrade.bind(this));
}
async getData(data) {
let key = Tagger.prepareName(data),
newData = await this.db.get(key, 'songs'),
handlerName = data.force ? 'id3-request-force' : 'id3-request';
if (newData) {
newData['index'] = data['index'];
eventHandler.sendData(handlerName, 'success', newData);
} else {
this.parseData(data, key).then(r => {
r['index'] = data['index'];
eventHandler.sendData(handlerName, 'success', r);
});
eventHandler.sendData(handlerName, 'waiting', data);
}
}
async removeData(data) {
let key = Tagger.prepareName(data),
newData = await this.db.remove(key, 'songs');
eventHandler.sendData('id3-remove', 'success', newData);
}
async setData(data, key) {
let newData = await this.db.set(key, data, 'songs');
eventHandler.sendData('id3-set', 'success', newData);
}
ready(data) {
console.log("[ID3] > Song Database Ready");
eventHandler.sendData('id3-ready', "startup", "");
}
upgrade(data) {
let db = data.result,
songs = db.createObjectStore("songs", {keyPath: 'key'});
songs.createIndex("name", "name", {unique: false});
}
//if not found in key-value storage read it! this take some time so this is async!
async parseData(data, key) {
let tag = await new Promise((resolve, reject) => {
new jsmediatags.Reader(data.file)
.read({
onSuccess: (tag) => {
resolve(tag);
},
onError: (error) => {
console.log(`[ID3] > Error Parsing Data!`);
resolve({
tags: {}
});
}
});
})
let tags = tag.tags,
values = {
title: tags.title || data.name,
artist: tags.artist || 'VA',
genre: tags.genre || 'Unknown',
year: tags.year || 1970,
key: key
};
await this.setData(values, key);
return values;
}
}
const tagger = new Tagger(self),
eventHandler = new EventHandler(self);
tagger.init();