nightl test-scenarios krude

click-textual
Maveno 11 months ago
parent 24d0700db2
commit ad58ba5ce6

@ -31,11 +31,12 @@ VERSION='0.1.3'
@click.group()
@click.pass_context
def ffx(ctx):
@click.option('--database-file', type=str, default='', help='Path to database file')
def ffx(ctx, database_file):
"""FFX"""
ctx.obj = {}
ctx.obj['database'] = databaseContext()
ctx.obj['database'] = databaseContext(databasePath=database_file)
# Define a subcommand

@ -11,17 +11,21 @@ from ffx.model.media_tag import MediaTag
from ffx.model.track_tag import TrackTag
def databaseContext():
def databaseContext(databasePath: str = ''):
"""sqlite:///:memory:"""
databaseContext = {}
# Initialize DB
homeDir = os.path.expanduser("~")
ffxVarDir = os.path.join(homeDir, '.local', 'var', 'ffx')
if not os.path.exists(ffxVarDir):
os.makedirs(ffxVarDir)
if databasePath is None:
databasePath = ':memory:'
elif not databasePath:
homeDir = os.path.expanduser("~")
ffxVarDir = os.path.join(homeDir, '.local', 'var', 'ffx')
if not os.path.exists(ffxVarDir):
os.makedirs(ffxVarDir)
databasePath = os.path.join(ffxVarDir, 'ffx.db')
databaseContext['url'] = f"sqlite:///{os.path.join(ffxVarDir, 'ffx.db')}"
databaseContext['url'] = f"sqlite:///{databasePath}"
databaseContext['engine'] = create_engine(databaseContext['url'])
databaseContext['session'] = sessionmaker(bind=databaseContext['engine'])

@ -456,3 +456,27 @@ class FfxController():
if rc:
raise click.ClickException(f"Command resulted in error: rc={rc} error={err}")
def createEmptyFile(self,
path: str = 'output.mp4',
sizeX: int = 1280,
sizeY: int = 720,
rate: int = 25,
length: int = 10):
commandTokens = FfxController.COMMAND_TOKENS
commandTokens += ['-f',
'lavfi',
'-i',
f"color=size={sizeX}x{sizeY}:rate={rate}:color=black",
'-f',
'lavfi',
'-i',
'anullsrc=channel_layout=stereo:sample_rate=44100',
'-t',
str(length),
path]
out, err, rc = executeProcess(commandTokens)

@ -0,0 +1,191 @@
import os, math, tempfile
from ffx.process import executeProcess
def getTimeString(hours: float = 0.0,
minutes: float = 0.0,
seconds: float = 0.0,
millis: float = 0.0,
format: str = ''):
duration = (hours * 3600.0
+ minutes * 60.0
+ seconds
+ millis / 1000.0)
hours = math.floor(duration / 3600.0)
remaining = duration - 3600.0 * hours
minutes = math.floor(remaining / 60.0)
remaining = remaining - 60.0 * minutes
seconds = math.floor(remaining)
remaining = remaining - seconds
millis = math.floor(remaining * 1000)
if format == 'ass':
return f"{hours:01d}:{minutes:02d}:{seconds:02d}.{millis:02d}"
# srt & vtt
return f"{hours:02d}:{minutes:02d}:{seconds:02d}.{millis:03d}"
def createAssFile(entries: dict):
# [Script Info]
# ; Script generated by FFmpeg/Lavc61.3.100
# ScriptType: v4.00+
# PlayResX: 384
# PlayResY: 288
# ScaledBorderAndShadow: yes
# YCbCr Matrix: None
#
# [V4+ Styles]
# Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
# Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,1
#
# [Events]
# Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
# Dialogue: 0,0:00:01.00,0:00:02.00,Default,,0,0,0,,yolo
# Dialogue: 0,0:00:03.00,0:00:04.00,Default,,0,0,0,,zolo
# Dialogue: 0,0:00:05.00,0:00:06.00,Default,,0,0,0,,golo
tmpFileName = tempfile.mktemp(suffix=".ass")
with open(tmpFileName, 'w') as tmpFile:
tmpFile.write("[Script Info]\n")
tmpFile.write("; Script generated by Ffx\n")
tmpFile.write("ScriptType: v4.00+\n")
tmpFile.write("PlayResX: 384\n")
tmpFile.write("PlayResY: 288\n")
tmpFile.write("ScaledBorderAndShadow: yes\n")
tmpFile.write("YCbCr Matrix: None\n")
tmpFile.write("\n")
tmpFile.write("[V4+ Styles]\n")
tmpFile.write("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n")
tmpFile.write("Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,1\n")
tmpFile.write("\n")
tmpFile.write("[Events]\n")
tmpFile.write("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n")
for entryIndex in range(len(entries)):
tmpFile.write(f"Dialogue: 0,{getTimeString(seconds=entries[entryIndex]['start'], format='ass')},{getTimeString(seconds=entries[entryIndex]['end'], format='ass')},Default,,0,0,0,,{entries[entryIndex]['text']}\n")
return tmpFileName
def createSrtFile(entries: dict):
# 1
# 00:00:00,000 --> 00:00:02,500
# Welcome to the Example Subtitle File!
#
# 2
# 00:00:03,000 --> 00:00:06,000
# This is a demonstration of SRT subtitles.
#
# 3
# 00:00:07,000 --> 00:00:10,500
# You can use SRT files to add subtitles to your videos.
tmpFileName = tempfile.mktemp(suffix=".srt")
with open(tmpFileName, 'w') as tmpFile:
for entryIndex in range(len(entries)):
tmpFile.write(f"{entryIndex}\n")
tmpFile.write(f"{getTimeString(seconds=entries[entryIndex]['start'])} --> {getTimeString(seconds=entries[entryIndex]['end'])}\n")
tmpFile.write(f"{entries[entryIndex]['text']}\n\n")
return tmpFileName
def createVttFile(entries: dict):
# WEBVTT
#
# 01:20:33.050 --> 01:20:35.050
# Yolo
tmpFileName = tempfile.mktemp(suffix=".vtt")
with open(tmpFileName, 'w') as tmpFile:
tmpFile.write("WEBVTT\n")
for entryIndex in range(len(entries)):
tmpFile.write("\n")
tmpFile.write(f"{getTimeString(seconds=entries[entryIndex]['start'])} --> {getTimeString(seconds=entries[entryIndex]['end'])}\n")
tmpFile.write(f"{entries[entryIndex]['text']}\n")
return tmpFileName
def createMediaFile(directory: str = '',
baseName: str = 'media',
format: str = '',
extension: str = 'mkv',
sizeX: int = 1280,
sizeY: int = 720,
rate: int = 25,
length: int = 10):
# subtitleContent = []
# subtitleContent.append({'start': 1, 'end': 2, 'text': 'yolo'})
# subtitleContent.append({'start': 3, 'end': 4, 'text': 'zolo'})
# subtitleContent.append({'start': 5, 'end': 6, 'text': 'golo'})
# subtitleFilePath = createVttFile(subtitleContent)
# commandTokens = FfxController.COMMAND_TOKENS
commandTokens = ['ffmpeg', '-y']
commandTokens += ['-f',
'lavfi',
'-i',
f"color=size={sizeX}x{sizeY}:rate={rate}:color=black"]
commandTokens += ['-f',
'lavfi',
'-i',
'anullsrc=channel_layout=stereo:sample_rate=44100']
# '-i',
# subtitleFilePath,
commandTokens += ['-map', '0:v:0']
#'-map', '0:v:0',
commandTokens += ['-map', '1:a:0']
commandTokens += ['-map', '1:a:0']
# '-map', '2:s:0',
# '-c:s', 'webvtt',
commandTokens += ['-t', str(length)]
if format:
commandTokens += ['-f', format]
fileName = f"{baseName}.{extension}"
if directory:
outputPath = os.path.join(directory, fileName)
else:
outputPath = fileName
commandTokens += [outputPath]
print(f"command sequence: {commandTokens}")
out, err, rc = executeProcess(commandTokens)
if rc:
print(f"Creating testfile failed with {rc}: {err}")
def createEmptyDirectory():
return tempfile.mkdtemp()
def createEmptyFile(suffix=None):
return tempfile.mkstemp(suffix=suffix)

@ -0,0 +1,26 @@
import os, sys, importlib, glob, inspect
from ffx.test.helper import createEmptyDirectory
class Scenario():
def __init__(self):
self._testDirectory = createEmptyDirectory()
@staticmethod
def list():
basePath = os.path.dirname(__file__)
return [int(os.path.basename(p)[8:-3])
for p
in glob.glob(f"{ basePath }/scenario*.py", recursive = True)
if p != __file__]
@staticmethod
def getClassReference(identifier):
importlib.import_module(f"ffx.test.scenario{ identifier }")
for name, obj in inspect.getmembers(sys.modules[f"ffx.test.scenario{ identifier }"]):
if inspect.isclass(obj) and name == f"Scenario{identifier}":
return obj

@ -0,0 +1,23 @@
import click
from .scenario import Scenario
from ffx.test.helper import createMediaFile
class Scenario1(Scenario):
"""Creating file VAa, h264/aac/aac
Converting to VaA, vp9/opus/opus
No tmdb, default parameters"""
def __init__(self):
super().__init__()
def i_am(self):
return 1
def run(self):
click.echo(f"Running scenario 1")
createMediaFile(directory=self._testDirectory)

@ -0,0 +1,12 @@
from .scenario import Scenario
class Scenario2(Scenario):
def __init__(self):
super().__init__()
def run(self):
pass
# self._testDirectory
#createMediaFile()

@ -0,0 +1,12 @@
from .scenario import Scenario
class Scenario3(Scenario):
def __init__(self):
super().__init__()
def run(self):
pass
# self._testDirectory
#createMediaFile()

@ -0,0 +1,80 @@
#! /usr/bin/python3
import os, sys, subprocess, json, click, time, re, tempfile, math
from datetime import datetime, timedelta
from ffx.file_properties import FileProperties
from ffx.ffx_app import FfxApp
from ffx.ffx_controller import FfxController
from ffx.show_controller import ShowController
from ffx.tmdb_controller import TmdbController
from ffx.database import databaseContext
from ffx.track_descriptor import TrackDescriptor
from ffx.track_type import TrackType
from ffx.video_encoder import VideoEncoder
from ffx.track_disposition import TrackDisposition
from ffx.process import executeProcess
from ffx.test.helper import createMediaFile
from ffx.test.scenario import Scenario
VERSION='0.1.0'
# 0.1.1
# Bugfixes, TMBD identify shows
# 0.1.2
# Bugfixes
# 0.1.3
# Subtitle file imports
@click.group()
@click.pass_context
def ffx(ctx):
"""FFX"""
ctx.obj = {}
ctx.obj['database'] = databaseContext(databasePath=None)
# Define a subcommand
@ffx.command()
def version():
click.echo(VERSION)
# Another subcommand
@ffx.command()
def help():
click.echo(f"ffx tests {VERSION}\n")
click.echo(f"Usage: ffx_test ...")
# @ffx.command()
# def show():
# for i in Scenario().list():
# click.echo(i)
# Another subcommand
@ffx.command()
def run():
"""Run ffx test sequences"""
for scenarioIndex in Scenario().list():
scenario = Scenario().getClassReference(scenarioIndex)()
click.echo(f"Running scenario {scenarioIndex}")
scenario.run()
if __name__ == '__main__':
ffx()
Loading…
Cancel
Save