Merge pull request #245 from Sonarr/skyhook-search

Use skyhook for searching
pull/3113/head
Mark McDowall 10 years ago
commit d5ba11bd51

@ -13,7 +13,7 @@ namespace NzbDrone.Api.Series
private readonly ISearchForNewSeries _searchProxy;
public SeriesLookupModule(ISearchForNewSeries searchProxy)
: base("/Series/lookup")
: base("/series/lookup")
{
_searchProxy = searchProxy;
Get["/"] = x => Search();

@ -6,7 +6,7 @@ using NzbDrone.Core.MetadataSource;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.MetadataSourceTests
namespace NzbDrone.Core.Test.MetadataSource
{
[TestFixture]
public class SearchSeriesComparerFixture : CoreTest

@ -1,21 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MetadataSource;
using NzbDrone.Core.MetadataSource.SkyHook;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
using NzbDrone.Test.Common;
using NzbDrone.Test.Common.Categories;
namespace NzbDrone.Core.Test.MetadataSourceTests
namespace NzbDrone.Core.Test.MetadataSource.SkyHook
{
[TestFixture]
[IntegrationTest]
public class TvdbDataProxyFixture : CoreTest<TvDbProxy>
public class SkyHookProxySearchFixture : CoreTest<SkyHookProxy>
{
[SetUp]
public void Setup()

@ -239,8 +239,8 @@
<Compile Include="MediaFiles\EpisodeImport\Specifications\UpgradeSpecificationFixture.cs" />
<Compile Include="MediaFiles\ImportApprovedEpisodesFixture.cs" />
<Compile Include="MediaFiles\MediaFileRepositoryFixture.cs" />
<Compile Include="MetadataSourceTests\TvdbDataProxyFixture.cs" />
<Compile Include="MetadataSourceTests\SearchSeriesComparerFixture.cs" />
<Compile Include="MetadataSource\SkyHook\SkyHookProxySearchFixture.cs" />
<Compile Include="MetadataSource\SearchSeriesComparerFixture.cs" />
<Compile Include="MetadataSource\SkyHook\SkyHookProxyFixture.cs" />
<Compile Include="NotificationTests\SynologyIndexerFixture.cs" />
<Compile Include="OrganizerTests\FileNameBuilderTests\CleanTitleFixture.cs" />

@ -6,7 +6,7 @@ using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.MetadataSource;
using NzbDrone.Core.MetadataSource.SkyHook;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Test.Framework;
@ -25,7 +25,7 @@ namespace NzbDrone.Core.Test.TvTests
{
UseRealHttp();
_gameOfThrones = Mocker.Resolve<TvDbProxy>().GetSeriesInfo(121361);//Game of thrones
_gameOfThrones = Mocker.Resolve<SkyHookProxy>().GetSeriesInfo(121361);//Game of thrones
// Remove specials.
_gameOfThrones.Item2.RemoveAll(v => v.SeasonNumber == 0);

@ -0,0 +1,17 @@
using System.Net;
using NzbDrone.Core.Exceptions;
namespace NzbDrone.Core.MetadataSource.SkyHook
{
public class SkyHookException : NzbDroneClientException
{
public SkyHookException(string message) : base(HttpStatusCode.ServiceUnavailable, message)
{
}
public SkyHookException(string message, params object[] args)
: base(HttpStatusCode.ServiceUnavailable, message, args)
{
}
}
}

@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Web;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
@ -10,23 +13,25 @@ using NzbDrone.Core.Tv;
namespace NzbDrone.Core.MetadataSource.SkyHook
{
public class SkyHookProxy : IProvideSeriesInfo
public class SkyHookProxy : IProvideSeriesInfo, ISearchForNewSeries
{
private readonly Logger _logger;
private readonly IHttpClient _httpClient;
private readonly Logger _logger;
private readonly HttpRequestBuilder _requestBuilder;
public SkyHookProxy(Logger logger, IHttpClient httpClient)
public SkyHookProxy(IHttpClient httpClient, Logger logger)
{
_logger = logger;
_httpClient = httpClient;
_logger = logger;
_requestBuilder = new HttpRequestBuilder("http://skyhook.sonarr.tv/v1/tvdb/shows/en/");
_requestBuilder = new HttpRequestBuilder("http://skyhook.sonarr.tv/v1/tvdb/{route}/en/");
}
public Tuple<Series, List<Episode>> GetSeriesInfo(int tvdbSeriesId)
{
var httpRequest = _requestBuilder.Build(tvdbSeriesId.ToString());
httpRequest.AddSegment("route", "shows");
var httpResponse = _httpClient.Get<ShowResource>(httpRequest);
var episodes = httpResponse.Resource.Episodes.Select(MapEpisode);
var series = MapSeries(httpResponse.Resource);
@ -34,6 +39,58 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
return new Tuple<Series, List<Episode>>(series, episodes.ToList());
}
public List<Series> SearchForNewSeries(string title)
{
try
{
var lowerTitle = title.ToLowerInvariant();
if (lowerTitle.StartsWith("tvdb:") || lowerTitle.StartsWith("tvdbid:"))
{
var slug = lowerTitle.Split(':')[1].Trim();
int tvdbId;
if (slug.IsNullOrWhiteSpace() || slug.Any(char.IsWhiteSpace) || !Int32.TryParse(slug, out tvdbId) || tvdbId <= 0)
{
return new List<Series>();
}
try
{
return new List<Series> { GetSeriesInfo(tvdbId).Item1 };
}
catch (Common.Http.HttpException ex)
{
if (ex.Response.StatusCode == HttpStatusCode.NotFound)
{
return new List<Series>();
}
throw;
}
}
var term = HttpUtility.UrlEncode((title.ToLower().Trim()));
var httpRequest = _requestBuilder.Build("?term={term}");
httpRequest.AddSegment("route", "search");
httpRequest.AddSegment("term", term);
var httpResponse = _httpClient.Get<List<ShowResource>>(httpRequest);
return httpResponse.Resource.SelectList(MapSeries);
}
catch (Common.Http.HttpException)
{
throw new SkyHookException("Search for '{0}' failed. Unable to communicate with SkyHook.", title);
}
catch (Exception ex)
{
_logger.WarnException(ex.Message, ex);
throw new SkyHookException("Search for '{0}' failed. Invalid response received from SkyHook.", title);
}
}
private static Series MapSeries(ShowResource show)
{
var series = new Series();
@ -91,8 +148,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
var newActor = new Actor
{
Name = arg.Name,
Character = arg.Character,
Character = arg.Character
};
if (arg.Image != null)
@ -185,6 +241,5 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
return MediaCoverTypes.Unknown;
}
}
}
}

@ -1,272 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Web;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MetadataSource.Tvdb;
using NzbDrone.Core.Tv;
using TVDBSharp;
using TVDBSharp.Models.Enums;
namespace NzbDrone.Core.MetadataSource
{
public class TvDbProxy : ISearchForNewSeries
{
private readonly Logger _logger;
private static readonly Regex CollapseSpaceRegex = new Regex(@"\s+", RegexOptions.Compiled);
private static readonly Regex InvalidSearchCharRegex = new Regex(@"(?:\*|\(|\)|'|!|@|\+)", RegexOptions.Compiled);
private readonly TVDB _tvdb;
public TvDbProxy(Logger logger)
{
_logger = logger;
_tvdb = new TVDB("5D2D188E86E07F4F");
}
private IEnumerable<TVDBSharp.Models.Show> SearchTvdb(string title)
{
var lowerTitle = title.ToLowerInvariant();
if (lowerTitle.StartsWith("tvdb:") || lowerTitle.StartsWith("tvdbid:"))
{
var slug = lowerTitle.Split(':')[1].Trim();
int tvdbId;
if (slug.IsNullOrWhiteSpace() || slug.Any(char.IsWhiteSpace) || !Int32.TryParse(slug, out tvdbId) || tvdbId <= 0)
{
return Enumerable.Empty<TVDBSharp.Models.Show>();
}
try
{
return new[] { _tvdb.GetShow(tvdbId) };
}
catch (Common.Http.HttpException ex)
{
if (ex.Response.StatusCode == HttpStatusCode.NotFound)
{
return Enumerable.Empty<TVDBSharp.Models.Show>();
}
throw;
}
}
return _tvdb.Search(GetSearchTerm(lowerTitle), 10);
}
public List<Series> SearchForNewSeries(string title)
{
try
{
var tvdbSeries = SearchTvdb(title.Trim());
var series = tvdbSeries.Select(MapSeries).ToList();
series.Sort(new SearchSeriesComparer(title));
return series;
}
catch (Common.Http.HttpException)
{
throw new TvdbException("Search for '{0}' failed. Unable to communicate with TVDB.", title);
}
catch (Exception ex)
{
_logger.WarnException(ex.Message, ex);
throw new TvdbException("Search for '{0}' failed. Invalid response received from TVDB.", title);
}
}
public Tuple<Series, List<Tv.Episode>> GetSeriesInfo(int tvdbSeriesId)
{
var tvdbSeries = _tvdb.GetShow(tvdbSeriesId);
var episodes = tvdbSeries.Episodes.Select(MapEpisode);
episodes = RemoveDuplicates(episodes);
var series = MapSeries(tvdbSeries);
return new Tuple<Series, List<Tv.Episode>>(series, episodes.ToList());
}
private static IEnumerable<Tv.Episode> RemoveDuplicates(IEnumerable<Tv.Episode> episodes)
{
//http://support.trakt.tv/forums/188762-general/suggestions/4430690-anger-management-duplicate-episode
var episodeGroup = episodes.GroupBy(e => e.SeasonNumber.ToString("0000") + e.EpisodeNumber.ToString("0000"));
return episodeGroup.Select(g => g.First());
}
private static Series MapSeries(TVDBSharp.Models.Show show)
{
var series = new Series();
series.TvdbId = show.Id;
//series.TvRageId = show.tvrage_id;
series.ImdbId = show.ImdbId;
series.Title = show.Name;
series.CleanTitle = Parser.Parser.CleanSeriesTitle(show.Name);
series.SortTitle = SeriesTitleNormalizer.Normalize(show.Name, show.Id);
if (show.FirstAired != null)
{
series.Year = show.FirstAired.Value.Year;
series.FirstAired = show.FirstAired.Value.ToUniversalTime();
}
series.Overview = show.Description;
if (show.Runtime != null)
{
series.Runtime = show.Runtime.Value;
}
series.Network = show.Network;
if (show.AirTime != null)
{
series.AirTime = show.AirTime.Value.ToString();
}
series.TitleSlug = GenerateSlug(show.Name);
series.Status = GetSeriesStatus(show.Status);
series.Ratings = GetRatings(show.RatingCount, show.Rating);
series.Genres = show.Genres;
series.Certification = show.ContentRating.ToString().ToUpper();
series.Actors = new List<Tv.Actor>();
series.Seasons = GetSeasons(show);
if (show.Banner != null)
{
series.Images.Add(new MediaCover.MediaCover { CoverType = MediaCoverTypes.Banner, Url = show.Banner.ToString() });
}
if (show.Poster != null)
{
series.Images.Add(new MediaCover.MediaCover { CoverType = MediaCoverTypes.Poster, Url = show.Poster.ToString() });
}
if (show.Fanart != null)
{
series.Images.Add(new MediaCover.MediaCover { CoverType = MediaCoverTypes.Fanart, Url = show.Fanart.ToString() });
}
return series;
}
private static Episode MapEpisode(TVDBSharp.Models.Episode traktEpisode)
{
var episode = new Episode();
episode.Overview = traktEpisode.Description;
episode.SeasonNumber = traktEpisode.SeasonNumber;
episode.EpisodeNumber = traktEpisode.EpisodeNumber;
episode.AbsoluteEpisodeNumber = traktEpisode.AbsoluteEpisodeNumber;
episode.Title = traktEpisode.Title;
if (traktEpisode.FirstAired != null)
{
episode.AirDate = traktEpisode.FirstAired.Value.ToString("yyyy-MM-dd");
episode.AirDateUtc = traktEpisode.FirstAired.Value.ToUniversalTime();
}
episode.Ratings = GetRatings(traktEpisode.RatingCount, traktEpisode.Rating);
//Don't include series fanart images as episode screenshot
if (traktEpisode.EpisodeImage != null)
{
episode.Images.Add(new MediaCover.MediaCover(MediaCoverTypes.Screenshot, traktEpisode.EpisodeImage.ToString()));
}
return episode;
}
private static SeriesStatusType GetSeriesStatus(Status status)
{
if (status == Status.Ended)
{
return SeriesStatusType.Ended;
}
return SeriesStatusType.Continuing;
}
private static string GetSearchTerm(string phrase)
{
phrase = phrase.RemoveAccent();
phrase = InvalidSearchCharRegex.Replace(phrase, "");
// if (!phrase.Any(char.IsWhiteSpace) && phrase.Any(char.IsUpper) && phrase.Any(char.IsLower) && phrase.Length > 4)
// {
// phrase = ExpandCamelCaseRegEx.Replace(phrase, " ");
// }
phrase = CollapseSpaceRegex.Replace(phrase, " ").Trim();
phrase = phrase.Trim('-');
phrase = HttpUtility.UrlEncode(phrase.ToLower());
return phrase;
}
private static Tv.Ratings GetRatings(int ratingCount, decimal? rating)
{
var result = new Tv.Ratings { Votes = ratingCount };
if (rating != null)
{
result.Value = rating.Value;
}
return result;
}
private static List<Tv.Season> GetSeasons(TVDBSharp.Models.Show show)
{
var seasons = new List<Tv.Season>();
foreach (var seasonNumber in show.Episodes.Select(c => c.SeasonNumber).Distinct().OrderByDescending(c => c))
{
var season = new Tv.Season
{
SeasonNumber = seasonNumber
};
/* if (season.images != null)
{
season.Images.Add(new MediaCover.MediaCover(MediaCoverTypes.Poster, season.images.poster));
}*/
seasons.Add(season);
}
return seasons;
}
private static readonly Regex RemoveRegex = new Regex(@"[^\w-]", RegexOptions.Compiled);
public static string GenerateSlug(string showTitle)
{
if (showTitle.StartsWith("."))
{
showTitle = "dot" + showTitle.Substring(1);
}
showTitle = showTitle.Replace(" ", "-");
showTitle = showTitle.Replace("&", "and");
showTitle = RemoveRegex.Replace(showTitle, String.Empty);
showTitle = showTitle.RemoveAccent();
showTitle = showTitle.ToLowerInvariant();
return showTitle;
}
}
}

@ -1,16 +0,0 @@
using System.Net;
using NzbDrone.Core.Exceptions;
namespace NzbDrone.Core.MetadataSource.Tvdb
{
public class TvdbException : NzbDroneClientException
{
public TvdbException(string message) : base(HttpStatusCode.ServiceUnavailable, message)
{
}
public TvdbException(string message, params object[] args) : base(HttpStatusCode.ServiceUnavailable, message, args)
{
}
}
}

@ -646,9 +646,8 @@
<Compile Include="MetadataSource\SkyHook\Resource\ShowResource.cs" />
<Compile Include="MetadataSource\SkyHook\Resource\TimeOfDayResource.cs" />
<Compile Include="MetadataSource\SkyHook\SkyHookProxy.cs" />
<Compile Include="MetadataSource\TvDbProxy.cs" />
<Compile Include="MetadataSource\SearchSeriesComparer.cs" />
<Compile Include="MetadataSource\Tvdb\TvdbException.cs" />
<Compile Include="MetadataSource\SkyHook\SkyHookException.cs" />
<Compile Include="Metadata\Consumers\MediaBrowser\MediaBrowserMetadata.cs" />
<Compile Include="Metadata\Consumers\MediaBrowser\MediaBrowserMetadataSettings.cs" />
<Compile Include="Metadata\Consumers\Roksbox\RoksboxMetadata.cs" />
@ -961,10 +960,6 @@
<Project>{F2BE0FDF-6E47-4827-A420-DD4EF82407F8}</Project>
<Name>NzbDrone.Common</Name>
</ProjectReference>
<ProjectReference Include="..\TVDBSharp\TVDBSharp.csproj">
<Project>{0cc493d7-0a9f-4199-9615-0a977945d716}</Project>
<Name>TVDBSharp</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="..\..\Logo\64.png">

@ -34,9 +34,6 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceUninstall", "ServiceHelpers\ServiceUninstall\ServiceUninstall.csproj", "{700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Core", "NzbDrone.Core\NzbDrone.Core.csproj", "{FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}"
ProjectSection(ProjectDependencies) = postProject
{0CC493D7-0A9F-4199-9615-0A977945D716} = {0CC493D7-0A9F-4199-9615-0A977945D716}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Update", "NzbDrone.Update\NzbDrone.Update.csproj", "{4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}"
EndProject
@ -91,8 +88,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogentriesNLog", "Logentrie
{90D6E9FC-7B88-4E1B-B018-8FA742274558} = {90D6E9FC-7B88-4E1B-B018-8FA742274558}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TVDBSharp", "TVDBSharp\TVDBSharp.csproj", "{0CC493D7-0A9F-4199-9615-0A977945D716}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
@ -273,12 +268,6 @@ Global
{9DC31DE3-79FF-47A8-96B4-6BA18F6BB1CB}.Mono|x86.Build.0 = Release|x86
{9DC31DE3-79FF-47A8-96B4-6BA18F6BB1CB}.Release|x86.ActiveCfg = Release|x86
{9DC31DE3-79FF-47A8-96B4-6BA18F6BB1CB}.Release|x86.Build.0 = Release|x86
{0CC493D7-0A9F-4199-9615-0A977945D716}.Debug|x86.ActiveCfg = Debug|x86
{0CC493D7-0A9F-4199-9615-0A977945D716}.Debug|x86.Build.0 = Debug|x86
{0CC493D7-0A9F-4199-9615-0A977945D716}.Mono|x86.ActiveCfg = Release|x86
{0CC493D7-0A9F-4199-9615-0A977945D716}.Mono|x86.Build.0 = Release|x86
{0CC493D7-0A9F-4199-9615-0A977945D716}.Release|x86.ActiveCfg = Release|x86
{0CC493D7-0A9F-4199-9615-0A977945D716}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -311,7 +300,6 @@ Global
{411A9E0E-FDC6-4E25-828A-0C2CD1CD96F8} = {F6E3A728-AE77-4D02-BAC8-82FBC1402DDA}
{90D6E9FC-7B88-4E1B-B018-8FA742274558} = {F6E3A728-AE77-4D02-BAC8-82FBC1402DDA}
{9DC31DE3-79FF-47A8-96B4-6BA18F6BB1CB} = {F6E3A728-AE77-4D02-BAC8-82FBC1402DDA}
{0CC493D7-0A9F-4199-9615-0A977945D716} = {F6E3A728-AE77-4D02-BAC8-82FBC1402DDA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EnterpriseLibraryConfigurationToolBinariesPath = packages\Unity.2.1.505.0\lib\NET35;packages\Unity.2.1.505.2\lib\NET35

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>

@ -1,290 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Xml.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using TVDBSharp.Models.DAO;
using TVDBSharp.Models.Enums;
using TVDBSharp.Utilities;
namespace TVDBSharp.Models
{
/// <summary>
/// Provides builder classes for complex entities.
/// </summary>
public class Builder
{
private const string UriPrefix = "http://thetvdb.com/banners/";
private readonly IDataProvider _dataProvider;
/// <summary>
/// Initializes a new Builder object with the given <see cref="IDataProvider" />.
/// </summary>
/// <param name="dataProvider">The DataProvider used to retrieve XML responses.</param>
public Builder(IDataProvider dataProvider)
{
_dataProvider = dataProvider;
}
/// <summary>
/// Builds a show object from the given show ID.
/// </summary>
/// <param name="showID">ID of the show to serialize into a <see cref="Show" /> object.</param>
/// <returns>Returns the Show object.</returns>
public Show BuildShow(int showID)
{
var builder = new ShowBuilder(_dataProvider.GetShow(showID));
return builder.GetResult();
}
public Episode BuildEpisode(int episodeId, string lang)
{
var builder = new EpisodeBuilder(_dataProvider.GetEpisode(episodeId, lang).Descendants("Episode").First());
return builder.GetResult();
}
public Updates BuildUpdates(Interval interval)
{
var builder = new UpdatesBuilder(_dataProvider.GetUpdates(interval));
return builder.GetResult();
}
/// <summary>
/// Returns a list of <see cref="Show" /> objects that match the given query.
/// </summary>
/// <param name="query">Query the search is performed with.</param>
/// <param name="results">Maximal amount of shows the resultset should return.</param>
/// <returns>Returns a list of show objects.</returns>
public List<Show> Search(string query, int results)
{
var shows = new List<Show>();
var doc = _dataProvider.Search(query);
foreach (var element in doc.Descendants("Series").Take(results))
{
var id = int.Parse(element.GetXmlData("seriesid"));
try
{
var response = _dataProvider.GetShow(id);
shows.Add(new ShowBuilder(response).GetResult());
}
catch (HttpException ex)
{
}
}
return shows;
}
private static Uri GetBannerUri(string uriSuffix)
{
if (uriSuffix.IsNullOrWhiteSpace())
{
return null;
}
return new Uri(UriPrefix + uriSuffix, UriKind.Absolute);
}
private class ShowBuilder
{
private readonly Show _show;
public ShowBuilder(XDocument doc)
{
_show = new Show();
_show.Id = int.Parse(doc.GetSeriesData("id"));
_show.ImdbId = doc.GetSeriesData("IMDB_ID");
_show.Name = doc.GetSeriesData("SeriesName");
_show.Language = doc.GetSeriesData("Language");
_show.Network = doc.GetSeriesData("Network");
_show.Description = doc.GetSeriesData("Overview");
_show.Rating = string.IsNullOrWhiteSpace(doc.GetSeriesData("Rating"))
? (decimal?) null
: Convert.ToDecimal(doc.GetSeriesData("Rating"),
System.Globalization.CultureInfo.InvariantCulture);
_show.RatingCount = string.IsNullOrWhiteSpace(doc.GetSeriesData("RatingCount"))
? 0
: Convert.ToInt32(doc.GetSeriesData("RatingCount"));
_show.Runtime = string.IsNullOrWhiteSpace(doc.GetSeriesData("Runtime"))
? (int?) null
: Convert.ToInt32(doc.GetSeriesData("Runtime"));
_show.Banner = GetBannerUri(doc.GetSeriesData("banner"));
_show.Fanart = GetBannerUri(doc.GetSeriesData("fanart"));
_show.LastUpdated = string.IsNullOrWhiteSpace(doc.GetSeriesData("lastupdated"))
? (long?) null
: Convert.ToInt64(doc.GetSeriesData("lastupdated"));
_show.Poster = GetBannerUri(doc.GetSeriesData("poster"));
_show.Zap2ItID = doc.GetSeriesData("zap2it_id");
_show.FirstAired = string.IsNullOrWhiteSpace(doc.GetSeriesData("FirstAired"))
? (DateTime?) null
: Utils.ParseDate(doc.GetSeriesData("FirstAired"));
_show.AirTime = string.IsNullOrWhiteSpace(doc.GetSeriesData("Airs_Time"))
? (TimeSpan?) null
: Utils.ParseTime(doc.GetSeriesData("Airs_Time"));
_show.AirDay = string.IsNullOrWhiteSpace(doc.GetSeriesData("Airs_DayOfWeek"))
? (Frequency?) null
: (Frequency) Enum.Parse(typeof (Frequency), doc.GetSeriesData("Airs_DayOfWeek"));
_show.Status = string.IsNullOrWhiteSpace(doc.GetSeriesData("Status"))
? Status.Unknown
: (Status) Enum.Parse(typeof (Status), doc.GetSeriesData("Status"));
_show.ContentRating = Utils.GetContentRating(doc.GetSeriesData("ContentRating"));
_show.Genres =
new List<string>(doc.GetSeriesData("Genre")
.Split(new[] {'|'}, StringSplitOptions.RemoveEmptyEntries));
_show.Actors =
new List<string>(doc.GetSeriesData("Actors")
.Split(new[] {'|'}, StringSplitOptions.RemoveEmptyEntries));
_show.Episodes = new EpisodesBuilder(doc).BuildEpisodes();
}
public Show GetResult()
{
return _show;
}
}
public class EpisodeBuilder
{
private readonly Episode _episode;
public EpisodeBuilder(XElement episodeNode)
{
_episode = new Episode
{
Id = int.Parse(episodeNode.GetXmlData("id")),
Title = episodeNode.GetXmlData("EpisodeName"),
Description = episodeNode.GetXmlData("Overview"),
AbsoluteEpisodeNumber =
string.IsNullOrWhiteSpace(episodeNode.GetXmlData("absolute_number"))
? (int?)null
: int.Parse(episodeNode.GetXmlData("absolute_number")),
EpisodeNumber = int.Parse(episodeNode.GetXmlData("EpisodeNumber")),
Director = episodeNode.GetXmlData("Director"),
EpisodeImage = GetBannerUri(episodeNode.GetXmlData("filename")),
FirstAired =
string.IsNullOrWhiteSpace(episodeNode.GetXmlData("FirstAired"))
? (DateTime?) null
: Utils.ParseDate(episodeNode.GetXmlData("FirstAired")),
GuestStars =
new List<string>(episodeNode.GetXmlData("GuestStars")
.Split(new[] {'|'}, StringSplitOptions.RemoveEmptyEntries)),
ImdbId = episodeNode.GetXmlData("IMDB_ID"),
Language = episodeNode.GetXmlData("Language"),
LastUpdated =
string.IsNullOrWhiteSpace(episodeNode.GetXmlData("lastupdated"))
? 0L
: Convert.ToInt64(episodeNode.GetXmlData("lastupdated")),
Rating =
string.IsNullOrWhiteSpace(episodeNode.GetXmlData("Rating"))
? (Decimal?) null
: Convert.ToDecimal(episodeNode.GetXmlData("Rating"),
System.Globalization.CultureInfo.InvariantCulture),
RatingCount =
string.IsNullOrWhiteSpace(episodeNode.GetXmlData("RatingCount"))
? 0
: Convert.ToInt32(episodeNode.GetXmlData("RatingCount")),
SeasonId = int.Parse(episodeNode.GetXmlData("seasonid")),
SeasonNumber = int.Parse(episodeNode.GetXmlData("SeasonNumber")),
SeriesId = int.Parse(episodeNode.GetXmlData("seriesid")),
ThumbHeight =
string.IsNullOrWhiteSpace(episodeNode.GetXmlData("thumb_height"))
? (int?) null
: Convert.ToInt32(episodeNode.GetXmlData("thumb_height")),
ThumbWidth =
string.IsNullOrWhiteSpace(episodeNode.GetXmlData("thumb_width"))
? (int?) null
: Convert.ToInt32(episodeNode.GetXmlData("thumb_width")),
TmsExport = episodeNode.GetXmlData("tms_export"),
Writers =
new List<string>(episodeNode.GetXmlData("Writer")
.Split(new[] {'|'}, StringSplitOptions.RemoveEmptyEntries))
};
}
public Episode GetResult()
{
return _episode;
}
}
private class EpisodesBuilder
{
private readonly XDocument _doc;
public EpisodesBuilder(XDocument doc)
{
_doc = doc;
}
public List<Episode> BuildEpisodes()
{
var result = new List<Episode>();
foreach (var episodeNode in _doc.Descendants("Episode"))
{
var episode = new EpisodeBuilder(episodeNode).GetResult();
result.Add(episode);
}
return result;
}
}
public class UpdatesBuilder
{
private readonly Updates _updates;
public UpdatesBuilder(XDocument doc)
{
if (doc.Root != null)
{
_updates = new Updates
{
Time = int.Parse(doc.Root.Attribute("time").Value),
UpdatedSeries = doc.Root.Elements("Series")
.Select(elt => new UpdatedSerie
{
Id = int.Parse(elt.Element("id").Value),
Time = int.Parse(elt.Element("time").Value)
})
.ToList(),
UpdatedEpisodes = doc.Root.Elements("Episode")
.Select(elt => new UpdatedEpisode
{
Id = int.Parse(elt.Element("id").Value),
SerieId = int.Parse(elt.Element("Series").Value),
Time = int.Parse(elt.Element("time").Value)
})
.ToList(),
UpdatedBanners = doc.Root.Elements("Banner")
.Select(elt => new UpdatedBanner
{
SerieId = int.Parse(elt.Element("Series").Value),
Format = elt.Element("format").Value,
Language =
elt.Elements("language").Select(n => n.Value).FirstOrDefault() ?? string.Empty,
Path = elt.Element("path").Value,
Type = elt.Element("type").Value,
SeasonNumber = elt.Elements("SeasonNumber").Any()
? int.Parse(elt.Element("SeasonNumber").Value)
: (int?) null,
Time = int.Parse(elt.Element("time").Value)
})
.ToList()
};
}
}
public Updates GetResult()
{
return _updates;
}
}
}
}

@ -1,55 +0,0 @@
using System.IO;
using System.Net;
using System.Xml.Linq;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Http;
using NzbDrone.Common.Instrumentation;
using TVDBSharp.Models.Enums;
namespace TVDBSharp.Models.DAO
{
/// <summary>
/// Standard implementation of the <see cref="IDataProvider" /> interface.
/// </summary>
public class DataProvider : IDataProvider
{
public string ApiKey { get; set; }
private const string BaseUrl = "http://thetvdb.com";
private static HttpClient httpClient = new HttpClient(new CacheManager(), NzbDroneLogger.GetLogger(typeof(DataProvider)));
public XDocument GetShow(int showID)
{
return GetXDocumentFromUrl(string.Format("{0}/api/{1}/series/{2}/all/en.xml", BaseUrl, ApiKey, showID));
}
public XDocument GetEpisode(int episodeId, string lang)
{
return GetXDocumentFromUrl(string.Format("{0}/api/{1}/episodes/{2}/{3}.xml", BaseUrl, ApiKey, episodeId, lang));
}
public XDocument GetUpdates(Interval interval)
{
return GetXDocumentFromUrl(string.Format("{0}/api/{1}/updates/updates_{2}.xml", BaseUrl, ApiKey, IntervalHelpers.Print(interval)));
}
public XDocument Search(string query)
{
return GetXDocumentFromUrl(string.Format("{0}/api/GetSeries.php?seriesname={1}", BaseUrl, query));
}
private static XDocument GetXDocumentFromUrl(string url)
{
var request = new HttpRequest(url, new HttpAccept("application/xml"));
var response = httpClient.Get(request);
return XDocument.Parse(response.Content);
}
}
}

@ -1,45 +0,0 @@
using System.Xml.Linq;
using TVDBSharp.Models.Enums;
namespace TVDBSharp.Models.DAO
{
/// <summary>
/// Defines a Dataprovider API.
/// </summary>
public interface IDataProvider
{
/// <summary>
/// The API key provided by TVDB.
/// </summary>
string ApiKey { get; set; }
/// <summary>
/// Retrieves the show with the given id and returns the corresponding XML tree.
/// </summary>
/// <param name="showID">ID of the show you wish to lookup.</param>
/// <returns>Returns an XML tree of the show object.</returns>
XDocument GetShow(int showID);
/// <summary>
/// Retrieves the episode with the given id and returns the corresponding XML tree.
/// </summary>
/// <param name="episodeId">ID of the episode to retrieve</param>
/// <param name="lang">ISO 639-1 language code of the episode</param>
/// <returns>XML tree of the episode object</returns>
XDocument GetEpisode(int episodeId, string lang);
/// <summary>
/// Retrieves updates on tvdb (Shows, Episodes and Banners)
/// </summary>
/// <param name="interval">The interval for the updates</param>
/// <returns>XML tree of the Updates object</returns>
XDocument GetUpdates(Interval interval);
/// <summary>
/// Returns an XML tree representing a search query for the given parameter.
/// </summary>
/// <param name="query">Query to perform the search with.</param>
/// <returns>Returns an XML tree of a search result.</returns>
XDocument Search(string query);
}
}

@ -1,43 +0,0 @@
namespace TVDBSharp.Models.Enums
{
/// <summary>
/// Different content ratings. View <c>http://en.wikipedia.org/wiki/TV_Parental_Guidelines</c> for more info.
/// </summary>
public enum ContentRating
{
/// <summary>
/// Not suitable for children under 14.
/// </summary>
TV14,
/// <summary>
/// This program contains material that parents may find unsuitable for younger children.
/// </summary>
TVPG,
/// <summary>
/// This program is designed to be appropriate for all children.
/// </summary>
TVY,
/// <summary>
/// This program is designed for children age 7 and above.
/// </summary>
TVY7,
/// <summary>
/// Most parents would find this program suitable for all ages.
/// </summary>
TVG,
/// <summary>
/// This program is specifically designed to be viewed by adults and therefore may be unsuitable for children under 17.
/// </summary>
TVMA,
/// <summary>
/// Default value if no rating is given.
/// </summary>
Unknown
}
}

@ -1,14 +0,0 @@
namespace TVDBSharp.Models.Enums
{
public enum Frequency
{
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday,
Daily
}
}

@ -1,32 +0,0 @@
using System;
namespace TVDBSharp.Models.Enums
{
public enum Interval
{
Day,
Week,
Month,
All
}
public static class IntervalHelpers
{
public static string Print(Interval interval)
{
switch (interval)
{
case Interval.Day:
return "day";
case Interval.Week:
return "week";
case Interval.Month:
return "month";
case Interval.All:
return "all";
default:
throw new ArgumentException("Unsupported interval enum: " + interval);
}
}
}
}

@ -1,23 +0,0 @@
namespace TVDBSharp.Models.Enums
{
/// <summary>
/// Describes the current status of a show.
/// </summary>
public enum Status
{
/// <summary>
/// No more episodes are being released.
/// </summary>
Ended,
/// <summary>
/// The show is ongoing.
/// </summary>
Continuing,
/// <summary>
/// Default value if no status is specified.
/// </summary>
Unknown
}
}

@ -1,116 +0,0 @@
using System;
using System.Collections.Generic;
namespace TVDBSharp.Models
{
/// <summary>
/// Entity describing an episode of a <see cref="Show" />show.
/// </summary>
public class Episode
{
/// <summary>
/// Unique identifier for an episode.
/// </summary>
public int Id { get; set; }
/// <summary>
/// Director of the episode.
/// </summary>
public string Director { get; set; }
/// <summary>
/// This episode's title.
/// </summary>
public string Title { get; set; }
/// <summary>
/// This episode's absolute number
/// </summary>
public int? AbsoluteEpisodeNumber { get; set; }
/// <summary>
/// This episode's number in the appropriate season.
/// </summary>
public int EpisodeNumber { get; set; }
/// <summary>
/// This episode's season.
/// </summary>
public int SeasonNumber { get; set; }
/// <summary>
/// The date of the first time this episode has aired.
/// </summary>
public DateTime? FirstAired { get; set; }
/// <summary>
/// A list of guest stars.
/// </summary>
public List<string> GuestStars { get; set; }
/// <summary>
/// Unique identifier on IMDb.
/// </summary>
public string ImdbId { get; set; }
/// <summary>
/// Main language spoken in the episode.
/// </summary>
public string Language { get; set; }
/// <summary>
/// A short description of the episode.
/// </summary>
public string Description { get; set; }
/// <summary>
/// Average rating as shown on IMDb.
/// </summary>
public decimal? Rating { get; set; }
/// <summary>
/// Amount of votes cast.
/// </summary>
public int RatingCount { get; set; }
/// <summary>
/// Writers(s) of the episode.
/// </summary>
public List<String> Writers { get; set; }
/// <summary>
/// Let me know if you find out what this is.
/// </summary>
public Uri EpisodeImage { get; set; }
/// <summary>
/// Timestamp of the last update to this episode.
/// </summary>
public long? LastUpdated { get; set; }
/// <summary>
/// Unique identifier of the season.
/// </summary>
public int SeasonId { get; set; }
/// <summary>
/// Unique identifier of the show.
/// </summary>
public int SeriesId { get; set; }
/// <summary>
/// Height dimension of the thumbnail in pixels.
/// </summary>
public int? ThumbHeight { get; set; }
/// <summary>
/// Width dimension of the thumbnail in pixels;
/// </summary>
public int? ThumbWidth { get; set; }
/// <summary>
/// Let me know if you find out what this is.
/// </summary>
public string TmsExport { get; set; }
}
}

@ -1,122 +0,0 @@
using System;
using System.Collections.Generic;
using TVDBSharp.Models.Enums;
namespace TVDBSharp.Models
{
/// <summary>
/// Entity describing a show.
/// </summary>
public class Show
{
/// <summary>
/// Unique identifier used by IMDb.
/// </summary>
public string ImdbId { get; set; }
/// <summary>
/// Unique identifier used by TVDB and TVDBSharp.
/// </summary>
public int Id { get; set; }
/// <summary>
/// List of all actors in the show.
/// </summary>
public List<string> Actors { get; set; }
/// <summary>
/// Day of the week when the show airs.
/// </summary>
public Frequency? AirDay { get; set; }
/// <summary>
/// Time of the day when the show airs.
/// </summary>
public TimeSpan? AirTime { get; set; }
/// <summary>
/// Rating of the content provided by an official organ.
/// </summary>
public ContentRating ContentRating { get; set; }
/// <summary>
/// The date the show aired for the first time.
/// </summary>
public DateTime? FirstAired { get; set; }
/// <summary>
/// A list of genres the show is associated with.
/// </summary>
public List<string> Genres { get; set; }
/// <summary>
/// Main language of the show.
/// </summary>
public string Language { get; set; }
/// <summary>
/// Network that broadcasts the show.
/// </summary>
public string Network { get; set; }
/// <summary>
/// A short overview of the show.
/// </summary>
public string Description { get; set; }
/// <summary>
/// Average rating as shown on IMDb.
/// </summary>
public decimal? Rating { get; set; }
/// <summary>
/// Amount of votes cast.
/// </summary>
public int RatingCount { get; set; }
/// <summary>
/// Let me know if you find out what this is.
/// </summary>
public int? Runtime { get; set; }
/// <summary>
/// Name of the show.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Current status of the show.
/// </summary>
public Status Status { get; set; }
/// <summary>
/// Link to the banner image.
/// </summary>
public Uri Banner { get; set; }
/// <summary>
/// Link to a fanart image.
/// </summary>
public Uri Fanart { get; set; }
/// <summary>
/// Timestamp of the latest update.
/// </summary>
public long? LastUpdated { get; set; }
/// <summary>
/// Let me know if you find out what this is.
/// </summary>
public Uri Poster { get; set; }
/// <summary>
/// No clue
/// </summary>
public string Zap2ItID { get; set; }
/// <summary>
/// A list of all episodes associated with this show.
/// </summary>
public List<Episode> Episodes { get; set; }
}
}

@ -1,49 +0,0 @@
using System;
using System.Collections.Generic;
namespace TVDBSharp.Models
{
public class Updates : UnixTimestampedObject
{
public List<UpdatedBanner> UpdatedBanners { get; set; }
public List<UpdatedEpisode> UpdatedEpisodes { get; set; }
public List<UpdatedSerie> UpdatedSeries { get; set; }
}
public class UnixTimestampedObject
{
private static DateTime _startDate = new DateTime(1970, 1, 1);
private int _unixTimestamp;
public DateTime Timestamp
{
get { return _startDate.AddSeconds(_unixTimestamp); }
}
public int Time
{
set { _unixTimestamp = value; }
}
}
public class UpdatedSerie : UnixTimestampedObject
{
public int Id { get; set; }
}
public class UpdatedEpisode : UnixTimestampedObject
{
public int Id { get; set; }
public int SerieId { get; set; }
}
public class UpdatedBanner : UnixTimestampedObject
{
public int SerieId { get; set; }
public string Format { get; set; }
public string Language { get; set; }
public string Path { get; set; }
public string Type { get; set; }
public int? SeasonNumber { get; set; }
}
}

@ -1,39 +0,0 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("TVDBSharp")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TVDBSharp")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("c78961a8-afda-4a36-910b-bf5a090eebb3")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

@ -1,72 +0,0 @@
using System.Collections.Generic;
using TVDBSharp.Models;
using TVDBSharp.Models.DAO;
using TVDBSharp.Models.Enums;
namespace TVDBSharp
{
/// <summary>
/// The main class which will handle all user interaction.
/// </summary>
public class TVDB
{
private readonly IDataProvider _dataProvider;
/// <summary>
/// Creates a new instance with the provided API key and dataProvider.
/// </summary>
/// <param name="apiKey">The API key provided by TVDB.</param>
/// <param name="dataProvider">Specify your own <see cref="IDataProvider" /> instance.</param>
public TVDB(string apiKey, IDataProvider dataProvider)
{
_dataProvider = dataProvider;
_dataProvider.ApiKey = apiKey;
}
/// <summary>
/// Creates a new instance with the provided API key and standard <see cref="IDataProvider" />.
/// </summary>
/// <param name="apiKey">The API key provided by TVDB.</param>
public TVDB(string apiKey)
{
_dataProvider = new DataProvider {ApiKey = apiKey};
}
/// <summary>
/// Search for a show in the database.
/// </summary>
/// <param name="query">Query that identifies the show.</param>
/// <param name="results">Maximal amount of results in the returning set. Default is 5.</param>
/// <returns>Returns a list of shows.</returns>
public List<Show> Search(string query, int results = 5)
{
return new Builder(_dataProvider).Search(query, results);
}
/// <summary>
/// Get a specific show based on its ID.
/// </summary>
/// <param name="showId">ID of the show.</param>
/// <returns>Returns the corresponding show.</returns>
public Show GetShow(int showId)
{
return new Builder(_dataProvider).BuildShow(showId);
}
/// <summary>
/// Get a specific episode based on its ID.
/// </summary>
/// <param name="episodeId">ID of the episode</param>
/// <param name="lang">ISO 639-1 language code for the episode</param>
/// <returns>The corresponding episode</returns>
public Episode GetEpisode(int episodeId, string lang = "en")
{
return new Builder(_dataProvider).BuildEpisode(episodeId, lang);
}
public Updates GetUpdates(Interval interval)
{
return new Builder(_dataProvider).BuildUpdates(interval);
}
}
}

@ -1,83 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProjectGuid>{0CC493D7-0A9F-4199-9615-0A977945D716}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>TVDBSharp</RootNamespace>
<AssemblyName>TVDBSharp</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="NLog">
<HintPath>..\packages\NLog.2.1.0\lib\net40\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Models\Builder.cs" />
<Compile Include="Models\DAO\DataProvider.cs" />
<Compile Include="Models\DAO\IDataProvider.cs" />
<Compile Include="Models\Enums\ContentRating.cs" />
<Compile Include="Models\Enums\Frequency.cs" />
<Compile Include="Models\Enums\Interval.cs" />
<Compile Include="Models\Enums\Status.cs" />
<Compile Include="Models\Episode.cs" />
<Compile Include="Models\Show.cs" />
<Compile Include="Models\Updates.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TVDB.cs" />
<Compile Include="Utilities\Extensions.cs" />
<Compile Include="Utilities\Utils.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\NzbDrone.Common\NzbDrone.Common.csproj">
<Project>{F2BE0FDF-6E47-4827-A420-DD4EF82407F8}</Project>
<Name>NzbDrone.Common</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

@ -1,58 +0,0 @@
using System.Xml.Linq;
using System.Xml.Schema;
namespace TVDBSharp.Utilities
{
/// <summary>
/// Extension methods used to simplify data extraction.
/// </summary>
public static class Extensions
{
/// <summary>
/// Retrieves a value from an XML tree representing a show.
/// </summary>
/// <param name="doc">XML tree representing a show.</param>
/// <param name="element">Name of the element with the data.</param>
/// <returns>Returns the value corresponding to the given element name.</returns>
/// <exception cref="XmlSchemaException">Thrown when the element doesn't exist or the XML tree is incorrect.</exception>
public static string GetSeriesData(this XDocument doc, string element)
{
var root = doc.Element("Data");
if (root != null)
{
var xElement = root.Element("Series");
if (xElement != null)
{
var result = xElement.Element(element);
if (result != null)
{
return result.Value;
}
throw new XmlSchemaException("Could not find element <" + element + ">");
}
throw new XmlSchemaException("Could not find element <Series>");
}
throw new XmlSchemaException("Could not find element <Data>");
}
/// <summary>
/// Retrieves a value from an XML tree.
/// </summary>
/// <param name="xmlObject">The given XML (sub)tree.</param>
/// <param name="element">Name of the element with the data.</param>
/// <returns>Returns the value corresponding to the given element name;</returns>
/// <exception cref="XmlSchemaException">Thrown when the element doesn't exist.</exception>
public static string GetXmlData(this XElement xmlObject, string element)
{
var result = xmlObject.Element(element);
return result != null ? result.Value : null;
// Removed in favor of returning a null value
// This will allow us to catch a non-existing tag with the null-coalescing operator
// Never trust the XML provider.
//throw new XmlSchemaException("Element <" + element + "> could not be found.");
}
}
}

@ -1,73 +0,0 @@
using System;
using System.Globalization;
using TVDBSharp.Models.Enums;
namespace TVDBSharp.Utilities
{
/// <summary>
/// Provides static utility methods.
/// </summary>
public static class Utils
{
/// <summary>
/// Parses a string of format yyyy-MM-dd to a <see cref="DateTime" /> object.
/// </summary>
/// <param name="value">String to be parsed.</param>
/// <returns>Returns a <see cref="DateTime" /> representation.</returns>
public static DateTime ParseDate(string value)
{
DateTime date;
DateTime.TryParseExact(value, "yyyy-MM-dd", CultureInfo.CurrentCulture, DateTimeStyles.AssumeLocal, out date);
return date;
}
/// <summary>
/// Parses a string of format hh:mm tt to a <see cref="TimeSpan" /> object.
/// </summary>
/// <param name="value">String to be parsed.</param>
/// <returns>Returns a <see cref="TimeSpan" /> representation.</returns>
public static TimeSpan ParseTime(string value)
{
DateTime date;
if (!DateTime.TryParse(value, out date))
{
return new TimeSpan();
}
return date.TimeOfDay;
}
/// <summary>
/// Translates the incoming string to a <see cref="ContentRating" /> enum, if applicable.
/// </summary>
/// <param name="rating">The rating in string format.</param>
/// <returns>Returns the appropriate <see cref="ContentRating" /> value.</returns>
/// <exception cref="ArgumentException">Throws an exception if no conversion could be applied.</exception>
public static ContentRating GetContentRating(string rating)
{
switch (rating)
{
case "TV-14":
return ContentRating.TV14;
case "TV-PG":
return ContentRating.TVPG;
case "TV-Y":
return ContentRating.TVY;
case "TV-Y7":
return ContentRating.TVY7;
case "TV-G":
return ContentRating.TVG;
case "TV-MA":
return ContentRating.TVMA;
default:
return ContentRating.Unknown;
}
}
}
}
Loading…
Cancel
Save