content: # -*- coding: utf-8 -*-
  import copy
  from datetime import timedelta
  import logging
  import os
  from typing import cast, Any, Dict, Iterator, List, Optional
  
  import pysubs2
  import srt
  import sys
  
  
  logging.basicConfig(level=logging.INFO)
  logger: logging.Logger = logging.getLogger(__name__)
  
  
  class GenericSubtitle:
      def __init__(self, start, end, inner):
          self.start = start
          self.end = end
          self.inner = inner
  
      def __eq__(self, other: object) -> bool:
          if not isinstance(other, GenericSubtitle):
              return False
          eq = True
          eq = eq and self.start == other.start
          eq = eq and self.end == other.end
          eq = eq and self.inner == other.inner
          return eq
  
      @property
      def content(self) -> str:
          if isinstance(self.inner, srt.Subtitle):
              ret = self.inner.content
          elif isinstance(self.inner, pysubs2.SSAEvent):
              ret = self.inner.text
          else:
              raise NotImplementedError(
                  "unsupported subtitle type: %s" % type(self.inner)
              )
          return ret
  
      def resolve_inner_timestamps(self):
          ret = copy.deepcopy(self.inner)
          if isinstance(self.inner, srt.Subtitle):
              ret.start = self.start
              ret.end = self.end
          elif isinstance(self.inner, pysubs2.SSAEvent):
              ret.start = pysubs2.make_time(s=self.start.total_seconds())
              ret.end = pysubs2.make_time(s=self.end.total_seconds())
          else:
              raise NotImplementedError(
                  "unsupported subtitle type: %s" % type(self.inner)
              )
          return ret
  
      def merge_with(self, other):
          assert isinstance(self.inner, type(other.inner))
          inner_merged = copy.deepcopy(self.inner)
          if isinstance(self.inner, srt.Subtitle):
              inner_merged.content = "{}\n{}".format(
                  inner_merged.content, other.inner.content
              )
              return self.__class__(self.start, self.end, inner_merged)
          else:
              raise NotImplementedError(
                  "unsupported subtitle type: %s" % type(self.inner)
              )
  
      @classmethod
      def wrap_inner_subtitle(cls, sub) -> "GenericSubtitle":
          if isinstance(sub, srt.Subtitle):
              return cls(sub.start, sub.end, sub)
          elif isinstance(sub, pysubs2.SSAEvent):
              return cls(
                  timedelta(milliseconds=sub.start), timedelta(milliseconds=sub.end), sub
              )
          else:
              raise NotImplementedError("unsupported subtitle type: %s" % type(sub))
  
  
  class GenericSubtitlesFile:
      def __init__(self, subs: List[GenericSubtitle], *_, **kwargs: Any):
          sub_format: str = cast(str, kwargs.pop("sub_format", None))
          if sub_format is None:
              raise ValueError("format must be specified")
          encoding: str = cast(str, kwargs.pop("encoding", None))
          if encoding is None:
              raise ValueError("encoding must be specified")
          self.subs_: List[GenericSubtitle] = subs
          self._sub_format: str = sub_format
          self._encoding: str = encoding
          self._styles: Optional[Dict[str, pysubs2.SSAStyle]] = kwargs.pop("styles", None)
          self._fonts_opaque: Optional[Dict[str, Any]] = kwargs.pop("fonts_opaque", None)
          self._info: Optional[Dict[str, str]] = kwargs.pop("info", None)
  
      def set_encoding(self, encoding: str) -> "GenericSubtitlesFile":
          if encoding != "same":
              self._encoding = encoding
          return self
  
      def __len__(self) -> int:
          return len(self.subs_)
  
      def __getitem__(self, item: int) -> GenericSubtitle:
          return self.subs_[item]
  
      def __iter__(self) -> Iterator[GenericSubtitle]:
          return iter(self.subs_)
  
      def clone_props_for_subs(
          self, new_subs: List[GenericSubtitle]
      ) -> "GenericSubtitlesFile":
          return GenericSubtitlesFile(
              new_subs,
              sub_format=self._sub_format,
              encoding=self._encoding,
              styles=self._styles,
              fonts_opaque=self._fonts_opaque,
              info=self._info,
          )
  
      def gen_raw_resolved_subs(self):
          for sub in self.subs_:
              yield sub.resolve_inner_timestamps()
  
      def offset(self, td: timedelta) -> "GenericSubtitlesFile":
          offset_subs = []
          for sub in self.subs_:
              offset_subs.append(GenericSubtitle(sub.start + td, sub.end + td, sub.inner))
          return self.clone_props_for_subs(offset_subs)
  
      def write_file(self, fname: str) -> None:
          # TODO: converter to go between self.subs_format and out_format
          if fname is None:
              out_format = self._sub_format
          else:
              out_format = os.path.splitext(fname)[-1][1:]
          subs = list(self.gen_raw_resolved_subs())
          if self._sub_format in ("ssa", "ass", "vtt"):
              ssaf = pysubs2.SSAFile()
              ssaf.events = subs
              if self._styles is not None:
                  ssaf.styles = self._styles
              if self._info is not None:
                  ssaf.info = self._info
              if self._fonts_opaque is not None:
                  ssaf.fonts_opaque = self._fonts_opaque
              to_write = ssaf.to_string(out_format)
          elif self._sub_format == "srt" and out_format in ("ssa", "ass", "vtt"):
              to_write = pysubs2.SSAFile.from_string(srt.compose(subs)).to_string(
                  out_format
              )
          elif out_format == "srt":
              to_write = srt.compose(subs)
          else:
              raise NotImplementedError("unsupported output format: %s" % out_format)
  
          with open(fname or sys.stdout.fileno(), "wb") as f:
              f.write(to_write.encode(self._encoding))
  
  
  class SubsMixin:
      def __init__(self, subs: Optional[GenericSubtitlesFile] = None) -> None:
          self.subs_: Optional[GenericSubtitlesFile] = subs
  
      def set_encoding(self, encoding: str) -> "SubsMixin":
          self.subs_.set_encoding(encoding)
          return self
  