From 303fd4bc80dd65bb0d289bbbaab367f54fd4aeb7 Mon Sep 17 00:00:00 2001 From: Maveno Date: Tue, 12 Nov 2024 19:40:35 +0100 Subject: [PATCH] #387 Suffices --- .gitignore | 2 + ansible/inventory/ffx.yml | 8 +++ ansible/setup_node.yml | 113 +++++++++++++++++++++++++++++++++++++ bin/ffx.py | 79 +++++++++++++++++++------- bin/ffx/ffx_controller.py | 16 +++--- bin/ffx/file_properties.py | 50 ---------------- 6 files changed, 190 insertions(+), 78 deletions(-) create mode 100644 ansible/inventory/ffx.yml create mode 100644 ansible/setup_node.yml diff --git a/.gitignore b/.gitignore index d158bc5..2c416ef 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ __pycache__ junk/ .vscode .ipynb_checkpoints/ +ansible/inventory/hawaii.yml +ansible/inventory/peppermint.yml diff --git a/ansible/inventory/ffx.yml b/ansible/inventory/ffx.yml new file mode 100644 index 0000000..08c969e --- /dev/null +++ b/ansible/inventory/ffx.yml @@ -0,0 +1,8 @@ +all: + hosts: + ffx: + ansible_host: + ansible_user: + + ffxSystemUsername: + ffxHomeDirectory: diff --git a/ansible/setup_node.yml b/ansible/setup_node.yml new file mode 100644 index 0000000..c6da0b9 --- /dev/null +++ b/ansible/setup_node.yml @@ -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="" + + - 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 diff --git a/bin/ffx.py b/bin/ffx.py index 3bc0710..0bc86ca 100755 --- a/bin/ffx.py +++ b/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) diff --git a/bin/ffx/ffx_controller.py b/bin/ffx/ffx_controller.py index 8e6756c..a05074f 100644 --- a/bin/ffx/ffx_controller.py +++ b/bin/ffx/ffx_controller.py @@ -112,9 +112,12 @@ class FfxController(): return ['-ss', str(cropStart), '-t', str(cropLength)] - def generateOutputTokens(self, filepath, format, ext): - outputFilePath = f"{filepath}.{ext}" - return ['-f', format, outputFilePath] + 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)}") diff --git a/bin/ffx/file_properties.py b/bin/ffx/file_properties.py index 9af0220..d9f25be 100644 --- a/bin/ffx/file_properties.py +++ b/bin/ffx/file_properties.py @@ -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