merging tmdb und ffx complete crudest

click-textual
Javanaut 12 months ago
parent ce2f3993e1
commit e3115e7557

@ -228,8 +228,7 @@ def convert(ctx,
if cTokens and len(cTokens) == 2: if cTokens and len(cTokens) == 2:
context['crop_start'] = int(cTokens[0]) context['crop_start'] = int(cTokens[0])
context['crop_lenght'] = int(cTokens[1]) context['crop_lenght'] = int(cTokens[1])
click.echo(f"Crop start={context['crop_start']} length={context['crop_length']}")
click.echo(f"Crop start={context['crop_start']} length={context['crop_length']}")
# ## Conversion parameters # ## Conversion parameters
@ -304,6 +303,9 @@ def convert(ctx,
forcedSubtitleTrackSubIndex = click.prompt("More than one forced subtitle stream detected! Please select stream", type=int) forcedSubtitleTrackSubIndex = click.prompt("More than one forced subtitle stream detected! Please select stream", type=int)
sourceMediaDescriptor.setForcedSubTrack(TrackType.SUBTITLE, forcedSubtitleTrackSubIndex) sourceMediaDescriptor.setForcedSubTrack(TrackType.SUBTITLE, forcedSubtitleTrackSubIndex)
if context['import_subtitles']:
sourceMediaDescriptor.importSubtitles(context['subtitle_directory'], context['subtitle_prefix'])
fc = FfxController(context, sourceMediaDescriptor) fc = FfxController(context, sourceMediaDescriptor)
# mappingTokens = fc.generateMetadataTokens() # mappingTokens = fc.generateMetadataTokens()
@ -315,9 +317,6 @@ def convert(ctx,
audioTokens = fc.generateAudioEncodingTokens() audioTokens = fc.generateAudioEncodingTokens()
click.echo(f"Audio Tokens: {audioTokens}") click.echo(f"Audio Tokens: {audioTokens}")
audioTokens = fc
click.echo(f"Audio Tokens: {audioTokens}")
else: else:
# Case pattern matching # Case pattern matching

@ -8,7 +8,7 @@ from ffx.audio_layout import AudioLayout
from ffx.track_type import TrackType from ffx.track_type import TrackType
from ffx.video_encoder import VideoEncoder from ffx.video_encoder import VideoEncoder
from ffx.process import executeProcess from ffx.process import executeProcess
from ffx.file_properties import FileProperties
class FfxController(): class FfxController():
@ -360,7 +360,7 @@ class FfxController():
if videoEncoder == VideoEncoder.AV1: if videoEncoder == VideoEncoder.AV1:
commandSequence = (commandTokens commandSequence = (commandTokens
#+ subtitleImportFileTokens + self.__targetMediaDescriptor.getImportFileTokens()
+ self.__targetMediaDescriptor.getInputMappingTokens() + self.__targetMediaDescriptor.getInputMappingTokens()
+ self.generateDispositionTokens()) + self.generateDispositionTokens())
@ -404,7 +404,7 @@ class FfxController():
executeProcess(commandSequence1) executeProcess(commandSequence1)
commandSequence2 = (commandTokens commandSequence2 = (commandTokens
#+ subtitleImportFileTokens + self.__targetMediaDescriptor.getImportFileTokens()
+ self.__targetMediaDescriptor.getInputMappingTokens() + self.__targetMediaDescriptor.getInputMappingTokens()
+ self.generateDispositionTokens()) + self.generateDispositionTokens())

@ -17,9 +17,6 @@ class FileProperties():
SEASON_EPISODE_INDICATOR_MATCH = '[sS]([0-9]+)[eE]([0-9]+)' SEASON_EPISODE_INDICATOR_MATCH = '[sS]([0-9]+)[eE]([0-9]+)'
EPISODE_INDICATOR_MATCH = '[eE]([0-9]+)' EPISODE_INDICATOR_MATCH = '[eE]([0-9]+)'
SEASON_EPISODE_STREAM_LANGUAGE_MATCH = '[sS]([0-9]+)[eE]([0-9]+)_([0-9]+)_([a-z]{3})'
SUBTITLE_FILE_EXTENSION = 'vtt'
DEFAULT_INDEX_DIGITS = 3 DEFAULT_INDEX_DIGITS = 3
def __init__(self, context, sourcePath): def __init__(self, context, sourcePath):

@ -1,118 +1,174 @@
import os, re, click import os
import re
import click
from typing import List, Self from typing import List, Self
from ffx.track_type import TrackType from ffx.track_type import TrackType
from ffx.track_disposition import TrackDisposition from ffx.track_disposition import TrackDisposition
from ffx.file_properties import FileProperties
from ffx.track_descriptor import TrackDescriptor from ffx.track_descriptor import TrackDescriptor
from ffx.helper import dictDiff, DIFF_ADDED_KEY, DIFF_CHANGED_KEY, DIFF_REMOVED_KEY from ffx.helper import dictDiff, DIFF_ADDED_KEY, DIFF_CHANGED_KEY, DIFF_REMOVED_KEY
class MediaDescriptor(): class MediaDescriptor:
"""This class represents the structural content of a media file including streams and metadata""" """This class represents the structural content of a media file including streams and metadata"""
CONTEXT_KEY = 'context' CONTEXT_KEY = "context"
TAGS_KEY = 'tags' TAGS_KEY = "tags"
TRACKS_KEY = 'tracks' TRACKS_KEY = "tracks"
TRACK_DESCRIPTOR_LIST_KEY = 'track_descriptors' TRACK_DESCRIPTOR_LIST_KEY = "track_descriptors"
CLEAR_TAGS_FLAG_KEY = 'clear_tags' CLEAR_TAGS_FLAG_KEY = "clear_tags"
FFPROBE_DISPOSITION_KEY = 'disposition' FFPROBE_DISPOSITION_KEY = "disposition"
FFPROBE_TAGS_KEY = 'tags' FFPROBE_TAGS_KEY = "tags"
FFPROBE_CODEC_TYPE_KEY = 'codec_type' FFPROBE_CODEC_TYPE_KEY = "codec_type"
JELLYFIN_ORDER_FLAG_KEY = 'jellyfin_order' JELLYFIN_ORDER_FLAG_KEY = "jellyfin_order"
EXCLUDED_MEDIA_TAGS = [ EXCLUDED_MEDIA_TAGS = ["creation_time"]
'creation_time'
] SEASON_EPISODE_STREAM_LANGUAGE_MATCH = '[sS]([0-9]+)[eE]([0-9]+)_([0-9]+)_([a-z]{3})'
SUBTITLE_FILE_EXTENSION = 'vtt'
def __init__(self, **kwargs): def __init__(self, **kwargs):
if MediaDescriptor.TAGS_KEY in kwargs.keys(): if MediaDescriptor.TAGS_KEY in kwargs.keys():
if type(kwargs[MediaDescriptor.TAGS_KEY]) is not dict: if type(kwargs[MediaDescriptor.TAGS_KEY]) is not dict:
raise TypeError(f"MediaDescriptor.__init__(): Argument {MediaDescriptor.TAGS_KEY} is required to be of type dict") raise TypeError(
self.__mediaTags = kwargs[MediaDescriptor.TAGS_KEY] f"MediaDescriptor.__init__(): Argument {
MediaDescriptor.TAGS_KEY} is required to be of type dict"
)
self.__mediaTags = kwargs[MediaDescriptor.TAGS_KEY]
else: else:
self.__mediaTags = {} self.__mediaTags = {}
if MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY in kwargs.keys(): if MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY in kwargs.keys():
if type(kwargs[MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY]) is not list: # Use List typehint for TrackDescriptor as well if it works if (
raise TypeError(f"MediaDescriptor.__init__(): Argument {MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY} is required to be of type list") type(kwargs[MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY]) is not list
for d in kwargs[MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY]: ): # Use List typehint for TrackDescriptor as well if it works
if type(d) is not TrackDescriptor: raise TypeError(
raise TypeError(f"TrackDesciptor.__init__(): All elements of argument list {MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY} are required to be of type TrackDescriptor") f"MediaDescriptor.__init__(): Argument {
self.__trackDescriptors = kwargs[MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY] MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY} is required to be of type list"
)
for d in kwargs[MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY]:
if type(d) is not TrackDescriptor:
raise TypeError(
f"TrackDesciptor.__init__(): All elements of argument list {
MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY} are required to be of type TrackDescriptor"
)
self.__trackDescriptors = kwargs[MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY]
else: else:
self.__trackDescriptors = [] self.__trackDescriptors = []
if MediaDescriptor.CLEAR_TAGS_FLAG_KEY in kwargs.keys(): if MediaDescriptor.CLEAR_TAGS_FLAG_KEY in kwargs.keys():
if type(kwargs[MediaDescriptor.CLEAR_TAGS_FLAG_KEY]) is not bool: if type(kwargs[MediaDescriptor.CLEAR_TAGS_FLAG_KEY]) is not bool:
raise TypeError(f"MediaDescriptor.__init__(): Argument {MediaDescriptor.CLEAR_TAGS_FLAG_KEY} is required to be of type bool") raise TypeError(
self.__clearTags = kwargs[MediaDescriptor.CLEAR_TAGS_FLAG_KEY] f"MediaDescriptor.__init__(): Argument {
MediaDescriptor.CLEAR_TAGS_FLAG_KEY} is required to be of type bool"
)
self.__clearTags = kwargs[MediaDescriptor.CLEAR_TAGS_FLAG_KEY]
else: else:
self.__clearTags = False self.__clearTags = False
if MediaDescriptor.JELLYFIN_ORDER_FLAG_KEY in kwargs.keys(): if MediaDescriptor.JELLYFIN_ORDER_FLAG_KEY in kwargs.keys():
if type(kwargs[MediaDescriptor.JELLYFIN_ORDER_FLAG_KEY]) is not bool: if type(kwargs[MediaDescriptor.JELLYFIN_ORDER_FLAG_KEY]) is not bool:
raise TypeError(f"MediaDescriptor.__init__(): Argument {MediaDescriptor.JELLYFIN_ORDER_FLAG_KEY} is required to be of type bool") raise TypeError(
self.__jellyfinOrder = kwargs[MediaDescriptor.JELLYFIN_ORDER_FLAG_KEY] f"MediaDescriptor.__init__(): Argument {
MediaDescriptor.JELLYFIN_ORDER_FLAG_KEY} is required to be of type bool"
)
self.__jellyfinOrder = kwargs[MediaDescriptor.JELLYFIN_ORDER_FLAG_KEY]
else: else:
self.__jellyfinOrder = False self.__jellyfinOrder = False
def getDefaultVideoTrack(self): def getDefaultVideoTrack(self):
videoDefaultTracks = [v for v in self.getVideoTracks() if TrackDisposition.DEFAULT in v.getDispositionSet()] videoDefaultTracks = [
v
for v in self.getVideoTracks()
if TrackDisposition.DEFAULT in v.getDispositionSet()
]
if len(videoDefaultTracks) > 1: if len(videoDefaultTracks) > 1:
raise ValueError('MediaDescriptor.getDefaultVideoTrack(): More than one default video track is not supported') raise ValueError(
"MediaDescriptor.getDefaultVideoTrack(): More than one default video track is not supported"
)
return videoDefaultTracks[0] if videoDefaultTracks else None return videoDefaultTracks[0] if videoDefaultTracks else None
def getForcedVideoTrack(self): def getForcedVideoTrack(self):
videoForcedTracks = [v for v in self.getVideoTracks() if TrackDisposition.FORCED in v.getDispositionSet()] videoForcedTracks = [
v
for v in self.getVideoTracks()
if TrackDisposition.FORCED in v.getDispositionSet()
]
if len(videoForcedTracks) > 1: if len(videoForcedTracks) > 1:
raise ValueError('MediaDescriptor.getForcedVideoTrack(): More than one forced video track is not supported') raise ValueError(
"MediaDescriptor.getForcedVideoTrack(): More than one forced video track is not supported"
)
return videoForcedTracks[0] if videoForcedTracks else None return videoForcedTracks[0] if videoForcedTracks else None
def getDefaultAudioTrack(self): def getDefaultAudioTrack(self):
audioDefaultTracks = [a for a in self.getAudioTracks() if TrackDisposition.DEFAULT in a.getDispositionSet()] audioDefaultTracks = [
a
for a in self.getAudioTracks()
if TrackDisposition.DEFAULT in a.getDispositionSet()
]
if len(audioDefaultTracks) > 1: if len(audioDefaultTracks) > 1:
raise ValueError('MediaDescriptor.getDefaultAudioTrack(): More than one default audio track is not supported') raise ValueError(
"MediaDescriptor.getDefaultAudioTrack(): More than one default audio track is not supported"
)
return audioDefaultTracks[0] if audioDefaultTracks else None return audioDefaultTracks[0] if audioDefaultTracks else None
def getForcedAudioTrack(self): def getForcedAudioTrack(self):
audioForcedTracks = [a for a in self.getAudioTracks() if TrackDisposition.FORCED in a.getDispositionSet()] audioForcedTracks = [
a
for a in self.getAudioTracks()
if TrackDisposition.FORCED in a.getDispositionSet()
]
if len(audioForcedTracks) > 1: if len(audioForcedTracks) > 1:
raise ValueError('MediaDescriptor.getForcedAudioTrack(): More than one forced audio track is not supported') raise ValueError(
"MediaDescriptor.getForcedAudioTrack(): More than one forced audio track is not supported"
)
return audioForcedTracks[0] if audioForcedTracks else None return audioForcedTracks[0] if audioForcedTracks else None
def getDefaultSubtitleTrack(self): def getDefaultSubtitleTrack(self):
subtitleDefaultTracks = [s for s in self.getSubtitleTracks() if TrackDisposition.DEFAULT in s.getDispositionSet()] subtitleDefaultTracks = [
s
for s in self.getSubtitleTracks()
if TrackDisposition.DEFAULT in s.getDispositionSet()
]
if len(subtitleDefaultTracks) > 1: if len(subtitleDefaultTracks) > 1:
raise ValueError('MediaDescriptor.getDefaultSubtitleTrack(): More than one default subtitle track is not supported') raise ValueError(
"MediaDescriptor.getDefaultSubtitleTrack(): More than one default subtitle track is not supported"
)
return subtitleDefaultTracks[0] if subtitleDefaultTracks else None return subtitleDefaultTracks[0] if subtitleDefaultTracks else None
def getForcedSubtitleTrack(self): def getForcedSubtitleTrack(self):
subtitleForcedTracks = [s for s in self.getSubtitleTracks() if TrackDisposition.FORCED in s.getDispositionSet()] subtitleForcedTracks = [
s
for s in self.getSubtitleTracks()
if TrackDisposition.FORCED in s.getDispositionSet()
]
if len(subtitleForcedTracks) > 1: if len(subtitleForcedTracks) > 1:
raise ValueError('MediaDescriptor.getForcedSubtitleTrack(): More than one forced subtitle track is not supported') raise ValueError(
"MediaDescriptor.getForcedSubtitleTrack(): More than one forced subtitle track is not supported"
)
return subtitleForcedTracks[0] if subtitleForcedTracks else None return subtitleForcedTracks[0] if subtitleForcedTracks else None
def setDefaultSubTrack(self, trackType: TrackType, subIndex: int):
def setDefaultSubTrack(self, trackType : TrackType, subIndex : int):
for t in self.getAllTrackDescriptors(): for t in self.getAllTrackDescriptors():
if t.getType() == trackType: if t.getType() == trackType:
t.setDispositionFlag(TrackDisposition.DEFAULT, t.getSubIndex() == int(subIndex)) t.setDispositionFlag(
TrackDisposition.DEFAULT, t.getSubIndex() == int(subIndex)
)
def setForcedSubTrack(self, trackType : TrackType, subIndex : int): def setForcedSubTrack(self, trackType: TrackType, subIndex: int):
for t in self.getAllTrackDescriptors(): for t in self.getAllTrackDescriptors():
if t.getType() == trackType: if t.getType() == trackType:
t.setDispositionFlag(TrackDisposition.FORCED, t.getSubIndex() == int(subIndex)) t.setDispositionFlag(
TrackDisposition.FORCED, t.getSubIndex() == int(subIndex)
)
def getReorderedTrackDescriptors(self): def getReorderedTrackDescriptors(self):
@ -129,32 +185,43 @@ class MediaDescriptor():
if self.__jellyfinOrder: if self.__jellyfinOrder:
if not videoDefaultTrack is None: if not videoDefaultTrack is None:
videoTracks.append(videoTracks.pop(videoTracks.index(videoDefaultTrack))) videoTracks.append(
videoTracks.pop(videoTracks.index(videoDefaultTrack))
)
if not audioDefaultTrack is None: if not audioDefaultTrack is None:
audioTracks.append(audioTracks.pop(audioTracks.index(audioDefaultTrack))) audioTracks.append(
audioTracks.pop(audioTracks.index(audioDefaultTrack))
)
if not subtitleDefaultTrack is None: if not subtitleDefaultTrack is None:
subtitleTracks.append(subtitleTracks.pop(subtitleTracks.index(subtitleDefaultTrack))) subtitleTracks.append(
subtitleTracks.pop(subtitleTracks.index(subtitleDefaultTrack))
)
reorderedTrackDescriptors = videoTracks + audioTracks + subtitleTracks reorderedTrackDescriptors = videoTracks + audioTracks + subtitleTracks
orderedSourceTrackSequence = [t.getSourceIndex() for t in reorderedTrackDescriptors] orderedSourceTrackSequence = [
t.getSourceIndex() for t in reorderedTrackDescriptors
]
if len(set(orderedSourceTrackSequence)) < len(orderedSourceTrackSequence): if len(set(orderedSourceTrackSequence)) < len(orderedSourceTrackSequence):
raise ValueError(f"Multiple streams originating from the same source stream not supported") raise ValueError(
f"Multiple streams originating from the same source stream not supported"
)
return reorderedTrackDescriptors return reorderedTrackDescriptors
@classmethod @classmethod
def fromFfprobe(cls, formatData, streamData): def fromFfprobe(cls, formatData, streamData):
kwargs = {} kwargs = {}
if MediaDescriptor.FFPROBE_TAGS_KEY in formatData.keys(): if MediaDescriptor.FFPROBE_TAGS_KEY in formatData.keys():
kwargs[MediaDescriptor.TAGS_KEY] = formatData[MediaDescriptor.FFPROBE_TAGS_KEY] kwargs[MediaDescriptor.TAGS_KEY] = formatData[
MediaDescriptor.FFPROBE_TAGS_KEY
]
kwargs[MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY] = [] kwargs[MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY] = []
#TODO: Evtl obsolet # TODO: Evtl obsolet
subIndexCounters = {} subIndexCounters = {}
for streamObj in streamData: for streamObj in streamData:
@ -165,40 +232,48 @@ class MediaDescriptor():
if trackType != TrackType.UNKNOWN: if trackType != TrackType.UNKNOWN:
if trackType not in subIndexCounters.keys(): if trackType not in subIndexCounters.keys():
subIndexCounters[trackType] = 0 subIndexCounters[trackType] = 0
kwargs[MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY].append(TrackDescriptor.fromFfprobe(streamObj, kwargs[MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY].append(
subIndex=subIndexCounters[trackType])) TrackDescriptor.fromFfprobe(
streamObj, subIndex=subIndexCounters[trackType]
)
)
subIndexCounters[trackType] += 1 subIndexCounters[trackType] += 1
return cls(**kwargs) return cls(**kwargs)
def getTags(self): def getTags(self):
return self.__mediaTags return self.__mediaTags
def sortSubIndices(
def sortSubIndices(self, descriptors : List[TrackDescriptor]) -> List[TrackDescriptor]: self, descriptors: List[TrackDescriptor]
) -> List[TrackDescriptor]:
subIndex = 0 subIndex = 0
for t in descriptors: for t in descriptors:
t.setSubIndex(subIndex) t.setSubIndex(subIndex)
subIndex += 1 subIndex += 1
return descriptors return descriptors
def getAllTrackDescriptors(self) -> List[TrackDescriptor]: def getAllTrackDescriptors(self) -> List[TrackDescriptor]:
return self.getVideoTracks() + self.getAudioTracks() + self.getSubtitleTracks() return self.getVideoTracks() + self.getAudioTracks() + self.getSubtitleTracks()
def getVideoTracks(self) -> List[TrackDescriptor]: def getVideoTracks(self) -> List[TrackDescriptor]:
return [v for v in self.__trackDescriptors.copy() if v.getType() == TrackType.VIDEO] return [
v for v in self.__trackDescriptors.copy() if v.getType() == TrackType.VIDEO
]
def getAudioTracks(self) -> List[TrackDescriptor]: def getAudioTracks(self) -> List[TrackDescriptor]:
return [a for a in self.__trackDescriptors.copy() if a.getType() == TrackType.AUDIO] return [
a for a in self.__trackDescriptors.copy() if a.getType() == TrackType.AUDIO
]
def getSubtitleTracks(self) -> List[TrackDescriptor]: def getSubtitleTracks(self) -> List[TrackDescriptor]:
return [s for s in self.__trackDescriptors.copy() if s.getType() == TrackType.SUBTITLE] return [
s
for s in self.__trackDescriptors.copy()
if s.getType() == TrackType.SUBTITLE
]
def getJellyfin(self): def getJellyfin(self):
return self.__jellyfinOrder return self.__jellyfinOrder
@ -209,33 +284,33 @@ class MediaDescriptor():
def getClearTags(self): def getClearTags(self):
return self.__clearTags return self.__clearTags
def compare(self, vsMediaDescriptor: Self):
def compare(self, vsMediaDescriptor : Self):
if not isinstance(vsMediaDescriptor, self.__class__): if not isinstance(vsMediaDescriptor, self.__class__):
raise click.ClickException(f"MediaDescriptor.compare(): Argument is required to be of type {self.__class__}") raise click.ClickException(
f"MediaDescriptor.compare(): Argument is required to be of type {
self.__class__}"
)
vsTags = vsMediaDescriptor.getTags() vsTags = vsMediaDescriptor.getTags()
tags = self.getTags() tags = self.getTags()
#HINT: Some tags differ per file, for example creation_time, so these are removed before diff # HINT: Some tags differ per file, for example creation_time, so these are removed before diff
for emt in MediaDescriptor.EXCLUDED_MEDIA_TAGS: for emt in MediaDescriptor.EXCLUDED_MEDIA_TAGS:
if emt in tags.keys(): if emt in tags.keys():
del tags[emt] del tags[emt]
if emt in vsTags.keys(): if emt in vsTags.keys():
del vsTags[emt] del vsTags[emt]
tagsDiff = dictDiff(vsTags, tags) tagsDiff = dictDiff(vsTags, tags)
compareResult = {} compareResult = {}
if tagsDiff: if tagsDiff:
compareResult[MediaDescriptor.TAGS_KEY] = tagsDiff compareResult[MediaDescriptor.TAGS_KEY] = tagsDiff
# Target track configuration (from DB) # Target track configuration (from DB)
#tracks = self.getAllTrackDescriptors() # tracks = self.getAllTrackDescriptors()
tracks = self.getReorderedTrackDescriptors() tracks = self.getReorderedTrackDescriptors()
numTracks = len(tracks) numTracks = len(tracks)
@ -245,95 +320,154 @@ class MediaDescriptor():
maxNumOfTracks = max(numVsTracks, numTracks) maxNumOfTracks = max(numVsTracks, numTracks)
trackCompareResult = {} trackCompareResult = {}
for tp in range(maxNumOfTracks): for tp in range(maxNumOfTracks):
# inspect/update funktionier nur so # inspect/update funktionier nur so
if self.__jellyfinOrder: if self.__jellyfinOrder:
vsTrackIndex = tracks[tp].getSourceIndex() vsTrackIndex = tracks[tp].getSourceIndex()
else: else:
vsTrackIndex = tp vsTrackIndex = tp
# vsTrackIndex = tracks[tp].getSourceIndex() # vsTrackIndex = tracks[tp].getSourceIndex()
# Will trigger if tracks are missing in file # Will trigger if tracks are missing in file
if tp > (numVsTracks - 1): if tp > (numVsTracks - 1):
if DIFF_ADDED_KEY not in trackCompareResult.keys(): if DIFF_ADDED_KEY not in trackCompareResult.keys():
trackCompareResult[DIFF_ADDED_KEY] = set() trackCompareResult[DIFF_ADDED_KEY] = set()
trackCompareResult[DIFF_ADDED_KEY].add(tracks[tp].getIndex()) trackCompareResult[DIFF_ADDED_KEY].add(tracks[tp].getIndex())
continue continue
# Will trigger if tracks are missing in DB definition # Will trigger if tracks are missing in DB definition
# New tracks will be added per update via this way # New tracks will be added per update via this way
if tp > (numTracks - 1): if tp > (numTracks - 1):
if DIFF_REMOVED_KEY not in trackCompareResult.keys(): if DIFF_REMOVED_KEY not in trackCompareResult.keys():
trackCompareResult[DIFF_REMOVED_KEY] = {} trackCompareResult[DIFF_REMOVED_KEY] = {}
trackCompareResult[DIFF_REMOVED_KEY][vsTracks[vsTrackIndex].getIndex()] = vsTracks[vsTrackIndex] trackCompareResult[DIFF_REMOVED_KEY][
continue vsTracks[vsTrackIndex].getIndex()
] = vsTracks[vsTrackIndex]
# assumption is made here that the track order will not change for all files of a sequence continue
trackDiff = tracks[tp].compare(vsTracks[vsTrackIndex])
# assumption is made here that the track order will not change for all files of a sequence
if trackDiff: trackDiff = tracks[tp].compare(vsTracks[vsTrackIndex])
if DIFF_CHANGED_KEY not in trackCompareResult.keys():
trackCompareResult[DIFF_CHANGED_KEY] = {} if trackDiff:
trackCompareResult[DIFF_CHANGED_KEY][vsTracks[vsTrackIndex].getIndex()] = trackDiff if DIFF_CHANGED_KEY not in trackCompareResult.keys():
trackCompareResult[DIFF_CHANGED_KEY] = {}
trackCompareResult[DIFF_CHANGED_KEY][
vsTracks[vsTrackIndex].getIndex()
] = trackDiff
if trackCompareResult: if trackCompareResult:
compareResult[MediaDescriptor.TRACKS_KEY] = trackCompareResult compareResult[MediaDescriptor.TRACKS_KEY] = trackCompareResult
return compareResult return compareResult
def getImportFileTokens(self, use_sub_index: bool = True):
reorderedTrackDescriptors = self.getReorderedTrackDescriptors()
importFileTokens = []
for rtd in reorderedTrackDescriptors:
importedFilePath = rtd.getExternalSourceFilePath()
def getInputMappingTokens(self, use_sub_index : bool = True): if not importedFilePath is None:
importFileTokens += [
"-i",
importedFilePath,
]
return importFileTokens
def getInputMappingTokens(self, use_sub_index: bool = True):
reorderedTrackDescriptors = self.getReorderedTrackDescriptors() reorderedTrackDescriptors = self.getReorderedTrackDescriptors()
inputMappingTokens = [] inputMappingTokens = []
filePointer = 1
for rtd in reorderedTrackDescriptors: for rtd in reorderedTrackDescriptors:
trackType = rtd.getType()
if use_sub_index:
inputMappingTokens += ['-map', f"0:{trackType.indicator()}:{rtd.getSubIndex()}"]
else:
inputMappingTokens += ['-map', f"0:{rtd.getIndex()}"]
return inputMappingTokens
importedFilePath = rtd.getExternalSourceFilePath()
# matchingFileSubtitleDescriptors = sorted([d for d in availableFileSubtitleDescriptors if d['season'] == season and d['episode'] == episode], key=lambda d: d['stream']) if availableFileSubtitleDescriptors else [] trackType = rtd.getType()
if use_sub_index:
if importedFilePath is None:
inputMappingTokens += [
"-map",
f"0:{trackType.indicator()}:{rtd.getSubIndex()}",
]
else:
inputMappingTokens += [
"-map",
f"{filePointer}:{trackType.indicator()}:0",
]
filePointer += 1
else:
inputMappingTokens += ["-map", f"0:{rtd.getIndex()}"]
return inputMappingTokens
def searchSubtitleFiles(searchDirectory, prefix): def searchSubtitleFiles(searchDirectory, prefix):
sesl_match = re.compile(FileProperties.SEASON_EPISODE_STREAM_LANGUAGE_MATCH) sesl_match = re.compile(MediaDescriptor.SEASON_EPISODE_STREAM_LANGUAGE_MATCH)
availableFileSubtitleDescriptors = [] availableFileSubtitleDescriptors = []
for subtitleFilename in os.listdir(searchDirectory): for subtitleFilename in os.listdir(searchDirectory):
if subtitleFilename.startswith(prefix) and subtitleFilename.endswith('.' + FileProperties.SUBTITLE_FILE_EXTENSION): if subtitleFilename.startswith(prefix) and subtitleFilename.endswith(
"." + MediaDescriptor.SUBTITLE_FILE_EXTENSION
):
sesl_result = sesl_match.search(subtitleFilename) sesl_result = sesl_match.search(subtitleFilename)
if sesl_result is not None: if sesl_result is not None:
subtitleFilePath = os.path.join(searchDirectory, subtitleFilename) subtitleFilePath = os.path.join(searchDirectory, subtitleFilename)
if os.path.isfile(subtitleFilePath): if os.path.isfile(subtitleFilePath):
subtitleFileDescriptor = {} subtitleFileDescriptor = {}
subtitleFileDescriptor['path'] = subtitleFilePath subtitleFileDescriptor["path"] = subtitleFilePath
subtitleFileDescriptor['season'] = int(sesl_result.group(1)) subtitleFileDescriptor["season"] = int(sesl_result.group(1))
subtitleFileDescriptor['episode'] = int(sesl_result.group(2)) subtitleFileDescriptor["episode"] = int(sesl_result.group(2))
subtitleFileDescriptor['stream'] = int(sesl_result.group(3)) subtitleFileDescriptor["stream"] = int(sesl_result.group(3))
subtitleFileDescriptor['language'] = sesl_result.group(4) subtitleFileDescriptor["language"] = sesl_result.group(4)
availableFileSubtitleDescriptors.append(subtitleFileDescriptor) availableFileSubtitleDescriptors.append(subtitleFileDescriptor)
click.echo(f"Found {len(availableFileSubtitleDescriptors)} subtitles in files\n") click.echo(
f"Found {len(availableFileSubtitleDescriptors)} subtitles in files\n"
)
return availableFileSubtitleDescriptors return availableFileSubtitleDescriptors
def importSubtitles(
def importSubtitles(self, searchDirectory, prefix): self, searchDirectory, prefix, season: int = -1, episode: int = -1
):
availableFileSubtitleDescriptors = self.searchSubtitleFiles(searchDirectory, prefix)
availableFileSubtitleDescriptors = self.searchSubtitleFiles(
if len(availableFileSubtitleDescriptors) != len(self.getSubtitleTracks()): searchDirectory, prefix
raise click.ClickException(f"MediaDescriptor.importSubtitles(): Number if subtitle files not matching number of subtitle tracks") )
subtitleTracks = self.getSubtitleTracks()
# if len(availableFileSubtitleDescriptors) != len(subtitleTracks):
# raise click.ClickException(f"MediaDescriptor.importSubtitles(): Number if subtitle files not matching number of subtitle tracks")
matchingFileSubtitleDescriptors = (
sorted(
[
d
for d in availableFileSubtitleDescriptors
if d["season"] == int(season) and d["episode"] == int(episode)
],
key=lambda d: d["stream"],
)
if availableFileSubtitleDescriptors
else []
)
for mfsd in matchingFileSubtitleDescriptors:
matchingSubtitleTrackDescriptor = [
s for s in subtitleTracks if s.getIndex() == mfsd["stream"]
]
if matchingSubtitleTrackDescriptor:
matchingSubtitleTrackDescriptor[0].setExternalSourceFilePath(
mfsd["path"]
)

@ -8,227 +8,287 @@ from .track_disposition import TrackDisposition
from .helper import dictDiff, setDiff from .helper import dictDiff, setDiff
class TrackDescriptor(): class TrackDescriptor:
ID_KEY = 'id' ID_KEY = "id"
INDEX_KEY = 'index' INDEX_KEY = "index"
SOURCE_INDEX_KEY = 'source_index' SOURCE_INDEX_KEY = "source_index"
SUB_INDEX_KEY = 'sub_index' SUB_INDEX_KEY = "sub_index"
PATTERN_ID_KEY = 'pattern_id' PATTERN_ID_KEY = "pattern_id"
EXTERNAL_SOURCE_FILE_PATH_KEY = "external_source_file"
DISPOSITION_SET_KEY = 'disposition_set'
TAGS_KEY = 'tags' DISPOSITION_SET_KEY = "disposition_set"
TAGS_KEY = "tags"
TRACK_TYPE_KEY = 'track_type'
AUDIO_LAYOUT_KEY = 'audio_layout' TRACK_TYPE_KEY = "track_type"
AUDIO_LAYOUT_KEY = "audio_layout"
FFPROBE_INDEX_KEY = 'index'
FFPROBE_DISPOSITION_KEY = 'disposition' FFPROBE_INDEX_KEY = "index"
FFPROBE_TAGS_KEY = 'tags' FFPROBE_DISPOSITION_KEY = "disposition"
FFPROBE_CODEC_TYPE_KEY = 'codec_type' FFPROBE_TAGS_KEY = "tags"
FFPROBE_CODEC_TYPE_KEY = "codec_type"
def __init__(self, **kwargs):
def __init__(self, **kwargs):
if TrackDescriptor.ID_KEY in kwargs.keys():
if type(kwargs[TrackDescriptor.ID_KEY]) is not int: if TrackDescriptor.ID_KEY in kwargs.keys():
raise TypeError(f"TrackDesciptor.__init__(): Argument {TrackDescriptor.ID_KEY} is required to be of type int") if type(kwargs[TrackDescriptor.ID_KEY]) is not int:
self.__trackId = kwargs[TrackDescriptor.ID_KEY] raise TypeError(
else: f"TrackDesciptor.__init__(): Argument {TrackDescriptor.ID_KEY} is required to be of type int"
self.__trackId = -1 )
self.__trackId = kwargs[TrackDescriptor.ID_KEY]
if TrackDescriptor.PATTERN_ID_KEY in kwargs.keys(): else:
if type(kwargs[TrackDescriptor.PATTERN_ID_KEY]) is not int: self.__trackId = -1
raise TypeError(f"TrackDesciptor.__init__(): Argument {TrackDescriptor.PATTERN_ID_KEY} is required to be of type int")
self.__patternId = kwargs[TrackDescriptor.PATTERN_ID_KEY] if TrackDescriptor.PATTERN_ID_KEY in kwargs.keys():
else: if type(kwargs[TrackDescriptor.PATTERN_ID_KEY]) is not int:
self.__patternId = -1 raise TypeError(
f"TrackDesciptor.__init__(): Argument {TrackDescriptor.PATTERN_ID_KEY} is required to be of type int"
if TrackDescriptor.INDEX_KEY in kwargs.keys(): )
if type(kwargs[TrackDescriptor.INDEX_KEY]) is not int: self.__patternId = kwargs[TrackDescriptor.PATTERN_ID_KEY]
raise TypeError(f"TrackDesciptor.__init__(): Argument {TrackDescriptor.INDEX_KEY} is required to be of type int") else:
self.__index = kwargs[TrackDescriptor.INDEX_KEY] self.__patternId = -1
else:
self.__index = -1 if TrackDescriptor.EXTERNAL_SOURCE_FILE_PATH_KEY in kwargs.keys():
if type(kwargs[TrackDescriptor.EXTERNAL_SOURCE_FILE_PATH_KEY]) is not str:
if TrackDescriptor.SOURCE_INDEX_KEY in kwargs.keys() and type(kwargs[TrackDescriptor.SOURCE_INDEX_KEY]) is int: raise TypeError(
self.__sourceIndex = kwargs[TrackDescriptor.SOURCE_INDEX_KEY] f"TrackDesciptor.__init__(): Argument {TrackDescriptor.EXTERNAL_SOURCE_FILE_PATH_KEY} is required to be of type str"
else: )
self.__sourceIndex = self.__index self.__externalSourceFilePath = kwargs[TrackDescriptor.EXTERNAL_SOURCE_FILE_PATH_KEY]
else:
if TrackDescriptor.SUB_INDEX_KEY in kwargs.keys(): self.__externalSourceFilePath = None
if type(kwargs[TrackDescriptor.SUB_INDEX_KEY]) is not int:
raise TypeError(f"TrackDesciptor.__init__(): Argument {TrackDescriptor.SUB_INDEX_KEY} is required to be of type int") if TrackDescriptor.INDEX_KEY in kwargs.keys():
self.__subIndex = kwargs[TrackDescriptor.SUB_INDEX_KEY] if type(kwargs[TrackDescriptor.INDEX_KEY]) is not int:
else: raise TypeError(
self.__subIndex = -1 f"TrackDesciptor.__init__(): Argument {TrackDescriptor.INDEX_KEY} is required to be of type int"
)
if TrackDescriptor.TRACK_TYPE_KEY in kwargs.keys(): self.__index = kwargs[TrackDescriptor.INDEX_KEY]
if type(kwargs[TrackDescriptor.TRACK_TYPE_KEY]) is not TrackType: else:
raise TypeError(f"TrackDesciptor.__init__(): Argument {TrackDescriptor.TRACK_TYPE_KEY} is required to be of type TrackType") self.__index = -1
self.__trackType = kwargs[TrackDescriptor.TRACK_TYPE_KEY]
else: if (
self.__trackType = TrackType.UNKNOWN TrackDescriptor.SOURCE_INDEX_KEY in kwargs.keys()
and type(kwargs[TrackDescriptor.SOURCE_INDEX_KEY]) is int
if TrackDescriptor.TAGS_KEY in kwargs.keys(): ):
if type(kwargs[TrackDescriptor.TAGS_KEY]) is not dict: self.__sourceIndex = kwargs[TrackDescriptor.SOURCE_INDEX_KEY]
raise TypeError(f"TrackDesciptor.__init__(): Argument {TrackDescriptor.TAGS_KEY} is required to be of type dict") else:
self.__trackTags = kwargs[TrackDescriptor.TAGS_KEY] self.__sourceIndex = self.__index
else:
self.__trackTags = {} if TrackDescriptor.SUB_INDEX_KEY in kwargs.keys():
if type(kwargs[TrackDescriptor.SUB_INDEX_KEY]) is not int:
if TrackDescriptor.DISPOSITION_SET_KEY in kwargs.keys(): raise TypeError(
if type(kwargs[TrackDescriptor.DISPOSITION_SET_KEY]) is not set: f"TrackDesciptor.__init__(): Argument {TrackDescriptor.SUB_INDEX_KEY} is required to be of type int"
raise TypeError(f"TrackDesciptor.__init__(): Argument {TrackDescriptor.DISPOSITION_SET_KEY} is required to be of type set") )
for d in kwargs[TrackDescriptor.DISPOSITION_SET_KEY]: self.__subIndex = kwargs[TrackDescriptor.SUB_INDEX_KEY]
if type(d) is not TrackDisposition: else:
raise TypeError(f"TrackDesciptor.__init__(): All elements of argument set {TrackDescriptor.DISPOSITION_SET_KEY} is required to be of type TrackDisposition") self.__subIndex = -1
self.__dispositionSet = kwargs[TrackDescriptor.DISPOSITION_SET_KEY]
else: if TrackDescriptor.TRACK_TYPE_KEY in kwargs.keys():
self.__dispositionSet = set() if type(kwargs[TrackDescriptor.TRACK_TYPE_KEY]) is not TrackType:
raise TypeError(
if TrackDescriptor.AUDIO_LAYOUT_KEY in kwargs.keys(): f"TrackDesciptor.__init__(): Argument {TrackDescriptor.TRACK_TYPE_KEY} is required to be of type TrackType"
if type(kwargs[TrackDescriptor.AUDIO_LAYOUT_KEY]) is not AudioLayout: )
raise TypeError(f"TrackDesciptor.__init__(): Argument {TrackDescriptor.AUDIO_LAYOUT_KEY} is required to be of type AudioLayout") self.__trackType = kwargs[TrackDescriptor.TRACK_TYPE_KEY]
self.__audioLayout = kwargs[TrackDescriptor.AUDIO_LAYOUT_KEY] else:
else: self.__trackType = TrackType.UNKNOWN
self.__audioLayout = AudioLayout.LAYOUT_UNDEFINED
if TrackDescriptor.TAGS_KEY in kwargs.keys():
if type(kwargs[TrackDescriptor.TAGS_KEY]) is not dict:
@classmethod raise TypeError(
def fromFfprobe(cls, streamObj, subIndex : int = -1): f"TrackDesciptor.__init__(): Argument {TrackDescriptor.TAGS_KEY} is required to be of type dict"
"""Processes ffprobe stream data as array with elements according to the following example )
self.__trackTags = kwargs[TrackDescriptor.TAGS_KEY]
else:
self.__trackTags = {}
if TrackDescriptor.DISPOSITION_SET_KEY in kwargs.keys():
if type(kwargs[TrackDescriptor.DISPOSITION_SET_KEY]) is not set:
raise TypeError(
f"TrackDesciptor.__init__(): Argument {TrackDescriptor.DISPOSITION_SET_KEY} is required to be of type set"
)
for d in kwargs[TrackDescriptor.DISPOSITION_SET_KEY]:
if type(d) is not TrackDisposition:
raise TypeError(
f"TrackDesciptor.__init__(): All elements of argument set {TrackDescriptor.DISPOSITION_SET_KEY} is required to be of type TrackDisposition"
)
self.__dispositionSet = kwargs[TrackDescriptor.DISPOSITION_SET_KEY]
else:
self.__dispositionSet = set()
if TrackDescriptor.AUDIO_LAYOUT_KEY in kwargs.keys():
if type(kwargs[TrackDescriptor.AUDIO_LAYOUT_KEY]) is not AudioLayout:
raise TypeError(
f"TrackDesciptor.__init__(): Argument {TrackDescriptor.AUDIO_LAYOUT_KEY} is required to be of type AudioLayout"
)
self.__audioLayout = kwargs[TrackDescriptor.AUDIO_LAYOUT_KEY]
else:
self.__audioLayout = AudioLayout.LAYOUT_UNDEFINED
@classmethod
def fromFfprobe(cls, streamObj, subIndex: int = -1):
"""Processes ffprobe stream data as array with elements according to the following example
{
"index": 4,
"codec_name": "hdmv_pgs_subtitle",
"codec_long_name": "HDMV Presentation Graphic Stream subtitles",
"codec_type": "subtitle",
"codec_tag_string": "[0][0][0][0]",
"codec_tag": "0x0000",
"r_frame_rate": "0/0",
"avg_frame_rate": "0/0",
"time_base": "1/1000",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 1421035,
"duration": "1421.035000",
"disposition": {
"default": 1,
"dub": 0,
"original": 0,
"comment": 0,
"lyrics": 0,
"karaoke": 0,
"forced": 0,
"hearing_impaired": 0,
"visual_impaired": 0,
"clean_effects": 0,
"attached_pic": 0,
"timed_thumbnails": 0,
"non_diegetic": 0,
"captions": 0,
"descriptions": 0,
"metadata": 0,
"dependent": 0,
"still_image": 0
},
"tags": {
"language": "ger",
"title": "German Full"
}
}
"""
trackType = (
TrackType.fromLabel(streamObj["codec_type"])
if "codec_type" in streamObj.keys()
else TrackType.UNKNOWN
)
if trackType != TrackType.UNKNOWN:
kwargs = {}
kwargs[TrackDescriptor.INDEX_KEY] = (
int(streamObj[TrackDescriptor.FFPROBE_INDEX_KEY])
if TrackDescriptor.FFPROBE_INDEX_KEY in streamObj.keys()
else -1
)
kwargs[TrackDescriptor.SOURCE_INDEX_KEY] = kwargs[TrackDescriptor.INDEX_KEY]
kwargs[TrackDescriptor.SUB_INDEX_KEY] = subIndex
kwargs[TrackDescriptor.TRACK_TYPE_KEY] = trackType
kwargs[TrackDescriptor.DISPOSITION_SET_KEY] = (
{ {
"index": 4, t
"codec_name": "hdmv_pgs_subtitle", for d in (
"codec_long_name": "HDMV Presentation Graphic Stream subtitles", k
"codec_type": "subtitle", for (k, v) in streamObj[
"codec_tag_string": "[0][0][0][0]", TrackDescriptor.FFPROBE_DISPOSITION_KEY
"codec_tag": "0x0000", ].items()
"r_frame_rate": "0/0", if v
"avg_frame_rate": "0/0", )
"time_base": "1/1000", if (t := TrackDisposition.find(d)) is not None
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 1421035,
"duration": "1421.035000",
"disposition": {
"default": 1,
"dub": 0,
"original": 0,
"comment": 0,
"lyrics": 0,
"karaoke": 0,
"forced": 0,
"hearing_impaired": 0,
"visual_impaired": 0,
"clean_effects": 0,
"attached_pic": 0,
"timed_thumbnails": 0,
"non_diegetic": 0,
"captions": 0,
"descriptions": 0,
"metadata": 0,
"dependent": 0,
"still_image": 0
},
"tags": {
"language": "ger",
"title": "German Full"
} }
} if TrackDescriptor.FFPROBE_DISPOSITION_KEY in streamObj.keys()
""" else set()
)
trackType = TrackType.fromLabel(streamObj['codec_type']) if 'codec_type' in streamObj.keys() else TrackType.UNKNOWN kwargs[TrackDescriptor.TAGS_KEY] = (
streamObj[TrackDescriptor.FFPROBE_TAGS_KEY]
if trackType != TrackType.UNKNOWN: if TrackDescriptor.FFPROBE_TAGS_KEY in streamObj.keys()
else {}
kwargs = {} )
kwargs[TrackDescriptor.AUDIO_LAYOUT_KEY] = (
kwargs[TrackDescriptor.INDEX_KEY] = int(streamObj[TrackDescriptor.FFPROBE_INDEX_KEY]) if TrackDescriptor.FFPROBE_INDEX_KEY in streamObj.keys() else -1 AudioLayout.identify(streamObj)
kwargs[TrackDescriptor.SOURCE_INDEX_KEY] = kwargs[TrackDescriptor.INDEX_KEY] if trackType == TrackType.AUDIO
kwargs[TrackDescriptor.SUB_INDEX_KEY] = subIndex else AudioLayout.LAYOUT_UNDEFINED
)
kwargs[TrackDescriptor.TRACK_TYPE_KEY] = trackType
kwargs[TrackDescriptor.DISPOSITION_SET_KEY] = {t for d in (k for (k,v) in streamObj[TrackDescriptor.FFPROBE_DISPOSITION_KEY].items() if v)
if (t := TrackDisposition.find(d)) if t is not None} if TrackDescriptor.FFPROBE_DISPOSITION_KEY in streamObj.keys() else set()
kwargs[TrackDescriptor.TAGS_KEY] = streamObj[TrackDescriptor.FFPROBE_TAGS_KEY] if TrackDescriptor.FFPROBE_TAGS_KEY in streamObj.keys() else {}
kwargs[TrackDescriptor.AUDIO_LAYOUT_KEY] = AudioLayout.identify(streamObj) if trackType == TrackType.AUDIO else AudioLayout.LAYOUT_UNDEFINED
return cls(**kwargs)
else:
return None
def getId(self):
return self.__trackId
def getPatternId(self): return cls(**kwargs)
return self.__patternId else:
return None
def getIndex(self): def getId(self):
return self.__index return self.__trackId
def getSourceIndex(self): def getPatternId(self):
return self.__sourceIndex return self.__patternId
def getIndex(self):
return self.__index
def getSubIndex(self): def getSourceIndex(self):
return self.__subIndex return self.__sourceIndex
def setSubIndex(self, subIndex): def getSubIndex(self):
self.__subIndex = subIndex return self.__subIndex
def getType(self): def setSubIndex(self, subIndex):
return self.__trackType self.__subIndex = subIndex
def getLanguage(self): def getType(self):
if 'language' in self.__trackTags.keys(): return self.__trackType
return IsoLanguage.findThreeLetter(self.__trackTags['language'])
else:
return IsoLanguage.UNDEFINED
def getTitle(self): def getLanguage(self):
if 'title' in self.__trackTags.keys(): if "language" in self.__trackTags.keys():
return str(self.__trackTags['title']) return IsoLanguage.findThreeLetter(self.__trackTags["language"])
else: else:
return '' return IsoLanguage.UNDEFINED
def getAudioLayout(self): def getTitle(self):
return self.__audioLayout if "title" in self.__trackTags.keys():
return str(self.__trackTags["title"])
else:
return ""
def getAudioLayout(self):
return self.__audioLayout
def getTags(self): def getTags(self):
return self.__trackTags return self.__trackTags
def getDispositionSet(self): def getDispositionSet(self):
return self.__dispositionSet return self.__dispositionSet
def getDispositionFlag(self, disposition: TrackDisposition) -> bool:
return bool(disposition in self.__dispositionSet)
def getDispositionFlag(self, disposition : TrackDisposition) -> bool: def setDispositionFlag(self, disposition: TrackDisposition, state: bool):
return bool(disposition in self.__dispositionSet) if state:
self.__dispositionSet.add(disposition)
else:
self.__dispositionSet.discard(disposition)
def setDispositionFlag(self, disposition : TrackDisposition, state : bool): def compare(self, vsTrackDescriptor):
if state:
self.__dispositionSet.add(disposition)
else:
self.__dispositionSet.discard(disposition)
compareResult = {}
def compare(self, vsTrackDescriptor): tagsDiffResult = dictDiff(vsTrackDescriptor.getTags(), self.getTags())
compareResult = {} if tagsDiffResult:
compareResult[TrackDescriptor.TAGS_KEY] = tagsDiffResult
tagsDiffResult = dictDiff(vsTrackDescriptor.getTags(), self.getTags()) vsDispositions = vsTrackDescriptor.getDispositionSet()
dispositions = self.getDispositionSet()
if tagsDiffResult: dispositionDiffResult = setDiff(vsDispositions, dispositions)
compareResult[TrackDescriptor.TAGS_KEY] = tagsDiffResult
vsDispositions = vsTrackDescriptor.getDispositionSet() if dispositionDiffResult:
dispositions = self.getDispositionSet() compareResult[TrackDescriptor.DISPOSITION_SET_KEY] = dispositionDiffResult
dispositionDiffResult = setDiff(vsDispositions, dispositions) return compareResult
if dispositionDiffResult: def setExternalSourceFilePath(self, filePath: str):
compareResult[TrackDescriptor.DISPOSITION_SET_KEY] = dispositionDiffResult self.__externalSourceFilePath = str(filePath)
return compareResult def getExternalSourceFilePath(self):
return self.__externalSourceFilePath

Loading…
Cancel
Save