Files
archy/packages/app/vite-tmdb.ts
T
DorianandClaude Opus 4.6 ad63a7b1af feat(content): add TV Series content type with TMDB integration
Add complete TV series content surface: extraction from AI responses,
grid/detail views, TMDB TV search endpoint, and panel tab integration.
Includes film_ext-to-TV-series conversion for backward compatibility
and AI prompt instructions for [[tv_ext:...]] tags.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 06:50:03 +00:00

71 lines
2.7 KiB
TypeScript

import type { Plugin } from 'vite'
import type { Connect } from 'vite'
import { loadEnv } from 'vite'
const TMDB_POSTER = 'https://image.tmdb.org/t/p/w342'
const TMDB_BACKDROP = 'https://image.tmdb.org/t/p/w780'
function createTmdbSearchMiddleware(tmdbKey: string | undefined, type: 'movie' | 'tv') {
return async (req: Connect.IncomingMessage, res: any, next: () => void) => {
if (req.method !== 'GET') return next()
const url = new URL(req.url ?? '', `http://${req.headers?.host ?? 'localhost'}`)
const q = url.searchParams.get('q')?.trim()
const y = url.searchParams.get('y')
if (!q) {
res.writeHead(400, { 'Content-Type': 'application/json' })
res.end(JSON.stringify({ error: 'Missing q (query)' }))
return
}
if (!tmdbKey) {
res.writeHead(503, { 'Content-Type': 'application/json' })
res.end(JSON.stringify({ error: 'TMDB_API_KEY not configured' }))
return
}
try {
const yearParam = type === 'movie' ? 'primary_release_year' : 'first_air_date_year'
const params = new URLSearchParams({
api_key: tmdbKey,
query: q,
...(y ? { [yearParam]: y } : {}),
})
const tmdbRes = await fetch(
`https://api.themoviedb.org/3/search/${type}?${params}`
)
const data = (await tmdbRes.json()) as {
results?: { poster_path?: string; backdrop_path?: string }[]
}
const first = data.results?.[0]
const posterUrl = first?.poster_path ? `${TMDB_POSTER}${first.poster_path}` : null
const backdropUrl = first?.backdrop_path ? `${TMDB_BACKDROP}${first.backdrop_path}` : null
res.setHeader('Content-Type', 'application/json')
res.setHeader('Access-Control-Allow-Origin', '*')
res.setHeader('Cache-Control', 'public, max-age=86400')
res.end(JSON.stringify({ posterUrl, backdropUrl }))
} catch (err) {
console.error('[tmdb]', err)
res.writeHead(502, { 'Content-Type': 'application/json' })
res.end(JSON.stringify({ error: String(err) }))
}
}
}
export function tmdbPlugin(): Plugin {
let tmdbKey: string | undefined
return {
name: 'aiui-tmdb-proxy',
configResolved(config) {
const env = loadEnv(config.mode, process.cwd(), '')
tmdbKey = env.TMDB_API_KEY ?? env.VITE_TMDB_API_KEY
},
configureServer(server) {
server.middlewares.use('/api/tmdb/search', createTmdbSearchMiddleware(tmdbKey, 'movie'))
server.middlewares.use('/api/tmdb/search-tv', createTmdbSearchMiddleware(tmdbKey, 'tv'))
},
configurePreviewServer(server) {
server.middlewares.use('/api/tmdb/search', createTmdbSearchMiddleware(tmdbKey, 'movie'))
server.middlewares.use('/api/tmdb/search-tv', createTmdbSearchMiddleware(tmdbKey, 'tv'))
},
}
}