nightl
This commit is contained in:
@@ -339,7 +339,7 @@ def convert(ctx,
|
||||
|
||||
click.echo(f"Input mapping tokens: {targetMediaDescriptor.getInputMappingTokens()}")
|
||||
|
||||
fc = FfxController(currentMediaDescriptor, targetMediaDescriptor)
|
||||
fc = FfxController(context, currentMediaDescriptor, targetMediaDescriptor)
|
||||
|
||||
mappingTokens = fc.generateMetadataTokens()
|
||||
click.echo(f"Metadata Tokens: {mappingTokens}")
|
||||
|
||||
@@ -13,7 +13,7 @@ class AudioLayout(Enum):
|
||||
LAYOUT_UNDEFINED = {"layout": "undefined", "index": 0}
|
||||
|
||||
|
||||
def layout(self):
|
||||
def label(self):
|
||||
"""Returns the layout as string"""
|
||||
return self.value['layout']
|
||||
|
||||
@@ -21,6 +21,12 @@ class AudioLayout(Enum):
|
||||
"""Returns the layout as string"""
|
||||
return self.value['layout']
|
||||
|
||||
@staticmethod
|
||||
def fromIndex(index : int):
|
||||
try:
|
||||
return [a for a in AudioLayout if a.index() == int(index)][0]
|
||||
except:
|
||||
return AudioLayout.LAYOUT_UNDEFINED
|
||||
|
||||
def identify(self, streamObj):
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from ffx.media_descriptor import MediaDescriptor
|
||||
from ffx.helper import DIFF_ADDED_KEY, DIFF_REMOVED_KEY, DIFF_CHANGED_KEY
|
||||
from ffx.track_descriptor import TrackDescriptor
|
||||
from ffx.model.track import Track
|
||||
from ffx.audio_layout import AudioLayout
|
||||
|
||||
|
||||
class FfxController():
|
||||
@@ -37,8 +38,12 @@ class FfxController():
|
||||
|
||||
INPUT_FILE_EXTENSIONS = ['mkv', 'mp4', 'avi', 'flv', 'webm']
|
||||
|
||||
def __init__(self, sourceMediaDescriptor : MediaDescriptor, targetMediaDescriptor : MediaDescriptor):
|
||||
def __init__(self,
|
||||
context : dict,
|
||||
sourceMediaDescriptor : MediaDescriptor,
|
||||
targetMediaDescriptor : MediaDescriptor):
|
||||
|
||||
self.__context = context
|
||||
self.__sourceMediaDescriptor = sourceMediaDescriptor
|
||||
self.__targetMediaDescriptor = targetMediaDescriptor
|
||||
|
||||
@@ -99,49 +104,49 @@ class FfxController():
|
||||
return ['-f', format, f"{filepath}.{ext}"]
|
||||
|
||||
|
||||
def generateAudioEncodingTokens(self, context, index, layout):
|
||||
def generateAudioEncodingTokens(self, subIndex : int, layout : AudioLayout):
|
||||
"""Generates ffmpeg options for one output audio stream including channel remapping, codec and bitrate"""
|
||||
pass
|
||||
#
|
||||
# if layout == STREAM_LAYOUT_6_1:
|
||||
# return [f"-c:a:{index}",
|
||||
# 'libopus',
|
||||
# f"-filter:a:{index}",
|
||||
# 'channelmap=channel_layout=6.1',
|
||||
# f"-b:a:{index}",
|
||||
# context['bitrates']['dts']]
|
||||
#
|
||||
# elif layout == STREAM_LAYOUT_5_1:
|
||||
# return [f"-c:a:{index}",
|
||||
# 'libopus',
|
||||
# f"-filter:a:{index}",
|
||||
# "channelmap=FL-FL|FR-FR|FC-FC|LFE-LFE|SL-BL|SR-BR:5.1",
|
||||
# f"-b:a:{index}",
|
||||
# context['bitrates']['ac3']]
|
||||
#
|
||||
# elif layout == STREAM_LAYOUT_STEREO:
|
||||
# return [f"-c:a:{index}",
|
||||
# 'libopus',
|
||||
# f"-b:a:{index}",
|
||||
# context['bitrates']['stereo']]
|
||||
#
|
||||
# elif layout == STREAM_LAYOUT_6CH:
|
||||
# return [f"-c:a:{index}",
|
||||
# 'libopus',
|
||||
# f"-filter:a:{index}",
|
||||
# "channelmap=FL-FL|FR-FR|FC-FC|LFE-LFE|SL-BL|SR-BR:5.1",
|
||||
# f"-b:a:{index}",
|
||||
# context['bitrates']['ac3']]
|
||||
# else:
|
||||
# return []
|
||||
|
||||
if layout == AudioLayout.LAYOUT_6_1:
|
||||
return [f"-c:a:{subIndex}",
|
||||
'libopus',
|
||||
f"-filter:a:{subIndex}",
|
||||
'channelmap=channel_layout=6.1',
|
||||
f"-b:a:{subIndex}",
|
||||
self.__context['bitrates']['dts']]
|
||||
|
||||
elif layout == AudioLayout.LAYOUT_5_1:
|
||||
return [f"-c:a:{subIndex}",
|
||||
'libopus',
|
||||
f"-filter:a:{subIndex}",
|
||||
"channelmap=FL-FL|FR-FR|FC-FC|LFE-LFE|SL-BL|SR-BR:5.1",
|
||||
f"-b:a:{subIndex}",
|
||||
self.__context['bitrates']['ac3']]
|
||||
|
||||
elif layout == AudioLayout.LAYOUT_STEREO:
|
||||
return [f"-c:a:{subIndex}",
|
||||
'libopus',
|
||||
f"-b:a:{subIndex}",
|
||||
self.__context['bitrates']['stereo']]
|
||||
|
||||
elif layout == AudioLayout.LAYOUT_6CH:
|
||||
return [f"-c:a:{subIndex}",
|
||||
'libopus',
|
||||
f"-filter:a:{subIndex}",
|
||||
"channelmap=FL-FL|FR-FR|FC-FC|LFE-LFE|SL-BL|SR-BR:5.1",
|
||||
f"-b:a:{subIndex}",
|
||||
self.__context['bitrates']['ac3']]
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def generateClearTokens(self, streams):
|
||||
clearTokens = []
|
||||
for s in streams:
|
||||
for k in FfxController.MKVMERGE_METADATA_KEYS:
|
||||
clearTokens += [f"-metadata:s:{s['type'][0]}:{s['sub_index']}", f"{k}="]
|
||||
return clearTokens
|
||||
# def generateClearTokens(self, streams):
|
||||
# clearTokens = []
|
||||
# for s in streams:
|
||||
# for k in FfxController.MKVMERGE_METADATA_KEYS:
|
||||
# clearTokens += [f"-metadata:s:{s['type'][0]}:{s['sub_index']}", f"{k}="]
|
||||
# return clearTokens
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -191,7 +191,9 @@ class MediaDescriptor():
|
||||
|
||||
#HINT: Some tags differ per file, for example creation_time, so these are removed before diff
|
||||
for emt in MediaDescriptor.EXCLUDED_MEDIA_TAGS:
|
||||
if emt in tags.keys():
|
||||
del tags[emt]
|
||||
if emt in vsTags.keys():
|
||||
del vsTags[emt]
|
||||
|
||||
tagsDiff = dictDiff(vsTags, tags)
|
||||
@@ -218,12 +220,12 @@ class MediaDescriptor():
|
||||
|
||||
for tp in range(maxNumOfTracks):
|
||||
|
||||
# if self.__jellyfinOrder:
|
||||
# vsTrackIndex = tracks[tp].getSourceIndex()
|
||||
# else:
|
||||
# vsTrackIndex = tp
|
||||
|
||||
# inspect/update funktionier nur so
|
||||
if self.__jellyfinOrder:
|
||||
vsTrackIndex = tracks[tp].getSourceIndex()
|
||||
else:
|
||||
vsTrackIndex = tp
|
||||
# vsTrackIndex = tracks[tp].getSourceIndex()
|
||||
|
||||
# Will trigger if tracks are missing in file
|
||||
if tp > (numVsTracks - 1):
|
||||
|
||||
@@ -507,6 +507,8 @@ class MediaDetailsScreen(Screen):
|
||||
|
||||
if DIFF_REMOVED_KEY in self.__mediaDifferences[MediaDescriptor.TRACKS_KEY].keys():
|
||||
for removedTrackIndex, removedTrack in self.__mediaDifferences[MediaDescriptor.TRACKS_KEY][DIFF_REMOVED_KEY].items():
|
||||
|
||||
# Track per inspect/update hinzufügen
|
||||
self.__tc.addTrack(removedTrack, patternId = self.__currentPattern.getId())
|
||||
|
||||
if DIFF_CHANGED_KEY in self.__mediaDifferences[MediaDescriptor.TRACKS_KEY].keys():
|
||||
|
||||
@@ -11,6 +11,8 @@ from ffx.iso_language import IsoLanguage
|
||||
from ffx.track_disposition import TrackDisposition
|
||||
from ffx.track_descriptor import TrackDescriptor
|
||||
|
||||
from ffx.audio_layout import AudioLayout
|
||||
|
||||
import click
|
||||
|
||||
class Track(Base):
|
||||
@@ -40,9 +42,10 @@ class Track(Base):
|
||||
|
||||
track_tags = relationship('TrackTag', back_populates='track', cascade="all, delete", lazy="joined")
|
||||
|
||||
|
||||
disposition_flags = Column(Integer)
|
||||
|
||||
audio_layout = Column(Integer)
|
||||
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
@@ -57,7 +60,7 @@ class Track(Base):
|
||||
|
||||
|
||||
@classmethod
|
||||
def fromStreamObj(cls, streamObj, patternId):
|
||||
def fromFfprobeStreamObj(cls, streamObj, patternId):
|
||||
"""{
|
||||
'index': 4,
|
||||
'codec_name': 'hdmv_pgs_subtitle',
|
||||
@@ -124,14 +127,15 @@ class Track(Base):
|
||||
"""
|
||||
|
||||
|
||||
trackType = streamObj['codec_type']
|
||||
trackType = streamObj[TrackDescriptor.FFPROBE_CODEC_TYPE_KEY]
|
||||
|
||||
if trackType in [t.label() for t in TrackType]:
|
||||
|
||||
# sub_index = int(subIndex),
|
||||
return cls(pattern_id = patternId,
|
||||
track_type = trackType,
|
||||
disposition_flags = sum([2**t.index() for (k,v) in streamObj['disposition'].items() if v and (t := TrackDisposition.find(k)) is not None]))
|
||||
disposition_flags = sum([2**t.index() for (k,v) in streamObj[TrackDescriptor.FFPROBE_DISPOSITION_KEY].items()
|
||||
if v and (t := TrackDisposition.find(k)) is not None]),
|
||||
audio_layout = AudioLayout.identify(streamObj))
|
||||
|
||||
else:
|
||||
return None
|
||||
@@ -163,6 +167,9 @@ class Track(Base):
|
||||
def getDispositionSet(self):
|
||||
return TrackDisposition.toSet(self.disposition_flags)
|
||||
|
||||
def getAudioLayout(self):
|
||||
return AudioLayout.fromIndex(self.audio_layout)
|
||||
|
||||
def getTags(self):
|
||||
return {str(t.key):str(t.value) for t in self.track_tags}
|
||||
|
||||
@@ -194,4 +201,6 @@ class Track(Base):
|
||||
kwargs[TrackDescriptor.DISPOSITION_SET_KEY] = self.getDispositionSet()
|
||||
kwargs[TrackDescriptor.TAGS_KEY] = self.getTags()
|
||||
|
||||
kwargs[TrackDescriptor.AUDIO_LAYOUT_KEY] = self.getAudioLayout()
|
||||
|
||||
return TrackDescriptor(**kwargs)
|
||||
|
||||
@@ -138,7 +138,7 @@ class PatternDetailsScreen(Screen):
|
||||
row = (td.getIndex(),
|
||||
trackType.label(),
|
||||
typeCounter[trackType],
|
||||
" ",
|
||||
td.getAudioLayout().label(),
|
||||
td.getLanguage().label(),
|
||||
td.getTitle(),
|
||||
'Yes' if TrackDisposition.DEFAULT in dispoSet else 'No',
|
||||
|
||||
@@ -82,16 +82,16 @@ class ShowDetailsScreen(Screen):
|
||||
self.show_obj = self.__sc.getShowDesciptor(showId) if showId is not None else {}
|
||||
|
||||
|
||||
def loadPatterns(self, show_id):
|
||||
def loadPatterns(self, show_id : int):
|
||||
|
||||
try:
|
||||
s = self.Session()
|
||||
q = s.query(Pattern).filter(Pattern.show_id == int(show_id))
|
||||
|
||||
return [{'id': int(p.id), 'pattern': p.pattern} for p in q.all()]
|
||||
return [{'id': int(p.id), 'pattern': str(p.pattern)} for p in q.all()]
|
||||
|
||||
except Exception as ex:
|
||||
click.ClickException(f"loadPatterns(): {repr(ex)}")
|
||||
raise click.ClickException(f"ShowDetailsScreen.loadPatterns(): {repr(ex)}")
|
||||
finally:
|
||||
s.close()
|
||||
|
||||
@@ -109,7 +109,11 @@ class ShowDetailsScreen(Screen):
|
||||
self.query_one("#indicator_season_digits_input", Input).value = str(self.show_obj['indicator_season_digits'])
|
||||
self.query_one("#indicator_episode_digits_input", Input).value = str(self.show_obj['indicator_episode_digits'])
|
||||
|
||||
for pattern in self.loadPatterns(int(self.show_obj['id'])):
|
||||
showId = int(self.show_obj['id'])
|
||||
#raise click.ClickException(f"show_id {showId}")
|
||||
patternList = self.loadPatterns(showId)
|
||||
# raise click.ClickException(f"patternList {patternList}")
|
||||
for pattern in patternList:
|
||||
row = (pattern['pattern'],)
|
||||
self.patternTable.add_row(*map(str, row))
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ class TrackDescriptor():
|
||||
FFPROBE_INDEX_KEY = 'index'
|
||||
FFPROBE_DISPOSITION_KEY = 'disposition'
|
||||
FFPROBE_TAGS_KEY = 'tags'
|
||||
FFPROBE_CODEC_TYPE_KEY = 'codec_type'
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
|
||||
@@ -348,6 +348,7 @@ class TrackDetailsScreen(Screen):
|
||||
|
||||
if self.__isNew:
|
||||
|
||||
# Track per Screen hinzufügen
|
||||
self.__tc.addTrack(trackDescriptor)
|
||||
self.dismiss(trackDescriptor)
|
||||
|
||||
@@ -355,6 +356,7 @@ class TrackDetailsScreen(Screen):
|
||||
|
||||
track = self.__tc.getTrack(self.__pattern.getId(), self.__index)
|
||||
|
||||
# Track per details screen updaten
|
||||
if self.__tc.updateTrack(track.getId(), trackDescriptor):
|
||||
self.dismiss(trackDescriptor)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user