/// <summary> /// Sends metadata information about the TV show into lab.rolisoft.net cache. /// </summary> /// <param name="tv">The TV show.</param> public static void UpdateRemoteCache(TVShow tv) { new Thread(() => { try { var info = new Remote.Objects.ShowInfo { Title = tv.Title, Description = tv.Description, Genre = tv.Genre, Cover = tv.Cover, Started = (long)tv.Episodes[0].Airdate.ToUnixTimestamp(), Airing = tv.Airing, AirTime = tv.AirTime, AirDay = tv.AirDay, Network = tv.Network, Runtime = tv.Runtime, Seasons = tv.Episodes.Last().Season, Episodes = tv.Episodes.Count, Source = tv.Source, SourceID = tv.SourceID }; var hash = BitConverter.ToString(new HMACSHA256(Encoding.ASCII.GetBytes(Utils.GetUUID() + "\0" + Signature.Version)).ComputeHash(Encoding.UTF8.GetBytes( info.Title + info.Description + string.Join(string.Empty, info.Genre) + info.Cover + info.Started + (info.Airing ? "true" : "false") + info.AirTime + info.AirDay + info.Network + info.Runtime + info.Seasons + info.Episodes + info.Source + info.SourceID ))).ToLower().Replace("-", string.Empty); API.SetShowInfo(info, hash); } catch { } }).Start(); }
/// <summary> /// Generates a regular expression for matching the show's name. /// </summary> /// <param name="show">The show's name.</param> /// <param name="db">The database entry, if any.</param> /// <returns> /// Regular expression which matches to the show's name. /// </returns> public static Regex GenerateTitleRegex(string show = null, TVShow db = null) { if (show == null) { show = db.Title; } // see if the show has a different name show = show.Trim(); if (db != null && !string.IsNullOrWhiteSpace(db.Data.Get("scene"))) { show = db.Data["scene"]; } else if (Regexes.Exclusions.ContainsKey(show)) { show = Regexes.Exclusions[show]; } // see if the show already has a hand-written regex if (Regexes.Pregenerated.ContainsKey(show)) { return new Regex(Regexes.Pregenerated[show], RegexOptions.IgnoreCase); } // the CLR is optimized for uppercase string matching show = show.ToUpper(); // replace apostrophes which occur in contractions to a null placeholder show = Regexes.Contractions.Replace(show, "\0"); // replace "&" to "and" show = Regexes.Ampersand.Replace(show, "AND"); // remove special characters show = Regexes.SpecialChars.Replace(show, " ").Trim(); // remove parentheses //show = show.Replace("(", string.Empty).Replace(")", string.Empty); // make year optional show = Regexes.Year.Replace(show, m => "(?:" + m.Groups[1].Value + ")?"); // make common words and single characters optional show = Regexes.Common.Replace(show, m => "(?:" + m.Groups[1].Value + ")?"); show = Regexes.OneChar.Replace(show, m => "(?:" + m.Groups[1].Value + ")?"); // replace null placeholder for apostrophes show = show.Replace("\0", @"(?:\\?['`’\._])?"); // replace whitespace to non-letter matcher show = Regexes.Whitespace.Replace(show.Trim(), "[^A-Z0-9]+"); // quick fix for ending optional tags show = show.Replace("[^A-Z0-9]+(?:", "[^A-Z0-9]*(?:").Replace(")?(?:", ")?[^A-Z0-9]*(?:"); // add boundary restrictions show = @"(?:\b|_)" + show + @"(?:\b|_)"; return new Regex(show, RegexOptions.IgnoreCase); }
/// <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="show">The show to search for.</param> public FileSearch(IEnumerable<string> paths, TVShow show) { _checkFile = StandardCheckFile; _titleRegex = new[] { show.GenerateRegex() }; _episodeRegex = new[] { default(Regex) }; InitStartPaths(paths); }
/// <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.ReadInt32()).GetUnixTimestamp(); ep.Title = inbr.ReadString(); ep.Summary = inbr.ReadString(); ep.Picture = inbr.ReadString(); ep.URL = inbr.ReadString(); return(ep); }
/// <summary> /// Modifies one or more properties of an existing TV show. /// </summary> /// <param name="show">The TV show in the database.</param> /// <param name="modification">The array of modified parameters.</param> public abstract void ModifyShow(TVShow show, params string[] modification);
/// <summary> /// Removes an existing TV show. /// </summary> /// <param name="show">The TV show to be removed.</param> public abstract void RemoveShow(TVShow show);
/// <summary> /// Updates the specified TV show in the database. /// </summary> /// <param name="show">The TV show to update.</param> /// <param name="callback">The status callback.</param> /// <returns> /// Updated TV show or <c>null</c>. /// </returns> public static TVShow Update(TVShow show, Action<int, string> callback = null) { Log.Info("Updating " + show.Title + "..."); var st = DateTime.Now; if (callback != null) { callback(0, "Updating " + show.Title + "..."); } Guide guide; try { guide = Updater.CreateGuide(show.Source); } catch (Exception ex) { Log.Error("Error while creating guide object for " + show.Title + ".", ex); if (callback != null) { callback(-1, "Could not get guide object of type " + show.Source + " for " + show.Title + "."); } return null; } TVShow tv; try { tv = guide.GetData(show.SourceID, show.Language); } catch (Exception ex) { Log.Error("Error while downloading data from guide for " + show.Title + ".", ex); if (callback != null) { callback(-1, "Could not get guide data for " + show.Source + "#" + show.SourceID + "."); } return null; } tv.ID = show.ID; tv.Data = show.Data; tv.Directory = show.Directory; tv.EpisodeByID = new Dictionary<int, Episode>(); if (tv.Title != show.Title) { tv.Title = show.Title; } 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; Episode op; if (show.EpisodeByID.TryGetValue(ep.Number + (ep.Season * 1000), out op) && op.Watched) { ep.Watched = true; } if (!string.IsNullOrWhiteSpace(tv.AirTime) && ep.Airdate != Utils.UnixEpoch) { ep.Airdate = DateTime.Parse(ep.Airdate.ToString("yyyy-MM-dd ") + tv.AirTime).ToLocalTimeZone(tv.TimeZone); } } try { tv.Save(); } catch (Exception ex) { Log.Error("Error while saving updated database for " + show.Title + ".", ex); if (callback != null) { callback(-1, "Could not save database for " + show.Title + "."); } return null; } TVShows[tv.ID] = tv; DataChange = DateTime.Now; if (callback != null) { callback(1, "Updated " + show.Title + "."); } Log.Debug("Successfully updated " + show.Title + " in " + (DateTime.Now - st).TotalSeconds + "s."); return tv; }
/// <summary> /// Adds a new TV show. /// </summary> /// <param name="show">The newly added TV show.</param> public abstract void AddShow(TVShow show);
/// <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(); } try { show.EpisodeByID[sn * 1000 + en].Watched = true; } catch (KeyNotFoundException) { } } } return show; }
/// <summary> /// Removes the specified TV show from the database. /// </summary> /// <param name="show">The TV show to remove.</param> /// <param name="callback">The status callback.</param> /// <returns> /// <c>true</c> on success; otherwise, <c>false</c>. /// </returns> public static bool Remove(TVShow show, Action<int, string> callback = null) { Log.Info("Removing " + show.Title + "..."); if (callback != null) { callback(0, "Removing " + show.Title + "..."); } try { Directory.Delete(show.Directory, true); } catch (Exception ex) { Log.Error("Error while removing " + show.Title + ".", ex); if (callback != null) { callback(-1, "Could not remove database for " + show.Title + "."); } return false; } TVShows.Remove(show.ID); DataChange = DateTime.Now; if (Library.Files != null && Library.Files.Count != 0) { foreach (var ep in Library.Files) { if (Math.Floor((double)ep.Key / 1000 / 1000) == show.ID) { ep.Value.Clear(); } } Library.SaveList(); } if (callback != null) { callback(1, "Removed " + show.Title + "."); } return true; }
/// <summary> /// Unmarks one or more episodes. /// </summary> /// <param name="show">The TV show in the database.</param> /// <param name="episodes">The list of episode ranges. A range consists of two numbers from the same season.</param> public override void UnmarkEpisodes(TVShow show, params int[][] episodes) { Log.Debug("Queued change: unmark " + show.Title + " episodes " + episodes.Aggregate(string.Empty, (c, i) => c + ", " + string.Join(", ", i)).TrimStart(", ".ToCharArray())); _changes.Enqueue(new Change(show, ChangeType.UnmarkEpisode, episodes)); _timer.Start(); }
/// <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> /// Unmarks one or more episodes. /// </summary> /// <param name="show">The TV show in the database.</param> /// <param name="episodes">The list of episode ranges. A range consists of two numbers from the same season.</param> public abstract void UnmarkEpisodes(TVShow show, params int[][] episodes);
/// <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> /// Serializes the list of marked episodes for the specified TV show. /// </summary> /// <param name="show">The TV show in the database.</param> /// <param name="range">if set to <c>true</c> sequential episode numbering will be turned into ranges.</param> /// <returns> /// List of marked episode ranges. /// </returns> public static object SerializeMarkedEpisodes(TVShow show, bool range = true) { var eps = show.Episodes.Where(e => e.Watched).OrderBy(e => e.ID).Select(e => e.ID - e.Show.ID * 1000000); if (!range) { return eps; } var list = new List<object>(); var start = 0; var prev = 0; foreach (var ep in eps) { if (prev == ep - 1) { prev = ep; } else { if (start != 0 && prev != 0) { list.Add(start == prev ? start : (object)new[] { start, prev }); } start = prev = ep; } } if ((list.Count == 0 && start != 0 && prev != 0) || (list.Count != 0 && list.Last() != new[] { start, prev })) { list.Add(start == prev ? start : (object)new[] { start, prev }); } return list; }
/// <summary> /// Initializes a new instance of the <see cref="Change" /> class. /// </summary> /// <param name="show">The show.</param> /// <param name="type">The type.</param> /// <param name="data">The data.</param> public Change(TVShow show, ChangeType type, object data = null) { Time = (DateTime.UtcNow.Ticks - 621355968000000000d) / 10000000d; Title = show.Title; ShowID = show.ID; Source = show.Source; SourceID = show.SourceID; Language = show.Language; Type = type; Data = data ?? string.Empty; }
/// <summary> /// Removes an existing TV show. /// </summary> /// <param name="show">The TV show to be removed.</param> public override void RemoveShow(TVShow show) { Log.Debug("Queued change: remove " + show.Title); _changes.Enqueue(new Change(show, ChangeType.RemoveShow)); _timer.Start(); }
/// <summary> /// Modifies one or more properties of an existing TV show. /// </summary> /// <param name="show">The TV show in the database.</param> /// <param name="modification">The array of modified parameters.</param> public override void ModifyShow(TVShow show, params string[] modification) { Log.Debug("Queued change: modify " + show.Title); _changes.Enqueue(new Change(show, ChangeType.ModifyShow, new Dictionary<string, string>(show.Data))); _timer.Start(); }
/// <summary> /// Adds a new TV show. /// </summary> /// <param name="show">The newly added TV show.</param> public override void AddShow(TVShow show) { Log.Debug("Queued change: add " + show.Title); _changes.Enqueue(new Change(show, ChangeType.AddShow, new Dictionary<string, string>(show.Data))); _timer.Start(); }
/// <summary> /// Initializes a new instance of the <see cref="GuideDropDownTVShowItem"/> class. /// </summary> /// <param name="tvShow">The TV show.</param> public GuideDropDownTVShowItem(TVShow tvShow) { Show = tvShow; }
/// <summary> /// Selects the show. /// </summary> /// <param name="show">The TV show.</param> public void SelectShow(TVShow show) { for (var i = 0; i < comboBox.Items.Count; i++) { if (comboBox.Items[i] is GuideDropDownTVShowItem && ((GuideDropDownTVShowItem)comboBox.Items[i]).Show == show) { comboBox.SelectedIndex = i; break; } } }
/// <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(); } try { show.EpisodeByID[sn * 1000 + en].Watched = true; } catch (KeyNotFoundException) { } } } return(show); }
/// <summary> /// Unmarks one or more episodes. /// </summary> /// <param name="show">The TV show in the database.</param> /// <param name="episodes">The list of episodes.</param> public override void UnmarkEpisodes(TVShow show, params int[] episodes) { Log.Debug("Queued change: unmark " + show.Title + " episodes " + string.Join(", ", episodes)); _changes.Enqueue(new Change(show, ChangeType.UnmarkEpisode, episodes)); _timer.Start(); }