refactor(video): rename useRetrieveThumbnail to useVideoThumbnail and add remove functionality

The hook has been renamed to better reflect its purpose and expanded with a removeThumbnail function to provide complete thumbnail management capabilities
This commit is contained in:
icarus 2025-10-13 21:51:44 +08:00
parent 6c097e6733
commit e88b4c091d
2 changed files with 86 additions and 70 deletions

View File

@ -1,70 +0,0 @@
import { loggerService } from '@logger'
import { retrieveVideoContent } from '@renderer/services/ApiService'
import ImageStorage from '@renderer/services/ImageStorage'
import { getProviderById } from '@renderer/services/ProviderService'
import { Video } from '@renderer/types'
import { useCallback } from 'react'
const logger = loggerService.withContext('useRetrieveThumbnail')
const pendingSet = new Set<string>()
export const useRetrieveThumbnail = () => {
const retrieveThumbnail = useCallback(async (video: Video): Promise<string | null> => {
const provider = getProviderById(video.providerId)
if (!provider) {
throw new Error(`Provider not found for id ${video.providerId}`)
}
const thumbnailKey = `video-thumbnail-${video.id}`
if (pendingSet.has(thumbnailKey)) {
throw new Error('Thumbnail retrieval already pending')
}
pendingSet.add(thumbnailKey)
try {
const cachedThumbnail = await ImageStorage.get(thumbnailKey)
if (cachedThumbnail) {
return cachedThumbnail
}
const result = await retrieveVideoContent({
type: 'openai',
provider,
videoId: video.id,
query: { variant: 'thumbnail' }
})
const { response } = result
if (!response.ok) {
throw new Error(`Unexpected thumbnail status: ${response.status}`)
}
const blob = await response.blob()
if (!blob || blob.size === 0) {
throw new Error('Thumbnail response body is empty')
}
const base64 = await new Promise<string>((resolve, reject) => {
const reader = new FileReader()
reader.onloadend = () => {
if (typeof reader.result === 'string') {
resolve(reader.result)
} else {
reject(new Error('Failed to convert thumbnail to base64'))
}
}
reader.onerror = () => reject(reader.error ?? new Error('Failed to read thumbnail blob'))
reader.readAsDataURL(blob)
})
await ImageStorage.set(thumbnailKey, base64)
return base64
} catch (e) {
logger.error(`Failed to get thumbnail for video ${video.id}`, e as Error)
} finally {
pendingSet.delete(thumbnailKey)
}
return null
}, [])
return retrieveThumbnail
}

View File

@ -0,0 +1,86 @@
import { loggerService } from '@logger'
import { retrieveVideoContent } from '@renderer/services/ApiService'
import ImageStorage from '@renderer/services/ImageStorage'
import { getProviderById } from '@renderer/services/ProviderService'
import { Video } from '@renderer/types'
import { useCallback } from 'react'
const logger = loggerService.withContext('useRetrieveThumbnail')
const pendingSet = new Set<string>()
export const useVideoThumbnail = () => {
const getThumbnailKey = useCallback((id: string) => {
return `video-thumbnail-${id}`
}, [])
const retrieveThumbnail = useCallback(
async (video: Video): Promise<string | null> => {
const provider = getProviderById(video.providerId)
if (!provider) {
throw new Error(`Provider not found for id ${video.providerId}`)
}
const thumbnailKey = getThumbnailKey(video.id)
if (pendingSet.has(thumbnailKey)) {
throw new Error('Thumbnail retrieval already pending')
}
pendingSet.add(thumbnailKey)
try {
const cachedThumbnail = await ImageStorage.get(thumbnailKey)
if (cachedThumbnail) {
return cachedThumbnail
}
const result = await retrieveVideoContent({
type: 'openai',
provider,
videoId: video.id,
query: { variant: 'thumbnail' }
})
const { response } = result
if (!response.ok) {
throw new Error(`Unexpected thumbnail status: ${response.status}`)
}
const blob = await response.blob()
if (!blob || blob.size === 0) {
throw new Error('Thumbnail response body is empty')
}
const base64 = await new Promise<string>((resolve, reject) => {
const reader = new FileReader()
reader.onloadend = () => {
if (typeof reader.result === 'string') {
resolve(reader.result)
} else {
reject(new Error('Failed to convert thumbnail to base64'))
}
}
reader.onerror = () => reject(reader.error ?? new Error('Failed to read thumbnail blob'))
reader.readAsDataURL(blob)
})
await ImageStorage.set(thumbnailKey, base64)
return base64
} catch (e) {
logger.error(`Failed to get thumbnail for video ${video.id}`, e as Error)
} finally {
pendingSet.delete(thumbnailKey)
}
return null
},
[getThumbnailKey]
)
const removeThumbnail = useCallback(
async (id: string) => {
const key = getThumbnailKey(id)
return ImageStorage.remove(key)
},
[getThumbnailKey]
)
return { getThumbnailKey, retrieveThumbnail, removeThumbnail }
}