Пример #1
0
	def replaceSubFileWith(input_file: Path, sub_file: Path, output_folder: Path):
		output_tmp1 = output_folder.joinpath(input_file.append_stem('_fxd_sub_tmp1').name)
		cmd = [
			'ffmpeg',
			'-y',
			'-i',
			F'{input_file}',
			'-map_metadata',
			'0',
			'-sn',
			'-c',
			'copy',
			F'{output_tmp1}'
		]
		common.run_process(cmd, silent=True)
		
		output_tmp = output_folder.joinpath(input_file.append_stem('_fxd_sub').name)
		cmd = [
			'ffmpeg',
			'-y',
			'-i',
			F'{output_tmp1}',
			'-i',
			F'{sub_file}',
			'-map_metadata',
			'0',
			'-c',
			'copy',
			F'{output_tmp}'
		]
		common.run_process(cmd, silent=True)
		output_tmp1.unlink()
		return output_tmp
Пример #2
0
class PyMergeMKVLinks():
    def __init__(self, args):
        self.args = args

        if self.args.re_encode:
            self.args.via_ffmpeg = True

        self.sourceFolder: Path = self.args.sourceDir[0]
        self.outputFolder: Path = self.args.destDir[0]
        self.outputFolder.mkdir(exist_ok=True)
        self.sourceFiles = self.generateFileList()
        if not len(self.sourceFiles):
            print(F"Found no files with segments in: {self.sourceFolder}")
            exit(1)
        self.tmpDir = Path("_unlink_temp/")
        self.tmpDir.mkdir(exist_ok=True)
        self.processFiles()

    def generateFileList(self):
        segs = {}
        for f in self.sourceFolder.listfiles():
            js = mkvstuff.mkvJson(f)
            if "properties" in js["container"]:
                segs[js["container"]["properties"]["segment_uid"]] = f
        return segs

    def processFiles(self):
        for i, (segmentUid, sourceFile) in enumerate(self.sourceFiles.items()):
            sourceFile: Path
            tmpOutDir = self.tmpDir.joinpath(str(i))
            if segments := mkvstuff.getChapterDict(sourceFile):
                if not len([x for x in segments.values() if x["segment_uid"]]):
                    self.plainCopy(sourceFile,
                                   self.outputFolder.joinpath(sourceFile.name))
                    continue
                tmpOutDir.mkdir(parents=True, exist_ok=True)
                if segmentList := self.buildSegmentList(
                        sourceFile, segments, tmpOutDir):
                    new_chapter = None
                    if self.args.chapters:
                        new_chapter = tmpOutDir.joinpath("new_chapter.xml")
                        with new_chapter.open('w', encoding='utf-8') as f:
                            f.write(
                                mkvstuff.segmentListToChapterFile(segmentList))
                    self.buildMkvFromSegments(segmentList,
                                              self.outputFolder.joinpath(
                                                  sourceFile.name),
                                              self.tmpDir.joinpath(str(i)),
                                              chapter=new_chapter)
Пример #3
0
    def buildSegmentList(self,
                         input_file: Path,
                         segmentList: dict,
                         outputDirectory: Path = None,
                         fullOutputDirectory: Path = None):
        if not outputDirectory and not fullOutputDirectory:
            raise Exception(
                "mergeSegmentsIntoFile requires either outputDirectory or fullOutputDirectory to be set"
            )

        split_times = []
        for i in sorted(segmentList.keys()):
            seg = segmentList[i]
            if seg["segment_uid"] is None and (
                    segmentList[i + 1]["segment_uid"] if
                (i + 1) < len(segmentList) else True):
                if "time_end" not in seg:
                    if i + 1 in segmentList:
                        split_times.append(
                            (i, segmentList[i + 1]["time_start"]))
                    elif i - 1 in segmentList and 'time_end' in segmentList[i -
                                                                            1]:
                        split_times.append((i, segmentList[i - 1]["time_end"]))
                else:
                    split_times.append((i, seg["time_end"]))
            else:
                if seg["segment_uid"] in self.sourceFiles:
                    if self.args.re_encode:
                        print(
                            F'Re-encoding {self.sourceFiles[seg["segment_uid"]]}'
                        )
                        segmentList[i]["file_path"] = mkvstuff.reEncodeFile(
                            self.sourceFiles[seg["segment_uid"]],
                            outputDirectory)
                    else:
                        segmentList[i]["file_path"] = self.sourceFiles[
                            seg["segment_uid"]]

        output_file: Path = None
        if fullOutputDirectory:
            output_file = fullOutputDirectory
        else:
            output_file = outputDirectory.joinpath(
                input_file.change_stem("parts").name)

        split_files = mkvstuff.splitFilesByTimeCodes(
            input_file,
            split_times,
            output_file,
            viaFfmpeg=self.args.via_ffmpeg,
            reEncode=self.args.re_encode)

        print(F"Files are: {','.join(str(x) for x in split_files)}")

        for i, seg in segmentList.items():
            if i in split_files:
                segmentList[i]["file_path"] = split_files[i]

        return segmentList
Пример #4
0
	def extract_chapter(input_file: Path, output_folder: Path = Path(".")) -> Path:
		cmd = ['mkvextract.exe']
		cmd.append(str(input_file))
		cmd.append('chapters')
		full_output_path = output_folder.joinpath(input_file.with_suffix(".xml").name)
		cmd.append(str(full_output_path))
		common.run_process(cmd, silent=True)
		return full_output_path
Пример #5
0
	def extract_first_subtitle(input_file: Path, output_folder: Path = None):
		output = input_file.change_suffix(".ass")
		if output_folder:
			output = output_folder.joinpath(input_file.change_suffix(".ass").name)
		cmd = [
			'ffmpeg',
			'-y',
			'-i',
			F'{input_file}',
			'-vn',
			'-an',
			F'{output}'
		]

		common.run_process(cmd, silent=True)
		return output
Пример #6
0
    def buildMkvFromSegments(self,
                             segmentList,
                             output_file: Path,
                             tmpDir: Path,
                             chapter=None):
        concat_file = Path("concat.txt")
        font_dir = tmpDir.joinpath("fonts")
        font_dir.mkdir(exist_ok=True)
        style_list = {}
        for i in sorted(segmentList.keys()):
            seg = segmentList[i]
            if 'file_path' not in seg:
                continue

            mkvstuff.ext_all_fonts_to_dir(seg['file_path'], font_dir)
            sub_file = mkvstuff.extract_first_subtitle(seg['file_path'],
                                                       tmpDir)

            sub_file = mkvstuff.suffixStyleNaming(
                sub_file, F"partid_{i}")  # silly double up

            for styleStr in mkvstuff.getStylesFromAssFile(sub_file):
                styleDict = mkvstuff.style_to_dict(styleStr)
                style_list[styleDict["name"]] = styleDict

            sub_file.unlink()

        for i in sorted(segmentList.keys()):
            seg = segmentList[i]
            if 'file_path' not in seg:
                continue
            _fixed_sub = mkvstuff.extract_first_subtitle(
                seg["file_path"], tmpDir)
            _fixed_sub = mkvstuff.suffixStyleNaming(
                _fixed_sub, F"partid_{i}"
            )  # silly double up, but too lazy to save in memory
            _fixed_sub = mkvstuff.replaceAssStylesWithList(
                _fixed_sub, style_list)
            _fixed_sub_mkv = mkvstuff.replaceSubFileWith(
                seg["file_path"], _fixed_sub, tmpDir)
            segmentList[i]["file_path"] = _fixed_sub_mkv

        with concat_file.open("w", encoding="utf-8") as f:
            for i in sorted(segmentList.keys()):
                seg = segmentList[i]
                if 'file_path' not in seg:
                    continue
                f.write(F"file '{seg['file_path']}'\n")

        _fixed_sub.unlink()

        output_file_tmp = output_file.append_stem('_tmp')

        cmd = [
            'ffmpeg',
            '-y',
            '-f',
            'concat',
            '-safe',
            '0',
            '-i',
            F'{concat_file}',
        ]

        if self.args.re_encode:
            cmd.append('-map')
            cmd.append('0')
            cmd.append('-g')
            cmd.append('1')
            cmd.append('-pix_fmt')
            cmd.append('yuv420p')
            cmd.append('-c:v')
            cmd.append('h264_nvenc')
            cmd.append('-c:a')
            cmd.append('pcm_s16le')
            cmd.append('-b:v')
            cmd.append('2M')
            cmd.append('-s')
            cmd.append('1280x720')
        else:
            cmd.append('-c')
            cmd.append('copy')
        cmd.append(F'{output_file_tmp}')

        fonts_list = mkvstuff.build_font_list(font_dir)

        print(
            F"Merging into{' (with re-encode)' if self.args.re_encode else ''}: {output_file_tmp}"
        )
        common.run_process(cmd, silent=True)
        concat_file.unlink()

        output_file = output_file.parent.joinpath(
            common.strip_crc(output_file.stem) + output_file.suffix)

        print(F"Merging (with chapter & fonts) into: {output_file}")
        cmd = [
            "mkvmerge",
            "--ui-language",
            "en",
            "--output",
            F"{output_file}",
            "(",
            F"{output_file_tmp}",
            ")",
        ]
        if chapter:
            cmd.extend([
                "--chapter-language",
                "eng",
                "--chapters",
                F"{chapter}",
            ])
        for font in fonts_list:
            cmd.extend([
                "--attachment-name", F"{font.name}", "--attachment-mime-type",
                F"{font.mime}", "--attach-file", F"{font.resolve()}"
            ])
        common.run_process(cmd, silent=True)
        output_file_tmp.unlink()
        print("\rCalculating and appending CRC-Sum...", end='')
        csum = common.crc32f(output_file)
        output_file.move(output_file.append_stem(F' [{csum}]'))
        print(F"\rCalculating and appending CRC-Sum, OK: {csum}")