v 0.1.1
This commit is contained in:
23
.env.example
23
.env.example
@@ -1,12 +1,19 @@
|
|||||||
# Synology NAS
|
# Synology NAS
|
||||||
NAS_FQDN=https://your-nas.domain.com
|
NAS_FQDN="https://your-nas.example.com"
|
||||||
NAS_USER=your_username
|
NAS_USER="your_username"
|
||||||
NAS_PASS=your_password
|
NAS_PASS="your_password"
|
||||||
NAS_FILE=/team-folders/path/to/your/file.osheet
|
NAS_FILE="/Team Folder/path/to/file.osheet"
|
||||||
|
|
||||||
|
#Loging
|
||||||
|
RUST_LOG="info"
|
||||||
|
|
||||||
# Nexrender
|
# Nexrender
|
||||||
NEXRENDER_API_URL=http://your-nexrender-server:3000/api/v1/jobs
|
NEXRENDER_API_URL="http://nexrender-server:3050/api/v1/jobs"
|
||||||
OUTPUT_FOLDER=//your-storage/path/to/output
|
OUTPUT_FOLDER="/path/to/output"
|
||||||
|
|
||||||
# Logging
|
# After Effects Templates
|
||||||
RUST_LOG=info
|
TEMPLATE_DOUBLE_SRC="file:///path/to/double_team_template.aepx"
|
||||||
|
TEMPLATE_SINGLE_SRC="file:///path/to/single_team_template.aepx"
|
||||||
|
TEMPLATE_COMPOSITION="main"
|
||||||
|
TEMPLATE_OUTPUT_MODULE="h264"
|
||||||
|
TEMPLATE_OUTPUT_EXT="mp4"
|
||||||
31
README.md
31
README.md
@@ -114,7 +114,7 @@ RUST_LOG=debug cargo run
|
|||||||
### Переменные окружения
|
### Переменные окружения
|
||||||
|
|
||||||
| Переменная | Обязательна | Описание |
|
| Переменная | Обязательна | Описание |
|
||||||
|---------------------|-------------|------------------------------------------------------|
|
|-------------------------|-------------|------------------------------------------------------|
|
||||||
| `NAS_FQDN` | Да | URL NAS Synology с протоколом и портом |
|
| `NAS_FQDN` | Да | URL NAS Synology с протоколом и портом |
|
||||||
| `NAS_USER` | Да | Имя пользователя учетной записи Synology |
|
| `NAS_USER` | Да | Имя пользователя учетной записи Synology |
|
||||||
| `NAS_PASS` | Да | Пароль учетной записи Synology |
|
| `NAS_PASS` | Да | Пароль учетной записи Synology |
|
||||||
@@ -122,6 +122,35 @@ RUST_LOG=debug cargo run
|
|||||||
| `NEXRENDER_API_URL` | Да | Конечная точка API сервера Nexrender |
|
| `NEXRENDER_API_URL` | Да | Конечная точка API сервера Nexrender |
|
||||||
| `OUTPUT_FOLDER` | Да | Сетевой путь для рендеренных видео |
|
| `OUTPUT_FOLDER` | Да | Сетевой путь для рендеренных видео |
|
||||||
| `RUST_LOG` | Нет | Уровень детализации логирования (по умолчанию: info) |
|
| `RUST_LOG` | Нет | Уровень детализации логирования (по умолчанию: info) |
|
||||||
|
| `TEMPLATE_DOUBLE_SRC` | Да | Путь к AEP-шаблону для двух команд |
|
||||||
|
| `TEMPLATE_SINGLE_SRC` | Да | Путь к AEP-шаблону для одной команды |
|
||||||
|
| `TEMPLATE_COMPOSITION` | Да | Имя композиции в проекте AE (например, `main`) |
|
||||||
|
| `TEMPLATE_OUTPUT_MODULE`| Да | Имя модуля вывода в AE (например, `h264`) |
|
||||||
|
| `TEMPLATE_OUTPUT_EXT` | Да | Расширение выходного файла (например, `mp4`) |
|
||||||
|
|
||||||
|
### Пример файла `.env`
|
||||||
|
|
||||||
|
```env
|
||||||
|
# Synology NAS
|
||||||
|
NAS_FQDN="https://your-nas.example.com"
|
||||||
|
NAS_USER="your_username"
|
||||||
|
NAS_PASS="your_password"
|
||||||
|
NAS_FILE="/Team Folder/path/to/file.osheet"
|
||||||
|
|
||||||
|
#Loging
|
||||||
|
RUST_LOG="info"
|
||||||
|
|
||||||
|
# Nexrender
|
||||||
|
NEXRENDER_API_URL="http://nexrender-server:3050/api/v1/jobs"
|
||||||
|
OUTPUT_FOLDER="/path/to/output"
|
||||||
|
|
||||||
|
# After Effects Templates
|
||||||
|
TEMPLATE_DOUBLE_SRC="file:///path/to/double_team_template.aepx"
|
||||||
|
TEMPLATE_SINGLE_SRC="file:///path/to/single_team_template.aepx"
|
||||||
|
TEMPLATE_COMPOSITION="main"
|
||||||
|
TEMPLATE_OUTPUT_MODULE="h264"
|
||||||
|
TEMPLATE_OUTPUT_EXT="mp4"
|
||||||
|
```
|
||||||
|
|
||||||
## Структура электронной таблицы
|
## Структура электронной таблицы
|
||||||
|
|
||||||
|
|||||||
10
src/main.rs
10
src/main.rs
@@ -357,10 +357,12 @@ async fn process_nexrender_jobs(workbook: &ExcelWorkbook, config: &Config) -> Re
|
|||||||
for job in jobs {
|
for job in jobs {
|
||||||
let client = http_client.clone();
|
let client = http_client.clone();
|
||||||
let api_url = config.nexrender_api_url.clone();
|
let api_url = config.nexrender_api_url.clone();
|
||||||
let output_folder = config.output_folder.clone();
|
let config_clone = config.clone(); // ✅ Клонируем весь конфиг
|
||||||
|
|
||||||
tasks.push(tokio::spawn(async move {
|
tasks.push(tokio::spawn(async move {
|
||||||
let nexrender_job = job.to_nexrender_job(&output_folder);
|
let nexrender_job = job.to_nexrender_job(&config_clone); // ✅ Передаём Config
|
||||||
|
info!("Submitting job: {}", job.outfile_name);
|
||||||
|
|
||||||
let response = client.post(&api_url).json(&nexrender_job).send().await?;
|
let response = client.post(&api_url).json(&nexrender_job).send().await?;
|
||||||
|
|
||||||
if response.status().is_success() {
|
if response.status().is_success() {
|
||||||
@@ -371,7 +373,9 @@ async fn process_nexrender_jobs(workbook: &ExcelWorkbook, config: &Config) -> Re
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error!("Failed to submit job: {}", job.outfile_name);
|
let status = response.status();
|
||||||
|
let text = response.text().await.unwrap_or_default();
|
||||||
|
error!("Failed to submit job ({}): {}", status, text);
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -90,22 +90,32 @@ pub struct Template {
|
|||||||
pub output_ext: String,
|
pub output_ext: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Template {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
src: "file:///c:/users/virtVmix-2/Downloads/PackShot_DOUBLE.aepx".to_string(),
|
|
||||||
composition: "pack".to_string(),
|
|
||||||
output_module: "Start_h264".to_string(),
|
|
||||||
output_ext: "mp4".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Template {
|
impl Template {
|
||||||
pub fn single() -> Self {
|
pub fn double(
|
||||||
|
src: String,
|
||||||
|
composition: String,
|
||||||
|
output_module: String,
|
||||||
|
output_ext: String,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
src: "file:///c:/users/virtVmix-2/Downloads/PackShot_SINGLE.aepx".to_string(),
|
src,
|
||||||
..Default::default()
|
composition,
|
||||||
|
output_module,
|
||||||
|
output_ext,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn single(
|
||||||
|
src: String,
|
||||||
|
composition: String,
|
||||||
|
output_module: String,
|
||||||
|
output_ext: String,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
src,
|
||||||
|
composition,
|
||||||
|
output_module,
|
||||||
|
output_ext,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -292,17 +302,32 @@ impl JobData {
|
|||||||
variants
|
variants
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_nexrender_job(&self, output_folder: &str) -> NexrenderJob {
|
// ЕДИНСТВЕННАЯ реализация метода
|
||||||
|
pub fn to_nexrender_job(&self, config: &crate::config::Config) -> NexrenderJob {
|
||||||
let template = if self.team_b.is_empty() {
|
let template = if self.team_b.is_empty() {
|
||||||
Template::single()
|
Template::single(
|
||||||
|
config.template_single_src.clone(),
|
||||||
|
config.template_composition.clone(),
|
||||||
|
config.template_output_module.clone(),
|
||||||
|
config.template_output_ext.clone(),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
Template::default()
|
Template::double(
|
||||||
|
config.template_double_src.clone(),
|
||||||
|
config.template_composition.clone(),
|
||||||
|
config.template_output_module.clone(),
|
||||||
|
config.template_output_ext.clone(),
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let output_path = format!("{}/{}.mp4", output_folder, self.outfile_name);
|
let output_path = format!(
|
||||||
|
"{}/{}.{}",
|
||||||
|
config.output_folder, self.outfile_name, config.template_output_ext
|
||||||
|
);
|
||||||
|
|
||||||
let mut actions = Actions::default();
|
let mut actions = Actions::default();
|
||||||
actions.postrender.push(PostrenderAction::Copy {
|
actions.postrender.push(PostrenderAction::Copy {
|
||||||
input: "encoded.mp4".to_string(),
|
input: format!("encoded.{}", config.template_output_ext),
|
||||||
output: output_path,
|
output: output_path,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -503,16 +528,16 @@ impl LogoRegistry {
|
|||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, team: String, sport: String, link: String) {
|
|
||||||
self.logos.insert((team, sport), link);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_capacity(capacity: usize) -> Self {
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
logos: HashMap::with_capacity(capacity),
|
logos: HashMap::with_capacity(capacity),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, team: String, sport: String, link: String) {
|
||||||
|
self.logos.insert((team, sport), link);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn find(&self, team: &str, sport: &str) -> Option<String> {
|
pub fn find(&self, team: &str, sport: &str) -> Option<String> {
|
||||||
if let Some(link) = self.logos.get(&(team.to_string(), sport.to_string())) {
|
if let Some(link) = self.logos.get(&(team.to_string(), sport.to_string())) {
|
||||||
return Some(link.clone());
|
return Some(link.clone());
|
||||||
|
|||||||
Reference in New Issue
Block a user