mirror of
https://gitlab.com/foxixus/neomovies.git
synced 2025-10-27 17:38:50 +05:00
fix
This commit is contained in:
38
src/app/api/alloha/route.ts
Normal file
38
src/app/api/alloha/route.ts
Normal 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 });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { useSettings } from '@/hooks/useSettings';
|
import { useSettings } from '@/hooks/useSettings';
|
||||||
import { moviesAPI } from '@/lib/api';
|
import { moviesAPI } from '@/lib/api';
|
||||||
@@ -88,10 +88,12 @@ interface MoviePlayerProps {
|
|||||||
|
|
||||||
export default function MoviePlayer({ id, title, poster, imdbId }: MoviePlayerProps) {
|
export default function MoviePlayer({ id, title, poster, imdbId }: MoviePlayerProps) {
|
||||||
const { settings, isInitialized } = useSettings();
|
const { settings, isInitialized } = useSettings();
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
// containerRef removed – using direct iframe integration
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [currentPlayer, setCurrentPlayer] = useState(settings.defaultPlayer);
|
const [currentPlayer, setCurrentPlayer] = useState(settings.defaultPlayer);
|
||||||
|
const [iframeSrc, setIframeSrc] = useState<string | null>(null);
|
||||||
|
const [imdbMissing, setImdbMissing] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isInitialized) {
|
if (isInitialized) {
|
||||||
@@ -124,75 +126,53 @@ export default function MoviePlayer({ id, title, poster, imdbId }: MoviePlayerPr
|
|||||||
}, [id, imdbId]);
|
}, [id, imdbId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (settings.defaultPlayer === 'lumex') {
|
const loadPlayer = async () => {
|
||||||
return;
|
try {
|
||||||
}
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
// Очищаем контейнер при изменении плеера
|
let currentImdb = imdbId;
|
||||||
if (containerRef.current) {
|
if (!currentImdb) {
|
||||||
containerRef.current.innerHTML = '';
|
const { data } = await moviesAPI.getMovie(id);
|
||||||
}
|
const imdb = (data as any)?.imdb_id;
|
||||||
|
if (!imdb) {
|
||||||
const playerDiv = document.createElement('div');
|
setImdbMissing(true);
|
||||||
playerDiv.className = 'kinobox_player';
|
} else {
|
||||||
containerRef.current?.appendChild(playerDiv);
|
setImdbMissing(false);
|
||||||
|
currentImdb = imdb;
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
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);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
document.body.appendChild(script);
|
loadPlayer();
|
||||||
|
}, [id, imdbId, currentPlayer]);
|
||||||
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]);
|
|
||||||
|
|
||||||
const handleRetry = () => {
|
const handleRetry = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
if (containerRef.current) {
|
|
||||||
containerRef.current.innerHTML = '';
|
|
||||||
}
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -208,17 +188,10 @@ export default function MoviePlayer({ id, title, poster, imdbId }: MoviePlayerPr
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PlayerContainer>
|
<PlayerContainer>
|
||||||
{settings.defaultPlayer === 'lumex' && imdbId ? (
|
{iframeSrc ? (
|
||||||
<StyledIframe
|
<StyledIframe src={iframeSrc} allow="fullscreen" loading="lazy" />
|
||||||
src={`${process.env.NEXT_PUBLIC_LUMEX_URL}?imdb_id=${imdbId}`}
|
|
||||||
allow="fullscreen"
|
|
||||||
loading="lazy"
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<>
|
loading && <LoadingContainer>Загрузка плеера...</LoadingContainer>
|
||||||
<div ref={containerRef} style={{ width: '100%', height: '100%', position: 'absolute' }} />
|
|
||||||
{loading && <LoadingContainer>Загрузка плеера...</LoadingContainer>}
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
</PlayerContainer>
|
</PlayerContainer>
|
||||||
{settings.defaultPlayer !== 'lumex' && (
|
{settings.defaultPlayer !== 'lumex' && (
|
||||||
@@ -229,6 +202,11 @@ export default function MoviePlayer({ id, title, poster, imdbId }: MoviePlayerPr
|
|||||||
Для возможности скачивания фильма выберите плеер Lumex в настройках
|
Для возможности скачивания фильма выберите плеер Lumex в настройках
|
||||||
</DownloadMessage>
|
</DownloadMessage>
|
||||||
)}
|
)}
|
||||||
|
{imdbMissing && settings.defaultPlayer !== 'alloha' && (
|
||||||
|
<DownloadMessage>
|
||||||
|
Для просмотра данного фильма/сериала выберите плеер Alloha
|
||||||
|
</DownloadMessage>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,11 +75,6 @@ export default function SettingsContent() {
|
|||||||
name: 'Alloha',
|
name: 'Alloha',
|
||||||
description: 'Основной плеер с высоким качеством',
|
description: 'Основной плеер с высоким качеством',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'collaps',
|
|
||||||
name: 'Collaps',
|
|
||||||
description: 'Альтернативный плеер с хорошей стабильностью',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'lumex',
|
id: 'lumex',
|
||||||
name: 'Lumex',
|
name: 'Lumex',
|
||||||
@@ -88,7 +83,7 @@ export default function SettingsContent() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
const handlePlayerSelect = (playerId: string) => {
|
const handlePlayerSelect = (playerId: string) => {
|
||||||
updateSettings({ defaultPlayer: playerId as 'alloha' | 'collaps' | 'lumex' });
|
updateSettings({ defaultPlayer: playerId as 'alloha' | 'lumex' });
|
||||||
// Возвращаемся на предыдущую страницу
|
// Возвращаемся на предыдущую страницу
|
||||||
window.history.back();
|
window.history.back();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ interface Settings {
|
|||||||
theme: 'light' | 'dark';
|
theme: 'light' | 'dark';
|
||||||
language: 'ru' | 'en';
|
language: 'ru' | 'en';
|
||||||
notifications: boolean;
|
notifications: boolean;
|
||||||
defaultPlayer: 'alloha' | 'collaps' | 'lumex';
|
defaultPlayer: 'alloha' | 'lumex';
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultSettings: Settings = {
|
const defaultSettings: Settings = {
|
||||||
|
|||||||
Reference in New Issue
Block a user