|
class UserFeedbackStore { |
|
constructor() { |
|
this.dbName = 'ClipTaggerDB'; |
|
this.version = 1; |
|
this.db = null; |
|
} |
|
|
|
async initialize() { |
|
return new Promise((resolve, reject) => { |
|
const request = indexedDB.open(this.dbName, this.version); |
|
|
|
request.onerror = () => reject(request.error); |
|
request.onsuccess = () => { |
|
this.db = request.result; |
|
resolve(); |
|
}; |
|
|
|
request.onupgradeneeded = (event) => { |
|
const db = event.target.result; |
|
|
|
|
|
if (!db.objectStoreNames.contains('audioFeedback')) { |
|
const audioStore = db.createObjectStore('audioFeedback', { |
|
keyPath: 'id', |
|
autoIncrement: true |
|
}); |
|
audioStore.createIndex('timestamp', 'timestamp', { unique: false }); |
|
} |
|
|
|
if (!db.objectStoreNames.contains('tagFeedback')) { |
|
const tagStore = db.createObjectStore('tagFeedback', { |
|
keyPath: 'id', |
|
autoIncrement: true |
|
}); |
|
tagStore.createIndex('tag', 'tag', { unique: false }); |
|
tagStore.createIndex('timestamp', 'timestamp', { unique: false }); |
|
} |
|
|
|
if (!db.objectStoreNames.contains('customTags')) { |
|
const customTagStore = db.createObjectStore('customTags', { |
|
keyPath: 'tag' |
|
}); |
|
customTagStore.createIndex('usage', 'usage', { unique: false }); |
|
} |
|
}; |
|
}); |
|
} |
|
|
|
async saveAudioFeedback(audioHash, originalTags, correctedTags, audioFeatures) { |
|
if (!this.db) await this.initialize(); |
|
|
|
const transaction = this.db.transaction(['audioFeedback'], 'readwrite'); |
|
const store = transaction.objectStore('audioFeedback'); |
|
|
|
const feedback = { |
|
audioHash, |
|
originalTags, |
|
correctedTags, |
|
audioFeatures, |
|
timestamp: Date.now() |
|
}; |
|
|
|
return new Promise((resolve, reject) => { |
|
const request = store.add(feedback); |
|
request.onsuccess = () => resolve(request.result); |
|
request.onerror = () => reject(request.error); |
|
}); |
|
} |
|
|
|
async saveTagFeedback(tag, feedback, audioHash) { |
|
if (!this.db) await this.initialize(); |
|
|
|
const transaction = this.db.transaction(['tagFeedback'], 'readwrite'); |
|
const store = transaction.objectStore('tagFeedback'); |
|
|
|
const tagFeedback = { |
|
tag, |
|
feedback, |
|
audioHash, |
|
timestamp: Date.now() |
|
}; |
|
|
|
return new Promise((resolve, reject) => { |
|
const request = store.add(tagFeedback); |
|
request.onsuccess = () => resolve(request.result); |
|
request.onerror = () => reject(request.error); |
|
}); |
|
} |
|
|
|
async saveCustomTag(tag) { |
|
if (!this.db) await this.initialize(); |
|
|
|
const transaction = this.db.transaction(['customTags'], 'readwrite'); |
|
const store = transaction.objectStore('customTags'); |
|
|
|
return new Promise((resolve, reject) => { |
|
const getRequest = store.get(tag); |
|
getRequest.onsuccess = () => { |
|
const existing = getRequest.result; |
|
const tagData = existing ? |
|
{ ...existing, usage: existing.usage + 1 } : |
|
{ tag, usage: 1, timestamp: Date.now() }; |
|
|
|
const putRequest = store.put(tagData); |
|
putRequest.onsuccess = () => resolve(putRequest.result); |
|
putRequest.onerror = () => reject(putRequest.error); |
|
}; |
|
getRequest.onerror = () => reject(getRequest.error); |
|
}); |
|
} |
|
|
|
async getCustomTags(limit = 20) { |
|
if (!this.db) await this.initialize(); |
|
|
|
const transaction = this.db.transaction(['customTags'], 'readonly'); |
|
const store = transaction.objectStore('customTags'); |
|
const index = store.index('usage'); |
|
|
|
return new Promise((resolve, reject) => { |
|
const request = index.openCursor(null, 'prev'); |
|
const results = []; |
|
|
|
request.onsuccess = (event) => { |
|
const cursor = event.target.result; |
|
if (cursor && results.length < limit) { |
|
results.push(cursor.value); |
|
cursor.continue(); |
|
} else { |
|
resolve(results); |
|
} |
|
}; |
|
request.onerror = () => reject(request.error); |
|
}); |
|
} |
|
|
|
async getTagFeedback(tag = null) { |
|
if (!this.db) await this.initialize(); |
|
|
|
const transaction = this.db.transaction(['tagFeedback'], 'readonly'); |
|
const store = transaction.objectStore('tagFeedback'); |
|
|
|
return new Promise((resolve, reject) => { |
|
let request; |
|
if (tag) { |
|
const index = store.index('tag'); |
|
request = index.getAll(tag); |
|
} else { |
|
request = store.getAll(); |
|
} |
|
|
|
request.onsuccess = () => resolve(request.result); |
|
request.onerror = () => reject(request.error); |
|
}); |
|
} |
|
|
|
async getAudioFeedback(limit = 100) { |
|
if (!this.db) await this.initialize(); |
|
|
|
const transaction = this.db.transaction(['audioFeedback'], 'readonly'); |
|
const store = transaction.objectStore('audioFeedback'); |
|
const index = store.index('timestamp'); |
|
|
|
return new Promise((resolve, reject) => { |
|
const request = index.openCursor(null, 'prev'); |
|
const results = []; |
|
|
|
request.onsuccess = (event) => { |
|
const cursor = event.target.result; |
|
if (cursor && results.length < limit) { |
|
results.push(cursor.value); |
|
cursor.continue(); |
|
} else { |
|
resolve(results); |
|
} |
|
}; |
|
request.onerror = () => reject(request.error); |
|
}); |
|
} |
|
|
|
|
|
async hashAudioFile(file) { |
|
const arrayBuffer = await file.arrayBuffer(); |
|
const hashBuffer = await crypto.subtle.digest('SHA-256', arrayBuffer); |
|
const hashArray = Array.from(new Uint8Array(hashBuffer)); |
|
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('').substring(0, 16); |
|
} |
|
|
|
async clearAllData() { |
|
if (!this.db) await this.initialize(); |
|
|
|
const transaction = this.db.transaction(['audioFeedback', 'tagFeedback', 'customTags'], 'readwrite'); |
|
|
|
await Promise.all([ |
|
new Promise((resolve, reject) => { |
|
const request = transaction.objectStore('audioFeedback').clear(); |
|
request.onsuccess = () => resolve(); |
|
request.onerror = () => reject(request.error); |
|
}), |
|
new Promise((resolve, reject) => { |
|
const request = transaction.objectStore('tagFeedback').clear(); |
|
request.onsuccess = () => resolve(); |
|
request.onerror = () => reject(request.error); |
|
}), |
|
new Promise((resolve, reject) => { |
|
const request = transaction.objectStore('customTags').clear(); |
|
request.onsuccess = () => resolve(); |
|
request.onerror = () => reject(request.error); |
|
}) |
|
]); |
|
} |
|
} |
|
|
|
export default UserFeedbackStore; |