/// <summary>
        /// Initializes a new instance of the <see cref="FileSearch"/> class.
        /// </summary>
        /// <param name="paths">The paths where to start the search.</param>
        /// <param name="episode">The episode to search for.</param>
        public FileSearch(IEnumerable<string> paths, Episode episode)
        {
            _checkFile    = StandardCheckFile;
            _titleRegex   = new[] { episode.Show.GenerateRegex() };
            _episodeRegex = new[] { episode.GenerateRegex() };

            InitStartPaths(paths);
        }
        /// <summary>
        /// Searches for the specified show and its episode.
        /// </summary>
        /// <param name="ep">The episode.</param>
        public void Search(Episode ep)
        {
            _active = true;
            var showmbp = false;
            var mthd = new Thread(() => TaskDialog.Show(new TaskDialogOptions
                {
                    Title                   = "Searching...",
                    MainInstruction         = "{0} S{1:00}E{2:00}".FormatWith(ep.Show.Title, ep.Season, ep.Number),
                    Content                 = "Searching for the episode...",
                    CustomButtons           = new[] { "Cancel" },
                    ShowMarqueeProgressBar  = true,
                    EnableCallbackTimer     = true,
                    AllowDialogCancellation = true,
                    Callback                = (dialog, args, data) =>
                        {
                            if (!showmbp)
                            {
                                dialog.SetProgressBarMarquee(true, 0);
                                showmbp = true;
                            }

                            if (args.ButtonId != 0)
                            {
                                if (_active)
                                {
                                    try { _os.CancelSearch(); } catch { }
                                }

                                return false;
                            }

                            if (!_active)
                            {
                                dialog.ClickButton(500);
                                return false;
                            }

                            return true;
                        }
                }));
            mthd.SetApartmentState(ApartmentState.STA);
            mthd.Start();

            _os.SearchAsync(ep);

            Utils.Win7Taskbar(state: TaskbarProgressBarState.Indeterminate);
        }
 /// <summary>
 /// Searches for videos on the service asynchronously.
 /// </summary>
 /// <param name="ep">The episode.</param>
 public void SearchAsync(Episode ep)
 {
     SearchThread = new Thread(() =>
         {
             try
             {
                 var url = Search(ep);
                 OnlineSearchDone.Fire(this, "{0} S{1:00}E{2:00}".FormatWith(ep.Show.Name, ep.Season, ep.Number), url);
             }
             catch (OnlineVideoNotFoundException ex)
             {
                 OnlineSearchError.Fire(this, "{0} S{1:00}E{2:00}".FormatWith(ep.Show.Name, ep.Season, ep.Number), ex.Message, new Tuple<string, string, string>(ex.LinkTitle, ex.LinkURL, null));
             }
             catch (Exception ex)
             {
                 OnlineSearchError.Fire(this, "{0} S{1:00}E{2:00}".FormatWith(ep.Show.Name, ep.Season, ep.Number), "There was an error while searching for the video on this service.", new Tuple<string, string, string>(null, null, ex.Message));
             }
         });
     SearchThread.Start();
 }
        /// <summary>
        /// Searches for videos on Netflix.
        /// </summary>
        /// <param name="ep">The episode.</param>
        /// <returns>
        /// URL of the video.
        /// </returns>
        public override string Search(Episode ep)
        {
            var rest = new RestClient
                {
                    QueryHandling        = QueryHandling.AppendToParameters,
                    DecompressionMethods = DecompressionMethods.GZip,
                    UserAgent            = Signature.Software + "/" + Signature.Version,
                    FollowRedirects      = true,
                    Authority            = "http://api.netflix.com/",
                    Credentials          = new OAuthCredentials
                        {
                            Type              = OAuthType.ProtectedResource,
                            SignatureMethod   = OAuthSignatureMethod.HmacSha1,
                            ParameterHandling = OAuthParameterHandling.HttpAuthorizationHeader,
                            ConsumerKey       = ConsumerKey,
                            ConsumerSecret    = SharedSecret
                        }
                };

            #region Detect and set proxy
            string proxy = null;
            object proxyId;
            if (Settings.Get<Dictionary<string, object>>("Proxied Domains").TryGetValue("netflix.com", out proxyId) || Settings.Get<Dictionary<string, object>>("Proxied Domains").TryGetValue("api.netflix.com", out proxyId))
            {
                proxy = (string)Settings.Get<Dictionary<string, object>>("Proxies")[(string)proxyId];
            }

            if (proxy != null)
            {
                var proxyUri = new Uri(proxy.Replace("$domain.", string.Empty));

                switch (proxyUri.Scheme.ToLower())
                {
                    case "http":
                        if (proxy.Contains("$url") || (proxy.Contains("$domain") && proxy.Contains("$path")))
                        {
                            throw new Exception("Web-based proxies are not supported with Netflix for now, because of OAuth signatures.");
                        }
                        else
                        {
                            rest.Proxy = proxyUri.Host + ":" + proxyUri.Port;
                        }
                        break;

                    case "socks4":
                    case "socks4a":
                    case "socks5":
                        var tunnel = new HttpToSocks { RemoteProxy = HttpToSocks.Proxy.ParseUri(proxyUri) };
                        tunnel.Listen();
                        rest.Proxy = tunnel.LocalProxy.Host + ":" + tunnel.LocalProxy.Port;
                        break;
                }
            }
            #endregion

            var request = new RestRequest { Path = "catalog/titles" };
            request.AddParameter("term", ep.Show.Title);
            request.AddParameter("max_results", "1");
            request.AddParameter("expand", "seasons");

            var resp  = XDocument.Parse(rest.Request(request).Content);
            var links = resp.XPathSelectElements("//link[@rel='http://schemas.netflix.com/catalog/title.season']");

            string seasonid = null;
            foreach (var link in links)
            {
                if (link.Attribute("title").Value.EndsWith(" " + ep.Season))
                {
                    seasonid = link.Attribute("href").Value;
                    break;
                }
            }

            if (seasonid != null)
            {
                request = new RestRequest { Path = seasonid.Replace("http://api.netflix.com/", string.Empty) + "/episodes" };
                resp    = XDocument.Parse(rest.Request(request).Content);
                var ids = resp.XPathSelectElements("//id").ToList();

                if (ids.Count >= ep.Number)
                {
                    return ids[ep.Number - 1].Value.Replace("http://api.netflix.com/catalog/titles/programs/", "http://movies.netflix.com/WiPlayer?movieid=");
                }
            }

            throw new OnlineVideoNotFoundException("No matching videos were found.", "Open Netflix search page", "http://movies.netflix.com/WiSearch?v1=" + Utils.EncodeURL(ep.Show.Title));
        }
        /// <summary>
        /// Downloads the specified link near the specified video.
        /// </summary>
        /// <param name="link">The link.</param>
        /// <param name="episode">The episode to search for.</param>
        public void DownloadNearVideoOld(Subtitle link, Episode episode)
        {
            _link = link;
            _ep   = episode;

            var paths = Settings.Get<List<string>>("Download Paths");

            if (paths.Count == 0)
            {
                TaskDialog.Show(new TaskDialogOptions
                    {
                        MainIcon                = VistaTaskDialogIcon.Error,
                        Title                   = "Search path not configured",
                        MainInstruction         = "Search path not configured",
                        Content                 = "To use this feature you must set your download path." + Environment.NewLine + Environment.NewLine + "To do so, click on the logo on the upper left corner of the application, then select 'Configure Software'. On the new window click the 'Browse' button under 'Download Path'.",
                        AllowDialogCancellation = true,
                        CustomButtons           = new[] { "OK" }
                    });
                return;
            }

            _active = true;
            _tdstr = "Searching for the episode...";
            var showmbp = false;
            var mthd = new Thread(() => TaskDialog.Show(new TaskDialogOptions
                {
                    Title                   = "Searching...",
                    MainInstruction         = link.Release,
                    Content                 = "Searching for the episode...",
                    CustomButtons           = new[] { "Cancel" },
                    ShowProgressBar         = true,
                    ShowMarqueeProgressBar  = true,
                    EnableCallbackTimer     = true,
                    AllowDialogCancellation = true,
                    Callback                = (dialog, args, data) =>
                        {
                            if (!showmbp && _tdpos == 0)
                            {
                                dialog.SetProgressBarMarquee(true, 0);

                                showmbp = true;
                            }

                            if (_tdpos > 0 && showmbp)
                            {
                                dialog.SetMarqueeProgressBar(false);
                                dialog.SetProgressBarState(VistaProgressBarState.Normal);
                                dialog.SetProgressBarPosition(_tdpos);

                                showmbp = false;
                            }

                            if (_tdpos > 0)
                            {
                                dialog.SetProgressBarPosition(_tdpos);
                            }

                            dialog.SetContent(_tdstr);

                            if (args.ButtonId != 0)
                            {
                                if (_active)
                                {
                                    try
                                    {
                                        if (_fs != null)
                                        {
                                            _fs.CancelSearch();
                                        }

                                        if (_dl != null)
                                        {
                                            _dl.CancelAsync();
                                        }
                                    }
                                    catch { }
                                }

                                return false;
                            }

                            if (!_active)
                            {
                                dialog.ClickButton(500);
                                return false;
                            }

                            return true;
                        }
                }));
            mthd.SetApartmentState(ApartmentState.STA);
            mthd.Start();

            _fs = new FileSearch(paths, _ep);

            _fs.FileSearchDone += NearVideoFileSearchDoneOld;
            _fs.FileSearchProgressChanged += NearVideoFileSearchProgressChangedOld;
            _fs.BeginSearch();

            Utils.Win7Taskbar(state: TaskbarProgressBarState.Indeterminate);
        }
        /// <summary>
        /// Downloads the specified link near the specified video.
        /// </summary>
        /// <param name="link">The link.</param>
        /// <param name="episode">The episode to search for.</param>
        /// <param name="file">The file.</param>
        public void DownloadNearVideo(Subtitle link, Episode episode, string file)
        {
            _link = link;
            _ep   = episode;
            _file = file;
            
            _active = true;
            _tdtit = link.Release;
            _tdstr = "Sending request to " + (string.IsNullOrWhiteSpace(link.FileURL ?? link.InfoURL) ? link.Source.Name : new Uri(link.FileURL ?? link.InfoURL).DnsSafeHost.Replace("www.", string.Empty)) + "...";
            var showmbp = false;
            var mthd = new Thread(() => TaskDialog.Show(new TaskDialogOptions
                {
                    Title                   = "Downloading...",
                    MainInstruction         = _tdtit,
                    Content                 = _tdstr,
                    CustomButtons           = new[] { "Cancel" },
                    ShowMarqueeProgressBar  = true,
                    ShowProgressBar         = true,
                    EnableCallbackTimer     = true,
                    AllowDialogCancellation = true,
                    Callback                = (dialog, args, data) =>
                        {
                            if (!showmbp && _tdpos == 0)
                            {
                                dialog.SetProgressBarMarquee(true, 0);

                                showmbp = true;
                            }

                            if (_tdpos > 0 && showmbp)
                            {
                                dialog.SetMarqueeProgressBar(false);
                                dialog.SetProgressBarState(VistaProgressBarState.Normal);
                                dialog.SetProgressBarPosition(_tdpos);

                                showmbp = false;
                            }

                            if (_tdpos > 0)
                            {
                                dialog.SetProgressBarPosition(_tdpos);
                            }

                            dialog.SetContent(_tdstr);

                            if (args.ButtonId != 0)
                            {
                                if (_active)
                                {
                                    try { _dl.CancelAsync(); } catch { }
                                }

                                return false;
                            }

                            if (!_active)
                            {
                                dialog.ClickButton(500);
                                return false;
                            }

                            return true;
                        }
                }));
            mthd.SetApartmentState(ApartmentState.STA);
            mthd.Start();
            
            _dl                          = link.Source.Downloader;
            _dl.DownloadFileCompleted   += NearVideoDownloadFileCompleted;
            _dl.DownloadProgressChanged += (s, a) =>
                {
                    _tdstr = "Downloading file... ({0}%)".FormatWith(a.Data);
                    _tdpos = a.Data;
                };

            _dl.Download(link, Path.Combine(Path.GetTempPath(), Utils.CreateSlug(link.Release.Replace('.', ' ').Replace('_', ' ') + " " + link.Source.Name + " " + Utils.Rand.Next().ToString("x"), false)));

            Utils.Win7Taskbar(state: TaskbarProgressBarState.Indeterminate);
        }
 /// <summary>
 /// Searches for videos on BBC iPlayer.
 /// </summary>
 /// <param name="ep">The episode.</param>
 /// <returns>
 /// URL of the video.
 /// </returns>
 public override string Search(Episode ep)
 {
     return "http://www.google.com/search?btnI=I'm+Feeling+Lucky&hl=en&q=" + Utils.EncodeURL("intitle:" + ep.Show.Title + " intitle:\"Season " + ep.Season + ", Episode " + ep.Number + "\" site:amazon.com");
 }
 /// <summary>
 /// Determines whether the specified link matches the rule set for the specified show
 /// </summary>
 /// <param name="episode">The episode.</param>
 /// <param name="link">The link.</param>
 /// <returns>
 ///   <c>true</c> if the specified link matches the rule; otherwise, <c>false</c>.
 /// </returns>
 public static bool IsMatchingRule(Episode episode, Link link)
 {
     return link.Quality == PreferredQuality ||
            ((DateTime.Now - episode.Airdate) > WaitForPreferred && link.Quality == SecondPreferredQuality);
 }
        /// <summary>
        /// Determines whether the specified link matches the rule set for the specified show
        /// </summary>
        /// <param name="episode">The episode.</param>
        /// <param name="link">The link.</param>
        /// <returns>
        ///   <c>true</c> if the specified link matches the rule; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsMatchingRule(Episode episode, Link link)
        {
            // TODO

            return link.Quality == Qualities.WebDL720p || (DateTime.Now - episode.Airdate) > WaitForPreferred;
        }
Exemple #10
0
        /// <summary>
        /// Loads an object from the stream.
        /// </summary>
        /// <param name="show">The show associated with the episode.</param>
        /// <param name="inbr">The source reader for episode listing.</param>
        /// <returns>
        /// Deserialized object.
        /// </returns>
        internal static Episode Load(TVShow show, BinaryReader inbr)
        {
            var ep = new Episode();

            ep.Show   = show;
            ep.Season = inbr.ReadByte();
            ep.Number = inbr.ReadByte();
            ep.ID     = ep.Number + (ep.Season * 1000) + (ep.Show.ID * 1000 * 1000);

            if (ep.Number == 255)
            {
                ep.Number += inbr.ReadByte();
            }

            ep.Airdate = ((double)inbr.ReadUInt32()).GetUnixTimestamp();
            ep.Title   = inbr.ReadString();
            ep.Summary = inbr.ReadString();
            ep.Picture = inbr.ReadString();
            ep.URL     = inbr.ReadString();

            return ep;
        }
        /// <summary>
        /// Searches for videos on Serienjunkies.
        /// </summary>
        /// <param name="ep">The episode.</param>
        /// <returns>
        /// URL of the video.
        /// </returns>
        public override string Search(Episode ep)
        {
            var name = ep.Show.Title.ToLower();
                name = Regex.Replace(name, @"[^a-z0-9\s]", string.Empty);
                name = Regex.Replace(name, @"\s+", "-");

            if (Downloads.Engines.HTTP.Serienjunkies.AlternativeNames.ContainsKey(name))
            {
                name = Downloads.Engines.HTTP.Serienjunkies.AlternativeNames[name];
            }

            return "{0}serie/{1}/#{2},{3}".FormatWith(Site, name, ep.Season, ep.Number);
        }
Exemple #12
0
 /// <summary>
 /// Searches for videos on BBC iPlayer.
 /// </summary>
 /// <param name="ep">The episode.</param>
 /// <returns>
 /// URL of the video.
 /// </returns>
 public override string Search(Episode ep)
 {
     return "http://www.google.com/search?btnI=I'm+Feeling+Lucky&hl=en&q=" + Utils.EncodeURL("intitle:" + ep.Show.Name + " intitle:\"season " + ep.Season + "\" site:itunes.apple.com inurl:/tv-season/");
 }
        /// <summary>
        /// Selects the episode.
        /// </summary>
        /// <param name="ep">The episode.</param>
        public void SelectEpisode(Episode ep)
        {
            SelectShow(ep.Show);

            tabControl.SelectedIndex = 1;

            for (var i = 0; i < listView.Items.Count; i++)
            {
                if (((GuideListViewItem)listView.Items[i]).ID == ep)
                {
                    listView.SelectedIndex = i;
                    listView.ScrollIntoView(listView.Items[i]);
                    break;
                }
            }
        }
        /// <summary>
        /// Searches for videos on Hulu.
        /// </summary>
        /// <param name="ep">The episode.</param>
        /// <returns>
        /// URL of the video.
        /// </returns>
        public override string Search(Episode ep)
        {
            var xdoc = Utils.GetXML("http://www.hulu.com/feed/search?fs=0&query=" + Utils.EncodeURL("show:" + ep.Show.Title + " season:" + ep.Season + " episode:" + ep.Number + " type:episode") + "&sort_by=relevance&st=1");
            var link = xdoc.XPathSelectElement("//item/link[1]");

            if (link != null)
            {
                return link.Value;
            }

            throw new OnlineVideoNotFoundException("No matching videos were found.", "Open Hulu search page", "http://www.hulu.com/search?query=" + Utils.EncodeURL("show:" + ShowNames.Parser.CleanTitleWithEp(ep.Show.Title) + " season:" + ep.Season + " episode:" + ep.Number + " type:episode") + "&st=1");
        }
        /// <summary>
        /// Handles the Click event of the searchButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void SearchButtonClick(object sender = null, RoutedEventArgs e = null)
        {
            if (string.IsNullOrWhiteSpace(textBox.Text)) return;

            if (_searching)
            {
                ActiveSearch.CancelAsync();
                SubtitleSearchDone();
                return;
            }

            SubtitlesListViewItemCollection.Clear();

            textBox.IsEnabled    = false;
            searchButton.Content = "Cancel";

            ActiveSearch = new SubtitleSearch(ActiveSearchEngines, ActiveLangs, filterResults.IsChecked);

            ActiveSearch.SubtitleSearchDone          += SubtitleSearchDone;
            ActiveSearch.SubtitleSearchEngineNewLink += SubtitleSearchEngineNewLink;
            ActiveSearch.SubtitleSearchEngineDone    += SubtitleSearchEngineDone;
            ActiveSearch.SubtitleSearchEngineError   += SubtitleSearchEngineError;
            
            SetStatus("Searching for subtitles on " + (string.Join(", ", ActiveSearch.SearchEngines.Select(engine => engine.Name).ToArray())) + "...", true);

            _searching = true;

            ActiveSearch.SearchAsync(textBox.Text);

            _dbep = FileNames.Parser.ParseFile(textBox.Text, null, false).DbEpisode;

            Utils.Win7Taskbar(0, TaskbarProgressBarState.Normal);
        }
        /// <summary>
        /// Searches for videos on SideReel.
        /// </summary>
        /// <param name="ep">The episode.</param>
        /// <returns>
        /// URL of the video.
        /// </returns>
        public override string Search(Episode ep)
        {
            var html = Utils.GetHTML("http://www.sidereel.com/_television/search?q=" + Utils.EncodeURL(ep.Show.Name));
            var link = html.DocumentNode.GetNodeAttributeValue("//div[@class='title']/h2/a[1]", "href");

            if (string.IsNullOrWhiteSpace(link))
            {
                throw new OnlineVideoNotFoundException("No matching videos were found.", "Open SideReel search page", "http://www.sidereel.com/_television/search?q=" + Utils.EncodeURL(ep.Show.Name));
            }

            return "http://www.sidereel.com/{0}/season-{1}/episode-{2}/search".FormatWith(link.Trim(" /".ToCharArray()), ep.Season, ep.Number);
        }
Exemple #17
0
        /// <summary>
        /// Loads an object from the directory.
        /// </summary>
        /// <param name="dir">The source directory.</param>
        /// <returns>
        /// Deserialized object.
        /// </returns>
        public static TVShow Load(string dir)
        {
            var show = new TVShow {
                Directory = dir
            };

            using (var info = File.OpenRead(Path.Combine(dir, "info")))
                using (var conf = File.OpenRead(Path.Combine(dir, "conf")))
                    using (var seen = File.OpenRead(Path.Combine(dir, "seen")))
                        using (var inbr = new BinaryReader(info))
                            using (var cobr = new BinaryReader(conf))
                                using (var sebr = new BinaryReader(seen))
                                {
                                    int epnr;

                                    var sver = inbr.ReadByte();
                                    var supd = inbr.ReadUInt32();

                                    show.Title       = inbr.ReadString();
                                    show.Source      = inbr.ReadString();
                                    show.SourceID    = inbr.ReadString();
                                    show.Description = inbr.ReadString();
                                    show.Genre       = inbr.ReadString();
                                    show.Cover       = inbr.ReadString();
                                    show.Airing      = inbr.ReadBoolean();
                                    show.AirTime     = inbr.ReadString();
                                    show.AirDay      = inbr.ReadString();
                                    show.Network     = inbr.ReadString();
                                    show.Runtime     = inbr.ReadByte();
                                    show.TimeZone    = inbr.ReadString();
                                    show.Language    = inbr.ReadString();
                                    show.URL         = inbr.ReadString();

                                    epnr = inbr.ReadUInt16();

                                    var dver = cobr.ReadByte();
                                    var dupd = cobr.ReadUInt32();
                                    var dcnt = cobr.ReadUInt16();

                                    show.Data = new Dictionary <string, string>();

                                    for (var i = 0; i < dcnt; i++)
                                    {
                                        show.Data[cobr.ReadString()] = cobr.ReadString();
                                    }

                                    show.ID     = int.Parse(show.Data["showid"]);
                                    show._rowId = int.Parse(show.Data["rowid"]);

                                    string ctitle;
                                    if (show.Data.TryGetValue("title", out ctitle))
                                    {
                                        show._title = ctitle;
                                    }

                                    show.Episodes    = new List <Episode>(epnr);
                                    show.EpisodeByID = new Dictionary <int, Episode>();

                                    for (var i = 0; i < epnr; i++)
                                    {
                                        var ep = Episode.Load(show, inbr);
                                        show.Episodes.Add(ep);
                                        show.EpisodeByID[ep.Season * 1000 + ep.Number] = ep;
                                    }

                                    var tver = sebr.ReadByte();
                                    var tupd = sebr.ReadUInt32();
                                    var tcnt = sebr.ReadUInt16();

                                    for (var i = 0; i < tcnt; i++)
                                    {
                                        var sn = sebr.ReadByte();
                                        var en = sebr.ReadByte();

                                        if (en == 255)
                                        {
                                            en += sebr.ReadByte();
                                        }

                                        Episode epw;
                                        if (show.EpisodeByID.TryGetValue(sn * 1000 + en, out epw))
                                        {
                                            epw.Watched = true;
                                        }
                                    }
                                }

            return(show);
        }
        /// <summary>
        /// Searches for the specified episode and returns the download links.
        /// </summary>
        /// <param name="ep">The episode.</param>
        /// <returns>
        /// List of download links.
        /// </returns>
        public static List<Link> SearchForLinks(Episode ep)
        {
            var links = new List<Link>();
            var dlsrc = new DownloadSearch(ActiveSearchEngines, true);
            var start = DateTime.Now;
            var busy  = true;

            dlsrc.DownloadSearchEngineNewLink += (s, e) => links.Add(e.Data);
            dlsrc.DownloadSearchDone          += (s, e) => { busy = false; };

            dlsrc.SearchAsync(ep.Show.Name + " " + (ep.Show.Data.Get("notation") == "airdate" ? ep.Airdate.ToOriginalTimeZone(ep.Show.TimeZone).ToString("yyyy.MM.dd") : string.Format("S{0:00}E{1:00}", ep.Season, ep.Number)));

            while (busy && (DateTime.Now - start).TotalMinutes < 2)
            {
                Thread.Sleep(TimeSpan.FromSeconds(1));
            }

            return links;
        }
 /// <summary>
 /// Searches for videos on the service.
 /// </summary>
 /// <param name="ep">The episode.</param>
 /// <returns>
 /// URL of the video.
 /// </returns>
 public abstract string Search(Episode ep);
        /// <summary>
        /// Initializes a new instance of the <see cref="ShowFile" /> class.
        /// </summary>
        /// <param name="name">The name of the original file.</param>
        /// <param name="show">The name of the show.</param>
        /// <param name="ep">The parsed season and episode.</param>
        /// <param name="title">The title of the episode.</param>
        /// <param name="quality">The quality of the file.</param>
        /// <param name="group">The group.</param>
        /// <param name="airdate">The airdate of the episode.</param>
        /// <param name="dbtvshow">The TV show in the local database.</param>
        /// <param name="dbepisode">The episode in the local database.</param>
        /// <param name="success">if set to <c>true</c> the file was successfully parsed.</param>
        public ShowFile(string name, string show, ShowEpisode ep, string title, string quality, string group, DateTime airdate, TVShow dbtvshow = null, Episode dbepisode = null, bool success = true)
        {
            Name          = name;
            Extension     = Path.GetExtension(Name);
            Show          = show;
            Episode       = ep;
            Title         = title;
            Quality       = quality;
            Group         = group;
            Airdate       = airdate;
            Success       = success;
            DbTVShow      = dbtvshow;
            DbEpisode     = dbepisode;

            if (DbTVShow != null || DbEpisode != null)
            {
                Local = true;
            }
        }
        /// <summary>
        /// Searches for the specified episode and returns the download links.
        /// </summary>
        /// <param name="ep">The episode.</param>
        /// <returns>
        /// List of download links.
        /// </returns>
        public static async Task<List<Link>> SearchForLinks(Episode ep)
        {
            var links = new List<Link>();
            var dlsrc = new DownloadSearch(AutoSearchEngines, true);

            dlsrc.DownloadSearchEngineNewLink += (s, e) => links.Add(e.Data);

            var tasks = dlsrc.SearchAsync(ep.Show.Title + " " + (ep.Show.Data.Get("notation") == "airdate" ? ep.Airdate.ToOriginalTimeZone(ep.Show.TimeZone).ToString("yyyy.MM.dd") : string.Format("S{0:00}E{1:00}", ep.Season, ep.Number)));

            await Task.WhenAll(tasks);

            return links;
        }
        /// <summary>
        /// Determines whether the specified file matches the rule set for the specified show
        /// </summary>
        /// <param name="episode">The episode.</param>
        /// <param name="file">The file.</param>
        /// <returns>
        ///   <c>true</c> if the specified file matches the rule; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsMatchingRule(Episode episode, string file)
        {
            var quality = FileNames.Parser.ParseQuality(file);

            return quality == PreferredQuality ||
                   ((DateTime.Now - episode.Airdate) > WaitForPreferred && quality == SecondPreferredQuality);
        }
        /// <summary>
        /// Searches for videos on BBC iPlayer.
        /// </summary>
        /// <param name="ep">The episode.</param>
        /// <returns>
        /// URL of the video.
        /// </returns>
        public override string Search(Episode ep)
        {
            var html  = Utils.GetHTML("http://www.bbc.co.uk/iplayer/search?q=" + Utils.EncodeURL(ep.Show.Title + " Series " + ep.Season + " Episode " + ep.Number));
            var links = html.DocumentNode.SelectNodes("//h3/a/span[@class='title']");
            
            if (links != null)
            {
                foreach (var link in links)
                {
                    if (link.InnerText.Contains(" - Series " + ep.Season + "Episode " + ep.Number))
                    {
                        return "http://www.bbc.co.uk" + link.GetNodeAttributeValue("..", "href");
                    }
                }
            }

            throw new OnlineVideoNotFoundException("No matching videos were found.", "Open iPlayer search page", "http://www.bbc.co.uk/iplayer/search?q=" + Utils.EncodeURL(ep.Show.Title + " Series " + ep.Season + " Episode " + ep.Number));
        }
        /// <summary>
        /// Determines whether the specified file matches the rule set for the specified show
        /// </summary>
        /// <param name="episode">The episode.</param>
        /// <param name="file">The file.</param>
        /// <returns>
        ///   <c>true</c> if the specified file matches the rule; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsMatchingRule(Episode episode, string file)
        {
            // TODO

            var quality = FileNames.Parser.ParseQuality(file);

            return quality == Qualities.WebDL720p;
        }