FF-1886: Create video thumbnail flow element

This commit is contained in:
John Andrews
2024-10-20 21:31:15 +13:00
parent 8331480a6c
commit cf52a9a9fd
14 changed files with 307 additions and 25 deletions

View File

@@ -22,8 +22,7 @@ public class CreateThumbnail : VideoNode
/// Gets or sets the destination path for zipping.
/// </summary>
[TextVariable(1)]
[Required]
public string Destination { get; set; } = string.Empty;
public string OutputFile { get; set; }
/// <summary>
/// The width of the thumbnail.
@@ -104,6 +103,10 @@ public class CreateThumbnail : VideoNode
return -1;
}
string localFile = lfResult.Value;
string output = args.ReplaceVariables(OutputFile, stripMissing: true);
if (string.IsNullOrWhiteSpace(output))
output = FileHelper.ChangeExtension(args.FileName, "jpg");
// Ensure time is within bounds
TimeSpan captureTime = GetValidCaptureTime(videoInfo.VideoStreams[0].Duration);
@@ -136,23 +139,14 @@ public class CreateThumbnail : VideoNode
return 2;
}
string dest = args.ReplaceVariables(Destination, stripMissing: true);
if (string.IsNullOrWhiteSpace(dest))
if (args.FileService.FileMove(resizedThumbnailPath, output).Failed(out error))
{
dest = resizedThumbnailPath;
args.Logger?.WLog("Failed to move file: " + error);
return 2;
}
else
{
if (args.FileService.FileMove(resizedThumbnailPath, dest).Failed(out error))
{
args.Logger?.WLog("Failed to move file: " + error);
return 2;
}
}
args.Logger?.ILog("Thumbnail Path: " + dest);
args.Logger?.ILog("Thumbnail Path: " + output);
// Set output variable
args.UpdateVariables(new Dictionary<string, object> { { "ThumbnailPath", dest } });
args.UpdateVariables(new Dictionary<string, object> { { "ThumbnailPath", output } });
return 1;
}
catch (Exception ex)
@@ -205,6 +199,8 @@ public class CreateThumbnail : VideoNode
args.Logger?.ELog("FFmpeg failed to capture thumbnail.");
return false;
}
args.LogImage(outputPath);
return true;
}

View File

@@ -51,6 +51,28 @@
"2": "Keine Werbespots entdeckt"
}
},
"CreateThumbnail": {
"Description": "Erstellt ein Thumbnail-Bild aus einer Videodatei.",
"Label": "Thumbnail erstellen",
"Fields": {
"Height": "Höhe",
"Height-Help": "Die Höhe des Thumbnail-Bildes.",
"OutputFile": "Ausgabedatei",
"OutputFile-Help": "Der Dateipfad, in dem das Thumbnail-Bild gespeichert wird. Wenn das Feld leer bleibt, wird eine .jpg-Datei im selben Verzeichnis wie die Originaldatei erstellt.",
"ResizeMode": "Modus",
"ResizeMode-Help": "Die Methode, die zum Skalieren des Bildes verwendet wird.",
"SkipBlackFrames": "Schwarze Frames überspringen",
"SkipBlackFrames-Help": "Wenn aktiviert, wird ein schwarzer Frame übersprungen und ein anderer Frame verwendet.",
"Time": "Zeit",
"Time-Help": "Die Zeit im Video, aus der das Thumbnail erstellt wird.",
"Width": "Breite",
"Width-Help": "Die Breite des Thumbnail-Bildes."
},
"Outputs": {
"1": "Thumbnail erstellt.",
"2": "Thumbnail konnte nicht erstellt werden."
}
},
"DisableAmd": {
"Description": "Deaktiviert den AMD AMF Hardware-Encoder",
"Label": "Deaktiviert AMD",

View File

@@ -51,6 +51,28 @@
"2": "No commercials detected"
}
},
"CreateThumbnail": {
"Description": "Creates a thumbnail image from a video file.",
"Label": "Create Thumbnail",
"Fields": {
"Height": "Height",
"Height-Help": "The height of the thumbnail image.",
"OutputFile": "Output File",
"OutputFile-Help": "The file path where the thumbnail image will be saved. If left blank, a .jpg file will be created in the same location as the original file.",
"ResizeMode": "Mode",
"ResizeMode-Help": "The method used for resizing the image.",
"SkipBlackFrames": "Skip Black Frames",
"SkipBlackFrames-Help": "If enabled, the system will skip black frames and select another frame instead.",
"Time": "Time",
"Time-Help": "The time in the video from which to capture the thumbnail.",
"Width": "Width",
"Width-Help": "The width of the thumbnail image."
},
"Outputs": {
"1": "Thumbnail created.",
"2": "Failed to create thumbnail."
}
},
"DisableAmd": {
"Description": "Disables AMD AMF hardware encoder",
"Label": "Disable AMD",
@@ -845,27 +867,27 @@
}
},
"SubtitleExtractor": {
"Description": "Extract a single subtitle tracks and saves it to the destination. Can extract srt, ass, and ssa format.\nThis will NOT update the working file, and will keep the working file the same as the input file.\n\nOutput 1: Subtitles were extracted\nOutput 2: No subtitles found to extract",
"Description": "Extracts a single subtitle track and saves it to the specified destination. Supports extraction of SRT, ASS, and SSA formats.\nThis operation does NOT modify the working file; it will remain unchanged from the input file.\n\nOutput 1: Subtitles extracted successfully.\nOutput 2: No subtitles found to extract.",
"Label": "Subtitle Extractor",
"Fields": {
"ExtractAll": "Extract All",
"ExtractAll-Help": "If all matching subtitles should be extracted.",
"ExtractAll-Help": "Whether to extract all matching subtitles.",
"ForcedOnly": "Forced Only",
"ForcedOnly-Help": "If only forced subtitles should be extracted.",
"ForcedOnly-Help": "Whether to extract only forced subtitles.",
"Language": "Language",
"Language-Help": "The [ISO 639-2](https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes) language code to use.",
"OnlyTextSubtitles": "Only Text Subtitles",
"OnlyTextSubtitles-Help": "If only text subtitles should be extracted, all image based subtitles will be skipped.",
"OnlyTextSubtitles-Help": "Whether to extract only text subtitles; all image-based subtitles will be skipped.",
"OutputFile": "Output File",
"OutputFile-Help": "Where to save the the output file to, e.g. \"'{folder.Orig.FullName}\\{file.Orig.FileName}.srt'\" to save it with the original file as a srt output.\nIf left blank an srt subtitle will be created in the same folder as the original input file.",
"OutputFile-Help": "Location to save the extracted subtitle. If left blank, a .srt file will be created in the same location as the original file.",
"SetWorkingFile": "Set as Working File",
"SetWorkingFile-Help": "When this is checked, if a subtitle is extracted, the working file will be changed to this extracted subtitle. The original working file will NOT be deleted.",
"SetWorkingFile-Help": "If checked, the working file will be updated to this extracted subtitle if one is successfully extracted. The original working file will not be deleted.",
"Title": "Title",
"Title-Help": "Optionally, enter a title. This can be either a regular expression or a string that must appear in the title to be matched."
"Title-Help": "Optionally enter a title. This can be either a regular expression or a string that must appear in the title to match."
},
"Outputs": {
"1": "Subtitles extracted",
"2": "No subtitles extracted"
"1": "Subtitles extracted successfully.",
"2": "No subtitles extracted."
}
},
"VideoAlreadyProcessed": {

View File

@@ -51,6 +51,28 @@
"2": "No se detectaron comerciales"
}
},
"CreateThumbnail": {
"Description": "Crea una imagen miniatura de un archivo de video.",
"Label": "Crear Miniatura",
"Fields": {
"Height": "Altura",
"Height-Help": "La altura de la imagen miniatura.",
"OutputFile": "Archivo de Salida",
"OutputFile-Help": "La ruta del archivo donde se guardará la imagen miniatura. Si se deja en blanco, se creará un archivo .jpg en la misma ubicación que el archivo original.",
"ResizeMode": "Modo",
"ResizeMode-Help": "El método utilizado para redimensionar la imagen.",
"SkipBlackFrames": "Omitir Marcos Negros",
"SkipBlackFrames-Help": "Si está activado, se omitirán los marcos negros y se seleccionará otro marco.",
"Time": "Tiempo",
"Time-Help": "El tiempo en el video del que se capturará la miniatura.",
"Width": "Ancho",
"Width-Help": "El ancho de la imagen miniatura."
},
"Outputs": {
"1": "Miniatura creada.",
"2": "Error al crear la miniatura."
}
},
"DisableAmd": {
"Description": "Desactiva el codificador de hardware AMD AMF",
"Label": "Desactivar AMD",

View File

@@ -51,6 +51,28 @@
"2": "Aucune publicité détectée"
}
},
"CreateThumbnail": {
"Description": "Crée une image miniature à partir d'un fichier vidéo.",
"Label": "Créer une miniature",
"Fields": {
"Height": "Hauteur",
"Height-Help": "La hauteur de l'image miniature.",
"OutputFile": "Fichier de sortie",
"OutputFile-Help": "Le chemin du fichier où l'image miniature sera enregistrée. Si ce champ est laissé vide, un fichier .jpg sera créé dans le même emplacement que le fichier d'origine.",
"ResizeMode": "Mode",
"ResizeMode-Help": "Le mode utilisé pour redimensionner l'image.",
"SkipBlackFrames": "Ignorer les images noires",
"SkipBlackFrames-Help": "Si activé, les images noires seront ignorées et une autre image sera utilisée.",
"Time": "Temps",
"Time-Help": "Le moment de la vidéo où capturer la miniature.",
"Width": "Largeur",
"Width-Help": "La largeur de l'image miniature."
},
"Outputs": {
"1": "Miniature créée.",
"2": "Échec de la création de la miniature."
}
},
"DisableAmd": {
"Description": "Désactive l'encodeur matériel AMD AMF",
"Label": "Désactiver AMD",

View File

@@ -51,6 +51,28 @@
"2": "Nessuna pubblicità rilevata"
}
},
"CreateThumbnail": {
"Description": "Crea un'immagine di anteprima da un file video.",
"Label": "Crea Anteprima",
"Fields": {
"Height": "Altezza",
"Height-Help": "L'altezza dell'immagine di anteprima.",
"OutputFile": "File di Uscita",
"OutputFile-Help": "Il percorso del file in cui verrà salvata l'immagine di anteprima. Se lasciato vuoto, verrà creato un file .jpg nella stessa posizione del file originale.",
"ResizeMode": "Modalità",
"ResizeMode-Help": "Il metodo utilizzato per ridimensionare l'immagine.",
"SkipBlackFrames": "Salta Frame Neri",
"SkipBlackFrames-Help": "Se attivato, verranno saltati i frame neri e selezionato un altro frame.",
"Time": "Tempo",
"Time-Help": "Il tempo nel video da cui prendere l'anteprima.",
"Width": "Larghezza",
"Width-Help": "La larghezza dell'immagine di anteprima."
},
"Outputs": {
"1": "Anteprima creata.",
"2": "Impossibile creare l'anteprima."
}
},
"DisableAmd": {
"Description": "Disabilita l'encoder hardware AMD AMF",
"Label": "Disabilita AMD",

View File

@@ -51,6 +51,28 @@
"2": "コマーシャルは検出されませんでした"
}
},
"CreateThumbnail": {
"Description": "動画ファイルからサムネイル画像を作成します。",
"Label": "サムネイル作成",
"Fields": {
"Height": "高さ",
"Height-Help": "サムネイル画像の高さ。",
"OutputFile": "出力ファイル",
"OutputFile-Help": "サムネイル画像を保存するファイルパス。空白の場合、元のファイルと同じ場所に .jpg ファイルが作成されます。",
"ResizeMode": "モード",
"ResizeMode-Help": "画像のサイズを変更する際に使用するモード。",
"SkipBlackFrames": "黒いフレームをスキップ",
"SkipBlackFrames-Help": "チェックされている場合、黒いフレームが検出された場合は他のフレームが使用されます。",
"Time": "時間",
"Time-Help": "サムネイルを作成する動画の時刻。",
"Width": "幅",
"Width-Help": "サムネイル画像の幅。"
},
"Outputs": {
"1": "サムネイルが作成されました。",
"2": "サムネイルの作成に失敗しました。"
}
},
"DisableAmd": {
"Description": "AMD AMFハードウェアエンコーダーを無効にします。",
"Label": "AMDを無効にする",

View File

@@ -51,6 +51,28 @@
"2": "광고가 감지되지 않았습니다."
}
},
"CreateThumbnail": {
"Description": "비디오 파일에서 썸네일 이미지를 생성합니다.",
"Label": "썸네일 생성",
"Fields": {
"Height": "높이",
"Height-Help": "썸네일 이미지의 높이.",
"OutputFile": "출력 파일",
"OutputFile-Help": "썸네일 이미지를 저장할 파일 경로. 비워 두면 원본 파일과 동일한 위치에 .jpg 파일이 생성됩니다.",
"ResizeMode": "모드",
"ResizeMode-Help": "이미지를 크기 조정할 때 사용하는 모드.",
"SkipBlackFrames": "검은 프레임 건너뛰기",
"SkipBlackFrames-Help": "선택하면 검은 프레임이 감지되면 다른 프레임이 사용됩니다.",
"Time": "시간",
"Time-Help": "썸네일을 추출할 비디오의 시간.",
"Width": "너비",
"Width-Help": "썸네일 이미지의 너비."
},
"Outputs": {
"1": "썸네일이 생성되었습니다.",
"2": "썸네일 생성에 실패했습니다."
}
},
"DisableAmd": {
"Description": "AMD AMF 하드웨어 인코더를 비활성화합니다.",
"Label": "AMD 비활성화",

View File

@@ -51,6 +51,28 @@
"2": "Geen reclames gedetecteerd"
}
},
"CreateThumbnail": {
"Description": "Maakt een miniatuurafbeelding van een videobestand.",
"Label": "Miniatuur maken",
"Fields": {
"Height": "Hoogte",
"Height-Help": "De hoogte van de miniatuurafbeelding.",
"OutputFile": "Uitvoerbestand",
"OutputFile-Help": "Het pad waar de miniatuurafbeelding wordt opgeslagen. Als dit veld leeg is, wordt er een .jpg-bestand gemaakt in dezelfde locatie als het originele bestand.",
"ResizeMode": "Modus",
"ResizeMode-Help": "De modus die gebruikt wordt bij het schalen van de afbeelding.",
"SkipBlackFrames": "Zwarte frames overslaan",
"SkipBlackFrames-Help": "Indien aangevinkt, wordt een ander frame gebruikt wanneer een zwart frame wordt gedetecteerd.",
"Time": "Tijd",
"Time-Help": "De tijd in de video waar de miniatuur van wordt gemaakt.",
"Width": "Breedte",
"Width-Help": "De breedte van de miniatuurafbeelding."
},
"Outputs": {
"1": "Miniatuur gemaakt.",
"2": "Mislukt om miniatuur te maken."
}
},
"DisableAmd": {
"Description": "Deactiveert de AMD AMF hardware-encoder",
"Label": "Deactiveer AMD",

View File

@@ -51,6 +51,28 @@
"2": "Nenhum comercial detectado"
}
},
"CreateThumbnail": {
"Description": "Cria uma imagem de miniatura a partir de um arquivo de vídeo.",
"Label": "Criar Miniatura",
"Fields": {
"Height": "Altura",
"Height-Help": "A altura da imagem da miniatura.",
"OutputFile": "Arquivo de Saída",
"OutputFile-Help": "O caminho do arquivo onde a imagem da miniatura será salva. Se deixado em branco, um arquivo .jpg será criado no mesmo local do arquivo original.",
"ResizeMode": "Modo",
"ResizeMode-Help": "O modo usado para redimensionar a imagem.",
"SkipBlackFrames": "Pular Quadros Pretos",
"SkipBlackFrames-Help": "Se marcado, um quadro preto será ignorado e outro quadro será usado.",
"Time": "Tempo",
"Time-Help": "O momento no vídeo de onde a miniatura será capturada.",
"Width": "Largura",
"Width-Help": "A largura da imagem da miniatura."
},
"Outputs": {
"1": "Miniatura criada.",
"2": "Falha ao criar miniatura."
}
},
"DisableAmd": {
"Description": "Desativa o codificador de hardware AMD AMF",
"Label": "Desativar AMD",

View File

@@ -51,6 +51,28 @@
"2": "Реклама не обнаружена"
}
},
"CreateThumbnail": {
"Description": "Создает миниатюру изображения из видеофайла.",
"Label": "Создать миниатюру",
"Fields": {
"Height": "Высота",
"Height-Help": "Высота изображения миниатюры.",
"OutputFile": "Файл вывода",
"OutputFile-Help": "Путь к файлу, в который будет сохранена миниатюра. Если оставить пустым, будет создан файл .jpg в том же месте, что и исходный файл.",
"ResizeMode": "Режим",
"ResizeMode-Help": "Режим, используемый для изменения размера изображения.",
"SkipBlackFrames": "Пропускать чёрные кадры",
"SkipBlackFrames-Help": "Если установлено, при обнаружении чёрного кадра будет использован другой кадр.",
"Time": "Время",
"Time-Help": "Время в видео, с которого будет взята миниатюра.",
"Width": "Ширина",
"Width-Help": "Ширина изображения миниатюры."
},
"Outputs": {
"1": "Миниатюра создана.",
"2": "Не удалось создать миниатюру."
}
},
"DisableAmd": {
"Description": "Отключает аппаратный кодер AMD AMF",
"Label": "Отключить AMD",

View File

@@ -51,6 +51,28 @@
"2": "Ingen reklam upptäckt"
}
},
"CreateThumbnail": {
"Description": "Skapar en miniatyrbild från en videofil.",
"Label": "Skapa Miniatyrbild",
"Fields": {
"Height": "Höjd",
"Height-Help": "Miniatyrbildens höjd.",
"OutputFile": "Utdatafil",
"OutputFile-Help": "Sökvägen där miniatyrbilden ska sparas. Om fältet lämnas tomt skapas en .jpg-fil på samma plats som originalfilen.",
"ResizeMode": "Läge",
"ResizeMode-Help": "Läget som används vid storleksändring av bilden.",
"SkipBlackFrames": "Hoppa över svarta bildrutor",
"SkipBlackFrames-Help": "Om markerad, kommer en annan bildruta att användas om en svart bildruta upptäcks.",
"Time": "Tid",
"Time-Help": "Tiden i videon där miniatyrbilden ska tas från.",
"Width": "Bredd",
"Width-Help": "Miniatyrbildens bredd."
},
"Outputs": {
"1": "Miniatyrbild skapad.",
"2": "Misslyckades med att skapa miniatyrbild."
}
},
"DisableAmd": {
"Description": "Inaktiverar AMD AMF hårdvaruavkodare",
"Label": "Inaktivera AMD",

View File

@@ -51,6 +51,28 @@
"2": "未检测到广告"
}
},
"CreateThumbnail": {
"Description": "从视频文件创建缩略图。",
"Label": "创建缩略图",
"Fields": {
"Height": "高度",
"Height-Help": "缩略图的高度。",
"OutputFile": "输出文件",
"OutputFile-Help": "保存缩略图的文件路径。如果为空,将在与原始文件相同的位置创建一个 .jpg 文件。",
"ResizeMode": "模式",
"ResizeMode-Help": "调整图片大小时使用的模式。",
"SkipBlackFrames": "跳过黑帧",
"SkipBlackFrames-Help": "选中时,如果检测到黑帧,将使用其他帧。",
"Time": "时间",
"Time-Help": "从视频中截取缩略图的时间点。",
"Width": "宽度",
"Width-Help": "缩略图的宽度。"
},
"Outputs": {
"1": "缩略图已创建。",
"2": "创建缩略图失败。"
}
},
"DisableAmd": {
"Description": "禁用 AMD AMF 硬件编码器",
"Label": "禁用 AMD",

View File

@@ -51,6 +51,28 @@
"2": "未檢測到廣告"
}
},
"CreateThumbnail": {
"Description": "從影片檔案創建縮圖。",
"Label": "創建縮圖",
"Fields": {
"Height": "高度",
"Height-Help": "縮圖的高度。",
"OutputFile": "輸出檔案",
"OutputFile-Help": "保存縮圖的檔案路徑。如果留空,將在與原始檔案相同的位置創建一個 .jpg 檔案。",
"ResizeMode": "模式",
"ResizeMode-Help": "調整圖片大小時使用的模式。",
"SkipBlackFrames": "跳過黑幀",
"SkipBlackFrames-Help": "勾選此選項時,如果檢測到黑幀,將使用其他幀。",
"Time": "時間",
"Time-Help": "從影片中擷取縮圖的時間點。",
"Width": "寬度",
"Width-Help": "縮圖的寬度。"
},
"Outputs": {
"1": "縮圖已創建。",
"2": "創建縮圖失敗。"
}
},
"DisableAmd": {
"Description": "禁用 AMD AMF 硬體編碼器",
"Label": "禁用 AMD",