def _apply_keyframe(api: Api, origin: int, delta: int) -> int: if not api.video.current_stream or not api.video.current_stream.keyframes: raise CommandError("keyframe information is not available") possible_pts = [ api.video.current_stream.timecodes[i] for i in api.video.current_stream.keyframes ] return _bisect(possible_pts, origin, delta)
def unpack(self, api: Api) -> int: """Resolves frame indexes into pts. :param api: core API :return: resolved pts """ current_stream = api.video.current_stream if self.unit == _TimeUnit.FRAME: if not current_stream or not current_stream.timecodes: raise CommandError("timecode information is not available") idx = max(1, min(self.value, len(current_stream.timecodes))) - 1 return current_stream.timecodes[idx] if self.unit == _TimeUnit.KEYFRAME: if not current_stream or not current_stream.timecodes: raise CommandError("keyframe information is not available") idx = max(1, min(self.value, len(current_stream.keyframes))) - 1 return current_stream.timecodes[current_stream.keyframes[idx]] if self.unit == _TimeUnit.MS: return self.value raise NotImplementedError(f"unknown unit: {self.unit}")
async def visit_rel_frame(self, node: Any, visited: list[Any]) -> Any: direction, _ = _flatten(visited) origin = self._api.playback.current_pts if direction == _Token.FIRST: return _Time(1, _TimeUnit.FRAME) if direction == _Token.LAST: current_stream = self._api.video.current_stream if not current_stream or not current_stream.timecodes: raise CommandError("timecode information is not available") return _Time(len(current_stream.timecodes), _TimeUnit.FRAME) if direction == _Token.CURRENT: return _Time(origin) delta = _Token.delta_from_direction(direction) return _Time(_apply_frame(self._api, origin, delta))
async def run(self) -> None: text = QApplication.clipboard().text() if not text: self.api.log.error("clipboard is empty, aborting") return lines = text.rstrip("\n").split("\n") subs = await self.args.target.get_subtitles() if not subs: raise CommandUnavailable("nothing to paste into") if len(lines) != len(subs): raise CommandError(f"size mismatch (" f"selected {len(subs)} lines, " f"got {len(lines)} lines in clipboard)".format( len(subs), len(lines))) with self.api.undo.capture(): if self.args.subject == "text": for line, sub in zip(lines, subs): sub.text = line elif self.args.subject == "notes": for line, sub in zip(lines, subs): sub.note = line elif self.args.subject == "times": times: list[tuple[int, int]] = [] for line in lines: try: start, end = line.split("-", 1) times.append( (str_to_ms(start.strip()), str_to_ms(end.strip()))) except ValueError as ex: raise ValueError( f"invalid time format: {line}") from ex for time, sub in zip(times, subs): sub.start = time[0] sub.end = time[1] else: raise AssertionError
async def run(self) -> None: subs = await self.args.target.get_subtitles() if not subs: raise CommandUnavailable("nothing to split") new_selection: T.List[AssEvent] = [] with self.api.undo.capture(), self.api.gui.throttle_updates(): for sub in subs: if "\\k" not in sub.text: continue start = sub.start end = sub.end try: syllables = list(self._get_syllables(sub.text)) except ass_tag_parser.ParseError as ex: raise CommandError(str(ex)) idx = sub.index self.api.subs.events.remove(idx, 1) new_subs: T.List[AssEvent] = [] for i, syllable in enumerate(syllables): sub_copy = copy(sub) sub_copy.start = start sub_copy.end = min(end, start + syllable.duration) sub_copy.text = syllable.text if i > 0: sub_copy.note = "" start = sub_copy.end new_subs.append(sub_copy) self.api.subs.events.insert(idx, *new_subs) new_selection += new_subs self.api.subs.selected_indexes = [ sub.index for sub in new_selection if sub.index is not None ]
async def _get(self, origin: Optional[int]) -> int: try: node_visitor = _PtsNodeVisitor(self._api, origin) return await node_visitor.parse(self.expr.strip()) except parsimonious.exceptions.ParseError as ex: raise CommandError(f"syntax error near {ex.pos}: {ex}") from ex
def _apply_frame(api: Api, origin: int, delta: int) -> int: if not api.video.current_stream or not api.video.current_stream.timecodes: raise CommandError("timecode information is not available") return _bisect(api.video.current_stream.timecodes, origin, delta)