/
Ruden161
/
player
Обзор
Документация
Войти
/
Ruden161
/
player
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/video/timecodes.py
231 строка
8 KB
Ruden161
Start
23 ноя 2025, 16:19
23 ноя 2025, 16:19
0ff3eca
Код
Авторство
О чём код?
""" Модуль для работы с таймкодами """ from PyQt6.QtCore import QObject, pyqtSignal from typing import List, Dict, Optional import json import os class TimecodeEntry: """Класс для представления одного таймкода""" def __init__(self, time: float, description: str = "", tags: List[str] = None): """ Инициализация таймкода Args: time: Время в секундах description: Описание таймкода tags: Список тегов """ self.time = time self.description = description self.tags = tags or [] def to_dict(self) -> Dict: """Преобразовать таймкод в словарь""" return { 'time': self.time, 'description': self.description, 'tags': self.tags } @classmethod def from_dict(cls, data: Dict) -> 'TimecodeEntry': """Создать таймкод из словаря""" return cls( time=data['time'], description=data.get('description', ''), tags=data.get('tags', []) ) def __str__(self) -> str: """Строковое представление таймкода""" minutes = int(self.time // 60) seconds = int(self.time % 60) milliseconds = int((self.time % 1) * 1000) return f"{minutes:02d}:{seconds:02d}.{milliseconds:03d}" class TimecodeManager(QObject): """Менеджер таймкодов""" # Сигналы timecodes_changed = pyqtSignal() # Изменены таймкоды timecode_added = pyqtSignal(TimecodeEntry) # Добавлен новый таймкод timecode_removed = pyqtSignal(TimecodeEntry) # Удален таймкод def __init__(self, video_path: Optional[str] = None): """ Инициализация менеджера таймкодов Args: video_path: Путь к видеофайлу (для сохранения таймкодов) """ super().__init__() self.video_path = video_path self.timecodes: List[TimecodeEntry] = [] def add_timecode(self, time: float, description: str = "", tags: List[str] = None) -> TimecodeEntry: """ Добавить новый таймкод Args: time: Время в секундах description: Описание tags: Теги Returns: Добавленный таймкод """ timecode = TimecodeEntry(time, description, tags) self.timecodes.append(timecode) self.timecodes.sort(key=lambda x: x.time) # Сортируем по времени self.timecode_added.emit(timecode) self.timecodes_changed.emit() return timecode def remove_timecode(self, timecode: TimecodeEntry) -> bool: """ Удалить таймкод Args: timecode: Таймкод для удаления Returns: True если таймкод был удален, False если не найден """ if timecode in self.timecodes: self.timecodes.remove(timecode) self.timecode_removed.emit(timecode) self.timecodes_changed.emit() return True return False def remove_timecode_at_time(self, time: float, tolerance: float = 0.1) -> bool: """ Удалить таймкод по времени Args: time: Время в секундах tolerance: Допустимая погрешность в секундах Returns: True если таймкод был удален, False если не найден """ for timecode in self.timecodes: if abs(timecode.time - time) <= tolerance: return self.remove_timecode(timecode) return False def get_timecodes_in_range(self, start_time: float, end_time: float) -> List[TimecodeEntry]: """ Получить таймкоды в заданном диапазоне времени Args: start_time: Начальное время в секундах end_time: Конечное время в секундах Returns: Список таймкодов в диапазоне """ return [tc for tc in self.timecodes if start_time <= tc.time <= end_time] def get_nearest_timecode(self, time: float) -> Optional[TimecodeEntry]: """ Получить ближайший таймкод к заданному времени Args: time: Время в секундах Returns: Ближайший таймкод или None если таймкоды отсутствуют """ if not self.timecodes: return None return min(self.timecodes, key=lambda tc: abs(tc.time - time)) def clear_timecodes(self): """Очистить все таймкоды""" self.timecodes.clear() self.timecodes_changed.emit() def save_to_file(self, file_path: Optional[str] = None) -> bool: """ Сохранить таймкоды в файл Args: file_path: Путь к файлу (если не указан, используется путь к видео + .timecodes) Returns: True если успешно сохранено, False в случае ошибки """ if not file_path and self.video_path: file_path = self.video_path + '.timecodes' if not file_path: return False try: data = [tc.to_dict() for tc in self.timecodes] with open(file_path, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) return True except Exception: return False def load_from_file(self, file_path: Optional[str] = None) -> bool: """ Загрузить таймкоды из файла Args: file_path: Путь к файлу (если не указан, используется путь к видео + .timecodes) Returns: True если успешно загружено, False в случае ошибки """ if not file_path and self.video_path: file_path = self.video_path + '.timecodes' if not file_path or not os.path.exists(file_path): return False try: with open(file_path, 'r', encoding='utf-8') as f: data = json.load(f) self.timecodes.clear() for item in data: self.timecodes.append(TimecodeEntry.from_dict(item)) self.timecodes.sort(key=lambda x: x.time) self.timecodes_changed.emit() return True except Exception: return False def get_timecodes_with_tag(self, tag: str) -> List[TimecodeEntry]: """ Получить таймкоды с заданным тегом Args: tag: Тег для поиска Returns: Список таймкодов с заданным тегом """ return [tc for tc in self.timecodes if tag in tc.tags] def format_time(self, time: float) -> str: """ Форматировать время в строку Args: time: Время в секундах Returns: Отформатированная строка времени """ return str(TimecodeEntry(time))