Ejemplo n.º 1
0
        /// <summary>
        /// Renames media file
        /// <remarks> ExtractRar might have modified file name. Hence, don't pass `filePath` as param,
        /// it should be retrieved from FileInfo </remarks>
        /// ToDo: don't rename if input is mkv or rar
        ///  introduce mFileInfo.OutPath instead
        /// </summary>
        private void RenameFile()
        {
            string filePath = mFileInfo.Path;

            // don't rename archives
            if (IsSupportedArchive(filePath, false))
            {
                return;
            }

            var year    = GetYear();
            var title   = GetTitle();
            var ripInfo = GetRipperInfo();

            // Console.WriteLine("year: " + year);
            // Console.WriteLine("title: " + title);
            // Console.WriteLine("ripInfo: " + ripInfo);

            var outFileName = mFileInfo.Parent + '\\' + title + ' ' + year + ripInfo;
            // Support TV Shows, look for E\d\d pattern
            string pattern = @"^E\d{2}";

            if (string.IsNullOrEmpty(year) && System.Text.RegularExpressions.Regex.IsMatch(title, pattern,
                                                                                           System.Text.RegularExpressions.RegexOptions.IgnoreCase))
            {
                // temporary patch: to uppercase title for TV Shows
                var ext = ripInfo.Substring(ripInfo.Length - 4);
                outFileName = mFileInfo.Parent + '\\' + title + ripInfo.Substring(0, ripInfo.Length - 4).Replace('.', ' ') + ext;
            }

            // Console.WriteLine("output File Name: " + outFileName);

            if (mFileInfo.Path != outFileName)
            {
                // May be we need modification flag for each stage i.e., rename, media conversion and so on..
                mFileInfo.Update("rename");
                Console.WriteLine("   " + GetSimplifiedPath(mFileInfo.Path) + ": " + mFileInfo.ModInfo);
                Console.WriteLine("-> " + GetSimplifiedPath(outFileName));
            }

            if (!ShouldSimulate && mFileInfo.IsModified && !mFileInfo.IsInError)
            {
                // check if file already exists before rename, send to recycle bin if exists :)
                if (File.Exists(outFileName))
                {
                    FileOperationAPIWrapper.Send(outFileName);
                }
                File.Move(mFileInfo.Path, outFileName);
                // Update file name so that next stage can pick it up
                mFileInfo.Path = outFileName;
            }
        }
Ejemplo n.º 2
0
        private async Task UpdateLocalFFMpeg(string localVersion, string latestVersion)
        {
            Console.WriteLine("Updating..");
            var dirToDelete = ffmpegLocation + "." + localVersion;

            if (Directory.Exists(dirToDelete))
            {
                FileOperationAPIWrapper.Send(dirToDelete);
            }
            Console.WriteLine("Waiting for ffmpeg dir lock to be freed..");
            // 3s did not work on 02-15 for some reason, increased to 10s
            await Task.Delay(10000);

            Directory.Move(ffmpegLocation, dirToDelete);
            // example URL:
            var ffmpegURL = "https://ffmpeg.zeranoe.com/builds/win64/shared/ffmpeg-" + latestVersion + "-win64-shared.zip";
            // download and extract latest ffmpeg
            HttpClient client = new HttpClient();
            // check later when getting exception about forcibly closed connetion on transport
            // System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls11 |
            //  System.Net.SecurityProtocolType.Tls12;

            string newffmpegDirName   = ffmpegLocation + "-" + latestVersion + "-win64-shared";
            string zipFileNameWithExt = newffmpegDirName + ".zip";

            Console.WriteLine("Downloading " + ffmpegURL);
            Console.WriteLine("Temporarily saving to " + zipFileNameWithExt);
            // Send asynchronous request
            try {
                await client.GetAsync(ffmpegURL).ContinueWith(
                    (requestTask) => {
                    // Get HTTP response from completed task.
                    HttpResponseMessage response = requestTask.Result;
                    // Check that response was successful or throw exception
                    response.EnsureSuccessStatusCode();
                    // Read response asynchronously and save to file
                    response.Content.ReadAsFileAsync(zipFileNameWithExt, true);
                });
            } catch (Exception e) {
                Console.WriteLine("Exception: " + e.Message);
                return;
            }
            // wait for file stream to release the file
            await Task.Delay(1000);

            System.IO.Compression.ZipFile.ExtractToDirectory(zipFileNameWithExt, ffmpegLocation + @"\..\");
            Directory.Move(newffmpegDirName, ffmpegLocation);
            FileOperationAPIWrapper.Send(dirToDelete);
            FileOperationAPIWrapper.Send(zipFileNameWithExt);
        }
Ejemplo n.º 3
0
        /// <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);
        }
Ejemplo n.º 4
0
        /// <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);
        }
Ejemplo n.º 5
0
        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;
            }
        }