import { Clock, Minus, Plus, RotateCcw } from "lucide-react" import { useState } from "react" import { useTranslation } from "react-i18next" import { toast } from "sonner" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover" import { useTimeline } from "@/features/timeline/hooks/use-timeline" import { useTracks } from "@/features/timeline/hooks/use-tracks" import { SubtitleClip } from "../types/subtitles" /** * Инструменты синхронизации субтитров * Позволяет сдвигать время субтитров и выполнять массовые операции */ export function SubtitleSyncTools() { const { t } = useTranslation() const { tracks } = useTracks() const { updateClip } = useTimeline() const [timeOffset, setTimeOffset] = useState(0) const [isOpen, setIsOpen] = useState(false) /** * Проверяет, является ли клип субтитром */ const isSubtitleClip = (clip: any): clip is SubtitleClip => { return ( clip.type === "subtitle" && typeof clip.text === "string" && typeof clip.startTime === "number" && typeof clip.duration === "number" ) } /** * Получает все субтитры из таймлайна */ const getSubtitlesFromTimeline = (): SubtitleClip[] => { const subtitles: SubtitleClip[] = [] for (const track of tracks) { if (track.type === "subtitle") { for (const clip of track.clips) { if (isSubtitleClip(clip)) { subtitles.push(clip) } } } } return subtitles } /** * Применяет временной сдвиг ко всем субтитрам */ const applyTimeOffset = async () => { if (timeOffset === 0) return const subtitles = getSubtitlesFromTimeline() if (subtitles.length === 0) { toast.error(t("subtitles.sync.noSubtitles", "Нет субтитров"), { description: t("subtitles.sync.noSubtitlesDesc", "На таймлайне нет субтитров для синхронизации"), }) return } try { let updatedCount = 0 for (const subtitle of subtitles) { const newStartTime = Math.max(0, Number(subtitle.startTime || 0) + Number(timeOffset || 0)) void updateClip(subtitle.id, { startTime: newStartTime, }) updatedCount++ } toast.success(t("subtitles.sync.success", "Синхронизация выполнена"), { description: t("subtitles.sync.successDesc", "Обновлено {{count}} субтитров", { count: updatedCount }), }) setIsOpen(false) setTimeOffset(0) } catch (error) { console.error("Ошибка при синхронизации субтитров:", error) toast.error(t("subtitles.sync.error", "Ошибка синхронизации"), { description: t("subtitles.sync.errorDesc", "Не удалось синхронизировать субтитры"), }) } } /** * Сбрасывает временной сдвиг */ const resetOffset = () => { setTimeOffset(0) } return (

{t("subtitles.sync.adjustTiming", "Настройка времени")}

{t("subtitles.sync.adjustDesc", "Сдвинуть все субтитры на указанное время")}

setTimeOffset(Number.parseFloat(e.target.value) || 0)} step={0.1} className="text-center" />
{timeOffset > 0 && t("subtitles.sync.shiftForward", "Субтитры будут сдвинуты вперед на {{time}}с", { time: timeOffset.toFixed(1), })} {timeOffset < 0 && t("subtitles.sync.shiftBackward", "Субтитры будут сдвинуты назад на {{time}}с", { time: Math.abs(timeOffset).toFixed(1), })} {timeOffset === 0 && t("subtitles.sync.noShift", "Субтитры не будут сдвинуты")}
) }