yt_common: chapters and audio mixins
This commit is contained in:
parent
80a0580608
commit
eeba604d11
@ -1 +1 @@
|
||||
from . import antialiasing, automation, config, data, deband, logging, source # noqa: F401
|
||||
from . import antialiasing, automation, chapters, config, data, deband, logging, scale, source # noqa: F401
|
||||
|
63
yt_common/yt_common/chapters.py
Normal file
63
yt_common/yt_common/chapters.py
Normal file
@ -0,0 +1,63 @@
|
||||
from lxml import etree
|
||||
from random import getrandbits
|
||||
|
||||
from typing import Dict, List, NamedTuple, Set
|
||||
|
||||
LANGMAP: Dict[str, str] = {
|
||||
"eng": "en",
|
||||
"und": "und",
|
||||
"jpn": "ja",
|
||||
}
|
||||
|
||||
|
||||
class Chapter(NamedTuple):
|
||||
title: str
|
||||
frame: int
|
||||
lang: str = "eng"
|
||||
|
||||
|
||||
class RandMan:
|
||||
used: Set[int]
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.used = set()
|
||||
|
||||
def get_rand(self, bits: int = 64) -> str:
|
||||
r = getrandbits(bits)
|
||||
while r in self.used:
|
||||
r = getrandbits(bits)
|
||||
self.used.add(r)
|
||||
return str(r)
|
||||
|
||||
|
||||
def timecode_to_timestamp(stamp: float) -> str:
|
||||
m = int(stamp // 60)
|
||||
stamp %= 60
|
||||
h = int(m // 60)
|
||||
m %= 60
|
||||
return f"{h:02d}:{m:02d}:{stamp:06.3f}000000"
|
||||
|
||||
|
||||
def make_chapters(chapters: List[Chapter], timecodes: List[float], outfile: str) -> None:
|
||||
chapters.sort(key=lambda c: c.frame)
|
||||
rand = RandMan()
|
||||
|
||||
root = etree.Element("Chapters")
|
||||
ed = etree.SubElement(root, "EditionEntry")
|
||||
etree.SubElement(ed, "EditionUID").text = rand.get_rand()
|
||||
|
||||
for i, c in enumerate(chapters):
|
||||
start = timecode_to_timestamp(timecodes[c.frame])
|
||||
end = timecode_to_timestamp(timecodes[chapters[i+1].frame]) if i < len(chapters) - 1 else None
|
||||
atom = etree.SubElement(ed, "ChapterAtom")
|
||||
etree.SubElement(atom, "ChapterTimeStart").text = start
|
||||
if end is not None:
|
||||
etree.SubElement(atom, "ChapterTimeEnd").text = end
|
||||
disp = etree.SubElement(atom, "ChapterDisplay")
|
||||
etree.SubElement(disp, "ChapterString").text = c.title
|
||||
etree.SubElement(disp, "ChapLanguageIETF").text = LANGMAP[c.lang]
|
||||
etree.SubElement(disp, "ChapterLanguage").text = c.lang
|
||||
etree.SubElement(atom, "ChapterUID").text = rand.get_rand()
|
||||
|
||||
with open(outfile, "wb") as o:
|
||||
o.write(etree.tostring(root, encoding="utf-8", xml_declaration=True, pretty_print=True))
|
@ -1,4 +1,8 @@
|
||||
from typing import Union
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import List, Union
|
||||
|
||||
|
||||
class Config():
|
||||
@ -16,5 +20,48 @@ class Config():
|
||||
self.datapath = datapath
|
||||
|
||||
def format_filename(self, filename: str) -> str:
|
||||
return filename.format(epnum=self.desc, title=self.title,
|
||||
title_long=self.title_long, resolution=self.resolution)
|
||||
fname = filename.format(epnum=self.desc, title=self.title,
|
||||
title_long=self.title_long, resolution=self.resolution)
|
||||
return os.path.join(f"../{self.desc}/", fname)
|
||||
|
||||
def encode_audio(self, afile: str) -> str:
|
||||
return afile # default: passthrough
|
||||
|
||||
|
||||
class AudioEncoder(ABC):
|
||||
@abstractmethod
|
||||
def encode_audio(self, afile: str) -> str:
|
||||
pass
|
||||
|
||||
|
||||
class FFAudio(AudioEncoder):
|
||||
def encode_audio(self, afile: str) -> str:
|
||||
ffmpeg_args = [
|
||||
"ffmpeg",
|
||||
"-hide_banner", "-loglevel", "panic",
|
||||
"-i", afile,
|
||||
"-y",
|
||||
"-map", "0:a",
|
||||
] + self.codec_args() + ["_ffaudio_encode.mka"]
|
||||
print("+ " + " ".join(ffmpeg_args))
|
||||
subprocess.call(ffmpeg_args)
|
||||
return "_ffaudio_encode.mka"
|
||||
|
||||
@abstractmethod
|
||||
def codec_args(self) -> List[str]:
|
||||
pass
|
||||
|
||||
|
||||
class OpusMixin(FFAudio):
|
||||
def codec_args(self) -> List[str]:
|
||||
return ["-c:a", "libopus", "-b:a", "192k", "-sample_fmt", "s16"]
|
||||
|
||||
|
||||
class FdkAacMixin(FFAudio):
|
||||
def codec_args(self) -> List[str]:
|
||||
return ["-c:a", "libfdk_aac", "-b:a", "256k", "-sample_fmt", "s16"]
|
||||
|
||||
|
||||
class FlacMixin(FFAudio):
|
||||
def codec_args(self) -> List[str]:
|
||||
return ["-c:a", "flac"]
|
||||
|
@ -78,8 +78,9 @@ class FileSource(ABC):
|
||||
class SimpleSource(FileSource):
|
||||
src: List[FileTrim]
|
||||
|
||||
def __init__(self, src: Union[FileTrim, List[FileTrim]]) -> None:
|
||||
self.src = src if isinstance(src, list) else [src]
|
||||
def __init__(self, src: Union[str, List[str], FileTrim, List[FileTrim]]) -> None:
|
||||
srcl = src if isinstance(src, list) else [src]
|
||||
self.src = [FileTrim(s, (None, None)) if isinstance(s, str) else s for s in srcl]
|
||||
|
||||
def get_audio(self) -> List[FileTrim]:
|
||||
return self.src
|
||||
|
Loading…
x
Reference in New Issue
Block a user