/// <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; }
/// <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); }
/// <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); }
/// <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; }