Metadata coming together for XBMC

This commit is contained in:
Mark McDowall 2012-07-09 21:37:24 -07:00
parent 8263ab1d0f
commit b50e16a456
10 changed files with 317 additions and 66 deletions

View File

@ -200,6 +200,10 @@ namespace NzbDrone.Common
return File.ReadAllText(filePath);
}
public virtual void WriteAllText(string filename, string contents)
{
File.WriteAllText(filename, contents);
}
public static bool PathEquals(string firstPath, string secondPath)
{

View File

@ -0,0 +1,21 @@
using System.Data;
using Migrator.Framework;
namespace NzbDrone.Core.Datastore.Migrations
{
[Migration(20120707)]
public class Migration20120707 : NzbDroneMigration
{
protected override void MainDbUpgrade()
{
Database.AddTable("MetadataDefinitions", new[]
{
new Column("Id", DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity),
new Column("Enable", DbType.Boolean, ColumnProperty.NotNull),
new Column("MetadataProviderType", DbType.String, ColumnProperty.NotNull),
new Column("Name", DbType.String, ColumnProperty.NotNull)
});
}
}
}

View File

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Text;
namespace NzbDrone.Core.Model
namespace NzbDrone.Core.Model.Metadata
{
public class MisnamedEpisodeModel
{

View File

@ -81,5 +81,22 @@ namespace NzbDrone.Core.Providers
}
return true;
}
public virtual void Download(string remotePath, string filename)
{
var url = BANNER_URL_PREFIX + remotePath;
try
{
_httpProvider.DownloadFile(url, filename);
logger.Trace("Successfully download banner from '{0}' to '{1}'", url, filename);
}
catch (Exception ex)
{
var message = String.Format("Failed to download Banner from '{0}' to '{1}'", url, filename);
logger.DebugException(message, ex);
throw;
}
}
}
}

View File

@ -501,6 +501,27 @@ namespace NzbDrone.Core.Providers.Core
set { SetValue("PlexPassword", value); }
}
public virtual Boolean MetadataEnabled
{
get { return GetValueBoolean("MetadataEnabled"); }
set { SetValue("MetadataEnabled", value); }
}
public virtual Boolean MetadataXbmcEnabled
{
get { return GetValueBoolean("MetadataXbmcEnabled"); }
set { SetValue("MetadataXbmcEnabled", value); }
}
public virtual Boolean MetadataUseBanners
{
get { return GetValueBoolean("MetadataUseBanners"); }
set { SetValue("MetadataUseBanners", value); }
}
private string GetValue(string key)
{
return GetValue(key, String.Empty);

View File

@ -1,8 +1,10 @@
using System;
using NLog;
using NzbDrone.Common;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
using TvdbLib.Data;
namespace NzbDrone.Core.Providers.Metadata
{
@ -10,43 +12,42 @@ namespace NzbDrone.Core.Providers.Metadata
{
protected readonly Logger _logger;
protected readonly ConfigProvider _configProvider;
protected readonly DiskProvider _diskProvider;
protected readonly BannerProvider _bannerProvider;
protected readonly EpisodeProvider _episodeProvider;
protected MetadataBase(ConfigProvider configProvider)
protected MetadataBase(ConfigProvider configProvider, DiskProvider diskProvider,
BannerProvider bannerProvider, EpisodeProvider episodeProvider)
{
_configProvider = configProvider;
_diskProvider = diskProvider;
_bannerProvider = bannerProvider;
_episodeProvider = episodeProvider;
_logger = LogManager.GetLogger(GetType().ToString());
}
/// <summary>
/// Gets the name for the notification provider
/// Gets the name for the metabase provider
/// </summary>
public abstract string Name { get; }
/// <summary>
/// Performs the on grab action
/// Creates metadata for a series
/// </summary>
/// <param name = "message">The message to send to the receiver</param>
public abstract void OnGrab(string message);
/// <param name = "series">The series to create the metadata for</param>
/// <param name = "tvDbSeries">Series information from TheTvDb</param>
public abstract void ForSeries(Series series, TvdbSeries tvDbSeries);
/// <summary>
/// Performs the on download action
/// Creates metadata for the episode file
/// </summary>
/// <param name = "message">The message to send to the receiver</param>
/// <param name = "series">The Series for the new download</param>
public abstract void OnDownload(string message, Series series);
/// <param name = "episodeFile">The episode file to create the metadata</param>
/// <param name = "tvDbSeries">Series information from TheTvDb</param>
public abstract void ForEpisodeFile(EpisodeFile episodeFile, TvdbSeries tvDbSeries);
/// <summary>
/// Performs the on rename action
/// </summary>
/// <param name = "message">The message to send to the receiver</param>
/// <param name = "series">The Series for the new download</param>
public abstract void OnRename(string message, Series series);
/// <summary>
/// Performs the after rename action, this will be handled after all renaming for episode/season/series
/// </summary>
/// <param name = "message">The message to send to the receiver</param>
/// <param name = "series">The Series for the new download</param>
public abstract void AfterRename(string message, Series series);
public virtual string GetEpisodeGuideUrl(int seriesId)
{
return String.Format("http://www.thetvdb.com/api/{0}/series/{1}/all/en.zip", TvDbProvider.TVDB_APIKEY, seriesId);
}
}
}

View File

@ -0,0 +1,199 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using NLog;
using NzbDrone.Common;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
using TvdbLib.Data;
using TvdbLib.Data.Banner;
namespace NzbDrone.Core.Providers.Metadata
{
public abstract class Xbmc : MetadataBase
{
protected readonly Logger _logger;
public Xbmc(ConfigProvider configProvider, DiskProvider diskProvider, BannerProvider bannerProvider, EpisodeProvider episodeProvider)
: base(configProvider, diskProvider, bannerProvider, episodeProvider)
{
}
public override string Name
{
get { return "XBMC"; }
}
public override void ForSeries(Series series, TvdbSeries tvDbSeries)
{
//Create tvshow.nfo, fanart.jpg, folder.jpg and searon##.tbn
var episodeGuideUrl = GetEpisodeGuideUrl(series.SeriesId);
_logger.Debug("Generating tvshow.nfo for: {0}", series.Title);
var sb = new StringBuilder();
var xws = new XmlWriterSettings();
xws.OmitXmlDeclaration = false;
xws.Indent = false;
using (var xw = XmlWriter.Create(sb, xws))
{
var tvShow = new XElement("tvshow");
tvShow.Add(new XElement("title", tvDbSeries.SeriesName));
tvShow.Add(new XElement("rating", tvDbSeries.Rating));
tvShow.Add(new XElement("plot", tvDbSeries.Overview));
tvShow.Add(new XElement("episodeguide", new XElement("url"), episodeGuideUrl));
tvShow.Add(new XElement("episodeguideurl", episodeGuideUrl));
tvShow.Add(new XElement("mpaa", tvDbSeries.ContentRating));
tvShow.Add(new XElement("genre", tvDbSeries.GenreString));
tvShow.Add(new XElement("premiered", tvDbSeries.FirstAired.ToString("yyyy-MM-dd")));
tvShow.Add(new XElement("studio", tvDbSeries.Network));
foreach(var actor in tvDbSeries.TvdbActors)
{
tvShow.Add(new XElement("actor",
new XElement("name", actor.Name),
new XElement("role", actor.Role),
new XElement("thumb", actor.ActorImage)
));
}
var doc = new XDocument(tvShow);
doc.Save(xw);
}
_logger.Debug("Saving tvshow.nfo for {0}", series.Title);
_diskProvider.WriteAllText(Path.Combine(series.Path, "tvshow.nfo"), sb.ToString());
_logger.Debug("Downloading fanart for: {0}", series.Title);
_bannerProvider.Download(tvDbSeries.FanartPath, Path.Combine(series.Path, "fanart.jpg"));
if (!_configProvider.MetadataUseBanners)
{
_logger.Debug("Downloading series thumbnail for: {0}", series.Title);
_bannerProvider.Download(tvDbSeries.PosterPath, "folder.jpg");
_logger.Debug("Downloading Season posters for {0}", series.Title);
DownloadSeasonThumbnails(series, tvDbSeries, TvdbSeasonBanner.Type.season);
}
else
{
_logger.Debug("Downloading series banner for: {0}", series.Title);
_bannerProvider.Download(tvDbSeries.BannerPath, "folder.jpg");
_logger.Debug("Downloading Season banners for {0}", series.Title);
DownloadSeasonThumbnails(series, tvDbSeries, TvdbSeasonBanner.Type.seasonwide);
}
}
public override void ForEpisodeFile(EpisodeFile episodeFile, TvdbSeries tvDbSeries)
{
//Download filename.tbn and filename.nfo
//Use BannerPath for Thumbnail
var episodes = _episodeProvider.GetEpisodesByFileId(episodeFile.EpisodeFileId);
if (!episodes.Any())
{
_logger.Debug("No episodes where found for this episode file: {0}", episodeFile.EpisodeFileId);
return;
}
var episodeFileThumbnail = tvDbSeries.Episodes.FirstOrDefault(
e =>
e.SeasonNumber == episodeFile.SeasonNumber &&
e.EpisodeNumber == episodes.First().EpisodeNumber);
if (episodeFileThumbnail == null || String.IsNullOrWhiteSpace(episodeFileThumbnail.BannerPath))
{
_logger.Debug("No thumbnail is available for this episode");
return;
}
_logger.Debug("Downloading episode thumbnail for: {0}", episodeFile.EpisodeFileId);
_bannerProvider.Download(episodeFileThumbnail.BannerPath, "folder.jpg");
_logger.Debug("Generating filename.nfo for: {0}", episodeFile.EpisodeFileId);
var sb = new StringBuilder();
var xws = new XmlWriterSettings();
xws.OmitXmlDeclaration = false;
xws.Indent = false;
using (var xw = XmlWriter.Create(sb, xws))
{
var doc = new XDocument();
foreach (var episode in episodes)
{
var tvdbEpisode =
tvDbSeries.Episodes.FirstOrDefault(
e =>
e.SeasonNumber == episode.SeasonNumber &&
e.EpisodeNumber == episode.EpisodeNumber);
if (tvdbEpisode == null)
{
_logger.Debug("Unable to find episode from TvDb - skipping");
return;
}
var details = new XElement("episodedetails");
details.Add(new XElement("title", tvdbEpisode.EpisodeName));
details.Add(new XElement("season", tvdbEpisode.SeasonNumber));
details.Add(new XElement("episode", tvdbEpisode.EpisodeNumber));
details.Add(new XElement("aired", tvdbEpisode.FirstAired));
details.Add(new XElement("plot", tvDbSeries.Overview));
details.Add(new XElement("displayseason"));
details.Add(new XElement("displayepisode"));
details.Add(new XElement("thumb", "http://www.thetvdb.com/banners/" + tvdbEpisode.BannerPath));
details.Add(new XElement("watched", "false"));
details.Add(new XElement("credits", tvdbEpisode.Writer.First()));
details.Add(new XElement("director", tvdbEpisode.Directors.First()));
details.Add(new XElement("rating", tvDbSeries.Rating));
foreach(var actor in tvdbEpisode.GuestStars)
{
if (!String.IsNullOrWhiteSpace(actor))
continue;
details.Add(new XElement("actor",
new XElement("name", actor)
));
}
foreach(var actor in tvDbSeries.TvdbActors)
{
details.Add(new XElement("actor",
new XElement("name", actor.Name),
new XElement("role", actor.Role),
new XElement("thumb", actor.ActorImage)
));
}
doc.Add(details);
doc.Save(xw);
}
}
var filename = Path.GetFileNameWithoutExtension(episodeFile.Path) + ".nfo";
_logger.Debug("Saving episodedetails to: {0}", filename);
_diskProvider.WriteAllText(filename, sb.ToString());
}
private void DownloadSeasonThumbnails(Series series, TvdbSeries tvDbSeries, TvdbSeasonBanner.Type bannerType)
{
var seasons = tvDbSeries.SeasonBanners.Where(s => s.BannerType == bannerType).Select(s => s.Season);
foreach (var season in seasons)
{
var banner = tvDbSeries.SeasonBanners.FirstOrDefault(b => b.BannerType == bannerType && b.Season == season);
_logger.Debug("Downloading banner for Season: {0} Series: {1}", season, series.Title);
_bannerProvider.Download(banner.BannerPath,
Path.Combine(series.Path, String.Format("season{0:00}.tbn", season)));
}
}
}
}

View File

@ -16,13 +16,15 @@ namespace NzbDrone.Core.Providers
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly IDatabase _database;
private IEnumerable<MetadataBase> _metadataBases;
private IEnumerable<MetadataBase> _metadataProviders;
private readonly TvDbProvider _tvDbProvider;
[Inject]
public MetadataProvider(IDatabase database, IEnumerable<MetadataBase> metadataBases)
public MetadataProvider(IDatabase database, IEnumerable<MetadataBase> metadataProviders, TvDbProvider tvDbProvider)
{
_database = database;
_metadataBases = metadataBases;
_metadataProviders = metadataProviders;
_tvDbProvider = tvDbProvider;
}
public MetadataProvider()
@ -30,12 +32,12 @@ namespace NzbDrone.Core.Providers
}
public virtual List<MetabaseDefinition> All()
public virtual List<MetadataDefinition> All()
{
return _database.Fetch<MetabaseDefinition>();
return _database.Fetch<MetadataDefinition>();
}
public virtual void SaveSettings(MetabaseDefinition settings)
public virtual void SaveSettings(MetadataDefinition settings)
{
if (settings.Id == 0)
{
@ -50,31 +52,31 @@ namespace NzbDrone.Core.Providers
}
}
public virtual MetabaseDefinition GetSettings(Type type)
public virtual MetadataDefinition GetSettings(Type type)
{
return _database.SingleOrDefault<MetabaseDefinition>("WHERE MetadataProviderType = @0", type.ToString());
return _database.SingleOrDefault<MetadataDefinition>("WHERE MetadataProviderType = @0", type.ToString());
}
public virtual IList<MetadataBase> GetEnabledExternalNotifiers()
public virtual IList<MetadataBase> GetEnabledMetabaseProviders()
{
var all = All();
return _metadataBases.Where(i => all.Exists(c => c.MetadataProviderType == i.GetType().ToString() && c.Enable)).ToList();
return _metadataProviders.Where(i => all.Exists(c => c.MetadataProviderType == i.GetType().ToString() && c.Enable)).ToList();
}
public virtual void InitializeNotifiers(IList<MetadataBase> notifiers)
public virtual void Initialize(IList<MetadataBase> metabaseProviders)
{
Logger.Debug("Initializing notifiers. Count {0}", notifiers.Count);
Logger.Debug("Initializing metabases. Count {0}", metabaseProviders.Count);
_metadataBases = notifiers;
_metadataProviders = metabaseProviders;
var currentNotifiers = All();
foreach (var notificationProvider in notifiers)
foreach (var notificationProvider in metabaseProviders)
{
MetadataBase metadataProviderLocal = notificationProvider;
if (!currentNotifiers.Exists(c => c.MetadataProviderType == metadataProviderLocal.GetType().ToString()))
{
var settings = new MetabaseDefinition
var settings = new MetadataDefinition
{
Enable = false,
MetadataProviderType = metadataProviderLocal.GetType().ToString(),
@ -86,35 +88,23 @@ namespace NzbDrone.Core.Providers
}
}
public virtual void OnGrab(string message)
public virtual void CreateForSeries(Series series)
{
foreach (var notifier in _metadataBases.Where(i => GetSettings(i.GetType()).Enable))
var tvDbSeries = _tvDbProvider.GetSeries(series.SeriesId, false, true);
foreach (var provider in _metadataProviders.Where(i => GetSettings(i.GetType()).Enable))
{
notifier.OnGrab(message);
provider.ForSeries(series, tvDbSeries);
}
}
public virtual void OnDownload(string message, Series series)
public virtual void CreateForEpisodeFile(EpisodeFile episodeFile)
{
foreach (var notifier in _metadataBases.Where(i => GetSettings(i.GetType()).Enable))
{
notifier.OnDownload(message, series);
}
}
var tvDbSeries = _tvDbProvider.GetSeries(episodeFile.SeriesId, true, true);
public virtual void OnRename(string message, Series series)
foreach (var provider in _metadataProviders.Where(i => GetSettings(i.GetType()).Enable))
{
foreach (var notifier in _metadataBases.Where(i => GetSettings(i.GetType()).Enable))
{
notifier.OnRename(message, series);
}
}
public virtual void AfterRename(string message, Series series)
{
foreach (var notifier in _metadataBases.Where(i => GetSettings(i.GetType()).Enable))
{
notifier.AfterRename(message, series);
provider.ForEpisodeFile(episodeFile, tvDbSeries);
}
}
}

View File

@ -14,7 +14,7 @@ namespace NzbDrone.Core.Providers
public class TvDbProvider
{
private readonly EnvironmentProvider _environmentProvider;
private const string TVDB_APIKEY = "5D2D188E86E07F4F";
public const string TVDB_APIKEY = "5D2D188E86E07F4F";
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly TvdbHandler _handler;
@ -44,13 +44,12 @@ namespace NzbDrone.Core.Providers
}
}
public virtual TvdbSeries GetSeries(int id, bool loadEpisodes)
public virtual TvdbSeries GetSeries(int id, bool loadEpisodes, bool loadActors = false)
{
lock (_handler)
{
Logger.Debug("Fetching SeriesId'{0}' from tvdb", id);
var result = _handler.GetSeries(id, TvdbLanguage.DefaultLanguage, loadEpisodes, false, true, true);
var result = _handler.GetSeries(id, TvdbLanguage.DefaultLanguage, loadEpisodes, loadActors, true, true);
//Fix American Dad's scene gongshow
if (result != null && result.Id == 73141)
@ -86,6 +85,5 @@ namespace NzbDrone.Core.Providers
return result;
}
}
}
}

View File

@ -2,9 +2,9 @@
namespace NzbDrone.Core.Repository
{
[TableName("MetabaseDefinitions")]
[TableName("MetadataDefinitions")]
[PrimaryKey("Id", autoIncrement = true)]
public class MetabaseDefinition
public class MetadataDefinition
{
public int Id { get; set; }