diff --git a/.gitignore b/.gitignore index 10b47ab..fbd4cd1 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ ffmpeg2pass*.log **/__pycache__/ **/*.egg-info/ **/bdmv/ +**/bdpremux/ diff --git a/Princess Principal/01/01.vpy b/Princess Principal/01/01.vpy new file mode 100644 index 0000000..3c25dd2 --- /dev/null +++ b/Princess Principal/01/01.vpy @@ -0,0 +1,41 @@ +import vapoursynth as vs + +from pripri_common import PriPriConfig, edgefix, denoise, descale, antialias, regrain, scenefilter_ed, finalize + +from yt_common.automation import SelfRunner +from yt_common.source import FileTrim, SimpleSource + +from typing import Optional + +import os + +core = vs.core + +EPNUM: int = int(os.path.basename(os.path.splitext(__file__)[0])) +CONFIG: PriPriConfig = PriPriConfig(EPNUM) +SOURCE: SimpleSource = SimpleSource( + FileTrim("../bdmv/[170927][BDMV] プリンセス・プリンシパル I/PRINCESS_PRINCIPAL_1/BDMV/STREAM/00006.m2ts", (0, -24)) +) +ED: Optional[int] = 32608 + + +def filter() -> vs.VideoNode: + src = SOURCE.source() + if ED is not None: + src = src.std.FreezeFrames(first=[src.num_frames-4], last=[src.num_frames-1], replacement=[src.num_frames-5]) + ef = edgefix(src) + den = denoise(ef) + rescale = descale(den) + aa = antialias(rescale) + grain = regrain(aa) + ed = scenefilter_ed(grain, src, ED) + final = finalize(ed) + src.set_output(1) + final.set_output(0) + return final + + +if __name__ == "__main__": + SelfRunner(CONFIG, SOURCE, filter, audio_codec=["-c:a", "libopus", "-b:a", "192k", "-sample_fmt", "s16"]) +else: + filter() diff --git a/Princess Principal/02/02.vpy b/Princess Principal/02/02.vpy new file mode 100644 index 0000000..db6291c --- /dev/null +++ b/Princess Principal/02/02.vpy @@ -0,0 +1,41 @@ +import vapoursynth as vs + +from pripri_common import PriPriConfig, edgefix, denoise, descale, antialias, regrain, scenefilter_ed, finalize + +from yt_common.automation import SelfRunner +from yt_common.source import FileTrim, SimpleSource + +from typing import Optional + +import os + +core = vs.core + +EPNUM: int = int(os.path.basename(os.path.splitext(__file__)[0])) +CONFIG: PriPriConfig = PriPriConfig(EPNUM) +SOURCE: SimpleSource = SimpleSource( + FileTrim("../bdmv/[170927][BDMV] プリンセス・プリンシパル I/PRINCESS_PRINCIPAL_1/BDMV/STREAM/00007.m2ts", (0, -45)) +) +ED: Optional[int] = 32607 + + +def filter() -> vs.VideoNode: + src = SOURCE.source() + if ED is not None: + src = src.std.FreezeFrames(first=[src.num_frames-4], last=[src.num_frames-1], replacement=[src.num_frames-5]) + ef = edgefix(src) + den = denoise(ef) + rescale = descale(den) + aa = antialias(rescale) + grain = regrain(aa) + ed = scenefilter_ed(grain, src, ED) + final = finalize(ed) + src.set_output(1) + final.set_output(0) + return final + + +if __name__ == "__main__": + SelfRunner(CONFIG, SOURCE, filter, audio_codec=["-c:a", "libopus", "-b:a", "192k", "-sample_fmt", "s16"]) +else: + filter() diff --git a/Princess Principal/mypy.ini b/Princess Principal/mypy.ini new file mode 120000 index 0000000..f79cd28 --- /dev/null +++ b/Princess Principal/mypy.ini @@ -0,0 +1 @@ +../yt_common/mypy.ini \ No newline at end of file diff --git a/Princess Principal/pripri_common/__init__.py b/Princess Principal/pripri_common/__init__.py new file mode 100644 index 0000000..07e7558 --- /dev/null +++ b/Princess Principal/pripri_common/__init__.py @@ -0,0 +1,3 @@ +from .config import PriPriConfig # noqa: F401 +from .filter import edgefix, denoise, descale, antialias, regrain, scenefilter_ed, finalize # noqa: F401 +from . import filter # noqa: F401 diff --git a/Princess Principal/pripri_common/config.py b/Princess Principal/pripri_common/config.py new file mode 100644 index 0000000..6e302d6 --- /dev/null +++ b/Princess Principal/pripri_common/config.py @@ -0,0 +1,21 @@ +from yt_common.config import Config + +from typing import Union + +import os + +TITLE: str = "PriPri" +TITLE_LONG: str = "Princess Principal" +RESOLUTION: int = 1080 +DATAPATH: str = os.path.dirname(__file__) + + +class PriPriConfig(Config): + def __init__(self, desc: Union[str, int]) -> None: + super().__init__( + desc, + TITLE, + TITLE_LONG, + RESOLUTION, + DATAPATH + ) diff --git a/Princess Principal/pripri_common/filter.py b/Princess Principal/pripri_common/filter.py new file mode 100644 index 0000000..c259dba --- /dev/null +++ b/Princess Principal/pripri_common/filter.py @@ -0,0 +1,91 @@ +import vapoursynth as vs +import os + +from typing import Any, Dict, Optional + +from yt_common.antialiasing import sraa_clamp, mask_strong +from yt_common.data import FSRCNNX +from yt_common.denoise import bm3d + +from G41Fun import MaskedDHA +from awsmfunc import bbmod +from kagefunc import retinex_edgemask +from lvsfunc.kernels import Bicubic +from lvsfunc.misc import replace_ranges, scale_thresh +from lvsfunc.scale import descale as ldescale +from vardefunc import fsrcnnx_upscale, diff_creditless_mask +from vsutil import depth +from vsutil import Range as CRange + +NCED = os.path.join(os.path.dirname(__file__), + "../bdmv/[180223][BDMV] プリンセス・プリンシパル VI/PRINCESS_PRINCIPAL_6/BDMV/STREAM/00013.m2ts") + +core = vs.core + + +def edgefix(clip: vs.VideoNode) -> vs.VideoNode: + bb: vs.VideoNode = bbmod(clip, top=3, bottom=3, left=3, right=3, blur=500) + return bb + + +def denoise(clip: vs.VideoNode) -> vs.VideoNode: + return bm3d(clip, sigma=0.75, radius=1) + + +def _nnedi3_double(clip: vs.VideoNode) -> vs.VideoNode: + nnargs: Dict[str, Any] = dict(field=0, dh=True, nsize=4, nns=4, qual=2, pscrn=2) + nn = clip.std.Transpose() \ + .nnedi3.nnedi3(**nnargs) \ + .std.Transpose() \ + .nnedi3.nnedi3(**nnargs) + return nn.resize.Bicubic(src_top=0.5, src_left=0.5) + + +def descale(clip: vs.VideoNode) -> vs.VideoNode: + def _fsrlineart(clip: vs.VideoNode, width: int, height: int) -> vs.VideoNode: + clip = clip.resize.Point(1280, 720) + assert clip.format is not None + nn = depth(_nnedi3_double(depth(clip, 16)), clip.format.bits_per_sample) + fsr = fsrcnnx_upscale(clip, width, height, upscaled_smooth=nn, shader_file=FSRCNNX) + mask = retinex_edgemask(depth(fsr.std.ShufflePlanes(0, vs.GRAY), 16)) + mask = mask.std.Binarize(scale_thresh(0.65, mask)).std.Maximum() + mask = depth(mask, clip.format.bits_per_sample, range_in=CRange.FULL, range=CRange.FULL) + return core.std.MaskedMerge(nn.resize.Bicubic(width, height, filter_param_a=0, filter_param_b=1/2), fsr, mask) + return depth(ldescale(clip, height=720, kernel=Bicubic(b=0, c=1/2), upscaler=_fsrlineart, mask=None), 16) + + +def antialias(clip: vs.VideoNode) -> vs.VideoNode: + def _sraa_pp_dehalo(sraa: vs.VideoNode) -> vs.VideoNode: + sraa = MaskedDHA(sraa, rx=2.4, darkstr=0.1, brightstr=0.75) + return sraa + return sraa_clamp(clip, postprocess=_sraa_pp_dehalo, mask=mask_strong(clip)) + + +def regrain(clip: vs.VideoNode) -> vs.VideoNode: + mask_bright = clip.std.PlaneStats().adg.Mask(5) + mask_dark = clip.std.PlaneStats().adg.Mask(15) + sgrain_l = core.std.MaskedMerge(clip, clip.grain.Add(var=0.15, constant=True, seed=393), mask_bright.std.Invert()) + sgrain_h = core.std.MaskedMerge(clip, clip.grain.Add(var=0.25, uvar=0.1, constant=True, seed=393), mask_bright) + sgrain_h = core.std.MaskedMerge(clip, sgrain_h, mask_dark.std.Invert()) + sgrain = sgrain_h.std.MergeDiff(clip.std.MakeDiff(sgrain_l)) + dgrain = core.std.MaskedMerge(clip, clip.grain.Add(var=0.35, uvar=0.1, constant=False, seed=393), mask_dark) + grain = dgrain.std.MergeDiff(clip.std.MakeDiff(sgrain)) + return grain + + +def scenefilter_ed(clip: vs.VideoNode, src: vs.VideoNode, ed: Optional[int]) -> vs.VideoNode: + if ed is None: + return clip + nc = depth(core.lsmas.LWLibavSource(NCED)[24:-24], 16) + den = denoise(src) + dehalo = MaskedDHA(den, rx=2, darkstr=0.1, brightstr=0.75) + edc = replace_ranges(den, dehalo, [(ed+2121, ed+2159)]) + edc = antialias(edc) + edc = regrain(edc) + mask = diff_creditless_mask(src, src[ed:], nc, ed, 6425, prefilter=True) + edc = core.std.MaskedMerge(edc, den, mask) + return replace_ranges(clip, edc, [(ed, ed+2159)]) + + +def finalize(clip: vs.VideoNode) -> vs.VideoNode: + return depth(clip, 10) diff --git a/Princess Principal/pripri_common/final-settings b/Princess Principal/pripri_common/final-settings new file mode 100644 index 0000000..957b876 --- /dev/null +++ b/Princess Principal/pripri_common/final-settings @@ -0,0 +1 @@ +x265 --input - --y4m --input-depth 10 --output-depth 10 --input-csp i420 --profile main10 --colormatrix bt709 --colorprim bt709 --transfer bt709 --preset slower --rc-lookahead 72 --keyint 360 --min-keyint 23 --subme 5 --qcomp 0.7 --crf 15 --aq-mode 3 --aq-strength 0.9 --bframes 16 --psy-rd 2.0 --psy-rdoq 1.8 --rdoq-level 1 --deblock -2:-2 --no-sao --no-open-gop --no-strong-intra-smoothing --frames {frames:d} --output {filename:s}.h265 diff --git a/Princess Principal/setup.py b/Princess Principal/setup.py new file mode 100755 index 0000000..60ec4d7 --- /dev/null +++ b/Princess Principal/setup.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 + +import setuptools + +name = "pripri_common" +version = "0.0.0" +release = "0.0.0" + +setuptools.setup( + name=name, + version=release, + author="louis", + author_email="louis@poweris.moe", + description="princess principal common module", + packages=["pripri_common"], + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + ], + package_data={ + 'pripri_common': ['py.typed', 'final-settings'], + }, + python_requires='>=3.8', +) diff --git a/yt_common/yt_common/antialiasing.py b/yt_common/yt_common/antialiasing.py index 38cf9bc..8396794 100644 --- a/yt_common/yt_common/antialiasing.py +++ b/yt_common/yt_common/antialiasing.py @@ -35,7 +35,7 @@ def combine_mask(clip: vs.VideoNode, weak: Union[Range, List[Range], None] = Non def sraa_clamp(clip: vs.VideoNode, mask: Optional[vs.VideoNode] = None, - strength: float = 2, opencl: bool = True, + strength: float = 2, opencl: bool = False, postprocess: Optional[Callable[[vs.VideoNode], vs.VideoNode]] = None) -> vs.VideoNode: sraa = upscaled_sraa(clip, rfactor=1.3, nnedi3cl=opencl, downscaler=Bicubic(b=0, c=1/2).scale) sraa = postprocess(sraa) if postprocess else sraa diff --git a/yt_common/yt_common/automation.py b/yt_common/yt_common/automation.py index ca79af6..ed58262 100644 --- a/yt_common/yt_common/automation.py +++ b/yt_common/yt_common/automation.py @@ -42,8 +42,7 @@ class Encoder(): cleanup: List[str] - def __init__(self, epnum: int, settings_path: str, - binary: Optional[str] = None, force: bool = False) -> None: + def __init__(self, settings_path: str, binary: Optional[str] = None, force: bool = False) -> None: self.binary = binary if binary is not None else "" self.force = force self.cleanup = [] @@ -181,7 +180,7 @@ class SelfRunner(): self.video_clean = False self.audio_clean = False - parser = argparse.ArgumentParser(description=f"Encode {self.config.title} Episode {self.config.epnum:02d}") + parser = argparse.ArgumentParser(description=f"Encode {self.config.title} {self.config.desc}") if workraw_filter: parser.add_argument("-w", "--workraw", help="Encode workraw, fast x264.", action="store_true") parser.add_argument("-s", "--start", nargs='?', type=int, help="Start encode at frame START.") @@ -226,7 +225,7 @@ class SelfRunner(): if start >= end: raise ValueError("Start frame must be before end frame!") - out_name = f"{self.config.title.lower()}_{self.config.epnum:02d}_{self.suffix}.mkv" + out_name = f"{self.config.title.lower()}_{self.config.desc}_{self.suffix}.mkv" if args.comparison and workraw_filter: log.status("Generating comparison...") @@ -244,8 +243,8 @@ class SelfRunner(): if not os.path.isfile(settings_path): raise FileNotFoundError(f"Failed to find {settings_path}!") - self.encoder = Encoder(self.config.epnum, settings_path, args.encoder, args.force) - self.video_file = self.encoder.encode(self.clip, f"{self.config.epnum:02d}_{self.suffix}_{start}_{end}", + self.encoder = Encoder(settings_path, args.encoder, args.force) + self.video_file = self.encoder.encode(self.clip, f"{self.config.desc}_{self.suffix}_{start}_{end}", start, end) log.status("--- LOOKING FOR AUDIO ---") @@ -288,7 +287,7 @@ class SelfRunner(): "--track-order", "0:0,0:1", ] if chapters: - chap = [f for f in [f"{self.config.epnum:02d}.xml", "chapters.xml"] if os.path.isfile(f)] + chap = [f for f in [f"{self.config.desc}.xml", "chapters.xml"] if os.path.isfile(f)] if len(chap) != 0: mkvtoolnix_args += [ "--chapters", chap[0], diff --git a/yt_common/yt_common/config.py b/yt_common/yt_common/config.py index e9e9bb5..0369f3d 100644 --- a/yt_common/yt_common/config.py +++ b/yt_common/yt_common/config.py @@ -1,17 +1,20 @@ +from typing import Union + + class Config(): - epnum: int + desc: str title: str title_long: str resolution: int datapath: str - def __init__(self, epnum: int, title: str, title_long: str, resolution: int, datapath: str) -> None: - self.epnum = epnum + def __init__(self, desc: Union[int, str], title: str, title_long: str, resolution: int, datapath: str) -> None: + self.desc = desc if isinstance(desc, str) else f"{desc:02d}" self.title = title self.title_long = title_long self.resolution = resolution self.datapath = datapath def format_filename(self, filename: str) -> str: - return filename.format(epnum=self.epnum, title=self.title, + return filename.format(epnum=self.desc, title=self.title, title_long=self.title_long, resolution=self.resolution) diff --git a/yt_common/yt_common/source.py b/yt_common/yt_common/source.py index 172d2dd..c9bf9e2 100644 --- a/yt_common/yt_common/source.py +++ b/yt_common/yt_common/source.py @@ -17,11 +17,11 @@ from .logging import log core = vs.core -SUBSPLS_FILENAME: str = "[SubsPlease] {title_long} - {epnum:02d} ({resolution}p) [$GLOB].mkv" -ER_FILENAME: str = "[Erai-raws] {title_long} - {epnum:02d} [v0][{resolution}p]$GLOB.mkv" +SUBSPLS_FILENAME: str = "[SubsPlease] {title_long} - {epnum} ({resolution}p) [$GLOB].mkv" +ER_FILENAME: str = "[Erai-raws] {title_long} - {epnum} [v0][{resolution}p]$GLOB.mkv" FUNI_INTRO: int = 289 -AMAZON_FILENAME_CBR: str = "{title_long} - {epnum:02d} (Amazon Prime CBR {resolution}p).mkv" -AMAZON_FILENAME_VBR: str = "{title_long} - {epnum:02d} (Amazon Prime VBR {resolution}p).mkv" +AMAZON_FILENAME_CBR: str = "{title_long} - {epnum} (Amazon Prime CBR {resolution}p).mkv" +AMAZON_FILENAME_VBR: str = "{title_long} - {epnum} (Amazon Prime VBR {resolution}p).mkv" class FileTrim(NamedTuple):