update dependencies and add downloads page, various fixes
This commit is contained in:
+17
-94
@@ -30,18 +30,9 @@ import AddIcon from '@mui/icons-material/Add'
|
||||
import CloudDownloadIcon from '@mui/icons-material/CloudDownload'
|
||||
import type { Server } from '../context/ServersContext'
|
||||
import { useServers } from '../context/ServersContext'
|
||||
import { HydrusClient, extractTitleFromTags } from '../api/hydrusClient'
|
||||
import { buildLibraryCacheKey, getLibraryCacheStats, loadLibraryCache, pruneLibraryCache, saveLibraryCache } from '../libraryCache'
|
||||
import type { MediaSection, ServerSyncSummary, Track } from '../types'
|
||||
|
||||
const SYNC_SECTION_LIMIT = 2000
|
||||
import { buildLibraryCacheKey, getLibraryCacheStats, pruneLibraryCache } from '../libraryCache'
|
||||
import { syncLibraryCache } from '../librarySync'
|
||||
const DEFAULT_SERVER_FORM = { name: '', host: '', port: undefined, apiKey: '', ssl: false, forceApiKeyInQuery: false }
|
||||
const SYNC_SECTIONS: Array<{ id: MediaSection; label: string; predicate: string }> = [
|
||||
{ id: 'audio', label: 'Audio', predicate: 'system:filetype = audio' },
|
||||
{ id: 'video', label: 'Video', predicate: 'system:filetype = video' },
|
||||
{ id: 'image', label: 'Image', predicate: 'system:filetype = image' },
|
||||
{ id: 'application', label: 'Applications', predicate: 'system:filetype = application' },
|
||||
]
|
||||
|
||||
type SettingsPageProps = {
|
||||
onClose?: () => void
|
||||
@@ -71,18 +62,6 @@ export default function SettingsPage({ onClose, devOverlayEnabled, onDevOverlayE
|
||||
const syncNoticeTimeoutsRef = useRef<Record<string, number>>({})
|
||||
const currentCacheKey = useMemo(() => buildLibraryCacheKey(servers), [servers])
|
||||
|
||||
const extractNamespaceValue = (tags: string[] | null | undefined, ns: string) => {
|
||||
if (!tags || !Array.isArray(tags)) return null
|
||||
const prefix = `${ns.toLowerCase()}:`
|
||||
const values = tags
|
||||
.filter((tag) => typeof tag === 'string' && tag.toLowerCase().startsWith(prefix))
|
||||
.map((tag) => tag.slice(prefix.length).replace(/_/g, ' ').trim())
|
||||
.filter(Boolean)
|
||||
return values.sort((a, b) => b.length - a.length)[0] || null
|
||||
}
|
||||
|
||||
const buildTrackCacheKey = (serverId?: string, fileId?: number) => (serverId && fileId != null ? `${serverId}:${fileId}` : '')
|
||||
|
||||
useEffect(() => {
|
||||
setEditing(null)
|
||||
setForm(DEFAULT_SERVER_FORM)
|
||||
@@ -195,82 +174,26 @@ export default function SettingsPage({ onClose, devOverlayEnabled, onDevOverlayE
|
||||
setSyncingServerId(server.id)
|
||||
|
||||
try {
|
||||
const client = new HydrusClient(server)
|
||||
const cacheKey = buildLibraryCacheKey(servers)
|
||||
const snapshot = await loadLibraryCache(cacheKey)
|
||||
const mergedSearchCache = { ...(snapshot?.searchCache ?? {}) }
|
||||
const mergedTrackMap: Record<string, Track> = {}
|
||||
const previousServerTrackKeys = new Set<string>()
|
||||
|
||||
let localCounter = Date.now()
|
||||
for (const track of snapshot?.tracks ?? []) {
|
||||
const hydratedTrack: Track = { ...track, id: ++localCounter }
|
||||
const key = buildTrackCacheKey(hydratedTrack.serverId, hydratedTrack.fileId)
|
||||
if (!key) continue
|
||||
|
||||
if (hydratedTrack.serverId === server.id) {
|
||||
previousServerTrackKeys.add(key)
|
||||
continue
|
||||
}
|
||||
|
||||
mergedTrackMap[key] = hydratedTrack
|
||||
}
|
||||
|
||||
const counts: ServerSyncSummary['counts'] = {}
|
||||
const currentServerTrackKeys = new Set<string>()
|
||||
|
||||
for (const section of SYNC_SECTIONS) {
|
||||
const searchTags = [section.predicate]
|
||||
const ids = await client.searchFiles(searchTags, SYNC_SECTION_LIMIT)
|
||||
counts[section.id] = ids.length
|
||||
mergedSearchCache[`${server.id}|${section.id}|tracks|${JSON.stringify(searchTags)}`] = ids
|
||||
|
||||
if (ids.length === 0) continue
|
||||
|
||||
const tagMap = await client.getFilesTags(ids, 8)
|
||||
const mediaInfoMap = section.id === 'application' ? await client.getFilesMediaInfo(ids, 6) : {}
|
||||
for (const fileId of ids) {
|
||||
const tags = tagMap[fileId] || []
|
||||
const key = buildTrackCacheKey(server.id, fileId)
|
||||
if (!key) continue
|
||||
currentServerTrackKeys.add(key)
|
||||
|
||||
mergedTrackMap[key] = {
|
||||
id: ++localCounter,
|
||||
fileId,
|
||||
serverId: server.id,
|
||||
serverName: server.name || server.host,
|
||||
title: extractTitleFromTags(tags) || '',
|
||||
artist: extractNamespaceValue(tags, 'artist') || undefined,
|
||||
album: extractNamespaceValue(tags, 'album') || undefined,
|
||||
tags: tags.length ? tags : undefined,
|
||||
url: client.getFileUrl(fileId),
|
||||
thumbnail: client.getThumbnailUrl(fileId),
|
||||
mimeType: mediaInfoMap[fileId]?.mimeType,
|
||||
isVideo: mediaInfoMap[fileId]?.isVideo ?? (section.id === 'video' ? true : undefined),
|
||||
mediaKind: section.id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await saveLibraryCache(cacheKey, Object.values(mergedTrackMap), mergedSearchCache)
|
||||
|
||||
const total = Object.values(counts).reduce((sum, value) => sum + (value || 0), 0)
|
||||
const addedCount = Array.from(currentServerTrackKeys).filter((key) => !previousServerTrackKeys.has(key)).length
|
||||
const removedCount = Array.from(previousServerTrackKeys).filter((key) => !currentServerTrackKeys.has(key)).length
|
||||
const summary: ServerSyncSummary = {
|
||||
updatedAt: Date.now(),
|
||||
total,
|
||||
counts,
|
||||
}
|
||||
const result = await syncLibraryCache(servers, { targetServerIds: [server.id] })
|
||||
const summary = result.summaries[server.id]
|
||||
if (!summary) throw new Error('Sync did not return a server summary')
|
||||
|
||||
updateServer(server.id, { syncSummary: summary })
|
||||
|
||||
if (summary.message) {
|
||||
setLastTest(summary.message)
|
||||
await refreshCacheStats(result.cacheKey)
|
||||
return
|
||||
}
|
||||
|
||||
const addedCount = result.addedCounts[server.id] ?? 0
|
||||
const removedCount = result.removedCounts[server.id] ?? 0
|
||||
const completionMessage = addedCount === 0 && removedCount === 0
|
||||
? `Sync complete. No file changes. ${total} cached items.`
|
||||
? `Sync complete. No file changes. ${summary.total} cached items.`
|
||||
: `Sync complete. Added ${addedCount} files, removed ${removedCount} files.`
|
||||
setLastTest(`Sync complete. ${total} cached items.`)
|
||||
setLastTest(`Sync complete. ${summary.total} cached items.`)
|
||||
setSyncCompletionNotices((current) => ({ ...current, [server.id]: completionMessage }))
|
||||
await refreshCacheStats(cacheKey)
|
||||
await refreshCacheStats(result.cacheKey)
|
||||
if (syncNoticeTimeoutsRef.current[server.id]) {
|
||||
window.clearTimeout(syncNoticeTimeoutsRef.current[server.id])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user