#387 Suffices
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,3 +2,5 @@ __pycache__
|
||||
junk/
|
||||
.vscode
|
||||
.ipynb_checkpoints/
|
||||
ansible/inventory/hawaii.yml
|
||||
ansible/inventory/peppermint.yml
|
||||
|
||||
8
ansible/inventory/ffx.yml
Normal file
8
ansible/inventory/ffx.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
all:
|
||||
hosts:
|
||||
ffx:
|
||||
ansible_host: <domain>
|
||||
ansible_user: <system user>
|
||||
|
||||
ffxSystemUsername: <system user>
|
||||
ffxHomeDirectory: <home directory>
|
||||
113
ansible/setup_node.yml
Normal file
113
ansible/setup_node.yml
Normal file
@@ -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
|
||||
77
bin/ffx.py
77
bin/ffx.py
@@ -374,6 +374,10 @@ def convert(ctx,
|
||||
|
||||
context['video_encoder'] = VideoEncoder.fromLabel(video_encoder)
|
||||
|
||||
targetFormat = FfxController.DEFAULT_FILE_FORMAT
|
||||
targetExtension = FfxController.DEFAULT_FILE_EXTENSION
|
||||
|
||||
|
||||
#TODO: #407 Without effect -> remove
|
||||
context['use_jellyfin'] = False
|
||||
|
||||
@@ -510,14 +514,24 @@ def convert(ctx,
|
||||
|
||||
ctx.obj['logger'].info(f"\nProcessing file {sourcePath}")
|
||||
|
||||
targetSuffices = {}
|
||||
|
||||
|
||||
mediaFileProperties = FileProperties(context, sourceFilename)
|
||||
|
||||
|
||||
#HINT: -1 if not set
|
||||
showSeason = (cliOverrides['tmdb']['season'] if 'tmdb' in cliOverrides.keys()
|
||||
and 'season' in cliOverrides['tmdb'] else mediaFileProperties.getSeason())
|
||||
showEpisode = (cliOverrides['tmdb']['episode'] if 'tmdb' in cliOverrides.keys()
|
||||
and 'episode' in cliOverrides['tmdb'] else mediaFileProperties.getEpisode())
|
||||
if 'tmdb' in cliOverrides.keys() and 'season' in cliOverrides['tmdb']:
|
||||
showSeason = cliOverrides['tmdb']['season']
|
||||
else:
|
||||
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}")
|
||||
|
||||
|
||||
@@ -568,6 +582,12 @@ def convert(ctx,
|
||||
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
|
||||
#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())
|
||||
@@ -580,16 +600,8 @@ def convert(ctx,
|
||||
sName, showYear = tc.getShowNameAndYear(showId)
|
||||
showName = filterFilename(sName)
|
||||
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:
|
||||
showFilenamePrefix = currentShowDescriptor.getFilenamePrefix()
|
||||
indexSeasonDigits = currentShowDescriptor.getIndexSeasonDigits()
|
||||
indexEpisodeDigits = currentShowDescriptor.getIndexEpisodeDigits()
|
||||
indicatorSeasonDigits = currentShowDescriptor.getIndicatorSeasonDigits()
|
||||
indicatorEpisodeDigits = currentShowDescriptor.getIndicatorEpisodeDigits()
|
||||
|
||||
tmdbEpisodeResult = tc.queryEpisode(showId, showSeason, showEpisode)
|
||||
|
||||
@@ -607,34 +619,59 @@ def convert(ctx,
|
||||
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}")
|
||||
|
||||
|
||||
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}")
|
||||
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"sourceFileBasename={sourceFileBasename}")
|
||||
|
||||
targetFileBasename = mediaFileProperties.assembleTargetFileBasename(label,
|
||||
q if len(q_list) > 1 else -1,
|
||||
extraTokens = extra)
|
||||
# targetFileBasename = mediaFileProperties.assembleTargetFileBasename(label,
|
||||
# q if len(q_list) > 1 else -1,
|
||||
#
|
||||
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
|
||||
targetFilename = ((f"{sourceFileBasename}_q{q}" if len(q_list) > 1 else sourceFileBasename)
|
||||
if context['use_tmdb'] else targetFileBasename)
|
||||
# targetFilename = ((f"{sourceFileBasename}_q{q}" if len(q_list) > 1 else sourceFileBasename)
|
||||
# if context['use_tmdb'] else targetFileBasename)
|
||||
|
||||
targetFilename = f"{'_'.join(targetFilenameTokens)}.{targetExtension}"
|
||||
|
||||
targetPath = os.path.join(output_directory if output_directory else sourceDirectory, targetFilename)
|
||||
|
||||
#TODO: target extension anpassen
|
||||
ctx.obj['logger'].info(f"Creating file {targetFilename}.webm")
|
||||
ctx.obj['logger'].info(f"Creating file {targetFilename}")
|
||||
|
||||
fc.runJob(sourcePath,
|
||||
targetPath,
|
||||
targetFormat,
|
||||
context['video_encoder'],
|
||||
q,
|
||||
preset)
|
||||
|
||||
@@ -112,9 +112,12 @@ class FfxController():
|
||||
return ['-ss', str(cropStart), '-t', str(cropLength)]
|
||||
|
||||
|
||||
def generateOutputTokens(self, filepath, format, ext):
|
||||
outputFilePath = f"{filepath}.{ext}"
|
||||
def generateOutputTokens(self, filePathBase, format = '', ext = ''):
|
||||
outputFilePath = f"{filePathBase}{'.'+str(ext) if ext else ''}"
|
||||
if format:
|
||||
return ['-f', format, outputFilePath]
|
||||
else:
|
||||
return [outputFilePath]
|
||||
|
||||
|
||||
def generateAudioEncodingTokens(self):
|
||||
@@ -245,6 +248,7 @@ class FfxController():
|
||||
def runJob(self,
|
||||
sourcePath,
|
||||
targetPath,
|
||||
targetFormat: str = '',
|
||||
videoEncoder: VideoEncoder = VideoEncoder.VP9,
|
||||
quality: int = DEFAULT_QUALITY,
|
||||
preset: int = DEFAULT_AV1_PRESET):
|
||||
@@ -271,8 +275,7 @@ class FfxController():
|
||||
commandSequence += FfxController.generateCropTokens()
|
||||
|
||||
commandSequence += self.generateOutputTokens(targetPath,
|
||||
FfxController.DEFAULT_FILE_FORMAT,
|
||||
FfxController.DEFAULT_FILE_EXTENSION)
|
||||
targetFormat)
|
||||
|
||||
self.__logger.debug(f"FfxController.runJob() commandSequence:{' '.join(commandSequence)}")
|
||||
|
||||
@@ -322,8 +325,7 @@ class FfxController():
|
||||
commandSequence2 += self.generateCropTokens()
|
||||
|
||||
commandSequence2 += self.generateOutputTokens(targetPath,
|
||||
FfxController.DEFAULT_FILE_FORMAT,
|
||||
FfxController.DEFAULT_FILE_EXTENSION)
|
||||
targetFormat)
|
||||
|
||||
self.__logger.debug(f"FfxController.runJob() commandSequence2:{' '.join(commandSequence2)}")
|
||||
|
||||
|
||||
@@ -209,53 +209,3 @@ class FileProperties():
|
||||
|
||||
def getFileBasename(self):
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user