better advanced config form
This commit is contained in:
parent
7f7ca6a237
commit
53b2fd442b
@ -5,11 +5,13 @@ use serde_with::{serde_as, NoneAsEmptyString};
|
||||
use shlex::split;
|
||||
use sqlx::{Pool, Sqlite};
|
||||
use tokio::io::AsyncReadExt;
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::db::{handles, models::AdvancedConfiguration};
|
||||
use crate::utils::ServiceError;
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, TS)]
|
||||
#[ts(export, export_to = "advanced_config.d.ts")]
|
||||
pub struct AdvancedConfig {
|
||||
pub decoder: DecoderConfig,
|
||||
pub encoder: EncoderConfig,
|
||||
@ -18,81 +20,115 @@ pub struct AdvancedConfig {
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, TS)]
|
||||
#[ts(export, export_to = "advanced_config.d.ts")]
|
||||
pub struct DecoderConfig {
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub input_param: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub output_param: Option<String>,
|
||||
#[ts(skip)]
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
pub input_cmd: Option<Vec<String>>,
|
||||
#[ts(skip)]
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
pub output_cmd: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, TS)]
|
||||
#[ts(export, export_to = "advanced_config.d.ts")]
|
||||
pub struct EncoderConfig {
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub input_param: Option<String>,
|
||||
#[ts(skip)]
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
pub input_cmd: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, TS)]
|
||||
#[ts(export, export_to = "advanced_config.d.ts")]
|
||||
pub struct IngestConfig {
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub input_param: Option<String>,
|
||||
#[ts(skip)]
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
pub input_cmd: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, TS)]
|
||||
#[ts(export, export_to = "advanced_config.d.ts")]
|
||||
pub struct FilterConfig {
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub deinterlace: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub pad_scale_w: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub pad_scale_h: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub pad_video: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub fps: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub scale: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub set_dar: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub fade_in: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub fade_out: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub overlay_logo_scale: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub overlay_logo_fade_in: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub overlay_logo_fade_out: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub overlay_logo: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub tpad: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub drawtext_from_file: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub drawtext_from_zmq: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub aevalsrc: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub afade_in: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub afade_out: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub apad: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub volume: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub split: Option<String>,
|
||||
}
|
||||
|
@ -454,8 +454,7 @@ pub struct Storage {
|
||||
pub filler_path: PathBuf,
|
||||
pub extensions: Vec<String>,
|
||||
pub shuffle: bool,
|
||||
#[ts(skip)]
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
#[serde(skip_deserializing)]
|
||||
pub shared_storage: bool,
|
||||
}
|
||||
|
||||
@ -490,7 +489,6 @@ pub struct Text {
|
||||
#[ts(skip)]
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
pub zmq_server_socket: Option<String>,
|
||||
#[ts(rename = "font")]
|
||||
#[serde(alias = "fontfile")]
|
||||
pub font: String,
|
||||
#[ts(skip)]
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="min-w-[200px] pe-8 w-[768px]">
|
||||
<div class="max-w-[1200px] xs:pe-8">
|
||||
<h2 class="pt-3 text-3xl">{{ t('advanced.title') }}</h2>
|
||||
<p class="mt-5 font-bold text-orange-500">{{ t('advanced.warning') }}</p>
|
||||
<form
|
||||
@ -7,26 +7,417 @@
|
||||
class="mt-10 grid md:grid-cols-[180px_auto] gap-5"
|
||||
@submit.prevent="onSubmitAdvanced"
|
||||
>
|
||||
<template v-for="(item, key) in configStore.advanced" :key="key">
|
||||
<div class="text-xl pt-3 text-right">{{ setTitle(key.toString()) }}:</div>
|
||||
<div class="md:pt-4">
|
||||
<label
|
||||
v-for="(_, name) in (item as Record<string, any>)"
|
||||
:key="name"
|
||||
class="form-control w-full"
|
||||
>
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">{{ name }}</span>
|
||||
</div>
|
||||
<input
|
||||
:id="name"
|
||||
v-model="item[name]"
|
||||
type="text"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<div class="text-xl pt-3 md:text-right">{{ t('advanced.decoder') }}:</div>
|
||||
<div class="md:pt-4">
|
||||
<label class="form-control mb-2">
|
||||
<div class="whitespace-pre-line">
|
||||
In streaming mode, the decoder settings are responsible for unifying the media files.
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Input Parameter</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.decoder.input_param"
|
||||
type="text"
|
||||
name="input_param"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Output Parameter</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.decoder.output_param"
|
||||
type="text"
|
||||
name="output_param"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">
|
||||
Default: -c:v mpeg2video -g 1 -b:v 57600k -minrate 57600k -maxrate 57600k -bufsize 28800k
|
||||
-mpegts_flags initial_discontinuity -c:a s302m -strict -2 -sample_fmt s16 -ar 48000 -ac 2 -f
|
||||
mpegts
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="text-xl pt-3 md:text-right">{{ t('advanced.encoder') }}:</div>
|
||||
<div class="md:pt-4">
|
||||
<label class="form-control mb-2">
|
||||
<div class="whitespace-pre-line">Encoder settings representing the streaming output.</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Input Parameter</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.encoder.input_param"
|
||||
type="text"
|
||||
name="input_param"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="text-xl pt-3 md:text-right">{{ t('advanced.filter') }}:</div>
|
||||
<div class="md:pt-4">
|
||||
<label class="form-control mb-2">
|
||||
<div class="whitespace-pre-line">
|
||||
The filters are mainly there to transform audio and video into the correct format, but also to
|
||||
place text and logo over the video, create in/out fade etc.<br />
|
||||
|
||||
If curly brackets are included in the default values, these must be adopted.<br />
|
||||
|
||||
If a filter is not compatible and you know that it is not absolutely necessary to use it, add
|
||||
null/anull.
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Deinterlace</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.deinterlace"
|
||||
type="text"
|
||||
name="deinterlace"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">Default: yadif=0:-1:0 </span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Pad Scaling Width</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.pad_scale_w"
|
||||
type="text"
|
||||
name="pad_scale_w"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80"> Default: scale={}:-1 </span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Pad Scaling Height</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.pad_scale_h"
|
||||
type="text"
|
||||
name="pad_scale_h"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80"> Default: scale=-1:{} </span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Pad Video</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.pad_video"
|
||||
type="text"
|
||||
name="pad_video"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">
|
||||
Default: pad=max(iw\\,ih*({0}/{1})):ow/({0}/{1}):(ow-iw)/2:(oh-ih)/2
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">FPS</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.fps"
|
||||
type="text"
|
||||
name="fps"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80"> Default: fps={} </span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Scale</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.scale"
|
||||
type="text"
|
||||
name="scale"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80"> Default: scale={}:{} </span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Set Dar</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.set_dar"
|
||||
type="text"
|
||||
name="set_dar"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80"> Default: setdar=dar={} </span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Fade In</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.fade_in"
|
||||
type="text"
|
||||
name="fade_in"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80"> Default: fade=in:st=0:d=0.5 </span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Fade Out</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.fade_out"
|
||||
type="text"
|
||||
name="fade_out"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80"> Default: fade=out:st={}:d=1.0 </span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Logo Scale</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.overlay_logo_scale"
|
||||
type="text"
|
||||
name="overlay_logo_scale"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80"> Default: scale={} </span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Logo Fade In</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.overlay_logo_fade_in"
|
||||
type="text"
|
||||
name="overlay_logo_fade_in"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">
|
||||
Default: fade=in:st=0:d=1.0:alpha=1
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Logo Fade Out</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.overlay_logo_fade_out"
|
||||
type="text"
|
||||
name="overlay_logo_fade_out"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">
|
||||
Default: fade=out:st={}:d=1.0:alpha=1
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Logo Overlay</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.overlay_logo"
|
||||
type="text"
|
||||
name="overlay_logo"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">
|
||||
Default: null[l];[v][l]overlay={}:shortest=1
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">TPad</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.tpad"
|
||||
type="text"
|
||||
name="tpad"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">
|
||||
Default: tpad=stop_mode=add:stop_duration={}
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Drawtext from File</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.drawtext_from_file"
|
||||
type="text"
|
||||
name="drawtext_from_file"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80"> Default: drawtext=text='{}':{}{} </span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Drawtext from ZMQ</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.drawtext_from_zmq"
|
||||
type="text"
|
||||
name="drawtext_from_zmq"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">
|
||||
Default: zmq=b=tcp\\\\://'{}',drawtext@dyntext={}
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Audio Source</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.aevalsrc"
|
||||
type="text"
|
||||
name="aevalsrc"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80 break-all">
|
||||
Default: aevalsrc=0:channel_layout=stereo:duration={}:sample_rate=48000
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Audio Fade In</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.afade_in"
|
||||
type="text"
|
||||
name="afade_in"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80"> Default: afade=in:st=0:d=0.5 </span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Audio Fade Out</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.afade_out"
|
||||
type="text"
|
||||
name="afade_out"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80"> Default: afade=out:st={}:d=1.0 </span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Audio Pad</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.apad"
|
||||
type="text"
|
||||
name="apad"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80"> Default: apad=whole_dur={} </span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Volumen</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.volume"
|
||||
type="text"
|
||||
name="volume"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80"> Default: volume={} </span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Split</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.filter.split"
|
||||
type="text"
|
||||
name="split"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80"> Default: split={}{} </span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="text-xl pt-3 md:text-right">{{ t('advanced.ingest') }}:</div>
|
||||
<div class="md:pt-4">
|
||||
<label class="form-control mb-2">
|
||||
<div class="whitespace-pre-line">Ingest settings are for live streaming input.</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Input Parameter</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="configStore.advanced.ingest.input_param"
|
||||
type="text"
|
||||
name="input_param"
|
||||
class="input input-sm input-bordered w-full"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="mt-5 mb-10">
|
||||
<button class="btn btn-primary" type="submit">{{ t('config.save') }}</button>
|
||||
</div>
|
||||
@ -50,21 +441,6 @@ const indexStore = useIndex()
|
||||
|
||||
const showModal = ref(false)
|
||||
|
||||
function setTitle(input: string): string {
|
||||
switch (input) {
|
||||
case 'decoder':
|
||||
return t('advanced.decoder')
|
||||
case 'encoder':
|
||||
return t('advanced.encoder')
|
||||
case 'filter':
|
||||
return t('advanced.filter')
|
||||
case 'ingest':
|
||||
return t('advanced.ingest')
|
||||
default:
|
||||
return input
|
||||
}
|
||||
}
|
||||
|
||||
async function onSubmitAdvanced() {
|
||||
const update = await configStore.setAdvancedConfig()
|
||||
configStore.onetimeInfo = true
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="max-w-[1200px] pe-8">
|
||||
<div class="max-w-[1200px] xs:pe-8">
|
||||
<h2 class="pt-3 text-3xl">{{ t('config.playoutConf') }}</h2>
|
||||
<form
|
||||
v-if="configStore.playout"
|
||||
@ -24,7 +24,7 @@
|
||||
class="input input-sm input-bordered w-full max-w-36"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="label-text-alt">{{ t('config.stopThreshold') }}</span>
|
||||
<span class="text-sm select-text text-base-content/80">{{ t('config.stopThreshold') }}</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
@ -79,7 +79,7 @@
|
||||
class="input input-sm input-bordered w-full max-w-36"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="label-text-alt">{{ t('config.mailInterval') }}</span>
|
||||
<span class="text-sm select-text text-base-content/80">{{ t('config.mailInterval') }}</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
@ -125,7 +125,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="label py-0">
|
||||
<span class="label-text-alt">{{ t('config.logDetect') }}</span>
|
||||
<span class="text-sm select-text text-base-content/80">{{ t('config.logDetect') }}</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
@ -138,7 +138,7 @@
|
||||
class="input input-sm input-bordered w-full truncate"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="label-text-alt">{{ t('config.logIgnore') }}</span>
|
||||
<span class="text-sm select-text text-base-content/80">{{ t('config.logIgnore') }}</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
@ -258,6 +258,11 @@
|
||||
type="text"
|
||||
class="input input-sm input-bordered w-full max-w-lg"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">{{
|
||||
t('config.processingLogoPath')
|
||||
}}</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
@ -281,6 +286,11 @@
|
||||
type="text"
|
||||
class="input input-sm input-bordered w-full max-w-md"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">{{
|
||||
t('config.processingLogoScale')
|
||||
}}</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
@ -291,6 +301,11 @@
|
||||
type="text"
|
||||
class="input input-sm input-bordered w-full max-w-md"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">{{
|
||||
t('config.processingLogoPosition')
|
||||
}}</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
@ -304,6 +319,11 @@
|
||||
step="1"
|
||||
class="input input-sm input-bordered w-full max-w-36"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">{{
|
||||
t('config.processingAudioTracks')
|
||||
}}</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
@ -317,6 +337,11 @@
|
||||
step="1"
|
||||
class="input input-sm input-bordered w-full max-w-36"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">{{
|
||||
t('config.processingAudioIndex')
|
||||
}}</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
@ -330,6 +355,11 @@
|
||||
step="1"
|
||||
class="input input-sm input-bordered w-full max-w-36"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">{{
|
||||
t('config.processingAudioChannels')
|
||||
}}</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="label">
|
||||
@ -353,15 +383,27 @@
|
||||
class="textarea textarea-bordered"
|
||||
rows="3"
|
||||
/>
|
||||
</label>
|
||||
<label class="form-control w-full flex-row mt-2">
|
||||
<input
|
||||
v-model="configStore.playout.processing.vtt_enable"
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm me-1 mt-2"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Enable VTT</span>
|
||||
<span class="text-sm select-text text-base-content/80">{{
|
||||
t('config.processingCustomFilter')
|
||||
}}</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="flex flex-row">
|
||||
<input
|
||||
v-model="configStore.playout.processing.vtt_enable"
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm me-1 mt-2"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Enable VTT</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="label py-0">
|
||||
<span class="text-sm select-text text-base-content/80">{{
|
||||
t('config.processingVTTEnable')
|
||||
}}</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
@ -373,6 +415,11 @@
|
||||
type="text"
|
||||
class="input input-sm input-bordered w-full max-w-lg"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">{{
|
||||
t('config.processingVTTDummy')
|
||||
}}</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@ -412,6 +459,11 @@
|
||||
class="textarea textarea-bordered"
|
||||
rows="3"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">{{
|
||||
t('config.ingestCustomFilter')
|
||||
}}</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@ -422,7 +474,7 @@
|
||||
{{ t('config.playlistHelp') }}
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full max-w-xs">
|
||||
<label class="form-control w-full">
|
||||
<div class="label">
|
||||
<span class="label-text text-base font-bold">Day Start</span>
|
||||
</div>
|
||||
@ -432,8 +484,11 @@
|
||||
class="input input-sm input-bordered w-full max-w-xs"
|
||||
pattern="([01]?[0-9]|2[0-4]):[0-5][0-9]:[0-5][0-9]"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">{{ t('config.playlistDayStart') }}</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full max-w-xs">
|
||||
<label class="form-control w-full">
|
||||
<div class="label">
|
||||
<span class="label-text text-base font-bold">Length</span>
|
||||
</div>
|
||||
@ -443,15 +498,23 @@
|
||||
class="input input-sm input-bordered w-full max-w-xs"
|
||||
pattern="([01]?[0-9]|2[0-4]):[0-5][0-9]:[0-5][0-9]"
|
||||
/>
|
||||
</label>
|
||||
<label class="form-control w-full flex-row mt-2">
|
||||
<input
|
||||
v-model="configStore.playout.playlist.infinit"
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm me-1 mt-2"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Enable</span>
|
||||
<span class="text-sm select-text text-base-content/80">{{ t('config.playlistLength') }}</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="flex flex-row">
|
||||
<input
|
||||
v-model="configStore.playout.playlist.infinit"
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm me-1 mt-2"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Infinit</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="label py-0">
|
||||
<span class="text-sm select-text text-base-content/80">{{ t('config.playlistInfinit') }}</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
@ -473,6 +536,9 @@
|
||||
name="filler"
|
||||
class="input input-sm input-bordered w-full max-w-lg"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">{{ t('config.storageFiller') }}</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full">
|
||||
<div class="label">
|
||||
@ -483,15 +549,23 @@
|
||||
type="text"
|
||||
class="input input-sm input-bordered w-full max-w-lg"
|
||||
/>
|
||||
</label>
|
||||
<label class="form-control w-full flex-row mt-2">
|
||||
<input
|
||||
v-model="configStore.playout.storage.shuffle"
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm me-1 mt-2"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Shuffle</span>
|
||||
<span class="text-sm select-text text-base-content/80">{{ t('config.storageExtension') }}</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="flex flex-row">
|
||||
<input
|
||||
v-model="configStore.playout.storage.shuffle"
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm me-1 mt-2"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Shuffle</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="label py-0">
|
||||
<span class="text-sm select-text text-base-content/80">{{ t('config.storageShuffle') }}</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
@ -522,15 +596,23 @@
|
||||
type="text"
|
||||
class="input input-sm input-bordered w-full max-w-lg"
|
||||
/>
|
||||
</label>
|
||||
<label class="form-control w-full flex-row mt-2">
|
||||
<input
|
||||
v-model="configStore.playout.text.text_from_filename"
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm me-1 mt-2"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Text from File</span>
|
||||
<span class="text-sm select-text text-base-content/80">{{ t('config.textFont') }}</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full mt-2">
|
||||
<div class="flex flex-row">
|
||||
<input
|
||||
v-model="configStore.playout.text.text_from_filename"
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm me-1 mt-2"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="label-text !text-md font-bold">Text from File</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="label py-0">
|
||||
<span class="text-sm select-text text-base-content/80">{{ t('config.textFromFile') }}</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full">
|
||||
@ -542,6 +624,9 @@
|
||||
type="text"
|
||||
class="input input-sm input-bordered w-full truncate"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">{{ t('config.textStyle') }}</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="form-control w-full">
|
||||
<div class="label">
|
||||
@ -552,6 +637,9 @@
|
||||
type="text"
|
||||
class="input input-sm input-bordered w-full max-w-lg"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">{{ t('config.textRegex') }}</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@ -582,6 +670,9 @@
|
||||
name="task_path"
|
||||
class="input input-sm input-bordered w-full max-w-lg"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="text-sm select-text text-base-content/80">{{ t('config.taskPath') }}</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="w-full max-w-[800px] pe-8">
|
||||
<div class="w-full max-w-[800px] xs:pe-8">
|
||||
<h2 class="pt-3 text-3xl">{{ t('user.title') }}</h2>
|
||||
<div v-if="authStore.role === 'GlobalAdmin'" class="flex flex-col xs:flex-row gap-2 w-full mb-5 mt-10">
|
||||
<div class="grow">
|
||||
@ -234,12 +234,12 @@ async function addUser(add: boolean) {
|
||||
await getUsers()
|
||||
await getUserConfig()
|
||||
} else {
|
||||
indexStore.msgAlert('error', t('user.addFailed'), 2)
|
||||
indexStore.msgAlert('error', t('user.addFailed'), 3)
|
||||
}
|
||||
|
||||
clearUser()
|
||||
} else {
|
||||
indexStore.msgAlert('error', t('user.mismatch'), 2)
|
||||
indexStore.msgAlert('error', t('user.mismatch'), 3)
|
||||
}
|
||||
} else {
|
||||
showUserModal.value = false
|
||||
@ -248,8 +248,13 @@ async function addUser(add: boolean) {
|
||||
}
|
||||
|
||||
async function onSubmitUser() {
|
||||
if (newPass.value && newPass.value === confirmPass.value) {
|
||||
configStore.configUser.password = newPass.value
|
||||
if (newPass.value) {
|
||||
if (newPass.value === confirmPass.value) {
|
||||
configStore.configUser.password = newPass.value
|
||||
} else {
|
||||
indexStore.msgAlert('error', t('user.mismatch'), 3)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
authStore.inspectToken()
|
||||
|
@ -182,31 +182,41 @@ export default {
|
||||
output: 'Ausgabe',
|
||||
placeholderPass: 'Passwort',
|
||||
help: 'Hilfe',
|
||||
generalHelp: `Manchmal kann es vorkommen, dass eine Datei beschädigt ist, aber dennoch abspielbar. Dies kann einen Streaming-Fehler für alle folgenden Dateien verursachen. Die einzige Lösung in diesem Fall ist, ffplayout zu stoppen und es erneut zu starten.
|
||||
'Stop Threshold' stoppt ffplayout, wenn es asynchron in der Zeit über diesen Wert hinaus ist. Ein Wert unter 3 kann unerwartete Fehler verursachen.`,
|
||||
mailHelp: `Sende Fehlermeldungen an eine E-Mail-Adresse, wie z.B. fehlende Clips, fehlendes oder ungültiges Playlist-Format usw. Lass den Empfänger leer, wenn dies nicht benötigt wird.
|
||||
'Interval' bezieht sich auf die Anzahl der Sekunden bis zur nächsten E-Mail; der Wert muss in Schritten von 10 erfolgen und darf nicht weniger als 30 Sekunden betragen.`,
|
||||
logHelp: `'ffmpeg_level/ingest_level' kann INFO, WARNING oder ERROR sein.
|
||||
'detect_silence' protokolliert eine Fehlermeldung, wenn die Audioleitung während des Validierungsprozesses 15 Sekunden lang stumm ist.
|
||||
'ignore' erlaubt dem Protokoll, Zeichenfolgen zu ignorieren, die übereinstimmende Zeilen enthalten; das Format ist eine durch Semikolons getrennte Liste.`,
|
||||
processingHelp: `Die Standardverarbeitung für alle Clips sorgt für Einzigartigkeit. Der Modus kann entweder 'playlist' oder 'folder' sein.
|
||||
Der Parameter 'aspect' muss eine Gleitkommazahl sein.
|
||||
Der Parameter 'audio_tracks' gibt an, wie viele Audiotracks verarbeitet werden sollen. 'audio_channels' kann verwendet werden, wenn das Audio mehr als Stereo-Kanäle hat.
|
||||
Das 'logo' wird nur verwendet, wenn der Pfad existiert; der Pfad ist relativ zu deinem Speicherordner.
|
||||
'logo_scale' skaliert das Logo auf die Zielgröße. Lasse es leer, wenn keine Skalierung erforderlich ist. Das Format ist 'Breite:Höhe', z.B. '100:-1' für proportionale Skalierung. Die Option 'logo_opacity' ermöglicht es, das Logo transparent zu machen. Die 'logo_position' wird im Format 'x:y' angegeben, was die Position des Logos festlegt.
|
||||
Mit 'custom_filter' ist es möglich, zusätzliche Filter anzuwenden. Die Filterausgaben sollten mit [c_v_out] für Video-Filter und [c_a_out] für Audio-Filter enden.
|
||||
'vtt_enable' kann nur im HLS-Modus verwendet werden, und nur wenn *.vtt-Dateien mit demselben Dateinamen wie die Videodatei existieren.`,
|
||||
ingestHelp: `Starte einen Server für einen Eingabestream. Dieser Stream überschreibt den normalen Stream, bis er beendet ist. Es gibt nur einen sehr einfachen Authentifizierungsmechanismus, der überprüft, ob der Stream-Name korrekt ist.
|
||||
'custom_filter' kann auf die gleiche Weise verwendet werden wie der im Verarbeitungsabschnitt.`,
|
||||
playlistHelp: `'day_start' gibt an, zu welcher Zeit die Playlist starten soll; lass 'day_start' leer, wenn die Playlist immer am Anfang starten soll. 'length' stellt die Ziellänge der Playlist dar; wenn es leer ist, wird die reale Länge nicht berücksichtigt.
|
||||
'infinite: true' funktioniert mit einer einzigen Playlist-Datei und schleift sie unendlich.`,
|
||||
storageHelp: `'filler' wird verwendet, um anstelle einer fehlenden Datei oder zur Auffüllung der verbleibenden Zeit auf insgesamt 24 Stunden abzuspielen. Es kann eine Datei oder ein Ordner sein und wird bei Bedarf wiederholt.
|
||||
'extensions' gibt an, nach welchen Dateien anhand dieser Erweiterung gesucht werden soll. Aktiviere 'shuffle', um Dateien zufällig auszuwählen.`,
|
||||
textHelp: `Überlagere Text in Kombination mit libzmq zur Fernmanipulation von Text. 'font' ist ein relativer Pfad zu deinem Speicherordner.
|
||||
'text_from_filename' aktiviert die Extraktion von Text aus einem Dateinamen. Mit 'style' kannst du die Drawtext-Parameter wie Position, Farbe usw. definieren. Die Übermittlung von Text über die API überschreibt dies. Mit 'regex' kannst du Dateinamen formatieren, um einen Titel daraus zu extrahieren.`,
|
||||
taskHelp: `Führe ein externes Programm mit einem angegebenen Medienobjekt aus. Das Medienobjekt ist im JSON-Format und enthält alle Informationen über den aktuellen Clip. Das externe Programm kann ein Skript oder eine Binärdatei sein, aber es sollte nur für kurze Zeit ausgeführt werden.`,
|
||||
outputHelp: `Das endgültige Playout-Encoding, passe die Einstellungen nach deinen Bedürfnissen an. 'mode' hat die Optionen 'desktop', 'hls', 'null' und 'stream'. Verwende 'stream' und passe die 'output_param:'-Einstellungen an, wenn du an einen RTMP/RTSP/SRT/...-Server streamen möchtest.
|
||||
In der Produktion solltest du keine HLS-Playlists mit ffplayout bereitstellen; verwende Nginx oder einen anderen Webserver!`,
|
||||
generalHelp: 'Manchmal kann es passieren, dass eine Datei beschädigt ist, aber dennoch abgespielt werden kann. Dies kann zu einem Streaming-Fehler für alle folgenden Dateien führen. Die einzige Lösung in diesem Fall ist, ffplayout zu stoppen und erneut zu starten.',
|
||||
stopThreshold: 'Der Schwellenwert stoppt ffplayout, wenn es zeitlich asynchron über diesem Wert ist. Eine Zahl unter 3 kann unerwartete Fehler verursachen.',
|
||||
mailHelp: `Sende Fehlermeldungen an eine E-Mail-Adresse, wie z.B. fehlende Clips, fehlendes oder ungültiges Playlist-Format usw. Lass den Empfänger leer, wenn du dies nicht benötigst.`,
|
||||
mailInterval: 'Das Intervall bezieht sich auf die Anzahl der Sekunden, bis eine neue E-Mail gesendet wird; der Wert muss in 10er-Schritten und nicht unter 30 Sekunden liegen.',
|
||||
logHelp: 'Passen Sie das Verhalten des Loggings an.',
|
||||
logDetect: 'Protokolliert eine Fehlermeldung, wenn die Audioleitung während des Validierungsprozesses 15 Sekunden lang stumm ist.',
|
||||
logIgnore: 'Ignoriere Zeichenfolgen, die übereinstimmende Zeilen enthalten; das Format ist eine durch Semikolon getrennte Liste.',
|
||||
processingHelp: 'Die Standardverarbeitung für alle Clips stellt die Einzigartigkeit sicher.',
|
||||
processingLogoPath: 'Das Logo wird nur verwendet, wenn der Pfad existiert; der Pfad ist relativ zum Speicherordner.',
|
||||
processingLogoScale: `Lass die Skalierung des Logos leer, wenn keine Skalierung erforderlich ist. Das Format lautet 'Breite:Höhe', zum Beispiel: '100:-1' für proportionale Skalierung.`,
|
||||
processingLogoPosition: `Die Position wird im Format 'x:y' angegeben.`,
|
||||
processingAudioTracks: 'Gib an, wie viele Audiospuren verarbeitet werden sollen.',
|
||||
processingAudioIndex: 'Welche Audiospur verwendet werden soll, -1 für alle.',
|
||||
processingAudioChannels: 'Stelle die Anzahl der Audiokanäle ein, wenn das Audio mehr Kanäle als Stereo hat.',
|
||||
processingCustomFilter: 'Füge benutzerdefinierte Filter zur Verarbeitung hinzu. Die Filterausgaben müssen mit [c_v_out] für Video-Filter und [c_a_out] für Audio-Filter enden.',
|
||||
processingVTTEnable: 'VTT kann nur im HLS-Modus verwendet werden und nur, wenn *.vtt-Dateien mit demselben Namen wie die Videodatei vorhanden sind.',
|
||||
processingVTTDummy: 'Ein Platzhalter wird benötigt, wenn keine vtt-Datei vorhanden ist.',
|
||||
ingestHelp: `Starte einen Server für einen Ingest-Stream. Dieser Stream wird den normalen Stream überschreiben, bis er beendet ist. Es gibt nur einen sehr einfachen Authentifizierungsmechanismus, der überprüft, ob der Streamname korrekt ist.`,
|
||||
ingestCustomFilter: 'Wende einen benutzerdefinierten Filter auf den Ingest-Stream auf dieselbe Weise wie im Abschnitt Verarbeitung an.',
|
||||
playlistHelp: 'Playlist-Verwaltung.',
|
||||
playlistDayStart: 'Zu welcher Zeit die Playlist starten soll; lasse es leer, wenn die Playlist immer von Anfang an starten soll.',
|
||||
playlistLength: 'Ziel-Länge der Playlist; wenn es leer ist, wird die reale Länge nicht berücksichtigt.',
|
||||
playlistInfinit: 'Eine einzelne Playlist-Datei endlos wiederholen.',
|
||||
storageHelp: 'Speichereinstellungen, die Standorte sind relativ zum Kanal-Speicher.',
|
||||
storageFiller: 'Verwende Füllmaterial, um anstelle einer fehlenden Datei abzuspielen oder um die verbleibende Zeit zu füllen, um eine Gesamtdauer von 24 Stunden zu erreichen. Es kann eine Datei oder ein Ordner sein und wird bei Bedarf wiederholt.',
|
||||
storageExtension: 'Gib an, welche Dateien gesucht und verwendet werden sollen.',
|
||||
storageShuffle: 'Wähle Dateien zufällig aus (im Ordner-Modus und bei der Playlist-Erstellung).',
|
||||
textHelp: 'Texteinblendung in Kombination mit libzmq für die Fernmanipulation von Text.',
|
||||
textFont: 'Relativer Pfad zum Kanal-Speicher.',
|
||||
textFromFile: 'Extrahiere Text aus einem Dateinamen.',
|
||||
textStyle: 'Definiere die Parameter für drawtext, wie Position, Farbe usw. Das Posten von Text über die API überschreibt dies.',
|
||||
textRegex: 'Formatiere Dateinamen, um einen Titel daraus zu extrahieren.',
|
||||
taskHelp: 'Führe ein externes Programm mit einem gegebenen Medienobjekt aus. Das Medienobjekt ist im JSON-Format und enthält alle Informationen über den aktuellen Clip. Das externe Programm kann ein Skript oder eine Binärdatei sein, sollte aber nur für kurze Zeit laufen.',
|
||||
taskPath: 'Pfad zur ausführbaren Datei.',
|
||||
outputHelp: `Die endgültige Playout-Codierung, passe die Einstellungen nach deinen Bedürfnissen an. Verwende den 'stream'-Modus und passe den 'Ausgabe-Parameter' an, wenn du zu einem RTMP/RTSP/SRT/...-Server streamen möchtest. Im Produktionsbetrieb verwende kein HLS mit ffplayout; nutze Nginx oder einen anderen Webserver!`,
|
||||
restartTile: 'Playout neustarten',
|
||||
restartText: 'ffplayout neustarten um Einstellungen anzuwenden?',
|
||||
updatePlayoutSuccess: 'Update der Playout-Konfiguration erfolgreich!',
|
||||
|
@ -189,24 +189,34 @@ export default {
|
||||
logHelp: 'Adjust logging behavior.',
|
||||
logDetect: 'Logs an error message if the audio line is silent for 15 seconds during the validation process.',
|
||||
logIgnore: 'Ignore strings that contain matched lines; the format is a semicolon-separated list.',
|
||||
processingHelp: `Default processing for all clips ensures uniqueness. The mode can be either 'playlist' or 'folder'.
|
||||
The 'Aspect' parameter must be a float number.
|
||||
The 'Audio Tracks' parameter specifies how many audio tracks should be processed. 'Audio Channels' can be used if the audio has more channels than stereo.
|
||||
The 'Logo' is used only if the path exists; the path is relative to your storage folder.
|
||||
'Logo Scale' scales the logo to the target size. Leave it blank if no scaling is needed. The format is 'width:height', for example: '100:-1' for proportional scaling. The 'logo_opacity' option allows the logo to become transparent.
|
||||
'Logo Position' is specified in the format 'x:y', which sets the logo's position.
|
||||
With 'Custom Filter', it is possible to apply additional filters. The filter outputs should end with [c_v_out] for video filters and [c_a_out] for audio filters.
|
||||
'Enable VTT' can only be used in HLS mode, and only when *.vtt files with the same filename as the video file exist.`,
|
||||
ingestHelp: `Run a server for an ingest stream. This stream will override the normal streaming until it is finished. There is only a very simple authentication mechanism, which checks if the stream name is correct.
|
||||
'Custom Filter' can be used in the same way as the one in the process section.`,
|
||||
playlistHelp: `'day_start' indicates at what time the playlist should start; leave 'day_start' blank if the playlist should always start at the beginning. 'length' represents the target length of the playlist; when it is blank, the real length will not be considered.
|
||||
'infinite: true' works with a single playlist file and loops it infinitely.`,
|
||||
storageHelp: `'filler' is used to play in place of a missing file or to fill the remaining time to reach a total of 24 hours. It can be a file or folder and will loop when necessary.
|
||||
'extensions' specifies which files to search for by this extension. Activate 'shuffle' to pick files randomly.`,
|
||||
textHelp: `Overlay text in combination with libzmq for remote text manipulation. 'font' is a relative path to your storage folder.
|
||||
'text_from_filename' activates the extraction of text from a filename. With 'style', you can define the drawtext parameters, such as position, color, etc. Posting text over the API will override this. With 'regex', you can format file names to extract a title from them.`,
|
||||
taskHelp: `Run an external program with a given media object. The media object is in JSON format and contains all the information about the current clip. The external program can be a script or a binary, but it should only run for a short time.`,
|
||||
outputHelp: `The final playout encoding, set the settings according to your needs. 'mode' has the options 'desktop', 'hls', 'null', and 'stream'. Use 'stream' and adjust the 'output_param:' settings when you want to stream to an RTMP/RTSP/SRT/... server.
|
||||
processingHelp: 'Default processing for all clips ensures uniqueness.',
|
||||
processingLogoPath: 'The logo is used only if the path exists; the path is relative to the storage folder.',
|
||||
processingLogoScale: `Leave logo scale blank if no scaling is needed. The format is 'width:height', for example: '100:-1' for proportional scaling.`,
|
||||
processingLogoPosition: `Position is specified in the format 'x:y'`,
|
||||
processingAudioTracks: 'Specify how many audio tracks should be processed.',
|
||||
processingAudioIndex: 'Which audio line to use, -1 for all.',
|
||||
processingAudioChannels: 'Set the audio channel count, if audio has more channels than stereo.',
|
||||
processingCustomFilter: 'Add custom filters to the processing. The filter outputs must end with [c_v_out] for video filters and [c_a_out] for audio filters.',
|
||||
processingVTTEnable: 'VTT can only be used in HLS mode and only if there are *.vtt files with the same name as the video file.',
|
||||
processingVTTDummy: 'A placeholder is needed if there is no vtt file.',
|
||||
ingestHelp: `Run a server for an ingest stream. This stream will override the normal streaming until it is finished. There is only a very simple authentication mechanism, which checks if the stream name is correct.`,
|
||||
ingestCustomFilter: 'Apply a custom filter to the Ingest stream in the same way as in the Processing section.',
|
||||
playlistHelp: 'Playlist handling.',
|
||||
playlistDayStart: 'At what time the playlist should start; leave it blank if the playlist should always start at the beginning.',
|
||||
playlistLength: 'Target length of the playlist; when it is blank, the real length will not be considered.',
|
||||
playlistInfinit: 'Loop a single playlist file infinitely.',
|
||||
storageHelp: 'Storage settings, locations are relative to channel storage.',
|
||||
storageFiller: 'Use filler to play in place of a missing file or to fill the remaining time to reach a total of 24 hours. It can be a file or folder and will loop when necessary.',
|
||||
storageExtension: 'Specify which files to search and use.',
|
||||
storageShuffle: 'Pick files randomly (in folder mode and playlist generation).',
|
||||
textHelp: 'Overlay text in combination with libzmq for remote text manipulation.',
|
||||
textFont: 'Relative path to channel storage.',
|
||||
textFromFile: 'Extraction of text from a filename.',
|
||||
textStyle: 'Define the drawtext parameters, such as position, color, etc. Posting text over the API will override this.',
|
||||
textRegex: 'Format file names to extract a title from them.',
|
||||
taskHelp: 'Run an external program with a given media object. The media object is in JSON format and contains all the information about the current clip. The external program can be a script or a binary, but it should only run for a short time.',
|
||||
taskPath: 'Path to executable.',
|
||||
outputHelp: `The final playout encoding, set the settings according to your needs. Use 'stream' mode and adjust the 'Output Parameter' when you want to stream to an RTMP/RTSP/SRT/... server.
|
||||
In production, don't serve HLS playlists with ffplayout; use Nginx or another web server!`,
|
||||
restartTile: 'Restart Playout',
|
||||
restartText: 'Restart ffplayout to apply changes?',
|
||||
|
@ -182,31 +182,41 @@ export default {
|
||||
output: 'Saída',
|
||||
placeholderPass: 'Senha',
|
||||
help: 'Ajuda',
|
||||
generalHelp: `Às vezes, pode acontecer que um arquivo esteja corrompido, mas ainda seja reproduzível. Isso pode produzir um erro de streaming para todos os arquivos seguintes. A única solução nesse caso é parar o ffplayout e iniciá-lo novamente.
|
||||
'Stop Threshold' para o ffplayout se ele estiver fora de sincronia no tempo acima desse valor. Um número abaixo de 3 pode causar erros inesperados.`,
|
||||
mailHelp: `Envie mensagens de erro para um endereço de e-mail, como clipes ausentes, formato de playlist ausente ou inválido, etc. Deixe o destinatário em branco se você não precisar disso.
|
||||
'Interval' refere-se ao número de segundos até que um novo e-mail seja enviado; o valor deve ser em incrementos de 10 e não inferior a 30 segundos.`,
|
||||
logHelp: `'ffmpeg_level/ingest_level' pode ser INFO, WARNING ou ERROR.
|
||||
'detect_silence' registra uma mensagem de erro se a linha de áudio estiver em silêncio por 15 segundos durante o processo de validação.
|
||||
'ignore' permite que o log ignore cadeias de caracteres que contenham linhas correspondentes; o formato é uma lista separada por ponto e vírgula.`,
|
||||
processingHelp: `O processamento padrão para todos os clipes garante a exclusividade. O modo pode ser 'playlist' ou 'folder'.
|
||||
O parâmetro 'aspect' deve ser um número de ponto flutuante.
|
||||
O parâmetro 'audio_tracks' especifica quantas trilhas de áudio devem ser processadas. 'audio_channels' pode ser usado se o áudio tiver mais canais que estéreo.
|
||||
O 'logo' é usado apenas se o caminho existir; o caminho é relativo à sua pasta de armazenamento.
|
||||
'logo_scale' redimensiona o logotipo para o tamanho desejado. Deixe em branco se não for necessário redimensionar. O formato é 'largura:altura', por exemplo, '100:-1' para redimensionamento proporcional. A opção 'logo_opacity' permite que o logotipo fique transparente. A 'logo_position' é especificada no formato 'x:y', que define a posição do logotipo.
|
||||
Com 'custom_filter', é possível aplicar filtros adicionais. As saídas de filtro devem terminar com [c_v_out] para filtros de vídeo e [c_a_out] para filtros de áudio.
|
||||
'vtt_enable' só pode ser usado no modo HLS e somente quando existirem arquivos *.vtt com o mesmo nome do arquivo de vídeo.`,
|
||||
ingestHelp: `Execute um servidor para um fluxo de ingestão. Esse fluxo substituirá o streaming normal até que seja concluído. Existe apenas um mecanismo de autenticação muito simples, que verifica se o nome do fluxo está correto.
|
||||
'custom_filter' pode ser usado da mesma forma que o da seção de processamento.`,
|
||||
playlistHelp: `'day_start' indica a que horas a playlist deve começar; deixe 'day_start' em branco se a playlist sempre deve começar do início. 'length' representa a duração alvo da playlist; quando está em branco, o comprimento real não será considerado.
|
||||
'infinite: true' funciona com um único arquivo de playlist e o repete infinitamente.`,
|
||||
storageHelp: `'filler' é usado para tocar no lugar de um arquivo ausente ou para preencher o tempo restante para atingir um total de 24 horas. Pode ser um arquivo ou pasta e será repetido quando necessário.
|
||||
'extensions' especifica quais arquivos procurar com base nessa extensão. Ative 'shuffle' para selecionar arquivos aleatoriamente.`,
|
||||
textHelp: `Sobreponha texto em combinação com libzmq para manipulação remota de texto. 'font' é um caminho relativo à sua pasta de armazenamento.
|
||||
'text_from_filename' ativa a extração de texto a partir de um nome de arquivo. Com 'style', você pode definir os parâmetros do drawtext, como posição, cor, etc. Enviar texto pela API substituirá isso. Com 'regex', você pode formatar nomes de arquivos para extrair um título deles.`,
|
||||
taskHelp: `Execute um programa externo com um objeto de mídia fornecido. O objeto de mídia está no formato JSON e contém todas as informações sobre o clipe atual. O programa externo pode ser um script ou um binário, mas deve ser executado por um curto período de tempo.`,
|
||||
outputHelp: `A codificação final do playout, ajuste as configurações conforme suas necessidades. 'mode' tem as opções 'desktop', 'hls', 'null' e 'stream'. Use 'stream' e ajuste as configurações 'output_param:' quando quiser transmitir para um servidor RTMP/RTSP/SRT/... .
|
||||
Em produção, não sirva playlists HLS com ffplayout; use Nginx ou outro servidor web!`,
|
||||
generalHelp: 'Às vezes pode acontecer de um arquivo estar corrompido, mas ainda ser reproduzível. Isso pode causar um erro de streaming para todos os arquivos seguintes. A única solução nesse caso é parar o ffplayout e reiniciá-lo.',
|
||||
stopThreshold: 'O limite para o ffplayout se ele estiver fora de sincronia acima deste valor. Um número abaixo de 3 pode causar erros inesperados.',
|
||||
mailHelp: `Envie mensagens de erro para um endereço de e-mail, como clipes ausentes, formato de playlist ausente ou inválido, etc. Deixe o destinatário em branco se não precisar disso.`,
|
||||
mailInterval: 'O intervalo se refere ao número de segundos até o envio de um novo e-mail; o valor deve ser em incrementos de 10 e não inferior a 30 segundos.',
|
||||
logHelp: 'Ajuste o comportamento de log.',
|
||||
logDetect: 'Registra uma mensagem de erro se a linha de áudio estiver em silêncio por 15 segundos durante o processo de validação.',
|
||||
logIgnore: 'Ignorar strings que contenham linhas correspondentes; o formato é uma lista separada por ponto e vírgula.',
|
||||
processingHelp: 'O processamento padrão para todos os clipes garante a exclusividade.',
|
||||
processingLogoPath: 'O logotipo só é usado se o caminho existir; o caminho é relativo à pasta de armazenamento.',
|
||||
processingLogoScale: `Deixe a escala do logotipo em branco se não for necessário escalonamento. O formato é 'largura:altura', por exemplo: '100:-1' para escalonamento proporcional.`,
|
||||
processingLogoPosition: `A posição é especificada no formato 'x:y'.`,
|
||||
processingAudioTracks: 'Especifique quantas faixas de áudio devem ser processadas.',
|
||||
processingAudioIndex: 'Qual linha de áudio usar, -1 para todas.',
|
||||
processingAudioChannels: 'Defina a contagem de canais de áudio, se o áudio tiver mais canais do que estéreo.',
|
||||
processingCustomFilter: 'Adicione filtros personalizados ao processamento. As saídas de filtro devem terminar com [c_v_out] para filtros de vídeo e [c_a_out] para filtros de áudio.',
|
||||
processingVTTEnable: 'VTT só pode ser usado no modo HLS e apenas se houver arquivos *.vtt com o mesmo nome do arquivo de vídeo.',
|
||||
processingVTTDummy: 'Um espaço reservado é necessário se não houver arquivo vtt.',
|
||||
ingestHelp: `Execute um servidor para um fluxo de ingestão. Este fluxo substituirá o streaming normal até que termine. Há apenas um mecanismo de autenticação simples que verifica se o nome do fluxo está correto.`,
|
||||
ingestCustomFilter: 'Aplique um filtro personalizado ao fluxo de ingestão da mesma forma que na seção de Processamento.',
|
||||
playlistHelp: 'Gerenciamento de playlist.',
|
||||
playlistDayStart: 'A que horas a playlist deve começar; deixe em branco se a playlist sempre começar do início.',
|
||||
playlistLength: 'Duração alvo da playlist; quando estiver em branco, o comprimento real não será considerado.',
|
||||
playlistInfinit: 'Reproduza infinitamente um único arquivo de playlist.',
|
||||
storageHelp: 'Configurações de armazenamento, os locais são relativos ao armazenamento do canal.',
|
||||
storageFiller: 'Use preenchimento para tocar no lugar de um arquivo ausente ou para preencher o tempo restante para atingir um total de 24 horas. Pode ser um arquivo ou pasta e será repetido quando necessário.',
|
||||
storageExtension: 'Especifique quais arquivos procurar e usar.',
|
||||
storageShuffle: 'Escolha arquivos aleatoriamente (no modo de pasta e geração de playlist).',
|
||||
textHelp: 'Sobrepor texto em combinação com libzmq para manipulação remota de texto.',
|
||||
textFont: 'Caminho relativo ao armazenamento do canal.',
|
||||
textFromFile: 'Extração de texto a partir de um nome de arquivo.',
|
||||
textStyle: 'Defina os parâmetros drawtext, como posição, cor, etc. Postar texto pela API substituirá isso.',
|
||||
textRegex: 'Formate nomes de arquivos para extrair um título deles.',
|
||||
taskHelp: 'Execute um programa externo com um objeto de mídia fornecido. O objeto de mídia está em formato JSON e contém todas as informações sobre o clipe atual. O programa externo pode ser um script ou binário, mas deve ser executado apenas por um curto período de tempo.',
|
||||
taskPath: 'Caminho para o executável.',
|
||||
outputHelp: `A codificação final do playout, ajuste as configurações de acordo com suas necessidades. Use o modo 'stream' e ajuste o 'Parâmetro de Saída' quando quiser fazer streaming para um servidor RTMP/RTSP/SRT/... No ambiente de produção, não sirva playlists HLS com ffplayout; use Nginx ou outro servidor web!`,
|
||||
restartTile: 'Reiniciar Playout',
|
||||
restartText: 'Reiniciar o ffplayout para aplicar as alterações?',
|
||||
updatePlayoutSuccess: 'Sucesso na atualização da configuração do playout!',
|
||||
|
@ -182,30 +182,41 @@ export default {
|
||||
output: 'Out',
|
||||
placeholderPass: 'Password',
|
||||
help: 'Help',
|
||||
generalHelp: `Sometimes it can happen that a file is corrupt but still playable. This can produce a streaming error for all following files. The only solution in this case is to stop ffplayout and start it again.
|
||||
'Stop Threshold' stops ffplayout if it is asynchronous in time above this value. A number below 3 can cause unexpected errors.`,
|
||||
mailHelp: `Send error messages to an email address, such as missing clips, missing or invalid playlist format, etc.. Leave the recipient blank if you don't need this.
|
||||
'Interval' refers to the number of seconds until a new email is sent; the value must be in increments of 10 and not lower then 30 seconds.`,
|
||||
logHelp: `'ffmpeg_level/ingest_level' can be INFO, WARNING, or ERROR.
|
||||
'detect_silence' logs an error message if the audio line is silent for 15 seconds during the validation process.
|
||||
'ignore' allows logging to ignore strings that contain matched lines; the format is a semicolon-separated list.`,
|
||||
processingHelp: `Default processing for all clips ensures uniqueness. The mode can be either 'playlist' or 'folder'.
|
||||
The 'aspect' parameter must be a float number.
|
||||
The 'audio_tracks' parameter specifies how many audio tracks should be processed.'audio_channels' can be used if the audio has more channels than stereo.
|
||||
The 'logo' is used only if the path exists; the path is relative to your storage folder.
|
||||
'logo_scale' scales the logo to the target size. Leave it blank if no scaling is needed. The format is 'width:height', for example, '100:-1' for proportional scaling. The 'logo_opacity' option allows the logo to become transparent.'logo_position' is specified in the format 'x:y', which sets the logo's position.
|
||||
With 'custom_filter', it is possible to apply additional filters. The filter outputs should end with [c_v_out] for video filters and [c_a_out] for audio filters.
|
||||
'vtt_enable' can only be used in HLS mode, and only when *.vtt files with the same filename as the video file exist.`,
|
||||
ingestHelp: `Run a server for an ingest stream. This stream will override the normal streaming until it is finished. There is only a very simple authentication mechanism, which checks if the stream name is correct.
|
||||
'custom_filter' can be used in the same way as the one in the process section.`,
|
||||
playlistHelp: `'day_start' indicates at what time the playlist should start; leave 'day_start' blank if the playlist should always start at the beginning. 'length' represents the target length of the playlist; when it is blank, the real length will not be considered.
|
||||
'infinite: true' works with a single playlist file and loops it infinitely.`,
|
||||
storageHelp: `'filler' is used to play in place of a missing file or to fill the remaining time to reach a total of 24 hours. It can be a file or folder and will loop when necessary.
|
||||
'extensions' specifies which files to search for by this extension. Activate 'shuffle' to pick files randomly.`,
|
||||
textHelp: `Overlay text in combination with libzmq for remote text manipulation. 'font' is a relative path to your storage folder.
|
||||
'text_from_filename' activates the extraction of text from a filename. With 'style', you can define the drawtext parameters, such as position, color, etc. Posting text over the API will override this. With 'regex', you can format file names to extract a title from them.`,
|
||||
taskHelp: `Run an external program with a given media object. The media object is in JSON format and contains all the information about the current clip. The external program can be a script or a binary, but it should only run for a short time.`,
|
||||
outputHelp: `The final playout encoding, set the settings according to your needs. 'mode' has the options 'desktop', 'hls', 'null', and 'stream'. Use 'stream' and adjust the 'output_param:' settings when you want to stream to an RTMP/RTSP/SRT/... server.
|
||||
generalHelp: 'Sometimes it can happen that a file is corrupt but still playable. This can produce a streaming error for all following files. The only solution in this case is to stop ffplayout and start it again.',
|
||||
stopThreshold: 'The threshold stops ffplayout if it is asynchronous in time above this value. A number below 3 can cause unexpected errors.',
|
||||
mailHelp: `Send error messages to an email address, such as missing clips, missing or invalid playlist format, etc.. Leave the recipient blank if you don't need this.`,
|
||||
mailInterval: 'The interval refers to the number of seconds until a new email is sent; the value must be in increments of 10 and not lower then 30 seconds.',
|
||||
logHelp: 'Adjust logging behavior.',
|
||||
logDetect: 'Logs an error message if the audio line is silent for 15 seconds during the validation process.',
|
||||
logIgnore: 'Ignore strings that contain matched lines; the format is a semicolon-separated list.',
|
||||
processingHelp: 'Default processing for all clips ensures uniqueness.',
|
||||
processingLogoPath: 'The logo is used only if the path exists; the path is relative to the storage folder.',
|
||||
processingLogoScale: `Leave logo scale blank if no scaling is needed. The format is 'width:height', for example: '100:-1' for proportional scaling.`,
|
||||
processingLogoPosition: `Position is specified in the format 'x:y'`,
|
||||
processingAudioTracks: 'Specify how many audio tracks should be processed.',
|
||||
processingAudioIndex: 'Which audio line to use, -1 for all.',
|
||||
processingAudioChannels: 'Set the audio channel count, if audio has more channels than stereo.',
|
||||
processingCustomFilter: 'Add custom filters to the processing. The filter outputs must end with [c_v_out] for video filters and [c_a_out] for audio filters.',
|
||||
processingVTTEnable: 'VTT can only be used in HLS mode and only if there are *.vtt files with the same name as the video file.',
|
||||
processingVTTDummy: 'A placeholder is needed if there is no vtt file.',
|
||||
ingestHelp: `Run a server for an ingest stream. This stream will override the normal streaming until it is finished. There is only a very simple authentication mechanism, which checks if the stream name is correct.`,
|
||||
ingestCustomFilter: 'Apply a custom filter to the Ingest stream in the same way as in the Processing section.',
|
||||
playlistHelp: 'Playlist handling.',
|
||||
playlistDayStart: 'At what time the playlist should start; leave it blank if the playlist should always start at the beginning.',
|
||||
playlistLength: 'Target length of the playlist; when it is blank, the real length will not be considered.',
|
||||
playlistInfinit: 'Loop a single playlist file infinitely.',
|
||||
storageHelp: 'Storage settings, locations are relative to channel storage.',
|
||||
storageFiller: 'Use filler to play in place of a missing file or to fill the remaining time to reach a total of 24 hours. It can be a file or folder and will loop when necessary.',
|
||||
storageExtension: 'Specify which files to search and use.',
|
||||
storageShuffle: 'Pick files randomly (in folder mode and playlist generation).',
|
||||
textHelp: 'Overlay text in combination with libzmq for remote text manipulation.',
|
||||
textFont: 'Relative path to channel storage.',
|
||||
textFromFile: 'Extraction of text from a filename.',
|
||||
textStyle: 'Define the drawtext parameters, such as position, color, etc. Posting text over the API will override this.',
|
||||
textRegex: 'Format file names to extract a title from them.',
|
||||
taskHelp: 'Run an external program with a given media object. The media object is in JSON format and contains all the information about the current clip. The external program can be a script or a binary, but it should only run for a short time.',
|
||||
taskPath: 'Path to executable.',
|
||||
outputHelp: `The final playout encoding, set the settings according to your needs. Use 'stream' mode and adjust the 'Output Parameter' when you want to stream to an RTMP/RTSP/SRT/... server.
|
||||
In production, don't serve HLS playlists with ffplayout; use Nginx or another web server!`,
|
||||
restartTile: 'Перезапуск Playout',
|
||||
restartText: 'Перезапустить ffplayout для применения изменений?',
|
||||
|
@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="flex w-full h-[calc(100vh-60px)] ps-1">
|
||||
<div class="flex-none w-[70px] join join-vertical me-3 pt-7">
|
||||
<div class="flex flex-wrap xs:flex-nowrap w-full xs:h-[calc(100vh-60px)] ps-1">
|
||||
<div class="xs:flex-none w-full xs:w-[68px] join join-horizontal xs:join-vertical me-1 pt-7">
|
||||
<button
|
||||
class="join-item w-full btn btn-sm btn-primary duration-500"
|
||||
class="join-item btn btn-sm btn-primary duration-500"
|
||||
:class="activeConf === 1 && 'btn-secondary'"
|
||||
@click="activeConf = 1"
|
||||
>
|
||||
@ -10,28 +10,28 @@
|
||||
</button>
|
||||
<button
|
||||
v-if="authStore.role === 'GlobalAdmin'"
|
||||
class="join-item w-full btn btn-sm btn-primary duration-500"
|
||||
class="join-item btn btn-sm btn-primary duration-500"
|
||||
:class="activeConf === 2 && 'btn-secondary'"
|
||||
@click="activeConf = 2"
|
||||
>
|
||||
Advanced
|
||||
</button>
|
||||
<button
|
||||
class="join-item w-full btn btn-sm btn-primary mt-1 duration-500"
|
||||
class="join-item btn btn-sm btn-primary mt-1 duration-500"
|
||||
:class="activeConf === 3 && 'btn-secondary'"
|
||||
@click="activeConf = 3"
|
||||
>
|
||||
Playout
|
||||
</button>
|
||||
<button
|
||||
class="join-item w-full btn btn-sm btn-primary mt-1 duration-500"
|
||||
class="join-item btn btn-sm btn-primary mt-1 duration-500"
|
||||
:class="activeConf === 4 && 'btn-secondary'"
|
||||
@click="activeConf = 4"
|
||||
>
|
||||
{{ t('config.user') }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="w-[calc(100%-70px)] mt-6 px-6 overflow-auto">
|
||||
<div class="w-full xs:w-[calc(100%-70px)] mt-6 px-3 xs:px-6 overflow-auto">
|
||||
<div>
|
||||
<div v-if="activeConf === 1" class="w-full flex justify-center">
|
||||
<ConfigChannel />
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { defineStore } from 'pinia'
|
||||
import type { AdvancedConfig } from '~/types/advanced_config'
|
||||
|
||||
|
||||
export const useConfig = defineStore('config', {
|
||||
@ -10,7 +11,7 @@ export const useConfig = defineStore('config', {
|
||||
channels: [] as Channel[],
|
||||
channelsRaw: [] as Channel[],
|
||||
playlistLength: 86400.0,
|
||||
advanced: {} as any,
|
||||
advanced: {} as AdvancedConfig,
|
||||
playout: {} as PlayoutConfigExt,
|
||||
currentUser: 0,
|
||||
configUser: {} as User,
|
||||
|
11
frontend/types/advanced_config.d.ts
vendored
Normal file
11
frontend/types/advanced_config.d.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type AdvancedConfig = { decoder: DecoderConfig, encoder: EncoderConfig, filter: FilterConfig, ingest: IngestConfig, };
|
||||
|
||||
export type DecoderConfig = { input_param: string, output_param: string, };
|
||||
|
||||
export type EncoderConfig = { input_param: string, };
|
||||
|
||||
export type FilterConfig = { deinterlace: string, pad_scale_w: string, pad_scale_h: string, pad_video: string, fps: string, scale: string, set_dar: string, fade_in: string, fade_out: string, overlay_logo_scale: string, overlay_logo_fade_in: string, overlay_logo_fade_out: string, overlay_logo: string, tpad: string, drawtext_from_file: string, drawtext_from_zmq: string, aevalsrc: string, afade_in: string, afade_out: string, apad: string, volume: string, split: string, };
|
||||
|
||||
export type IngestConfig = { input_param: string, };
|
1
frontend/types/index.d.ts
vendored
1
frontend/types/index.d.ts
vendored
@ -1,4 +1,5 @@
|
||||
import type { JwtPayload } from 'jwt-decode'
|
||||
import type { AdvancedConfig } from '~/types/advanced_config'
|
||||
import type { PlayoutConfig, Playlist as Ply } from '~/types/playout_config'
|
||||
|
||||
export {}
|
||||
|
2
frontend/types/playout_config.d.ts
vendored
2
frontend/types/playout_config.d.ts
vendored
@ -25,7 +25,7 @@ export type ProcessMode = "folder" | "playlist";
|
||||
|
||||
export type Processing = { mode: ProcessMode, audio_only: boolean, copy_audio: boolean, copy_video: boolean, width: bigint, height: bigint, aspect: number, fps: number, add_logo: boolean, logo: string, logo_scale: string, logo_opacity: number, logo_position: string, audio_tracks: number, audio_track_index: number, audio_channels: number, volume: number, custom_filter: string, vtt_enable: boolean, vtt_dummy: string | null, };
|
||||
|
||||
export type Storage = { filler: string, extensions: Array<string>, shuffle: boolean, };
|
||||
export type Storage = { filler: string, extensions: Array<string>, shuffle: boolean, shared_storage: boolean, };
|
||||
|
||||
export type Task = { enable: boolean, path: string, };
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user