diff --git a/src/components/mixed/ImageLightbox.tsx b/src/components/mixed/ImageLightbox.tsx index 0bd41fc..5904e04 100644 --- a/src/components/mixed/ImageLightbox.tsx +++ b/src/components/mixed/ImageLightbox.tsx @@ -21,6 +21,7 @@ export default function ImageLightbox({ url, name, onClose, onPrev, onNext, item ) const [aiTagging, setAiTagging] = useState(false) const [aiTagError, setAiTagError] = useState(null) + const [tagRefreshKey, setTagRefreshKey] = useState(0) useEffect(() => { const handleKey = (e: KeyboardEvent) => { @@ -82,6 +83,7 @@ export default function ImageLightbox({ url, name, onClose, onPrev, onNext, item setAiTagError(null) try { await onAiTag() + setTagRefreshKey((k) => k + 1) onTagsChanged?.() } catch (err) { setAiTagError(err instanceof Error ? err.message : 'AI tagging failed') @@ -165,7 +167,7 @@ export default function ImageLightbox({ url, name, onClose, onPrev, onNext, item

Tags

- + ) : ( diff --git a/src/components/mixed/MixedView.tsx b/src/components/mixed/MixedView.tsx index 1931507..42bc4db 100644 --- a/src/components/mixed/MixedView.tsx +++ b/src/components/mixed/MixedView.tsx @@ -378,6 +378,19 @@ export default function MixedView({ libraryId, initialPath }: Props) { onClose={() => setModal(null)} onPrev={modal.mediaIndex > 0 ? () => navigateModal(-1) : undefined} onNext={modal.mediaIndex < mediaEntries.length - 1 ? () => navigateModal(1) : undefined} + onAiTag={modal.itemKey ? async () => { + const res = await fetch('/api/ai-tagging', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ itemKey: modal.itemKey }), + }) + if (!res.ok) { + const data = await res.json().catch(() => ({})) + throw new Error((data as { error?: string }).error ?? 'AI tagging failed') + } + fetchAssignments() + setFilterRefreshKey((k) => k + 1) + } : undefined} /> )} {modal?.type === 'image' && ( diff --git a/src/components/mixed/VideoPlayerModal.tsx b/src/components/mixed/VideoPlayerModal.tsx index 495aa5a..b1a1031 100644 --- a/src/components/mixed/VideoPlayerModal.tsx +++ b/src/components/mixed/VideoPlayerModal.tsx @@ -12,10 +12,11 @@ interface Props { onNext?: () => void itemKey?: string onTagsChanged?: () => void + onAiTag?: () => Promise context?: 'mixed' | 'movies' | 'tv' } -export default function VideoPlayerModal({ url, name, onClose, onPrev, onNext, itemKey, onTagsChanged, context = 'mixed' }: Props) { +export default function VideoPlayerModal({ url, name, onClose, onPrev, onNext, itemKey, onTagsChanged, onAiTag, context = 'mixed' }: Props) { const settings = useUserSettings() const autoPlay = context === 'mixed' ? settings.mixedAutoplay : context === 'movies' ? settings.moviesAutoplay : settings.tvAutoplay const loop = context === 'mixed' ? settings.mixedLoop : context === 'movies' ? settings.moviesLoop : settings.tvLoop @@ -24,6 +25,9 @@ export default function VideoPlayerModal({ url, name, onClose, onPrev, onNext, i const [showTags, setShowTags] = useState( () => !!itemKey && typeof window !== 'undefined' && window.innerWidth >= 1280 ) + const [aiTagging, setAiTagging] = useState(false) + const [aiTagError, setAiTagError] = useState(null) + const [tagRefreshKey, setTagRefreshKey] = useState(0) useEffect(() => { const handleKey = (e: KeyboardEvent) => { @@ -76,6 +80,43 @@ export default function VideoPlayerModal({ url, name, onClose, onPrev, onNext, i 🏷 )} + {onAiTag && ( + + )}