Exemple #1
0
        /// <summary>
        /// Returns the final extension for the file to be converted
        /// </summary>
        /// <param name="conversionOptions">Conversion Options</param>
        /// <returns>Extension as specified in the Conversion Profile</returns>
        public static string GetConversionExtension(ConversionJobOptions conversionOptions)
        {
            Ini ini = new Ini(GlobalDefs.ProfileFile);
            string orderSetting = ini.ReadString(conversionOptions.profile, "order", "").ToLower().Trim();
            if (!orderSetting.Contains("mencoder")) orderSetting = orderSetting.Replace("me","mencoder");
            if (!orderSetting.Contains("handbrake")) orderSetting = orderSetting.Replace("hb", "handbrake");
            if (!orderSetting.Contains("ffmpeg")) orderSetting = orderSetting.Replace("ff", "ffmpeg");

            string[] tool = orderSetting.Split(',');

            // We can check the first tool since all tools will lead to the same final extension
            string extension = ini.ReadString(conversionOptions.profile, tool[0] + "-ext", "").ToLower().Trim();
            string remuxTo = ini.ReadString(conversionOptions.profile, tool[0] + "-remuxto", "").ToLower().Trim();

            if (!string.IsNullOrEmpty(remuxTo))
            {
                if (remuxTo[0] != '.') remuxTo = "." + remuxTo;  // Just in case someone does something dumb like forget the leading "."
                return remuxTo;
            }
            else
            {
                if (extension[0] != '.') extension = "." + extension;  // Just in case someone does something dumb like forget the leading "."
                return extension;
            }
        }
Exemple #2
0
        /// <summary>
        /// Used to execute custom commands after the conversion process is compelte just before the file is moved to the desination directory
        /// </summary>
        /// <param name="prefix">Prefix for reading lines from profile</param>
        /// <param name="profile">Profile name</param>
        /// <param name="taskName">Task Name</param>
        /// <param name="workingPath">Temp working path</param>
        /// <param name="destinationPath">Destination path for converted file</param>
        /// <param name="convertedFile">Full path to final converted file</param>
        /// <param name="sourceFile">Full path to original source file</param>
        /// <param name="remuxFile">Full path to intermediate remuxed file</param>
        /// <param name="edlFile">Full path to EDL file</param>
        /// <param name="srtFile">Full path to SRT file</param>
        /// <param name="metaData">Video metadata structure for source file</param>
        /// <param name="jobStatus">ref to JobStatus</param>
        /// <param name="jobLog">JobLog</param>
        public CustomCommand(string prefix, string profile, string taskName, string workingPath, string destinationPath, string convertedFile, string sourceFile, string remuxFile, string edlFile, string srtFile, VideoTags metaData, JobStatus jobStatus, Log jobLog)
        {
            _profile = profile;
            _taskName = taskName;
            _jobLog = jobLog;
            _jobStatus = jobStatus;
            _workingPath = workingPath;
            _destinationPath = destinationPath;
            _convertedFile = convertedFile;
            _sourceFile = sourceFile;
            _remuxFile = remuxFile;
            _edlFile = edlFile;
            _srtFile = srtFile;
            _metaData = metaData;
            _prefix = prefix;

            Ini ini = new Ini(GlobalDefs.ProfileFile);
            commandPath = ini.ReadString(profile, prefix + "Path", "").ToLower().Trim();
            commandParameters = ini.ReadString(profile, prefix + "Parameters", "");
            hangPeriod = ini.ReadInteger(profile, prefix + "HangPeriod", GlobalDefs.HANG_PERIOD_DETECT);
            customCommandCritical = ini.ReadBoolean(profile, prefix + "Critical", false); // NOTE: if customCommandCritical is TRUE will need to return false in case it's a failure
            customCommandUISession = ini.ReadBoolean(profile, prefix + "UISession", false); // Does the custom command need a UI Session (Session 1) with admin privileges
            customCommandShowWindow = ini.ReadBoolean(profile, prefix + "ShowWindow", true); // Show the window or hide it
            customCommandExitCodeCheck = ini.ReadBoolean(profile, prefix + "ExitCodeCheck", false); // Don't check for exit code

            _jobLog.WriteEntry(this, "Custom command parameters read -> " + " \n" + _prefix + "Path = " + commandPath + " \n" + _prefix + "Parameters = " + commandParameters + " \n" + _prefix + "HangPeriod = " + hangPeriod.ToString(System.Globalization.CultureInfo.InvariantCulture) + " \n" + _prefix + "Critical = " + customCommandCritical.ToString() + " \n" + _prefix + "UISession = " + customCommandUISession.ToString() + " \n" + _prefix + "ShowWindow = " + customCommandShowWindow.ToString() + " \n" + _prefix + "ExitCodeCheck = " + customCommandExitCodeCheck.ToString(), Log.LogEntryType.Debug);
        }
        public RemoteEngineForm()
        {
            InitializeComponent();

            Ini tempIni = new Ini(GlobalDefs.TempSettingsFile);
            string remoteServerName = tempIni.ReadString("Engine", "RemoteServerName", GlobalDefs.MCEBUDDY_SERVER_NAME);
            int remoteServerPort = tempIni.ReadInteger("Engine", "RemoteServerPort", int.Parse(GlobalDefs.MCEBUDDY_SERVER_PORT));

            engineNameTxt.Text = remoteServerName;
            portNoTxt.Text = remoteServerPort.ToString(System.Globalization.CultureInfo.InvariantCulture);
        }
Exemple #4
0
        /// <summary>
        /// Gets the order of the encoders in the specified profile
        /// </summary>
        /// <param name="profile">Profile to get encoders order</param>
        /// <returns>String array containing the encoders in execution order</returns>
        public static string[] GetProfileEncoderOrder(string profile)
        {
            Ini ini = new Ini(GlobalDefs.ProfileFile);

            string orderSetting = ini.ReadString(profile, "order", "").ToLower().Trim();
            if (!orderSetting.Contains("mencoder")) orderSetting = orderSetting.Replace("me", "mencoder");
            if (!orderSetting.Contains("handbrake")) orderSetting = orderSetting.Replace("hb", "handbrake");
            if (!orderSetting.Contains("ffmpeg")) orderSetting = orderSetting.Replace("ff", "ffmpeg");

            string[] order = orderSetting.Split(',');

            return order;
        }
Exemple #5
0
        public Remover(string profile, string uncutVideo, string workingPath, string edlFile, float initialSkipSeconds, VideoInfo remuxedVideoFileInfo, JobStatus jobStatus, Log jobLog)
            : base(profile, uncutVideo, remuxedVideoFileInfo.Duration, edlFile, initialSkipSeconds, jobStatus, jobLog)
        {
            _remuxedVideoFileInfo = remuxedVideoFileInfo;
            _uncutVideo = uncutVideo;
            _ext = Util.FilePaths.CleanExt(_uncutVideo);
            _workingPath = workingPath;
            _duration = _remuxedVideoFileInfo.Duration;
            _jobStatus = jobStatus;
            _jobLog = jobLog;

            // Read various profile parameters
            Ini configProfileIni = new Ini(GlobalDefs.ProfileFile);
            _cutMP4Alternative = configProfileIni.ReadBoolean(profile, "CutMP4Alternate", false); // for FFMPEG and Handbrake, we have commerical cutting options, for mEncoder cutting is done during conversion using -edl option
            jobLog.WriteEntry("MP4 Alternative Cutting -> " + _cutMP4Alternative.ToString(CultureInfo.InvariantCulture), Log.LogEntryType.Debug);
            _universalCommercialRemover = configProfileIni.ReadBoolean(profile, "UniversalCommercialRemover", false); // Forcing the use of CutFFMPEG which works on all video types
            jobLog.WriteEntry("Universal Commercial Remover -> " + _universalCommercialRemover.ToString(CultureInfo.InvariantCulture), Log.LogEntryType.Debug);
            string commercialMerge = configProfileIni.ReadString(profile, "CommercialMergeTool", ""); // Force tool to merge commercial segments
            jobLog.WriteEntry("Force Commercial Segment Merging Tool -> " + commercialMerge, Log.LogEntryType.Debug);

            switch (commercialMerge.ToLower())
            {
                case "avidemux":
                    _useAVIDemuxMerge = true;
                    break;

                case "ffmpeg":
                    _useFFMPEGMerge = true;
                    break;

                case "":
                    break;

                default:
                    jobLog.WriteEntry("INVALID Force Commercial Segment Merging Tool -> " + commercialMerge, Log.LogEntryType.Warning);
                    break;
            }
        }
Exemple #6
0
        public ConversionJob(ConversionJobOptions conversionJobOptions, VideoMetaData metaData)
        {
            _conversionOptions = conversionJobOptions; // First thing to do
            _metaData = metaData; // Save the metadata if present

            _originalFileNameBackup = _conversionOptions.sourceVideo; // This is what we use to report to the world what we're working on, _sourceVideo may change under certain conditions below
            if (String.IsNullOrEmpty(_conversionOptions.destinationPath))
                _conversionOptions.destinationPath = Path.GetDirectoryName(_conversionOptions.sourceVideo); // No dest path = convert in place

            _jobStatus = new JobStatus();
            _jobStatus.SourceFile = _conversionOptions.sourceVideo;
            _jobStatus.TaskName = _conversionOptions.taskName;

            // Read various engine parameters
            _maxConcurrentJobs = MCEBuddyConf.GlobalMCEConfig.GeneralOptions.maxConcurrentJobs;
            _spaceCheck = MCEBuddyConf.GlobalMCEConfig.GeneralOptions.spaceCheck;
            _subtitleSegmentOffset = MCEBuddyConf.GlobalMCEConfig.GeneralOptions.subtitleSegmentOffset;

            // Read various profile parameters
            Ini configProfileIni = new Ini(GlobalDefs.ProfileFile);

            // Profile only parameters 
            _preConversionCommercialRemover = configProfileIni.ReadBoolean(_conversionOptions.profile, "PreConversionCommercialRemover", false); // Check if the user wants to remove commercials before the actual conversion in which case we always return false - i.e. remove commercial during remux stage
            _copyLOGFile = configProfileIni.ReadBoolean(_conversionOptions.profile, "CopyLogFile", false); // Check if the user wants to save the log file generated by Comskip
            _copyPropertiesFile = configProfileIni.ReadBoolean(_conversionOptions.profile, "CopyPropertiesFile", false); // Check if the user wants to save the properties file for SageTV metadata

            if (configProfileIni.ReadString(_conversionOptions.profile, "AutoDeinterlace", "default") == "default")
                _autoDeinterlace = _conversionOptions.autoDeInterlace;
            else
                _autoDeinterlace = configProfileIni.ReadBoolean(_conversionOptions.profile, "AutoDeinterlace", false);

            if (_conversionOptions.renameOnly)
                _commercialSkipCut = true; //no cutting if we are renaming only
            else if (configProfileIni.ReadString(_conversionOptions.profile, "CommercialSkipCut", "default") == "default")
                _commercialSkipCut = _conversionOptions.commercialSkipCut;
            else _commercialSkipCut = configProfileIni.ReadBoolean(_conversionOptions.profile, "CommercialSkipCut", false);
        }
Exemple #7
0
 private void ReadEMailSettings(Ini configIni)
 {
     mceBuddyConfSettings.generalOptions.eMailSettings.eMailBasicSettings.smtpServer = configIni.ReadString("Engine", "eMailServer", "");
     mceBuddyConfSettings.generalOptions.eMailSettings.eMailBasicSettings.port = configIni.ReadInteger("Engine", "eMailPort", 25); // default port is 25
     mceBuddyConfSettings.generalOptions.eMailSettings.eMailBasicSettings.ssl = configIni.ReadBoolean("Engine", "eMailSSL", false);
     mceBuddyConfSettings.generalOptions.eMailSettings.eMailBasicSettings.fromAddress = configIni.ReadString("Engine", "eMailFrom", "");
     mceBuddyConfSettings.generalOptions.eMailSettings.eMailBasicSettings.toAddresses = configIni.ReadString("Engine", "eMailTo", "");
     mceBuddyConfSettings.generalOptions.eMailSettings.successEvent = configIni.ReadBoolean("Engine", "eMailSuccess", true);
     mceBuddyConfSettings.generalOptions.eMailSettings.failedEvent = configIni.ReadBoolean("Engine", "eMailFailed", true);
     mceBuddyConfSettings.generalOptions.eMailSettings.cancelledEvent = configIni.ReadBoolean("Engine", "eMailCancelled", true);
     mceBuddyConfSettings.generalOptions.eMailSettings.startEvent = configIni.ReadBoolean("Engine", "eMailStart", true);
     mceBuddyConfSettings.generalOptions.eMailSettings.downloadFailedEvent = configIni.ReadBoolean("Engine", "eMailDownloadFailed", true);
     mceBuddyConfSettings.generalOptions.eMailSettings.queueEvent = configIni.ReadBoolean("Engine", "eMailQueue", true);
     mceBuddyConfSettings.generalOptions.eMailSettings.successSubject = configIni.ReadString("Engine", "eMailSuccessSubject", "");
     mceBuddyConfSettings.generalOptions.eMailSettings.failedSubject = configIni.ReadString("Engine", "eMailFailedSubject", "");
     mceBuddyConfSettings.generalOptions.eMailSettings.cancelledSubject = configIni.ReadString("Engine", "eMailCancelledSubject", "");
     mceBuddyConfSettings.generalOptions.eMailSettings.startSubject = configIni.ReadString("Engine", "eMailStartSubject", "");
     mceBuddyConfSettings.generalOptions.eMailSettings.downloadFailedSubject = configIni.ReadString("Engine", "eMailDownloadFailedSubject", "");
     mceBuddyConfSettings.generalOptions.eMailSettings.queueSubject = configIni.ReadString("Engine", "eMailQueueSubject", "");
     mceBuddyConfSettings.generalOptions.eMailSettings.skipBody = configIni.ReadBoolean("Engine", "eMailSkipBody", false);
     mceBuddyConfSettings.generalOptions.eMailSettings.eMailBasicSettings.userName = configIni.ReadString("Engine", "eMailUsername", "");
     mceBuddyConfSettings.generalOptions.eMailSettings.eMailBasicSettings.password = configIni.ReadString("Engine", "eMailPassword", "");
     if (!String.IsNullOrEmpty(mceBuddyConfSettings.generalOptions.eMailSettings.eMailBasicSettings.password))
         mceBuddyConfSettings.generalOptions.eMailSettings.eMailBasicSettings.password = Util.Crypto.Decrypt(mceBuddyConfSettings.generalOptions.eMailSettings.eMailBasicSettings.password); // password is stored encrypted
 }
Exemple #8
0
        private void ReadGeneralSettings(Ini configIni)
        {
            // Read the General Settings
            ReadHourMinute(configIni, ref mceBuddyConfSettings.generalOptions.wakeHour, ref mceBuddyConfSettings.generalOptions.wakeMinute, "Wake");
            ReadHourMinute(configIni, ref mceBuddyConfSettings.generalOptions.startHour, ref mceBuddyConfSettings.generalOptions.startMinute, "Start");
            ReadHourMinute(configIni, ref mceBuddyConfSettings.generalOptions.stopHour, ref mceBuddyConfSettings.generalOptions.stopMinute, "Stop");

            mceBuddyConfSettings.generalOptions.domainName = configIni.ReadString("Engine", "DomainName", "");
            mceBuddyConfSettings.generalOptions.userName = configIni.ReadString("Engine", "UserName", "Guest");
            mceBuddyConfSettings.generalOptions.password = configIni.ReadString("Engine", "Password", "");
            if (!String.IsNullOrEmpty(mceBuddyConfSettings.generalOptions.password))
                mceBuddyConfSettings.generalOptions.password = Crypto.Decrypt(mceBuddyConfSettings.generalOptions.password); // Password is kept as encrypted
            mceBuddyConfSettings.generalOptions.daysOfWeek = configIni.ReadString("Engine", "DaysOfWeek", "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday");
            mceBuddyConfSettings.generalOptions.maxConcurrentJobs = configIni.ReadInteger("Engine", "MaxConcurrentJobs", 1);
            mceBuddyConfSettings.generalOptions.logJobs = configIni.ReadBoolean("Engine", "LogJobs", true);
            mceBuddyConfSettings.generalOptions.logLevel = configIni.ReadInteger("Engine", "LogLevel", 3);
            mceBuddyConfSettings.generalOptions.logKeepDays = configIni.ReadInteger("Engine", "LogKeepDays", 15);
            mceBuddyConfSettings.generalOptions.deleteOriginal = configIni.ReadBoolean("Engine", "DeleteOriginal", false);
            mceBuddyConfSettings.generalOptions.useRecycleBin = configIni.ReadBoolean("Engine", "UseRecycleBin", false);
            mceBuddyConfSettings.generalOptions.archiveOriginal = configIni.ReadBoolean("Engine", "ArchiveOriginal", false);
            mceBuddyConfSettings.generalOptions.deleteConverted = configIni.ReadBoolean("Engine", "DeleteConverted", false); 
            mceBuddyConfSettings.generalOptions.allowSleep = configIni.ReadBoolean("Engine", "AllowSleep", true);
            mceBuddyConfSettings.generalOptions.suspendOnBattery = configIni.ReadBoolean("Engine", "SuspendOnBattery", false);
            mceBuddyConfSettings.generalOptions.minimumAge = configIni.ReadInteger("Engine", "MinimumAge", 0);
            mceBuddyConfSettings.generalOptions.sendEmail = configIni.ReadBoolean("Engine", "SendEmail", false);
            mceBuddyConfSettings.generalOptions.locale = configIni.ReadString("Engine", "Locale", CultureInfo.CurrentCulture.Name);
            mceBuddyConfSettings.generalOptions.tempWorkingPath = configIni.ReadString("Engine", "TempWorkingPath", "");
            CheckPathEnding(ref mceBuddyConfSettings.generalOptions.tempWorkingPath);
            mceBuddyConfSettings.generalOptions.archivePath = configIni.ReadString("Engine", "ArchivePath", "");
            CheckPathEnding(ref mceBuddyConfSettings.generalOptions.archivePath);
            mceBuddyConfSettings.generalOptions.failedPath = configIni.ReadString("Engine", "FailedPath", "");
            CheckPathEnding(ref mceBuddyConfSettings.generalOptions.failedPath);
            mceBuddyConfSettings.generalOptions.spaceCheck = configIni.ReadBoolean("Engine", "SpaceCheck", true);
            mceBuddyConfSettings.generalOptions.comskipPath = configIni.ReadString("Engine", "CustomComskipPath", "");
            mceBuddyConfSettings.generalOptions.customProfilePath = configIni.ReadString("Engine", "CustomProfilePath", "");
            mceBuddyConfSettings.generalOptions.hangTimeout = configIni.ReadInteger("Engine", "HangPeriod", GlobalDefs.HANG_PERIOD_DETECT);
            mceBuddyConfSettings.generalOptions.pollPeriod = configIni.ReadInteger("Engine", "PollPeriod", GlobalDefs.MONITOR_POLL_PERIOD);
            mceBuddyConfSettings.generalOptions.processPriority = configIni.ReadString("Engine", "ProcessPriority", "Normal");
            mceBuddyConfSettings.generalOptions.CPUAffinity = (IntPtr) configIni.ReadLong("Engine", "CPUAffinity", 0);
            mceBuddyConfSettings.generalOptions.engineRunning = configIni.ReadBoolean("Engine", "EngineRunning", false);
            mceBuddyConfSettings.generalOptions.localServerPort = configIni.ReadInteger("Engine", "LocalServerPort", int.Parse(GlobalDefs.MCEBUDDY_SERVER_PORT));
            mceBuddyConfSettings.generalOptions.uPnPEnable = configIni.ReadBoolean("Engine", "UPnPEnable", false);
            mceBuddyConfSettings.generalOptions.firewallExceptionEnabled = configIni.ReadBoolean("Engine", "FirewallExceptionEnable", false);
            string srtSegmentOffset = configIni.ReadString("Engine", "SubtitleSegmentOffset", GlobalDefs.SEGMENT_CUT_OFFSET_GOP_COMPENSATE);
            double.TryParse(srtSegmentOffset, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out mceBuddyConfSettings.generalOptions.subtitleSegmentOffset);
            
            ReadEMailSettings(configIni);
        }
Exemple #9
0
        /// <summary>
        /// Check the local file for updates downloaded earlier
        /// </summary>
        private void CheckForUpdates()
        {
            if (!_newUpdateDownloaded) // Nothing to process
                return;
            else
                _newUpdateDownloaded = false; // We have processed this new update

            Monitor.Enter(_announcementTextScrollTimer); // Take the lock before we modify anything

            Ini configIni = new Ini(GlobalDefs.TempSettingsFile);

            // 1st is Announcement [Announcement, Link, ToolTip]
            string announcement = configIni.ReadString("Engine", "Announcement", "");
            string announcementLink = configIni.ReadString("Engine", "AnnouncementLink", "");
            _announcementInfo[0, 0] = announcement;
            _announcementInfo[0, 1] = announcementLink;
            if (String.IsNullOrWhiteSpace(announcementLink))
                _announcementInfo[0, 2] = ""; // Clear the pop up tooltip
            else
                _announcementInfo[0, 2] = Localise.GetPhrase("Click here to open link"); // Set a pop up tooltip

            // 2nd is Version [Announcement, Link, ToolTip]
            //Get the version of this app
            Version CurrentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;

            // Check for any new version and write to form if required (this comes in the end, it trumps all annoucements
            Version LatestVersion = CurrentVersion;
            string LatestVersionString = configIni.ReadString("Engine", "LatestVersion", "");

            if (!String.IsNullOrWhiteSpace(LatestVersionString))
                LatestVersion = new Version(LatestVersionString);

            if (LatestVersion > CurrentVersion)
            {
                string MCEBuddyVersion = LatestVersion.Major.ToString(CultureInfo.InvariantCulture) + "." + LatestVersion.Minor.ToString(CultureInfo.InvariantCulture) + "." + LatestVersion.Build.ToString(CultureInfo.InvariantCulture);
                if (LatestVersion.Revision == 1) //Revision version 1 = Release version else BETA version
                    _announcementInfo[1, 0] = Localise.GetPhrase("New version") + " " + MCEBuddyVersion + " " + Localise.GetPhrase("available");
                else
                    _announcementInfo[1, 0] = Localise.GetPhrase("New Beta version") + " " + MCEBuddyVersion + " " + Localise.GetPhrase("available");
                _announcementInfo[1, 1] = Crypto.Decrypt(GlobalDefs.MCEBUDDY_DOWNLOAD_NEW_VERSION);
                _announcementInfo[1, 2] = Localise.GetPhrase("Click here to download new version of MCEBuddy"); // Set a pop up tooltip
            }
            else
                _announcementInfo[1, 0] = _announcementInfo[1, 1] = _announcementInfo[1, 2] = "";

            Monitor.Exit(_announcementTextScrollTimer);
        }
Exemple #10
0
        private void StatusForm_Load(object sender, EventArgs e)
        {
            // Check for changes in screen resolution and screen changes (multi monitor support) - this HAS to be in Load and NOT in the constructor since the form has not been initiatized yet
            this.MaximumSize = Screen.FromControl(this).WorkingArea.Size; // Set the maximum size for the form based on working areas so we don't end up with dead/inaccessible locations

            // Set the version properties (Versioning is driven as Major.Minor.Build.Revision)
            MajorTitle.Text = "MCEBuddy " + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Major.ToString(System.Globalization.CultureInfo.InvariantCulture) + "." + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Minor.ToString(System.Globalization.CultureInfo.InvariantCulture);
            if (System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Revision == 0) // BETA versions have revision code (Major.Minor.Build.Revision) as 0
                BetaTitle.Text = "Beta " + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Build.ToString(System.Globalization.CultureInfo.InvariantCulture);
            else
                BetaTitle.Text = "Release " + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Build.ToString(System.Globalization.CultureInfo.InvariantCulture);

            Ini tempIni = new Ini(GlobalDefs.TempSettingsFile);
            // Check if this is the first time the GUI is start after an installation
            if (tempIni.ReadBoolean("GUI", "FirstStartComplete", false) == false)
            {
                MessageBox.Show(Localise.GetPhrase("Rest your mouse on any button, box or item to get Instant Help on it.\n\nFor more information on how to use, troubleshoot or get support for MCEBuddy click on the <Getting Started> link on the top right corner.\n\nDonations are always welcome :) Enjoy!\n\n  - Ramit, Derek & Goose"), Localise.GetPhrase("Welcome to MCEBuddy"));
                tempIni.Write("GUI", "FirstStartComplete", true);
            }

            // Check for server location and start the thread to keep the UI connected to the MCEBuddy engine
            string remoteServerName = tempIni.ReadString("Engine", "RemoteServerName", GlobalDefs.MCEBUDDY_SERVER_NAME);
            if (remoteServerName != GlobalDefs.MCEBUDDY_SERVER_NAME) // check if it's a remote machine
                _connectPeriod = GlobalDefs.REMOTE_ENGINE_POLL_PERIOD; // remote machine needs be pinged slower

            // If this thread is not the thread that created the control, we'll invoke a callback in a threadsafe way to fix the control
            _tryConnectThread = new Thread(TryConnect);
            _tryConnectThread.IsBackground = true; // Kill this thread if the process is closed
            _tryConnectThread.CurrentCulture = _tryConnectThread.CurrentUICulture = Localise.MCEBuddyCulture;
            _tryConnectThread.Start();

            // Start the announcement text scroll timer
            _announcementTextScrollTimer.Tick += new EventHandler(this.ScrollAnnouncementLabel);
            _announcementTextScrollTimer.Interval = 250;
            _announcementTextScrollTimer.Start();

            // Now start the core background job status thread
            backgroundUpdate.WorkerSupportsCancellation = true;
            backgroundUpdate.RunWorkerAsync();

            this.Show(); // Show the form
        }
        /// <summary>
        /// Remux the WTV file directly to TSMPEG using FFMPEG
        /// Uses 3 levels of remuxing, stream copy, video transcode and video+audio transcode with support for Auto FPS detection or manual FPS override
        /// Sets the fixCorruptedRemux flag is it falls back to transcodes the video and audio using remux
        /// </summary>
        /// <param name="remuxTypes">Type of remuxing to try, copy, slow or both</param>
        /// <returns>Success or Failure</returns>
        private bool RemuxFFmpeg(FFMPEGRemuxType remuxTypes)
        {
            float FPS = 0;
            bool skipCopyRemux = false; // Do we need to skip stream copy
            bool skipSlowRemux = false; // Do we need to skip the slow copy

            if (remuxTypes == FFMPEGRemuxType.Recode) // Check if user asked to skip the copy remux
                skipCopyRemux = true;
            else if (remuxTypes == FFMPEGRemuxType.Copy)
                skipSlowRemux = true;

            // Read ReMux Parameters from Config Profile
            Ini configProfileIni = new Ini(GlobalDefs.ConfigFile);
            string profile = "FFMpegBackupRemux"; // This is where the Fallback Remux parameters are stored

            // MediaInfo is more reliable than FFMPEG but it doesn't always succeed
            _jobLog.WriteEntry(this, "Reading MediaInfo from " + _RecordingFile, Log.LogEntryType.Debug);
            FPS = VideoParams.FPS(_RecordingFile);
            _jobLog.WriteEntry(this, "Video FPS : " + FPS.ToString(CultureInfo.InvariantCulture), Log.LogEntryType.Debug);
            if ((FPS <= 0) || ((FPS > _RecordingFileMediaInfo.MediaInfo.VideoInfo.FPS) && (_RecordingFileMediaInfo.MediaInfo.VideoInfo.FPS > 0))) // MediaInfo did not succeed or got wrong value
            {
                _jobLog.WriteEntry(this, "Reading FFMPEG info from " + _RecordingFile, Log.LogEntryType.Debug);

                if (_RecordingFileMediaInfo.Success && !_RecordingFileMediaInfo.ParseError)
                    FPS = _RecordingFileMediaInfo.MediaInfo.VideoInfo.FPS; // Get the FPS
                else
                    _jobLog.WriteEntry(this, "ERROR reading FFMPEG Media info from " + _RecordingFile + ", disabling AutoFPS support", Log.LogEntryType.Warning);
            }

            // First check if the video is mpeg1 or mpeg2 video, else we need to move on to Slow Remux which will convert the video to MPEG2VIDEO
            // If it's mpeg1 or mpeg2, we can stream copy it directly
            // Check if we are copying mpeg4 video or if we are asked to copy all video codecs the copy remux it
            if (_RecordingFileMediaInfo.Success && !_RecordingFileMediaInfo.ParseError)
            {
                if (remuxTypes != FFMPEGRemuxType.Copy) // If we are forced to do copy remux then skip the check
                {
                    // Check if we have a valid copy remux configuration
                    if (!( // If not any of the below, then skip the copy remux
                        _allowAllCopyRemuxing || // Copy all
                        (_allowH264CopyRemuxing && _mpeg4Codecs.Any(s => s.Contains(_RecordingFileMediaInfo.MediaInfo.VideoInfo.VideoCodec.ToLower()))) || // Copy h264
                        _mpeg2Codecs.Any(s => s.Contains(_RecordingFileMediaInfo.MediaInfo.VideoInfo.VideoCodec.ToLower())) || // mpeg2
                        _mpeg1Codecs.Any(s => s.Contains(_RecordingFileMediaInfo.MediaInfo.VideoInfo.VideoCodec.ToLower())) // mpeg1
                        ))
                    {
                        _jobLog.WriteEntry(this, "Video codec is not supported for fast copy remux in current configuration, skipping to slow remux. Video Codec found -> " + _RecordingFileMediaInfo.MediaInfo.VideoInfo.VideoCodec.ToLower(), Log.LogEntryType.Information);
                        skipCopyRemux = true;
                    }
                }
                else
                    _jobLog.WriteEntry(this, "Fast copy remuxing forced, skipping check for valid copy remux configuration. Video Codec found -> " + _RecordingFileMediaInfo.MediaInfo.VideoInfo.VideoCodec.ToLower(), Log.LogEntryType.Warning);
            }

            if (!skipCopyRemux)
            {
                int profileCount = 0;
                while (true) // We do this in a loop until all MPEG2 CopyRemux profiles have been consumed
                {
                    // Check for Multiple Audio Streams
                    // Copy all streams if there is an audio selection specified and we'll extract it later (make sure you use the -map 0:a command to copy ALL audio stream, -acodec copy copies only 1 audio stream withou the map command)
                    // Use coptyb and copyts to avoid invalid DTS errors
                    // Threads 0 causes an error in some streams, avoid
                    _jobLog.WriteEntry(this, Localise.GetPhrase("Copy remux loop ") + profileCount.ToString(CultureInfo.InvariantCulture), Log.LogEntryType.Information);

                    // First try to copy all the streams directly (read parmeters for copy profile)
                    string copyRemuxParams = configProfileIni.ReadString(profile, "CopyRemux" + profileCount.ToString(CultureInfo.InvariantCulture), "");

                    if (String.IsNullOrWhiteSpace(copyRemuxParams)) // Have we used up all the CopyRemux profiles, then we're done here - try something else
                        break;

                    // Some files have zero channel audio tracks in them, if so then copying all audio track will fails
                    // So we check for these tracks and run the remux
                    if (FFMPEGRemuxZeroChannelFix(copyRemuxParams, FPS))
                        break; // We're good, all done

                    profileCount++; // try the next one
                }
            }

            if (!skipSlowRemux && !RemuxedFileOK()) //check if file is created and if we aren't skipping the slow remux
            {
                _jobStatus.PercentageComplete = 100; // reset it to try again
                _jobStatus.CurrentAction = Localise.GetPhrase("Slow Remuxing");

                int profileCount = 0;
                while (true) // Now loop through all the SlowRemux profiles until we succeed or fail
                {
                    _jobLog.WriteEntry(this, Localise.GetPhrase("Slow remux loop ") + profileCount.ToString(CultureInfo.InvariantCulture), Log.LogEntryType.Information);

                    // Now try to copy audio and transcode video (read parameters for Slow Remux profile)
                    string slowRemuxParams = configProfileIni.ReadString(profile, "SlowRemux" + profileCount.ToString(CultureInfo.InvariantCulture), "");

                    if (String.IsNullOrWhiteSpace(slowRemuxParams)) // Have we used up all the SlowRemux profiles, then we're done here
                        break;

                    // Some files have zero channel audio tracks in them, if so then copying all audio track will fails
                    // So we check for these tracks and run the remux
                    if (FFMPEGRemuxZeroChannelFix(slowRemuxParams, FPS))
                        break; // We're good, all done

                    profileCount++; // Move onto the next profile iteration
                }

                if (!RemuxedFileOK()) //check of file is created
                {
                    _jobLog.WriteEntry(Localise.GetPhrase("Slow Remux using FFMPEG failed at") + " " + _jobStatus.PercentageComplete.ToString(CultureInfo.InvariantCulture) + "%", Log.LogEntryType.Error);
                    Util.FileIO.TryFileDelete(RemuxedFile);
                    return false;
                }
                else
                    slowRemuxed = true; // We have successfully remuxed the file but using the slow method (i.e. possibly destorying any CC data)
            }
            else if (skipSlowRemux) // Check if the copy remuxed file is okay since we aren't doing slow remux
            {
                if (RemuxedFileOK())
                    return true;
                else
                {
                    Util.FileIO.TryFileDelete(RemuxedFile); // Clean up
                    return false;
                }
            }

            return true;
        }
Exemple #12
0
        /// <summary>
        /// Tries to keep connected to the MCEBuddy Engine over TCP/IP. Once connected it downloads the MCEBuddy Config options from the server.
        /// </summary>
        /// <returns>True if it is connected to the Pipe</returns>
        private void TryConnect()
        {
            while (!_exit) // Keep trying to connect as long as app is running
            {
                bool configLockTaken = false; // Flag to see state of lock
                
                try
                {
                    Monitor.Enter(_configLock, ref configLockTaken); // Take a lock before getting settings, incase Settings are being changed by the user
                    if (_pipeProxy.ServiceShutdownBySystem()) // Has the system initated shutdown, if so we need to shutdown the GUI (to avoid uninstall issues)
                    {
                        Monitor.Exit(_configLock);
                        configLockTaken = false;
                        _exit = true; // We are done, release all threads and resources
                        this.Close(); // Close the GUI
                        continue;
                    }
                    MCEBuddyConf.GlobalMCEConfig = new MCEBuddyConf(_pipeProxy.GetConfigParameters()); // Get the parameters from the Engine we are connected to
                    _jobs = _pipeProxy.GetAllJobsInQueueStatus();
                    _isEngineRunning = _pipeProxy.EngineRunning();
                    _isEngineSuspended = _pipeProxy.IsSuspended();
                    _isEngineCrashed = _pipeProxy.EngineCrashed();
                    _isWithinConversionTimes = _pipeProxy.WithinConversionTimes();
                    Monitor.Exit(_configLock);
                    configLockTaken = false;
                    _isEngineConnected = true; // All good, we are connected

                    Thread.Sleep(_connectPeriod * (WindowState == FormWindowState.Minimized ? GlobalDefs.GUI_MINIMIZED_ENGINE_POLL_SLOW_FACTOR : 1)); // Check again in x seconds, refresh y times slower
                    continue;
                }
                catch (Exception) // Whoops pipe broken!
                {
                    if (configLockTaken)
                    {
                        Monitor.Exit(_configLock); // Release the lock
                        configLockTaken = false;
                    }
                    _isWithinConversionTimes = _isEngineConnected = _isEngineCrashed = _isEngineRunning = _isEngineSuspended = false; // We are no longer connected
                    _pipeProxy = null; // We should start over
                }

                try // Try to reconnect
                {
                    ChannelFactory<ICore> pipeFactory;
                    string serverString;

                    Ini tempIni = new Ini(GlobalDefs.TempSettingsFile);
                    string remoteServerName = tempIni.ReadString("Engine", "RemoteServerName", GlobalDefs.MCEBUDDY_SERVER_NAME);
                    int remoteServerPort = tempIni.ReadInteger("Engine", "RemoteServerPort", int.Parse(GlobalDefs.MCEBUDDY_SERVER_PORT));

                    if (serverInfoLbl.InvokeRequired) // Cannot access UI elements directly from a non UI thread
                        serverInfoLbl.Invoke(new MethodInvoker(delegate { serverInfoLbl.Text = "Engine: " + remoteServerName + "  Port: " + remoteServerPort.ToString(); }));
                    else
                        serverInfoLbl.Text = "Engine: " + remoteServerName + "  Port: " + remoteServerPort.ToString();

                    // If it's LOCALHOST, we use local NAMED PIPE else network SOAP WEB SERVICES
                    if (remoteServerName == GlobalDefs.MCEBUDDY_SERVER_NAME)
                    {
                        // local NAMED PIPE
                        serverString = GlobalDefs.MCEBUDDY_LOCAL_NAMED_PIPE;
                        NetNamedPipeBinding npb = new NetNamedPipeBinding();
                        TimeSpan timeoutPeriod = GlobalDefs.PIPE_TIMEOUT;
                        npb.OpenTimeout = npb.CloseTimeout = npb.SendTimeout = npb.ReceiveTimeout = timeoutPeriod;
                        npb.TransferMode = TransferMode.Buffered;
                        npb.MaxReceivedMessageSize = npb.MaxBufferPoolSize = npb.MaxBufferSize = Int32.MaxValue;
                        npb.ReaderQuotas = XmlDictionaryReaderQuotas.Max;
                        pipeFactory = new ChannelFactory<ICore>(npb, new EndpointAddress(serverString));
                    }
                    else
                    {
                        // network SOAP WEB SERVICES
                        serverString = GlobalDefs.MCEBUDDY_WEB_SOAP_PIPE;
                        serverString = serverString.Replace(GlobalDefs.MCEBUDDY_SERVER_NAME, remoteServerName); // Update the Server Name with that from the config file
                        serverString = serverString.Replace(GlobalDefs.MCEBUDDY_SERVER_PORT, remoteServerPort.ToString(CultureInfo.InvariantCulture)); // Update the Server Port with that from the config file
                        BasicHttpBinding ntb = new BasicHttpBinding(GlobalDefs.MCEBUDDY_PIPE_SECURITY);
                        TimeSpan timeoutPeriod = GlobalDefs.PIPE_TIMEOUT;
                        ntb.OpenTimeout = ntb.CloseTimeout = ntb.SendTimeout = ntb.ReceiveTimeout = timeoutPeriod;
                        ntb.TransferMode = TransferMode.Buffered;
                        ntb.MaxReceivedMessageSize = ntb.MaxBufferPoolSize = ntb.MaxBufferSize = Int32.MaxValue;
                        ntb.ReaderQuotas = XmlDictionaryReaderQuotas.Max;
                        pipeFactory = new ChannelFactory<ICore>(ntb, new EndpointAddress(serverString));
                    }

                    // Increase the max objects allowed in serialization channel otherwise we lose the connection when there more than 5K objects in the queue
                    foreach (OperationDescription operation in pipeFactory.Endpoint.Contract.Operations)
                    {
                        DataContractSerializerOperationBehavior dataContractBehavior = operation.Behaviors[typeof(DataContractSerializerOperationBehavior)] as DataContractSerializerOperationBehavior;

                        if (dataContractBehavior != null)
                            dataContractBehavior.MaxItemsInObjectGraph = Int32.MaxValue;
                    }

                    Monitor.Enter(_configLock, ref configLockTaken);
                    ICore tempPipeProxy = pipeFactory.CreateChannel();
                    MCEBuddyConf.GlobalMCEConfig = new MCEBuddyConf(tempPipeProxy.GetConfigParameters()); // Get the parameters from the Engine we are connected to
                    _jobs = tempPipeProxy.GetAllJobsInQueueStatus();
                    _isEngineRunning = tempPipeProxy.EngineRunning();
                    _isEngineSuspended = tempPipeProxy.IsSuspended();
                    _isEngineCrashed = tempPipeProxy.EngineCrashed();
                    _isWithinConversionTimes = tempPipeProxy.WithinConversionTimes();
                    GlobalDefs.profilesSummary = tempPipeProxy.GetProfilesSummary(); // Get a list of all the profiles and descriptions
                    GlobalDefs.engineProcessorCount = tempPipeProxy.GetProcessorCount(); // Number of processors on the engine machine
                    try // special case, ShowAnalyzer sometimes hangs the system and fails to respond, ignore and continue with log
                    {
                        GlobalDefs.showAnalyzerInstalled = tempPipeProxy.ShowAnalyzerInstalled(); // Check if Showanalyzer is installed
                    }
                    catch (Exception e)
                    {
                        Log.WriteSystemEventLog("Unable to get status of ShowAnalyzer, please reinstall ShowAnalyzer and reboot the system. Error " + e.ToString(), EventLogEntryType.Error);
                        MessageBox.Show(Localise.GetPhrase("ShowAnalyzer is not responding. Please the reboot system or reinstall ShowAnalyzer."), Localise.GetPhrase("ShowAnalyzer Not Responding"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                    Monitor.Exit(_configLock);
                    configLockTaken = false;

                    // all good again, update the status
                    _pipeProxy = tempPipeProxy;
                    _versionMismatch = false; // set after pipeProxy
                    _isEngineConnected = true;
                }
                catch (Exception e)
                {
                    // Check for version mistmatch
                    if ((e.InnerException is System.Runtime.Serialization.SerializationException) || (e is System.ServiceModel.ActionNotSupportedException))
                        _versionMismatch = true;
                    else
                        _versionMismatch = false;

                    //WriteEventLog(Localise.GetPhrase("MCEBuddy GUI: Unable to create pipe to MCEBuddy service"), EventLogEntryType.Warning); //not required since this call will fail when MCEBuddy Service has not started and will overflow the eventlog. The message will be shown on the GUI
                    if (configLockTaken)
                    {
                        Monitor.Exit(_configLock);
                        configLockTaken = false;
                    }
                    _isWithinConversionTimes = _isEngineConnected = _isEngineCrashed = _isEngineRunning = _isEngineSuspended = false; // Still broken
                    _pipeProxy = null; // Last item

                    Thread.Sleep(_connectPeriod * (WindowState == FormWindowState.Minimized ? GlobalDefs.GUI_MINIMIZED_ENGINE_POLL_SLOW_FACTOR : 1)); // Try to connect every x seconds
                }

                if (_isEngineConnected) // SetUserLocale should never be called from within a try catch statement since it can cause an exception if there is an application restart
                    SetUserLocale(); // ReInitialize MCEBuddy (we may have been disconnected and parameters changed, connected to a new engine etc)
            }
        }
Exemple #13
0
        private void paypalButton_Click(object sender, EventArgs e)
        {
            Ini configIni = new Ini(GlobalDefs.TempSettingsFile);
            string donationLink = configIni.ReadString("Engine", "DonationLink", "");
            if (String.IsNullOrWhiteSpace(donationLink))
                donationLink = Crypto.Decrypt(GlobalDefs.MCEBUDDY_HOME_PAGE); // backup

            OpenLink(donationLink);
        }
        /// <summary>
        /// Remux the source recorded file using the specified base parameters, but also check if the source file (or Remux file) has any zero channel audio streams in it.
        /// If so it tries to remux using FFMPEG and the given parameters but compensating to keep only one audio channel
        /// It also checks to see if it can locate the user identified audio language within the source recorded file if required
        /// </summary>
        /// <param name="baseRemuxParams">Base parameters used for remuxing</param>
        /// <param name="FPS">Frame rate for the Recorded file</param>
        /// <param name="fixRemuxedFile">True if Remuxed file file needs to be FIXED for Zero Channel Audio, false if Recorded file needs to be checked and then fixed</param>
        /// <param name="ffmpeg">Point to the last executed ffmpeg object (used for analysis) since this is a recursive reentrant function, we need to keep track</param>
        /// <returns>True if there are no zero channel audio tracks or on a successful remux</returns>
        private bool FFMPEGRemuxZeroChannelFix(string baseRemuxParams, float FPS, bool fixRemuxedFile, ref FFmpeg ffmpeg)
        {
            bool autoFPS = false; // Used to check if Auto FPS was used

            _jobLog.WriteEntry(this, "Verifying " + (fixRemuxedFile ? "Remuxed" : "Recorded") + " file audio streams for Zero Channel Audio", Log.LogEntryType.Debug);

            // Compensate for FFMPEG bug #2227 where the mjpeg is identified as a video stream hence breaking -map 0:v, rather replace 'v' with the actual video stream number
            if (_RecordingFileMediaInfo.Success && !_RecordingFileMediaInfo.ParseError)
            {
                if (baseRemuxParams.Contains("-map 0:v"))
                {
                    if (_RecordingFileMediaInfo.MediaInfo.VideoInfo.Stream != -1) // Check if we have a file with only audio streams
                        baseRemuxParams = baseRemuxParams.Replace("-map 0:v", "-map 0:" + _RecordingFileMediaInfo.MediaInfo.VideoInfo.Stream.ToString(CultureInfo.InvariantCulture)); // replace 0:v with the actual video stream number
                    else
                    {
                        _jobLog.WriteEntry(this, "No Video stream detected in original file, removing support for video stream selection", Log.LogEntryType.Warning);
                        baseRemuxParams = baseRemuxParams.Replace("-map 0:v", ""); // remove 0:v since we have no video stream
                    }
                }

                // Check of the original file has no audio, then remove support for audio mappings
                if (_RecordingFileMediaInfo.AudioTracks < 1)
                {
                    _jobLog.WriteEntry(this, "No Audio stream detected in original file, removing support for audio stream selection", Log.LogEntryType.Warning);
                    baseRemuxParams = baseRemuxParams.Replace("-map 0:a", ""); // remove 0:v since we have no video stream
                }
            }
            else
            {
                _jobLog.WriteEntry(this, "Error reading audio and video streams, removing support for audio and video stream selection", Log.LogEntryType.Warning);
                baseRemuxParams = Regex.Replace(baseRemuxParams, @"-map 0:[\S]*", ""); // Remove all patterns like -map 0:v or -map 0:4 since we cannot read ffmpeg stream info
            }

            // We have a 0 channel audio we try to compensate for it by selecting the appropriate audio channel
            if (CheckForNoneOrZeroChannelAudioTrack((fixRemuxedFile ? RemuxedFile : _RecordingFile), _jobStatus, _jobLog))
            {
                _jobLog.WriteEntry(this, Localise.GetPhrase("Found 0 channel audio while remuxing, re-remuxing using a single audio track"), Log.LogEntryType.Information);
                _jobStatus.CurrentAction = Localise.GetPhrase("Re-ReMuxing due to audio error");

                // DO NOT USE MAP ALL commands, we only need to copy one audio and one video stream
                baseRemuxParams = Regex.Replace(baseRemuxParams, @"-map 0:[\S]*", ""); // Remove all patterns like -map 0:v or -map 0:4

                if (_RecordingFileMediaInfo.Success && !_RecordingFileMediaInfo.ParseError)
                {
                    // Audio parameters - find the best Audio channel for the selected language or best audio track if there are imparired tracks otherwise by default the encoder will select the best audio channel (encoders do not do a good job of ignoring imparired tracks)
                    bool selectedTrack = false;
                    int audioChannels = 0;
                    int audioStream = -1;
                    int videoStream = -1;
                    bool selectedAudioImpaired = false;

                    if ((!String.IsNullOrEmpty(_requestedAudioLanguage) || (_RecordingFileMediaInfo.ImpariedAudioTrackCount > 0)) && (_RecordingFileMediaInfo.AudioTracks > 1)) // More than 1 audio track to choose from and either we have a language match request or a presence of an imparied channel (likely no audio)
                    {
                        for (int i = 0; i < _RecordingFileMediaInfo.AudioTracks; i++)
                        {
                            bool processTrack = false; // By default we don't need to process

                            // Language selection check, if the user has picked a specific language code, look for it
                            // If we find a match, we look the one with the highest number of channels in it
                            if (!String.IsNullOrEmpty(_requestedAudioLanguage))
                            {
                                if ((_RecordingFileMediaInfo.MediaInfo.AudioInfo[i].Language.ToLower() == _requestedAudioLanguage) && (_RecordingFileMediaInfo.MediaInfo.AudioInfo[i].Channels > 0))
                                {
                                    if (selectedTrack)
                                    {
                                        if (!( // take into account impaired tracks (since impaired tracks typically have no audio)
                                            ((_RecordingFileMediaInfo.MediaInfo.AudioInfo[i].Channels > audioChannels) && !_RecordingFileMediaInfo.MediaInfo.AudioInfo[i].Impaired) || // PREFERENCE to non-imparied Audio tracks with the most channels
                                            ((_RecordingFileMediaInfo.MediaInfo.AudioInfo[i].Channels > audioChannels) && selectedAudioImpaired) || // PREFERENCE to Audio tracks with most channels if currently selected track is impaired
                                            (!_RecordingFileMediaInfo.MediaInfo.AudioInfo[i].Impaired && selectedAudioImpaired) // PREFER non impaired audio over currently selected impaired
                                            ))
                                            continue; // we have found a lang match, now we are looking for more channels only now
                                    }

                                    processTrack = true; // All conditions met, we need to process this track
                                }
                            }
                            else if (_RecordingFileMediaInfo.MediaInfo.AudioInfo[i].Channels > 0)// we have a imparied audio track, select the non impaired track with the highest number of tracks or bitrate or frequency
                            {
                                if (selectedTrack)
                                {
                                    if (!( // take into account impaired tracks (since impaired tracks typically have no audio)
                                        ((_RecordingFileMediaInfo.MediaInfo.AudioInfo[i].Channels > audioChannels) && !_RecordingFileMediaInfo.MediaInfo.AudioInfo[i].Impaired) || // PREFERENCE to non-imparied Audio tracks with the most channels
                                        ((_RecordingFileMediaInfo.MediaInfo.AudioInfo[i].Channels > audioChannels) && selectedAudioImpaired) || // PREFERENCE to Audio tracks with most channels if currently selected track is impaired
                                        (!_RecordingFileMediaInfo.MediaInfo.AudioInfo[i].Impaired && selectedAudioImpaired) // PREFER non impaired audio over currently selected impaired
                                        ))
                                        continue; // we have found a lang match, now we are looking for more channels only now
                                }
                             
                                processTrack = true; // All conditions met, we need to process this track
                            }

                            if (processTrack) // We need to process this track
                            {
                                audioChannels = _RecordingFileMediaInfo.MediaInfo.AudioInfo[i].Channels;
                                audioStream = _RecordingFileMediaInfo.MediaInfo.AudioInfo[i].Stream; // store the stream number for the selected audio channel
                                string audioCodec = _RecordingFileMediaInfo.MediaInfo.AudioInfo[i].AudioCodec;
                                int audioTrack = i; // Store the audio track number we selected
                                string audioLanguage = _RecordingFileMediaInfo.MediaInfo.AudioInfo[i].Language.ToLower(); // this is what we selected
                                selectedAudioImpaired = _RecordingFileMediaInfo.MediaInfo.AudioInfo[i].Impaired; // Is this an imparied track?
                                videoStream = _RecordingFileMediaInfo.MediaInfo.VideoInfo.Stream; // Store the video information
                                selectedTrack = true; // We found a suitable track

                                if (!String.IsNullOrEmpty(_requestedAudioLanguage))
                                    _jobLog.WriteEntry(this, Localise.GetPhrase("Found Audio Language match for language") + " " + _requestedAudioLanguage.ToUpper() + ", " + Localise.GetPhrase("Audio Stream") + " " + audioStream.ToString(CultureInfo.InvariantCulture) + ", " + Localise.GetPhrase("Audio Track") + " " + audioTrack.ToString(CultureInfo.InvariantCulture) + ", " + Localise.GetPhrase("Channels") + " " + audioChannels.ToString(CultureInfo.InvariantCulture) + ", " + Localise.GetPhrase("Codec") + "->" + audioCodec + ", Audio Impaired->" + selectedAudioImpaired.ToString(), Log.LogEntryType.Debug);
                                else
                                    _jobLog.WriteEntry(this, Localise.GetPhrase("Compensating for audio impaired tracks, selected track with language") + " " + _requestedAudioLanguage.ToUpper() + ", " + Localise.GetPhrase("Audio Stream") + " " + audioStream.ToString(CultureInfo.InvariantCulture) + ", " + Localise.GetPhrase("Audio Track") + " " + audioTrack.ToString(CultureInfo.InvariantCulture) + ", " + Localise.GetPhrase("Channels") + " " + audioChannels.ToString(CultureInfo.InvariantCulture) + ", " + Localise.GetPhrase("Codec") + "->" + audioCodec + ", Audio Impaired->" + selectedAudioImpaired.ToString(), Log.LogEntryType.Debug);
                            }
                        }
                    }

                    // If we have a found a suitable language, select it else let FFMPEG select it automatically
                    if (selectedTrack)
                    {
                        if (audioStream != -1)
                            baseRemuxParams += " -map 0:" + audioStream.ToString(CultureInfo.InvariantCulture); // Select the Audiotrack we had isolated earlier
                        
                        if (videoStream != -1)
                            baseRemuxParams += " -map 0:" + videoStream.ToString(CultureInfo.InvariantCulture); // Check if we have a video stream
                    }
                    else
                        _jobLog.WriteEntry(this, "No audio language match found, letting encoder choose best audio language", Log.LogEntryType.Warning);
                }
                else
                    _jobLog.WriteEntry(this, "Error reading audio streams, letting encoder choose best audio language", Log.LogEntryType.Warning);
            }

            // Build the command line to remux the file now
            string ffmpegParams = "";

            // Check for auto frame rate and replace with video framerate
            if (baseRemuxParams.Contains("-r auto"))
            {
                if (FPS > 0)
                {
                    _jobLog.WriteEntry(this, "Detected Auto FPS request, setting frame rate to " + FPS.ToString(CultureInfo.InvariantCulture), Log.LogEntryType.Debug);
                    baseRemuxParams = baseRemuxParams.Replace("-r auto", "-r " + FPS.ToString(CultureInfo.InvariantCulture));
                    autoFPS = true;
                }
                else
                {
                    _jobLog.WriteEntry(this, Localise.GetPhrase("Cannot read frame rate from file, skipping frame rate adjustment"), Log.LogEntryType.Warning);
                    baseRemuxParams = baseRemuxParams.Replace("-r auto", ""); // no framerate since we can't read it
                    autoFPS = false;
                }
            }
            else
                autoFPS = false;

            // Check for input file placeholders and substitute
            if (baseRemuxParams.Contains("-i <source>")) // Check if we have a input file placeholder (useful if we need to put commands before -i)
                ffmpegParams = "-y " + baseRemuxParams.Replace("-i <source>", "-i " + Util.FilePaths.FixSpaces(_RecordingFile) + " ") + " " + Util.FilePaths.FixSpaces(RemuxedFile);
            else
                ffmpegParams = "-y -i " + Util.FilePaths.FixSpaces(_RecordingFile) + " " + baseRemuxParams + " " + Util.FilePaths.FixSpaces(RemuxedFile); // DO NOT USE -async 1 with COPY

            FFmpeg.FFMpegExecuteAndHandleErrors(ffmpegParams, _jobStatus, _jobLog, Util.FilePaths.FixSpaces(RemuxedFile), false, out ffmpeg); // Run ffmpeg and check for common errors, we will get back the final executed ffmpeg object which we can then check for errors/analyze
            if (!ffmpeg.Success || !RemuxedFileOK()) //check of file is created, outputhandler reports success (Percentage not requires since Success is more accurate)
            {
                // last ditch effort, try to fix for all errors
                if (ffmpeg.Success && !fixRemuxedFile) // avoid infinite loop, fix remuxed file only if we started out checking the recorded file
                {
                    if (!FFMPEGRemuxZeroChannelFix(baseRemuxParams, FPS, true, ref ffmpeg)) // Call ZeroChannelAudioFix this time to fix the remuxed file
                    {
                        _jobLog.WriteEntry(Localise.GetPhrase("0 Channel ReMux using FFMPEG failed at") + " " + _jobStatus.PercentageComplete.ToString(CultureInfo.InvariantCulture) + "%", Log.LogEntryType.Error);
                        Util.FileIO.TryFileDelete(RemuxedFile);
                        return false;
                    }
                }
                else
                {
                    Util.FileIO.TryFileDelete(RemuxedFile);
                    return false; // Avoid infinite loop, we are done here, nothing can be done, failed...
                }
            }
            else if (fixRemuxedFile) // If we are in the loop fixing the remuxed file, we did good, return now - don't process further yet
                return true;

            // Remux succeeded, check for Dropped or Duplicate packets due to incorrect FPS
            _jobLog.WriteEntry("Average rate of dropped frames :" + " " + ffmpeg.AverageDropROC.ToString("#0.00", CultureInfo.InvariantCulture), Log.LogEntryType.Debug);
            _jobLog.WriteEntry("Average rate of duplicate frames :" + " " + ffmpeg.AverageDupROC.ToString("#0.00", CultureInfo.InvariantCulture), Log.LogEntryType.Debug);

            // Read ReMux Parameters from Config Profile
            Ini configProfileIni = new Ini(GlobalDefs.ConfigFile);
            string profile = "FFMpegBackupRemux"; // This is where the Fallback Remux parameters are stored
            
            // Read the Drop frame threshhold
            double dropThreshold;
            double.TryParse(configProfileIni.ReadString(profile, "RemuxDropThreshold", "3.0"), System.Globalization.NumberStyles.Float, CultureInfo.InvariantCulture, out dropThreshold);

            // Read the Duplicate frame threshhold
            double dupThreshold;
            double.TryParse(configProfileIni.ReadString(profile, "RemuxDuplicateThreshold", "3.0"), System.Globalization.NumberStyles.Float, CultureInfo.InvariantCulture, out dupThreshold);

            if ((ffmpeg.AverageDropROC > dropThreshold) || (ffmpeg.AverageDupROC > dupThreshold))
            {
                if (autoFPS) // Check if we used AutoFPS and also if this isn't a going into an infinite loop
                    _jobLog.WriteEntry(Localise.GetPhrase("Remuxed file has too many dropped or duplicate frames, try to manually set the frame rate. Auto FPS used ->") + " " + FPS.ToString(CultureInfo.InvariantCulture), Log.LogEntryType.Warning);
                else
                    _jobLog.WriteEntry(Localise.GetPhrase("Remuxed file has too many dropped or duplicate frames, check/set the manual remux frame rate"), Log.LogEntryType.Warning);
            }

            // Since we are successful, keep track of how many seconds we skipped while remuxing the file
            FFMpegMEncoderParams checkParams = new FFMpegMEncoderParams(baseRemuxParams);
            float.TryParse(checkParams.ParameterValue("-ss"), System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out skipInitialSeconds);

            return true; // All done here
        }
Exemple #15
0
        private void ReadMonitorSettings(Ini configIni)
        {
            // Read the Monitor Tasks
            string[] searchRecords = configIni.ReadString("Engine", "SearchRecords", "").Split(',');
            foreach (string searchRecord in searchRecords)
            {
                if (String.IsNullOrEmpty(searchRecord))
                    continue;

                MonitorJobOptions mjo = new MonitorJobOptions();

                mjo.taskName = searchRecord;
                mjo.searchPath = configIni.ReadString(searchRecord, "SearchPath", "");
                CheckPathEnding(ref mjo.searchPath);
                mjo.searchPattern = configIni.ReadString(searchRecord, "SearchPattern", GlobalDefs.DEFAULT_VIDEO_STRING);
                mjo.searchPattern = mjo.searchPattern.Replace(GlobalDefs.DEFAULT_VIDEO_STRING, GlobalDefs.DEFAULT_VIDEO_FILE_TYPES);
                mjo.monitorSubdirectories = configIni.ReadBoolean(searchRecord, "MonitorSubdirectories", true);
                mjo.monitorConvertedFiles = configIni.ReadBoolean(searchRecord, "MonitorConvertedFiles", false);
                mjo.reMonitorRecordedFiles = configIni.ReadBoolean(searchRecord, "ReMonitorRecordedFiles", false);

                mjo.domainName = configIni.ReadString(searchRecord, "DomainName", "");
                mjo.userName = configIni.ReadString(searchRecord, "UserName", "Guest");
                mjo.password = configIni.ReadString(searchRecord, "Password", "");
                if (!String.IsNullOrEmpty(mjo.password))
                    mjo.password = Crypto.Decrypt(mjo.password); // Password is kept as encrypted

                mceBuddyConfSettings.monitorTasks.Add(mjo); // Add the Monitor Task object
            }
        }
Exemple #16
0
        private bool CheckUnsupported(string profile, string tool)
        {
            _jobLog.WriteEntry(this, ("Checking for Unsupported profile for container / codec combination"), Log.LogEntryType.Information);
            Ini ini = new Ini(GlobalDefs.ProfileFile);
            string unsupportedCombinations = ini.ReadString(profile, tool + "-unsupported", "").ToLower().Trim();

            if (unsupportedCombinations != "")
            {
                List<string> videoItems = new List<string>();

                // Use properties for ORIGINAL video (not remuxed file, since the user is referring to original video properties, remuxed is always MPEG2 and TS)
                // Derive all possible combinations from the source video (video, audio and extension)
                videoItems.Add(_videoFile.OriginalVideoFFMPEGStreamInfo.MediaInfo.VideoInfo.VideoCodec);
                foreach (MediaInfo.Audio audioInfo in _videoFile.OriginalVideoFFMPEGStreamInfo.MediaInfo.AudioInfo) // check all audio codecs found
                    videoItems.Add(audioInfo.AudioCodec);
                videoItems.Add(_videoFile.OriginalFileExtension.ToLower().Replace(".", ""));

                AddCombinations(ref videoItems);

                // Get the unsupported list and check to see if there are any matches
                string[] unsupported = unsupportedCombinations.Split(',');
                foreach (string combo in unsupported)
                {
                    string c = combo.ToLower().Trim();
                    if (videoItems.Contains(c))
                    {
                        _jobLog.WriteEntry(this, 
                            ("Unsupported profile for container / codec combination") + " " + c + " " + profile,
                            Log.LogEntryType.Warning);
                        _unsupported = true;
                        return true;
                    }
                }
            }
            return false;
        }
Exemple #17
0
        private void ReadConversionSettings(Ini configIni)
        {
            // Read the Conversion Tasks
            string[] conversionRecords = configIni.ReadString("Engine", "Tasks", "").Split(',');
            foreach (string conversionRecord in conversionRecords)
            {
                if (String.IsNullOrEmpty(conversionRecord))
                    continue;

                ConversionJobOptions cjo = new ConversionJobOptions();

                cjo.taskName = conversionRecord;
                cjo.profile = configIni.ReadString(conversionRecord, "Profile", "");
                cjo.destinationPath = configIni.ReadString(conversionRecord, "DestinationPath", "");
                CheckPathEnding(ref cjo.destinationPath);
                cjo.workingPath = configIni.ReadString(conversionRecord, "WorkingPath", "");
                CheckPathEnding(ref cjo.workingPath);
                cjo.fallbackToSourcePath = configIni.ReadBoolean(conversionRecord, "FallbackDestination", false);
                cjo.autoIncrementFilename = configIni.ReadBoolean(conversionRecord, "AutoIncrementFilename", false);
                cjo.skipReprocessing = configIni.ReadBoolean(conversionRecord, "SkipReprocessing", false);
                cjo.checkReprocessingHistory = configIni.ReadBoolean(conversionRecord, "CheckReprocessingHistory", false);
                cjo.addToiTunes = configIni.ReadBoolean(conversionRecord, "AddToiTunesLibrary", false);
                cjo.addToWMP = configIni.ReadBoolean(conversionRecord, "AddToWMPLibrary", false);
                cjo.maxWidth = configIni.ReadInteger(conversionRecord, "MaxWidth", 720);
                cjo.FPS = configIni.ReadString(conversionRecord, "FPS", "");
                cjo.renameBySeries = configIni.ReadBoolean(conversionRecord, "RenameBySeries", true);
                cjo.altRenameBySeries = configIni.ReadBoolean(conversionRecord, "AltRenameBySeries", false);
                cjo.customRenameBySeries = configIni.ReadString(conversionRecord, "CustomRenameBySeries", "");
                cjo.renameOnly = configIni.ReadBoolean(conversionRecord, "RenameOnly", false);
                cjo.fileSelection = configIni.ReadString(conversionRecord, "FileSelection", "");
                cjo.metaShowSelection = configIni.ReadString(conversionRecord, "MetaSelection", "");
                cjo.metaNetworkSelection = configIni.ReadString(conversionRecord, "MetaChannelSelection", "");
                string monitorNameList = configIni.ReadString(conversionRecord, "MonitorTaskNames", "");
                if (String.IsNullOrWhiteSpace(monitorNameList))
                    cjo.monitorTaskNames = null; // list should be empty if nothing is there
                else
                    cjo.monitorTaskNames = monitorNameList.Split(',');
                cjo.audioLanguage = configIni.ReadString(conversionRecord, "AudioLanguage", "");
                string audioOffsetStr = configIni.ReadString(conversionRecord, "AudioOffset", "0");
                double.TryParse(audioOffsetStr, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out cjo.audioOffset);
                cjo.drc = configIni.ReadBoolean(conversionRecord, "DRC", true);
                cjo.stereoAudio = configIni.ReadBoolean(conversionRecord, "StereoAudio", true);
                cjo.encoderSelectBestAudioTrack = configIni.ReadBoolean(conversionRecord, "EncoderSelectBestAudioTrack", true);
                cjo.autoDeInterlace = configIni.ReadBoolean(conversionRecord, "AutoDeInterlace", true);
                cjo.preferHardwareEncoding = configIni.ReadBoolean(conversionRecord, "PreferHardwareEncoding", true);
                cjo.startTrim = configIni.ReadInteger(conversionRecord, "StartTrim", 0);
                cjo.endTrim = configIni.ReadInteger(conversionRecord, "EndTrim", 0);
                cjo.insertQueueTop = configIni.ReadBoolean(conversionRecord, "InsertQueueTop", false);
                cjo.extractXML = configIni.ReadBoolean(conversionRecord, "ExtractXML", false);
                cjo.writeMetadata = configIni.ReadBoolean(conversionRecord, "WriteMetadata", true);
                cjo.disableCropping = configIni.ReadBoolean(conversionRecord, "DisableCropping", false);
                cjo.commercialSkipCut = configIni.ReadBoolean(conversionRecord, "TaskCommercialSkipCut", false);
                cjo.skipCopyBackup = configIni.ReadBoolean(conversionRecord, "SkipCopyBackup", false);
                cjo.skipRemuxing = configIni.ReadBoolean(conversionRecord, "SkipRemux", false);
                cjo.ignoreCopyProtection = configIni.ReadBoolean(conversionRecord, "IgnoreCopyProtection", false);
                cjo.tivoMAKKey = configIni.ReadString(conversionRecord, "TiVOMAKKey", "");
                cjo.downloadSeriesDetails = configIni.ReadBoolean(conversionRecord, "DownloadSeriesDetails", true);
                cjo.downloadBanner = configIni.ReadBoolean(conversionRecord, "DownloadBanner", true);
                cjo.enabled = configIni.ReadBoolean(conversionRecord, "Enabled", true);
                cjo.extractCC = configIni.ReadString(conversionRecord, "ExtractCC", "");
                cjo.embedSubtitlesChapters = configIni.ReadBoolean(conversionRecord, "EmbedSubtitlesChapters", false);
                cjo.prioritizeOriginalBroadcastDateMatch = configIni.ReadBoolean(conversionRecord, "PrioritizeOriginalBroadcastDateMatch", false);

                string ccOffsetStr = configIni.ReadString(conversionRecord, "CCOffset", GlobalDefs.DefaultCCOffset);
                double.TryParse(ccOffsetStr, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out cjo.ccOffset);

                string qualityMultiplierStr = configIni.ReadString(conversionRecord, "QualityMultiplier", "1");
                double.TryParse(qualityMultiplierStr, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out cjo.qualityMultiplier);
                if (cjo.qualityMultiplier <= 0.01) cjo.qualityMultiplier = 0.01F;
                if (cjo.qualityMultiplier > 4) cjo.qualityMultiplier = 4F;

                string volumeMultiplierStr = configIni.ReadString(conversionRecord, "VolumeMultiplier", "0");
                double.TryParse(volumeMultiplierStr, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out cjo.volumeMultiplier);
                if (cjo.volumeMultiplier <= -20) cjo.volumeMultiplier = -20F; //-10db minimum
                if (cjo.volumeMultiplier > 60) cjo.volumeMultiplier = 60F; //30db max

                string metaShowType = configIni.ReadString(conversionRecord, "MetaShowTypeSelection", ShowType.Default.ToString());
                if (String.Compare(metaShowType, ShowType.Movie.ToString(), true) == 0)
                    cjo.metaShowTypeSelection = ShowType.Movie;
                else if (String.Compare(metaShowType, ShowType.Series.ToString(), true) == 0)
                    cjo.metaShowTypeSelection = ShowType.Series;
                else if (String.Compare(metaShowType, ShowType.Sports.ToString(), true) == 0)
                    cjo.metaShowTypeSelection = ShowType.Sports;
                else
                    cjo.metaShowTypeSelection = ShowType.Default;

                string drmType = configIni.ReadString(conversionRecord, "MetaDRMTypeSelection", DRMType.All.ToString());
                if (String.Compare(drmType, DRMType.Protected.ToString(), true) == 0)
                    cjo.metaDRMSelection = DRMType.Protected;
                else if (String.Compare(drmType, DRMType.Unprotected.ToString(), true) == 0)
                    cjo.metaDRMSelection = DRMType.Unprotected;
                else
                    cjo.metaDRMSelection = DRMType.All;

                string showType = configIni.ReadString(conversionRecord, "ForceShowType", ShowType.Default.ToString());
                if (String.Compare(showType, ShowType.Movie.ToString(), true) == 0)
                    cjo.forceShowType = ShowType.Movie;
                else if (String.Compare(showType, ShowType.Series.ToString(), true) == 0)
                    cjo.forceShowType = ShowType.Series;
                else if (String.Compare(showType, ShowType.Sports.ToString(), true) == 0)
                    cjo.forceShowType = ShowType.Sports;
                else
                    cjo.forceShowType = ShowType.Default;
                
                string commercialRemovalStr = configIni.ReadString(conversionRecord, "CommercialRemoval", CommercialRemovalOptions.Comskip.ToString());
                if (String.Compare(commercialRemovalStr, CommercialRemovalOptions.Comskip.ToString(), true) == 0)
                    cjo.commercialRemoval = CommercialRemovalOptions.Comskip;
                else if (String.Compare(commercialRemovalStr, CommercialRemovalOptions.ShowAnalyzer.ToString(), true) == 0)
                    cjo.commercialRemoval = CommercialRemovalOptions.ShowAnalyzer;
                else
                    cjo.commercialRemoval = CommercialRemovalOptions.None;
                
                cjo.comskipIni = configIni.ReadString(conversionRecord, "ComskipINI", "");

                cjo.domainName = configIni.ReadString(conversionRecord, "DomainName", "");
                cjo.userName = configIni.ReadString(conversionRecord, "UserName", "Guest");
                cjo.password = configIni.ReadString(conversionRecord, "Password", "");
                if (!String.IsNullOrEmpty(cjo.password))
                    cjo.password = Crypto.Decrypt(cjo.password); // Password is kept as encrypted

                int metaCorrectionsCount = configIni.ReadInteger(conversionRecord, "MetaCorrectionsCount", 0);
                if (metaCorrectionsCount < 1)
                    cjo.metadataCorrections = null;
                else
                {
                    cjo.metadataCorrections = new ConversionJobOptions.MetadataCorrectionOptions[metaCorrectionsCount];
                    for (int i = 0; i < metaCorrectionsCount; i++) // The entries are kept in their own section, easier to manage
                    {
                        cjo.metadataCorrections[i] = new ConversionJobOptions.MetadataCorrectionOptions();
                        cjo.metadataCorrections[i].originalTitle = configIni.ReadString(conversionRecord + "-MetaCorrectionEntries", "OriginalTitle" + i.ToString(), "");
                        cjo.metadataCorrections[i].correctedTitle = configIni.ReadString(conversionRecord + "-MetaCorrectionEntries", "CorrectedTitle" + i.ToString(), "");
                        cjo.metadataCorrections[i].tvdbSeriesId = configIni.ReadString(conversionRecord + "-MetaCorrectionEntries", "TVDBSeriesId" + i.ToString(), "");
                        cjo.metadataCorrections[i].imdbSeriesId = configIni.ReadString(conversionRecord + "-MetaCorrectionEntries", "IMDBSeriesId" + i.ToString(), "");
                    }
                }

                mceBuddyConfSettings.conversionTasks.Add(cjo); // Add the Monitor Task object
            }
        }
Exemple #18
0
        /// <summary>
        /// Checks if the converted files need to be kept in sync with source files. It deletes the converted file if the source file is deleted.
        /// This function is thread safe
        /// </summary>
        /// <param name="useRecycleBin">True to use Recycle Bin while deleting</param>
        public void SyncConvertedFiles(bool useRecycleBin)
        {
            try
            {
                Monitor.Enter(_monitorSyncFiles); // Make this thread safe

                // Build a list of files to be monitored from the History file to sync source with converted files
                Ini historyIni = new Ini(GlobalDefs.HistoryFile);

                try
                {
                    List<string> convertedFiles = historyIni.GetSectionNames(); // Get list of all files (includes converted and source)

                    foreach (string foundFile in convertedFiles)
                    {
                        if (!_monitorSyncFiles.Contains(foundFile)) // We just keep building the list here and check if they are deleted later
                        {
                            _monitorSyncFiles.Add(foundFile); // add to the list
                            Log.AppLog.WriteEntry(this, "File " + foundFile + " is being monitored for syncing with output file", Log.LogEntryType.Debug);
                        }
                    }
                }
                catch (Exception e)
                {
                    Log.AppLog.WriteEntry(this, "Unable to get History section names", Log.LogEntryType.Error, true);
                    Log.AppLog.WriteEntry(this, "Error -> " + e.ToString(), Log.LogEntryType.Error, true);
                }

                // Check if the sources files are deleted and delete the converted files
                foreach (string sourceFile in new List<string>(_monitorSyncFiles)) // Create a new list to iterate through else it throws an exception when we modify it
                {
                    if (File.Exists(sourceFile))
                        continue; // Source file still exists, nothing to do

                    // Source file no longer, exists, it has been deleted
                    // Check if the file has been converted and if so then get the location of the converted file from the history file
                    int convCount = 0;
                    string convFile = "";
                    while ((convFile = historyIni.ReadString(sourceFile, "ConvertedTo" + convCount.ToString(System.Globalization.CultureInfo.InvariantCulture), "")) != "")
                    {
                        // Delete the EDL, SRT, XML, NFO etc files also along with the original file if present
                        foreach (string supportFileExt in GlobalDefs.supportFilesExt)
                        {
                            string extFile = Path.Combine(Path.GetDirectoryName(convFile), Path.GetFileNameWithoutExtension(convFile) + supportFileExt); // support file

                            if (File.Exists(extFile)) // don't overburden the log
                                Log.AppLog.WriteEntry(this, "Source File " + sourceFile + " deleted, deleting converted support file " + extFile, Log.LogEntryType.Debug);

                            FileIO.TryFileDelete(extFile, useRecycleBin); // Delete support file
                        }

                        if (File.Exists(convFile)) // don't overburden the log
                            Log.AppLog.WriteEntry(this, "Source File " + sourceFile + " deleted, deleting converted file " + convFile, Log.LogEntryType.Debug);

                        FileIO.TryFileDelete(convFile, useRecycleBin); // Try to delete the converted file since the source file is deleted
                        DeleteParentDirectoryChainIfEmpty(convFile); // Delete the parent directory chain if empty for the converted file

                        convCount++;
                    }
                }

                Monitor.Exit(_monitorSyncFiles);
            }
            catch (Exception e) // Incase the thread terminates, release the lock and exit gracefully
            {
                // Release the queue lock if taken
                try { Monitor.Exit(_monitorSyncFiles); } // Incase it's taken release it, if not taken it will throw an exception
                catch { }

                Log.AppLog.WriteEntry(this, "Sync Converted Files terminated", Log.LogEntryType.Warning, true);
                Log.AppLog.WriteEntry(this, "Error -> " + e.ToString(), Log.LogEntryType.Warning, true);
            }
        }
Exemple #19
0
        /// <summary>
        /// Check if a file is in the queue, if not add it to the queue.
        /// This function does NOT take a lock on the queue before modifying it. This function is not thread safe
        /// </summary>
        /// <param name="filePath">Filename to check and add</param>
        /// <param name="monitorTask">Name of the monitor task adding the file, blank if manually added</param>
        /// <param name="manualFile">True is it's added manually to the queue</param>
        private void CheckAndAddFile(string filePath, MonitorJobOptions monitorTask, bool manualFile)
        {
            Ini iniHistory = new Ini(GlobalDefs.HistoryFile);
            if (!QueueContains(filePath))
            {
                if (!Util.FileIO.FileLocked(filePath))
                {
                    string historyRec = iniHistory.ReadString(filePath, "Status", "");

                    // If it's an output file (you can skip output file reconversion by setting SkipReconversion in Conversion Task Settings)
                    if ((monitorTask != null) && monitorTask.monitorConvertedFiles)
                        if (Core.ConvertedFileStatuses.Any(x => x.Equals(historyRec)))
                            historyRec = ""; // This is a converted file and we have been asked to process converted files also

                    // Are we asked to reconvert recorded files
                    if ((monitorTask != null) && monitorTask.reMonitorRecordedFiles)
                        if (Core.SourceFileStatuses.Any(x => x.Equals(historyRec))) // Check if the status matches any of the source file status
                            historyRec = "";

                    if (historyRec == "" || manualFile) // Either the file has not been processed (Status is missing) or readded manually (Status is blank)
                    {
                        if (File.Exists(filePath))
                        {
                            if (manualFile)
                            {
                                AddJobs(filePath, monitorTask, true); //add manual jobs for conversion at the head of queue (after the last currently active job)
                            }
                            else
                            {
                                // Check to see if the age of the file is old enough
                                DateTime timeStamp = Util.FileIO.GetFileModifiedTime(filePath);
                                if (timeStamp.AddHours(_minimumAge) < DateTime.Now)
                                {
                                    AddJobs(filePath, monitorTask, false); // Added by a monitor task
                                }
                            }
                        }
                        else if (manualFile) //delete only if a manual entry is made
                        {
                            Log.AppLog.WriteEntry(this, "Unable to queue file for conversion - file not found " + filePath + "\r\n", Log.LogEntryType.Warning);
                            Ini iniManualQueue = new Ini(GlobalDefs.ManualQueueFile);
                            iniManualQueue.DeleteKey("ManualQueue", filePath);
                        }
                    }
                    else
                    {
                        if (!_processedFiles.Contains(filePath)) // Keep a track of processed file so we don't overload the mcebuddy.log file
                        {
                            _processedFiles.Add(filePath); // to the list of processed file so we don't end up doing it again
                            Log.AppLog.WriteEntry(this, "File " + filePath + " already converted with status " + historyRec + "\r\n", Log.LogEntryType.Debug);
                        }

                        // Manual file entry may have been readded multiple times, each time we log it and remove it from the ini file
                        if (manualFile) // Delete the manual entry
                        {
                            Log.AppLog.WriteEntry(this, "Manual file " + filePath + " already converted with status " + historyRec + "\r\n", Log.LogEntryType.Debug);
                            Ini iniManualQueue = new Ini(GlobalDefs.ManualQueueFile);
                            iniManualQueue.DeleteKey("ManualQueue", filePath);
                        }
                    }
                }
                else
                {
                    if (!_processedFiles.Contains(filePath)) // Keep a track of processed file so we don't overload the mcebuddy.log file
                    {
                        _processedFiles.Add(filePath); // to the list of processed file so we don't end up doing it again
                        Log.AppLog.WriteEntry(this, "Unable to queue file for conversion - file inaccessible/locked by another process " + filePath + "\r\n", Log.LogEntryType.Debug);
                    }

                    // Manual file entry may have been readded multiple times, each time we log it and remove it from the ini file
                    if (manualFile) // Delete the manual entry
                    {
                        Ini iniManualQueue = new Ini(GlobalDefs.ManualQueueFile);
                        iniManualQueue.DeleteKey("ManualQueue", filePath);
                        Log.AppLog.WriteEntry(this, "Unable to queue manual file for conversion - file inaccessible/locked by another process " + filePath + "\r\n", Log.LogEntryType.Debug);
                    }
                }
            }
        }
Exemple #20
0
        public List<string[]> GetProfilesSummary()
        {
            List<string[]> profileSummary = new List<string[]>();

            // Open and read all profiles
            Ini profileIni = new Ini(GlobalDefs.ProfileFile);
            foreach (string profile in profileIni.GetSectionNames())
                profileSummary.Add(new String[] { profile, profileIni.ReadString(profile, "Description", "") }); // 2 array string -> Profile Name, Description

            return profileSummary;
        }
Exemple #21
0
        private void WriteHistory(ConversionJob job)
        {
            Ini historyIni = new Ini(GlobalDefs.HistoryFile);
            GeneralOptions go = MCEBuddyConf.GlobalMCEConfig.GeneralOptions;

            bool sendEMail = go.sendEmail; // do we need to send an eMail after each job
            bool sendSuccess = go.eMailSettings.successEvent;
            bool sendFailed = go.eMailSettings.failedEvent;
            bool sendCancelled = go.eMailSettings.cancelledEvent;
            bool skipBody = go.eMailSettings.skipBody;
            string sendSuccessSubject = go.eMailSettings.successSubject;
            string sendFailedSubject = go.eMailSettings.failedSubject;
            string sendCancelledSubject = go.eMailSettings.cancelledSubject;

            string result = "Converted";
            if (job.Status.Error) result = "Error";
            if (job.Status.Cancelled) result = "Cancelled"; // Cancelled should be the last status to set because an error can be set if is cancelled

            int convCount = 0;
            while (historyIni.ReadString(job.OriginalFileName, result + "At" + convCount.ToString(System.Globalization.CultureInfo.InvariantCulture), "") != "")
                convCount++;
            historyIni.Write(job.OriginalFileName, result + "At" + convCount.ToString(System.Globalization.CultureInfo.InvariantCulture), DateTime.Now.ToString("s", System.Globalization.CultureInfo.InvariantCulture));

            switch (result)
            {
                case "Converted":
                    {
                        if (job.Status.SuccessfulSkipConversion)
                            Log.AppLog.WriteEntry(this, "Job for " + job.OriginalFileName + " Skipped ReConverting successfully using Conversion Task " + job.TaskName + " and Profile " + job.Profile, Log.LogEntryType.Information, true);
                        else
                            Log.AppLog.WriteEntry(this, "Job for " + job.OriginalFileName + " Converted successfully using Conversion Task " + job.TaskName + " and Profile " + job.Profile, Log.LogEntryType.Information, true);

                        historyIni.Write(job.OriginalFileName, "ConvertedTo" + convCount.ToString(System.Globalization.CultureInfo.InvariantCulture), job.ConvertedFile);
                        historyIni.Write(job.OriginalFileName, "ConvertedUsingProfile" + convCount.ToString(System.Globalization.CultureInfo.InvariantCulture), job.Profile);
                        historyIni.Write(job.OriginalFileName, "ConvertedUsingTask" + convCount.ToString(System.Globalization.CultureInfo.InvariantCulture), job.TaskName);
                        historyIni.Write(job.OriginalFileName, "ConvertedStart" + convCount.ToString(System.Globalization.CultureInfo.InvariantCulture), job.ConversionStartTime.ToString("s", System.Globalization.CultureInfo.InvariantCulture));

                        //Ensure converted files are not then re-converted during a scan
                        historyIni.Write(job.ConvertedFile, "Status", "OutputFromConversion"); // Status indicates destination file is output of an conversion, if the same file is added back for reconversion then it would log as converted
                        if (job.Status.SuccessfulSkipConversion)
                            historyIni.Write(job.ConvertedFile, "SkipConvertedToOutputAt" + convCount.ToString(System.Globalization.CultureInfo.InvariantCulture), job.ConversionEndTime.ToString("s", System.Globalization.CultureInfo.InvariantCulture));
                        else
                            historyIni.Write(job.ConvertedFile, "ConvertedToOutputAt" + convCount.ToString(System.Globalization.CultureInfo.InvariantCulture), job.ConversionEndTime.ToString("s", System.Globalization.CultureInfo.InvariantCulture));

                        // Send an eMail if required
                        if (sendEMail && sendSuccess)
                        {
                            string subject = Localise.GetPhrase("MCEBuddy successfully converted a video");
                            string message = Localise.GetPhrase("Source Video") + " -> " + job.OriginalFileName + "\r\n";
                            message += Localise.GetPhrase("Converted Video") + " -> " + job.ConvertedFile + "\r\n";
                            message += Localise.GetPhrase("Profile") + " -> " + job.Profile + "\r\n";
                            message += Localise.GetPhrase("Conversion Task") + " -> " + job.TaskName + "\r\n";
                            message += Localise.GetPhrase("Converted At") + " -> " + job.ConversionEndTime.ToString("s", System.Globalization.CultureInfo.InvariantCulture) + "\r\n";
                            message += Localise.GetPhrase("Time taken to convert") + " (hh:mm) -> " + (job.ConversionEndTime - job.ConversionStartTime).Hours.ToString("00") + ":" + (job.ConversionEndTime - job.ConversionStartTime).Minutes.ToString("00") + "\r\n";

                            // Check for custom subject and process
                            if (!String.IsNullOrWhiteSpace(sendSuccessSubject))
                                subject = UserCustomParams.CustomParamsReplace(sendSuccessSubject, job.WorkingPath, Path.GetDirectoryName(job.ConvertedFile), job.ConvertedFile, job.OriginalFileName, "", "", "", job.Profile, job.TaskName, job.MetaData, Log.AppLog);

                            eMailSendEngine.AddEmailToSendQueue(subject, (skipBody ? "" : message)); // Send the eMail through the email engine
                        }
                    }
                    break;

                case "Error":
                    {
                        Log.AppLog.WriteEntry(this, "Job for " + job.OriginalFileName + " has Error " + job.Status.ErrorMsg + " using Conversion Task " + job.TaskName + " and Profile " + job.Profile, Log.LogEntryType.Information, true);

                        historyIni.Write(job.OriginalFileName, "ErrorMessage" + convCount.ToString(System.Globalization.CultureInfo.InvariantCulture), job.Status.ErrorMsg);
                        historyIni.Write(job.OriginalFileName, "ErrorUsingProfile" + convCount.ToString(System.Globalization.CultureInfo.InvariantCulture), job.Profile);
                        historyIni.Write(job.OriginalFileName, "ErrorUsingTask" + convCount.ToString(System.Globalization.CultureInfo.InvariantCulture), job.TaskName);

                        // Send an eMail if required
                        if (sendEMail && sendFailed)
                        {
                            string subject = Localise.GetPhrase("MCEBuddy failed to converted a video");
                            string message = Localise.GetPhrase("Source Video") + " -> " + job.OriginalFileName + "\r\n";
                            message += Localise.GetPhrase("Profile") + " -> " + job.Profile + "\r\n";
                            message += Localise.GetPhrase("Conversion Task") + " -> " + job.TaskName + "\r\n";
                            message += Localise.GetPhrase("Error") + " -> " + job.Status.ErrorMsg + "\r\n";
                            message += Localise.GetPhrase("Failed At") + " -> " + job.ConversionEndTime.ToString("s", System.Globalization.CultureInfo.InvariantCulture) + "\r\n";

                            // Check for custom subject and process
                            if (!String.IsNullOrWhiteSpace(sendFailedSubject))
                                subject = UserCustomParams.CustomParamsReplace(sendFailedSubject, job.WorkingPath, "", job.ConvertedFile, job.OriginalFileName, "", "", "", job.Profile, job.TaskName, job.MetaData, Log.AppLog);

                            eMailSendEngine.AddEmailToSendQueue(subject, (skipBody ? "" : message)); // Send the eMail through the eMail engine
                        }
                    }
                    break;

                case "Cancelled":
                    {
                        Log.AppLog.WriteEntry(this, "Job for " + job.OriginalFileName + " Cancelled using Conversion Task " + job.TaskName + " and Profile " + job.Profile, Log.LogEntryType.Information, true);
                        historyIni.Write(job.OriginalFileName, "CancelledUsingProfile" + convCount.ToString(System.Globalization.CultureInfo.InvariantCulture), job.Profile);
                        historyIni.Write(job.OriginalFileName, "CancelledUsingTask" + convCount.ToString(System.Globalization.CultureInfo.InvariantCulture), job.TaskName);

                        // Send an eMail if required
                        if (sendEMail && sendCancelled)
                        {
                            string subject = Localise.GetPhrase("MCEBuddy cancelled a video conversion");
                            string message = Localise.GetPhrase("Source Video") + " -> " + job.OriginalFileName + "\r\n";
                            message += Localise.GetPhrase("Profile") + " -> " + job.Profile + "\r\n";
                            message += Localise.GetPhrase("Conversion Task") + " -> " + job.TaskName + "\r\n";
                            message += Localise.GetPhrase("Cancelled At") + " -> " + DateTime.Now.ToString("s", System.Globalization.CultureInfo.InvariantCulture) + "\r\n"; // It can be cancelled before it starts so end time is not a good indicator

                            // Check for custom subject and process
                            if (!String.IsNullOrWhiteSpace(sendCancelledSubject))
                                subject = UserCustomParams.CustomParamsReplace(sendCancelledSubject, job.WorkingPath, "", job.ConvertedFile, job.OriginalFileName, "", "", "", job.Profile, job.TaskName, job.MetaData, Log.AppLog);

                            eMailSendEngine.AddEmailToSendQueue(subject, (skipBody ? "" : message)); // Send the eMail through the eMail engine
                        }
                    }
                    break;

                default:
                    Log.AppLog.WriteEntry(this, "INVALID STATE (" + result + ") -> Job for " + job.OriginalFileName + " Converted using Conversion Task " + job.TaskName + " and Profile " + job.Profile, Log.LogEntryType.Error, true);

                    break;
            }

            if ( _queueManager.JobCount(job.OriginalFileName) <= 1)
            {
                // This is the last job processing this file, so write the status to the history file STATUS
                historyIni.Write(job.OriginalFileName, "Status", result); // Source file status
            }
        }
Exemple #22
0
        private void WriteConversionSettings(Ini configIni)
        {
            if (configIni == null)
                return;

            // First read and delete all Conversion tasks - start with a clean slate (incase there were previous delete conversion tasks without writing)
            string[] conversionRecords = configIni.ReadString("Engine", "Tasks", "").Split(',');
            foreach (string conversionRecord in conversionRecords)
            {
                if (String.IsNullOrEmpty(conversionRecord))
                    continue;

                configIni.DeleteSection(conversionRecord);
            }

            // Write the Converstion Task Settings
            foreach (ConversionJobOptions conversionTask in mceBuddyConfSettings.conversionTasks)
            {
                string section = conversionTask.taskName;

                configIni.Write(section, "Profile", conversionTask.profile);
                configIni.Write(section, "DestinationPath", conversionTask.destinationPath);
                configIni.Write(section, "WorkingPath", conversionTask.workingPath);
                configIni.Write(section, "FallbackDestination", conversionTask.fallbackToSourcePath);
                configIni.Write(section, "CheckReprocessingHistory", conversionTask.checkReprocessingHistory);
                configIni.Write(section, "AddToiTunesLibrary", conversionTask.addToiTunes);
                configIni.Write(section, "AddToWMPLibrary", conversionTask.addToWMP);
                configIni.Write(section, "AutoIncrementFilename", conversionTask.autoIncrementFilename);
                configIni.Write(section, "SkipReprocessing", conversionTask.skipReprocessing);
                configIni.Write(section, "MaxWidth", conversionTask.maxWidth);
                configIni.Write(section, "FPS", conversionTask.FPS);
                configIni.Write(section, "VolumeMultiplier", conversionTask.volumeMultiplier.ToString(CultureInfo.InvariantCulture));
                configIni.Write(section, "QualityMultiplier", conversionTask.qualityMultiplier.ToString(CultureInfo.InvariantCulture));
                configIni.Write(section, "RenameBySeries", conversionTask.renameBySeries);
                configIni.Write(section, "AltRenameBySeries", conversionTask.altRenameBySeries);
                configIni.Write(section, "CustomRenameBySeries", conversionTask.customRenameBySeries);
                configIni.Write(section, "RenameOnly", conversionTask.renameOnly);
                configIni.Write(section, "DownloadSeriesDetails", conversionTask.downloadSeriesDetails);
                configIni.Write(section, "DownloadBanner", conversionTask.downloadBanner); 
                configIni.Write(section, "FileSelection", conversionTask.fileSelection);
                configIni.Write(section, "MetaSelection", conversionTask.metaShowSelection);
                configIni.Write(section, "MetaChannelSelection", conversionTask.metaNetworkSelection);
                configIni.Write(section, "MonitorTaskNames", (conversionTask.monitorTaskNames == null ? "" : String.Join(",", conversionTask.monitorTaskNames)));
                configIni.Write(section, "DRC", conversionTask.drc);
                configIni.Write(section, "AudioLanguage", conversionTask.audioLanguage);
                configIni.Write(section, "AudioOffset", conversionTask.audioOffset.ToString(CultureInfo.InvariantCulture));
                configIni.Write(section, "InsertQueueTop", conversionTask.insertQueueTop);
                configIni.Write(section, "ExtractXML", conversionTask.extractXML);
                configIni.Write(section, "WriteMetadata", conversionTask.writeMetadata);
                configIni.Write(section, "AutoDeInterlace", conversionTask.autoDeInterlace);
                configIni.Write(section, "PreferHardwareEncoding", conversionTask.preferHardwareEncoding);
                configIni.Write(section, "StereoAudio", conversionTask.stereoAudio);
                configIni.Write(section, "EncoderSelectBestAudioTrack", conversionTask.encoderSelectBestAudioTrack);
                configIni.Write(section, "DisableCropping", conversionTask.disableCropping);
                configIni.Write(section, "StartTrim", conversionTask.startTrim);
                configIni.Write(section, "EndTrim", conversionTask.endTrim);
                configIni.Write(section, "ExtractCC", conversionTask.extractCC);
                configIni.Write(section, "CCOffset", conversionTask.ccOffset.ToString(CultureInfo.InvariantCulture));
                configIni.Write(section, "EmbedSubtitlesChapters", conversionTask.embedSubtitlesChapters);
                configIni.Write(section, "PrioritizeOriginalBroadcastDateMatch", conversionTask.prioritizeOriginalBroadcastDateMatch);
                configIni.Write(section, "TaskCommercialSkipCut", conversionTask.commercialSkipCut);
                configIni.Write(section, "SkipCopyBackup", conversionTask.skipCopyBackup);
                configIni.Write(section, "SkipRemux", conversionTask.skipRemuxing);
                configIni.Write(section, "IgnoreCopyProtection", conversionTask.ignoreCopyProtection);
                configIni.Write(section, "TiVOMAKKey", conversionTask.tivoMAKKey);
                configIni.Write(section, "Enabled", conversionTask.enabled);
                configIni.Write(section, "ForceShowType", conversionTask.forceShowType.ToString());
                configIni.Write(section, "MetaShowTypeSelection", conversionTask.metaShowTypeSelection.ToString());
                configIni.Write(section, "MetaDRMTypeSelection", conversionTask.metaDRMSelection.ToString());
                configIni.Write(section, "CommercialRemoval", conversionTask.commercialRemoval.ToString());
                configIni.Write(section, "ComskipINI", conversionTask.comskipIni);
                configIni.Write(section, "DomainName", conversionTask.domainName);
                configIni.Write(section, "UserName", conversionTask.userName);
                if (!String.IsNullOrEmpty(conversionTask.password))
                    configIni.Write(section, "Password", Crypto.Encrypt(conversionTask.password)); // Password is written as encrypted

                // First wipe the MetaCorrectionEntries section clean, to remove old/redundant data and then start afresh since we don't know how many entries may exist
                configIni.DeleteSection(section + "-MetaCorrectionEntries");

                if (conversionTask.metadataCorrections == null)
                    configIni.Write(section, "MetaCorrectionsCount", 0);
                else
                {
                    configIni.Write(section, "MetaCorrectionsCount", conversionTask.metadataCorrections.Length);

                    for (int i = 0; i < conversionTask.metadataCorrections.Length; i++) // the Enteries are kept in their own section
                    {
                        configIni.Write(section + "-MetaCorrectionEntries", "OriginalTitle" + i.ToString(), conversionTask.metadataCorrections[i].originalTitle);
                        configIni.Write(section + "-MetaCorrectionEntries", "CorrectedTitle" + i.ToString(), conversionTask.metadataCorrections[i].correctedTitle);
                        configIni.Write(section + "-MetaCorrectionEntries", "TVDBSeriesId" + i.ToString(), conversionTask.metadataCorrections[i].tvdbSeriesId);
                        configIni.Write(section + "-MetaCorrectionEntries", "IMDBSeriesId" + i.ToString(), conversionTask.metadataCorrections[i].imdbSeriesId);
                    }
                }
            }

            WriteConversionTasksList(configIni); // this list goes in the Engine section
        }
Exemple #23
0
        /// <summary>
        /// Returns the extension of the RenameExt command for the profile used
        /// </summary>
        /// <param name="profile">Name of the profile to check</param>
        /// <returns>Extension as indicated by the profile or an empty string if none exists</returns>
        private static string GetRenameFileExtension(string profile)
        {
            Ini profileIni = new Ini(GlobalDefs.ProfileFile);
            string renameExt = profileIni.ReadString(profile, "RenameExt", "");

            if (String.IsNullOrEmpty(renameExt)) return "";
            
            if (renameExt[0] != '.') renameExt = "." + renameExt;  // Just in case someone does something dumb like forget the leading "."

            return renameExt; // return the extension
        }
Exemple #24
0
        private void WriteMonitorSettings(Ini configIni)
        {
            if (configIni == null)
                return;

            // First read and delete all Monitor tasks - start with a clean slate (incase there were previous delete monitor tasks without writing)
            string[] searchRecords = configIni.ReadString("Engine", "SearchRecords", "").Split(',');
            foreach (string searchRecord in searchRecords)
            {
                if (String.IsNullOrEmpty(searchRecord))
                    continue;

                configIni.DeleteSection(searchRecord);
            }

            // Write the Monitor Tasks Settings
            foreach (MonitorJobOptions monitorTask in mceBuddyConfSettings.monitorTasks)
            {
                string section = monitorTask.taskName;

                configIni.Write(section, "SearchPath", monitorTask.searchPath);
                monitorTask.searchPattern = monitorTask.searchPattern.Replace(GlobalDefs.DEFAULT_VIDEO_STRING, GlobalDefs.DEFAULT_VIDEO_FILE_TYPES);
                configIni.Write(section, "SearchPattern", monitorTask.searchPattern);
                configIni.Write(section, "MonitorSubdirectories", monitorTask.monitorSubdirectories);
                configIni.Write(section, "MonitorConvertedFiles", monitorTask.monitorConvertedFiles);
                configIni.Write(section, "ReMonitorRecordedFiles", monitorTask.reMonitorRecordedFiles);

                configIni.Write(section, "DomainName", monitorTask.domainName);
                configIni.Write(section, "UserName", monitorTask.userName);
                if (!String.IsNullOrEmpty(monitorTask.password))
                    configIni.Write(section, "Password", Crypto.Encrypt(monitorTask.password)); // Password is written as encrypted
            }

            WriteMonitorTasksList(configIni); // this list goes in the Engine section
        }
        /// <summary>
        /// Remux the DVRMS file directly to TSMPEG using a special FFMPEG
        /// </summary>
        /// <returns>Success or Failure</returns>
        private bool RemuxDVRMSFFmpeg()
        {
            string profile = "DVRMSRemux"; // Reading the remux parameters from the file
            string ffmpegParams = "";
            Ini configProfileIni = new Ini(GlobalDefs.ConfigFile);

            // Threads 0 causes an error in some streams, avoid
            _jobLog.WriteEntry(this, Localise.GetPhrase("DVRMS file, using special FFMPEG to remux"), Log.LogEntryType.Information);

            // First try with regular FFMPEG and GenPTs, since the DVRMS tends to created corrupted files
            _jobStatus.CurrentAction = Localise.GetPhrase("Fast Remuxing");

            _jobLog.WriteEntry(this, Localise.GetPhrase("Reading DVRMS Remux parameters"), Log.LogEntryType.Information);

            // First try to copy all the streams directly (read parmeters for copy profile)
            string baseRemuxParams = configProfileIni.ReadString(profile, "Remux", "");

            if (String.IsNullOrWhiteSpace(baseRemuxParams)) // Have we used up all the CopyRemux profiles, then we're done here - try something else
            {
                _jobLog.WriteEntry(Localise.GetPhrase("DVRMS Remuxing disabled in config file, no parameters"), Log.LogEntryType.Error);
                Util.FileIO.TryFileDelete(RemuxedFile);
                return false;
            }

            // Check for input file placeholders and substitute
            if (baseRemuxParams.Contains("-i <source>")) // Check if we have a input file placeholder (useful if we need to put commands before -i)
            {
                baseRemuxParams = baseRemuxParams.Replace("-i <source>", "-i " + Util.FilePaths.FixSpaces(_RecordingFile) + " ");
                ffmpegParams = "-fflags +genpts -y " + baseRemuxParams + " " + Util.FilePaths.FixSpaces(RemuxedFile);
            }
            else
                ffmpegParams = "-fflags +genpts -y -i " + Util.FilePaths.FixSpaces(_RecordingFile) + " " + baseRemuxParams + " " + Util.FilePaths.FixSpaces(RemuxedFile); // DO NOT USE -async 1 with COPY

            FFmpeg ffmpeg;
            FFmpeg.FFMpegExecuteAndHandleErrors(ffmpegParams, _jobStatus, _jobLog, Util.FilePaths.FixSpaces(RemuxedFile), false, out ffmpeg); // Run and handle errors, don't need to check output file here
            if (!ffmpeg.Success || !RemuxedFileOK()) //check of file is created, outputhandler reports success (Percentage not requires since Success is more accurate)
            {
                // Use Special build of DVRMS FFMPEG to handle now
                _jobLog.WriteEntry(Localise.GetPhrase("DVRMS ReMux using FFMPEG GenPTS failed at") + " " + _jobStatus.PercentageComplete.ToString(CultureInfo.InvariantCulture) + "%. Retrying using special DVRMS FFMpeg", Log.LogEntryType.Warning);

                // DVR-MS supports only one audio stream
                ffmpegParams = ffmpegParams.Replace("-fflags +genpts", ""); // don't need genpts for special build dvrms ffmpeg

                ffmpeg = new FFmpeg(ffmpegParams, true, _jobStatus, _jobLog); // use SPECIAL BUILD DVRMS-FFMPEG, so we can't use FFMpegExecuteAndHandleErrors
                ffmpeg.Run();

                if (!ffmpeg.Success || !RemuxedFileOK()) //check of file is created, outputhandler reports success (Percentage not requires since Success is more accurate)
                {
                    _jobLog.WriteEntry(Localise.GetPhrase("DVRMS ReMux using FFMPEG failed at") + " " + _jobStatus.PercentageComplete.ToString(CultureInfo.InvariantCulture) + "%", Log.LogEntryType.Error);
                    Util.FileIO.TryFileDelete(RemuxedFile);
                    return false;
                }
            }

            // Since we are successful, keep track of how many seconds we skipped while remuxing the file
            FFMpegMEncoderParams checkParams = new FFMpegMEncoderParams(baseRemuxParams);
            float.TryParse(checkParams.ParameterValue("-ss"), System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out skipInitialSeconds);

            return true;
        }
Exemple #26
0
        private string _renameConvertedFileWithOriginalName = ""; // Keep track incase of filename conflict

        protected ConvertBase(ConversionJobOptions conversionOptions, string tool, VideoInfo videoFile, JobStatus jobStatus, Log jobLog, Scanner commercialScan)
            : base (true)
        {
            //Setup log and status
            _jobStatus = jobStatus;
            _jobLog = jobLog;

            //Set the destination paths
            _workingPath = conversionOptions.workingPath;
            Util.FilePaths.CreateDir(_workingPath);

            // Check first up to see if the source video uses an unsupported combination for this profile
            // Container, Video Codec, Audio Codec and whether it was originally a Media Center recording or not
            _videoFile = videoFile;
            _commercialScan = commercialScan;
            if (CheckUnsupported(conversionOptions.profile, tool)) return;

            // Set the input params and get the standard settings
            _maxWidth = conversionOptions.maxWidth;
            _userQuality = conversionOptions.qualityMultiplier;
            _volume = conversionOptions.volumeMultiplier;
            _drc = conversionOptions.drc;
            _startTrim = conversionOptions.startTrim;
            _endTrim = conversionOptions.endTrim;
            _encoderChooseBestAudioTrack = conversionOptions.encoderSelectBestAudioTrack;
            _fps = conversionOptions.FPS;
            _preferHardwareEncoding = conversionOptions.preferHardwareEncoding;

            Ini ini = new Ini(GlobalDefs.ProfileFile);

            // Profile override parameters - if default (i.e. does not exist then use conversion options else use profile parameters)
            if (ini.ReadString(conversionOptions.profile, "2ChannelAudio", "default") == "default")
                _2ChannelAudio = conversionOptions.stereoAudio;
            else
                _2ChannelAudio = ini.ReadBoolean(conversionOptions.profile, "2ChannelAudio", false); // Fix output to 2 channels (from profile)
            
            if (ini.ReadString(conversionOptions.profile, "SkipCropping", "default") == "default")
                _skipCropping = conversionOptions.disableCropping;
            else
                _skipCropping = ini.ReadBoolean(conversionOptions.profile, "SkipCropping", false); // Cropping can be forced in the profile
            
            if (ini.ReadString(conversionOptions.profile, "AutoDeinterlace", "default") == "default")
                _autoDeInterlacing = conversionOptions.autoDeInterlace;
            else
                _autoDeInterlacing = ini.ReadBoolean(conversionOptions.profile, "AutoDeinterlace", false);

            if (conversionOptions.renameOnly)
                _commercialSkipCut = true; //no cutting if we are renaming only
            else if (ini.ReadString(conversionOptions.profile, "CommercialSkipCut", "default") == "default")
                _commercialSkipCut = conversionOptions.commercialSkipCut;
            else _commercialSkipCut = ini.ReadBoolean(conversionOptions.profile, "CommercialSkipCut", false);

            // Profile only parameters
            _fixedResolution = ini.ReadBoolean(conversionOptions.profile, "FixedResolution", false);
            _2Pass = ini.ReadBoolean(conversionOptions.profile, "2pass", false);
            _generalParams = ini.ReadString(conversionOptions.profile, tool + "-general", "");
            _videoParams = ini.ReadString(conversionOptions.profile, tool + "-video", "");
            _audioParams = ini.ReadString(conversionOptions.profile, tool + "-audio", "");
            _extension = _videoFile.Extension = ini.ReadString(conversionOptions.profile, tool + "-ext", "").ToLower().Trim();
            if (string.IsNullOrWhiteSpace(_extension)) // Special case copy converter if there is no specified extension, it will be using the source file extension
                _extension = FilePaths.CleanExt(SourceVideo);
            _remuxTo = _videoFile.RemuxTo = ini.ReadString(conversionOptions.profile, tool + "-remuxto", "").ToLower().Trim();
            _audioDelay = ini.ReadString(conversionOptions.profile, tool + "-audiodelay", "skip").ToLower().Trim();

            if (_audioDelay == "auto") // Use the audio delay specified in the file
                _toolAudioDelay = videoFile.AudioDelay;
            else if (_audioDelay != "skip")
                double.TryParse(_audioDelay, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out _toolAudioDelay);

            if (conversionOptions.audioOffset != 0) // Conversion options Audio Delay takes priority over profile Audio Delay
                _toolAudioDelay = conversionOptions.audioOffset; 

            // Audio select the AC3 audio option if the source video has AC3)
            if (((videoFile.AudioCodec == "ac-3") || (videoFile.AudioCodec == "ac3") || (videoFile.AudioCodec != "e-ac-3") || (videoFile.AudioCodec != "eac3")) && (ini.ReadString(conversionOptions.profile, tool + "-audioac3", "") != ""))
                _audioParams = ini.ReadString(conversionOptions.profile, tool + "-audioac3", _audioParams);

            // E-AC3 test option if the source video has E-AC3 - Not required as mencoder can handle eac3 audio
            /*
            if (videoFile.AudioCodec == "e-ac-3" || _videoFile.AudioCodec != "eac3")
            {
                _audioParams = ini.ReadString(conversionOptions.profile, tool + "-audioeac3", _audioParams);
                if ((_audioParams == "") && (tool == "mencoder"))
                    _audioParams = "-noaudio ";
            }*/

            // Important to use temp name while converting - sometimes the sources files are copied to the working directory and the converted files conflict with teh original filename, compensate. E.g. TS file input, TS file output with Copy converter
            _convertedFile = Path.Combine(_workingPath, Path.GetFileNameWithoutExtension(SourceVideo) + "-converted" + _extension);
            _renameConvertedFileWithOriginalName = Path.Combine(_workingPath, Path.GetFileNameWithoutExtension(SourceVideo) + _extension);
        }
Exemple #27
0
        private void facebookBtn_Click(object sender, EventArgs e)
        {
            Ini configIni = new Ini(GlobalDefs.TempSettingsFile);
            string facebookLink = configIni.ReadString("Engine", "FacebookLink", "");
            if (String.IsNullOrWhiteSpace(facebookLink))
                facebookLink = Crypto.Decrypt(GlobalDefs.MCEBUDDY_FACEBOOK_PAGE); // backup

            OpenLink(facebookLink);
        }