Пример #1
0
        public bool Run(ConversionJobOptions conversionOptions, VideoInfo videoFile, Scanner commercialScan, string srtFile)
        {
            bool converted = false;
            Ini ini = new Ini(GlobalDefs.ProfileFile);

            // Dump the entire profile for debugging purposes (incase users have customized it)
            _jobLog.WriteEntry("Profile being used : " + conversionOptions.profile + ".\r\nProfile entries ->", Log.LogEntryType.Debug);
            SortedList<string, string> profileEntries = ini.GetSectionKeyValuePairs(conversionOptions.profile);
            foreach (string key in profileEntries.Keys)
            {
                _jobLog.WriteEntry(key + "=" + profileEntries[key], Log.LogEntryType.Debug);
            }

            string[] order = GetProfileEncoderOrder(conversionOptions.profile);

            foreach (string encoder in order)
            {
                switch (encoder.Trim())
                {
                    case "copy":
                        {
                            _jobLog.WriteEntry(this, Localise.GetPhrase("Using special case COPY for converter"), Log.LogEntryType.Information);

                            // Special case, no real encoder, just ignore any recoding and assume the output = input file
                            ConvertWithCopy convertWithCopy = new ConvertWithCopy(conversionOptions, "copy", videoFile, _jobStatus, _jobLog, commercialScan);
                            if (!convertWithCopy.Unsupported)
                            {
                                _jobLog.WriteEntry(this, Localise.GetPhrase("Converting with COPY"), Log.LogEntryType.Information);

                                bool ret = convertWithCopy.Convert();
                                if (ret)
                                {
                                    converted = true;
                                    _convertedFile = convertWithCopy.ConvertedFile;
                                    videoFile.ConversionTool = "copy";
                                }
                                else
                                {
                                    _jobLog.WriteEntry(this, Localise.GetPhrase("COPY did not convert successfully, using fallback if configured"), Log.LogEntryType.Error);
                                }
                            }

                            break;
                        }
                    case "mencoder":
                        {
                            ConvertWithMencoder convertWithMencoder = new ConvertWithMencoder(conversionOptions, "mencoder", videoFile, _jobStatus, _jobLog, commercialScan);
                            if (!convertWithMencoder.Unsupported)
                            {
                                _jobLog.WriteEntry(this, Localise.GetPhrase("Converting with MEncoder"), Log.LogEntryType.Information);
                                
                                bool ret = convertWithMencoder.Convert();
                                if (ret)
                                {
                                    converted = true;
                                    _convertedFile = convertWithMencoder.ConvertedFile;
                                    videoFile.ConversionTool = "mencoder";
                                }
                                else
                                {
                                    _jobLog.WriteEntry(this, Localise.GetPhrase("MEncoder did not convert successfully, using fallback if configured"), Log.LogEntryType.Error);
                                }
                            }
                            else
                                _jobLog.WriteEntry(this, Localise.GetPhrase("Unsupported MEncoder file formats"), Log.LogEntryType.Error);

                            break;
                        }
                    case "handbrake":
                        {
                            ConvertWithHandbrake convertWithHandbrake = new ConvertWithHandbrake(conversionOptions, "handbrake", videoFile, _jobStatus, _jobLog, commercialScan);
                            if (!convertWithHandbrake.Unsupported)
                            {
                                _jobLog.WriteEntry(this, Localise.GetPhrase("Converting with Handbrake"), Log.LogEntryType.Information); 
                                
                                bool ret = convertWithHandbrake.Convert();
                                if (ret)
                                {
                                    converted = true;
                                    _convertedFile = convertWithHandbrake.ConvertedFile;
                                    videoFile.ConversionTool = "handbrake";
                                }
                                else
                                {
                                    _jobLog.WriteEntry(this, Localise.GetPhrase("Handbrake did not convert successfully, using fallback if configured"), Log.LogEntryType.Error);
                                }
                            }
                            else
                                _jobLog.WriteEntry(this, Localise.GetPhrase("Unsupported Handbrake file formats"), Log.LogEntryType.Error);

                            break;
                        }
                    case "ffmpeg":
                        {
                            ConvertWithFfmpeg convertWithFfmpeg = new ConvertWithFfmpeg(conversionOptions, "ffmpeg", videoFile, _jobStatus, _jobLog, commercialScan, srtFile);
                            if (!convertWithFfmpeg.Unsupported)
                            {
                                _jobLog.WriteEntry(this, Localise.GetPhrase("Converting with FFMpeg"), Log.LogEntryType.Information); 

                                bool ret = convertWithFfmpeg.Convert();
                                if (ret)
                                {
                                    converted = true;
                                    _convertedFile = convertWithFfmpeg.ConvertedFile;
                                    _subtitleBurned = convertWithFfmpeg.SubtitleBurned; // Right now only ffmpeg supports subtitle burning
                                    videoFile.ConversionTool = "ffmpeg";
                                }
                                else
                                {
                                    _jobLog.WriteEntry(this, Localise.GetPhrase("FFMpeg did not convert successfully, using fallback if configured"), Log.LogEntryType.Error);
                                }
                            }
                            else
                                _jobLog.WriteEntry(this, Localise.GetPhrase("Unsupported FFMpeg file formats"), Log.LogEntryType.Error);

                            break;
                        }
                    default:
                        {
                            _jobLog.WriteEntry(Localise.GetPhrase("Unsupported converter"), Log.LogEntryType.Error); 
                            break;
                        }
                }

                if (converted || _jobStatus.Cancelled)
                    break;
            }

            if (!converted)
                _jobLog.WriteEntry(this, Localise.GetPhrase("Unable to convert file") + " " + Path.GetFileName(videoFile.SourceVideo) + " " + Localise.GetPhrase("using profile") + " " + conversionOptions.profile, Log.LogEntryType.Error);
            else
            {
                _jobLog.WriteEntry(this, Localise.GetPhrase("Successfully converted file") + " " + Path.GetFileName(videoFile.SourceVideo) + " " + Localise.GetPhrase("using profile") + " " + conversionOptions.profile, Log.LogEntryType.Debug); 

                //Reset the error message incase there was a fallback conversion the suceeded
                _jobStatus.ErrorMsg = "";
            }

            return converted;
        }
Пример #2
0
        /// <summary>
        /// Check the History if the file has been converted (check output/converted filename and path).
        /// This function is thread safe
        /// </summary>
        /// <param name="convertedFile">Output Filename and path to check</param>
        /// <returns>True of the output filename and path exists in the history file</returns>
        public static bool DoesConvertedFileExistCheckHistory(string convertedFile)
        {
            // TODO: A very very large history file can cause the computer to "hang" and have high CPU utilization, how does one handle this situation?
            try
            {
                // Check if the file has been converted in the past
                Ini historyIni = new Ini(GlobalDefs.HistoryFile);
                List<string> fileNames = historyIni.GetSectionNames();
                foreach (string filePath in fileNames)
                {
                    if (filePath.ToLower() == convertedFile.ToLower()) // Check if the converted file exists in the History list, ignore case
                        if (historyIni.GetSectionKeyValuePairs(filePath)["Status"] == "OutputFromConversion") // Double check that this file is an output from the conversion
                            return true;
                }
            }
            catch (Exception e)
            {
                Log.AppLog.WriteEntry("Unable to check History file entries", Log.LogEntryType.Error, true);
                Log.AppLog.WriteEntry("Error -> " + e.ToString(), Log.LogEntryType.Error, true);
            }

            return false;
        }
Пример #3
0
        /// <summary>
        /// Scans the Monitored directories and Manual Queue for new files to process
        /// Applies the filter tests
        /// Processes conversion task jobs for the files and adds them to the queue
        /// This function takes a lock on the Queue while modifying the queue and is thread safe
        /// </summary>
        public void ScanForFiles()
        {
            // Search the specific directories
            foreach (MonitorJobOptions monitorTask in MCEBuddyConf.GlobalMCEConfig.AllMonitorTasks)
            {
                IEnumerable<string> foundFiles = null;
                try
                {
                    // Directory.EnumerateFiles throws an exception if it comes across a protected/unaccesible directory and the ENTIRE list is empty
                    // Instead we need to handle exceptions, skip the protected file/directory and continue walking down the rest
                    foundFiles = FilePaths.GetDirectoryFiles(monitorTask.searchPath, "*", (monitorTask.monitorSubdirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)).OrderBy(File.GetLastWriteTime); // We sort the files by last modified time when scanning and adding (oldest to newest)

                    if (foundFiles != null && foundFiles.Count() > 0) // Check for no files (could be due to security access/protection errors
                    {
                        foreach (string foundFile in foundFiles)
                        {
                            if (GlobalDefs.Shutdown) // Check for a shutdown command, this can be an intensive loop
                                return; // Exit - we're done here

                            Monitor.Enter(_monitorTaskFilterMismatchFiles); // Make this thread safe
                            if (_monitorTaskFilterMismatchFiles.ContainsKey(foundFile)) // Check if this file has been processed by this monitor task and doesn't have a filter match, if so skip it (the filters do not change until the engine is stopped, settings changed, engine restarted which will create a new queue)
                            {
                                if (_monitorTaskFilterMismatchFiles[foundFile].Contains(monitorTask.taskName))
                                {
                                    Monitor.Exit(_monitorTaskFilterMismatchFiles);
                                    continue;
                                }
                            }
                            Monitor.Exit(_monitorTaskFilterMismatchFiles);

                            Monitor.Enter(_archivedFiles);
                            if (_archivedFiles.Contains(foundFile)) // Check if the file has been marked as an archive file if so skip it
                            {
                                Monitor.Exit(_archivedFiles);
                                continue;
                            }
                            Monitor.Exit(_archivedFiles);

                            // First check if this file is in the MCEBuddyArchive directory (which contains converted files, if so skip them)
                            if (Path.GetDirectoryName(foundFile).ToLower().Contains((string.IsNullOrEmpty(MCEBuddyConf.GlobalMCEConfig.GeneralOptions.archivePath) ? GlobalDefs.MCEBUDDY_ARCHIVE.ToLower() : MCEBuddyConf.GlobalMCEConfig.GeneralOptions.archivePath.ToLower())))
                            {
                                Monitor.Enter(_archivedFiles);
                                _archivedFiles.Add(foundFile); // add to the list
                                Monitor.Exit(_archivedFiles);
                                Log.AppLog.WriteEntry(this, "File " + foundFile + " has been converted and archived, skipping", Log.LogEntryType.Debug);
                                continue;
                            }

                            // 1st Level Pattern Check - Found a file, filename pattern match from monitor task
                            if (Util.Text.WildcardRegexPatternMatch(Path.GetFileName(foundFile), monitorTask.searchPattern)) // Check pattern match for Monitor Locations filter
                            {
                                // Take a lock here for EACH file before processing and modifying queue
                                // This is done per file and not for all files so that we don't lock up the engine interfaces which need the same lock to respond to GUI queries
                                // CheckAndAddFile is very intensive time consuming process for each file as it extracts metadata and compares filters
                                // Also EnumerateFiles is a very intensive process for very large nested and remote directories which will lock up the thread if the lock is taken
                                Monitor.Enter(Queue); // Take a lock on the queue before modifying the queue
                                CheckAndAddFile(foundFile, monitorTask, false); // Check history, monitor and conversion task filters and creates conversion job for file
                                Monitor.Exit(Queue); // Release the lock on the queue after modifying the queue
                            }
                            else // File type mismatch, log and keep track of them for each monitor task processed
                            {
                                Monitor.Enter(_monitorTaskFilterMismatchFiles); // Make it thread safe
                                if (!_monitorTaskFilterMismatchFiles.ContainsKey(foundFile)) /// Check if this file does not have a key, then create one
                                    _monitorTaskFilterMismatchFiles.Add(foundFile, new List<string>()); // Make a new key for the file
                                _monitorTaskFilterMismatchFiles[foundFile].Add(monitorTask.taskName); // Add this task for the file as a filter mismatch
                                Monitor.Exit(_monitorTaskFilterMismatchFiles);

                                Log.AppLog.WriteEntry(this, "File " + Path.GetFileName(foundFile) + " did not match wildcard" + " " + monitorTask.searchPattern + " for monitor task " + monitorTask.taskName, Log.LogEntryType.Debug);
                            }
                        }
                    }
                    else
                        Log.AppLog.WriteEntry("No accessible files founds in location " + monitorTask.searchPath + " for monitor task " + monitorTask.taskName, Log.LogEntryType.Information);
                }
                catch (Exception ex)
                {
                    Log.AppLog.WriteEntry("Unable to search for files in location " + monitorTask.searchPath + " for monitor task " + monitorTask.taskName + "\r\nERROR : " + ex.Message, Log.LogEntryType.Warning);
                    foundFiles = null;

                    try { Monitor.Exit(Queue); } // Release queue lock
                    catch { }

                    try { Monitor.Exit(_monitorTaskFilterMismatchFiles); } // Release monitor mismatch list lock
                    catch { }

                    try { Monitor.Exit(_archivedFiles); } // Release archived list lock
                    catch { }
                }
            }

            // Read the manual queue - manual selections are always first
            Ini iniQueue = new Ini(GlobalDefs.ManualQueueFile);
            SortedList<string, string> manualQueue = iniQueue.GetSectionKeyValuePairs("ManualQueue");
            foreach (KeyValuePair<string, string> manualFile in manualQueue)
            {
                string filePath = manualFile.Value; // Due to INI restriction only the Value can hold special characters like ];= which maybe contained in the filename, hence the Value is used to capture the "TRUE" filename (Key and Section have restrictions)

                if (GlobalDefs.Shutdown) // Check for a shutdown command, this can be an intensive loop
                    return; // Exit - we're done here

                // Check for valid entry
                if (String.IsNullOrWhiteSpace(filePath))
                    continue;

                string destinationPath = Path.GetDirectoryName(filePath);
                if (String.IsNullOrWhiteSpace(destinationPath)) // check for a null directory name here (happens with some root level network paths)
                {
                    iniQueue.DeleteSection(filePath); // Remove the key from the manual file
                    continue;
                }

                // Connect network drives if needed for each manual entry
                GeneralOptions go = MCEBuddyConf.GlobalMCEConfig.GeneralOptions;
                if (Util.Net.IsUNCPath(destinationPath))
                {
                    if (!String.IsNullOrWhiteSpace(go.userName))
                    {
                        ConnectNet(destinationPath, go.domainName, go.userName, go.password);
                    }
                    else
                    {
                        Log.AppLog.WriteEntry("No network authentication username found, defaulting to Guest authentication", Log.LogEntryType.Warning);
                        ConnectNet(destinationPath, "", GlobalDefs.DEFAULT_NETWORK_USERNAME, "");
                    }
                }

                if (Directory.Exists(filePath)) // After we are connected, check if the target is a directory (accidentally happens), we don't process it
                {
                    Log.AppLog.WriteEntry("Manually selected file " + filePath + " is a directory, skipping", Log.LogEntryType.Warning);
                    iniQueue.DeleteSection(filePath); // Remove the key from the manual file
                    continue;
                }

                if (!File.Exists(filePath)) // After we are connected, check if the file actually exists
                {
                    Log.AppLog.WriteEntry("Manually selected file " + filePath + " does not exist, skipping", Log.LogEntryType.Warning);
                    iniQueue.DeleteSection(filePath); // Remove the key from the manual file
                    continue;
                }

                Log.AppLog.WriteEntry("Manually selected file " + filePath + " added to queue", Log.LogEntryType.Debug);
                // Take a lock here for EACH file before processing and modifying queue
                // This is done per file and not for all files so that we don't lock up the engine interfaces which need the same lock to respond to GUI queries
                // CheckAndAddFile is very intensive time consuming process for each file as it extracts metadata and compares filters
                try
                {
                    Monitor.Enter(Queue); // Take a lock on the queue before modifying the queue
                    CheckAndAddFile(filePath, null, true);
                    Monitor.Exit(Queue); // Release the lock on the queue after modifying the queue
                }
                catch (Exception ex)
                {
                    Log.AppLog.WriteEntry("Add manual files terminated.\r\nERROR : " + ex.Message, Log.LogEntryType.Warning);

                    try { Monitor.Exit(Queue); } // Release queue lock
                    catch { }
                }
            }
        }
Пример #4
0
        public Dictionary<string, SortedList<string, string>> GetConversionHistory()
        {
            Ini historyIni = new Ini(GlobalDefs.HistoryFile);
            Dictionary<string, SortedList<string, string>> retVal = new Dictionary<string,SortedList<string,string>>();

            try
            {
                List<string> fileNames = historyIni.GetSectionNames();
                foreach (string filePath in fileNames)
                {
                    try
                    {
                        SortedList<string, string> entries = historyIni.GetSectionKeyValuePairs(filePath);
                        retVal.Add(filePath, entries); // Add the file and the entries for the file
                    }
                    catch (Exception e1)
                    {
                        Log.AppLog.WriteEntry(this, "Error processing history file section entry -> " + filePath + "\r\nError -> " + e1.ToString(), Log.LogEntryType.Error, true);
                    }
                }
            }
            catch (Exception e)
            {
                Log.AppLog.WriteEntry(this, "Unable to get History file entries.\r\nError -> " + e.ToString(), Log.LogEntryType.Error, true);
            }

            return retVal;
        }