예제 #1
0
파일: pts.py 프로젝트: zeromind/bubblesub
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)
예제 #2
0
파일: pts.py 프로젝트: zeromind/bubblesub
    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}")
예제 #3
0
파일: pts.py 프로젝트: zeromind/bubblesub
 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))
예제 #4
0
    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
예제 #5
0
    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
            ]
예제 #6
0
파일: pts.py 프로젝트: zeromind/bubblesub
 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
예제 #7
0
파일: pts.py 프로젝트: zeromind/bubblesub
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)