#389 Templating für Ausgabe-Dateinamen
This commit is contained in:
@@ -5,6 +5,7 @@ version = "0.2.2"
|
|||||||
license = {file = "LICENSE.md"}
|
license = {file = "LICENSE.md"}
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"requests",
|
"requests",
|
||||||
|
"jinja2",
|
||||||
"click",
|
"click",
|
||||||
"textual",
|
"textual",
|
||||||
"sqlalchemy",
|
"sqlalchemy",
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ class ConfigurationController():
|
|||||||
|
|
||||||
DATABASE_PATH_CONFIG_KEY = 'databasePath'
|
DATABASE_PATH_CONFIG_KEY = 'databasePath'
|
||||||
LOG_DIRECTORY_CONFIG_KEY = 'logDirectory'
|
LOG_DIRECTORY_CONFIG_KEY = 'logDirectory'
|
||||||
|
OUTPUT_FILENAME_TEMPLATE_KEY = 'outputFilenameTemplate'
|
||||||
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
|
|||||||
@@ -11,3 +11,5 @@ DEFAULT_7_1_BANDWIDTH = "384"
|
|||||||
|
|
||||||
DEFAULT_CROP_START = 60
|
DEFAULT_CROP_START = 60
|
||||||
DEFAULT_CROP_LENGTH = 180
|
DEFAULT_CROP_LENGTH = 180
|
||||||
|
|
||||||
|
DEFAULT_OUTPUT_FILENAME_TEMPLATE = '{{ ffx_show_name }} - {{ ffx_index }}{{ ffx_index_separator }}{{ ffx_episode_name }}{{ ffx_indicator_separator }}{{ ffx_indicator }}'
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from ffx.track_codec import TrackCodec
|
|||||||
|
|
||||||
from ffx.process import executeProcess
|
from ffx.process import executeProcess
|
||||||
from ffx.helper import filterFilename
|
from ffx.helper import filterFilename
|
||||||
|
from ffx.helper import getEpisodeFileBasename
|
||||||
|
|
||||||
from ffx.constants import DEFAULT_STEREO_BANDWIDTH, DEFAULT_AC3_BANDWIDTH, DEFAULT_DTS_BANDWIDTH, DEFAULT_7_1_BANDWIDTH
|
from ffx.constants import DEFAULT_STEREO_BANDWIDTH, DEFAULT_AC3_BANDWIDTH, DEFAULT_DTS_BANDWIDTH, DEFAULT_7_1_BANDWIDTH
|
||||||
|
|
||||||
@@ -649,14 +650,15 @@ def convert(ctx,
|
|||||||
|
|
||||||
if tmdbEpisodeResult:
|
if tmdbEpisodeResult:
|
||||||
filteredEpisodeName = filterFilename(tmdbEpisodeResult['name'])
|
filteredEpisodeName = filterFilename(tmdbEpisodeResult['name'])
|
||||||
sourceFileBasename = TmdbController.getEpisodeFileBasename(showFilenamePrefix,
|
sourceFileBasename = getEpisodeFileBasename(showFilenamePrefix,
|
||||||
filteredEpisodeName,
|
filteredEpisodeName,
|
||||||
shiftedShowSeason,
|
shiftedShowSeason,
|
||||||
shiftedShowEpisode,
|
shiftedShowEpisode,
|
||||||
indexSeasonDigits,
|
indexSeasonDigits,
|
||||||
indexEpisodeDigits,
|
indexEpisodeDigits,
|
||||||
indicatorSeasonDigits,
|
indicatorSeasonDigits,
|
||||||
indicatorEpisodeDigits)
|
indicatorEpisodeDigits,
|
||||||
|
context=ctx.obj)
|
||||||
|
|
||||||
if label:
|
if label:
|
||||||
if shiftedShowSeason > -1 and shiftedShowEpisode > -1:
|
if shiftedShowSeason > -1 and shiftedShowEpisode > -1:
|
||||||
|
|||||||
@@ -1,8 +1,21 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from jinja2 import Environment, Undefined
|
||||||
|
from .constants import DEFAULT_OUTPUT_FILENAME_TEMPLATE
|
||||||
|
from .configuration_controller import ConfigurationController
|
||||||
|
|
||||||
|
|
||||||
|
class EmptyStringUndefined(Undefined):
|
||||||
|
def __str__(self):
|
||||||
|
return ''
|
||||||
|
|
||||||
|
|
||||||
DIFF_ADDED_KEY = 'added'
|
DIFF_ADDED_KEY = 'added'
|
||||||
DIFF_REMOVED_KEY = 'removed'
|
DIFF_REMOVED_KEY = 'removed'
|
||||||
DIFF_CHANGED_KEY = 'changed'
|
DIFF_CHANGED_KEY = 'changed'
|
||||||
DIFF_UNCHANGED_KEY = 'unchanged'
|
DIFF_UNCHANGED_KEY = 'unchanged'
|
||||||
|
|
||||||
|
|
||||||
def dictDiff(a : dict, b : dict):
|
def dictDiff(a : dict, b : dict):
|
||||||
|
|
||||||
a_keys = set(a.keys())
|
a_keys = set(a.keys())
|
||||||
@@ -75,3 +88,79 @@ def filterFilename(fileName: str) -> str:
|
|||||||
fileName = str(fileName).replace("?", '#')
|
fileName = str(fileName).replace("?", '#')
|
||||||
|
|
||||||
return fileName.strip()
|
return fileName.strip()
|
||||||
|
|
||||||
|
|
||||||
|
def getEpisodeFileBasename(showName,
|
||||||
|
episodeName,
|
||||||
|
season,
|
||||||
|
episode,
|
||||||
|
indexSeasonDigits = 2,
|
||||||
|
indexEpisodeDigits = 2,
|
||||||
|
indicatorSeasonDigits = 2,
|
||||||
|
indicatorEpisodeDigits = 2,
|
||||||
|
context = None):
|
||||||
|
"""
|
||||||
|
One Piece:
|
||||||
|
indexSeasonDigits = 0,
|
||||||
|
indexEpisodeDigits = 4,
|
||||||
|
indicatorSeasonDigits = 2,
|
||||||
|
indicatorEpisodeDigits = 4
|
||||||
|
|
||||||
|
Three-Body:
|
||||||
|
indexSeasonDigits = 0,
|
||||||
|
indexEpisodeDigits = 2,
|
||||||
|
indicatorSeasonDigits = 2,
|
||||||
|
indicatorEpisodeDigits = 2
|
||||||
|
|
||||||
|
Dragonball:
|
||||||
|
indexSeasonDigits = 0,
|
||||||
|
indexEpisodeDigits = 3,
|
||||||
|
indicatorSeasonDigits = 2,
|
||||||
|
indicatorEpisodeDigits = 3
|
||||||
|
|
||||||
|
Boruto:
|
||||||
|
indexSeasonDigits = 0,
|
||||||
|
indexEpisodeDigits = 4,
|
||||||
|
indicatorSeasonDigits = 2,
|
||||||
|
indicatorEpisodeDigits = 4
|
||||||
|
"""
|
||||||
|
|
||||||
|
cc: ConfigurationController = context['config'] if context is not None and 'config' in context.keys() else None
|
||||||
|
configData = cc.getData() if cc is not None else {}
|
||||||
|
outputFilenameTemplate = configData.get(ConfigurationController.OUTPUT_FILENAME_TEMPLATE_KEY,
|
||||||
|
DEFAULT_OUTPUT_FILENAME_TEMPLATE)
|
||||||
|
|
||||||
|
if context is not None and 'logger' in context.keys():
|
||||||
|
logger = context['logger']
|
||||||
|
else:
|
||||||
|
logger = logging.getLogger('FFX')
|
||||||
|
logger.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
|
indexSeparator = ' ' if indexSeasonDigits or indexEpisodeDigits else ''
|
||||||
|
seasonIndex = '{num:{fill}{width}}'.format(num=season, fill='0', width=indexSeasonDigits) if indexSeasonDigits else ''
|
||||||
|
episodeIndex = '{num:{fill}{width}}'.format(num=episode, fill='0', width=indexEpisodeDigits) if indexEpisodeDigits else ''
|
||||||
|
|
||||||
|
indicatorSeparator = ' - ' if indicatorSeasonDigits or indicatorEpisodeDigits else ''
|
||||||
|
seasonIndicator = 'S{num:{fill}{width}}'.format(num=season, fill='0', width=indicatorSeasonDigits) if indicatorSeasonDigits else ''
|
||||||
|
episodeIndicator = 'E{num:{fill}{width}}'.format(num=episode, fill='0', width=indicatorEpisodeDigits) if indicatorEpisodeDigits else ''
|
||||||
|
|
||||||
|
jinjaKwargs = {
|
||||||
|
'ffx_show_name': showName,
|
||||||
|
'ffx_index_separator': indexSeparator,
|
||||||
|
'ffx_season_index': str(seasonIndex),
|
||||||
|
'ffx_episode_index': str(episodeIndex),
|
||||||
|
'ffx_index': str(seasonIndex) + str(episodeIndex),
|
||||||
|
'ffx_episode_name': episodeName,
|
||||||
|
'ffx_indicator_separator': indicatorSeparator,
|
||||||
|
'ffx_season_indicator': str(seasonIndicator),
|
||||||
|
'ffx_episode_indicator': str(episodeIndicator),
|
||||||
|
'ffx_indicator': str(seasonIndicator) + str(episodeIndicator)
|
||||||
|
}
|
||||||
|
|
||||||
|
jinjaEnv = Environment(undefined=EmptyStringUndefined)
|
||||||
|
jinjaTemplate = jinjaEnv.from_string(outputFilenameTemplate)
|
||||||
|
return jinjaTemplate.render(**jinjaKwargs)
|
||||||
|
|
||||||
|
# return ''.join(filenameTokens)
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ class MediaDescriptor:
|
|||||||
self.__logger = self.__context['logger']
|
self.__logger = self.__context['logger']
|
||||||
else:
|
else:
|
||||||
self.__context = {}
|
self.__context = {}
|
||||||
self.__logger = logging.getLogger('FFX').addHandler(logging.NullHandler())
|
self.__logger = logging.getLogger('FFX')
|
||||||
|
self.__logger.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
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:
|
||||||
@@ -402,7 +403,8 @@ class MediaDescriptor:
|
|||||||
|
|
||||||
if importedFilePath:
|
if importedFilePath:
|
||||||
|
|
||||||
self.__logger.info(f"Substituting subtitle stream {td.getSubIndex()} "
|
self.__logger.info(f"Substituting subtitle stream #{td.getIndex()} "
|
||||||
|
+ f"({td.getType().label()}:{td.getSubIndex()})"
|
||||||
+ f"with import from file {td.getExternalSourceFilePath()}")
|
+ f"with import from file {td.getExternalSourceFilePath()}")
|
||||||
|
|
||||||
importFileTokens += [
|
importFileTokens += [
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ class ShowDescriptor():
|
|||||||
self.__logger = self.__context['logger']
|
self.__logger = self.__context['logger']
|
||||||
else:
|
else:
|
||||||
self.__context = {}
|
self.__context = {}
|
||||||
self.__logger = logging.getLogger('FFX').addHandler(logging.NullHandler())
|
self.__logger = logging.getLogger('FFX')
|
||||||
|
self.__logger.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
if ShowDescriptor.ID_KEY in kwargs.keys():
|
if ShowDescriptor.ID_KEY in kwargs.keys():
|
||||||
if type(kwargs[ShowDescriptor.ID_KEY]) is not int:
|
if type(kwargs[ShowDescriptor.ID_KEY]) is not int:
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ from .scenario import Scenario
|
|||||||
from ffx.test.helper import createMediaTestFile
|
from ffx.test.helper import createMediaTestFile
|
||||||
from ffx.process import executeProcess
|
from ffx.process import executeProcess
|
||||||
from ffx.database import databaseContext
|
from ffx.database import databaseContext
|
||||||
|
|
||||||
from ffx.test.helper import createEmptyDirectory
|
from ffx.test.helper import createEmptyDirectory
|
||||||
|
from ffx.helper import getEpisodeFileBasename
|
||||||
|
|
||||||
from ffx.file_properties import FileProperties
|
from ffx.file_properties import FileProperties
|
||||||
|
|
||||||
@@ -205,9 +207,10 @@ class Scenario4(Scenario):
|
|||||||
tmdbEpisodeResult = self.__tc.queryEpisode(Scenario4.TEST_SHOW_IDENTIFIER,
|
tmdbEpisodeResult = self.__tc.queryEpisode(Scenario4.TEST_SHOW_IDENTIFIER,
|
||||||
tfo['season'], tfo['episode'])
|
tfo['season'], tfo['episode'])
|
||||||
|
|
||||||
expectedFileBasename = TmdbController.getEpisodeFileBasename(self.__testShowDescriptor.getFilenamePrefix(),
|
expectedFileBasename = getEpisodeFileBasename(self.__testShowDescriptor.getFilenamePrefix(),
|
||||||
tmdbEpisodeResult['name'],
|
tmdbEpisodeResult['name'],
|
||||||
tfo['season'], tfo['episode'])
|
tfo['season'], tfo['episode'],
|
||||||
|
context=testContext)
|
||||||
|
|
||||||
expectedFilename = f"{expectedFileBasename}.{Scenario4.EXPECTED_FILE_EXTENSION}"
|
expectedFilename = f"{expectedFileBasename}.{Scenario4.EXPECTED_FILE_EXTENSION}"
|
||||||
expectedFilePath = os.path.join(self._testDirectory, expectedFilename)
|
expectedFilePath = os.path.join(self._testDirectory, expectedFilename)
|
||||||
|
|||||||
@@ -25,8 +25,12 @@ class TmdbController():
|
|||||||
|
|
||||||
def __init__(self, context = None):
|
def __init__(self, context = None):
|
||||||
self.__context = context
|
self.__context = context
|
||||||
self.__logger = (context['logger'] if context is not None and 'logger' in context.keys()
|
|
||||||
else logging.getLogger('FFX').addHandler(logging.NullHandler()))
|
if context is None:
|
||||||
|
self.__logger = logging.getLogger('FFX')
|
||||||
|
self.__logger.addHandler(logging.NullHandler())
|
||||||
|
else:
|
||||||
|
self.__logger = context['logger']
|
||||||
|
|
||||||
self.__tmdbApiKey = os.environ.get('TMDB_API_KEY', None)
|
self.__tmdbApiKey = os.environ.get('TMDB_API_KEY', None)
|
||||||
if self.__tmdbApiKey is None:
|
if self.__tmdbApiKey is None:
|
||||||
@@ -128,61 +132,3 @@ class TmdbController():
|
|||||||
tmdbUrl = f"https://api.themoviedb.org/3/tv/{showId}/season/{season}/episode/{episode}{urlParams}"
|
tmdbUrl = f"https://api.themoviedb.org/3/tv/{showId}/season/{season}/episode/{episode}{urlParams}"
|
||||||
|
|
||||||
return self.getTmdbRequest(tmdbUrl)
|
return self.getTmdbRequest(tmdbUrl)
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def getEpisodeFileBasename(showName,
|
|
||||||
episodeName,
|
|
||||||
season,
|
|
||||||
episode,
|
|
||||||
indexSeasonDigits = 2,
|
|
||||||
indexEpisodeDigits = 2,
|
|
||||||
indicatorSeasonDigits = 2,
|
|
||||||
indicatorEpisodeDigits = 2):
|
|
||||||
"""
|
|
||||||
One Piece:
|
|
||||||
indexSeasonDigits = 0,
|
|
||||||
indexEpisodeDigits = 4,
|
|
||||||
indicatorSeasonDigits = 2,
|
|
||||||
indicatorEpisodeDigits = 4
|
|
||||||
|
|
||||||
Three-Body:
|
|
||||||
indexSeasonDigits = 0,
|
|
||||||
indexEpisodeDigits = 2,
|
|
||||||
indicatorSeasonDigits = 2,
|
|
||||||
indicatorEpisodeDigits = 2
|
|
||||||
|
|
||||||
Dragonball:
|
|
||||||
indexSeasonDigits = 0,
|
|
||||||
indexEpisodeDigits = 3,
|
|
||||||
indicatorSeasonDigits = 2,
|
|
||||||
indicatorEpisodeDigits = 3
|
|
||||||
|
|
||||||
Boruto:
|
|
||||||
indexSeasonDigits = 0,
|
|
||||||
indexEpisodeDigits = 4,
|
|
||||||
indicatorSeasonDigits = 2,
|
|
||||||
indicatorEpisodeDigits = 4
|
|
||||||
"""
|
|
||||||
filenameTokens = [str(showName), ' - ']
|
|
||||||
|
|
||||||
if indexSeasonDigits:
|
|
||||||
filenameTokens += ['{num:{fill}{width}}'.format(num=season, fill='0', width=indexSeasonDigits)]
|
|
||||||
if indexEpisodeDigits:
|
|
||||||
filenameTokens += ['{num:{fill}{width}}'.format(num=episode, fill='0', width=indexEpisodeDigits)]
|
|
||||||
if indexSeasonDigits or indexEpisodeDigits:
|
|
||||||
filenameTokens += [' ']
|
|
||||||
|
|
||||||
filenameTokens += [episodeName]
|
|
||||||
|
|
||||||
if indicatorSeasonDigits or indicatorEpisodeDigits:
|
|
||||||
filenameTokens += [' - ']
|
|
||||||
if indicatorSeasonDigits:
|
|
||||||
filenameTokens += ['S{num:{fill}{width}}'.format(num=season, fill='0', width=indicatorSeasonDigits)]
|
|
||||||
if indicatorEpisodeDigits:
|
|
||||||
filenameTokens += ['E{num:{fill}{width}}'.format(num=episode, fill='0', width=indicatorEpisodeDigits)]
|
|
||||||
|
|
||||||
return ''.join(filenameTokens)
|
|
||||||
|
|
||||||
def importShow(self, showId: int):
|
|
||||||
pass
|
|
||||||
@@ -47,7 +47,8 @@ class TrackDescriptor:
|
|||||||
self.__logger = self.__context['logger']
|
self.__logger = self.__context['logger']
|
||||||
else:
|
else:
|
||||||
self.__context = {}
|
self.__context = {}
|
||||||
self.__logger = logging.getLogger('FFX').addHandler(logging.NullHandler())
|
self.__logger = logging.getLogger('FFX')
|
||||||
|
self.__logger.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
if TrackDescriptor.ID_KEY in kwargs.keys():
|
if TrackDescriptor.ID_KEY in kwargs.keys():
|
||||||
if type(kwargs[TrackDescriptor.ID_KEY]) is not int:
|
if type(kwargs[TrackDescriptor.ID_KEY]) is not int:
|
||||||
|
|||||||
Reference in New Issue
Block a user