点击关注我的Telegram群组和微信公众号

MENU

使用Python脚本批量混流适合Plex媒体服务器的MKV视频

2021 年 12 月 25 日 • 阅读: 3002 • 技术,分享

圣诞快乐!
这是今年最后一篇文章了
Github: Masterain98/Anime-MKV-Plex-Packager

前言

最近在维护NAS上的Plex媒体服务器时发现在刮削内容完成情况下,Plex依然对日本动画资源的读取有困难,故根据实际遇上的情况写了个Python脚本将所有需要包含的多媒体资源重新混流以达到让Plex顺利读取的目的。将整个过程记录下来供众人参考,也为以后debug做个文档准备。

遇到的问题

  • 字幕文件信息不全

    • 许多来自字幕组的中文字幕都包含简体中文chs和繁体中文cht两种语言格式。MVK的语言编码使用的是ISO-639-2,Plex额外采用了ISO-639-1`,但它们都没有区分简繁体
    • 在一部分字幕组自行压制的番剧系列中,可以观察到Plex读取到了简繁体信息,这是因为字幕组在MKV混流时为字幕所对应的轨道以简繁体设置了名称。而在压制组和字幕组合作的番剧中,ass字幕文件并没有被和正片一起混流所以不会被Plex识别,或者被识别成错误的语言。
    • 以鬼灭之刃为例,字幕为随包外挂的ass文件,在文件名相同的情况下Plex能成功读取但没有正确的语言信息
      鬼灭之刃外挂字幕
    • 而像 FSN HF3这样的剧场版,蓝光盘中的原生字幕在压制组混流时已经被添加,但字幕组外挂的ass字幕仍然无法被正确识别
      FSN HF3
  • 内封字幕的字体

    • 在一些字幕组的高端操作下ass字幕可以做出很好的特效,但这可能需要配合相对应的字幕。而字幕组一般会将字体打包以减少番剧主文件占用过多储存空间,当Plex系统不包含对应的字体文件就会出现问题,Plex将采用其默认样式来渲染字幕。因此需要将字体文件以附件的形式和MVK一起混流,经过测试以附件形式混流的字体文件将会被Plex识别并启用。
  • 附加音轨不会被识别

    • 和字幕文件类似的问题,附带的MKA音轨(可能是5.1音轨或评论轨)不会被Plex识别,需要将MKA文件随MKV一起混流

脚本

  • 思路很简单,列目录读MKV文件,读取相同名字的外挂音轨和字幕

    • 这得益于字幕组对文件命名的标准化
  • 解压字体压缩包并以附件的形式混流

    • 在写码的时候发现一些字体压缩包使用了GBK编码而不是UTF-8,可能是字幕组在打包时使用了百度网盘的自动压缩工具
  • 主要使用的库为pymkv,核心是随MKVToolNix一起的mkvmerge程序
  • 将原始媒体文件和字幕自动重命名或删除,防止Plex重复采用

import os
import shutil
import zipfile
from pymkv import MKVFile, MKVTrack
from pathlib import Path

# 设置项
DELETE_FONTS = True
DELETE_ORIGINAL_MKV = False
RENAME_ORIGINAL_MKV = True
DELETE_ORIGINAL_MKA = False
RENAME_ORIGINAL_MKA = True
DELETE_CHS_SUB = False
RENAME_CHS_SUB = True
DELETE_CHT_SUB = False
RENAME_CHT_SUB = True
SUFFIX_NAME = "_Plex"


# https://gist.github.com/hideaki-t/c42a16189dd5f88a955d
# 网上抄来的```GBK```解压代码,进行了部分修改以适应本脚本功能
def unzip(f, encoding):
    font_list = []
    with zipfile.ZipFile(f) as z:
        for i in z.namelist():
            font_list.append("Fonts/" + i.encode('cp437').decode(encoding))
            n = Path("Fonts/" + i.encode('cp437').decode(encoding))
            if i[-1] == '/':
                if not n.exists():
                    n.mkdir()
            else:
                with n.open('wb') as w:
                    w.write(z.read(i))
    return font_list


if __name__ == '__main__':
    if DELETE_ORIGINAL_MKV and RENAME_ORIGINAL_MKV:
        print("Rename MKV instead")
        DELETE_ORIGINAL_MKV = False
    if DELETE_ORIGINAL_MKA and RENAME_ORIGINAL_MKA:
        print("Rename MKA instead")
        DELETE_ORIGINAL_MKA = False
    if DELETE_CHS_SUB and RENAME_CHS_SUB:
        print("Rename CHS instead")
        DELETE_ORIGINAL_MKA = False
    if DELETE_CHT_SUB and RENAME_CHT_SUB:
        print("Rename CHT instead")
        DELETE_ORIGINAL_MKA = False
    delete_list = []
    rename_list = []

    # 解压字体包
    # 方法是找包含 Font 和 .zip 的关键词
    folder_list = os.listdir()
    font_list = []
    for file_name in folder_list:
        if "Font" in file_name and ".zip" in file_name:
            print("Find font package file: " + file_name)
            if not os.path.exists("Fonts"):
                os.makedirs("Fonts")
                print("Fonts sub-directory created")
            font_list = unzip(file_name, "GBK")
            print("Unzipped to /Fonts: " + str(font_list))
            print("=" * 20)

    # 主任务
    for file_name in folder_list:
        # .mkv 为番剧主文件
        if ".mkv" in file_name:
            episode_name = file_name.replace(".mkv", "")
            this_task = MKVFile(file_name)
            for item in folder_list:
                if episode_name in item:
                    if ".mkv" in item:
                        print("Find main video: " + item)
                        if DELETE_ORIGINAL_MKV:
                            delete_list.append(item)
                        if RENAME_ORIGINAL_MKV:
                            rename_list.append(item)
                    # 混流字幕文件
                    if ".ass" in item:
                        # 以 sc 和 chs 作为识别简中字幕的关键词
                        if "chs" in item or "sc" in item:
                            this_chs = MKVTrack(item, track_name="chs", default_track=True, language="chi")
                            this_task.add_track(this_chs)
                            print("Find associated CHS subtitle: " + item)
                            if DELETE_CHS_SUB:
                                delete_list.append(item)
                            if RENAME_CHS_SUB:
                                rename_list.append(item)
                        # 以 tc 和 cht 作为识别简中字幕的关键词
                        if "cht" in item or "tc" in item:
                            this_cht = MKVTrack(item, track_name="cht", default_track=False, language="chi")
                            this_task.add_track(this_cht)
                            print("Find associated CHT subtitle: " + item)
                            if DELETE_CHT_SUB:
                                delete_list.append(item)
                            if RENAME_CHT_SUB:
                                rename_list.append(item)
                    # 混流外挂音轨
                    if ".mka" in item:
                        this_task.add_track(item)
                        print("Find associated audio: " + item)
                        if DELETE_ORIGINAL_MKA:
                            delete_list.append(item)
                        if RENAME_ORIGINAL_MKA:
                            rename_list.append(item)
            for font in font_list:
                this_task.add_attachment(font)
            # 为新的混流文件设置一个包含专属后缀的文件名
            newMKV_name = episode_name + SUFFIX_NAME + ".mkv"
            this_task.mux(newMKV_name)
            print("=" * 20)

    # Clean up
    # 删除解压的字体目录和其它原始文件
    try:
        shutil.rmtree("Fonts/")
        print("Remove Fonts Folder Successfully")
    except:
        print("Remove Fonts Folder Error")
    for file in delete_list:
        try:
            os.remove(file)
        except:
            print("Failed to delete " + file)
    for file in rename_list:
        os.rename(file, file + ".bak")

    input("Task finished. Press any key to exit...")

运行示例

  • 以鬼灭之刃为例,脚本运行截图如下
    鬼灭之刃 脚本
  • 以FSN HF3为例,以下是在字体文件是否以附件混流情况下Plex播放时的效果

    • 当字体文件没有随媒体文件混流时

    无字体效果

    • 当字体文件随媒体文件混流时

    有字体效果

最后编辑于: 2022 年 01 月 10 日
返回文章列表 文章二维码 打赏
本页链接的二维码
打赏二维码