From bb07b444902ee202f1b96a4cfedcad27c426065f Mon Sep 17 00:00:00 2001 From: Foxix Date: Tue, 24 Jun 2025 17:53:26 +0000 Subject: [PATCH] fix --- src/app/api/alloha/route.ts | 38 ++++++++++ src/components/MoviePlayer.tsx | 118 ++++++++++++----------------- src/components/SettingsContent.tsx | 7 +- src/hooks/useSettings.ts | 2 +- 4 files changed, 88 insertions(+), 77 deletions(-) create mode 100644 src/app/api/alloha/route.ts diff --git a/src/app/api/alloha/route.ts b/src/app/api/alloha/route.ts new file mode 100644 index 0000000..8ee5898 --- /dev/null +++ b/src/app/api/alloha/route.ts @@ -0,0 +1,38 @@ +import { NextResponse } from 'next/server'; + +export const revalidate = 0; // always fresh + +export async function GET(request: Request) { + try { + const { searchParams } = new URL(request.url); + const imdbId = searchParams.get('imdb_id'); + const tmdbId = searchParams.get('tmdb_id'); + + if (!imdbId && !tmdbId) { + return NextResponse.json({ error: 'imdb_id or tmdb_id query param is required' }, { status: 400 }); + } + + const token = process.env.ALLOHA_TOKEN; + if (!token) { + return NextResponse.json({ error: 'Server misconfiguration: ALLOHA_TOKEN missing' }, { status: 500 }); + } + + const idParam = imdbId ? `imdb=${encodeURIComponent(imdbId)}` : `tmdb=${encodeURIComponent(tmdbId!)}`; + const apiUrl = `https://api.alloha.tv/?token=${token}&${idParam}`; + const apiRes = await fetch(apiUrl, { next: { revalidate: 0 } }); + + if (!apiRes.ok) { + return NextResponse.json({ error: 'Failed to fetch from Alloha' }, { status: apiRes.status }); + } + + const json = await apiRes.json(); + if (json.status !== 'success' || !json.data?.iframe) { + return NextResponse.json({ error: 'Video not found' }, { status: 404 }); + } + + return NextResponse.json({ iframe: json.data.iframe }); + } catch (e) { + console.error('Alloha API route error:', e); + return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 }); + } +} diff --git a/src/components/MoviePlayer.tsx b/src/components/MoviePlayer.tsx index c4312cf..49fb3ae 100644 --- a/src/components/MoviePlayer.tsx +++ b/src/components/MoviePlayer.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useEffect, useRef, useState } from 'react'; +import { useEffect, useState } from 'react'; import styled from 'styled-components'; import { useSettings } from '@/hooks/useSettings'; import { moviesAPI } from '@/lib/api'; @@ -88,10 +88,12 @@ interface MoviePlayerProps { export default function MoviePlayer({ id, title, poster, imdbId }: MoviePlayerProps) { const { settings, isInitialized } = useSettings(); - const containerRef = useRef(null); + // containerRef removed – using direct iframe integration const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [currentPlayer, setCurrentPlayer] = useState(settings.defaultPlayer); + const [iframeSrc, setIframeSrc] = useState(null); + const [imdbMissing, setImdbMissing] = useState(false); useEffect(() => { if (isInitialized) { @@ -124,75 +126,53 @@ export default function MoviePlayer({ id, title, poster, imdbId }: MoviePlayerPr }, [id, imdbId]); useEffect(() => { - if (settings.defaultPlayer === 'lumex') { - return; - } + const loadPlayer = async () => { + try { + setLoading(true); + setError(null); - // Очищаем контейнер при изменении плеера - if (containerRef.current) { - containerRef.current.innerHTML = ''; - } - - const playerDiv = document.createElement('div'); - playerDiv.className = 'kinobox_player'; - containerRef.current?.appendChild(playerDiv); - - const script = document.createElement('script'); - script.src = 'https://kinobox.tv/kinobox.min.js'; - script.async = true; - - script.onload = () => { - if (window.kbox && containerRef.current) { - const playerConfig = { - search: { - imdb: imdbId, - title: title - }, - menu: { - enable: false, - default: 'menu_list', - mobile: 'menu_button', - format: '{N} :: {T} ({Q})', - limit: 5, - open: false, - }, - notFoundMessage: 'Видео не найдено.', - players: { - alloha: { enable: settings.defaultPlayer === 'alloha', position: 1 }, - collaps: { enable: settings.defaultPlayer === 'collaps', position: 2 }, - lumex: { enable: settings.defaultPlayer === 'lumex', position: 3 } - }, - params: { - all: { - poster: poster - } + let currentImdb = imdbId; + if (!currentImdb) { + const { data } = await moviesAPI.getMovie(id); + const imdb = (data as any)?.imdb_id; + if (!imdb) { + setImdbMissing(true); + } else { + setImdbMissing(false); + currentImdb = imdb; } - }; + } - window.kbox('.kinobox_player', playerConfig); + if (currentPlayer === 'alloha') { + // сначала попробуем по IMDb + let res = await fetch(`/api/alloha?imdb_id=${currentImdb}`); + if (!res.ok) { + // fallback на TMDB id (тот же id, передаваемый в компонент) + res = await fetch(`/api/alloha?tmdb_id=${id}`); + } + if (!res.ok) throw new Error('Видео не найдено'); + const json = await res.json(); + setIframeSrc(json.iframe); + } else if (currentPlayer === 'lumex') { + setIframeSrc(`${process.env.NEXT_PUBLIC_LUMEX_URL}?imdb_id=${currentImdb}`); + } else { + throw new Error('Выбран неподдерживаемый плеер'); + } + } catch (err) { + console.error(err); + setError('Не удалось загрузить плеер. Попробуйте позже.'); + } finally { setLoading(false); } }; - document.body.appendChild(script); - - return () => { - if (containerRef.current) { - containerRef.current.innerHTML = ''; - } - const existingScript = document.querySelector('script[src="https://kinobox.tv/kinobox.min.js"]'); - if (existingScript) { - document.body.removeChild(existingScript); - } - }; - }, [id, title, poster, imdbId, settings.defaultPlayer]); + loadPlayer(); + }, [id, imdbId, currentPlayer]); const handleRetry = () => { setLoading(true); setError(null); - if (containerRef.current) { - containerRef.current.innerHTML = ''; - } + setLoading(false); }; @@ -208,17 +188,10 @@ export default function MoviePlayer({ id, title, poster, imdbId }: MoviePlayerPr return ( <> - {settings.defaultPlayer === 'lumex' && imdbId ? ( - + {iframeSrc ? ( + ) : ( - <> -
- {loading && Загрузка плеера...} - + loading && Загрузка плеера... )} {settings.defaultPlayer !== 'lumex' && ( @@ -229,6 +202,11 @@ export default function MoviePlayer({ id, title, poster, imdbId }: MoviePlayerPr Для возможности скачивания фильма выберите плеер Lumex в настройках )} + {imdbMissing && settings.defaultPlayer !== 'alloha' && ( + + Для просмотра данного фильма/сериала выберите плеер Alloha + + )} ); } diff --git a/src/components/SettingsContent.tsx b/src/components/SettingsContent.tsx index 4384123..ba47d17 100644 --- a/src/components/SettingsContent.tsx +++ b/src/components/SettingsContent.tsx @@ -75,11 +75,6 @@ export default function SettingsContent() { name: 'Alloha', description: 'Основной плеер с высоким качеством', }, - { - id: 'collaps', - name: 'Collaps', - description: 'Альтернативный плеер с хорошей стабильностью', - }, { id: 'lumex', name: 'Lumex', @@ -88,7 +83,7 @@ export default function SettingsContent() { ]; const handlePlayerSelect = (playerId: string) => { - updateSettings({ defaultPlayer: playerId as 'alloha' | 'collaps' | 'lumex' }); + updateSettings({ defaultPlayer: playerId as 'alloha' | 'lumex' }); // Возвращаемся на предыдущую страницу window.history.back(); }; diff --git a/src/hooks/useSettings.ts b/src/hooks/useSettings.ts index 2d29304..bf861c7 100644 --- a/src/hooks/useSettings.ts +++ b/src/hooks/useSettings.ts @@ -6,7 +6,7 @@ interface Settings { theme: 'light' | 'dark'; language: 'ru' | 'en'; notifications: boolean; - defaultPlayer: 'alloha' | 'collaps' | 'lumex'; + defaultPlayer: 'alloha' | 'lumex'; } const defaultSettings: Settings = {