nightl test-scenarios krude
parent
24d0700db2
commit
ad58ba5ce6
@ -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…
Reference in New Issue