Spaces:
Sleeping
Sleeping
| import { | |
| getNewestMovies, | |
| getSeriesMovies, | |
| getSingleMovies, | |
| getCartoonMovies, | |
| getMoviesByCategory, | |
| getMoviesByCountry, | |
| getMoviesByTopic | |
| } from '../../lib/api.js'; | |
| const fetchWithTimeout = async (url, options = {}) => { | |
| const { timeout = 5000 } = options; | |
| const controller = new AbortController(); | |
| const id = setTimeout(() => controller.abort(), timeout); | |
| try { | |
| const response = await fetch(url, { ...options, signal: controller.signal }); | |
| clearTimeout(id); | |
| return response; | |
| } catch (e) { | |
| clearTimeout(id); | |
| throw e; | |
| } | |
| }; | |
| export const GET = async ({ url }) => { | |
| const type = url.searchParams.get('type') || ''; | |
| const category = url.searchParams.get('category') || ''; | |
| const country = url.searchParams.get('country') || ''; | |
| const topic = url.searchParams.get('topic') || ''; | |
| const keyword = url.searchParams.get('keyword') || url.searchParams.get('q') || ''; | |
| const page = parseInt(url.searchParams.get('page') || '1'); | |
| try { | |
| let result = { items: [] }; | |
| if (keyword) { | |
| result = await import('../../lib/api.js').then(m => m.searchMovies(keyword, page)); | |
| } else if (topic) { | |
| result = await getMoviesByTopic(topic, page); | |
| } else if (country) { | |
| result = await getMoviesByCountry(country, page); | |
| } else if (category) { | |
| if (category === 'phim-moi-cap-nhat') { | |
| result = await getNewestMovies(page); | |
| } else { | |
| result = await getMoviesByCategory(category, page); | |
| } | |
| } else if (type === 'newest') { | |
| result = await getNewestMovies(page); | |
| } else if (type === 'series') { | |
| result = await getSeriesMovies(page); | |
| } else if (type === 'single') { | |
| result = await getSingleMovies(page); | |
| } else if (type === 'cartoon') { | |
| result = await getCartoonMovies(page); | |
| } | |
| // FALLBACK SYSTEM: If less than 4 movies in local DB, fetch from public KKPhim API! | |
| if (!result.items || result.items.length < 4) { | |
| try { | |
| let fallbackUrl = ''; | |
| if (country) { | |
| fallbackUrl = `https://phimapi.com/v1/api/quoc-gia/${country}?page=${page}`; | |
| } else if (category) { | |
| const defaultTypes = { | |
| 'phim-bo': 'phim-bo', | |
| 'phim-le': 'phim-le', | |
| 'hoat-hinh': 'hoat-hinh', | |
| 'tv-shows': 'tv-shows' | |
| }; | |
| if (defaultTypes[category]) { | |
| fallbackUrl = `https://phimapi.com/v1/api/danh-sach/${defaultTypes[category]}?page=${page}`; | |
| } else if (category === 'phim-chieu-rap') { | |
| fallbackUrl = `https://phimapi.com/v1/api/the-loai/hanh-dong?page=${page}`; | |
| } else { | |
| fallbackUrl = `https://phimapi.com/v1/api/the-loai/${category}?page=${page}`; | |
| } | |
| } else if (type === 'newest') { | |
| fallbackUrl = `https://phimapi.com/danh-sach/phim-moi-cap-nhat?page=${page}`; | |
| } else if (type === 'series') { | |
| fallbackUrl = `https://phimapi.com/v1/api/danh-sach/phim-bo?page=${page}`; | |
| } else if (type === 'single') { | |
| fallbackUrl = `https://phimapi.com/v1/api/danh-sach/phim-le?page=${page}`; | |
| } else if (type === 'cartoon') { | |
| fallbackUrl = `https://phimapi.com/v1/api/danh-sach/hoat-hinh?page=${page}`; | |
| } | |
| if (fallbackUrl) { | |
| const res = await fetchWithTimeout(fallbackUrl); | |
| if (res.ok) { | |
| const data = await res.json(); | |
| let items = []; | |
| if (fallbackUrl.includes('danh-sach/phim-moi-cap-nhat')) { | |
| items = data.items || []; | |
| } else if (data.data && data.data.items) { | |
| items = data.data.items || []; | |
| } | |
| const mapped = items.map(item => ({ | |
| _id: item._id, | |
| name: item.name, | |
| slug: item.slug, | |
| origin_name: item.origin_name, | |
| thumb_url: item.thumb_url, | |
| poster_url: item.poster_url, | |
| year: item.year, | |
| quality: item.quality || 'FHD', | |
| lang: item.lang || 'Vietsub', | |
| episode_current: item.episode_current || 'Tập 1', | |
| type: item.type || 'single', | |
| isLocal: false | |
| })); | |
| const localItems = result.items || []; | |
| const mergedItems = [...localItems]; | |
| for (const item of mapped) { | |
| if (!mergedItems.some(x => x.slug === item.slug)) { | |
| mergedItems.push(item); | |
| } | |
| } | |
| result.items = mergedItems.slice(0, 12); | |
| } | |
| } | |
| } catch (err) { | |
| console.error('[API FALLBACK ERROR]', err); | |
| } | |
| } | |
| return new Response(JSON.stringify(result), { | |
| status: 200, | |
| headers: { 'Content-Type': 'application/json' } | |
| }); | |
| } catch (err) { | |
| console.error('Error fetching movies API:', err); | |
| return new Response(JSON.stringify({ error: err.message, items: [] }), { | |
| status: 500, | |
| headers: { 'Content-Type': 'application/json' } | |
| }); | |
| } | |
| }; | |