This commit is contained in:
2025-06-24 17:53:26 +00:00
parent f22a152bee
commit bb07b44490
4 changed files with 88 additions and 77 deletions

View File

@@ -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 });
}
}

View File

@@ -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<HTMLDivElement>(null);
// containerRef removed using direct iframe integration
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [currentPlayer, setCurrentPlayer] = useState(settings.defaultPlayer);
const [iframeSrc, setIframeSrc] = useState<string | null>(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 (
<>
<PlayerContainer>
{settings.defaultPlayer === 'lumex' && imdbId ? (
<StyledIframe
src={`${process.env.NEXT_PUBLIC_LUMEX_URL}?imdb_id=${imdbId}`}
allow="fullscreen"
loading="lazy"
/>
{iframeSrc ? (
<StyledIframe src={iframeSrc} allow="fullscreen" loading="lazy" />
) : (
<>
<div ref={containerRef} style={{ width: '100%', height: '100%', position: 'absolute' }} />
{loading && <LoadingContainer>Загрузка плеера...</LoadingContainer>}
</>
loading && <LoadingContainer>Загрузка плеера...</LoadingContainer>
)}
</PlayerContainer>
{settings.defaultPlayer !== 'lumex' && (
@@ -229,6 +202,11 @@ export default function MoviePlayer({ id, title, poster, imdbId }: MoviePlayerPr
Для возможности скачивания фильма выберите плеер Lumex в настройках
</DownloadMessage>
)}
{imdbMissing && settings.defaultPlayer !== 'alloha' && (
<DownloadMessage>
Для просмотра данного фильма/сериала выберите плеер Alloha
</DownloadMessage>
)}
</>
);
}

View File

@@ -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();
};

View File

@@ -6,7 +6,7 @@ interface Settings {
theme: 'light' | 'dark';
language: 'ru' | 'en';
notifications: boolean;
defaultPlayer: 'alloha' | 'collaps' | 'lumex';
defaultPlayer: 'alloha' | 'lumex';
}
const defaultSettings: Settings = {