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"> |     <nuxt-link :to="`/audiobook/${streamAudiobook.id}`" class="absolute -top-16 left-4 cursor-pointer"> | ||||||
|       <cards-book-cover :audiobook="streamAudiobook" :width="88" /> |       <cards-book-cover :audiobook="streamAudiobook" :width="88" /> | ||||||
|     </nuxt-link> |     </nuxt-link> | ||||||
|     <div class="flex items-center pl-24"> |     <div class="flex items-start pl-24"> | ||||||
|       <div> |       <div> | ||||||
|         <nuxt-link :to="`/audiobook/${streamAudiobook.id}`" class="hover:underline cursor-pointer text-lg"> |         <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> |           {{ title }} <span v-if="stream && $isDev" class="text-xs text-gray-400">({{ stream.id }})</span> | ||||||
| @ -22,7 +22,7 @@ | |||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|       <div class="flex-grow" /> |       <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> |     </div> | ||||||
| 
 | 
 | ||||||
|     <audio-player ref="audioPlayer" :chapters="chapters" :loading="isLoading" :bookmarks="bookmarks" @close="cancelStream" @updateTime="updateTime" @loaded="(d) => (totalDuration = d)" @showBookmarks="showBookmarks" @hook:mounted="audioPlayerMounted" /> |     <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" /> |         <div class="w-full h-px bg-white bg-opacity-10" /> | ||||||
|         <form @submit.prevent="submitCreateBookmark"> |         <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 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"> |             <div class="w-16 max-w-16 text-center"> | ||||||
|               <p class="text-sm font-mono"> |               <p class="text-sm font-mono text-gray-400"> | ||||||
|                 {{ this.$secondsToTimestamp(currentTime) }} |                 {{ this.$secondsToTimestamp(currentTime) }} | ||||||
|               </p> |               </p> | ||||||
|             </div> |             </div> | ||||||
|  | |||||||
| @ -1,12 +1,12 @@ | |||||||
| <template> | <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"> |   <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> --> |     <!-- <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"> |     <div class="w-16 max-w-16 text-center"> | ||||||
|       <p class="text-sm font-mono text-white text-opacity-80"> |       <p class="text-sm font-mono text-gray-400"> | ||||||
|         {{ this.$secondsToTimestamp(bookmark.time) }} |         {{ this.$secondsToTimestamp(bookmark.time) }} | ||||||
|       </p> |       </p> | ||||||
|     </div> |     </div> | ||||||
|     <div class="flex-grow overflow-hidden"> |     <div class="flex-grow overflow-hidden px-2"> | ||||||
|       <template v-if="isEditing"> |       <template v-if="isEditing"> | ||||||
|         <form @submit.prevent="submitUpdate"> |         <form @submit.prevent="submitUpdate"> | ||||||
|           <div class="flex items-center"> |           <div class="flex items-center"> | ||||||
|  | |||||||
| @ -20,6 +20,7 @@ module.exports = { | |||||||
|       maxWidth: { |       maxWidth: { | ||||||
|         '6': '1.5rem', |         '6': '1.5rem', | ||||||
|         '12': '3rem', |         '12': '3rem', | ||||||
|  |         '16': '4rem', | ||||||
|         '24': '6rem', |         '24': '6rem', | ||||||
|         '32': '8rem', |         '32': '8rem', | ||||||
|         '48': '12rem', |         '48': '12rem', | ||||||
|  | |||||||
							
								
								
									
										63
									
								
								server/Db.js
									
									
									
									
									
								
							
							
						
						
									
										63
									
								
								server/Db.js
									
									
									
									
									
								
							| @ -1,5 +1,6 @@ | |||||||
| const Path = require('path') | const Path = require('path') | ||||||
| const njodb = require("njodb") | const njodb = require("njodb") | ||||||
|  | const fs = require('fs-extra') | ||||||
| const jwt = require('jsonwebtoken') | const jwt = require('jsonwebtoken') | ||||||
| const Logger = require('./Logger') | const Logger = require('./Logger') | ||||||
| const Audiobook = require('./objects/Audiobook') | const Audiobook = require('./objects/Audiobook') | ||||||
| @ -187,6 +188,11 @@ class Db { | |||||||
|       return true |       return true | ||||||
|     }).catch((error) => { |     }).catch((error) => { | ||||||
|       Logger.error(`[DB] Update entity ${entityName} Failed: ${error}`) |       Logger.error(`[DB] Update entity ${entityName} Failed: ${error}`) | ||||||
|  | 
 | ||||||
|  |       if (error && error.code === 'ENOENT') { | ||||||
|  |         this.attemptDataRecovery(entityName) | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|       return false |       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() { |   recreateAudiobookDb() { | ||||||
|     return this.audiobooksDb.drop().then((results) => { |     return this.audiobooksDb.drop().then((results) => { | ||||||
|       Logger.info(`[DB] Dropped audiobook db`, results) |       Logger.info(`[DB] Dropped audiobook db`, results) | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user