/// <summary>
        /// Updates the status message on configures social networks.
        /// </summary>
        /// <param name="file">The identified file.</param>
        public static void PostToSocial(ShowFile file)
        {
            if (Settings.Get("Post only recent", true) && (DateTime.Now - file.Airdate).TotalDays > 21)
            {
                Log.Debug("Not posting " + file + " to social networks because it is not a recent episode.");
                return;
            }

            var listed = Settings.Get("Post restrictions list", new List <int>())
                         .Contains(Database.TVShows.Values.First(x => x.Title == file.Show).ID);

            switch (Settings.Get("Post restrictions list type", "black"))
            {
            case "black":
                if (listed)
                {
                    Log.Debug("Not posting " + file + " to social networks because the show is blacklisted.");
                    return;
                }
                break;

            case "white":
                if (!listed)
                {
                    Log.Debug("Not posting " + file + " to social networks because the show is not whitelisted.");
                    return;
                }
                break;
            }

            foreach (var engine in Extensibility.GetNewInstances <SocialEngine>())
            {
                if (!Settings.Get <bool>("Post to " + engine.Name))
                {
                    continue;
                }

                if (engine is OAuthEngine)
                {
                    var tokens = Settings.Get <List <string> >(engine.Name + " OAuth");

                    if (tokens != null && tokens.Count != 0)
                    {
                        ((OAuthEngine)engine).Tokens = tokens;
                    }
                    else
                    {
                        Log.Debug("Not posting " + file + " to " + engine.Name + " because it required OAuth tokens are missing.");
                        continue;
                    }
                }


                var format = Settings.Get(engine.Name + " Status Format", engine.DefaultStatusFormat);
                if (string.IsNullOrWhiteSpace(format))
                {
                    return;
                }

                try
                {
                    engine.PostMessage(FileNames.Parser.FormatFileName(format, file));
                    Log.Debug("Successfully posted " + file + " to " + engine.Name + ".");
                }
                catch (Exception ex)
                {
                    Log.Warn("Unhandled exception while posting " + file + " to " + engine.Name + ".", ex);
                }
            }
        }
        /// <summary>
        /// Checks for open files on the specified processes and marks them if recognized.
        /// </summary>
        public static void CheckOpenFiles()
        {
            if (!Settings.Get("Monitor Processes", true))
            {
                return;
            }

            Log.Debug("Checking for open files...");

            var alt    = Settings.Get("Process Monitoring Method", "Internal") == "WindowTitle";
            var netmon = Settings.Get <bool>("Monitor Network Shares");

            if (!alt && !Utils.IsAdmin)
            {
                Log.Info("You are not running with administrator rights but requested file handle monitoring.");
            }

            var procs = new List <string>();

            procs.AddRange(Settings.Get <List <string> >("Processes to Monitor"));

            try
            {
                procs.AddRange(Utils.GetDefaultVideoPlayers().Select(Path.GetFileName));
            }
            catch (Exception ex)
            {
                Log.Warn("Error while getting list of default video players.", ex);
            }

            if (Log.IsTraceEnabled)
            {
                Log.Trace("Requested processes:", procs);
            }

            if (!procs.Any() && !netmon && !UPnP.IsRunning)
            {
                Log.Debug("No processes specified to monitor and network share monitoring is disabled.");
                return;
            }

            var pids = GetPIDs(procs).Distinct().ToList();

            if (Log.IsTraceEnabled)
            {
                Log.Trace("Running PIDs:", pids);
            }

            if (!pids.Any() && !netmon && !UPnP.IsRunning)
            {
                Log.Debug("Unable to get at least one PID for the specified processes and network share monitoring is disabled.");
                return;
            }

            var files  = new List <FileInfo>();
            var titles = new List <string>();

            if (pids.Any())
            {
                if (!alt)
                {
                    using (var mre = new ManualResetEvent(false))
                    {
                        var thd = new Thread(() =>
                        {
                            try
                            {
                                files.AddRange(GetHandleList(pids));
                            }
                            finally
                            {
                                mre.Set();
                            }
                        })
                        {
                            IsBackground = true
                        };

                        thd.Start();

                        if (!mre.WaitOne(TimeSpan.FromMinutes(3)))
                        {
                            Log.Error("Process monitoring method timed out after 3 minutes. Please consider switching implementations from the Settings menu.");

                            try
                            {
                                thd.Interrupt();
                                thd.Abort();
                            } catch { }
                        }
                    }

                    if (files.Count != 0)
                    {
                        Log.Debug(Utils.FormatNumber(files.Count, "file handle", true) + " open for the PID" + (pids.Count != 1 ? "s" : string.Empty) + ": " + string.Join(", ", pids).TrimEnd(", ".ToCharArray()) + ".");
                    }
                }
                else
                {
                    titles.AddRange(GetWindownTitles(pids));

                    if (titles.Count != 0)
                    {
                        Log.Debug(Utils.FormatNumber(files.Count, "window title", true) + " found for the PID" + (pids.Count != 1 ? "s" : string.Empty) + ": " + string.Join(", ", pids).TrimEnd(", ".ToCharArray()) + ".");
                    }

                    if (Log.IsTraceEnabled)
                    {
                        Log.Trace("Window titles:", titles);
                    }
                }
            }

            if (Signature.IsActivated && UPnP.IsRunning)
            {
                try
                {
                    var cnt = files.Count;

                    files.AddRange(UPnP.GetActiveTransfers());

                    if (files.Count != cnt)
                    {
                        Log.Debug(Utils.FormatNumber(files.Count - cnt, "file handle", true) + " open through the UPnP/DLNA server.");
                    }
                }
                catch (Exception ex)
                {
                    Log.Warn("Cannot get active transfer list from the UPnP/DLNA server due to an exception.", ex);
                }
            }

            if (Signature.IsActivated && netmon)
            {
                try
                {
                    var cnt = files.Count;

                    files.AddRange(NetworkShares.GetActiveTransfers());

                    if (files.Count != cnt)
                    {
                        Log.Debug(Utils.FormatNumber(files.Count - cnt, "file handle", true) + " open through Windows file sharing.");
                    }
                }
                catch (Exception ex)
                {
                    Log.Warn("Cannot get active network share transfer list from Windows due to an exception.", ex);
                }
            }

            if (Log.IsTraceEnabled)
            {
                Log.Trace("Open file handles:", files.Select(fi => fi.FullName));
            }

            if (files.Count == 0 && titles.Count == 0)
            {
                Log.Debug("No " + (alt ? "window titles" : "file handles open") + " for the specified processes (" + (pids.Count == 0 ? "none running" : "PID" + (pids.Count != 1 ? "s" : string.Empty) + ": " + string.Join(", ", pids).TrimEnd(", ".ToCharArray())) + ") and services.");
                return;
            }

            foreach (var show in Database.TVShows)
            {
                var titleRegex   = Parser.GenerateTitleRegex(show.Value.Title, show.Value);
                var releaseExpr  = string.Empty;
                var releaseRegex = show.Value.Data.TryGetValue("regex", out releaseExpr) && !string.IsNullOrWhiteSpace(releaseExpr) ? new Regex(releaseExpr) : null;

                foreach (var file in files)
                {
                    if (Parser.IsMatch(file.DirectoryName + @"\" + file.Name, titleRegex) || (releaseRegex != null && Parser.IsMatch(file.DirectoryName + @"\" + file.Name, releaseRegex)))
                    {
                        var pf = FileNames.Parser.ParseFile(file.Name, file.DirectoryName.Split(Path.DirectorySeparatorChar), false);
                        if (pf.Success && show.Value.Title == pf.Show)
                        {
                            Log.Debug("Identified open file " + file.Name + " as " + pf + ".");

                            if (!OpenFiles.Contains(file.ToString()))
                            {
                                // add to open files list
                                // 5 minutes later we'll check again, and if it's still open we'll mark it as seen
                                // the reason for this is that an episode will be marked as seen only if you're watching it for more than 10 minutes (5 minute checks twice)

                                OpenFiles.Add(file.ToString());
                            }
                            else
                            {
                                MarkAsSeen(show.Value.ID, pf);
                            }
                        }
                    }
                }

                foreach (var title in titles)
                {
                    if (Parser.IsMatch(title, titleRegex, null, false) || (releaseRegex != null && Parser.IsMatch(title, releaseRegex, null, false)))
                    {
                        var pf = FileNames.Parser.ParseFile(title, null, false);
                        if (pf.Success && show.Value.Title == pf.Show)
                        {
                            Log.Debug("Identified window title " + title + " as " + pf + ".");

                            if (!OpenFiles.Contains(pf.ToString()))
                            {
                                OpenFiles.Add(pf.ToString());
                            }
                            else
                            {
                                MarkAsSeen(show.Value.ID, pf);
                            }
                        }
                    }
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Adds the specified TV show to the database.
        /// </summary>
        /// <param name="sid">The show ID to add to the database.</param>
        /// <param name="callback">The status callback.</param>
        /// <returns>Added TV show or <c>null</c>.</returns>
        public static TVShow Add(ShowID sid, Action <int, string> callback = null)
        {
            Log.Info("Adding " + sid.Guide.Name + "/" + sid.ID + "...");

            var st = DateTime.Now;

            if (callback != null)
            {
                callback(0, "Downloading guide from " + sid.Guide.Name + "...");
            }

            TVShow tv;

            try
            {
                tv = sid.Guide.GetData(sid.ID, sid.Language);

                if (tv.Episodes.Count == 0)
                {
                    Log.Error("Downloaded guide for " + tv.Title + " (" + sid.Guide.Name + "/" + sid.ID + ") has no episodes.");

                    if (callback != null)
                    {
                        callback(-1, "No episodes listed for this show on " + sid.Guide.Name + ".");
                    }

                    return(null);
                }
            }
            catch (Exception ex)
            {
                if (ex is ThreadAbortException)
                {
                    Log.Warn("Thread aborted while downloading data from guide for " + sid.Guide.Name + "/" + sid.ID + ".", ex);
                    return(null);
                }

                Log.Error("Error while downloading data from guide for " + sid.Guide.Name + "/" + sid.ID + ".", ex);

                if (callback != null)
                {
                    callback(-1, "Error while downloading data: " + ex.Message);
                }

                return(null);
            }

            if (TVShows.Values.FirstOrDefault(x => x.Title == tv.Title) != null)
            {
                Log.Error("Duplicate entry detected for " + tv.Title + " (" + sid.Guide.Name + "/" + sid.ID + ").");

                if (callback != null)
                {
                    callback(-1, tv.Title + " is already in your database.");
                }

                return(null);
            }

            foreach (var tvs in TVShows.Values)
            {
                tvs.RowID++;
                tvs.SaveData();
            }

            tv.RowID       = 0;
            tv.ID          = TVShows.Values.Count > 0 ? TVShows.Values.Max(x => x.ID) + 1 : 1;
            tv.Data        = new Dictionary <string, string>();
            tv.Directory   = Path.Combine(DataPath, Utils.CreateSlug(tv.Title, false));
            tv.EpisodeByID = new Dictionary <int, Episode>();

            if (Directory.Exists(tv.Directory))
            {
                tv.Directory += "-" + tv.Source.ToLower();
            }

            if (Directory.Exists(tv.Directory))
            {
                tv.Directory += "-" + Utils.Rand.Next();
            }

            try
            {
                Directory.CreateDirectory(tv.Directory);
            }
            catch (Exception ex)
            {
                Log.Error("Error while creating directory db\\" + Path.GetFileName(tv.Directory) + " for " + tv.Title + " (" + sid.Guide.Name + "/" + sid.ID + ").", ex);

                if (callback != null)
                {
                    callback(-1, "Error while creating database.");
                }

                return(null);
            }

            foreach (var ep in tv.Episodes)
            {
                ep.Show = tv;
                ep.ID   = ep.Number + (ep.Season * 1000) + (tv.ID * 1000 * 1000);

                tv.EpisodeByID[ep.Number + (ep.Season * 1000)] = ep;

                if (!string.IsNullOrWhiteSpace(tv.AirTime) && ep.Airdate != Utils.UnixEpoch)
                {
                    try { ep.Airdate = DateTime.Parse(ep.Airdate.ToString("yyyy-MM-dd ") + tv.AirTime).ToLocalTimeZone(tv.TimeZone); } catch { }
                }
            }

            try
            {
                tv.Save();
                tv.SaveTracking();
            }
            catch (Exception ex)
            {
                Log.Error("Error while saving database to db\\" + Path.GetFileName(tv.Directory) + " for " + tv.Title + " (" + sid.Guide.Name + "/" + sid.ID + ").", ex);

                if (callback != null)
                {
                    callback(-1, "Error while saving to database.");
                }

                return(null);
            }

            TVShows[tv.ID] = tv;
            DataChange     = DateTime.Now;

            if (tv.Language == "en")
            {
                Updater.UpdateRemoteCache(tv);
            }

            if (callback != null)
            {
                callback(1, "Show added successfully.");
            }

            Log.Debug("Successfully added " + tv.Title + " (" + sid.Guide.Name + "/" + sid.ID + ") in " + (DateTime.Now - st).TotalSeconds + "s.");

            return(tv);
        }
Пример #4
0
        /// <summary>
        /// Handles the Elapsed event of the ParserTimer control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Timers.ElapsedEventArgs"/> instance containing the event data.</param>
        private void ParserTimerElapsed(object sender, ElapsedEventArgs e)
        {
            if (_parsing)
            {
                return;
            }

            _parsing = true;

            var files = FilesListViewItemCollection.Where(f => !f.Processed).ToList();

            if (files.Count == 0)
            {
                goto end;
            }

            Log.Info("Starting to identify files in renamer queue...");
            var st = DateTime.Now;

            foreach (var file in files)
            {
                SetStatus("Identifying " + file.Information.Name + "...", true);
                Log.Debug("Identifying file " + file.Information.Name + "...");

                try
                {
                    file.Information = FileNames.Parser.ParseFile(file.Information.Name, Path.GetDirectoryName(file.Location).Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries));
                    file.Checked     = file.Recognized = file.Enabled = file.Information.Success;
                    file.Processed   = true;

                    if (file.Information.Success)
                    {
                        file.ShowStatusImage = "Collapsed";
                        file.ShowCheckBox    = "Visible";

                        Log.Debug("Identified file " + file.Information.Name + " as " + file.Information + ".");
                    }
                    else
                    {
                        file.StatusImage = "/RSTVShowTracker;component/Images/exclamation-red.png";

                        Log.Debug("Unable to identify file " + file.Information.Name + ": " + file.Information + ".");
                    }
                }
                catch (Exception ex)
                {
                    file.Information.ParseError = ShowFile.FailureReasons.ExceptionOccurred;
                    file.Checked     = file.Recognized = file.Enabled = false;
                    file.Processed   = true;
                    file.StatusImage = "/RSTVShowTracker;component/Images/exclamation-red.png";

                    Log.Warn("Exception while identifying file " + file.Information.Name + ".", ex);
                }

                file.RefreshEnabled();
            }

            Log.Info("File identification queue finished in " + (DateTime.Now - st).TotalSeconds + "s.");

            SetStatus();

end:
            _parsing = false;
        }
Пример #5
0
        /// <summary>
        /// The tasks which will run periodically.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Timers.ElapsedEventArgs"/> instance containing the event data.</param>
        public static void Tasks(object sender = null, ElapsedEventArgs e = null)
        {
            if (InProgress)
            {
                if (_inProgressCount == 5)
                {
                    Log.Warn("It is time to run Tasks(), but the last one didn't finish yet. Thread will be killed and a new Tasks() will run. (6/6)");

                    try
                    {
                        _lastThd.Abort();
                        _lastThd = null;
                    }
                    catch (Exception ex)
                    {
                        Log.Debug("Exception on stuck Tasks() thread abort.", ex);
                    }
                }
                else
                {
                    Log.Warn("It is time to run Tasks(), but the last one didn't finish yet so it'll be dropped. (" + (_inProgressCount + 1) + "/6)");
                    _inProgressCount++;
                    return;
                }
            }

            _lastThd = Thread.CurrentThread;

            var st = DateTime.Now;

            Log.Debug("Running background tasks...");

            InProgress       = true;
            _inProgressCount = 0;

            try
            {
                Library.StartWatching();
            }
            catch (Exception ex)
            {
                Log.Error("Unhandled exception while reindexing the library during background tasks.", ex);
            }

            try
            {
                CheckSoftwareUpdate();
            }
            catch (Exception ex)
            {
                Log.Error("Unhandled exception while checking for software update during background tasks.", ex);
            }

            try
            {
                CheckDatabaseUpdate();
            }
            catch (Exception ex)
            {
                Log.Error("Unhandled exception while checking for database update during background tasks.", ex);
            }

            try
            {
                CheckShowListUpdate();
            }
            catch (Exception ex)
            {
                Log.Error("Unhandled exception while checking for show list update during background tasks.", ex);
            }

            try
            {
                ProcessMonitor.CheckOpenFiles();
            }
            catch (Exception ex)
            {
                Log.Error("Unhandled exception while checking for open files during background tasks.", ex);
            }

            try
            {
                //AutoDownloader.SearchForMissingEpisodes();
            }
            catch (Exception ex)
            {
                Log.Error("Unhandled exception while searching for missing episodes during background tasks.", ex);
            }

            try
            {
                RestartIfNeeded();
            }
            catch (Exception ex)
            {
                Log.Error("Unhandled exception while checking if a software restart is required during background tasks.", ex);
            }

            InProgress = false;

            Log.Debug("Background tasks completed in " + (DateTime.Now - st).TotalSeconds + "s.");
        }
        /// <summary>
        /// Gets the cover of the specified show.
        /// </summary>
        /// <param name="show">The show to get covers for.</param>
        /// <param name="status">The method to call when reporting a status change.</param>
        /// <returns>
        /// Cover of the specified show or null.
        /// </returns>
        public static string GetCover(string show, Action <string> status)
        {
            var cover = GetCoverLocation(show);

            if (File.Exists(cover))
            {
                goto success;
            }

            Log.Info("Getting cover for " + show + "...");

            string url;

            // try to find it on The TVDB

            status("Searching for cover on The TVDB...");
            try
            {
                if ((url = GetCoverFromTVDB(show)) != null)
                {
                    status("Downloading cover from " + new Uri(url).Host + "...");
                    if (DownloadCover(url, cover))
                    {
                        goto success;
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Warn("Exception while searching for cover for " + show + " on TVDB.", ex);
            }

            // try to find it on IMDb

            status("Searching for cover on IMDb...");
            try
            {
                if ((url = GetCoverFromIMDb(show)) != null)
                {
                    status("Downloading cover from " + new Uri(url).Host + "...");
                    if (DownloadCover(url, cover))
                    {
                        goto success;
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Warn("Exception while searching for cover for " + show + " on IMDb.", ex);
            }

            // try to find it on Amazon

            status("Searching for cover on Amazon...");
            try
            {
                if ((url = GetCoverFromAmazon(show)) != null)
                {
                    status("Downloading cover from " + new Uri(url).Host + "...");
                    if (DownloadCover(url, cover))
                    {
                        goto success;
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Warn("Exception while searching for cover for " + show + " on Amazon.", ex);
            }

            // we were out of luck, but f**k that, we'll draw our own cover! with blackjack. and hookers. in fact, forget the cover.

            status("Drawing a cover...");
            DrawCover(show, cover);

success:
            return(cover);
        }