main
Maveno 11 months ago
parent 5febb96916
commit 303fd4bc80

2
.gitignore vendored

@ -2,3 +2,5 @@ __pycache__
junk/ junk/
.vscode .vscode
.ipynb_checkpoints/ .ipynb_checkpoints/
ansible/inventory/hawaii.yml
ansible/inventory/peppermint.yml

@ -0,0 +1,8 @@
all:
hosts:
ffx:
ansible_host: <domain>
ansible_user: <system user>
ffxSystemUsername: <system user>
ffxHomeDirectory: <home directory>

@ -0,0 +1,113 @@
- name: Setup FFX node
hosts: all
vars:
ffxRepoUrl: https://gitea.maveno.de/Javanaut/ffx.git
tasks:
- name: Update system and install packages
become: true
ansible.builtin.apt:
name:
- python3-virtualenv
- ffmpeg
- git
- screen
update_cache: yes
- name: Create sync dir
become: true
file:
path: "{{ ffxHomeDirectory }}/.local/var/sync/ffx"
state: directory
owner: "{{ ffxSystemUsername }}"
group: "{{ ffxSystemUsername }}"
mode: 0755
- name: Ensure local etc directory
become: true
file:
path: "{{ ffxHomeDirectory }}/.local/etc"
state: directory
owner: "{{ ffxSystemUsername }}"
group: "{{ ffxSystemUsername }}"
mode: 0755
- name: Ensure local src directory
become: true
file:
path: "{{ ffxHomeDirectory }}/.local/src"
state: directory
owner: "{{ ffxSystemUsername }}"
group: "{{ ffxSystemUsername }}"
mode: 0755
- name: Ensure local share directory
become: true
file:
path: "{{ ffxHomeDirectory }}/.local/share"
state: directory
owner: "{{ ffxSystemUsername }}"
group: "{{ ffxSystemUsername }}"
mode: 0755
- name: Prepare ffx virtualenv
become: true
become_user: "{{ ffxSystemUsername }}"
ansible.builtin.pip:
name:
- click
- textual
- sqlalchemy
- requests
virtualenv: "{{ ffxHomeDirectory }}/.local/share/ffx.venv"
- name: Clone ffx repository
become: true
become_user: "{{ ffxSystemUsername }}"
ansible.builtin.git:
repo: "{{ ffxRepoUrl }}"
dest: "{{ ffxHomeDirectory }}/.local/src/ffx"
version: dev
- name: Add TMDB API token placeholer to .bashrc
become: true
become_user: "{{ ffxSystemUsername }}"
ansible.builtin.lineinfile:
path: "{{ ffxHomeDirectory }}/.bashrc"
insertbefore: BOF
line: >-
export TMDB_API_KEY="<TMDB API token>"
- name: Add ffx alias to .bashrc
become: true
become_user: "{{ ffxSystemUsername }}"
ansible.builtin.lineinfile:
path: "{{ ffxHomeDirectory }}/.bashrc"
insertbefore: BOF
line: >-
alias ffx="{{ ffxHomeDirectory }}/.local/share/ffx.venv/bin/python
{{ ffxHomeDirectory }}/.local/src/ffx/bin/ffx.py"
- name: Ensure local sync directory
become: true
file:
path: "{{ ffxHomeDirectory }}/.local/var/sync/ffx"
state: directory
owner: "{{ ffxSystemUsername }}"
group: "{{ ffxSystemUsername }}"
mode: 0755
- name: Create ffx config file
become: true
become_user: "{{ ffxSystemUsername }}"
vars:
ffxConfiguration:
databasePath: "{{ ffxHomeDirectory }}/.local/var/sync/ffx/ffx.db"
ansible.builtin.copy:
content: "{{ ffxConfiguration | to_json }}"
dest: "{{ ffxHomeDirectory }}/.local/etc/ffx.json"
owner: "{{ ffxSystemUsername }}"
group: "{{ ffxSystemUsername }}"
mode: 0644

@ -374,6 +374,10 @@ def convert(ctx,
context['video_encoder'] = VideoEncoder.fromLabel(video_encoder) context['video_encoder'] = VideoEncoder.fromLabel(video_encoder)
targetFormat = FfxController.DEFAULT_FILE_FORMAT
targetExtension = FfxController.DEFAULT_FILE_EXTENSION
#TODO: #407 Without effect -> remove #TODO: #407 Without effect -> remove
context['use_jellyfin'] = False context['use_jellyfin'] = False
@ -510,14 +514,24 @@ def convert(ctx,
ctx.obj['logger'].info(f"\nProcessing file {sourcePath}") ctx.obj['logger'].info(f"\nProcessing file {sourcePath}")
targetSuffices = {}
mediaFileProperties = FileProperties(context, sourceFilename) mediaFileProperties = FileProperties(context, sourceFilename)
#HINT: -1 if not set #HINT: -1 if not set
showSeason = (cliOverrides['tmdb']['season'] if 'tmdb' in cliOverrides.keys() if 'tmdb' in cliOverrides.keys() and 'season' in cliOverrides['tmdb']:
and 'season' in cliOverrides['tmdb'] else mediaFileProperties.getSeason()) showSeason = cliOverrides['tmdb']['season']
showEpisode = (cliOverrides['tmdb']['episode'] if 'tmdb' in cliOverrides.keys() else:
and 'episode' in cliOverrides['tmdb'] else mediaFileProperties.getEpisode()) showSeason = mediaFileProperties.getSeason()
if 'tmdb' in cliOverrides.keys() and 'episode' in cliOverrides['tmdb']:
showEpisode = cliOverrides['tmdb']['episode']
else:
showEpisode = mediaFileProperties.getEpisode()
ctx.obj['logger'].debug(f"Season={showSeason} Episode={showEpisode}") ctx.obj['logger'].debug(f"Season={showSeason} Episode={showEpisode}")
@ -568,6 +582,12 @@ def convert(ctx,
fc = FfxController(context, targetMediaDescriptor, sourceMediaDescriptor) fc = FfxController(context, targetMediaDescriptor, sourceMediaDescriptor)
indexSeasonDigits = currentShowDescriptor.getIndexSeasonDigits() if not currentPattern is None else ShowDescriptor.DEFAULT_INDEX_SEASON_DIGITS
indexEpisodeDigits = currentShowDescriptor.getIndexEpisodeDigits() if not currentPattern is None else ShowDescriptor.DEFAULT_INDEX_EPISODE_DIGITS
indicatorSeasonDigits = currentShowDescriptor.getIndicatorSeasonDigits() if not currentPattern is None else ShowDescriptor.DEFAULT_INDICATOR_SEASON_DIGITS
indicatorEpisodeDigits = currentShowDescriptor.getIndicatorEpisodeDigits() if not currentPattern is None else ShowDescriptor.DEFAULT_INDICATOR_EPISODE_DIGITS
# Assemble target filename accordingly depending on TMDB lookup is enabled # Assemble target filename accordingly depending on TMDB lookup is enabled
#HINT: -1 if not set #HINT: -1 if not set
showId = cliOverrides['tmdb']['show'] if 'tmdb' in cliOverrides.keys() and 'show' in cliOverrides['tmdb'] else (-1 if currentShowDescriptor is None else currentShowDescriptor.getId()) showId = cliOverrides['tmdb']['show'] if 'tmdb' in cliOverrides.keys() and 'show' in cliOverrides['tmdb'] else (-1 if currentShowDescriptor is None else currentShowDescriptor.getId())
@ -580,16 +600,8 @@ def convert(ctx,
sName, showYear = tc.getShowNameAndYear(showId) sName, showYear = tc.getShowNameAndYear(showId)
showName = filterFilename(sName) showName = filterFilename(sName)
showFilenamePrefix = f"{showName} ({str(showYear)})" showFilenamePrefix = f"{showName} ({str(showYear)})"
indexSeasonDigits = ShowDescriptor.DEFAULT_INDEX_SEASON_DIGITS
indexEpisodeDigits = ShowDescriptor.DEFAULT_INDEX_EPISODE_DIGITS
indicatorSeasonDigits = ShowDescriptor.DEFAULT_INDICATOR_SEASON_DIGITS
indicatorEpisodeDigits = ShowDescriptor.DEFAULT_INDICATOR_EPISODE_DIGITS
else: else:
showFilenamePrefix = currentShowDescriptor.getFilenamePrefix() showFilenamePrefix = currentShowDescriptor.getFilenamePrefix()
indexSeasonDigits = currentShowDescriptor.getIndexSeasonDigits()
indexEpisodeDigits = currentShowDescriptor.getIndexEpisodeDigits()
indicatorSeasonDigits = currentShowDescriptor.getIndicatorSeasonDigits()
indicatorEpisodeDigits = currentShowDescriptor.getIndicatorEpisodeDigits()
tmdbEpisodeResult = tc.queryEpisode(showId, showSeason, showEpisode) tmdbEpisodeResult = tc.queryEpisode(showId, showSeason, showEpisode)
@ -607,34 +619,59 @@ def convert(ctx,
indicatorEpisodeDigits) indicatorEpisodeDigits)
if label:
if showSeason > -1 and showEpisode > -1:
targetSuffices['se'] = f"S{showSeason:0{indicatorSeasonDigits}d}E{showEpisode:0{indicatorEpisodeDigits}d}"
elif showEpisode > -1:
targetSuffices['se'] = f"E{showEpisode:0{indicatorEpisodeDigits}d}"
else:
if 'se' in targetSuffices.keys():
del targetSuffices['se']
ctx.obj['logger'].debug(f"fileBasename={sourceFileBasename}") ctx.obj['logger'].debug(f"fileBasename={sourceFileBasename}")
for q in q_list: for q in q_list:
if len(q_list) > 1:
targetSuffices['q'] = f"q{q}"
ctx.obj['logger'].debug(f"\nRunning job {jobIndex} file={sourcePath} q={q}") ctx.obj['logger'].debug(f"\nRunning job {jobIndex} file={sourcePath} q={q}")
jobIndex += 1 jobIndex += 1
extra = ['ffx'] if sourceFilenameExtension == FfxController.DEFAULT_FILE_EXTENSION else []
ctx.obj['logger'].debug(f"label={label if label else 'Falsy'}") ctx.obj['logger'].debug(f"label={label if label else 'Falsy'}")
ctx.obj['logger'].debug(f"sourceFileBasename={sourceFileBasename}") ctx.obj['logger'].debug(f"sourceFileBasename={sourceFileBasename}")
targetFileBasename = mediaFileProperties.assembleTargetFileBasename(label, # targetFileBasename = mediaFileProperties.assembleTargetFileBasename(label,
q if len(q_list) > 1 else -1, # q if len(q_list) > 1 else -1,
extraTokens = extra) #
targetFileBasename = sourceFileBasename if context['use_tmdb'] and not label else label
targetFilenameTokens = [targetFileBasename]
if 'se' in targetSuffices.keys():
targetFilenameTokens += [targetSuffices['se']]
if 'q' in targetSuffices.keys():
targetFilenameTokens += [targetSuffices['q']]
#TODO #387 #TODO #387
targetFilename = ((f"{sourceFileBasename}_q{q}" if len(q_list) > 1 else sourceFileBasename) # targetFilename = ((f"{sourceFileBasename}_q{q}" if len(q_list) > 1 else sourceFileBasename)
if context['use_tmdb'] else targetFileBasename) # if context['use_tmdb'] else targetFileBasename)
targetFilename = f"{'_'.join(targetFilenameTokens)}.{targetExtension}"
targetPath = os.path.join(output_directory if output_directory else sourceDirectory, targetFilename) targetPath = os.path.join(output_directory if output_directory else sourceDirectory, targetFilename)
#TODO: target extension anpassen #TODO: target extension anpassen
ctx.obj['logger'].info(f"Creating file {targetFilename}.webm") ctx.obj['logger'].info(f"Creating file {targetFilename}")
fc.runJob(sourcePath, fc.runJob(sourcePath,
targetPath, targetPath,
targetFormat,
context['video_encoder'], context['video_encoder'],
q, q,
preset) preset)

@ -112,9 +112,12 @@ class FfxController():
return ['-ss', str(cropStart), '-t', str(cropLength)] return ['-ss', str(cropStart), '-t', str(cropLength)]
def generateOutputTokens(self, filepath, format, ext): def generateOutputTokens(self, filePathBase, format = '', ext = ''):
outputFilePath = f"{filepath}.{ext}" outputFilePath = f"{filePathBase}{'.'+str(ext) if ext else ''}"
if format:
return ['-f', format, outputFilePath] return ['-f', format, outputFilePath]
else:
return [outputFilePath]
def generateAudioEncodingTokens(self): def generateAudioEncodingTokens(self):
@ -245,6 +248,7 @@ class FfxController():
def runJob(self, def runJob(self,
sourcePath, sourcePath,
targetPath, targetPath,
targetFormat: str = '',
videoEncoder: VideoEncoder = VideoEncoder.VP9, videoEncoder: VideoEncoder = VideoEncoder.VP9,
quality: int = DEFAULT_QUALITY, quality: int = DEFAULT_QUALITY,
preset: int = DEFAULT_AV1_PRESET): preset: int = DEFAULT_AV1_PRESET):
@ -271,8 +275,7 @@ class FfxController():
commandSequence += FfxController.generateCropTokens() commandSequence += FfxController.generateCropTokens()
commandSequence += self.generateOutputTokens(targetPath, commandSequence += self.generateOutputTokens(targetPath,
FfxController.DEFAULT_FILE_FORMAT, targetFormat)
FfxController.DEFAULT_FILE_EXTENSION)
self.__logger.debug(f"FfxController.runJob() commandSequence:{' '.join(commandSequence)}") self.__logger.debug(f"FfxController.runJob() commandSequence:{' '.join(commandSequence)}")
@ -322,8 +325,7 @@ class FfxController():
commandSequence2 += self.generateCropTokens() commandSequence2 += self.generateCropTokens()
commandSequence2 += self.generateOutputTokens(targetPath, commandSequence2 += self.generateOutputTokens(targetPath,
FfxController.DEFAULT_FILE_FORMAT, targetFormat)
FfxController.DEFAULT_FILE_EXTENSION)
self.__logger.debug(f"FfxController.runJob() commandSequence2:{' '.join(commandSequence2)}") self.__logger.debug(f"FfxController.runJob() commandSequence2:{' '.join(commandSequence2)}")

@ -209,53 +209,3 @@ class FileProperties():
def getFileBasename(self): def getFileBasename(self):
return self.__sourceFileBasename return self.__sourceFileBasename
def assembleTargetFileBasename(self,
label: str = "",
quality: int = -1,
fileIndex: int = -1,
indexDigits: int = DEFAULT_INDEX_DIGITS,
extraTokens: list = []):
if 'show_descriptor' in self.context.keys():
season_digits = self.context['show_descriptor'][ShowDescriptor.INDICATOR_SEASON_DIGITS_KEY]
episode_digits = self.context['show_descriptor'][ShowDescriptor.INDICATOR_EPISODE_DIGITS_KEY]
else:
season_digits = ShowDescriptor.DEFAULT_INDICATOR_SEASON_DIGITS
episode_digits = ShowDescriptor.DEFAULT_INDICATOR_EPISODE_DIGITS
targetFilenameTokens = []
# targetFilenameExtension = FfxController.DEFAULT_FILE_EXTENSION if extension is None else str(extension)
self.__logger.debug(f"assembleTargetFileBasename(): label={label} is {'truthy' if label else 'falsy'}")
if label:
targetFilenameTokens = [label]
if fileIndex > -1:
targetFilenameTokens += [f"{fileIndex:0{indexDigits}d}"]
elif self.__season > -1 and self.__episode > -1:
targetFilenameTokens += [f"S{self.__season:0{season_digits}d}E{self.__episode:0{episode_digits}d}"]
elif self.__episode > -1:
targetFilenameTokens += [f"E{self.__episode:0{episode_digits}d}"]
else:
targetFilenameTokens = [self.__sourceFileBasename]
if quality != -1:
targetFilenameTokens += [f"q{quality}"]
# In case source and target filenames are the same add an extension to distinct output from input
#if not label and self.__sourceFilenameExtension == targetFilenameExtension:
# targetFilenameTokens += ['ffx']
targetFilenameTokens += extraTokens
targetFilename = '_'.join(targetFilenameTokens)
self.__logger.debug(f"assembleTargetFileBasename(): Target filename: {targetFilename}")
return targetFilename

Loading…
Cancel
Save