/// <summary> /// Since an async method does not support ref parameter passing we cannot utilize /// `ref FileInfoType` here. Hence we copy it back in the end. /// </summary> /// <param name="ShouldSimulate"></param> /// <returns></returns> internal async Task <FileInfoType> Run(bool ShouldSimulate = true) { var filePath = mFileInfo.Path; // var mediaInfo = FileInfo.Parent + @"\ffmpeg_media_info.log"; Console.WriteLine("Processing Media " + filePath + ":"); string ffprobeStr = await GetMediaInfo(filePath); // TODO: make this debug statements more compact // Console.WriteLine("json string:" + ffprobeStr); var codecId = ParseMediaInfo(ffprobeStr); var codes = codecId.Split(' '); if (codes.Length == 0) { throw new ArgumentException("codecs are not set!"); } var sCodecId = codes[0]; var aCodecId = codes[1]; Console.WriteLine("a code: " + aCodecId + ", s code: " + (string.IsNullOrEmpty(sCodecId)? "Empty": sCodecId)); if (ShouldSimulate) { return(mFileInfo); } if (!string.IsNullOrEmpty(sCodecId)) { await ExtractSubtitle(filePath, sCodecId); } if (ShouldChangeContainer && !mFileInfo.IsInError) { // ToDo: check for space ahead? to avoid reanme in case of not free space // ConvertMedia has a high elapsed time, take advantage of async: do tasks before await // inside bool isSuccess = await ConvertMedia(filePath, aCodecId); if (isSuccess) { mFileInfo.Update("convert"); // remove the input mkv file FileOperationAPIWrapper.Send(filePath); // update file path mFileInfo.Path = mFileInfo.Parent + "\\" + System.IO.Path.GetFileNameWithoutExtension(filePath) + ".mp4"; if (!ShouldSimulate && !mFileInfo.IsInError) { // show how output media looks like Console.WriteLine(); ffprobeStr = await GetMediaInfo(mFileInfo.Path); sCodecId = ParseMediaInfo(ffprobeStr); // sCodecId can be null if there's no sub // System.Diagnostics.Debug.Assert(string.IsNullOrEmpty(sCodecId)); } } } return(mFileInfo); }
/// <summary> /// Extract Rar Archives and clean up /// /// https://docs.microsoft.com/en-us/dotnet/api/system.io.directory.getfiles /// /// References /// base URL https://github.com/adamhathcock/sharpcompress/blob/master /// USAGE.md /// src/SharpCompress/Common/ExtractionOptions.cs /// Deletion of compressed file after extracting it with nunrar /// https://stackoverflow.com/q/17467951 /// </summary> /// <param name="filePath">the file path variable</param> /// <returns></returns> public bool ExtractRar(string filePath) { if (!IsSupportedArchive(filePath)) { return(false); } mFileInfo.Update("extract"); using (var archive = SharpCompress.Archives.Rar.RarArchive.Open(filePath)) { // archive not null when next archive is not found try { // ToDO: show warning for multiple files foreach (var entry in archive.Entries) { // simulation does not continue because file is not extracted // extracting file during simulation: is it a good idea? mFileInfo.Path = mFileInfo.Parent + "\\" + entry.Key; HasEnoughFreeSpace(entry.Size, 2); if (!ShouldSimulate && !mFileInfo.IsInError) { entry.WriteToDirectory(mFileInfo.Parent, new SharpCompress.Common.ExtractionOptions() { ExtractFullPath = true, Overwrite = true } ); } break; // only get first item, for psa that's what we expect that much } } catch (System.ArgumentException e) { Console.WriteLine("Probably could not find next archive! Msg:\r\n" + e.Message); mFileInfo.Update("Fail: SharpCompress Rar Open error"); return(false); } } // remove processed Rar Archive/s var tail = "part1.rar"; if (filePath.EndsWith(tail, StringComparison.CurrentCultureIgnoreCase)) { // Only get files that begin with the letter "c". string sPath = GetSimplifiedPath(filePath); var pattern = sPath.Substring(0, sPath.Length - tail.Length) + "part*.rar"; // Console.WriteLine("Rar find pattern: " + pattern); debug string[] rarFiles = Directory.GetFiles(mFileInfo.Parent, pattern); if (!mFileInfo.IsInError) { foreach (string rarFile in rarFiles) { if (!ShouldSimulate) { FileOperationAPIWrapper.Send(rarFile); } } } } else if (!ShouldSimulate && !mFileInfo.IsInError) { Console.WriteLine("Removing file: " + filePath); FileOperationAPIWrapper.Send(filePath); } return(true); }
private async Task ExtractSubtitle(string filePath, string sCodecId) { // mkv, mp4, mpeg-2 m2ts, mov, qt can contain subtitles as attachments // ref, https://en.wikipedia.org/wiki/Comparison_of_video_container_formats // for now, for psa and rmz we only accept mkv if (System.IO.Path.GetExtension(filePath).ToLower() != ".mkv") { return; } // https://docs.microsoft.com/en-us/dotnet/api/system.io.path.getfilenamewithoutextension var subRipExt = ".srt"; var srtFilePath = mFileInfo.Parent + "\\" + System.IO.Path.GetFileNameWithoutExtension(filePath) + subRipExt; if (System.IO.File.Exists(srtFilePath)) { Console.WriteLine("Subrip file already exists, renaming"); var oldSrtFilePath = srtFilePath.Substring(0, srtFilePath.Length - subRipExt.Length) + "_old.srt"; if (System.IO.File.Exists(oldSrtFilePath)) { FileOperationAPIWrapper.Send(oldSrtFilePath); } System.IO.File.Move(srtFilePath, oldSrtFilePath); } TaskCompletionSource <bool> ffmpegEventHandled = new TaskCompletionSource <bool>(); using (System.Diagnostics.Process ffmpegProcess = new System.Diagnostics.Process { StartInfo = { FileName = FFMpegPath + @"\bin\ffmpeg.exe", // -y overwrite output file if exists Arguments = " -loglevel warning -i \"" + filePath + "\"" + " -codec:s srt -map " + sCodecId + " \"" + srtFilePath + "\"", UseShellExecute = false }, EnableRaisingEvents = true } ) { try { // Start a process and raise an event when done. ffmpegProcess.Exited += (sender, args) => { if (ffmpegProcess.ExitCode != 0) { Console.WriteLine("Exit code: " + ffmpegProcess.ExitCode + ", an overwrite is not " + "confirmed or ffmpeg is invoked incorrectly! Please check input stream. codec id: " + sCodecId); } Console.Write("Subtitle extraction time: " + Math.Round((ffmpegProcess.ExitTime - ffmpegProcess. StartTime).TotalMilliseconds) + " ms (), "); ffmpegEventHandled.TrySetResult(true); ffmpegProcess.Dispose(); }; ffmpegProcess.Start(); // better to utilize onExit than `WaitForExit` } catch (Exception ex) { Console.WriteLine($"An error occurred trying to run ffmpeg scodec copy \"{FFMpegPath}\""); Console.WriteLine(ex.Message); return; } // Run Concurrent // Cleanup garbage sub // Change sponsor text in psarip subs // Wait for ffmpeg process Exited event, but not more than 120 seconds await Task.WhenAny(ffmpegEventHandled.Task, Task.Delay(120000)); } // after extracting if it results a garbage subtitle (with sCount > 1) set shouldChangeContainer to false long srtSize = (new System.IO.FileInfo(srtFilePath)).Length; Console.WriteLine("Srt size: {0:F2} KB", srtSize * 1.0 / 1024); // Expecting at least 5 KB; if found less notify, but don't affect cont. change if (srtSize < (5 * 1024)) { Console.WriteLine("Subtitle file size is small (< 5 KB)!"); // ShouldChangeContainer = false; } }