0

我想自动压缩我的电影。因此,我在 python 中编写了一个 mediainfo 包装类,以生成一个 xml 输出,然后我将其解析为一个带有音频和字幕轨道列表的 movieinfo 类。

__author__ = 'dominik'


class Error(Exception):
    """ Error class
    """


class ValidationError(Error):
    """ Invalid or missing xml items
    """


class MovieInfo(object):
    """ Description of movie file
    """

    def __init__(self, media_info):
        self._video_track = None
        self._audio_tracks = []
        self._subtitle_tracks = []
        self.valid_movie = True
        for track in media_info.tracks:
            if track.track_type == "Audio":
                self._audio_tracks.append(AudioTrack(track))
            elif track.track_type == "Text":
                self._subtitle_tracks.append(SubtitleTrack(track))
            elif track.track_type == "Video":
                self._video_track = VideoTrack(track)

    @property
    def audio_tracks(self):
        if not hasattr(self, "_audio_tracks"):
            self._audio_tracks = []
        if len(self._audio_tracks) != 0:
            return self._audio_tracks

    @property
    def subtitle_tracks(self):
        if not hasattr(self, "_subtitle_tracks"):
            self._subtitle_tracks = []
        if len(self._subtitle_tracks) != 0:
            return self._subtitle_tracks


class Track(object):
    """ Abstract track class for audio and subtitle tracks
    """

    __KNOWN_LANGUAGE_CODES = {"en": "ENG", "de": "DE"}

    def __init__(self, track, valid_codecs):
        self._valid = True
        track_id = int(track.id)
        codec_id = self._determine_codec(track.codec_id, valid_codecs)
        language = self._determine_language(track.language)

        self._id = track_id
        self._codec_id = codec_id
        self._language = language

    def _determine_codec(self, track_codec, types):
        result = types.get(track_codec, None)
        if result is None:
            self._valid = False
        return result

    def _determine_language(self, track_language, types=__KNOWN_LANGUAGE_CODES):
        result = types.get(track_language, None)
        if result is None:
            self._valid = False
        return result


class AudioTrack(Track):
    """ Audio track class
    """

    __KNOWN_AUDIO_CODECS = {"A_DTS": "DTS", "A_AC3": "AC3"}

    def __init__(self, track):
        self._type = 1
        Track.__init__(self, track, self.__KNOWN_AUDIO_CODECS)

class SubtitleTrack(Track):
    """ Subtitle track class
    """

    __KNOWN_SUBTITLE_CODECS = {"S_VOBSUB": "VOBSUB"}

    def __init__(self, track):
        self._type = 2
        if track.forced == "Yes":
            self._forced = True
        else:
            self._forced = False
        Track.__init__(self, track, self.__KNOWN_SUBTITLE_CODECS)


class VideoTrack(object):
    """ Video track class (only one video track in movie info!)
    """

    def __init__(self, track):
        self._type = 0
        self._framerate = float(track.frame_rate)
        self._width = track.width
        self._height = track.height

这是 mediainfo 类(它是 pymediainfo 类):

from subprocess import Popen
import os
from tempfile import mkstemp
from bs4 import BeautifulSoup, NavigableString
from setuptools.compat import unicode

class Track(object):
    """ Hold the track information
    """

    def __getattr__(self, item):
        try:
            return object.__getattribute__(self, item)
        except:
            pass
        return None

    def __init__(self, xml_track):
        self.xml_track = xml_track
        self.track_type = xml_track.attrs["type"]
        for child in self.xml_track.children:
            if not isinstance(child, NavigableString):
                node_name = child.name.lower().strip()
                node_value = unicode(child.string)
                node_other_name = "other_%s" % node_name
                if getattr(self, node_name) is None:
                    setattr(self, node_name, node_value)
                else:
                    if getattr(self, node_other_name) is None:
                        setattr(self, node_other_name, [node_value, ])
                    else:
                        getattr(self, node_other_name).append(node_value)

        for key in [c for c in self.__dict__.keys() if c.startswith("other_")]:
            try:
                primary = key.replace("other_", "")
                setattr(self, primary, int(getattr(self, primary)))
            except:
                for value in getattr(self, key):
                    try:
                        actual = getattr(self, primary)
                        setattr(self, primary, int(value))
                        getattr(self, key).append(actual)
                        break
                    except:
                        pass

    def __repr__(self):
        return("<Track id='{0}', type='{1}'>".format(self.id, self.track_type))

    def to_data(self):
        data = {}
        for k, v in self.__dict__.items():
            if k != 'xml_track':
                data[k] = v
        return data

class Mediainfo(object):
    """ MediaInfo wrapper
    """

    def __init__(self, xml):
        self.xml_dom = xml

        if isinstance(xml, str):
            self.xml_dom = BeautifulSoup(xml, "xml")

    def _populate_tracks(self):
        if self.xml_dom is None:
            return
        for xml_track in self.xml_dom.Mediainfo.File.find_all("track"):
            self._tracks.append(Track(xml_track))

    @property
    def tracks(self):
        if not hasattr(self, "_tracks"):
            self._tracks = []
        if len(self._tracks) == 0:
            self._populate_tracks()
        return self._tracks

    @staticmethod
    def parse(filename):
        filehandler_out, filename_out = mkstemp(".xml", "mediainfo-")
        filehandler_err, filename_err = mkstemp(".error", "mediainfo-")
        filepointer_out = os.fdopen(filehandler_out, "r+b")
        filepointer_err = os.fdopen(filehandler_err, "r+b")
        mediainfo_command = ["mediainfo", "-f", "--Output=XML", filename]
        p = Popen(mediainfo_command, stdout=filepointer_out, stderr=filepointer_err)
        p.wait()
        filepointer_out.seek(0)
        xml_dom = BeautifulSoup(filepointer_out.read(), "xml")

        filepointer_out.close()
        filepointer_err.close()
        print(xml_dom)
        return Mediainfo(xml_dom)


    def to_data(self):
        data = {'tracks': []}
        for track in self.tracks:
            data['tracks'].append(track.to_data())
        return data

这个类为我提供了 xml 中的每条轨道,然后我解析了 movieinfo 中的相关信息。

好的,现在我有一个音轨列表,例如 3 个音轨,一个是德语和 DTS,一个是德语和 AC3,一个是英语和 AC3。现在我想以“1,2,3”格式从轨道中获取ID,以将其提供给handbrake cli。

我的问题是曲目的顺序。如果有德国 DTS 曲目,这应该是第一首曲目,第二首曲目也应该是第一首,但压缩为 aac,第三首曲目应该是 AAC 中的一个英文曲目。如果只有德语 AC3 曲目,则第一首曲目应为该曲目但压缩为 AAC,第二首曲目应为英语和 AAC。我不知道我怎么能做到这一点,你能帮我吗?我是 python 新手,来自 C、C++ 和 C#。在 C# 中,使用 lambda 很容易做到这一点。

4

1 回答 1

0

假设您知道要定义一个比较器,给定两个项目可以定义哪个比 Python 函数以及 C 或 C++ 更大。

从这里开始 - 1. https://wiki.python.org/moin/HowTo/Sorting/

  1. https://developers.google.com/edu/python/sorting

  2. http://docs.python.org/2/library/functions.html#sorted

使用 sorted 方法并定义您想要的键。

于 2013-10-22T07:06:03.130 回答