217 lines
6 KiB
JavaScript
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(); |