@@ -107,10 +105,7 @@ export default {
showLocalCovers: false,
previewUpload: null,
selectedFile: null,
- provider: 'google',
- currentSearchRequestId: null,
- searchInProgress: false,
- socketListenersActive: false
+ provider: 'google'
}
},
watch: {
@@ -134,7 +129,7 @@ export default {
},
providers() {
if (this.isPodcast) return this.$store.state.scanners.podcastProviders
- return [{ text: 'Best', value: 'best' }, ...this.$store.state.scanners.providers, ...this.$store.state.scanners.coverOnlyProviders, { text: 'All', value: 'all' }]
+ return [{ text: 'All', value: 'all' }, ...this.$store.state.scanners.providers, ...this.$store.state.scanners.coverOnlyProviders]
},
searchTitleLabel() {
if (this.provider.startsWith('audible')) return this.$strings.LabelSearchTitleOrASIN
@@ -191,9 +186,6 @@ export default {
_file.localPath = `${process.env.serverUrl}/api/items/${this.libraryItemId}/file/${file.ino}?token=${this.userToken}`
return _file
})
- },
- socket() {
- return this.$root.socket
}
},
methods: {
@@ -243,19 +235,7 @@ export default {
this.searchTitle = this.mediaMetadata.title || ''
this.searchAuthor = this.mediaMetadata.authorName || ''
if (this.isPodcast) this.provider = 'itunes'
- else {
- // Migrate from 'all' to 'best' (only once)
- const migrationKey = 'book-cover-provider-migrated'
- const currentProvider = localStorage.getItem('book-cover-provider') || localStorage.getItem('book-provider') || 'google'
-
- if (!localStorage.getItem(migrationKey) && currentProvider === 'all') {
- localStorage.setItem('book-cover-provider', 'best')
- localStorage.setItem(migrationKey, 'true')
- this.provider = 'best'
- } else {
- this.provider = currentProvider
- }
- }
+ else this.provider = localStorage.getItem('book-cover-provider') || localStorage.getItem('book-provider') || 'google'
},
removeCover() {
if (!this.coverPath) {
@@ -311,116 +291,22 @@ export default {
console.error('PersistProvider', error)
}
},
- generateRequestId() {
- return `cover-search-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
- },
- addSocketListeners() {
- if (!this.socket || this.socketListenersActive) return
-
- this.socket.on('cover_search_result', this.handleSearchResult)
- this.socket.on('cover_search_complete', this.handleSearchComplete)
- this.socket.on('cover_search_error', this.handleSearchError)
- this.socket.on('cover_search_provider_error', this.handleProviderError)
- this.socket.on('cover_search_cancelled', this.handleSearchCancelled)
- this.socket.on('disconnect', this.handleSocketDisconnect)
- this.socketListenersActive = true
- },
- removeSocketListeners() {
- if (!this.socket || !this.socketListenersActive) return
-
- this.socket.off('cover_search_result', this.handleSearchResult)
- this.socket.off('cover_search_complete', this.handleSearchComplete)
- this.socket.off('cover_search_error', this.handleSearchError)
- this.socket.off('cover_search_provider_error', this.handleProviderError)
- this.socket.off('cover_search_cancelled', this.handleSearchCancelled)
- this.socket.off('disconnect', this.handleSocketDisconnect)
- this.socketListenersActive = false
- },
- handleSearchResult(data) {
- if (data.requestId !== this.currentSearchRequestId) return
-
- // Add new covers to the list (avoiding duplicates)
- const newCovers = data.covers.filter((cover) => !this.coversFound.includes(cover))
- this.coversFound.push(...newCovers)
- },
- handleSearchComplete(data) {
- if (data.requestId !== this.currentSearchRequestId) return
-
- this.searchInProgress = false
- this.currentSearchRequestId = null
- },
- handleSearchError(data) {
- if (data.requestId !== this.currentSearchRequestId) return
-
- console.error('[Cover Search] Search error:', data.error)
- this.$toast.error(this.$strings.ToastCoverSearchFailed)
- this.searchInProgress = false
- this.currentSearchRequestId = null
- },
- handleProviderError(data) {
- if (data.requestId !== this.currentSearchRequestId) return
-
- console.warn(`[Cover Search] Provider ${data.provider} failed:`, data.error)
- },
- handleSearchCancelled(data) {
- if (data.requestId !== this.currentSearchRequestId) return
-
- this.searchInProgress = false
- this.currentSearchRequestId = null
- },
- handleSocketDisconnect() {
- // If we were in the middle of a search, cancel it (server can't send results anymore)
- if (this.searchInProgress && this.currentSearchRequestId) {
- this.searchInProgress = false
- this.currentSearchRequestId = null
- }
- },
- cancelCurrentSearch() {
- if (!this.currentSearchRequestId || !this.socket?.connected) {
- console.error('[Cover Search] Socket not connected')
- this.$toast.error(this.$strings.ToastConnectionNotAvailable)
- return
- }
-
- this.socket.emit('cancel_cover_search', this.currentSearchRequestId)
- this.currentSearchRequestId = null
- this.searchInProgress = false
- },
async submitSearchForm() {
- if (!this.socket?.connected) {
- console.error('[Cover Search] Socket not connected')
- this.$toast.error(this.$strings.ToastConnectionNotAvailable)
- return
- }
-
- // Cancel any existing search
- if (this.searchInProgress) {
- this.cancelCurrentSearch()
- }
-
// Store provider in local storage
this.persistProvider()
- // Setup socket listeners if not already done
- this.addSocketListeners()
-
- // Clear previous results
- this.coversFound = []
+ this.isProcessing = true
+ const searchQuery = this.getSearchQuery()
+ const results = await this.$axios
+ .$get(`/api/search/covers?${searchQuery}`)
+ .then((res) => res.results)
+ .catch((error) => {
+ console.error('Failed', error)
+ return []
+ })
+ this.coversFound = results
+ this.isProcessing = false
this.hasSearched = true
- this.searchInProgress = true
-
- // Generate unique request ID
- const requestId = this.generateRequestId()
- this.currentSearchRequestId = requestId
-
- // Emit search request via WebSocket
- this.socket.emit('search_covers', {
- requestId,
- title: this.searchTitle,
- author: this.searchAuthor || '',
- provider: this.provider,
- podcast: this.isPodcast
- })
},
setCover(coverFile) {
this.isProcessing = true
@@ -434,18 +320,6 @@ export default {
this.isProcessing = false
})
}
- },
- mounted() {
- // Setup socket listeners when component is mounted
- this.addSocketListeners()
- },
- beforeDestroy() {
- // Cancel any ongoing search when component is destroyed
- if (this.searchInProgress) {
- this.cancelCurrentSearch()
- }
- // Remove socket listeners
- this.removeSocketListeners()
}
}
diff --git a/client/strings/en-us.json b/client/strings/en-us.json
index 83acb5a69..42832e37a 100644
--- a/client/strings/en-us.json
+++ b/client/strings/en-us.json
@@ -1026,8 +1026,6 @@
"ToastCollectionItemsAddFailed": "Item(s) added to collection failed",
"ToastCollectionRemoveSuccess": "Collection removed",
"ToastCollectionUpdateSuccess": "Collection updated",
- "ToastConnectionNotAvailable": "Connection not available. Please try again later",
- "ToastCoverSearchFailed": "Cover search failed",
"ToastCoverUpdateFailed": "Cover update failed",
"ToastDateTimeInvalidOrIncomplete": "Date and time is invalid or incomplete",
"ToastDeleteFileFailed": "Failed to delete file",
diff --git a/server/SocketAuthority.js b/server/SocketAuthority.js
index ad55f6605..da31ba4a0 100644
--- a/server/SocketAuthority.js
+++ b/server/SocketAuthority.js
@@ -2,7 +2,6 @@ const SocketIO = require('socket.io')
const Logger = require('./Logger')
const Database = require('./Database')
const TokenManager = require('./auth/TokenManager')
-const CoverSearchManager = require('./managers/CoverSearchManager')
/**
* @typedef SocketClient
@@ -181,10 +180,6 @@ class SocketAuthority {
// Scanning
socket.on('cancel_scan', (libraryId) => this.cancelScan(libraryId))
- // Cover search streaming
- socket.on('search_covers', (payload) => this.handleCoverSearch(socket, payload))
- socket.on('cancel_cover_search', (requestId) => this.handleCancelCoverSearch(socket, requestId))
-
// Logs
socket.on('set_log_listener', (level) => Logger.addSocketListener(socket, level))
socket.on('remove_log_listener', () => Logger.removeSocketListener(socket.id))
@@ -205,10 +200,6 @@ class SocketAuthority {
const disconnectTime = Date.now() - _client.connected_at
Logger.info(`[SocketAuthority] Socket ${socket.id} disconnected from client "${_client.user.username}" after ${disconnectTime}ms (Reason: ${reason})`)
-
- // Cancel any active cover searches for this socket
- this.cancelSocketCoverSearches(socket.id)
-
delete this.clients[socket.id]
}
})
@@ -309,100 +300,5 @@ class SocketAuthority {
Logger.debug('[SocketAuthority] Cancel scan', id)
this.Server.cancelLibraryScan(id)
}
-
- /**
- * Handle cover search request via WebSocket
- * @param {SocketIO.Socket} socket
- * @param {Object} payload
- */
- async handleCoverSearch(socket, payload) {
- const client = this.clients[socket.id]
- if (!client?.user) {
- Logger.error('[SocketAuthority] Unauthorized cover search request')
- socket.emit('cover_search_error', {
- requestId: payload.requestId,
- error: 'Unauthorized'
- })
- return
- }
-
- const { requestId, title, author, provider, podcast } = payload
-
- if (!requestId || !title) {
- Logger.error('[SocketAuthority] Invalid cover search request')
- socket.emit('cover_search_error', {
- requestId,
- error: 'Invalid request parameters'
- })
- return
- }
-
- Logger.info(`[SocketAuthority] User ${client.user.username} initiated cover search ${requestId}`)
-
- // Callback for streaming results to client
- const onResult = (result) => {
- socket.emit('cover_search_result', {
- requestId,
- provider: result.provider,
- covers: result.covers,
- total: result.total
- })
- }
-
- // Callback when search completes
- const onComplete = () => {
- Logger.info(`[SocketAuthority] Cover search ${requestId} completed`)
- socket.emit('cover_search_complete', { requestId })
- }
-
- // Callback for provider errors
- const onError = (provider, errorMessage) => {
- socket.emit('cover_search_provider_error', {
- requestId,
- provider,
- error: errorMessage
- })
- }
-
- // Start the search
- CoverSearchManager.startSearch(requestId, { title, author, provider, podcast }, onResult, onComplete, onError).catch((error) => {
- Logger.error(`[SocketAuthority] Cover search ${requestId} failed:`, error)
- socket.emit('cover_search_error', {
- requestId,
- error: error.message
- })
- })
- }
-
- /**
- * Handle cancel cover search request
- * @param {SocketIO.Socket} socket
- * @param {string} requestId
- */
- handleCancelCoverSearch(socket, requestId) {
- const client = this.clients[socket.id]
- if (!client?.user) {
- Logger.error('[SocketAuthority] Unauthorized cancel cover search request')
- return
- }
-
- Logger.info(`[SocketAuthority] User ${client.user.username} cancelled cover search ${requestId}`)
-
- const cancelled = CoverSearchManager.cancelSearch(requestId)
- if (cancelled) {
- socket.emit('cover_search_cancelled', { requestId })
- }
- }
-
- /**
- * Cancel all cover searches associated with a socket (called on disconnect)
- * @param {string} socketId
- */
- cancelSocketCoverSearches(socketId) {
- // Get all active search request IDs and cancel those that might belong to this socket
- // Since we don't track socket-to-request mapping, we log this for debugging
- // The client will handle reconnection gracefully
- Logger.debug(`[SocketAuthority] Socket ${socketId} disconnected, any active searches will timeout`)
- }
}
module.exports = new SocketAuthority()
diff --git a/server/finders/BookFinder.js b/server/finders/BookFinder.js
index a6a6b07e6..2d7b57f14 100644
--- a/server/finders/BookFinder.js
+++ b/server/finders/BookFinder.js
@@ -11,7 +11,7 @@ const { levenshteinDistance, levenshteinSimilarity, escapeRegExp, isValidASIN }
const htmlSanitizer = require('../utils/htmlSanitizer')
class BookFinder {
- #providerResponseTimeout = 10000
+ #providerResponseTimeout = 30000
constructor() {
this.openLibrary = new OpenLibrary()
@@ -608,14 +608,6 @@ class BookFinder {
Logger.debug(`[BookFinder] Found ${providerResults.length} covers from ${providerString}`)
searchResults.push(...providerResults)
}
- } else if (provider === 'best') {
- // Best providers: google, fantlab, and audible.com
- const bestProviders = ['google', 'fantlab', 'audible']
- for (const providerString of bestProviders) {
- const providerResults = await this.search(null, providerString, title, author, options)
- Logger.debug(`[BookFinder] Found ${providerResults.length} covers from ${providerString}`)
- searchResults.push(...providerResults)
- }
} else {
searchResults = await this.search(null, provider, title, author, options)
}
diff --git a/server/managers/CoverSearchManager.js b/server/managers/CoverSearchManager.js
deleted file mode 100644
index ddcaa23db..000000000
--- a/server/managers/CoverSearchManager.js
+++ /dev/null
@@ -1,251 +0,0 @@
-const { setMaxListeners } = require('events')
-const Logger = require('../Logger')
-const BookFinder = require('../finders/BookFinder')
-const PodcastFinder = require('../finders/PodcastFinder')
-
-/**
- * Manager for handling streaming cover search across multiple providers
- */
-class CoverSearchManager {
- constructor() {
- /** @type {Map} Map of requestId to AbortController */
- this.activeSearches = new Map()
-
- // Default timeout for each provider search
- this.providerTimeout = 10000 // 10 seconds
-
- // Set to 0 to disable the max listeners limit
- // We need one listener per provider (15+) and may have multiple concurrent searches
- this.maxListeners = 0
- }
-
- /**
- * Start a streaming cover search
- * @param {string} requestId - Unique identifier for this search request
- * @param {Object} searchParams - Search parameters
- * @param {string} searchParams.title - Title to search for
- * @param {string} searchParams.author - Author to search for (optional)
- * @param {string} searchParams.provider - Provider to search (or 'all')
- * @param {boolean} searchParams.podcast - Whether this is a podcast search
- * @param {Function} onResult - Callback for each result chunk
- * @param {Function} onComplete - Callback when search completes
- * @param {Function} onError - Callback for errors
- */
- async startSearch(requestId, searchParams, onResult, onComplete, onError) {
- if (this.activeSearches.has(requestId)) {
- Logger.warn(`[CoverSearchManager] Search with requestId ${requestId} already exists`)
- return
- }
-
- const abortController = new AbortController()
-
- // Increase max listeners on this signal to accommodate parallel provider searches
- // AbortSignal is an EventTarget, so we use the events module's setMaxListeners
- setMaxListeners(this.maxListeners, abortController.signal)
-
- this.activeSearches.set(requestId, abortController)
-
- Logger.info(`[CoverSearchManager] Starting search ${requestId} with params:`, searchParams)
-
- try {
- const { title, author, provider, podcast } = searchParams
-
- if (podcast) {
- await this.searchPodcastCovers(requestId, title, abortController.signal, onResult, onError)
- } else {
- await this.searchBookCovers(requestId, provider, title, author, abortController.signal, onResult, onError)
- }
-
- if (!abortController.signal.aborted) {
- onComplete()
- }
- } catch (error) {
- if (error.name === 'AbortError') {
- Logger.info(`[CoverSearchManager] Search ${requestId} was cancelled`)
- } else {
- Logger.error(`[CoverSearchManager] Search ${requestId} failed:`, error)
- onError(error.message)
- }
- } finally {
- this.activeSearches.delete(requestId)
- }
- }
-
- /**
- * Cancel an active search
- * @param {string} requestId - Request ID to cancel
- */
- cancelSearch(requestId) {
- const abortController = this.activeSearches.get(requestId)
- if (abortController) {
- Logger.info(`[CoverSearchManager] Cancelling search ${requestId}`)
- abortController.abort()
- this.activeSearches.delete(requestId)
- return true
- }
- return false
- }
-
- /**
- * Search for podcast covers
- */
- async searchPodcastCovers(requestId, title, signal, onResult, onError) {
- try {
- const results = await this.executeWithTimeout(() => PodcastFinder.findCovers(title), this.providerTimeout, signal)
-
- if (signal.aborted) return
-
- const covers = this.extractCoversFromResults(results)
- if (covers.length > 0) {
- onResult({
- provider: 'itunes',
- covers,
- total: covers.length
- })
- }
- } catch (error) {
- if (error.name !== 'AbortError') {
- Logger.error(`[CoverSearchManager] Podcast search failed:`, error)
- onError('itunes', error.message)
- }
- }
- }
-
- /**
- * Search for book covers across providers
- */
- async searchBookCovers(requestId, provider, title, author, signal, onResult, onError) {
- let providers = []
-
- if (provider === 'all') {
- providers = [...BookFinder.providers]
- } else if (provider === 'best') {
- // Best providers: google, fantlab, and audible.com
- providers = ['google', 'fantlab', 'audible']
- } else {
- providers = [provider]
- }
-
- Logger.debug(`[CoverSearchManager] Searching ${providers.length} providers in parallel`)
-
- // Search all providers in parallel
- const searchPromises = providers.map(async (providerName) => {
- if (signal.aborted) return
-
- try {
- const searchResults = await this.executeWithTimeout(() => BookFinder.search(null, providerName, title, author || ''), this.providerTimeout, signal)
-
- if (signal.aborted) return
-
- const covers = this.extractCoversFromResults(searchResults)
-
- Logger.debug(`[CoverSearchManager] Found ${covers.length} covers from ${providerName}`)
-
- if (covers.length > 0) {
- onResult({
- provider: providerName,
- covers,
- total: covers.length
- })
- }
- } catch (error) {
- if (error.name !== 'AbortError') {
- Logger.warn(`[CoverSearchManager] Provider ${providerName} failed:`, error.message)
- onError(providerName, error.message)
- }
- }
- })
-
- await Promise.allSettled(searchPromises)
- }
-
- /**
- * Execute a promise with timeout and abort signal
- */
- async executeWithTimeout(fn, timeout, signal) {
- return new Promise(async (resolve, reject) => {
- let abortHandler = null
- let timeoutId = null
-
- // Cleanup function to ensure we always remove listeners
- const cleanup = () => {
- if (timeoutId) {
- clearTimeout(timeoutId)
- timeoutId = null
- }
- if (abortHandler) {
- signal.removeEventListener('abort', abortHandler)
- abortHandler = null
- }
- }
-
- // Set up timeout
- timeoutId = setTimeout(() => {
- cleanup()
- const error = new Error('Provider timeout')
- error.name = 'TimeoutError'
- reject(error)
- }, timeout)
-
- // Check if already aborted
- if (signal.aborted) {
- cleanup()
- const error = new Error('Search cancelled')
- error.name = 'AbortError'
- reject(error)
- return
- }
-
- // Set up abort handler
- abortHandler = () => {
- cleanup()
- const error = new Error('Search cancelled')
- error.name = 'AbortError'
- reject(error)
- }
- signal.addEventListener('abort', abortHandler)
-
- try {
- const result = await fn()
- cleanup()
- resolve(result)
- } catch (error) {
- cleanup()
- reject(error)
- }
- })
- }
-
- /**
- * Extract cover URLs from search results
- */
- extractCoversFromResults(results) {
- const covers = []
- if (!Array.isArray(results)) return covers
-
- results.forEach((result) => {
- if (result.covers && Array.isArray(result.covers)) {
- covers.push(...result.covers)
- }
- if (result.cover) {
- covers.push(result.cover)
- }
- })
-
- // Remove duplicates
- return [...new Set(covers)]
- }
-
- /**
- * Cancel all active searches (cleanup on server shutdown)
- */
- cancelAllSearches() {
- Logger.info(`[CoverSearchManager] Cancelling ${this.activeSearches.size} active searches`)
- for (const [requestId, abortController] of this.activeSearches.entries()) {
- abortController.abort()
- }
- this.activeSearches.clear()
- }
-}
-
-module.exports = new CoverSearchManager()
diff --git a/server/providers/Audible.js b/server/providers/Audible.js
index 2c12ffc1a..18879e912 100644
--- a/server/providers/Audible.js
+++ b/server/providers/Audible.js
@@ -3,7 +3,7 @@ const Logger = require('../Logger')
const { isValidASIN } = require('../utils/index')
class Audible {
- #responseTimeout = 10000
+ #responseTimeout = 30000
constructor() {
this.regionMap = {
@@ -106,7 +106,7 @@ class Audible {
return res.data
})
.catch((error) => {
- Logger.error('[Audible] ASIN search error', error.message)
+ Logger.error('[Audible] ASIN search error', error)
return null
})
}
@@ -158,7 +158,7 @@ class Audible {
return Promise.all(res.data.products.map((result) => this.asinSearch(result.asin, region, timeout)))
})
.catch((error) => {
- Logger.error('[Audible] query search error', error.message)
+ Logger.error('[Audible] query search error', error)
return []
})
}
diff --git a/server/providers/AudiobookCovers.js b/server/providers/AudiobookCovers.js
index 9bd1f367c..8e284fea2 100644
--- a/server/providers/AudiobookCovers.js
+++ b/server/providers/AudiobookCovers.js
@@ -2,7 +2,7 @@ const axios = require('axios')
const Logger = require('../Logger')
class AudiobookCovers {
- #responseTimeout = 10000
+ #responseTimeout = 30000
constructor() {}
@@ -24,7 +24,7 @@ class AudiobookCovers {
})
.then((res) => res?.data || [])
.catch((error) => {
- Logger.error('[AudiobookCovers] Cover search error', error.message)
+ Logger.error('[AudiobookCovers] Cover search error', error)
return []
})
return items.map((item) => ({ cover: item.versions.png.original }))
diff --git a/server/providers/Audnexus.js b/server/providers/Audnexus.js
index 9a76dc861..4f11a2a36 100644
--- a/server/providers/Audnexus.js
+++ b/server/providers/Audnexus.js
@@ -55,7 +55,7 @@ class Audnexus {
return this._processRequest(this.limiter(() => axios.get(authorRequestUrl)))
.then((res) => res.data || [])
.catch((error) => {
- Logger.error(`[Audnexus] Author ASIN request failed for ${name}`, error.message)
+ Logger.error(`[Audnexus] Author ASIN request failed for ${name}`, error)
return []
})
}
@@ -82,7 +82,7 @@ class Audnexus {
return this._processRequest(this.limiter(() => axios.get(authorRequestUrl.toString())))
.then((res) => res.data)
.catch((error) => {
- Logger.error(`[Audnexus] Author request failed for ${asin}`, error.message)
+ Logger.error(`[Audnexus] Author request failed for ${asin}`, error)
return null
})
}
@@ -158,7 +158,7 @@ class Audnexus {
return this._processRequest(this.limiter(() => axios.get(chaptersRequestUrl.toString())))
.then((res) => res.data)
.catch((error) => {
- Logger.error(`[Audnexus] Chapter ASIN request failed for ${asin}/${region}`, error.message)
+ Logger.error(`[Audnexus] Chapter ASIN request failed for ${asin}/${region}`, error)
return null
})
}
diff --git a/server/providers/CustomProviderAdapter.js b/server/providers/CustomProviderAdapter.js
index c079a1280..a5fed3939 100644
--- a/server/providers/CustomProviderAdapter.js
+++ b/server/providers/CustomProviderAdapter.js
@@ -4,7 +4,7 @@ const Logger = require('../Logger')
const htmlSanitizer = require('../utils/htmlSanitizer')
class CustomProviderAdapter {
- #responseTimeout = 10000
+ #responseTimeout = 30000
constructor() {}
@@ -61,7 +61,7 @@ class CustomProviderAdapter {
return res.data.matches
})
.catch((error) => {
- Logger.error('[CustomMetadataProvider] Search error', error.message)
+ Logger.error('[CustomMetadataProvider] Search error', error)
return []
})
diff --git a/server/providers/FantLab.js b/server/providers/FantLab.js
index d25be1c80..f33934ca2 100644
--- a/server/providers/FantLab.js
+++ b/server/providers/FantLab.js
@@ -2,7 +2,7 @@ const axios = require('axios')
const Logger = require('../Logger')
class FantLab {
- #responseTimeout = 10000
+ #responseTimeout = 30000
// 7 - other
// 11 - essay
// 12 - article
@@ -48,7 +48,7 @@ class FantLab {
return res.data || []
})
.catch((error) => {
- Logger.error('[FantLab] search error', error.message)
+ Logger.error('[FantLab] search error', error)
return []
})
@@ -77,7 +77,7 @@ class FantLab {
return resp.data || null
})
.catch((error) => {
- Logger.error(`[FantLab] work info request for url "${url}" error`, error.message)
+ Logger.error(`[FantLab] work info request for url "${url}" error`, error)
return null
})
@@ -193,7 +193,7 @@ class FantLab {
return resp.data || null
})
.catch((error) => {
- Logger.error(`[FantLab] search cover from edition with url "${url}" error`, error.message)
+ Logger.error(`[FantLab] search cover from edition with url "${url}" error`, error)
return null
})
diff --git a/server/providers/GoogleBooks.js b/server/providers/GoogleBooks.js
index 3aec4c849..76a3dceaa 100644
--- a/server/providers/GoogleBooks.js
+++ b/server/providers/GoogleBooks.js
@@ -2,7 +2,7 @@ const axios = require('axios')
const Logger = require('../Logger')
class GoogleBooks {
- #responseTimeout = 10000
+ #responseTimeout = 30000
constructor() {}
@@ -67,7 +67,7 @@ class GoogleBooks {
return res.data.items
})
.catch((error) => {
- Logger.error('[GoogleBooks] Volume search error', error.message)
+ Logger.error('[GoogleBooks] Volume search error', error)
return []
})
return items.map((item) => this.cleanResult(item))
diff --git a/server/providers/OpenLibrary.js b/server/providers/OpenLibrary.js
index fb73dc294..10d033786 100644
--- a/server/providers/OpenLibrary.js
+++ b/server/providers/OpenLibrary.js
@@ -1,7 +1,7 @@
const axios = require('axios').default
class OpenLibrary {
- #responseTimeout = 10000
+ #responseTimeout = 30000
constructor() {
this.baseUrl = 'https://openlibrary.org'
@@ -23,7 +23,7 @@ class OpenLibrary {
return res.data
})
.catch((error) => {
- console.error('Failed', error.message)
+ console.error('Failed', error)
return null
})
}
diff --git a/server/providers/iTunes.js b/server/providers/iTunes.js
index 87695c58c..57a47d0d1 100644
--- a/server/providers/iTunes.js
+++ b/server/providers/iTunes.js
@@ -28,7 +28,7 @@ const htmlSanitizer = require('../utils/htmlSanitizer')
*/
class iTunes {
- #responseTimeout = 10000
+ #responseTimeout = 30000
constructor() {}
@@ -63,7 +63,7 @@ class iTunes {
return response.data.results || []
})
.catch((error) => {
- Logger.error(`[iTunes] search request error`, error.message)
+ Logger.error(`[iTunes] search request error`, error)
return []
})
}