mirror of
https://github.com/vladmandic/sdnext.git
synced 2026-01-27 15:02:48 +03:00
- Enhance gallery sorting functionality - Update IndexedDB operations for better reliability
196 lines
5.9 KiB
JavaScript
196 lines
5.9 KiB
JavaScript
/**
|
|
* @type {?IDBDatabase}
|
|
*/
|
|
let db = null;
|
|
|
|
async function initIndexDB() {
|
|
async function createDB() {
|
|
return new Promise((resolve, reject) => {
|
|
const request = indexedDB.open('SDNext', 2);
|
|
request.onerror = (evt) => reject(evt);
|
|
request.onsuccess = (evt) => {
|
|
db = evt.target.result;
|
|
const countAll = db
|
|
.transaction(['thumbs'], 'readwrite')
|
|
.objectStore('thumbs')
|
|
.count();
|
|
countAll.onsuccess = () => log('initIndexDB', countAll.result);
|
|
resolve();
|
|
};
|
|
request.onupgradeneeded = (evt) => {
|
|
db = evt.target.result;
|
|
const oldver = evt.oldVersion;
|
|
if (oldver < 1) {
|
|
const store = db.createObjectStore('thumbs', { keyPath: 'hash' });
|
|
store.createIndex('hash', 'hash', { unique: true });
|
|
}
|
|
if (oldver < 2) {
|
|
const existingStore = request.transaction.objectStore('thumbs');
|
|
existingStore.createIndex('folder', 'folder', { unique: false });
|
|
}
|
|
resolve();
|
|
};
|
|
});
|
|
}
|
|
|
|
if (!db) await createDB();
|
|
}
|
|
|
|
async function add(record) {
|
|
if (!db) return null;
|
|
return new Promise((resolve, reject) => {
|
|
const request = db
|
|
.transaction(['thumbs'], 'readwrite')
|
|
.objectStore('thumbs')
|
|
.add(record);
|
|
request.onsuccess = (evt) => resolve(evt);
|
|
request.onerror = (evt) => reject(evt);
|
|
});
|
|
}
|
|
|
|
async function del(hash) {
|
|
if (!db) return null;
|
|
return new Promise((resolve, reject) => {
|
|
const request = db
|
|
.transaction(['thumbs'], 'readwrite')
|
|
.objectStore('thumbs')
|
|
.delete(hash);
|
|
request.onsuccess = (evt) => resolve(evt);
|
|
request.onerror = (evt) => reject(evt);
|
|
});
|
|
}
|
|
|
|
async function get(hash) {
|
|
if (!db) return null;
|
|
return new Promise((resolve, reject) => {
|
|
const request = db
|
|
.transaction(['thumbs'], 'readwrite')
|
|
.objectStore('thumbs')
|
|
.get(hash);
|
|
request.onsuccess = () => resolve(request.result);
|
|
request.onerror = (evt) => reject(evt);
|
|
});
|
|
}
|
|
|
|
async function put(record) {
|
|
if (!db) return null;
|
|
return new Promise((resolve, reject) => {
|
|
const request = db
|
|
.transaction(['thumbs'], 'readwrite')
|
|
.objectStore('thumbs')
|
|
.put(record);
|
|
request.onsuccess = (evt) => resolve(evt);
|
|
request.onerror = (evt) => reject(evt);
|
|
});
|
|
}
|
|
|
|
async function idbGetAllKeys(index = null, query = null) {
|
|
if (!db) return null;
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
let request;
|
|
const transaction = db.transaction('thumbs', 'readonly');
|
|
transaction.onabort = (e) => reject(e);
|
|
|
|
const store = transaction.objectStore('thumbs');
|
|
if (index) {
|
|
request = store.index(index).getAllKeys(query);
|
|
} else {
|
|
request = store.getAllKeys(query);
|
|
}
|
|
request.onsuccess = () => resolve(request.result);
|
|
request.onerror = (e) => reject(e);
|
|
} catch (err) {
|
|
reject(err);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get the number of entries in the IndexedDB thumbnail cache.
|
|
* @global
|
|
* @param {?string} folder - If specified, get the count for this gallery folder. Otherwise get the total count.
|
|
* @returns {Promise<number>}
|
|
*/
|
|
async function idbCount(folder = null) {
|
|
if (!db) return null;
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
let request;
|
|
const transaction = db.transaction('thumbs', 'readonly');
|
|
transaction.onabort = (e) => reject(e);
|
|
|
|
const store = transaction.objectStore('thumbs');
|
|
if (folder) {
|
|
request = store.index('folder').count(folder);
|
|
} else {
|
|
request = store.count();
|
|
}
|
|
request.onsuccess = () => resolve(request.result);
|
|
request.onerror = (e) => reject(e);
|
|
} catch (err) {
|
|
reject(err);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Cleanup function for IndexedDB thumbnail cache.
|
|
* @global
|
|
* @param {Set<string>} keepSet - Set containing the hashes of the current files in the folder
|
|
* @param {string} folder - Folder name/path
|
|
* @param {AbortSignal} signal - Signal from the AbortController for thumbCacheCleanup()
|
|
*/
|
|
async function idbFolderCleanup(keepSet, folder, signal) {
|
|
if (!db) return null;
|
|
if (!(keepSet instanceof Set)) {
|
|
throw new TypeError('IndexedDB cleaning function must be given a Set() of the current gallery hashes');
|
|
}
|
|
if (typeof folder !== 'string') {
|
|
throw new Error('IndexedDB cleaning function must be told the current active folder');
|
|
}
|
|
|
|
// Use range query to match folder and all its subdirectories
|
|
const folderNormalized = folder.replace(/\/+/g, '/').replace(/\/$/, '');
|
|
const range = IDBKeyRange.bound(folderNormalized, `${folderNormalized}\uffff`, false, true);
|
|
let removals = new Set(await idbGetAllKeys('folder', range));
|
|
removals = removals.difference(keepSet); // Don't need to keep full set in memory
|
|
const totalRemovals = removals.size;
|
|
if (signal.aborted) {
|
|
throw `Aborting. ${signal.reason}`; // eslint-disable-line no-throw-literal
|
|
}
|
|
return new Promise((resolve, reject) => {
|
|
const transaction = db.transaction('thumbs', 'readwrite');
|
|
function abortTransaction() {
|
|
signal.removeEventListener('abort', abortTransaction);
|
|
transaction.abort();
|
|
}
|
|
signal.addEventListener('abort', abortTransaction);
|
|
transaction.onabort = () => {
|
|
signal.removeEventListener('abort', abortTransaction);
|
|
reject(`Aborting. ${signal.reason}`); // eslint-disable-line prefer-promise-reject-errors
|
|
};
|
|
transaction.onerror = () => {
|
|
signal.removeEventListener('abort', abortTransaction);
|
|
reject(new Error('Database transaction error'));
|
|
};
|
|
transaction.oncomplete = async () => {
|
|
signal.removeEventListener('abort', abortTransaction);
|
|
resolve(totalRemovals);
|
|
};
|
|
|
|
try {
|
|
const store = transaction.objectStore('thumbs');
|
|
removals.forEach((entry) => { store.delete(entry); });
|
|
} catch (err) {
|
|
error(err);
|
|
abortTransaction();
|
|
}
|
|
});
|
|
}
|
|
|
|
window.idbAdd = add;
|
|
window.idbDel = del;
|
|
window.idbGet = get;
|
|
window.idbPut = put;
|