isundil 1 рік тому
батько
коміт
69bbcb190f

+ 2 - 5
static/public/js/access.js

@@ -36,7 +36,6 @@ $(() => {
                         type: "DELETE",
                         success: data => {
                             window.ReloadAccessList(data);
-                            MediaStorage.Instance.rebuildMetaList();
                             ok();
                         },
                         error: err => ok(false),
@@ -56,8 +55,7 @@ $(() => {
                             this.#linkStoredAccesses.add({key: i, value: data[i].linkId });
                         this.#UpdateStorage();
                         window.ReloadAccessList(data);
-                        MediaStorage.Instance.rebuildMetaList();
-                        ok(data);
+                        ok();
                     },
                     error: err => ok(false),
                 });
@@ -77,8 +75,7 @@ $(() => {
                                 this.#linkStoredAccesses.add({ key: i, value: data[i].linkId });
                             this.#UpdateStorage();
                             window.ReloadAccessList(data);
-                            MediaStorage.Instance.rebuildMetaList();
-                            ok();
+                            MediaStorage.Instance.rebuildMetaList().finally(ok);
                         });
                     });
                 });

+ 1 - 1
static/public/js/common.js

@@ -58,6 +58,6 @@ $(() => {
     document.Title.pop();
     AccessManager.RebuildAccess();
     loadHash(document.location?.hash?.substr(1));
-    MediaStorage.Instance.downloadMetaList();
+    MediaStorage.Instance.restoreMetaList();
 });
 

+ 117 - 0
static/public/js/indexedCache.js

@@ -0,0 +1,117 @@
+
+(() => {
+    const INDEXEDCACHE_STORAGE_NAME = "databank";
+    const INDEXEDCACHE_DATABASE_NAME = "media";
+    const INDEXEDCACHE_DBVERSION_COLUMN = "dbVersion";
+    IDBTransaction.READ_WRITE = "readwrite";
+    IDBTransaction.READ = "readonly";
+
+    class IndexedCache
+    {
+        #version = parseInt(localStorage?.getItem(INDEXEDCACHE_DBVERSION_COLUMN)) || 0;
+        #openReq = null;
+        #db = null;
+        #mediaStore = null;
+
+        constructor()
+        {
+            this.#openReq = new Promise((ok, ko) => {
+                const DBOpenRequest = window.indexedDB.open(INDEXEDCACHE_STORAGE_NAME, 1);
+                DBOpenRequest.onerror = evt => {
+                    console.error("Failed to open db: ", evt);
+                    this.onDbReady();
+                };
+                DBOpenRequest.onupgradeneeded = evt => {
+                    let mediaStore = evt.target.result.createObjectStore(INDEXEDCACHE_DATABASE_NAME, {
+                        autoIncrement: true,
+                    });
+                };
+                DBOpenRequest.onsuccess = evt => {
+                    this.onDbReady(evt.target.result);
+                };
+            });
+            MediaStorage.Instance.addEventListener("doneLoading", (evt) => {
+                this.pushMedias(MediaStorage.Instance.medias, MediaStorage.Instance.getDbVersion());
+            });
+        }
+
+        onDbReady(db, mediaStore) {
+            this.#openReq = null;
+            this.#db = db;
+            this.#mediaStore = mediaStore;
+        }
+
+        #reduceMedia(media) {
+            let mediaRawData = {
+                date: media.date.getTime(),
+                md5sum: media.md5sum,
+                fixedSum: media.fixedSum,
+                path: media.path,
+                fileName: media.fileName,
+                meta: media.meta,
+                fixedTags: Array.from(media.fixedTags),
+                tags: Array.from(media.tags),
+                version: media.version,
+                writeAccess: media.writeAccess
+            };
+
+            for (let i in mediaRawData.meta) {
+                if (mediaRawData.meta[i].value instanceof Date)
+                    mediaRawData.meta[i].value = mediaRawData.meta[i].value.getTime();
+            }
+
+            return JSON.stringify(mediaRawData);
+        }
+
+        async listMedias() {
+            await this.#openReq;
+            if (!this.#db)
+                return { medias: [], version: 0 };
+            let data = [];
+            try {
+                await new Promise(ok => {
+                    let transaction = this.#db.transaction([INDEXEDCACHE_DATABASE_NAME], IDBTransaction.READ);
+                    transaction.oncomplete = ok;
+                    transaction.onerror = ok;
+                    let storage = transaction.objectStore(INDEXEDCACHE_DATABASE_NAME);
+                    let req = storage.getAll();
+                    req.onsuccess = () => {
+                        data = req.result.map(x => JSON.parse(x));
+                    }
+                });
+            }
+            catch (err) {
+                console.error(err);
+                return { medias: [], version: 0 };
+            }
+            return { medias: data, version: data.length ? this.#version : 0 };
+        }
+
+        async pushMedias(mediaArr, version) {
+            await this.#openReq;
+            if (!this.#db)
+                return;
+            await new Promise(ok => {
+                let transaction = this.#db.transaction([INDEXEDCACHE_DATABASE_NAME], IDBTransaction.READ_WRITE);
+                transaction.oncomplete = ok;
+                transaction.onerror = ok;
+                let storage = transaction.objectStore(INDEXEDCACHE_DATABASE_NAME);
+                mediaArr.forEach(x => storage.put(this.#reduceMedia(x), x.fixedSum));
+            });
+            localStorage?.setItem(INDEXEDCACHE_DBVERSION_COLUMN, version);
+            this.#version = version;
+            console.log("Done updating db");
+        }
+
+        async clean() {
+            await this.#openReq;
+            if (!this.#db)
+                return;
+            this.#db.transaction(INDEXEDCACHE_DATABASE_NAME, IDBTransaction.READ_WRITE);
+            localStorage?.removeItem(INDEXEDCACHE_DBVERSION_COLUMN);
+            this.#version = 0;
+        }
+    }
+
+    window.indexedData = new IndexedCache();
+})();

+ 32 - 6
static/public/js/medias.js

@@ -11,7 +11,7 @@ class Media {
         this.version = data.version;
 
         this.tags = [];
-        this.writeAccess = data.accessType === 2;
+        this.writeAccess = data.writeAccess !== undefined ? data.writeAccess : (data.accessType === 2);
         this.thumbnail = `/api/media/thumbnail/${data.fixedSum}.jpg`;
         this.original = `/api/media/original/${data.fixedSum}`;
         this.ui = null;
@@ -74,7 +74,7 @@ class MediaStorage extends EventTarget
     medias = [];
     oldest = null;
     newest = null;
-    dbVersion = 0;
+    #dbVersion = 0;
     loadingVersion = 0;
 
     constructor() {
@@ -89,12 +89,13 @@ class MediaStorage extends EventTarget
         this.medias = [];
         this.oldest = null;
         this.newest = null;
-        this.dbVersion = 0;
+        this.#dbVersion = 0;
         this.loadingVersion = 0;
     }
 
-    rebuildMetaList() {
+    async rebuildMetaList() {
         this.#reset();
+        await window.indexedData.clean();
         this.dispatchEvent(new CustomEvent("rebuildMedia"));
         window.chronology.reset();
         this.downloadMetaList();
@@ -104,6 +105,24 @@ class MediaStorage extends EventTarget
         this.downloadMetaList(true);
     }
 
+    async restoreMetaList() {
+        if (this.isLoading())
+            return;
+        this.#isLoading = true;
+        document.getElementById("pch-infiniteScrollLoading").classList.remove("hidden");
+        try {
+            await LoadingTasks.push(async () => {
+                let data = await window.indexedData.listMedias();
+                this.pushAll(data.medias.map(x => new Media(x)));
+                this.#updateDbVersion(data.version);
+                this.#isLoading = false;
+            });
+        } catch (err) {
+            console.error(err);
+        }
+        this.downloadMetaList(true);
+    }
+
     downloadMetaList(isUpdate) {
         if (this.isLoading())
             return;
@@ -115,15 +134,16 @@ class MediaStorage extends EventTarget
                 let oldest = isUpdate !== true ? (this.oldest?.date?.getTime() || 0) : 0;
                 let oldestArg = oldest ? `&from=${oldest}` : "";
                 let requestCount = 300;
-                $.get(`/api/media/list?count=${requestCount}${chronology}${oldestArg}&version=${this.dbVersion}`, data => {
+                $.get(`/api/media/list?count=${requestCount}${chronology}${oldestArg}&version=${this.#dbVersion}`, data => {
                     this.pushAll(data.data.map(i => new Media(i)));
                     if (data.first || data.last)
                         window.chronology.rebuildRange(data.first, data.last);
                     this.#isLoading = false;
                     if ((data.data?.length || 0) < requestCount) {
                         document.getElementById("pch-infiniteScrollLoading").classList.add("hidden");
-                        this.dbVersion = Math.max(this.dbVersion, this.loadingVersion);
+                        this.#updateDbVersion(this.loadingVersion);
                         window.ReloadFilters(MediaStorage.Instance);
+                        this.dispatchEvent(new CustomEvent("doneLoading"));
                     }
                     else
                         setTimeout(this.downloadMetaList.bind(this, isUpdate), 25);
@@ -133,6 +153,12 @@ class MediaStorage extends EventTarget
         });
     }
 
+    getDbVersion() { return this.#dbVersion; }
+
+    #updateDbVersion(version) {
+        this.#dbVersion = Math.max(this.#dbVersion, version);
+    }
+
     #pushMeta(metaKey, metaVal) {
         if (metaKey === 'dateTime')
             return;

+ 2 - 0
static/public/js/uiAccess.js

@@ -40,12 +40,14 @@ loginCode.querySelector("button").addEventListener("click", () => {
         return;
     LoadingTasks.push(async () => {
         await AccessManager.LinkLogin(new Set([code]));
+        await MediaStorage.Instance.rebuildMetaList();
         closeLoginPopin();
     });
 });
 
 async function logout(accessId, linkId) {
     await AccessManager.Logout(accessId);
+    await MediaStorage.Instance.rebuildMetaList();
     closeLoginPopin();
 }
 

+ 1 - 0
templates/_footer.js

@@ -9,6 +9,7 @@ module.exports = `
 <script src="/public/js/taskQueue.js"></script>
 <script src="/public/js/access.js"></script>
 <script src="/public/js/medias.js"></script>
+<script src="/public/js/indexedCache.js"></script>
 <script src="/public/js/filters.js"></script>
 <script src="/public/js/uiCommon.js"></script>
 <script src="/public/js/uiMedia.js"></script>