Пример #1
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            var proxies = new List <string>();

            Configuration.GetSection("TPBProxies").Bind(proxies);
            var sofakingConfiguration = new SoFakingConfiguration();

            Configuration.GetSection("Sofaking").Bind(sofakingConfiguration);
            if (proxies.Count == 0)
            {
                throw new Exception("TPB Proxies configuration missing");
            }
            TPBProxies.SetProxies(proxies.ToArray());
            var transmissionConfiguration = new TransmissionConfiguration();

            Configuration.GetSection("Transmission").Bind(transmissionConfiguration);

            services.AddHttpClient();
            services.AddControllers().AddJsonOptions(opt =>
            {
                opt.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
                opt.JsonSerializerOptions.PropertyNamingPolicy        = null;
            });
            services.AddSingleton(transmissionConfiguration);
            services.AddSingleton <TransmissionHttpClientFactory>();
            services.AddSingleton(new SoFakingContextFactory());
            services.AddSingleton <MovieService>();
            services.AddSingleton <TPBParserService>();
            services.AddSingleton <ITorrentClientService, TransmissionService>();
            services.AddSingleton <IVerifiedMovieSearchService, ImdbService>();
        }
Пример #2
0
        public FFMPEGEncoderService(ILogger <FFMPEGEncoderService> logger, EncoderConfiguration configuration, SoFakingConfiguration sofakingConfiguration)
        {
            _logger                = logger;
            _configuration         = configuration;
            _sofakingConfiguration = sofakingConfiguration;

            SetCancellationToken();
        }
Пример #3
0
        public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
        .UseSystemd()                         // Linux service lifetime management
        .ConfigureAppConfiguration((context, builder) =>
        {
            builder
            .SetBasePath(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location))                                     // Required for Linux service
            .AddJsonFile("appsettings.json")
            .AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json")
            .AddJsonFile("dbsettings.json")
            .AddJsonFile($"dbsettings.{context.HostingEnvironment.EnvironmentName}.json")
            .AddEnvironmentVariables()
            .Build();
        })
        .ConfigureServices((hostContext, services) =>
        {
            var proxies = new List <string>();
            hostContext.Configuration.GetSection("TPBProxies").Bind(proxies);
            if (proxies.Count == 0)
            {
                throw new Exception("TPB Proxies configuration missing");
            }
            TPBProxies.SetProxies(proxies.ToArray());

            var downloadFinishedWorkerConfiguration = new DownloadFinishedWorkerConfiguration();
            hostContext.Configuration.GetSection("DownloadFinishedWorker").Bind(downloadFinishedWorkerConfiguration);
            var transmissionConfiguration = new TransmissionConfiguration();
            hostContext.Configuration.GetSection("Transmission").Bind(transmissionConfiguration);
            var encoderConfiguration = new EncoderConfiguration();
            hostContext.Configuration.GetSection("Encoder").Bind(encoderConfiguration);
            var sofakingConfiguration = new SoFakingConfiguration();
            hostContext.Configuration.GetSection("Sofaking").Bind(sofakingConfiguration);

            services
            .AddHttpClient()
            .AddSingleton(transmissionConfiguration)
            .AddSingleton(sofakingConfiguration)
            .AddSingleton <TransmissionHttpClientFactory>()
            .AddSingleton(downloadFinishedWorkerConfiguration)
            .AddSingleton(encoderConfiguration)
            .AddSingleton(new SoFakingContextFactory())
            .AddSingleton <MovieService>()
            .AddSingleton <TPBParserService>()
            .AddSingleton <ITorrentClientService, TransmissionService>()
            .AddSingleton <IVerifiedMovieSearchService, ImdbService>()
            //.AddSingleton<IEncoderService, FFMPEGEncoderService>()
            .AddHostedService <SoFakingWorker>();
        });
Пример #4
0
 public SoFakingWorker(ILogger <SoFakingWorker> logger, ILogger <FFMPEGEncoderService> loggerEnc, IHttpClientFactory clientFactory, DownloadFinishedWorkerConfiguration configuration, MovieService movieService, ITorrentClientService torrentClient, /* IEncoderService encoderService,*/ SoFakingConfiguration sofakingConfiguration, EncoderConfiguration encoderConfiguration)
 {
     if (clientFactory == null)
     {
         throw new ArgumentNullException(nameof(clientFactory));
     }
     if (movieService == null)
     {
         throw new ArgumentNullException(nameof(movieService));
     }
     if (configuration == null)
     {
         throw new ArgumentNullException(nameof(configuration));
     }
     if (logger == null)
     {
         throw new ArgumentNullException(nameof(logger));
     }
     if (loggerEnc == null)
     {
         throw new ArgumentNullException(nameof(loggerEnc));
     }
     if (torrentClient == null)
     {
         throw new ArgumentNullException(nameof(torrentClient));
     }
     if (encoderConfiguration == null)
     {
         throw new ArgumentNullException(nameof(encoderConfiguration));
     }
     if (sofakingConfiguration == null)
     {
         throw new ArgumentNullException(nameof(sofakingConfiguration));
     }
     _sofakingConfiguration = sofakingConfiguration;
     _clientFactory         = clientFactory;
     _movieService          = movieService;
     _configuration         = configuration;
     _logger               = logger;
     _loggerEnc            = loggerEnc;
     _torrentClient        = torrentClient;
     _encoderConfiguration = encoderConfiguration;
 }
Пример #5
0
        //private static ServiceProvider _serviceProvider;
        static async Task Main(string[] args)
        {
            IVerifiedMovie selectedMovie = null;
            var            builder       = new ConfigurationBuilder()
                                           .SetBasePath(Directory.GetCurrentDirectory())
                                           .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                                           .AddJsonFile("appsettings.Development.json", optional: true, reloadOnChange: true) // TODO: Change the Production with Enviroment
                                           .AddEnvironmentVariables();

            IConfigurationRoot configuration = builder.Build();
            var proxies = new List <string>();

            configuration.GetSection("TPBProxies").Bind(proxies);
            var sofakingConfiguration = new SoFakingConfiguration();

            configuration.GetSection("Sofaking").Bind(sofakingConfiguration);
            if (proxies.Count == 0)
            {
                throw new Exception("TPB Proxies configuration missing");
            }
            TPBProxies.SetProxies(proxies.ToArray());


            var transmissionConfiguration = new TransmissionConfiguration();

            configuration.GetSection("Transmission").Bind(transmissionConfiguration);

            //TransmissionHttpClient.Configure(transmissionConfiguration)

            var builder1 = new HostBuilder()
                           .ConfigureServices((hostContext, services) =>
            {
                services
                .AddHttpClient()
                .AddSingleton(transmissionConfiguration)
                .AddSingleton <TransmissionHttpClientFactory>()
                .AddSingleton(new SoFakingContextFactory())
                .AddSingleton <MovieService>()
                .AddSingleton <TPBParserService>()
                .AddSingleton <ITorrentClientService, TransmissionService>()
                .AddSingleton <IVerifiedMovieSearchService, ImdbService>();
            }).UseConsoleLifetime();

            var host = builder1.Build();

            using (var serviceScope = host.Services.CreateScope())
            {
                var serviceProvider = serviceScope.ServiceProvider;

                while (true)
                {
                    var movieService = serviceProvider.GetService <MovieService>();
                    Console.Clear();
                    Console.ResetColor();
                    Console.WriteLine("Enter a movie name in English to look for: (CTRL+C to quit)");
                    var query = Console.ReadLine();
                    var verifiedMovieSearch = serviceProvider.GetService <IVerifiedMovieSearchService>();
                    var verifiedMovies      = await verifiedMovieSearch.Search(query);

                    var movieJobs = await movieService.GetMoviesAsync();

                    if (verifiedMovies == null || verifiedMovies.Count == 0)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine("No results found.");
                        Console.ResetColor();
                        Console.ReadKey();
                        continue;
                    }

                    if (verifiedMovies.Count == 1)
                    {
                        selectedMovie = verifiedMovies.ElementAt(0);
                    }

                    if (verifiedMovies.Count > 1)
                    {
                        Console.WriteLine("There are several matches:");

                        for (var i = 0; i < verifiedMovies.Count(); i++)
                        {
                            var vm       = verifiedMovies.ElementAt(i);
                            var status   = string.Empty;
                            var movieJob = movieJobs.Where(x => x.ImdbId == vm.Id).FirstOrDefault();
                            if (movieJob != null)
                            {
                                status = SetMovieConsoleStatus(movieJob);
                            }

                            Console.WriteLine($"[{(i+1)}]\t{vm.Score}/10\t{vm.ScoreMetacritic} Metacritic\t{status}\t{vm.Title.Utf8ToAscii()} ({vm.ReleaseYear})");

                            if (movieJob != null)
                            {
                                Console.ResetColor();
                            }
                        }

                        Console.WriteLine($"[1-{verifiedMovies.Count()}] Search torrents for download, Any key = New search, CTRL+C = quit");

                        if (int.TryParse(Console.ReadLine(), out int selectedMovieIndex))
                        {
                            selectedMovie = verifiedMovies.ElementAt(selectedMovieIndex - 1);
                        }
                        else
                        {
                            continue;
                        }
                    }

                    var torrentSearchService = serviceProvider.GetService <TPBParserService>();
                    var torrentQuery         = $"{selectedMovie.Title} {selectedMovie.ReleaseYear}";

                    // TODO: get rid of this
                    goto defaulttorrentsearch;

                    #region Confirm torrent search query
confirmtorrentsearchquery:
                    {
                        Console.Clear();
                        Console.WriteLine($"Torrent search query: {torrentQuery}. Overwrite? (empty to keep)");
                        var tqInput = Console.ReadLine();
                        if (tqInput.Trim() != string.Empty)
                        {
                            torrentQuery = tqInput;
                        }
                        Console.Clear();
                    }
                    #endregion

defaulttorrentsearch:
                    {
                        // Just skip ahead...
                    }

                    var foundTorrents = await torrentSearchService.Search(torrentQuery);

                    if (foundTorrents.Count == 0)
                    {
                        Console.Write("\r\n");
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine("No torrents found.");
                        Console.ResetColor();

                        Console.WriteLine("\n");
                        Console.WriteLine($"Add to watchlist? [w], Cancel [n], CTRL+C = quit)");

                        if (Console.ReadLine() == "w")
                        {
                            try
                            {
                                var m = MergeMovie(selectedMovie);
                                m.TorrentName = query;
                                m.Status      = MovieStatusEnum.WatchingFor;

                                await movieService.AddMovie(m);

                                continue;
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine($"Could not add Movie to the watchlist: {ex.Message}");
                                Console.ReadKey();
                            }
                        }
                    }

                    Console.Clear();
                    for (var i = 0; i < foundTorrents.Count(); i++)
                    {
                        var t        = foundTorrents.ElementAt(i);
                        var status   = string.Empty;
                        var movieJob = movieJobs.Where(x => x.TorrentName == t.Name).FirstOrDefault();
                        if (movieJob != null)
                        {
                            status = SetMovieConsoleStatus(movieJob);
                        }

                        Console.WriteLine($"[{(i+1)}]\t{t.Seeders}\t{t.SizeGb}Gb\t{status}\t{t.Name}");

                        if (movieJob != null)
                        {
                            Console.ResetColor();
                        }
                    }

                    Console.WriteLine("\n");
                    var bestTorrent = TorrentRating.GetBestTorrent(foundTorrents, sofakingConfiguration.AudioLanguages);
                    if (bestTorrent == null)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine($"None of the torrents above passed the limits (Seeders > 0, Size Gb > {TorrentScoring.FileSizeGbMin} < {TorrentScoring.FileSizeGbMax}), or contained a banned word: {string.Join(", ", TorrentScoring.Tags.Where(x => x.Value == TorrentScoring.BannedTag).Select(x => x.Key))}");
                        Console.ResetColor();
                        Console.WriteLine("\n");
                        Console.WriteLine($"Cancel? [n], Watchlist [w], [1-{(foundTorrents.Count() + 1)}] for manual selection, [c] for changing the search query, CTRL+C = quit)");
                    }
                    else
                    {
                        Console.ForegroundColor = ConsoleColor.Green;
                        Console.WriteLine($"Best torrent: ({bestTorrent.Seeders} Seeders), {bestTorrent.SizeGb}Gb {bestTorrent.Name}");
                        Console.ResetColor();
                        Console.WriteLine("\n");
                        Console.WriteLine($"Download the best torrent? [y/n], [1-{(foundTorrents.Count() + 1)}] for manual selection, [c] for changing the search query, CTRL+C = quit)");
                    }

                    var    selectedTorrent = bestTorrent;
                    string input           = Console.ReadLine();

                    if (input == "n")
                    {
                        continue;
                    }

                    if (input == "c")
                    {
                        goto confirmtorrentsearchquery;
                    }

                    if (input == "w")
                    {
                        try
                        {
                            var m = MergeMovie(selectedMovie);
                            m.TorrentName = query;
                            m.Status      = MovieStatusEnum.WatchingFor;

                            await movieService.AddMovie(m);

                            Console.ForegroundColor = ConsoleColor.Green;
                            Console.WriteLine("Movie added to Watchlist.");
                            Console.ResetColor();
                            Thread.Sleep(3 * 1000);
                            continue;
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"Could not add Movie to the watchlist: {ex.Message}");
                            Console.ReadKey();
                        }

                        continue;
                    }

                    if (int.TryParse(input, out int selectedTorrentIndex))
                    {
                        selectedTorrent = foundTorrents.ElementAt(selectedTorrentIndex - 1);
                    }

                    if (selectedTorrent == null)
                    {
                        Console.WriteLine($"Selected torrent was null.");
                        Console.ReadKey();
                        continue;
                    }

                    var transmission = serviceProvider.GetService <ITorrentClientService>();
                    try
                    {
                        var result = await transmission.AddTorrentAsync(selectedTorrent.MagnetLink);

                        if (result == null)
                        {
                            throw new Exception("Could not add torrent to the torrent client.");
                        }
                        try
                        {
                            var m = MergeMovie(selectedMovie, selectedTorrent, result);

                            if (!await movieService.AddMovie(m))
                            {
                                throw new Exception("db failed");
                            }

                            Console.ForegroundColor = ConsoleColor.Green;
                            Console.WriteLine("Movie added for download.");
                            Console.ResetColor();
                            Thread.Sleep(3 * 1000);
                            continue;
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"Could not add Movie to the catalog: {ex.Message}");
                            Console.ReadKey();
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"Could not add torrent to download: {ex.Message}");
                        Console.ReadKey();
                    }
                }
            }


            //_serviceProvider = new ServiceCollection()
            //    .AddLogging()
            //    .AddHttpClient()
            //    .AddSingleton(transmissionConfiguration)
            //    .AddSingleton(new SoFakingContextFactory())
            //    .AddSingleton<MovieService>()
            //    .AddSingleton<TPBParserService>()
            //    .AddSingleton<ITorrentClientService, TransmissionService>()
            //    .AddSingleton<IVerifiedMovieSearchService, ImdbService>()
            //    .BuildServiceProvider();
        }
Пример #6
0
        private static VideoCompatibilityFlags HasAcceptableVideo(DConf dc, SoFakingConfiguration sc, IMediaInfo mediaInfo)
        {
            if (dc.AcceptedVideoCodecs == null)
            {
                throw new ArgumentNullException(nameof(dc.AcceptedVideoCodecs));
            }
            if (mediaInfo == null)
            {
                throw new ArgumentNullException(nameof(mediaInfo));
            }
            if (mediaInfo.VideoCodec == null)
            {
                throw new ArgumentNullException(nameof(mediaInfo.VideoCodec));
            }
            if (mediaInfo.FileInfo == null)
            {
                throw new ArgumentNullException(nameof(mediaInfo.FileInfo));
            }
            if (mediaInfo.HorizontalVideoResolution == -1)
            {
                throw new ArgumentException($"Horizontal resolution invalid: {nameof(mediaInfo.HorizontalVideoResolution)}");
            }

            var acceptableCodec = false;

            foreach (var vc in dc.AcceptedVideoCodecs)
            {
                if (mediaInfo.VideoCodec.IndexOf(vc) >= 0)
                {
                    acceptableCodec = true;
                    break;
                }
            }

            var acceptableResolution = mediaInfo.HorizontalVideoResolution <= sc.MaxHorizontalVideoResolution;
            var acceptableSize       = mediaInfo.FileInfo.Length > (sc.MaxSizeGb * 1024 * 1024);
            // TODO: Fixing getting the video bitrate right would speed up the program significantly.
            // Unfortunately, FFMPEG can't return bitrate of only the video stream. So we will ONLY stream copy if video and all the audio streams combined have a lower bitrate than level 4.2 h264 video bitrate compatible with PS4 (6,25Mbit/s)
            var acceptableBitrate = (mediaInfo.AVBitrateKbs == null || mediaInfo.AVBitrateKbs <= TargetVideoBitrateKbs);

            var flags = VideoCompatibilityFlags.Compatible;

            if (!acceptableCodec)
            {
                flags |= VideoCompatibilityFlags.IncompatibleCodec;
            }
            if (!acceptableResolution)
            {
                flags |= VideoCompatibilityFlags.IncompatibleResolution;
            }
            if (!acceptableSize)
            {
                flags |= VideoCompatibilityFlags.IncompatibleSize;
            }
            if (!acceptableBitrate)
            {
                flags |= VideoCompatibilityFlags.IncompatibleBitrate;
            }

            return(flags);
        }
Пример #7
0
        static async Task Main(string[] args)
        {
            if (args.Length == 0)
            {
                throw new Exception("No file to convert provided");
            }

            Console.WriteLine("Encoding: " + args[0]);

            var builder = new ConfigurationBuilder()
                          .SetBasePath(Directory.GetCurrentDirectory())
                          .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                          .AddJsonFile("appsettings.Development.json", optional: true, reloadOnChange: true) // TODO: Change the Production with Enviroment
                          .AddEnvironmentVariables();

            IConfigurationRoot configuration = builder.Build();
            var encoderConfiguration         = new EncoderConfiguration();

            configuration.GetSection("Encoder").Bind(encoderConfiguration);
            var sofakingConfiguration = new SoFakingConfiguration();

            configuration.GetSection("Sofaking").Bind(sofakingConfiguration);
            var dc = new DConf();

            configuration.GetSection("DownloadFinishedWorker").Bind(dc);

            var builder1 = new HostBuilder()
                           .ConfigureServices((hostContext, services) =>
            {
                services
                .AddSingleton(sofakingConfiguration)
                .AddSingleton(encoderConfiguration)
                .AddSingleton(new SoFakingContextFactory());
            }).UseConsoleLifetime();

            var host = builder1.Build();

            using (var serviceScope = host.Services.CreateScope())
            {
                var        done            = false;
                var        serviceProvider = serviceScope.ServiceProvider;
                var        logger          = new NullLogger <FFMPEGEncoderService>();
                var        flags           = EncodingTargetFlags.None;
                var        videoFile       = args[0];
                IMediaInfo mediaInfo       = null;
                var        useCuda         = true;

                Console.Clear();
                Console.WriteLine($"Is this a film (vs. cartoon)? [y/n]");
                if (Console.ReadKey().KeyChar == 'n')
                {
                    flags |= EncodingTargetFlags.VideoIsAnimation;
                }

                var encoderTranscodingInstance = new FFMPEGEncoderService(logger, encoderConfiguration, sofakingConfiguration);

                try
                {
                    mediaInfo = await encoderTranscodingInstance.GetMediaInfo(videoFile);
                }
                catch (Exception ex)
                {
                    Console.Clear();
                    Console.WriteLine("Can not read media info: " + ex.Message);
                    Console.ReadKey();
                    return;
                }

                // Find subtitles
                var filenameBase = Path.GetFileNameWithoutExtension(videoFile);
                var path         = Path.GetDirectoryName(videoFile);
                var subtitles    = new Dictionary <string, string>();

                foreach (var sl in sofakingConfiguration.SubtitleLanguages)
                {
                    var subPath = Path.Combine(path, filenameBase + $".{sl}.srt");
                    if (File.Exists(subPath))
                    {
                        subtitles.Add(sl, subPath);
                    }
                }

                if (subtitles.Count > 0)
                {
                    Console.Clear();
                    Console.WriteLine($"Found {subtitles.Count} subtitles to embed.");
                    Thread.Sleep(3 * 1000);

                    flags |= EncodingTargetFlags.ExternalSubtitles;
                }


                try
                {
                    var videoAudit = HasAcceptableVideo(dc, sofakingConfiguration, mediaInfo);

                    if (videoAudit != VideoCompatibilityFlags.Compatible)
                    {
                        Console.Clear();
                        Console.WriteLine("Video details:");
                        if (videoAudit.HasFlag(VideoCompatibilityFlags.IncompatibleCodec))
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                        }
                        Console.WriteLine($"   Codec: {mediaInfo.VideoCodec}, (Accepted: {string.Join(", ", dc.AcceptedVideoCodecs)})");
                        Console.ResetColor();
                        if (videoAudit.HasFlag(VideoCompatibilityFlags.IncompatibleResolution))
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                        }
                        Console.WriteLine($"   H. Resolution: {mediaInfo.HorizontalVideoResolution}px, (Max: {sofakingConfiguration.MaxHorizontalVideoResolution}px)");
                        Console.ResetColor();
                        if (videoAudit.HasFlag(VideoCompatibilityFlags.IncompatibleBitrate))
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                        }
                        Console.WriteLine($"   Avg bitrate: {(mediaInfo.AVBitrateKbs.HasValue ? ByteSize.FromKiloBytes(mediaInfo.AVBitrateKbs.Value).ToString() : "?")}/s, (Max: {ByteSize.FromKiloBytes(TargetVideoBitrateKbs)}/s");
                        Console.ResetColor();
                        if (videoAudit.HasFlag(VideoCompatibilityFlags.IncompatibleSize))
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                        }
                        Console.WriteLine($"   Size: {ByteSize.FromBytes(mediaInfo.FileInfo.Length)} (Max: {ByteSize.FromGigaBytes(sofakingConfiguration.MaxSizeGb)})");
                        Console.ResetColor();
                        Console.WriteLine();

                        Console.WriteLine($"Video needs converting. Continue? [y/n]");
                        if (Console.ReadKey().KeyChar == 'n')
                        {
                            return;
                        }

                        if (encoderConfiguration.CanUseCuda)
                        {
                            Console.Clear();
                            Console.WriteLine($"Use CUDA? [y/n]");
                            if (Console.ReadKey().KeyChar == 'n')
                            {
                                useCuda = false;;
                            }
                        }

                        flags |= EncodingTargetFlags.NeedsNewVideo;
                    }
                }
                catch (ArgumentException ex)
                {
                    Console.Clear();
                    Console.WriteLine("Incompatible video: " + ex.Message);
                    Console.ReadKey();
                    return;
                }

                try
                {
                    if (!HasAcceptableAudio(dc, mediaInfo))
                    {
                        Console.Clear();
                        Console.WriteLine($"Audio ({mediaInfo.AudioCodec}, (Accepted: {string.Join(", ", dc.AcceptedAudioCodecs)})) needs converting. Continue? [y/n]");
                        if (Console.ReadKey().KeyChar == 'n')
                        {
                            return;
                        }

                        flags |= EncodingTargetFlags.NeedsNewAudio;
                    }
                }
                catch (ArgumentException ex)
                {
                    Console.Clear();
                    Console.WriteLine("Incompatible audio: " + ex.Message);
                    Console.ReadKey();
                    return;
                }

                if (flags == EncodingTargetFlags.None)
                {
                    Console.Clear();
                    Console.WriteLine($"Video file {videoFile} doesn't need transcoding, adding to files to move.");
                    Console.ReadKey();
                    return;
                }

                Console.Clear();
                Console.WriteLine("Converting...");

                encoderTranscodingInstance.OnSuccess += (object sender, EncodingSuccessEventArgs e) => {
                    done = true;
                };

                encoderTranscodingInstance.OnProgress += (object sender, EncodingProgressEventArgs e) => {
                    Console.Clear();
                    Console.WriteLine($"Transcoding progress: {e.ProgressPercent:0.##}%");
                };

                // non-blocking, only starts the external engine
                await encoderTranscodingInstance.StartTranscodingAsync(new TranscodingJob
                {
                    SourceFile = videoFile,
                    Action     = flags,
                    Duration   = mediaInfo.Duration,
                    Subtitles  = subtitles,
                    UseCuda    = useCuda
                });

                while (!done)
                {
                    // wait until encoding finished
                }

                Console.Clear();
                Console.WriteLine("Done!");
                Thread.Sleep(3 * 1000);
            }
        }