Add: Search page, Add: Bookshelf list view, Fix: Audiobook progress sync, Fix: Download audiobook button, Change: User audiobook data to use SQL table

This commit is contained in:
advplyr 2021-11-19 20:00:34 -06:00
parent b6dd37b7f6
commit 3b6e7e1ce2
16 changed files with 908 additions and 1619 deletions

230
plugins/localStore.js Normal file
View file

@ -0,0 +1,230 @@
import { Storage } from '@capacitor/storage'
class LocalStorage {
constructor(vuexStore) {
this.vuexStore = vuexStore
this.userAudiobooksLoaded = false
this.downloadFolder = null
this.userAudiobooks = {}
}
async getMostRecentUserAudiobook(audiobookId) {
if (!this.userAudiobooksLoaded) {
await this.loadUserAudiobooks()
}
var local = this.getUserAudiobook(audiobookId)
var server = this.vuexStore.getters['user/getUserAudiobook'](audiobookId)
if (local && server) {
if (local.lastUpdate > server.lastUpdate) {
console.log('[LocalStorage] Most recent user audiobook is from LOCAL')
return local
}
console.log('[LocalStorage] Most recent user audiobook is from SERVER')
return server
} else if (local) {
console.log('[LocalStorage] Most recent user audiobook is from LOCAL')
return local
} else if (server) {
console.log('[LocalStorage] Most recent user audiobook is from SERVER')
return server
}
return null
}
async loadUserAudiobooks() {
try {
var val = (await Storage.get({ key: 'userAudiobooks' }) || {}).value || null
this.userAudiobooks = val ? JSON.parse(val) : {}
this.userAudiobooksLoaded = true
this.vuexStore.commit('user/setLocalUserAudiobooks', { ...this.userAudiobooks })
} catch (error) {
console.error('[LocalStorage] Failed to load user audiobooks', error)
}
}
async saveUserAudiobooks() {
try {
await Storage.set({ key: 'userAudiobooks', value: JSON.stringify(this.userAudiobooks) })
} catch (error) {
console.error('[LocalStorage] Failed to set user audiobooks', error)
}
}
async setAllAudiobookProgress(progresses) {
this.userAudiobooks = progresses
await this.saveUserAudiobooks()
this.vuexStore.commit('user/setLocalUserAudiobooks', { ...this.userAudiobooks })
}
async updateUserAudiobookData(progressPayload) {
this.userAudiobooks[progressPayload.audiobookId] = {
...progressPayload
}
await this.saveUserAudiobooks()
this.vuexStore.commit('user/setUserAudiobooks', { ...this.userAudiobooks })
this.vuexStore.commit('user/setLocalUserAudiobooks', { ...this.userAudiobooks })
}
async removeAudiobookProgress(audiobookId) {
if (!this.userAudiobooks[audiobookId]) return
delete this.userAudiobooks[audiobookId]
await this.saveUserAudiobooks()
this.vuexStore.commit('user/setUserAudiobooks', { ...this.userAudiobooks })
this.vuexStore.commit('user/setLocalUserAudiobooks', { ...this.userAudiobooks })
}
getUserAudiobook(audiobookId) {
return this.userAudiobooks[audiobookId] || null
}
async setToken(token) {
try {
if (token) {
await Storage.set({ key: 'token', value: token })
} else {
await Storage.remove({ key: 'token' })
}
} catch (error) {
console.error('[LocalStorage] Failed to set token', error)
}
}
async getToken() {
try {
return (await Storage.get({ key: 'token' }) || {}).value || null
} catch (error) {
console.error('[LocalStorage] Failed to get token', error)
return null
}
}
async setCurrentLibrary(library) {
try {
if (library) {
await Storage.set({ key: 'library', value: JSON.stringify(library) })
} else {
await Storage.remove({ key: 'library' })
}
} catch (error) {
console.error('[LocalStorage] Failed to set library', error)
}
}
async getCurrentLibrary() {
try {
var _value = (await Storage.get({ key: 'library' }) || {}).value || null
if (!_value) return null
return JSON.parse(_value)
} catch (error) {
console.error('[LocalStorage] Failed to get current library', error)
return null
}
}
async setDownloadFolder(folderObj) {
try {
if (folderObj) {
await Storage.set({ key: 'downloadFolder', value: JSON.stringify(folderObj) })
this.downloadFolder = folderObj
this.vuexStore.commit('setDownloadFolder', { ...this.downloadFolder })
} else {
await Storage.remove({ key: 'downloadFolder' })
this.downloadFolder = null
this.vuexStore.commit('setDownloadFolder', null)
}
} catch (error) {
console.error('[LocalStorage] Failed to set download folder', error)
}
}
async getDownloadFolder() {
try {
var _value = (await Storage.get({ key: 'downloadFolder' }) || {}).value || null
if (!_value) return null
this.downloadFolder = JSON.parse(_value)
this.vuexStore.commit('setDownloadFolder', { ...this.downloadFolder })
return this.downloadFolder
} catch (error) {
console.error('[LocalStorage] Failed to get download folder', error)
return null
}
}
async getServerUrl() {
try {
return (await Storage.get({ key: 'serverUrl' }) || {}).value || null
} catch (error) {
console.error('[LocalStorage] Failed to get serverUrl', error)
return null
}
}
async setUserSettings(settings) {
try {
await Storage.set({ key: 'userSettings', value: JSON.stringify(settings) })
} catch (error) {
console.error('[LocalStorage] Failed to update user settings', error)
}
}
async getUserSettings() {
try {
var settingsObj = await Storage.get({ key: 'userSettings' }) || {}
return settingsObj.value ? JSON.parse(settingsObj.value) : null
} catch (error) {
console.error('[LocalStorage] Failed to get user settings', error)
return null
}
}
async setCurrent(current) {
try {
if (current) {
await Storage.set({ key: 'current', value: JSON.stringify(current) })
} else {
await Storage.remove({ key: 'current' })
}
} catch (error) {
console.error('[LocalStorage] Failed to set current', error)
}
}
async getCurrent() {
try {
var currentObj = await Storage.get({ key: 'current' }) || {}
return currentObj.value ? JSON.parse(currentObj.value) : null
} catch (error) {
console.error('[LocalStorage] Failed to get current', error)
return null
}
}
async setBookshelfView(view) {
try {
await Storage.set({ key: 'bookshelfView', value: view })
} catch (error) {
console.error('[LocalStorage] Failed to set bookshelf view', error)
}
}
async getBookshelfView() {
try {
var view = await Storage.get({ key: 'bookshelfView' }) || {}
return view.value || null
} catch (error) {
console.error('[LocalStorage] Failed to get bookshelf view', error)
return null
}
}
}
export default ({ app, store }, inject) => {
inject('localStore', new LocalStorage(store))
}

439
plugins/sqlStore.js Normal file
View file

@ -0,0 +1,439 @@
import { Capacitor } from '@capacitor/core';
import { CapacitorDataStorageSqlite } from 'capacitor-data-storage-sqlite';
class StoreService {
store
platform
isOpen = false
constructor(vuexStore) {
this.vuexStore = vuexStore
this.currentTable = null
this.init()
}
/**
* Plugin Initialization
*/
init() {
this.platform = Capacitor.getPlatform()
this.store = CapacitorDataStorageSqlite
console.log('in init ', this.platform)
}
/**
* Open a Store
* @param _dbName string optional
* @param _table string optional
* @param _encrypted boolean optional
* @param _mode string optional
*/
async openStore(_dbName, _table, _encrypted, _mode) {
if (this.store != null) {
const database = _dbName ? _dbName : "storage"
const table = _table ? _table : "storage_table"
const encrypted = _encrypted ? _encrypted : false
const mode = _mode ? _mode : "no-encryption"
this.isOpen = false
try {
await this.store.openStore({ database, table, encrypted, mode })
// return Promise.resolve()
this.currentTable = table
this.isOpen = true
return true
} catch (err) {
// return Promise.reject(err)
return false
}
} else {
// return Promise.reject(new Error("openStore: Store not opened"))
return false
}
}
/**
* Close a store
* @param dbName
* @returns
*/
async closeStore(dbName) {
if (this.store != null) {
try {
await this.store.closeStore({ database: dbName })
return Promise.resolve()
} catch (err) {
return Promise.reject(err)
}
} else {
return Promise.reject(new Error("close: Store not opened"))
}
}
/**
* Check if a store is opened
* @param dbName
* @returns
*/
async isStoreOpen(dbName) {
if (this.store != null) {
try {
const ret = await this.store.isStoreOpen({ database: dbName })
return Promise.resolve(ret)
} catch (err) {
return Promise.reject(err)
}
} else {
return Promise.reject(new Error("isStoreOpen: Store not opened"))
}
}
/**
* Check if a store already exists
* @param dbName
* @returns
*/
async isStoreExists(dbName) {
if (this.store != null) {
try {
const ret = await this.store.isStoreExists({ database: dbName })
return Promise.resolve(ret)
} catch (err) {
return Promise.reject(err)
}
} else {
return Promise.reject(new Error("isStoreExists: Store not opened"))
}
}
/**
* Create/Set a Table
* @param table string
*/
async setTable(table) {
if (this.store != null) {
try {
await this.store.setTable({ table })
this.currentTable = table
return Promise.resolve()
} catch (err) {
return Promise.reject(err)
}
} else {
return Promise.reject(new Error("setTable: Store not opened"))
}
}
/**
* Set of Key
* @param key string
* @param value string
*/
async setItem(key, value) {
if (this.store != null) {
if (key.length > 0) {
try {
await this.store.set({ key, value });
return Promise.resolve();
} catch (err) {
return Promise.reject(err);
}
} else {
return Promise.reject(new Error("setItem: Must give a key"));
}
} else {
return Promise.reject(new Error("setItem: Store not opened"));
}
}
/**
* Get the Value for a given Key
* @param key string
*/
async getItem(key) {
if (this.store != null) {
if (key.length > 0) {
try {
const { value } = await this.store.get({ key });
console.log("in getItem value ", value)
return Promise.resolve(value);
} catch (err) {
console.error(`in getItem key: ${key} err: ${JSON.stringify(err)}`)
return Promise.reject(err);
}
} else {
return Promise.reject(new Error("getItem: Must give a key"));
}
} else {
return Promise.reject(new Error("getItem: Store not opened"));
}
}
async isKey(key) {
if (this.store != null) {
if (key.length > 0) {
try {
const { result } = await this.store.iskey({ key });
return Promise.resolve(result);
} catch (err) {
return Promise.reject(err);
}
} else {
return Promise.reject(new Error("isKey: Must give a key"));
}
} else {
return Promise.reject(new Error("isKey: Store not opened"));
}
}
async getAllKeysValues() {
if (this.store != null) {
try {
const { keysvalues } = await this.store.keysvalues();
return Promise.resolve(keysvalues);
} catch (err) {
return Promise.reject(err);
}
} else {
return Promise.reject(new Error("getAllKeysValues: Store not opened"));
}
}
async removeItem(key) {
if (this.store != null) {
if (key.length > 0) {
try {
await this.store.remove({ key });
return Promise.resolve();
} catch (err) {
return Promise.reject(err);
}
} else {
return Promise.reject(new Error("removeItem: Must give a key"));
}
} else {
return Promise.reject(new Error("removeItem: Store not opened"));
}
}
async clear() {
if (this.store != null) {
try {
await this.store.clear()
return true
} catch (err) {
console.error('[SqlStore] Failed to clear table', err.message)
return false
}
} else {
console.error('[SqlStore] Clear: Store not opened')
return false
}
}
async deleteStore(_dbName) {
const database = _dbName ? _dbName : "storage"
if (this.store != null) {
try {
await this.store.deleteStore({ database })
return Promise.resolve();
} catch (err) {
return Promise.reject(err.message)
}
} else {
return Promise.reject(new Error("deleteStore: Store not opened"));
}
}
async isTable(table) {
if (this.store != null) {
if (table.length > 0) {
try {
const { result } = await this.store.isTable({ table });
return Promise.resolve(result);
} catch (err) {
return Promise.reject(err);
}
} else {
return Promise.reject(new Error("isTable: Must give a table"));
}
} else {
return Promise.reject(new Error("isTable: Store not opened"));
}
}
async getAllTables() {
if (this.store != null) {
try {
const { tables } = await this.store.tables();
return Promise.resolve(tables);
} catch (err) {
return Promise.reject(err);
}
} else {
return Promise.reject(new Error("getAllTables: Store not opened"));
}
}
async ensureTable(tablename) {
if (!this.isOpen) {
var success = await this.openStore('storage', tablename)
if (!success) {
console.error('Store failed to open')
return false
}
}
try {
await this.setTable(tablename)
console.log('[SqlStore] Set Table ' + this.currentTable)
return true
} catch (error) {
console.error('Failed to set table', error)
return false
}
}
async setDownload(download) {
if (!download) return false
if (!(await this.ensureTable('downloads'))) {
return false
}
if (!download.id) {
console.error(`[SqlStore] set download invalid download ${download ? JSON.stringify(download) : 'null'}`)
return false
}
try {
await this.setItem(download.id, JSON.stringify(download))
console.log(`[STORE] Set Download ${download.id}`)
return true
} catch (error) {
console.error('Failed to set download in store', error)
return false
}
}
async removeDownload(id) {
if (!id) return false
if (!(await this.ensureTable('downloads'))) {
return false
}
try {
await this.removeItem(id)
console.log(`[STORE] Removed download ${id}`)
return true
} catch (error) {
console.error('Failed to remove download in store', error)
return false
}
}
async getAllDownloads() {
if (!(await this.ensureTable('downloads'))) {
return false
}
var keysvalues = await this.getAllKeysValues()
var downloads = []
for (let i = 0; i < keysvalues.length; i++) {
try {
var download = JSON.parse(keysvalues[i].value)
if (!download.id) {
console.error('[SqlStore] Removing invalid download')
await this.removeItem(keysvalues[i].key)
} else {
downloads.push(download)
}
} catch (error) {
console.error('Failed to parse download', error)
await this.removeItem(keysvalues[i].key)
}
}
return downloads
}
async setUserAudiobookData(userAudiobookData) {
if (!(await this.ensureTable('userAudiobookData'))) {
return false
}
try {
await this.setItem(userAudiobookData.audiobookId, JSON.stringify(userAudiobookData))
this.vuexStore.commit('user/setUserAudiobookData', userAudiobookData)
console.log(`[STORE] Set UserAudiobookData ${userAudiobookData.audiobookId}`)
return true
} catch (error) {
console.error('Failed to set UserAudiobookData in store', error)
return false
}
}
async removeUserAudiobookData(audiobookId) {
if (!(await this.ensureTable('userAudiobookData'))) {
return false
}
try {
await this.removeItem(audiobookId)
this.vuexStore.commit('user/removeUserAudiobookData', audiobookId)
console.log(`[STORE] Removed userAudiobookData ${id}`)
return true
} catch (error) {
console.error('Failed to remove userAudiobookData in store', error)
return false
}
}
async getAllUserAudiobookData() {
if (!(await this.ensureTable('userAudiobookData'))) {
return false
}
var keysvalues = await this.getAllKeysValues()
var data = []
for (let i = 0; i < keysvalues.length; i++) {
try {
var abdata = JSON.parse(keysvalues[i].value)
if (!abdata.audiobookId) {
console.error('[SqlStore] Removing invalid user audiobook data')
await this.removeItem(keysvalues[i].key)
} else {
data.push(abdata)
}
} catch (error) {
console.error('Failed to parse userAudiobookData', error)
await this.removeItem(keysvalues[i].key)
}
}
return data
}
async setAllUserAudiobookData(userAbData) {
if (!(await this.ensureTable('userAudiobookData'))) {
return false
}
console.log('[SqlStore] Setting all user audiobook data ' + userAbData.length)
var success = await this.clear()
if (!success) {
console.error('[SqlStore] Did not clear old user ab data, overwriting')
}
for (let i = 0; i < userAbData.length; i++) {
try {
var abdata = userAbData[i]
await this.setItem(abdata.audiobookId, JSON.stringify(abdata))
} catch (error) {
console.error('[SqlStore] Failed to set userAudiobookData', error)
}
}
this.vuexStore.commit('user/setAllUserAudiobookData', userAbData)
}
}
export default ({ app, store }, inject) => {
inject('sqlStore', new StoreService(store))
}

View file

@ -1,689 +0,0 @@
import { Capacitor } from '@capacitor/core';
import { CapacitorDataStorageSqlite } from 'capacitor-data-storage-sqlite';
import { Storage } from '@capacitor/storage'
class StoreService {
store
isService = false
platform
isOpen = false
constructor() {
this.init()
}
/**
* Plugin Initialization
*/
init() {
this.platform = Capacitor.getPlatform()
this.store = CapacitorDataStorageSqlite
this.isService = true
console.log('in init ', this.platform, this.isService)
}
/**
* Open a Store
* @param _dbName string optional
* @param _table string optional
* @param _encrypted boolean optional
* @param _mode string optional
*/
async openStore(_dbName, _table, _encrypted, _mode) {
if (this.isService && this.store != null) {
const database = _dbName ? _dbName : "storage"
const table = _table ? _table : "storage_table"
const encrypted = _encrypted ? _encrypted : false
const mode = _mode ? _mode : "no-encryption"
this.isOpen = false
try {
await this.store.openStore({ database, table, encrypted, mode })
// return Promise.resolve()
this.isOpen = true
return true
} catch (err) {
// return Promise.reject(err)
return false
}
} else {
// return Promise.reject(new Error("openStore: Store not opened"))
return false
}
}
/**
* Close a store
* @param dbName
* @returns
*/
async closeStore(dbName) {
if (this.isService && this.store != null) {
try {
await this.store.closeStore({ database: dbName })
return Promise.resolve()
} catch (err) {
return Promise.reject(err)
}
} else {
return Promise.reject(new Error("close: Store not opened"))
}
}
/**
* Check if a store is opened
* @param dbName
* @returns
*/
async isStoreOpen(dbName) {
if (this.isService && this.store != null) {
try {
const ret = await this.store.isStoreOpen({ database: dbName })
return Promise.resolve(ret)
} catch (err) {
return Promise.reject(err)
}
} else {
return Promise.reject(new Error("isStoreOpen: Store not opened"))
}
}
/**
* Check if a store already exists
* @param dbName
* @returns
*/
async isStoreExists(dbName) {
if (this.isService && this.store != null) {
try {
const ret = await this.store.isStoreExists({ database: dbName })
return Promise.resolve(ret)
} catch (err) {
return Promise.reject(err)
}
} else {
return Promise.reject(new Error("isStoreExists: Store not opened"))
}
}
/**
* Create/Set a Table
* @param table string
*/
async setTable(table) {
if (this.isService && this.store != null) {
try {
await this.store.setTable({ table })
return Promise.resolve()
} catch (err) {
return Promise.reject(err)
}
} else {
return Promise.reject(new Error("setTable: Store not opened"))
}
}
/**
* Set of Key
* @param key string
* @param value string
*/
async setItem(key, value) {
if (this.isService && this.store != null) {
if (key.length > 0) {
try {
await this.store.set({ key, value });
return Promise.resolve();
} catch (err) {
return Promise.reject(err);
}
} else {
return Promise.reject(new Error("setItem: Must give a key"));
}
} else {
return Promise.reject(new Error("setItem: Store not opened"));
}
}
/**
* Get the Value for a given Key
* @param key string
*/
async getItem(key) {
if (this.isService && this.store != null) {
if (key.length > 0) {
try {
const { value } = await this.store.get({ key });
console.log("in getItem value ", value)
return Promise.resolve(value);
} catch (err) {
console.error(`in getItem key: ${key} err: ${JSON.stringify(err)}`)
return Promise.reject(err);
}
} else {
return Promise.reject(new Error("getItem: Must give a key"));
}
} else {
return Promise.reject(new Error("getItem: Store not opened"));
}
}
async isKey(key) {
if (this.isService && this.store != null) {
if (key.length > 0) {
try {
const { result } = await this.store.iskey({ key });
return Promise.resolve(result);
} catch (err) {
return Promise.reject(err);
}
} else {
return Promise.reject(new Error("isKey: Must give a key"));
}
} else {
return Promise.reject(new Error("isKey: Store not opened"));
}
}
async getAllKeys() {
if (this.isService && this.store != null) {
try {
const { keys } = await this.store.keys();
return Promise.resolve(keys);
} catch (err) {
return Promise.reject(err);
}
} else {
return Promise.reject(new Error("getAllKeys: Store not opened"));
}
}
async getAllValues() {
if (this.isService && this.store != null) {
try {
const { values } = await this.store.values();
return Promise.resolve(values);
} catch (err) {
return Promise.reject(err);
}
} else {
return Promise.reject(new Error("getAllValues: Store not opened"));
}
}
async getFilterValues(filter) {
if (this.isService && this.store != null) {
try {
const { values } = await this.store.filtervalues({ filter });
return Promise.resolve(values);
} catch (err) {
return Promise.reject(err);
}
} else {
return Promise.reject(new Error("getFilterValues: Store not opened"));
}
}
async getAllKeysValues() {
if (this.isService && this.store != null) {
try {
const { keysvalues } = await this.store.keysvalues();
return Promise.resolve(keysvalues);
} catch (err) {
return Promise.reject(err);
}
} else {
return Promise.reject(new Error("getAllKeysValues: Store not opened"));
}
}
async removeItem(key) {
if (this.isService && this.store != null) {
if (key.length > 0) {
try {
await this.store.remove({ key });
return Promise.resolve();
} catch (err) {
return Promise.reject(err);
}
} else {
return Promise.reject(new Error("removeItem: Must give a key"));
}
} else {
return Promise.reject(new Error("removeItem: Store not opened"));
}
}
async clear() {
if (this.isService && this.store != null) {
try {
await this.store.clear();
return Promise.resolve();
} catch (err) {
return Promise.reject(err.message);
}
} else {
return Promise.reject(new Error("clear: Store not opened"));
}
}
async deleteStore(_dbName) {
const database = _dbName ? _dbName : "storage"
if (this.isService && this.store != null) {
try {
await this.store.deleteStore({ database })
return Promise.resolve();
} catch (err) {
return Promise.reject(err.message)
}
} else {
return Promise.reject(new Error("deleteStore: Store not opened"));
}
}
async isTable(table) {
if (this.isService && this.store != null) {
if (table.length > 0) {
try {
const { result } = await this.store.isTable({ table });
return Promise.resolve(result);
} catch (err) {
return Promise.reject(err);
}
} else {
return Promise.reject(new Error("isTable: Must give a table"));
}
} else {
return Promise.reject(new Error("isTable: Store not opened"));
}
}
async getAllTables() {
if (this.isService && this.store != null) {
try {
const { tables } = await this.store.tables();
return Promise.resolve(tables);
} catch (err) {
return Promise.reject(err);
}
} else {
return Promise.reject(new Error("getAllTables: Store not opened"));
}
}
async deleteTable(table) {
if (this.isService && this.store != null) {
if (table.length > 0) {
try {
await this.store.deleteTable({ table });
return Promise.resolve();
} catch (err) {
return Promise.reject(err);
}
} else {
return Promise.reject(new Error("deleteTable: Must give a table"));
}
} else {
return Promise.reject(new Error("deleteTable: Store not opened"));
}
}
async setServerConfig(config) {
if (!this.isOpen) {
var success = await this.openStore('storage', 'serverConfig')
if (!success) {
console.error('Store failed to open')
return false
}
}
try {
await this.setTable('serverConfig')
} catch (error) {
console.error('Failed to set table', error)
return
}
try {
await this.setItem('config', JSON.stringify(config))
console.log(`[STORE] Set Server Config`)
return true
} catch (error) {
console.error('Failed to set server config in store', error)
return false
}
}
async getServerConfig() {
if (!this.isOpen) {
var success = await this.openStore('storage', 'serverConfig')
if (!success) {
console.error('Store failed to open')
return false
}
}
try {
await this.setTable('serverConfig')
} catch (error) {
console.error('Failed to set table', error)
return
}
try {
var configVal = await this.getItem('config')
if (!configVal) {
console.log(`[STORE] server config not available`)
return null
}
var config = JSON.parse(configVal)
console.log(`[STORE] Got Server Config`, JSON.stringify(config))
return config
} catch (error) {
console.error('Failed to set server config in store', error)
return null
}
}
async setDownload(download) {
if (!this.isOpen) {
var success = await this.openStore('storage', 'downloads')
if (!success) {
console.error('Store failed to open')
return false
}
}
try {
await this.setTable('downloads')
} catch (error) {
console.error('Failed to set table', error)
return
}
try {
await this.setItem(download.id, JSON.stringify(download))
console.log(`[STORE] Set Download ${download.id}`)
return true
} catch (error) {
console.error('Failed to set download in store', error)
return false
}
}
async removeDownload(id) {
if (!this.isOpen) {
var success = await this.openStore('storage', 'downloads')
if (!success) {
console.error('Store failed to open')
return false
}
}
try {
await this.setTable('downloads')
} catch (error) {
console.error('Failed to set table', error)
return
}
try {
await this.removeItem(id)
console.log(`[STORE] Removed download ${id}`)
return true
} catch (error) {
console.error('Failed to remove download in store', error)
return false
}
}
async getAllDownloads() {
if (!this.isOpen) {
var success = await this.openStore('storage', 'downloads')
if (!success) {
console.error('Store failed to open')
return []
}
}
try {
await this.setTable('downloads')
} catch (error) {
console.error('Failed to set table', error)
return
}
var keysvalues = await this.getAllKeysValues()
var downloads = []
for (let i = 0; i < keysvalues.length; i++) {
try {
var download = JSON.parse(keysvalues[i].value)
downloads.push(download)
} catch (error) {
console.error('Failed to parse download', error)
await this.removeItem(keysvalues[i].key)
}
}
return downloads
}
}
class LocalStorage {
constructor(vuexStore) {
this.vuexStore = vuexStore
this.userAudiobooksLoaded = false
this.downloadFolder = null
this.userAudiobooks = {}
}
async getMostRecentUserAudiobook(audiobookId) {
if (!this.userAudiobooksLoaded) {
await this.loadUserAudiobooks()
}
var local = this.getUserAudiobook(audiobookId)
var server = this.vuexStore.getters['user/getUserAudiobook'](audiobookId)
if (local && server) {
if (local.lastUpdate > server.lastUpdate) {
console.log('[LocalStorage] Most recent user audiobook is from LOCAL')
return local
}
console.log('[LocalStorage] Most recent user audiobook is from SERVER')
return server
} else if (local) {
console.log('[LocalStorage] Most recent user audiobook is from LOCAL')
return local
} else if (server) {
console.log('[LocalStorage] Most recent user audiobook is from SERVER')
return server
}
return null
}
async loadUserAudiobooks() {
try {
var val = (await Storage.get({ key: 'userAudiobooks' }) || {}).value || null
this.userAudiobooks = val ? JSON.parse(val) : {}
this.userAudiobooksLoaded = true
this.vuexStore.commit('user/setLocalUserAudiobooks', { ...this.userAudiobooks })
} catch (error) {
console.error('[LocalStorage] Failed to load user audiobooks', error)
}
}
async saveUserAudiobooks() {
try {
await Storage.set({ key: 'userAudiobooks', value: JSON.stringify(this.userAudiobooks) })
} catch (error) {
console.error('[LocalStorage] Failed to set user audiobooks', error)
}
}
async setAllAudiobookProgress(progresses) {
this.userAudiobooks = progresses
await this.saveUserAudiobooks()
this.vuexStore.commit('user/setLocalUserAudiobooks', { ...this.userAudiobooks })
}
async updateUserAudiobookData(progressPayload) {
this.userAudiobooks[progressPayload.audiobookId] = {
...progressPayload
}
await this.saveUserAudiobooks()
this.vuexStore.commit('user/setUserAudiobooks', { ...this.userAudiobooks })
this.vuexStore.commit('user/setLocalUserAudiobooks', { ...this.userAudiobooks })
}
async removeAudiobookProgress(audiobookId) {
if (!this.userAudiobooks[audiobookId]) return
delete this.userAudiobooks[audiobookId]
await this.saveUserAudiobooks()
this.vuexStore.commit('user/setUserAudiobooks', { ...this.userAudiobooks })
this.vuexStore.commit('user/setLocalUserAudiobooks', { ...this.userAudiobooks })
}
getUserAudiobook(audiobookId) {
return this.userAudiobooks[audiobookId] || null
}
async setToken(token) {
try {
if (token) {
await Storage.set({ key: 'token', value: token })
} else {
await Storage.remove({ key: 'token' })
}
} catch (error) {
console.error('[LocalStorage] Failed to set token', error)
}
}
async getToken() {
try {
return (await Storage.get({ key: 'token' }) || {}).value || null
} catch (error) {
console.error('[LocalStorage] Failed to get token', error)
return null
}
}
async setCurrentLibrary(library) {
try {
if (library) {
await Storage.set({ key: 'library', value: JSON.stringify(library) })
} else {
await Storage.remove({ key: 'library' })
}
} catch (error) {
console.error('[LocalStorage] Failed to set library', error)
}
}
async getCurrentLibrary() {
try {
var _value = (await Storage.get({ key: 'library' }) || {}).value || null
if (!_value) return null
return JSON.parse(_value)
} catch (error) {
console.error('[LocalStorage] Failed to get current library', error)
return null
}
}
async setDownloadFolder(folderObj) {
try {
if (folderObj) {
await Storage.set({ key: 'downloadFolder', value: JSON.stringify(folderObj) })
this.downloadFolder = folderObj
this.vuexStore.commit('setDownloadFolder', { ...this.downloadFolder })
} else {
await Storage.remove({ key: 'downloadFolder' })
this.downloadFolder = null
this.vuexStore.commit('setDownloadFolder', null)
}
} catch (error) {
console.error('[LocalStorage] Failed to set download folder', error)
}
}
async getDownloadFolder() {
try {
var _value = (await Storage.get({ key: 'downloadFolder' }) || {}).value || null
if (!_value) return null
this.downloadFolder = JSON.parse(_value)
this.vuexStore.commit('setDownloadFolder', { ...this.downloadFolder })
return this.downloadFolder
} catch (error) {
console.error('[LocalStorage] Failed to get download folder', error)
return null
}
}
async getServerUrl() {
try {
return (await Storage.get({ key: 'serverUrl' }) || {}).value || null
} catch (error) {
console.error('[LocalStorage] Failed to get serverUrl', error)
return null
}
}
async setUserSettings(settings) {
try {
await Storage.set({ key: 'userSettings', value: JSON.stringify(settings) })
} catch (error) {
console.error('[LocalStorage] Failed to update user settings', error)
}
}
async getUserSettings() {
try {
var settingsObj = await Storage.get({ key: 'userSettings' }) || {}
return settingsObj.value ? JSON.parse(settingsObj.value) : null
} catch (error) {
console.error('[LocalStorage] Failed to get user settings', error)
return null
}
}
async setCurrent(current) {
try {
if (current) {
await Storage.set({ key: 'current', value: JSON.stringify(current) })
} else {
await Storage.remove({ key: 'current' })
}
} catch (error) {
console.error('[LocalStorage] Failed to set current', error)
}
}
async getCurrent() {
try {
var currentObj = await Storage.get({ key: 'current' }) || {}
return currentObj.value ? JSON.parse(currentObj.value) : null
} catch (error) {
console.error('[LocalStorage] Failed to get current', error)
return null
}
}
async setBookshelfView(view) {
try {
await Storage.set({ key: 'bookshelfView', value: view })
} catch (error) {
console.error('[LocalStorage] Failed to set bookshelf view', error)
}
}
async getBookshelfView() {
try {
var view = await Storage.get({ key: 'bookshelfView' }) || {}
return view.value || null
} catch (error) {
console.error('[LocalStorage] Failed to get bookshelf view', error)
return null
}
}
}
export default ({ app, store }, inject) => {
inject('sqlStore', new StoreService())
inject('localStore', new LocalStorage(store))
}