Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## Version 6.1.1

* Adding "Show completion popup message" (default off) and "Show error popup message" (default on) settings, replacing the old "Disable completion and error messages" toggle (thanks to Balthazar)
* Adding #703 precise frame-based trimming (--trim) for rigaya encoders (NVEncC, QSVEncC, VCEEncC) when using Exact seek mode (thanks to Augusto7743)
* Fixing #722 Timeout while extracting covers (thanks to larsk2)
* Fixing #722 Bottom Crop words cut off (thanks to larsk2)

## Version 6.1.0

* Adding #717 Output Naming settings tab with template editor, clickable variable chips, live preview, and validation for customizing output filenames with 23 pre-encode variables (thanks to roxerqermik)
Expand Down
210 changes: 210 additions & 0 deletions fastflix/data/languages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13947,3 +13947,213 @@ top:
ukr: верхній
kor: top
ron: top
Output Filename Template:
eng: Output Filename Template
deu: Vorlage für Ausgabedateinamen
fra: Modèle de nom de fichier de sortie
ita: Modello di nome del file di output
spa: Plantilla de nombre de archivo de salida
jpn: 出力ファイル名テンプレート
rus: Шаблон имени выходного файла
por: Modelo de nome de ficheiro de saída
swe: Mall för utdatafilens namn
pol: Szablon nazwy pliku wyjściowego
chs: 输出文件名模板
ukr: Шаблон імені вихідного файлу
kor: 출력 파일 이름 템플릿
ron: Șablon nume fișier de ieșire
Reset to default template:
eng: Reset to default template
deu: Auf Standardvorlage zurücksetzen
fra: Réinitialiser le modèle par défaut
ita: Ripristino del modello predefinito
spa: Restablecer plantilla por defecto
jpn: デフォルトテンプレートにリセット
rus: Сброс к шаблону по умолчанию
por: Repor o modelo predefinido
swe: Återställ till standardmall
pol: Przywróć domyślny szablon
chs: 重置为默认模板
ukr: Скидання до шаблону за замовчуванням
kor: 기본 템플릿으로 재설정
ron: Resetare la șablonul implicit
"Preview:":
eng: "Preview:"
deu: 'Vorschau:'
fra: 'Avant-première :'
ita: 'Anteprima:'
spa: 'Vista previa:'
jpn: プレビュー
rus: 'Предпросмотр:'
por: 'Pré-visualização:'
swe: 'Förhandsgranskning:'
pol: 'Podgląd:'
chs: 预览:
ukr: 'Попередній перегляд:'
kor: '미리 보기:'
ron: 'Previzualizare:'
Pre-Encode Variables:
eng: Pre-Encode Variables
deu: Variablen vorcodieren
fra: Pré-codage des variables
ita: Pre-codifica delle variabili
spa: Precodificación de variables
jpn: 変数の事前エンコード
rus: Предварительное кодирование переменных
por: Pré-codificar variáveis
swe: Förkoda variabler
pol: Wstępne kodowanie zmiennych
chs: 预编码变量
ukr: Змінні попереднього кодування
kor: 사전 인코딩 변수
ron: Pre-codificarea variabilelor
Example:
eng: Example
deu: Beispiel
fra: Exemple
ita: Esempio
spa: Ejemplo
jpn: 例
rus: Пример
por: Exemplo
swe: Exempel
pol: Przykład
chs: 示例
ukr: Приклад
kor: 예
ron: Exemplu
Post-Encode Variables:
eng: Post-Encode Variables
deu: Post-Encode-Variablen
fra: Variables post-codées
ita: Variabili post-codifica
spa: Variables postcodificación
jpn: ポスト・エンコード変数
rus: Переменные после кодирования
por: Variáveis pós-codificadas
swe: Variabler efter kodning
pol: Zmienne po zakodowaniu
chs: 编码后变量
ukr: Змінні після кодування
kor: 인코딩 후 변수
ron: Variabilele Post-Encode
Resolved after encoding completes; file will be renamed automatically:
eng: Resolved after encoding completes; file will be renamed automatically
deu: Nach Abschluss der Kodierung behoben; die Datei wird automatisch umbenannt
fra: Résolu une fois l'encodage terminé ; le fichier sera renommé automatiquement.
ita: Risolto al termine della codifica; il file verrà rinominato automaticamente.
spa: Resuelto una vez finalizada la codificación; el archivo se renombrará automáticamente.
jpn: エンコード完了後に解決。ファイル名は自動的に変更されます。
rus: Устранено после завершения кодирования; файл будет переименован автоматически
por: Resolvido após a conclusão da codificação; o ficheiro será renomeado automaticamente
swe: Löses efter att kodningen är klar; filen kommer att döpas om automatiskt
pol: Rozwiązane po zakończeniu kodowania; nazwa pliku zostanie zmieniona automatycznie.
chs: 编码完成后已解决;文件将自动重命名
ukr: Вирішено після завершення кодування; файл буде перейменовано автоматично
kor: 인코딩이 완료된 후 해결되며 파일 이름이 자동으로 변경됩니다.
ron: Rezolvat după finalizarea codării; fișierul va fi redenumit automat
Description:
eng: Description
deu: Beschreibung
fra: Description
ita: Descrizione
spa: Descripción
jpn: 説明
rus: Описание
por: Descrição
swe: Beskrivning
pol: Opis
chs: 说明
ukr: Опис
kor: 설명
ron: Descriere
Phase:
eng: Phase
deu: Phase
fra: Phase
ita: Fase
spa: Fase
jpn: フェーズ
rus: Фаза
por: Fase
swe: Fas
pol: Faza
chs: 阶段
ukr: Фаза
kor: 단계
ron: Faza
Pre-Encode:
eng: Pre-Encode
deu: Vor-Codierung
fra: Pré-encodage
ita: Pre-codifica
spa: Precodificación
jpn: プリ・エンコード
rus: Предварительное кодирование
por: Pré-codificar
swe: Förkodning
pol: Wstępne kodowanie
chs: 预编码
ukr: Попередній код
kor: 사전 인코딩
ron: Pre-codificare
Post-Encode:
eng: Post-Encode
deu: Post-Encode
fra: Post-Encode
ita: Post-codifica
spa: Post-Encode
jpn: ポスト・エンコード
rus: Post-Encode
por: Pós-codificação
swe: Post-kodning
pol: Post-Encode
chs: 编码后
ukr: Пост-енкод
kor: 인코딩 후
ron: Post-codificare
Output Naming:
eng: Output Naming
deu: Benennung der Ausgabe
fra: Désignation des sorties
ita: Denominazione dell'uscita
spa: Nombres de salida
jpn: 出力ネーミング
rus: Именование выходных данных
por: Nomeação de saída
swe: Namngivning av utdata
pol: Nazewnictwo wyjścia
chs: 输出命名
ukr: Іменування виходів
kor: 출력 이름 지정
ron: Denumiri de ieșire
Show completion popup message:
eng: Show completion popup message
deu: Popup-Meldung zum Abschluss anzeigen
fra: Afficher le message d'achèvement
ita: Mostra il messaggio popup di completamento
spa: Mostrar mensaje emergente de finalización
jpn: 完了ポップアップメッセージの表示
rus: Показать всплывающее сообщение о завершении
por: Mostrar mensagem pop-up de conclusão
swe: Visa popup-meddelande om slutförande
pol: Pokaż wyskakujący komunikat ukończenia
chs: 弹出显示完成信息
ukr: Показати спливаюче повідомлення про завершення
kor: 완료 팝업 메시지 표시
ron: Afișați mesajul pop-up de finalizare
Show error popup message:
eng: Show error popup message
deu: Fehler-Popup-Meldung anzeigen
fra: Afficher un message d'erreur
ita: Mostra il messaggio popup di errore
spa: Mostrar mensaje emergente de error
jpn: エラーのポップアップメッセージを表示する
rus: Показать всплывающее сообщение об ошибке
por: Mostrar mensagem pop-up de erro
swe: Visa popup-meddelande för fel
pol: Pokaż wyskakujący komunikat o błędzie
chs: 弹出错误信息
ukr: Показати спливаюче повідомлення про помилку
kor: 오류 팝업 메시지 표시
ron: Afișați mesajul pop-up de eroare
54 changes: 52 additions & 2 deletions fastflix/encoders/common/encc_helpers.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
import logging
from typing import List
from typing import List, Optional

from fastflix.models.video import SubtitleTrack, AudioTrack, DataTrack
from fastflix.models.video import SubtitleTrack, AudioTrack, DataTrack, Video
from fastflix.encoders.common.audio import lossless
from fastflix.models.fastflix import FastFlix
from fastflix.models.encode import VCEEncCAVCSettings, VCEEncCAV1Settings, VCEEncCSettings
Expand Down Expand Up @@ -72,6 +72,56 @@ def rigaya_auto_options(fastflix: FastFlix) -> List[str]:
]


def _parse_frame_rate(frame_rate_str: str) -> Optional[float]:
"""Parse a frame rate string like '24000/1001' or '30' into a float.

Returns None if the string is empty or cannot be parsed.
"""
if not frame_rate_str:
return None
try:
if "/" in frame_rate_str:
num, den = frame_rate_str.split("/", 1)
denominator = float(den)
if denominator == 0:
return None
return float(num) / denominator
return float(frame_rate_str)
except (ValueError, ZeroDivisionError):
return None


def rigaya_trim_or_seek(video: Video) -> List[str]:
"""Build time trimming arguments for rigaya encoders.

In exact mode (fast_seek=False), uses --trim with frame numbers for precise cutting.
In fast mode (fast_seek=True), uses --seek/--seekto with timestamps.
Falls back to --seek/--seekto if frame rate is unavailable in exact mode.
"""
start_time = video.video_settings.start_time
end_time = video.video_settings.end_time

if not start_time and not end_time:
return []

if not video.video_settings.fast_seek:
fps = _parse_frame_rate(video.frame_rate)
if fps:
start_frame = int(start_time * fps) if start_time else 0
if end_time:
end_frame = int(end_time * fps)
else:
end_frame = int(video.duration * fps)
return ["--trim", f"{start_frame}:{end_frame}"]

result = []
if start_time:
result.extend(["--seek", str(start_time)])
if end_time:
result.extend(["--seekto", str(end_time)])
return result


def pa_builder(settings: VCEEncCAVCSettings | VCEEncCAV1Settings | VCEEncCSettings):
if not settings.pre_analysis:
return ""
Expand Down
6 changes: 2 additions & 4 deletions fastflix/encoders/nvencc_av1/command_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
build_data,
rigaya_auto_options,
rigaya_avformat_reader,
rigaya_trim_or_seek,
)

logger = logging.getLogger("fastflix")
Expand Down Expand Up @@ -63,10 +64,7 @@ def build(fastflix: FastFlix):

if stream_id:
command.extend(["--video-streamid", str(stream_id)])
if video.video_settings.start_time:
command.extend(["--seek", str(video.video_settings.start_time)])
if video.video_settings.end_time:
command.extend(["--seekto", str(video.video_settings.end_time)])
command.extend(rigaya_trim_or_seek(video))
if video.video_settings.source_fps:
command.extend(["--fps", str(video.video_settings.source_fps)])
if video.video_settings.rotate:
Expand Down
6 changes: 2 additions & 4 deletions fastflix/encoders/nvencc_avc/command_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
build_data,
rigaya_auto_options,
rigaya_avformat_reader,
rigaya_trim_or_seek,
)

logger = logging.getLogger("fastflix")
Expand Down Expand Up @@ -57,10 +58,7 @@ def build(fastflix: FastFlix):

if stream_id:
command.extend(["--video-streamid", str(stream_id)])
if video.video_settings.start_time:
command.extend(["--seek", str(video.video_settings.start_time)])
if video.video_settings.end_time:
command.extend(["--seekto", str(video.video_settings.end_time)])
command.extend(rigaya_trim_or_seek(video))
if video.video_settings.source_fps:
command.extend(["--fps", str(video.video_settings.source_fps)])
if video.video_settings.rotate:
Expand Down
6 changes: 2 additions & 4 deletions fastflix/encoders/nvencc_hevc/command_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
build_data,
rigaya_auto_options,
rigaya_avformat_reader,
rigaya_trim_or_seek,
)

logger = logging.getLogger("fastflix")
Expand Down Expand Up @@ -63,10 +64,7 @@ def build(fastflix: FastFlix):

if stream_id:
command.extend(["--video-streamid", str(stream_id)])
if video.video_settings.start_time:
command.extend(["--seek", str(video.video_settings.start_time)])
if video.video_settings.end_time:
command.extend(["--seekto", str(video.video_settings.end_time)])
command.extend(rigaya_trim_or_seek(video))
if video.video_settings.source_fps:
command.extend(["--fps", str(video.video_settings.source_fps)])
if video.video_settings.rotate:
Expand Down
7 changes: 2 additions & 5 deletions fastflix/encoders/qsvencc_av1/command_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
build_data,
rigaya_auto_options,
rigaya_avformat_reader,
rigaya_trim_or_seek,
)

logger = logging.getLogger("fastflix")
Expand Down Expand Up @@ -58,11 +59,7 @@ def build(fastflix: FastFlix):
if stream_id:
command.extend(["--video-streamid", str(stream_id)])

if video.video_settings.start_time:
command.extend(["--seek", str(video.video_settings.start_time)])

if video.video_settings.end_time:
command.extend(["--seekto", str(video.video_settings.end_time)])
command.extend(rigaya_trim_or_seek(video))

if video.video_settings.source_fps:
command.extend(["--fps", str(video.video_settings.source_fps)])
Expand Down
7 changes: 2 additions & 5 deletions fastflix/encoders/qsvencc_avc/command_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
build_data,
rigaya_auto_options,
rigaya_avformat_reader,
rigaya_trim_or_seek,
)

logger = logging.getLogger("fastflix")
Expand Down Expand Up @@ -58,11 +59,7 @@ def build(fastflix: FastFlix):
if stream_id:
command.extend(["--video-streamid", str(stream_id)])

if video.video_settings.start_time:
command.extend(["--seek", str(video.video_settings.start_time)])

if video.video_settings.end_time:
command.extend(["--seekto", str(video.video_settings.end_time)])
command.extend(rigaya_trim_or_seek(video))

if video.video_settings.source_fps:
command.extend(["--fps", str(video.video_settings.source_fps)])
Expand Down
Loading