mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Add: db error recovery check, Fix: bookmarks modal UI overflow #115
This commit is contained in:
		
							parent
							
								
									f7a780032f
								
							
						
					
					
						commit
						f212ea91f9
					
				| @ -3,7 +3,7 @@ | ||||
|     <nuxt-link :to="`/audiobook/${streamAudiobook.id}`" class="absolute -top-16 left-4 cursor-pointer"> | ||||
|       <cards-book-cover :audiobook="streamAudiobook" :width="88" /> | ||||
|     </nuxt-link> | ||||
|     <div class="flex items-center pl-24"> | ||||
|     <div class="flex items-start pl-24"> | ||||
|       <div> | ||||
|         <nuxt-link :to="`/audiobook/${streamAudiobook.id}`" class="hover:underline cursor-pointer text-lg"> | ||||
|           {{ title }} <span v-if="stream && $isDev" class="text-xs text-gray-400">({{ stream.id }})</span> | ||||
| @ -22,7 +22,7 @@ | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="flex-grow" /> | ||||
|       <span v-if="stream" class="material-icons px-4 cursor-pointer" @click="cancelStream">close</span> | ||||
|       <span v-if="stream" class="material-icons p-4 cursor-pointer" @click="cancelStream">close</span> | ||||
|     </div> | ||||
| 
 | ||||
|     <audio-player ref="audioPlayer" :chapters="chapters" :loading="isLoading" :bookmarks="bookmarks" @close="cancelStream" @updateTime="updateTime" @loaded="(d) => (totalDuration = d)" @showBookmarks="showBookmarks" @hook:mounted="audioPlayerMounted" /> | ||||
|  | ||||
| @ -11,8 +11,8 @@ | ||||
|         <div class="w-full h-px bg-white bg-opacity-10" /> | ||||
|         <form @submit.prevent="submitCreateBookmark"> | ||||
|           <div v-show="canCreateBookmark" class="flex px-4 py-2 items-center text-center border-b border-white border-opacity-10 text-white text-opacity-80"> | ||||
|             <div class="w-16 text-center"> | ||||
|               <p class="text-sm font-mono"> | ||||
|             <div class="w-16 max-w-16 text-center"> | ||||
|               <p class="text-sm font-mono text-gray-400"> | ||||
|                 {{ this.$secondsToTimestamp(currentTime) }} | ||||
|               </p> | ||||
|             </div> | ||||
|  | ||||
| @ -1,12 +1,12 @@ | ||||
| <template> | ||||
|   <div :key="bookmark.id" :id="`bookmark-row-${bookmark.id}`" class="flex items-center px-4 py-4 justify-start relative hover:bg-bg" :class="wrapperClass" @click="click" @mouseover="mouseover" @mouseleave="mouseleave"> | ||||
|     <!-- <span class="material-icons" :class="highlight ? 'text-success' : 'text-white text-opacity-80'">{{ highlight ? 'bookmark' : 'bookmark_border' }}</span> --> | ||||
|     <div class="w-12 min-w-12 text-center"> | ||||
|       <p class="text-sm font-mono text-white text-opacity-80"> | ||||
|     <div class="w-16 max-w-16 text-center"> | ||||
|       <p class="text-sm font-mono text-gray-400"> | ||||
|         {{ this.$secondsToTimestamp(bookmark.time) }} | ||||
|       </p> | ||||
|     </div> | ||||
|     <div class="flex-grow overflow-hidden"> | ||||
|     <div class="flex-grow overflow-hidden px-2"> | ||||
|       <template v-if="isEditing"> | ||||
|         <form @submit.prevent="submitUpdate"> | ||||
|           <div class="flex items-center"> | ||||
|  | ||||
| @ -20,6 +20,7 @@ module.exports = { | ||||
|       maxWidth: { | ||||
|         '6': '1.5rem', | ||||
|         '12': '3rem', | ||||
|         '16': '4rem', | ||||
|         '24': '6rem', | ||||
|         '32': '8rem', | ||||
|         '48': '12rem', | ||||
|  | ||||
							
								
								
									
										63
									
								
								server/Db.js
									
									
									
									
									
								
							
							
						
						
									
										63
									
								
								server/Db.js
									
									
									
									
									
								
							| @ -1,5 +1,6 @@ | ||||
| const Path = require('path') | ||||
| const njodb = require("njodb") | ||||
| const fs = require('fs-extra') | ||||
| const jwt = require('jsonwebtoken') | ||||
| const Logger = require('./Logger') | ||||
| const Audiobook = require('./objects/Audiobook') | ||||
| @ -187,6 +188,11 @@ class Db { | ||||
|       return true | ||||
|     }).catch((error) => { | ||||
|       Logger.error(`[DB] Update entity ${entityName} Failed: ${error}`) | ||||
| 
 | ||||
|       if (error && error.code === 'ENOENT') { | ||||
|         this.attemptDataRecovery(entityName) | ||||
|       } | ||||
| 
 | ||||
|       return false | ||||
|     }) | ||||
|   } | ||||
| @ -204,6 +210,63 @@ class Db { | ||||
|     }) | ||||
|   } | ||||
| 
 | ||||
|   async attemptDataRecovery(entityName) { | ||||
|     var dbDirName = this.getEntityArrayKey(entityName) | ||||
|     var dbdir = Path.join(this.ConfigPath, dbDirName) | ||||
|     console.log('Attempting data recovery for:', dbdir) | ||||
| 
 | ||||
|     var exists = await fs.pathExists(dbdir) | ||||
|     if (!exists) { | ||||
|       console.error('Db dir does not exist', dbdir) | ||||
|       return | ||||
|     } | ||||
| 
 | ||||
|     try { | ||||
|       var dbdatadir = Path.join(dbdir, 'data') | ||||
|       var dbtmpdir = Path.join(dbdir, 'tmp') | ||||
| 
 | ||||
|       var datafiles = await fs.readdir(dbdatadir) | ||||
|       var tempfiles = await fs.readdir(dbtmpdir) | ||||
| 
 | ||||
|       var orphanOld = datafiles.find(df => df.endsWith('.old')) | ||||
|       if (orphanOld) { | ||||
|         // Get data file num
 | ||||
|         var dbnum = orphanOld.split('.')[1] | ||||
|         console.log('Found orphan json.old', orphanOld, `Num: ${dbnum}`) | ||||
| 
 | ||||
|         var dbDataFilename = `data.${dbnum}.json` | ||||
| 
 | ||||
|         // make sure data.#.json does not already exist
 | ||||
|         if (datafiles.includes(dbDataFilename)) { | ||||
|           console.warn(`${dbDataFilename} already exists, not recovering`) | ||||
|           return | ||||
|         } | ||||
| 
 | ||||
|         // find temp file that was supposed to be renamed
 | ||||
|         var matchingTmp = tempfiles.find(tmp => tmp.startsWith(`data.${dbnum}`)) | ||||
|         if (matchingTmp) { | ||||
|           console.log('found matching tmp file', matchingTmp) | ||||
| 
 | ||||
|           var tmpfileFullPath = Path.join(dbtmpdir, matchingTmp) | ||||
|           var renameToPath = Path.join(dbdatadir, dbDataFilename) | ||||
| 
 | ||||
|           console.log(`Renamining "${tmpfileFullPath}" => "${renameToPath}"`) | ||||
|           await fs.rename(tmpfileFullPath, renameToPath) | ||||
| 
 | ||||
|           console.log('Data recovery successful -- unlinking old') | ||||
| 
 | ||||
|           await fs.unlink(orphanOld) | ||||
|           console.log('Removed .old file') | ||||
|           var lockdirpath = Path.join(dbdatadir, `data.${dbnum}.lock`) | ||||
|           await fs.rmdir(lockdirpath) | ||||
|           console.log('Removed lock dir') | ||||
|         } | ||||
|       } | ||||
|     } catch (error) { | ||||
|       console.error('Data recovery failed', error) | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   recreateAudiobookDb() { | ||||
|     return this.audiobooksDb.drop().then((results) => { | ||||
|       Logger.info(`[DB] Dropped audiobook db`, results) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user