Улучшить управление видеоплеером и громкостью
- Автоматическая установка громкости на 100% при запуске плеера - Постоянный мониторинг громкости каждые 2 секунды во время воспроизведения - Усиление надежности команд Play/Pause/Seek (тройная отправка с задержками) - Улучшенная перемотка ±10 секунд для всех типов плееров - Поддержка громкости для нативного HTML5 видео (AniLibria) - Агрессивная установка громкости в первые 15 секунд после загрузки iframe Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
2ab0457568
commit
7da9ab00b1
1 changed files with 95 additions and 55 deletions
|
|
@ -697,34 +697,39 @@ export default function Cinema({
|
||||||
const isPlay = command === "play";
|
const isPlay = command === "play";
|
||||||
const isToggle = command === "toggle";
|
const isToggle = command === "toggle";
|
||||||
|
|
||||||
// 1. Kodik Player API (Supports both object and stringified commands)
|
// Отправляем команды многократно для надежности (разные плееры реагируют в разное время)
|
||||||
broadcastToWindowTree({ key: "kodik_player_api", value: { method: isToggle ? "toggle" : (isPlay ? "play" : "pause") } });
|
for (let i = 0; i < 3; i++) {
|
||||||
if (!isToggle) {
|
setTimeout(() => {
|
||||||
broadcastToWindowTree({ key: "kodik_player_api", value: { method: isPlay ? "play" : "pause" } });
|
// 1. Kodik Player API (Supports both object and stringified commands)
|
||||||
|
broadcastToWindowTree({ key: "kodik_player_api", value: { method: isToggle ? "toggle" : (isPlay ? "play" : "pause") } });
|
||||||
|
if (!isToggle) {
|
||||||
|
broadcastToWindowTree({ key: "kodik_player_api", value: { method: isPlay ? "play" : "pause" } });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Playerjs API (Used by Alloha, Kinoplay, Collaps, VideoCDN, Ashdi, HDRezka)
|
||||||
|
broadcastToWindowTree({ api: isToggle ? "toggle" : (isPlay ? "play" : "pause") });
|
||||||
|
if (!isToggle) {
|
||||||
|
broadcastToWindowTree({ api: isPlay ? "play" : "pause" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Alloha API
|
||||||
|
broadcastToWindowTree({ action: isPlay ? "play" : "pause" });
|
||||||
|
broadcastToWindowTree({ method: isPlay ? "play" : "pause" });
|
||||||
|
|
||||||
|
// 4. VidLink Pro / Video.js API
|
||||||
|
broadcastToWindowTree({ type: isPlay ? "PLAYER_PLAY" : "PLAYER_PAUSE" });
|
||||||
|
broadcastToWindowTree({ type: isPlay ? "play" : "pause" });
|
||||||
|
broadcastToWindowTree({ action: isPlay ? "play" : "pause" });
|
||||||
|
broadcastToWindowTree({ event: isPlay ? "play" : "pause" });
|
||||||
|
|
||||||
|
// 5. YouTube / VidSrc / AutoEmbed HTML5 API
|
||||||
|
broadcastToWindowTree({ event: "command", func: isPlay ? "playVideo" : "pauseVideo", args: "" });
|
||||||
|
|
||||||
|
// 6. Generic HTML5 postMessage
|
||||||
|
broadcastToWindowTree({ method: isPlay ? "play" : "pause" });
|
||||||
|
broadcastToWindowTree({ command: isPlay ? "play" : "pause" });
|
||||||
|
}, i * 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Playerjs API (Used by Alloha, Kinoplay, Collaps, VideoCDN, Ashdi, HDRezka)
|
|
||||||
broadcastToWindowTree({ api: isToggle ? "toggle" : (isPlay ? "play" : "pause") });
|
|
||||||
if (!isToggle) {
|
|
||||||
broadcastToWindowTree({ api: isPlay ? "play" : "pause" });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Alloha API
|
|
||||||
broadcastToWindowTree({ action: isPlay ? "play" : "pause" });
|
|
||||||
broadcastToWindowTree({ method: isPlay ? "play" : "pause" });
|
|
||||||
|
|
||||||
// 4. VidLink Pro / Video.js API
|
|
||||||
broadcastToWindowTree({ type: isPlay ? "PLAYER_PLAY" : "PLAYER_PAUSE" });
|
|
||||||
broadcastToWindowTree({ type: isPlay ? "play" : "pause" });
|
|
||||||
broadcastToWindowTree({ action: isPlay ? "play" : "pause" });
|
|
||||||
broadcastToWindowTree({ event: isPlay ? "play" : "pause" });
|
|
||||||
|
|
||||||
// 5. YouTube / VidSrc / AutoEmbed HTML5 API
|
|
||||||
broadcastToWindowTree({ event: "command", func: isPlay ? "playVideo" : "pauseVideo", args: "" });
|
|
||||||
|
|
||||||
// 6. Generic HTML5 postMessage
|
|
||||||
broadcastToWindowTree({ method: isPlay ? "play" : "pause" });
|
|
||||||
broadcastToWindowTree({ command: isPlay ? "play" : "pause" });
|
|
||||||
}, [broadcastToWindowTree]);
|
}, [broadcastToWindowTree]);
|
||||||
|
|
||||||
const setPlayerVolumeMax = useCallback((showToast: boolean = false) => {
|
const setPlayerVolumeMax = useCallback((showToast: boolean = false) => {
|
||||||
|
|
@ -802,7 +807,10 @@ export default function Cinema({
|
||||||
}, 120);
|
}, 120);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Установка громкости 100% каждый раз при воспроизведении
|
||||||
setPlayerVolumeMax(false);
|
setPlayerVolumeMax(false);
|
||||||
|
setTimeout(() => setPlayerVolumeMax(false), 500);
|
||||||
|
setTimeout(() => setPlayerVolumeMax(false), 1500);
|
||||||
setIsPlayingState(true);
|
setIsPlayingState(true);
|
||||||
showTvToast("Воспроизведение", "▶", 1200);
|
showTvToast("Воспроизведение", "▶", 1200);
|
||||||
}, [sendIframePlaybackCommand, setPlayerVolumeMax, showTvToast]);
|
}, [sendIframePlaybackCommand, setPlayerVolumeMax, showTvToast]);
|
||||||
|
|
@ -846,39 +854,44 @@ export default function Cinema({
|
||||||
const targetTime = Math.max(0, curTime + secondsDelta);
|
const targetTime = Math.max(0, curTime + secondsDelta);
|
||||||
currentPlaybackRef.current.currentTime = targetTime;
|
currentPlaybackRef.current.currentTime = targetTime;
|
||||||
|
|
||||||
// 1. Kodik API (Seek to absolute seconds & relative seek delta)
|
// Отправляем команды перемотки несколько раз для надежности
|
||||||
broadcastToWindowTree({ key: "kodik_player_api", value: { method: "seek", time: targetTime } });
|
for (let i = 0; i < 3; i++) {
|
||||||
broadcastToWindowTree({ key: "kodik_player_api", value: { method: "seek_delta", time: secondsDelta } });
|
setTimeout(() => {
|
||||||
broadcastToWindowTree({ key: "kodik_player_api", value: { method: secondsDelta > 0 ? "forward" : "rewind", time: Math.abs(secondsDelta) } });
|
// 1. Kodik API (Seek to absolute seconds & relative seek delta)
|
||||||
|
broadcastToWindowTree({ key: "kodik_player_api", value: { method: "seek", time: targetTime } });
|
||||||
|
broadcastToWindowTree({ key: "kodik_player_api", value: { method: "seek_delta", time: secondsDelta } });
|
||||||
|
broadcastToWindowTree({ key: "kodik_player_api", value: { method: secondsDelta > 0 ? "forward" : "rewind", time: Math.abs(secondsDelta) } });
|
||||||
|
|
||||||
// 2. Playerjs API (Used by Alloha, Kinoplay, Collaps, VideoCDN, Ashdi, HDRezka)
|
// 2. Playerjs API (Used by Alloha, Kinoplay, Collaps, VideoCDN, Ashdi, HDRezka)
|
||||||
broadcastToWindowTree({ api: "seek", set: targetTime });
|
broadcastToWindowTree({ api: "seek", set: targetTime });
|
||||||
broadcastToWindowTree({ api: "seek", set: secondsDelta > 0 ? `+${secondsDelta}` : `${secondsDelta}` });
|
broadcastToWindowTree({ api: "seek", set: secondsDelta > 0 ? `+${secondsDelta}` : `${secondsDelta}` });
|
||||||
broadcastToWindowTree({ api: "seek", time: targetTime });
|
broadcastToWindowTree({ api: "seek", time: targetTime });
|
||||||
broadcastToWindowTree({ api: "seek", delta: secondsDelta });
|
broadcastToWindowTree({ api: "seek", delta: secondsDelta });
|
||||||
broadcastToWindowTree({ api: "seek_delta", time: secondsDelta });
|
broadcastToWindowTree({ api: "seek_delta", time: secondsDelta });
|
||||||
|
|
||||||
// 3. Alloha API
|
// 3. Alloha API
|
||||||
broadcastToWindowTree({ action: "seek", time: targetTime });
|
broadcastToWindowTree({ action: "seek", time: targetTime });
|
||||||
broadcastToWindowTree({ action: "seek", delta: secondsDelta });
|
broadcastToWindowTree({ action: "seek", delta: secondsDelta });
|
||||||
broadcastToWindowTree({ method: "seek", time: targetTime });
|
broadcastToWindowTree({ method: "seek", time: targetTime });
|
||||||
broadcastToWindowTree({ method: "seekTo", value: targetTime });
|
broadcastToWindowTree({ method: "seekTo", value: targetTime });
|
||||||
|
|
||||||
// 4. VidLink Pro / Video.js API
|
// 4. VidLink Pro / Video.js API
|
||||||
broadcastToWindowTree({ type: "SEEK", data: { time: targetTime } });
|
broadcastToWindowTree({ type: "SEEK", data: { time: targetTime } });
|
||||||
broadcastToWindowTree({ type: "PLAYER_SEEK", time: targetTime });
|
broadcastToWindowTree({ type: "PLAYER_SEEK", time: targetTime });
|
||||||
broadcastToWindowTree({ type: "seek", time: targetTime });
|
broadcastToWindowTree({ type: "seek", time: targetTime });
|
||||||
broadcastToWindowTree({ action: "seek", time: targetTime });
|
broadcastToWindowTree({ action: "seek", time: targetTime });
|
||||||
broadcastToWindowTree({ action: "seek", delta: secondsDelta });
|
broadcastToWindowTree({ action: "seek", delta: secondsDelta });
|
||||||
|
|
||||||
// 5. YouTube / VidSrc / AutoEmbed HTML5 API
|
// 5. YouTube / VidSrc / AutoEmbed HTML5 API
|
||||||
broadcastToWindowTree({ event: "command", func: "seekTo", args: [targetTime, true] });
|
broadcastToWindowTree({ event: "command", func: "seekTo", args: [targetTime, true] });
|
||||||
broadcastToWindowTree({ event: "command", func: "seek", args: [targetTime] });
|
broadcastToWindowTree({ event: "command", func: "seek", args: [targetTime] });
|
||||||
broadcastToWindowTree({ action: "seekTo", value: targetTime });
|
broadcastToWindowTree({ action: "seekTo", value: targetTime });
|
||||||
|
|
||||||
// 6. Generic HTML5 postMessage
|
// 6. Generic HTML5 postMessage
|
||||||
broadcastToWindowTree({ method: "seek", time: targetTime });
|
broadcastToWindowTree({ method: "seek", time: targetTime });
|
||||||
broadcastToWindowTree({ command: "seek", time: targetTime });
|
broadcastToWindowTree({ command: "seek", time: targetTime });
|
||||||
|
}, i * 100);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
showTvToast(secondsDelta > 0 ? `+${secondsDelta} сек` : `${secondsDelta} сек`, secondsDelta > 0 ? "⏩" : "⏪", 1000);
|
showTvToast(secondsDelta > 0 ? `+${secondsDelta} сек` : `${secondsDelta} сек`, secondsDelta > 0 ? "⏩" : "⏪", 1000);
|
||||||
}, [broadcastToWindowTree, showTvToast]);
|
}, [broadcastToWindowTree, showTvToast]);
|
||||||
|
|
@ -1684,6 +1697,11 @@ export default function Cinema({
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setPlayerVolumeMax(false);
|
setPlayerVolumeMax(false);
|
||||||
}, 4500);
|
}, 4500);
|
||||||
|
// Агрессивная установка громкости каждые 3 секунды (первые 15 секунд)
|
||||||
|
const volumeInterval = setInterval(() => {
|
||||||
|
setPlayerVolumeMax(false);
|
||||||
|
}, 3000);
|
||||||
|
setTimeout(() => clearInterval(volumeInterval), 15000);
|
||||||
}, [sendIframePlaybackCommand, setPlayerVolumeMax]);
|
}, [sendIframePlaybackCommand, setPlayerVolumeMax]);
|
||||||
|
|
||||||
// Start playback for a media item (movie or specific series episode)
|
// Start playback for a media item (movie or specific series episode)
|
||||||
|
|
@ -1976,6 +1994,16 @@ export default function Cinema({
|
||||||
const activeMedia = playingMedia || selectedMedia;
|
const activeMedia = playingMedia || selectedMedia;
|
||||||
currentPlaybackRef.current = { currentTime, duration };
|
currentPlaybackRef.current = { currentTime, duration };
|
||||||
|
|
||||||
|
// Постоянно поддерживаем громкость на 100% для нативного видео
|
||||||
|
try {
|
||||||
|
if (videoRef.current.volume !== 1.0) {
|
||||||
|
videoRef.current.volume = 1.0;
|
||||||
|
}
|
||||||
|
if (videoRef.current.muted) {
|
||||||
|
videoRef.current.muted = false;
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
|
||||||
if (duration > 0 && isTauri) {
|
if (duration > 0 && isTauri) {
|
||||||
const payload: CinemaPlayback = {
|
const payload: CinemaPlayback = {
|
||||||
title_id: activeMedia.id,
|
title_id: activeMedia.id,
|
||||||
|
|
@ -2119,6 +2147,18 @@ export default function Cinema({
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
}, [playingEpisode, playerMode, allMirrorsFailed, playingMedia, selectedMedia, playingSeasonNumber, isTauri, currentUser?.email]);
|
}, [playingEpisode, playerMode, allMirrorsFailed, playingMedia, selectedMedia, playingSeasonNumber, isTauri, currentUser?.email]);
|
||||||
|
|
||||||
|
// Постоянный мониторинг и поддержание громкости на 100% во время воспроизведения
|
||||||
|
useEffect(() => {
|
||||||
|
if (!playingEpisode) return;
|
||||||
|
|
||||||
|
// Устанавливаем громкость каждые 2 секунды во время воспроизведения
|
||||||
|
const volumeKeeper = setInterval(() => {
|
||||||
|
setPlayerVolumeMax(false);
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
return () => clearInterval(volumeKeeper);
|
||||||
|
}, [playingEpisode, setPlayerVolumeMax]);
|
||||||
|
|
||||||
// Listen to postMessage from embedded players (VidLink, Kodik, Alloha)
|
// Listen to postMessage from embedded players (VidLink, Kodik, Alloha)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleWindowMessage = (e: MessageEvent) => {
|
const handleWindowMessage = (e: MessageEvent) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue