mirror of
https://github.com/Readarr/Readarr.git
synced 2026-04-25 22:36:59 -04:00
Refactor ExtraFile/MetadataFile Services (#104)
* Preliminary Work for Extras for Music * DB Migration for ExtraFiles, Other Cleanup * More Extras Work, Add Album Metadata Type * Update Housekeeps for Music Extras * Fix HouseKeeper and add new Tests * Final round of Cleanup
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -9,7 +9,7 @@ using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Extras.Metadata.Files;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace NzbDrone.Core.Extras.Metadata.Consumers.MediaBrowser
|
||||
{
|
||||
@@ -25,7 +25,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.MediaBrowser
|
||||
|
||||
public override string Name => "Emby (Legacy)";
|
||||
|
||||
public override MetadataFile FindMetadataFile(Series series, string path)
|
||||
public override MetadataFile FindMetadataFile(Artist artist, string path)
|
||||
{
|
||||
var filename = Path.GetFileName(path);
|
||||
|
||||
@@ -33,28 +33,28 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.MediaBrowser
|
||||
|
||||
var metadata = new MetadataFile
|
||||
{
|
||||
SeriesId = series.Id,
|
||||
ArtistId = artist.Id,
|
||||
Consumer = GetType().Name,
|
||||
RelativePath = series.Path.GetRelativePath(path)
|
||||
RelativePath = artist.Path.GetRelativePath(path)
|
||||
};
|
||||
|
||||
if (filename.Equals("series.xml", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (filename.Equals("artist.xml", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
metadata.Type = MetadataType.SeriesMetadata;
|
||||
metadata.Type = MetadataType.ArtistMetadata;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override MetadataFileResult SeriesMetadata(Series series)
|
||||
public override MetadataFileResult ArtistMetadata(Artist artist)
|
||||
{
|
||||
if (!Settings.SeriesMetadata)
|
||||
if (!Settings.ArtistMetadata)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
_logger.Debug("Generating series.xml for: {0}", series.Title);
|
||||
_logger.Debug("Generating artist.xml for: {0}", artist.Name);
|
||||
var sb = new StringBuilder();
|
||||
var xws = new XmlWriterSettings();
|
||||
xws.OmitXmlDeclaration = true;
|
||||
@@ -62,85 +62,73 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.MediaBrowser
|
||||
|
||||
using (var xw = XmlWriter.Create(sb, xws))
|
||||
{
|
||||
var tvShow = new XElement("Series");
|
||||
var artistElement = new XElement("Artist");
|
||||
|
||||
tvShow.Add(new XElement("id", series.TvdbId));
|
||||
tvShow.Add(new XElement("Status", series.Status));
|
||||
tvShow.Add(new XElement("Network", series.Network));
|
||||
tvShow.Add(new XElement("Airs_Time", series.AirTime));
|
||||
artistElement.Add(new XElement("id", artist.ForeignArtistId));
|
||||
artistElement.Add(new XElement("Status", artist.Status));
|
||||
|
||||
if (series.FirstAired.HasValue)
|
||||
{
|
||||
tvShow.Add(new XElement("FirstAired", series.FirstAired.Value.ToString("yyyy-MM-dd")));
|
||||
}
|
||||
artistElement.Add(new XElement("Added", artist.Added.ToString("MM/dd/yyyy HH:mm:ss tt")));
|
||||
artistElement.Add(new XElement("LockData", "false"));
|
||||
artistElement.Add(new XElement("Overview", artist.Overview));
|
||||
artistElement.Add(new XElement("LocalTitle", artist.Name));
|
||||
|
||||
tvShow.Add(new XElement("ContentRating", series.Certification));
|
||||
tvShow.Add(new XElement("Added", series.Added.ToString("MM/dd/yyyy HH:mm:ss tt")));
|
||||
tvShow.Add(new XElement("LockData", "false"));
|
||||
tvShow.Add(new XElement("Overview", series.Overview));
|
||||
tvShow.Add(new XElement("LocalTitle", series.Title));
|
||||
|
||||
if (series.FirstAired.HasValue)
|
||||
{
|
||||
tvShow.Add(new XElement("PremiereDate", series.FirstAired.Value.ToString("yyyy-MM-dd")));
|
||||
}
|
||||
|
||||
tvShow.Add(new XElement("Rating", series.Ratings.Value));
|
||||
tvShow.Add(new XElement("ProductionYear", series.Year));
|
||||
tvShow.Add(new XElement("RunningTime", series.Runtime));
|
||||
tvShow.Add(new XElement("IMDB", series.ImdbId));
|
||||
tvShow.Add(new XElement("TVRageId", series.TvRageId));
|
||||
tvShow.Add(new XElement("Genres", series.Genres.Select(genre => new XElement("Genre", genre))));
|
||||
artistElement.Add(new XElement("Rating", artist.Ratings.Value));
|
||||
artistElement.Add(new XElement("Genres", artist.Genres.Select(genre => new XElement("Genre", genre))));
|
||||
|
||||
var persons = new XElement("Persons");
|
||||
|
||||
foreach (var person in series.Actors)
|
||||
foreach (var person in artist.Members)
|
||||
{
|
||||
persons.Add(new XElement("Person",
|
||||
new XElement("Name", person.Name),
|
||||
new XElement("Type", "Actor"),
|
||||
new XElement("Role", person.Character)
|
||||
new XElement("Role", person.Instrument)
|
||||
));
|
||||
}
|
||||
|
||||
tvShow.Add(persons);
|
||||
artistElement.Add(persons);
|
||||
|
||||
|
||||
var doc = new XDocument(tvShow);
|
||||
var doc = new XDocument(artistElement);
|
||||
doc.Save(xw);
|
||||
|
||||
_logger.Debug("Saving series.xml for {0}", series.Title);
|
||||
_logger.Debug("Saving artist.xml for {0}", artist.Name);
|
||||
|
||||
return new MetadataFileResult("series.xml", doc.ToString());
|
||||
return new MetadataFileResult("artist.xml", doc.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public override MetadataFileResult EpisodeMetadata(Series series, EpisodeFile episodeFile)
|
||||
|
||||
public override MetadataFileResult AlbumMetadata(Artist artist, Album album)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override MetadataFileResult TrackMetadata(Artist artist, TrackFile trackFile)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> SeriesImages(Series series)
|
||||
public override List<ImageFileResult> ArtistImages(Artist artist)
|
||||
{
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> SeasonImages(Series series, Season season)
|
||||
public override List<ImageFileResult> AlbumImages(Artist artist, Album season)
|
||||
{
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> EpisodeImages(Series series, EpisodeFile episodeFile)
|
||||
public override List<ImageFileResult> TrackImages(Artist artist, TrackFile trackFile)
|
||||
{
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
private IEnumerable<ImageFileResult> ProcessSeriesImages(Series series)
|
||||
private IEnumerable<ImageFileResult> ProcessArtistImages(Artist artist)
|
||||
{
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
private IEnumerable<ImageFileResult> ProcessSeasonImages(Series series, Season season)
|
||||
private IEnumerable<ImageFileResult> ProcessAlbumImages(Artist artist, Album album)
|
||||
{
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
@@ -155,4 +143,4 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.MediaBrowser
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -18,11 +18,11 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.MediaBrowser
|
||||
|
||||
public MediaBrowserMetadataSettings()
|
||||
{
|
||||
SeriesMetadata = true;
|
||||
ArtistMetadata = true;
|
||||
}
|
||||
|
||||
[FieldDefinition(0, Label = "Artist Metadata", Type = FieldType.Checkbox, HelpText = "series.xml")]
|
||||
public bool SeriesMetadata { get; set; }
|
||||
[FieldDefinition(0, Label = "Artist Metadata", Type = FieldType.Checkbox, HelpText = "artist.xml")]
|
||||
public bool ArtistMetadata { get; set; }
|
||||
|
||||
public bool IsValid => true;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -12,7 +12,7 @@ using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Extras.Metadata.Files;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
||||
{
|
||||
@@ -36,25 +36,25 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
||||
|
||||
public override string Name => "Roksbox";
|
||||
|
||||
public override string GetFilenameAfterMove(Series series, EpisodeFile episodeFile, MetadataFile metadataFile)
|
||||
public override string GetFilenameAfterMove(Artist artist, TrackFile trackFile, MetadataFile metadataFile)
|
||||
{
|
||||
var episodeFilePath = Path.Combine(series.Path, episodeFile.RelativePath);
|
||||
var trackFilePath = Path.Combine(artist.Path, trackFile.RelativePath);
|
||||
|
||||
if (metadataFile.Type == MetadataType.EpisodeImage)
|
||||
if (metadataFile.Type == MetadataType.TrackImage)
|
||||
{
|
||||
return GetEpisodeImageFilename(episodeFilePath);
|
||||
return GetTrackImageFilename(trackFilePath);
|
||||
}
|
||||
|
||||
if (metadataFile.Type == MetadataType.EpisodeMetadata)
|
||||
if (metadataFile.Type == MetadataType.TrackMetadata)
|
||||
{
|
||||
return GetEpisodeMetadataFilename(episodeFilePath);
|
||||
return GetTrackMetadataFilename(trackFilePath);
|
||||
}
|
||||
|
||||
_logger.Debug("Unknown episode file metadata: {0}", metadataFile.RelativePath);
|
||||
return Path.Combine(series.Path, metadataFile.RelativePath);
|
||||
_logger.Debug("Unknown track file metadata: {0}", metadataFile.RelativePath);
|
||||
return Path.Combine(artist.Path, metadataFile.RelativePath);
|
||||
}
|
||||
|
||||
public override MetadataFile FindMetadataFile(Series series, string path)
|
||||
public override MetadataFile FindMetadataFile(Artist artist, string path)
|
||||
{
|
||||
var filename = Path.GetFileName(path);
|
||||
|
||||
@@ -63,9 +63,9 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
||||
|
||||
var metadata = new MetadataFile
|
||||
{
|
||||
SeriesId = series.Id,
|
||||
ArtistId = artist.Id,
|
||||
Consumer = GetType().Name,
|
||||
RelativePath = series.Path.GetRelativePath(path)
|
||||
RelativePath = artist.Path.GetRelativePath(path)
|
||||
};
|
||||
|
||||
//Series and season images are both named folder.jpg, only season ones sit in season folders
|
||||
@@ -75,22 +75,22 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
||||
|
||||
if (seasonMatch.Success)
|
||||
{
|
||||
metadata.Type = MetadataType.SeasonImage;
|
||||
metadata.Type = MetadataType.AlbumImage;
|
||||
|
||||
if (seasonMatch.Groups["specials"].Success)
|
||||
{
|
||||
metadata.SeasonNumber = 0;
|
||||
metadata.AlbumId = 0;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
metadata.SeasonNumber = Convert.ToInt32(seasonMatch.Groups["season"].Value);
|
||||
metadata.AlbumId = Convert.ToInt32(seasonMatch.Groups["season"].Value);
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
metadata.Type = MetadataType.SeriesImage;
|
||||
metadata.Type = MetadataType.ArtistImage;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
||||
|
||||
if (extension == ".xml")
|
||||
{
|
||||
metadata.Type = MetadataType.EpisodeMetadata;
|
||||
metadata.Type = MetadataType.TrackMetadata;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
||||
{
|
||||
if (!Path.GetFileNameWithoutExtension(filename).EndsWith("-thumb"))
|
||||
{
|
||||
metadata.Type = MetadataType.EpisodeImage;
|
||||
metadata.Type = MetadataType.TrackImage;
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
@@ -120,23 +120,28 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
||||
return null;
|
||||
}
|
||||
|
||||
public override MetadataFileResult SeriesMetadata(Series series)
|
||||
public override MetadataFileResult ArtistMetadata(Artist artist)
|
||||
{
|
||||
//Series metadata is not supported
|
||||
//Artist metadata is not supported
|
||||
return null;
|
||||
}
|
||||
|
||||
public override MetadataFileResult EpisodeMetadata(Series series, EpisodeFile episodeFile)
|
||||
public override MetadataFileResult AlbumMetadata(Artist artist, Album album)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override MetadataFileResult TrackMetadata(Artist artist, TrackFile trackFile)
|
||||
{
|
||||
if (!Settings.EpisodeMetadata)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
_logger.Debug("Generating Episode Metadata for: {0}", episodeFile.RelativePath);
|
||||
_logger.Debug("Generating Track Metadata for: {0}", trackFile.RelativePath);
|
||||
|
||||
var xmlResult = string.Empty;
|
||||
foreach (var episode in episodeFile.Episodes.Value)
|
||||
foreach (var track in trackFile.Tracks.Value)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var xws = new XmlWriterSettings();
|
||||
@@ -148,24 +153,10 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
||||
var doc = new XDocument();
|
||||
|
||||
var details = new XElement("video");
|
||||
details.Add(new XElement("title", string.Format("{0} - {1}x{2} - {3}", series.Title, episode.SeasonNumber, episode.EpisodeNumber, episode.Title)));
|
||||
details.Add(new XElement("year", episode.AirDate));
|
||||
details.Add(new XElement("genre", string.Join(" / ", series.Genres)));
|
||||
var actors = string.Join(" , ", series.Actors.ConvertAll(c => c.Name + " - " + c.Character).GetRange(0, Math.Min(3, series.Actors.Count)));
|
||||
details.Add(new XElement("title", string.Format("{0} - {1} - {2}", artist.Name, track.TrackNumber, track.Title)));
|
||||
details.Add(new XElement("genre", string.Join(" / ", artist.Genres)));
|
||||
var actors = string.Join(" , ", artist.Members.ConvertAll(c => c.Name + " - " + c.Instrument).GetRange(0, Math.Min(3, artist.Members.Count)));
|
||||
details.Add(new XElement("actors", actors));
|
||||
details.Add(new XElement("description", episode.Overview));
|
||||
details.Add(new XElement("length", series.Runtime));
|
||||
|
||||
if (series.Certification.IsNotNullOrWhiteSpace() &&
|
||||
ValidCertification.Contains(series.Certification.ToUpperInvariant()))
|
||||
{
|
||||
details.Add(new XElement("mpaa", series.Certification.ToUpperInvariant()));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
details.Add(new XElement("mpaa", "UNRATED"));
|
||||
}
|
||||
|
||||
doc.Add(details);
|
||||
doc.Save(xw);
|
||||
@@ -175,77 +166,78 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
||||
}
|
||||
}
|
||||
|
||||
return new MetadataFileResult(GetEpisodeMetadataFilename(episodeFile.RelativePath), xmlResult.Trim(Environment.NewLine.ToCharArray()));
|
||||
return new MetadataFileResult(GetTrackMetadataFilename(trackFile.RelativePath), xmlResult.Trim(Environment.NewLine.ToCharArray()));
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> SeriesImages(Series series)
|
||||
public override List<ImageFileResult> ArtistImages(Artist artist)
|
||||
{
|
||||
var image = series.Images.SingleOrDefault(c => c.CoverType == MediaCoverTypes.Poster) ?? series.Images.FirstOrDefault();
|
||||
var image = artist.Images.SingleOrDefault(c => c.CoverType == MediaCoverTypes.Poster) ?? artist.Images.FirstOrDefault();
|
||||
if (image == null)
|
||||
{
|
||||
_logger.Trace("Failed to find suitable Series image for series {0}.", series.Title);
|
||||
_logger.Trace("Failed to find suitable Artist image for artist {0}.", artist.Name);
|
||||
return null;
|
||||
}
|
||||
|
||||
var source = _mediaCoverService.GetCoverPath(series.Id, image.CoverType);
|
||||
var destination = Path.GetFileName(series.Path) + Path.GetExtension(source);
|
||||
var source = _mediaCoverService.GetCoverPath(artist.Id, image.CoverType);
|
||||
var destination = Path.GetFileName(artist.Path) + Path.GetExtension(source);
|
||||
|
||||
return new List<ImageFileResult>{ new ImageFileResult(destination, source) };
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> SeasonImages(Series series, Season season)
|
||||
public override List<ImageFileResult> AlbumImages(Artist artist, Album album)
|
||||
{
|
||||
var seasonFolders = GetSeasonFolders(series);
|
||||
var seasonFolders = GetAlbumFolders(artist);
|
||||
|
||||
string seasonFolder;
|
||||
if (!seasonFolders.TryGetValue(season.SeasonNumber, out seasonFolder))
|
||||
if (!seasonFolders.TryGetValue(album.ArtistId, out seasonFolder))
|
||||
{
|
||||
_logger.Trace("Failed to find season folder for series {0}, season {1}.", series.Title, season.SeasonNumber);
|
||||
_logger.Trace("Failed to find season folder for series {0}, season {1}.", artist.Name, album.Title);
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
//Roksbox only supports one season image, so first of all try for poster otherwise just use whatever is first in the collection
|
||||
var image = season.Images.SingleOrDefault(c => c.CoverType == MediaCoverTypes.Poster) ?? season.Images.FirstOrDefault();
|
||||
var image = album.Images.SingleOrDefault(c => c.CoverType == MediaCoverTypes.Poster) ?? album.Images.FirstOrDefault();
|
||||
if (image == null)
|
||||
{
|
||||
_logger.Trace("Failed to find suitable season image for series {0}, season {1}.", series.Title, season.SeasonNumber);
|
||||
_logger.Trace("Failed to find suitable season image for series {0}, season {1}.", artist.Name, album.Title);
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
var filename = Path.GetFileName(seasonFolder) + ".jpg";
|
||||
var path = series.Path.GetRelativePath(Path.Combine(series.Path, seasonFolder, filename));
|
||||
var path = artist.Path.GetRelativePath(Path.Combine(artist.Path, seasonFolder, filename));
|
||||
|
||||
return new List<ImageFileResult> { new ImageFileResult(path, image.Url) };
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> EpisodeImages(Series series, EpisodeFile episodeFile)
|
||||
public override List<ImageFileResult> TrackImages(Artist artist, TrackFile trackFile)
|
||||
{
|
||||
var screenshot = episodeFile.Episodes.Value.First().Images.SingleOrDefault(i => i.CoverType == MediaCoverTypes.Screenshot);
|
||||
//var screenshot = episodeFile.Tracks.Value.First().Images.SingleOrDefault(i => i.CoverType == MediaCoverTypes.Screenshot);
|
||||
|
||||
if (screenshot == null)
|
||||
{
|
||||
_logger.Trace("Episode screenshot not available");
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
//if (screenshot == null)
|
||||
//{
|
||||
// _logger.Trace("Episode screenshot not available");
|
||||
// return new List<ImageFileResult>();
|
||||
//}
|
||||
|
||||
return new List<ImageFileResult> {new ImageFileResult(GetEpisodeImageFilename(episodeFile.RelativePath), screenshot.Url)};
|
||||
//return new List<ImageFileResult> {new ImageFileResult(GetEpisodeImageFilename(episodeFile.RelativePath), screenshot.Url)};
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
private string GetEpisodeMetadataFilename(string episodeFilePath)
|
||||
private string GetTrackMetadataFilename(string trackFilePath)
|
||||
{
|
||||
return Path.ChangeExtension(episodeFilePath, "xml");
|
||||
return Path.ChangeExtension(trackFilePath, "xml");
|
||||
}
|
||||
|
||||
private string GetEpisodeImageFilename(string episodeFilePath)
|
||||
private string GetTrackImageFilename(string trackFilePath)
|
||||
{
|
||||
return Path.ChangeExtension(episodeFilePath, "jpg");
|
||||
return Path.ChangeExtension(trackFilePath, "jpg");
|
||||
}
|
||||
|
||||
private Dictionary<int, string> GetSeasonFolders(Series series)
|
||||
private Dictionary<int, string> GetAlbumFolders(Artist artist)
|
||||
{
|
||||
var seasonFolderMap = new Dictionary<int, string>();
|
||||
|
||||
foreach (var folder in _diskProvider.GetDirectories(series.Path))
|
||||
foreach (var folder in _diskProvider.GetDirectories(artist.Path))
|
||||
{
|
||||
var directoryinfo = new DirectoryInfo(folder);
|
||||
var seasonMatch = SeasonImagesRegex.Match(directoryinfo.Name);
|
||||
@@ -267,13 +259,13 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("Failed to parse season number from {0} for series {1}.", folder, series.Title);
|
||||
_logger.Debug("Failed to parse season number from {0} for artist {1}.", folder, artist.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("Rejecting folder {0} for series {1}.", Path.GetDirectoryName(folder), series.Title);
|
||||
_logger.Debug("Rejecting folder {0} for artist {1}.", Path.GetDirectoryName(folder), artist.Name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,19 +19,19 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
||||
public RoksboxMetadataSettings()
|
||||
{
|
||||
EpisodeMetadata = true;
|
||||
SeriesImages = true;
|
||||
SeasonImages = true;
|
||||
ArtistImages = true;
|
||||
AlbumImages = true;
|
||||
EpisodeImages = true;
|
||||
}
|
||||
|
||||
[FieldDefinition(0, Label = "Episode Metadata", Type = FieldType.Checkbox, HelpText = "Season##\\filename.xml")]
|
||||
public bool EpisodeMetadata { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Series Images", Type = FieldType.Checkbox, HelpText = "Series Title.jpg")]
|
||||
public bool SeriesImages { get; set; }
|
||||
[FieldDefinition(1, Label = "Artist Images", Type = FieldType.Checkbox, HelpText = "Artist Title.jpg")]
|
||||
public bool ArtistImages { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Season Images", Type = FieldType.Checkbox, HelpText = "Season ##.jpg")]
|
||||
public bool SeasonImages { get; set; }
|
||||
[FieldDefinition(2, Label = "Album Images", Type = FieldType.Checkbox, HelpText = "Album Title.jpg")]
|
||||
public bool AlbumImages { get; set; }
|
||||
|
||||
[FieldDefinition(3, Label = "Episode Images", Type = FieldType.Checkbox, HelpText = "Season##\\filename.jpg")]
|
||||
public bool EpisodeImages { get; set; }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -12,7 +12,7 @@ using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Extras.Metadata.Files;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
||||
{
|
||||
@@ -35,26 +35,26 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
||||
|
||||
public override string Name => "WDTV";
|
||||
|
||||
public override string GetFilenameAfterMove(Series series, EpisodeFile episodeFile, MetadataFile metadataFile)
|
||||
public override string GetFilenameAfterMove(Artist artist, TrackFile trackFile, MetadataFile metadataFile)
|
||||
{
|
||||
var episodeFilePath = Path.Combine(series.Path, episodeFile.RelativePath);
|
||||
var trackFilePath = Path.Combine(artist.Path, trackFile.RelativePath);
|
||||
|
||||
if (metadataFile.Type == MetadataType.EpisodeImage)
|
||||
if (metadataFile.Type == MetadataType.TrackImage)
|
||||
{
|
||||
return GetEpisodeImageFilename(episodeFilePath);
|
||||
return GetTrackImageFilename(trackFilePath);
|
||||
}
|
||||
|
||||
if (metadataFile.Type == MetadataType.EpisodeMetadata)
|
||||
if (metadataFile.Type == MetadataType.TrackMetadata)
|
||||
{
|
||||
return GetEpisodeMetadataFilename(episodeFilePath);
|
||||
return GetTrackMetadataFilename(trackFilePath);
|
||||
}
|
||||
|
||||
_logger.Debug("Unknown episode file metadata: {0}", metadataFile.RelativePath);
|
||||
return Path.Combine(series.Path, metadataFile.RelativePath);
|
||||
_logger.Debug("Unknown track file metadata: {0}", metadataFile.RelativePath);
|
||||
return Path.Combine(artist.Path, metadataFile.RelativePath);
|
||||
|
||||
}
|
||||
|
||||
public override MetadataFile FindMetadataFile(Series series, string path)
|
||||
public override MetadataFile FindMetadataFile(Artist artist, string path)
|
||||
{
|
||||
var filename = Path.GetFileName(path);
|
||||
|
||||
@@ -62,9 +62,9 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
||||
|
||||
var metadata = new MetadataFile
|
||||
{
|
||||
SeriesId = series.Id,
|
||||
ArtistId = artist.Id,
|
||||
Consumer = GetType().Name,
|
||||
RelativePath = series.Path.GetRelativePath(path)
|
||||
RelativePath = artist.Path.GetRelativePath(path)
|
||||
};
|
||||
|
||||
//Series and season images are both named folder.jpg, only season ones sit in season folders
|
||||
@@ -74,22 +74,22 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
||||
var seasonMatch = SeasonImagesRegex.Match(parentdir.Name);
|
||||
if (seasonMatch.Success)
|
||||
{
|
||||
metadata.Type = MetadataType.SeasonImage;
|
||||
metadata.Type = MetadataType.AlbumImage;
|
||||
|
||||
if (seasonMatch.Groups["specials"].Success)
|
||||
{
|
||||
metadata.SeasonNumber = 0;
|
||||
metadata.AlbumId = 0;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
metadata.SeasonNumber = Convert.ToInt32(seasonMatch.Groups["season"].Value);
|
||||
metadata.AlbumId = Convert.ToInt32(seasonMatch.Groups["season"].Value);
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
metadata.Type = MetadataType.SeriesImage;
|
||||
metadata.Type = MetadataType.ArtistImage;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@@ -101,10 +101,10 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
||||
switch (Path.GetExtension(filename).ToLowerInvariant())
|
||||
{
|
||||
case ".xml":
|
||||
metadata.Type = MetadataType.EpisodeMetadata;
|
||||
metadata.Type = MetadataType.TrackMetadata;
|
||||
return metadata;
|
||||
case ".metathumb":
|
||||
metadata.Type = MetadataType.EpisodeImage;
|
||||
metadata.Type = MetadataType.TrackImage;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@@ -113,23 +113,28 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
||||
return null;
|
||||
}
|
||||
|
||||
public override MetadataFileResult SeriesMetadata(Series series)
|
||||
public override MetadataFileResult ArtistMetadata(Artist artist)
|
||||
{
|
||||
//Series metadata is not supported
|
||||
//Artist metadata is not supported
|
||||
return null;
|
||||
}
|
||||
|
||||
public override MetadataFileResult EpisodeMetadata(Series series, EpisodeFile episodeFile)
|
||||
public override MetadataFileResult AlbumMetadata(Artist artist, Album album)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override MetadataFileResult TrackMetadata(Artist artist, TrackFile trackFile)
|
||||
{
|
||||
if (!Settings.EpisodeMetadata)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
_logger.Debug("Generating Episode Metadata for: {0}", Path.Combine(series.Path, episodeFile.RelativePath));
|
||||
_logger.Debug("Generating Track Metadata for: {0}", Path.Combine(artist.Path, trackFile.RelativePath));
|
||||
|
||||
var xmlResult = string.Empty;
|
||||
foreach (var episode in episodeFile.Episodes.Value)
|
||||
foreach (var track in trackFile.Tracks.Value)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var xws = new XmlWriterSettings();
|
||||
@@ -141,16 +146,13 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
||||
var doc = new XDocument();
|
||||
|
||||
var details = new XElement("details");
|
||||
details.Add(new XElement("id", series.Id));
|
||||
details.Add(new XElement("title", string.Format("{0} - {1}x{2:00} - {3}", series.Title, episode.SeasonNumber, episode.EpisodeNumber, episode.Title)));
|
||||
details.Add(new XElement("series_name", series.Title));
|
||||
details.Add(new XElement("episode_name", episode.Title));
|
||||
details.Add(new XElement("season_number", episode.SeasonNumber.ToString("00")));
|
||||
details.Add(new XElement("episode_number", episode.EpisodeNumber.ToString("00")));
|
||||
details.Add(new XElement("firstaired", episode.AirDate));
|
||||
details.Add(new XElement("genre", string.Join(" / ", series.Genres)));
|
||||
details.Add(new XElement("actor", string.Join(" / ", series.Actors.ConvertAll(c => c.Name + " - " + c.Character))));
|
||||
details.Add(new XElement("overview", episode.Overview));
|
||||
details.Add(new XElement("id", artist.Id));
|
||||
details.Add(new XElement("title", string.Format("{0} - {1} - {2}", artist.Name, track.TrackNumber, track.Title)));
|
||||
details.Add(new XElement("artist_name", artist.Name));
|
||||
details.Add(new XElement("track_name", track.Title));
|
||||
details.Add(new XElement("track_number", track.TrackNumber.ToString("00")));
|
||||
details.Add(new XElement("genre", string.Join(" / ", artist.Genres)));
|
||||
details.Add(new XElement("member", string.Join(" / ", artist.Members.ConvertAll(c => c.Name + " - " + c.Instrument))));
|
||||
|
||||
|
||||
//Todo: get guest stars, writer and director
|
||||
@@ -165,27 +167,27 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
||||
}
|
||||
}
|
||||
|
||||
var filename = GetEpisodeMetadataFilename(episodeFile.RelativePath);
|
||||
var filename = GetTrackMetadataFilename(trackFile.RelativePath);
|
||||
|
||||
return new MetadataFileResult(filename, xmlResult.Trim(Environment.NewLine.ToCharArray()));
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> SeriesImages(Series series)
|
||||
public override List<ImageFileResult> ArtistImages(Artist artist)
|
||||
{
|
||||
if (!Settings.SeriesImages)
|
||||
if (!Settings.ArtistImages)
|
||||
{
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
//Because we only support one image, attempt to get the Poster type, then if that fails grab the first
|
||||
var image = series.Images.SingleOrDefault(c => c.CoverType == MediaCoverTypes.Poster) ?? series.Images.FirstOrDefault();
|
||||
var image = artist.Images.SingleOrDefault(c => c.CoverType == MediaCoverTypes.Poster) ?? artist.Images.FirstOrDefault();
|
||||
if (image == null)
|
||||
{
|
||||
_logger.Trace("Failed to find suitable Series image for series {0}.", series.Title);
|
||||
_logger.Trace("Failed to find suitable Artist image for artist {0}.", artist.Name);
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
var source = _mediaCoverService.GetCoverPath(series.Id, image.CoverType);
|
||||
var source = _mediaCoverService.GetCoverPath(artist.Id, image.CoverType);
|
||||
var destination = "folder" + Path.GetExtension(source);
|
||||
|
||||
return new List<ImageFileResult>
|
||||
@@ -194,28 +196,28 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
||||
};
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> SeasonImages(Series series, Season season)
|
||||
public override List<ImageFileResult> AlbumImages(Artist artist, Album album)
|
||||
{
|
||||
if (!Settings.SeasonImages)
|
||||
if (!Settings.AlbumImages)
|
||||
{
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
var seasonFolders = GetSeasonFolders(series);
|
||||
var seasonFolders = GetAlbumFolders(artist);
|
||||
|
||||
//Work out the path to this season - if we don't have a matching path then skip this season.
|
||||
string seasonFolder;
|
||||
if (!seasonFolders.TryGetValue(season.SeasonNumber, out seasonFolder))
|
||||
if (!seasonFolders.TryGetValue(album.Id, out seasonFolder))
|
||||
{
|
||||
_logger.Trace("Failed to find season folder for series {0}, season {1}.", series.Title, season.SeasonNumber);
|
||||
_logger.Trace("Failed to find album folder for artist {0}, album {1}.", artist.Name, album.Title);
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
//WDTV only supports one season image, so first of all try for poster otherwise just use whatever is first in the collection
|
||||
var image = season.Images.SingleOrDefault(c => c.CoverType == MediaCoverTypes.Poster) ?? season.Images.FirstOrDefault();
|
||||
var image = album.Images.SingleOrDefault(c => c.CoverType == MediaCoverTypes.Poster) ?? album.Images.FirstOrDefault();
|
||||
if (image == null)
|
||||
{
|
||||
_logger.Trace("Failed to find suitable season image for series {0}, season {1}.", series.Title, season.SeasonNumber);
|
||||
_logger.Trace("Failed to find suitable album image for artist {0}, album {1}.", artist.Name, album.Title);
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
@@ -224,39 +226,27 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
||||
return new List<ImageFileResult>{ new ImageFileResult(path, image.Url) };
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> EpisodeImages(Series series, EpisodeFile episodeFile)
|
||||
public override List<ImageFileResult> TrackImages(Artist artist, TrackFile trackFile)
|
||||
{
|
||||
if (!Settings.EpisodeImages)
|
||||
{
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
var screenshot = episodeFile.Episodes.Value.First().Images.SingleOrDefault(i => i.CoverType == MediaCoverTypes.Screenshot);
|
||||
|
||||
if (screenshot == null)
|
||||
{
|
||||
_logger.Trace("Episode screenshot not available");
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
return new List<ImageFileResult>{ new ImageFileResult(GetEpisodeImageFilename(episodeFile.RelativePath), screenshot.Url) };
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
private string GetEpisodeMetadataFilename(string episodeFilePath)
|
||||
private string GetTrackMetadataFilename(string trackFilePath)
|
||||
{
|
||||
return Path.ChangeExtension(episodeFilePath, "xml");
|
||||
return Path.ChangeExtension(trackFilePath, "xml");
|
||||
}
|
||||
|
||||
private string GetEpisodeImageFilename(string episodeFilePath)
|
||||
private string GetTrackImageFilename(string trackFilePath)
|
||||
{
|
||||
return Path.ChangeExtension(episodeFilePath, "metathumb");
|
||||
return Path.ChangeExtension(trackFilePath, "metathumb");
|
||||
}
|
||||
|
||||
private Dictionary<int, string> GetSeasonFolders(Series series)
|
||||
private Dictionary<int, string> GetAlbumFolders(Artist artist)
|
||||
{
|
||||
var seasonFolderMap = new Dictionary<int, string>();
|
||||
|
||||
foreach (var folder in _diskProvider.GetDirectories(series.Path))
|
||||
foreach (var folder in _diskProvider.GetDirectories(artist.Path))
|
||||
{
|
||||
var directoryinfo = new DirectoryInfo(folder);
|
||||
var seasonMatch = SeasonImagesRegex.Match(directoryinfo.Name);
|
||||
@@ -278,14 +268,14 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("Failed to parse season number from {0} for series {1}.", folder, series.Title);
|
||||
_logger.Debug("Failed to parse season number from {0} for artist {1}.", folder, artist.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
_logger.Debug("Rejecting folder {0} for series {1}.", Path.GetDirectoryName(folder), series.Title);
|
||||
_logger.Debug("Rejecting folder {0} for artist {1}.", Path.GetDirectoryName(folder), artist.Name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using FluentValidation;
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Validation;
|
||||
@@ -19,19 +19,19 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
||||
public WdtvMetadataSettings()
|
||||
{
|
||||
EpisodeMetadata = true;
|
||||
SeriesImages = true;
|
||||
SeasonImages = true;
|
||||
ArtistImages = true;
|
||||
AlbumImages = true;
|
||||
EpisodeImages = true;
|
||||
}
|
||||
|
||||
[FieldDefinition(0, Label = "Episode Metadata", Type = FieldType.Checkbox)]
|
||||
public bool EpisodeMetadata { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Series Images", Type = FieldType.Checkbox)]
|
||||
public bool SeriesImages { get; set; }
|
||||
[FieldDefinition(1, Label = "Artist Images", Type = FieldType.Checkbox)]
|
||||
public bool ArtistImages { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Season Images", Type = FieldType.Checkbox)]
|
||||
public bool SeasonImages { get; set; }
|
||||
[FieldDefinition(2, Label = "Album Images", Type = FieldType.Checkbox)]
|
||||
public bool AlbumImages { get; set; }
|
||||
|
||||
[FieldDefinition(3, Label = "Episode Images", Type = FieldType.Checkbox)]
|
||||
public bool EpisodeImages { get; set; }
|
||||
|
||||
@@ -11,7 +11,7 @@ using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Extras.Metadata.Files;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
{
|
||||
@@ -27,31 +27,31 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
private static readonly Regex SeriesImagesRegex = new Regex(@"^(?<type>poster|banner|fanart)\.(?:png|jpg)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex SeasonImagesRegex = new Regex(@"^season(?<season>\d{2,}|-all|-specials)-(?<type>poster|banner|fanart)\.(?:png|jpg)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex ArtistImagesRegex = new Regex(@"^(?<type>poster|banner|fanart|logo)\.(?:png|jpg)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex AlbumImagesRegex = new Regex(@"^season(?<season>\d{2,}|-all|-specials)-(?<type>poster|banner|fanart|cover)\.(?:png|jpg)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex EpisodeImageRegex = new Regex(@"-thumb\.(?:png|jpg)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public override string Name => "Kodi (XBMC) / Emby";
|
||||
|
||||
public override string GetFilenameAfterMove(Series series, EpisodeFile episodeFile, MetadataFile metadataFile)
|
||||
public override string GetFilenameAfterMove(Artist artist, TrackFile trackFile, MetadataFile metadataFile)
|
||||
{
|
||||
var episodeFilePath = Path.Combine(series.Path, episodeFile.RelativePath);
|
||||
var trackFilePath = Path.Combine(artist.Path, trackFile.RelativePath);
|
||||
|
||||
if (metadataFile.Type == MetadataType.EpisodeImage)
|
||||
if (metadataFile.Type == MetadataType.TrackImage)
|
||||
{
|
||||
return GetEpisodeImageFilename(episodeFilePath);
|
||||
return GetEpisodeImageFilename(trackFilePath);
|
||||
}
|
||||
|
||||
if (metadataFile.Type == MetadataType.EpisodeMetadata)
|
||||
if (metadataFile.Type == MetadataType.TrackMetadata)
|
||||
{
|
||||
return GetEpisodeMetadataFilename(episodeFilePath);
|
||||
return GetEpisodeMetadataFilename(trackFilePath);
|
||||
}
|
||||
|
||||
_logger.Debug("Unknown episode file metadata: {0}", metadataFile.RelativePath);
|
||||
return Path.Combine(series.Path, metadataFile.RelativePath);
|
||||
return Path.Combine(artist.Path, metadataFile.RelativePath);
|
||||
}
|
||||
|
||||
public override MetadataFile FindMetadataFile(Series series, string path)
|
||||
public override MetadataFile FindMetadataFile(Artist artist, string path)
|
||||
{
|
||||
var filename = Path.GetFileName(path);
|
||||
|
||||
@@ -59,34 +59,34 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
|
||||
var metadata = new MetadataFile
|
||||
{
|
||||
SeriesId = series.Id,
|
||||
ArtistId = artist.Id,
|
||||
Consumer = GetType().Name,
|
||||
RelativePath = series.Path.GetRelativePath(path)
|
||||
RelativePath = artist.Path.GetRelativePath(path)
|
||||
};
|
||||
|
||||
if (SeriesImagesRegex.IsMatch(filename))
|
||||
if (ArtistImagesRegex.IsMatch(filename))
|
||||
{
|
||||
metadata.Type = MetadataType.SeriesImage;
|
||||
metadata.Type = MetadataType.ArtistImage;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
var seasonMatch = SeasonImagesRegex.Match(filename);
|
||||
var seasonMatch = AlbumImagesRegex.Match(filename);
|
||||
|
||||
if (seasonMatch.Success)
|
||||
{
|
||||
metadata.Type = MetadataType.SeasonImage;
|
||||
metadata.Type = MetadataType.AlbumImage;
|
||||
|
||||
var seasonNumberMatch = seasonMatch.Groups["season"].Value;
|
||||
int seasonNumber;
|
||||
|
||||
if (seasonNumberMatch.Contains("specials"))
|
||||
{
|
||||
metadata.SeasonNumber = 0;
|
||||
metadata.AlbumId = 0;
|
||||
}
|
||||
|
||||
else if (int.TryParse(seasonNumberMatch, out seasonNumber))
|
||||
{
|
||||
metadata.SeasonNumber = seasonNumber;
|
||||
metadata.AlbumId = seasonNumber;
|
||||
}
|
||||
|
||||
else
|
||||
@@ -99,13 +99,19 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
|
||||
if (EpisodeImageRegex.IsMatch(filename))
|
||||
{
|
||||
metadata.Type = MetadataType.EpisodeImage;
|
||||
metadata.Type = MetadataType.TrackImage;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
if (filename.Equals("tvshow.nfo", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (filename.Equals("artist.nfo", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
metadata.Type = MetadataType.SeriesMetadata;
|
||||
metadata.Type = MetadataType.ArtistMetadata;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
if (filename.Equals("album.nfo", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
metadata.Type = MetadataType.AlbumMetadata;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@@ -115,91 +121,120 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
!parseResult.FullSeason &&
|
||||
Path.GetExtension(filename) == ".nfo")
|
||||
{
|
||||
metadata.Type = MetadataType.EpisodeMetadata;
|
||||
metadata.Type = MetadataType.TrackMetadata;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override MetadataFileResult SeriesMetadata(Series series)
|
||||
public override MetadataFileResult ArtistMetadata(Artist artist)
|
||||
{
|
||||
if (!Settings.SeriesMetadata)
|
||||
if (!Settings.ArtistMetadata)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
_logger.Debug("Generating tvshow.nfo for: {0}", series.Title);
|
||||
_logger.Debug("Generating artist.nfo for: {0}", artist.Name);
|
||||
var sb = new StringBuilder();
|
||||
var xws = new XmlWriterSettings();
|
||||
xws.OmitXmlDeclaration = true;
|
||||
xws.Indent = false;
|
||||
|
||||
var episodeGuideUrl = string.Format("http://www.thetvdb.com/api/1D62F2F90030C444/series/{0}/all/en.zip", series.TvdbId);
|
||||
|
||||
using (var xw = XmlWriter.Create(sb, xws))
|
||||
{
|
||||
var tvShow = new XElement("tvshow");
|
||||
var artistElement = new XElement("artist");
|
||||
|
||||
tvShow.Add(new XElement("title", series.Title));
|
||||
artistElement.Add(new XElement("title", artist.Name));
|
||||
|
||||
if (series.Ratings != null && series.Ratings.Votes > 0)
|
||||
if (artist.Ratings != null && artist.Ratings.Votes > 0)
|
||||
{
|
||||
tvShow.Add(new XElement("rating", series.Ratings.Value));
|
||||
artistElement.Add(new XElement("rating", artist.Ratings.Value));
|
||||
}
|
||||
|
||||
tvShow.Add(new XElement("plot", series.Overview));
|
||||
tvShow.Add(new XElement("episodeguide", new XElement("url", episodeGuideUrl)));
|
||||
tvShow.Add(new XElement("episodeguideurl", episodeGuideUrl));
|
||||
tvShow.Add(new XElement("mpaa", series.Certification));
|
||||
tvShow.Add(new XElement("id", series.TvdbId));
|
||||
artistElement.Add(new XElement("musicbrainzartistid", artist.ForeignArtistId));
|
||||
artistElement.Add(new XElement("biography", artist.Overview));
|
||||
artistElement.Add(new XElement("outline", artist.Overview));
|
||||
//tvShow.Add(new XElement("episodeguide", new XElement("url", episodeGuideUrl)));
|
||||
//tvShow.Add(new XElement("episodeguideurl", episodeGuideUrl));
|
||||
|
||||
foreach (var genre in series.Genres)
|
||||
{
|
||||
tvShow.Add(new XElement("genre", genre));
|
||||
}
|
||||
//foreach (var genre in artist.Genres)
|
||||
//{
|
||||
// tvShow.Add(new XElement("genre", genre));
|
||||
//}
|
||||
|
||||
|
||||
if (series.FirstAired.HasValue)
|
||||
{
|
||||
tvShow.Add(new XElement("premiered", series.FirstAired.Value.ToString("yyyy-MM-dd")));
|
||||
}
|
||||
//foreach (var actor in artist.Members)
|
||||
//{
|
||||
// var xmlActor = new XElement("actor",
|
||||
// new XElement("name", actor.Name),
|
||||
// new XElement("role", actor.Instrument));
|
||||
|
||||
tvShow.Add(new XElement("studio", series.Network));
|
||||
// if (actor.Images.Any())
|
||||
// {
|
||||
// xmlActor.Add(new XElement("thumb", actor.Images.First().Url));
|
||||
// }
|
||||
|
||||
foreach (var actor in series.Actors)
|
||||
{
|
||||
var xmlActor = new XElement("actor",
|
||||
new XElement("name", actor.Name),
|
||||
new XElement("role", actor.Character));
|
||||
// tvShow.Add(xmlActor);
|
||||
//}
|
||||
|
||||
if (actor.Images.Any())
|
||||
{
|
||||
xmlActor.Add(new XElement("thumb", actor.Images.First().Url));
|
||||
}
|
||||
|
||||
tvShow.Add(xmlActor);
|
||||
}
|
||||
|
||||
var doc = new XDocument(tvShow);
|
||||
var doc = new XDocument(artistElement);
|
||||
doc.Save(xw);
|
||||
|
||||
_logger.Debug("Saving tvshow.nfo for {0}", series.Title);
|
||||
_logger.Debug("Saving artist.nfo for {0}", artist.Name);
|
||||
|
||||
return new MetadataFileResult("tvshow.nfo", doc.ToString());
|
||||
return new MetadataFileResult("artist.nfo", doc.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public override MetadataFileResult EpisodeMetadata(Series series, EpisodeFile episodeFile)
|
||||
public override MetadataFileResult AlbumMetadata(Artist artist, Album album)
|
||||
{
|
||||
if (!Settings.EpisodeMetadata)
|
||||
if (!Settings.AlbumMetadata)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
_logger.Debug("Generating Episode Metadata for: {0}", Path.Combine(series.Path, episodeFile.RelativePath));
|
||||
_logger.Debug("Generating album.nfo for: {0}", album.Title);
|
||||
var sb = new StringBuilder();
|
||||
var xws = new XmlWriterSettings();
|
||||
xws.OmitXmlDeclaration = true;
|
||||
xws.Indent = false;
|
||||
|
||||
using (var xw = XmlWriter.Create(sb, xws))
|
||||
{
|
||||
var albumElement = new XElement("album");
|
||||
|
||||
albumElement.Add(new XElement("title", album.Title));
|
||||
|
||||
if (album.Ratings != null && album.Ratings.Votes > 0)
|
||||
{
|
||||
albumElement.Add(new XElement("rating", album.Ratings.Value));
|
||||
}
|
||||
|
||||
albumElement.Add(new XElement("musicbrainzalbumid", album.ForeignAlbumId));
|
||||
albumElement.Add(new XElement("artistdesc", artist.Overview));
|
||||
albumElement.Add(new XElement("releasedate", album.ReleaseDate.Value.ToShortDateString()));
|
||||
|
||||
var doc = new XDocument(albumElement);
|
||||
doc.Save(xw);
|
||||
|
||||
_logger.Debug("Saving album.nfo for {0}", artist.Name);
|
||||
|
||||
return new MetadataFileResult("album.nfo", doc.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public override MetadataFileResult TrackMetadata(Artist artist, TrackFile trackFile)
|
||||
{
|
||||
if (!Settings.TrackMetadata)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
_logger.Debug("Generating Track Metadata for: {0}", Path.Combine(artist.Path, trackFile.RelativePath));
|
||||
|
||||
var xmlResult = string.Empty;
|
||||
foreach (var episode in episodeFile.Episodes.Value)
|
||||
foreach (var episode in trackFile.Tracks.Value)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var xws = new XmlWriterSettings();
|
||||
@@ -209,29 +244,15 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
using (var xw = XmlWriter.Create(sb, xws))
|
||||
{
|
||||
var doc = new XDocument();
|
||||
var image = episode.Images.SingleOrDefault(i => i.CoverType == MediaCoverTypes.Screenshot);
|
||||
|
||||
var details = new XElement("episodedetails");
|
||||
details.Add(new XElement("title", episode.Title));
|
||||
details.Add(new XElement("season", episode.SeasonNumber));
|
||||
details.Add(new XElement("episode", episode.EpisodeNumber));
|
||||
details.Add(new XElement("aired", episode.AirDate));
|
||||
details.Add(new XElement("plot", episode.Overview));
|
||||
details.Add(new XElement("episode", episode.TrackNumber));
|
||||
|
||||
//If trakt ever gets airs before information for specials we should add set it
|
||||
details.Add(new XElement("displayseason"));
|
||||
details.Add(new XElement("displayepisode"));
|
||||
|
||||
if (image == null)
|
||||
{
|
||||
details.Add(new XElement("thumb"));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
details.Add(new XElement("thumb", image.Url));
|
||||
}
|
||||
|
||||
details.Add(new XElement("watched", "false"));
|
||||
|
||||
if (episode.Ratings != null && episode.Ratings.Votes > 0)
|
||||
@@ -239,39 +260,39 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
details.Add(new XElement("rating", episode.Ratings.Value));
|
||||
}
|
||||
|
||||
if (episodeFile.MediaInfo != null)
|
||||
if (trackFile.MediaInfo != null)
|
||||
{
|
||||
var fileInfo = new XElement("fileinfo");
|
||||
var streamDetails = new XElement("streamdetails");
|
||||
|
||||
var video = new XElement("video");
|
||||
video.Add(new XElement("aspect", (float)episodeFile.MediaInfo.Width / (float)episodeFile.MediaInfo.Height));
|
||||
video.Add(new XElement("bitrate", episodeFile.MediaInfo.VideoBitrate));
|
||||
video.Add(new XElement("codec", episodeFile.MediaInfo.VideoCodec));
|
||||
video.Add(new XElement("framerate", episodeFile.MediaInfo.VideoFps));
|
||||
video.Add(new XElement("height", episodeFile.MediaInfo.Height));
|
||||
video.Add(new XElement("scantype", episodeFile.MediaInfo.ScanType));
|
||||
video.Add(new XElement("width", episodeFile.MediaInfo.Width));
|
||||
video.Add(new XElement("aspect", (float)trackFile.MediaInfo.Width / (float)trackFile.MediaInfo.Height));
|
||||
video.Add(new XElement("bitrate", trackFile.MediaInfo.VideoBitrate));
|
||||
video.Add(new XElement("codec", trackFile.MediaInfo.VideoCodec));
|
||||
video.Add(new XElement("framerate", trackFile.MediaInfo.VideoFps));
|
||||
video.Add(new XElement("height", trackFile.MediaInfo.Height));
|
||||
video.Add(new XElement("scantype", trackFile.MediaInfo.ScanType));
|
||||
video.Add(new XElement("width", trackFile.MediaInfo.Width));
|
||||
|
||||
if (episodeFile.MediaInfo.RunTime != null)
|
||||
if (trackFile.MediaInfo.RunTime != null)
|
||||
{
|
||||
video.Add(new XElement("duration", episodeFile.MediaInfo.RunTime.TotalMinutes));
|
||||
video.Add(new XElement("durationinseconds", episodeFile.MediaInfo.RunTime.TotalSeconds));
|
||||
video.Add(new XElement("duration", trackFile.MediaInfo.RunTime.TotalMinutes));
|
||||
video.Add(new XElement("durationinseconds", trackFile.MediaInfo.RunTime.TotalSeconds));
|
||||
}
|
||||
|
||||
streamDetails.Add(video);
|
||||
|
||||
var audio = new XElement("audio");
|
||||
audio.Add(new XElement("bitrate", episodeFile.MediaInfo.AudioBitrate));
|
||||
audio.Add(new XElement("channels", episodeFile.MediaInfo.AudioChannels));
|
||||
audio.Add(new XElement("codec", GetAudioCodec(episodeFile.MediaInfo.AudioFormat)));
|
||||
audio.Add(new XElement("language", episodeFile.MediaInfo.AudioLanguages));
|
||||
audio.Add(new XElement("bitrate", trackFile.MediaInfo.AudioBitrate));
|
||||
audio.Add(new XElement("channels", trackFile.MediaInfo.AudioChannels));
|
||||
audio.Add(new XElement("codec", GetAudioCodec(trackFile.MediaInfo.AudioFormat)));
|
||||
audio.Add(new XElement("language", trackFile.MediaInfo.AudioLanguages));
|
||||
streamDetails.Add(audio);
|
||||
|
||||
if (episodeFile.MediaInfo.Subtitles != null && episodeFile.MediaInfo.Subtitles.Length > 0)
|
||||
if (trackFile.MediaInfo.Subtitles != null && trackFile.MediaInfo.Subtitles.Length > 0)
|
||||
{
|
||||
var subtitle = new XElement("subtitle");
|
||||
subtitle.Add(new XElement("language", episodeFile.MediaInfo.Subtitles));
|
||||
subtitle.Add(new XElement("language", trackFile.MediaInfo.Subtitles));
|
||||
streamDetails.Add(subtitle);
|
||||
}
|
||||
|
||||
@@ -291,80 +312,52 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
}
|
||||
}
|
||||
|
||||
return new MetadataFileResult(GetEpisodeMetadataFilename(episodeFile.RelativePath), xmlResult.Trim(Environment.NewLine.ToCharArray()));
|
||||
return new MetadataFileResult(GetEpisodeMetadataFilename(trackFile.RelativePath), xmlResult.Trim(Environment.NewLine.ToCharArray()));
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> SeriesImages(Series series)
|
||||
public override List<ImageFileResult> ArtistImages(Artist artist)
|
||||
{
|
||||
if (!Settings.SeriesImages)
|
||||
if (!Settings.ArtistImages)
|
||||
{
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
return ProcessSeriesImages(series).ToList();
|
||||
return ProcessArtistImages(artist).ToList();
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> SeasonImages(Series series, Season season)
|
||||
public override List<ImageFileResult> AlbumImages(Artist artist, Album album)
|
||||
{
|
||||
if (!Settings.SeasonImages)
|
||||
if (!Settings.AlbumImages)
|
||||
{
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
return ProcessSeasonImages(series, season).ToList();
|
||||
return ProcessAlbumImages(artist, album).ToList();
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> EpisodeImages(Series series, EpisodeFile episodeFile)
|
||||
public override List<ImageFileResult> TrackImages(Artist artist, TrackFile trackFile)
|
||||
{
|
||||
if (!Settings.EpisodeImages)
|
||||
{
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var screenshot = episodeFile.Episodes.Value.First().Images.SingleOrDefault(i => i.CoverType == MediaCoverTypes.Screenshot);
|
||||
|
||||
if (screenshot == null)
|
||||
{
|
||||
_logger.Debug("Episode screenshot not available");
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
return new List<ImageFileResult>
|
||||
{
|
||||
new ImageFileResult(GetEpisodeImageFilename(episodeFile.RelativePath), screenshot.Url)
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex, "Unable to process episode image for file: {0}", Path.Combine(series.Path, episodeFile.RelativePath));
|
||||
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
private IEnumerable<ImageFileResult> ProcessSeriesImages(Series series)
|
||||
private IEnumerable<ImageFileResult> ProcessArtistImages(Artist artist)
|
||||
{
|
||||
foreach (var image in series.Images)
|
||||
foreach (var image in artist.Images)
|
||||
{
|
||||
var source = _mediaCoverService.GetCoverPath(series.Id, image.CoverType);
|
||||
var source = _mediaCoverService.GetCoverPath(artist.Id, image.CoverType);
|
||||
var destination = image.CoverType.ToString().ToLowerInvariant() + Path.GetExtension(source);
|
||||
|
||||
yield return new ImageFileResult(destination, source);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<ImageFileResult> ProcessSeasonImages(Series series, Season season)
|
||||
private IEnumerable<ImageFileResult> ProcessAlbumImages(Artist artist, Album album)
|
||||
{
|
||||
foreach (var image in season.Images)
|
||||
foreach (var image in album.Images)
|
||||
{
|
||||
var filename = string.Format("season{0:00}-{1}.jpg", season.SeasonNumber, image.CoverType.ToString().ToLower());
|
||||
|
||||
if (season.SeasonNumber == 0)
|
||||
{
|
||||
filename = string.Format("season-specials-{0}.jpg", image.CoverType.ToString().ToLower());
|
||||
}
|
||||
var destination = Path.GetFileName(album.Path);
|
||||
var filename = string.Format("{0}\\{1}{2}", destination, image.CoverType.ToString().ToLower(), Path.GetExtension(image.Url));
|
||||
|
||||
yield return new ImageFileResult(filename, image.Url);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using FluentValidation;
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Validation;
|
||||
@@ -18,28 +18,32 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
|
||||
public XbmcMetadataSettings()
|
||||
{
|
||||
SeriesMetadata = true;
|
||||
EpisodeMetadata = true;
|
||||
SeriesImages = true;
|
||||
SeasonImages = true;
|
||||
ArtistMetadata = true;
|
||||
AlbumMetadata = true;
|
||||
TrackMetadata = true;
|
||||
ArtistImages = true;
|
||||
AlbumImages = true;
|
||||
EpisodeImages = true;
|
||||
}
|
||||
|
||||
[FieldDefinition(0, Label = "Series Metadata", Type = FieldType.Checkbox)]
|
||||
public bool SeriesMetadata { get; set; }
|
||||
[FieldDefinition(0, Label = "Artist Metadata", Type = FieldType.Checkbox)]
|
||||
public bool ArtistMetadata { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Episode Metadata", Type = FieldType.Checkbox)]
|
||||
public bool EpisodeMetadata { get; set; }
|
||||
[FieldDefinition(1, Label = "Album Metadata", Type = FieldType.Checkbox)]
|
||||
public bool AlbumMetadata { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Series Images", Type = FieldType.Checkbox)]
|
||||
public bool SeriesImages { get; set; }
|
||||
[FieldDefinition(2, Label = "Track Metadata", Type = FieldType.Checkbox)]
|
||||
public bool TrackMetadata { get; set; }
|
||||
|
||||
[FieldDefinition(3, Label = "Season Images", Type = FieldType.Checkbox)]
|
||||
public bool SeasonImages { get; set; }
|
||||
[FieldDefinition(3, Label = "Artist Images", Type = FieldType.Checkbox)]
|
||||
public bool ArtistImages { get; set; }
|
||||
|
||||
[FieldDefinition(4, Label = "Episode Images", Type = FieldType.Checkbox)]
|
||||
[FieldDefinition(4, Label = "Album Images", Type = FieldType.Checkbox)]
|
||||
public bool AlbumImages { get; set; }
|
||||
|
||||
[FieldDefinition(5, Label = "Episode Images", Type = FieldType.Checkbox)]
|
||||
public bool EpisodeImages { get; set; }
|
||||
|
||||
|
||||
public bool IsValid => true;
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
@@ -7,7 +7,7 @@ using NzbDrone.Core.Extras.Files;
|
||||
using NzbDrone.Core.Extras.Metadata.Files;
|
||||
using NzbDrone.Core.Extras.Subtitles;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace NzbDrone.Core.Extras.Metadata
|
||||
{
|
||||
@@ -32,12 +32,12 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
|
||||
public override int Order => 0;
|
||||
|
||||
public override IEnumerable<ExtraFile> ProcessFiles(Series series, List<string> filesOnDisk, List<string> importedFiles)
|
||||
public override IEnumerable<ExtraFile> ProcessFiles(Artist artist, List<string> filesOnDisk, List<string> importedFiles)
|
||||
{
|
||||
_logger.Debug("Looking for existing metadata in {0}", series.Path);
|
||||
_logger.Debug("Looking for existing metadata in {0}", artist.Path);
|
||||
|
||||
var metadataFiles = new List<MetadataFile>();
|
||||
var filterResult = FilterAndClean(series, filesOnDisk, importedFiles);
|
||||
var filterResult = FilterAndClean(artist, filesOnDisk, importedFiles);
|
||||
|
||||
foreach (var possibleMetadataFile in filterResult.FilesOnDisk)
|
||||
{
|
||||
@@ -50,38 +50,38 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
|
||||
foreach (var consumer in _consumers)
|
||||
{
|
||||
var metadata = consumer.FindMetadataFile(series, possibleMetadataFile);
|
||||
var metadata = consumer.FindMetadataFile(artist, possibleMetadataFile);
|
||||
|
||||
if (metadata == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (metadata.Type == MetadataType.EpisodeImage ||
|
||||
metadata.Type == MetadataType.EpisodeMetadata)
|
||||
if (metadata.Type == MetadataType.TrackImage ||
|
||||
metadata.Type == MetadataType.TrackMetadata)
|
||||
{
|
||||
var localEpisode = _parsingService.GetLocalEpisode(possibleMetadataFile, series);
|
||||
var localTrack = _parsingService.GetLocalTrack(possibleMetadataFile, artist);
|
||||
|
||||
if (localEpisode == null)
|
||||
if (localTrack == null)
|
||||
{
|
||||
_logger.Debug("Unable to parse extra file: {0}", possibleMetadataFile);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (localEpisode.Episodes.Empty())
|
||||
if (localTrack.Tracks.Empty())
|
||||
{
|
||||
_logger.Debug("Cannot find related episodes for: {0}", possibleMetadataFile);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (localEpisode.Episodes.DistinctBy(e => e.EpisodeFileId).Count() > 1)
|
||||
if (localTrack.Tracks.DistinctBy(e => e.TrackFileId).Count() > 1)
|
||||
{
|
||||
_logger.Debug("Extra file: {0} does not match existing files.", possibleMetadataFile);
|
||||
continue;
|
||||
}
|
||||
|
||||
metadata.SeasonNumber = localEpisode.SeasonNumber;
|
||||
metadata.EpisodeFileId = localEpisode.Episodes.First().EpisodeFileId;
|
||||
metadata.AlbumId = localTrack.Album.Id;
|
||||
metadata.TrackFileId = localTrack.Tracks.First().TrackFileId;
|
||||
}
|
||||
|
||||
metadata.Extension = Path.GetExtension(possibleMetadataFile);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace NzbDrone.Core.Extras.Metadata.Files
|
||||
{
|
||||
public interface ICleanMetadataService
|
||||
{
|
||||
void Clean(Series series);
|
||||
void Clean(Artist artist);
|
||||
}
|
||||
|
||||
public class CleanExtraFileService : ICleanMetadataService
|
||||
@@ -25,15 +25,15 @@ namespace NzbDrone.Core.Extras.Metadata.Files
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Clean(Series series)
|
||||
public void Clean(Artist artist)
|
||||
{
|
||||
_logger.Debug("Cleaning missing metadata files for series: {0}", series.Title);
|
||||
_logger.Debug("Cleaning missing metadata files for artist: {0}", artist.Name);
|
||||
|
||||
var metadataFiles = _metadataFileService.GetFilesBySeries(series.Id);
|
||||
var metadataFiles = _metadataFileService.GetFilesByArtist(artist.Id);
|
||||
|
||||
foreach (var metadataFile in metadataFiles)
|
||||
{
|
||||
if (!_diskProvider.FileExists(Path.Combine(series.Path, metadataFile.RelativePath)))
|
||||
if (!_diskProvider.FileExists(Path.Combine(artist.Path, metadataFile.RelativePath)))
|
||||
{
|
||||
_logger.Debug("Deleting metadata file from database: {0}", metadataFile.RelativePath);
|
||||
_metadataFileService.Delete(metadataFile.Id);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using NLog;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.Extras.Files;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace NzbDrone.Core.Extras.Metadata.Files
|
||||
{
|
||||
@@ -12,8 +12,8 @@ namespace NzbDrone.Core.Extras.Metadata.Files
|
||||
|
||||
public class MetadataFileService : ExtraFileService<MetadataFile>, IMetadataFileService
|
||||
{
|
||||
public MetadataFileService(IExtraFileRepository<MetadataFile> repository, ISeriesService seriesService, IDiskProvider diskProvider, IRecycleBinProvider recycleBinProvider, Logger logger)
|
||||
: base(repository, seriesService, diskProvider, recycleBinProvider, logger)
|
||||
public MetadataFileService(IExtraFileRepository<MetadataFile> repository, IArtistService artistService, IDiskProvider diskProvider, IRecycleBinProvider recycleBinProvider, Logger logger)
|
||||
: base(repository, artistService, diskProvider, recycleBinProvider, logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Extras.Metadata.Files;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace NzbDrone.Core.Extras.Metadata
|
||||
{
|
||||
public interface IMetadata : IProvider
|
||||
{
|
||||
string GetFilenameAfterMove(Series series, EpisodeFile episodeFile, MetadataFile metadataFile);
|
||||
MetadataFile FindMetadataFile(Series series, string path);
|
||||
MetadataFileResult SeriesMetadata(Series series);
|
||||
MetadataFileResult EpisodeMetadata(Series series, EpisodeFile episodeFile);
|
||||
List<ImageFileResult> SeriesImages(Series series);
|
||||
List<ImageFileResult> SeasonImages(Series series, Season season);
|
||||
List<ImageFileResult> EpisodeImages(Series series, EpisodeFile episodeFile);
|
||||
string GetFilenameAfterMove(Artist artist, TrackFile trackFile, MetadataFile metadataFile);
|
||||
MetadataFile FindMetadataFile(Artist artist, string path);
|
||||
MetadataFileResult ArtistMetadata(Artist artist);
|
||||
MetadataFileResult AlbumMetadata(Artist artist, Album album);
|
||||
MetadataFileResult TrackMetadata(Artist artist, TrackFile trackFile);
|
||||
List<ImageFileResult> ArtistImages(Artist artist);
|
||||
List<ImageFileResult> AlbumImages(Artist artist, Album album);
|
||||
List<ImageFileResult> TrackImages(Artist artist, TrackFile trackFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using FluentValidation.Results;
|
||||
using NzbDrone.Core.Extras.Metadata.Files;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace NzbDrone.Core.Extras.Metadata
|
||||
{
|
||||
@@ -26,22 +26,23 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
return new ValidationResult();
|
||||
}
|
||||
|
||||
public virtual string GetFilenameAfterMove(Series series, EpisodeFile episodeFile, MetadataFile metadataFile)
|
||||
public virtual string GetFilenameAfterMove(Artist artist, TrackFile trackFile, MetadataFile metadataFile)
|
||||
{
|
||||
var existingFilename = Path.Combine(series.Path, metadataFile.RelativePath);
|
||||
var existingFilename = Path.Combine(artist.Path, metadataFile.RelativePath);
|
||||
var extension = Path.GetExtension(existingFilename).TrimStart('.');
|
||||
var newFileName = Path.ChangeExtension(Path.Combine(series.Path, episodeFile.RelativePath), extension);
|
||||
var newFileName = Path.ChangeExtension(Path.Combine(artist.Path, trackFile.RelativePath), extension);
|
||||
|
||||
return newFileName;
|
||||
}
|
||||
|
||||
public abstract MetadataFile FindMetadataFile(Series series, string path);
|
||||
public abstract MetadataFile FindMetadataFile(Artist artist, string path);
|
||||
|
||||
public abstract MetadataFileResult SeriesMetadata(Series series);
|
||||
public abstract MetadataFileResult EpisodeMetadata(Series series, EpisodeFile episodeFile);
|
||||
public abstract List<ImageFileResult> SeriesImages(Series series);
|
||||
public abstract List<ImageFileResult> SeasonImages(Series series, Season season);
|
||||
public abstract List<ImageFileResult> EpisodeImages(Series series, EpisodeFile episodeFile);
|
||||
public abstract MetadataFileResult ArtistMetadata(Artist artist);
|
||||
public abstract MetadataFileResult AlbumMetadata(Artist artist, Album album);
|
||||
public abstract MetadataFileResult TrackMetadata(Artist artist, TrackFile trackFile);
|
||||
public abstract List<ImageFileResult> ArtistImages(Artist artist);
|
||||
public abstract List<ImageFileResult> AlbumImages(Artist artist, Album album);
|
||||
public abstract List<ImageFileResult> TrackImages(Artist artist, TrackFile trackFile);
|
||||
|
||||
public virtual object RequestAction(string action, IDictionary<string, string> query) { return null; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -11,7 +11,7 @@ using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Extras.Files;
|
||||
using NzbDrone.Core.Extras.Metadata.Files;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace NzbDrone.Core.Extras.Metadata
|
||||
{
|
||||
@@ -24,6 +24,7 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IMediaFileAttributeService _mediaFileAttributeService;
|
||||
private readonly IMetadataFileService _metadataFileService;
|
||||
private readonly IAlbumService _albumService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public MetadataService(IConfigService configService,
|
||||
@@ -34,6 +35,7 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
IHttpClient httpClient,
|
||||
IMediaFileAttributeService mediaFileAttributeService,
|
||||
IMetadataFileService metadataFileService,
|
||||
IAlbumService albumService,
|
||||
Logger logger)
|
||||
: base(configService, diskProvider, diskTransferService, logger)
|
||||
{
|
||||
@@ -44,19 +46,20 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
_httpClient = httpClient;
|
||||
_mediaFileAttributeService = mediaFileAttributeService;
|
||||
_metadataFileService = metadataFileService;
|
||||
_albumService = albumService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public override int Order => 0;
|
||||
|
||||
public override IEnumerable<ExtraFile> CreateAfterSeriesScan(Series series, List<EpisodeFile> episodeFiles)
|
||||
public override IEnumerable<ExtraFile> CreateAfterArtistScan(Artist artist, List<Album> albums, List<TrackFile> trackFiles)
|
||||
{
|
||||
var metadataFiles = _metadataFileService.GetFilesBySeries(series.Id);
|
||||
_cleanMetadataService.Clean(series);
|
||||
var metadataFiles = _metadataFileService.GetFilesByArtist(artist.Id);
|
||||
_cleanMetadataService.Clean(artist);
|
||||
|
||||
if (!_diskProvider.FolderExists(series.Path))
|
||||
if (!_diskProvider.FolderExists(artist.Path))
|
||||
{
|
||||
_logger.Info("Series folder does not exist, skipping metadata creation");
|
||||
_logger.Info("Artist folder does not exist, skipping metadata creation");
|
||||
return Enumerable.Empty<MetadataFile>();
|
||||
}
|
||||
|
||||
@@ -66,14 +69,20 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
{
|
||||
var consumerFiles = GetMetadataFilesForConsumer(consumer, metadataFiles);
|
||||
|
||||
files.AddIfNotNull(ProcessSeriesMetadata(consumer, series, consumerFiles));
|
||||
files.AddRange(ProcessSeriesImages(consumer, series, consumerFiles));
|
||||
files.AddRange(ProcessSeasonImages(consumer, series, consumerFiles));
|
||||
files.AddIfNotNull(ProcessArtistMetadata(consumer, artist, consumerFiles));
|
||||
files.AddRange(ProcessArtistImages(consumer, artist, consumerFiles));
|
||||
files.AddRange(ProcessAlbumImages(consumer, artist, consumerFiles));
|
||||
|
||||
foreach (var episodeFile in episodeFiles)
|
||||
foreach (var album in albums)
|
||||
{
|
||||
files.AddIfNotNull(ProcessEpisodeMetadata(consumer, series, episodeFile, consumerFiles));
|
||||
files.AddRange(ProcessEpisodeImages(consumer, series, episodeFile, consumerFiles));
|
||||
album.Artist = artist;
|
||||
files.AddIfNotNull(ProcessAlbumMetadata(consumer, album, consumerFiles));
|
||||
}
|
||||
|
||||
foreach (var trackFile in trackFiles)
|
||||
{
|
||||
files.AddIfNotNull(ProcessEpisodeMetadata(consumer, artist, trackFile, consumerFiles));
|
||||
files.AddRange(ProcessEpisodeImages(consumer, artist, trackFile, consumerFiles));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,15 +91,15 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
return files;
|
||||
}
|
||||
|
||||
public override IEnumerable<ExtraFile> CreateAfterEpisodeImport(Series series, EpisodeFile episodeFile)
|
||||
public override IEnumerable<ExtraFile> CreateAfterTrackImport(Artist artist, TrackFile trackFile)
|
||||
{
|
||||
var files = new List<MetadataFile>();
|
||||
|
||||
foreach (var consumer in _metadataFactory.Enabled())
|
||||
{
|
||||
|
||||
files.AddIfNotNull(ProcessEpisodeMetadata(consumer, series, episodeFile, new List<MetadataFile>()));
|
||||
files.AddRange(ProcessEpisodeImages(consumer, series, episodeFile, new List<MetadataFile>()));
|
||||
files.AddIfNotNull(ProcessEpisodeMetadata(consumer, artist, trackFile, new List<MetadataFile>()));
|
||||
files.AddRange(ProcessEpisodeImages(consumer, artist, trackFile, new List<MetadataFile>()));
|
||||
}
|
||||
|
||||
_metadataFileService.Upsert(files);
|
||||
@@ -98,11 +107,11 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
return files;
|
||||
}
|
||||
|
||||
public override IEnumerable<ExtraFile> CreateAfterEpisodeImport(Series series, string seriesFolder, string seasonFolder)
|
||||
public override IEnumerable<ExtraFile> CreateAfterTrackImport(Artist artist, string artistFolder, string albumFolder)
|
||||
{
|
||||
var metadataFiles = _metadataFileService.GetFilesBySeries(series.Id);
|
||||
var metadataFiles = _metadataFileService.GetFilesByArtist(artist.Id);
|
||||
|
||||
if (seriesFolder.IsNullOrWhiteSpace() && seasonFolder.IsNullOrWhiteSpace())
|
||||
if (artistFolder.IsNullOrWhiteSpace() && albumFolder.IsNullOrWhiteSpace())
|
||||
{
|
||||
return new List<MetadataFile>();
|
||||
}
|
||||
@@ -113,15 +122,15 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
{
|
||||
var consumerFiles = GetMetadataFilesForConsumer(consumer, metadataFiles);
|
||||
|
||||
if (seriesFolder.IsNotNullOrWhiteSpace())
|
||||
if (artistFolder.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
files.AddIfNotNull(ProcessSeriesMetadata(consumer, series, consumerFiles));
|
||||
files.AddRange(ProcessSeriesImages(consumer, series, consumerFiles));
|
||||
files.AddIfNotNull(ProcessArtistMetadata(consumer, artist, consumerFiles));
|
||||
files.AddRange(ProcessArtistImages(consumer, artist, consumerFiles));
|
||||
}
|
||||
|
||||
if (seasonFolder.IsNotNullOrWhiteSpace())
|
||||
if (albumFolder.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
files.AddRange(ProcessSeasonImages(consumer, series, consumerFiles));
|
||||
files.AddRange(ProcessAlbumImages(consumer, artist, consumerFiles));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,9 +139,9 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
return files;
|
||||
}
|
||||
|
||||
public override IEnumerable<ExtraFile> MoveFilesAfterRename(Series series, List<EpisodeFile> episodeFiles)
|
||||
public override IEnumerable<ExtraFile> MoveFilesAfterRename(Artist artist, List<TrackFile> trackFiles)
|
||||
{
|
||||
var metadataFiles = _metadataFileService.GetFilesBySeries(series.Id);
|
||||
var metadataFiles = _metadataFileService.GetFilesByArtist(artist.Id);
|
||||
var movedFiles = new List<MetadataFile>();
|
||||
|
||||
// TODO: Move EpisodeImage and EpisodeMetadata metadata files, instead of relying on consumers to do it
|
||||
@@ -140,21 +149,21 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
|
||||
foreach (var consumer in _metadataFactory.GetAvailableProviders())
|
||||
{
|
||||
foreach (var episodeFile in episodeFiles)
|
||||
foreach (var trackFile in trackFiles)
|
||||
{
|
||||
var metadataFilesForConsumer = GetMetadataFilesForConsumer(consumer, metadataFiles).Where(m => m.EpisodeFileId == episodeFile.Id).ToList();
|
||||
var metadataFilesForConsumer = GetMetadataFilesForConsumer(consumer, metadataFiles).Where(m => m.TrackFileId == trackFile.Id).ToList();
|
||||
|
||||
foreach (var metadataFile in metadataFilesForConsumer)
|
||||
{
|
||||
var newFileName = consumer.GetFilenameAfterMove(series, episodeFile, metadataFile);
|
||||
var existingFileName = Path.Combine(series.Path, metadataFile.RelativePath);
|
||||
var newFileName = consumer.GetFilenameAfterMove(artist, trackFile, metadataFile);
|
||||
var existingFileName = Path.Combine(artist.Path, metadataFile.RelativePath);
|
||||
|
||||
if (newFileName.PathNotEquals(existingFileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
_diskProvider.MoveFile(existingFileName, newFileName);
|
||||
metadataFile.RelativePath = series.Path.GetRelativePath(newFileName);
|
||||
metadataFile.RelativePath = artist.Path.GetRelativePath(newFileName);
|
||||
movedFiles.Add(metadataFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -171,40 +180,40 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
return movedFiles;
|
||||
}
|
||||
|
||||
public override ExtraFile Import(Series series, EpisodeFile episodeFile, string path, string extension, bool readOnly)
|
||||
public override ExtraFile Import(Artist artist, TrackFile trackFile, string path, string extension, bool readOnly)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<MetadataFile> GetMetadataFilesForConsumer(IMetadata consumer, List<MetadataFile> seriesMetadata)
|
||||
private List<MetadataFile> GetMetadataFilesForConsumer(IMetadata consumer, List<MetadataFile> artistMetadata)
|
||||
{
|
||||
return seriesMetadata.Where(c => c.Consumer == consumer.GetType().Name).ToList();
|
||||
return artistMetadata.Where(c => c.Consumer == consumer.GetType().Name).ToList();
|
||||
}
|
||||
|
||||
private MetadataFile ProcessSeriesMetadata(IMetadata consumer, Series series, List<MetadataFile> existingMetadataFiles)
|
||||
private MetadataFile ProcessArtistMetadata(IMetadata consumer, Artist artist, List<MetadataFile> existingMetadataFiles)
|
||||
{
|
||||
var seriesMetadata = consumer.SeriesMetadata(series);
|
||||
var artistMetadata = consumer.ArtistMetadata(artist);
|
||||
|
||||
if (seriesMetadata == null)
|
||||
if (artistMetadata == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var hash = seriesMetadata.Contents.SHA256Hash();
|
||||
var hash = artistMetadata.Contents.SHA256Hash();
|
||||
|
||||
var metadata = GetMetadataFile(series, existingMetadataFiles, e => e.Type == MetadataType.SeriesMetadata) ??
|
||||
var metadata = GetMetadataFile(artist, existingMetadataFiles, e => e.Type == MetadataType.ArtistMetadata) ??
|
||||
new MetadataFile
|
||||
{
|
||||
SeriesId = series.Id,
|
||||
ArtistId = artist.Id,
|
||||
Consumer = consumer.GetType().Name,
|
||||
Type = MetadataType.SeriesMetadata
|
||||
Type = MetadataType.ArtistMetadata
|
||||
};
|
||||
|
||||
if (hash == metadata.Hash)
|
||||
{
|
||||
if (seriesMetadata.RelativePath != metadata.RelativePath)
|
||||
if (artistMetadata.RelativePath != metadata.RelativePath)
|
||||
{
|
||||
metadata.RelativePath = seriesMetadata.RelativePath;
|
||||
metadata.RelativePath = artistMetadata.RelativePath;
|
||||
|
||||
return metadata;
|
||||
}
|
||||
@@ -212,35 +221,79 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
return null;
|
||||
}
|
||||
|
||||
var fullPath = Path.Combine(series.Path, seriesMetadata.RelativePath);
|
||||
var fullPath = Path.Combine(artist.Path, artistMetadata.RelativePath);
|
||||
|
||||
_logger.Debug("Writing Series Metadata to: {0}", fullPath);
|
||||
SaveMetadataFile(fullPath, seriesMetadata.Contents);
|
||||
_logger.Debug("Writing Artist Metadata to: {0}", fullPath);
|
||||
SaveMetadataFile(fullPath, artistMetadata.Contents);
|
||||
|
||||
metadata.Hash = hash;
|
||||
metadata.RelativePath = seriesMetadata.RelativePath;
|
||||
metadata.RelativePath = artistMetadata.RelativePath;
|
||||
metadata.Extension = Path.GetExtension(fullPath);
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private MetadataFile ProcessEpisodeMetadata(IMetadata consumer, Series series, EpisodeFile episodeFile, List<MetadataFile> existingMetadataFiles)
|
||||
private MetadataFile ProcessAlbumMetadata(IMetadata consumer, Album album, List<MetadataFile> existingMetadataFiles)
|
||||
{
|
||||
var episodeMetadata = consumer.EpisodeMetadata(series, episodeFile);
|
||||
var albumMetadata = consumer.AlbumMetadata(album.Artist, album);
|
||||
|
||||
if (albumMetadata == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var hash = albumMetadata.Contents.SHA256Hash();
|
||||
|
||||
var metadata = GetMetadataFile(album.Artist, existingMetadataFiles, e => e.Type == MetadataType.AlbumMetadata && e.AlbumId == album.Id) ??
|
||||
new MetadataFile
|
||||
{
|
||||
ArtistId = album.ArtistId,
|
||||
AlbumId = album.Id,
|
||||
Consumer = consumer.GetType().Name,
|
||||
Type = MetadataType.AlbumMetadata
|
||||
};
|
||||
|
||||
if (hash == metadata.Hash)
|
||||
{
|
||||
if (albumMetadata.RelativePath != metadata.RelativePath)
|
||||
{
|
||||
metadata.RelativePath = albumMetadata.RelativePath;
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var fullPath = Path.Combine(album.Path, albumMetadata.RelativePath);
|
||||
|
||||
_logger.Debug("Writing Album Metadata to: {0}", fullPath);
|
||||
SaveMetadataFile(fullPath, albumMetadata.Contents);
|
||||
|
||||
metadata.Hash = hash;
|
||||
metadata.RelativePath = albumMetadata.RelativePath;
|
||||
metadata.Extension = Path.GetExtension(fullPath);
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private MetadataFile ProcessEpisodeMetadata(IMetadata consumer, Artist artist, TrackFile trackFile, List<MetadataFile> existingMetadataFiles)
|
||||
{
|
||||
var episodeMetadata = consumer.TrackMetadata(artist, trackFile);
|
||||
|
||||
if (episodeMetadata == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var fullPath = Path.Combine(series.Path, episodeMetadata.RelativePath);
|
||||
var fullPath = Path.Combine(artist.Path, episodeMetadata.RelativePath);
|
||||
|
||||
var existingMetadata = GetMetadataFile(series, existingMetadataFiles, c => c.Type == MetadataType.EpisodeMetadata &&
|
||||
c.EpisodeFileId == episodeFile.Id);
|
||||
var existingMetadata = GetMetadataFile(artist, existingMetadataFiles, c => c.Type == MetadataType.TrackMetadata &&
|
||||
c.TrackFileId == trackFile.Id);
|
||||
|
||||
if (existingMetadata != null)
|
||||
{
|
||||
var existingFullPath = Path.Combine(series.Path, existingMetadata.RelativePath);
|
||||
var existingFullPath = Path.Combine(artist.Path, existingMetadata.RelativePath);
|
||||
if (fullPath.PathNotEquals(existingFullPath))
|
||||
{
|
||||
_diskTransferService.TransferFile(existingFullPath, fullPath, TransferMode.Move);
|
||||
@@ -253,11 +306,11 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
var metadata = existingMetadata ??
|
||||
new MetadataFile
|
||||
{
|
||||
SeriesId = series.Id,
|
||||
SeasonNumber = episodeFile.SeasonNumber,
|
||||
EpisodeFileId = episodeFile.Id,
|
||||
ArtistId = artist.Id,
|
||||
AlbumId = trackFile.AlbumId,
|
||||
TrackFileId = trackFile.Id,
|
||||
Consumer = consumer.GetType().Name,
|
||||
Type = MetadataType.EpisodeMetadata,
|
||||
Type = MetadataType.TrackMetadata,
|
||||
RelativePath = episodeMetadata.RelativePath,
|
||||
Extension = Path.GetExtension(fullPath)
|
||||
};
|
||||
@@ -267,7 +320,7 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
return null;
|
||||
}
|
||||
|
||||
_logger.Debug("Writing Episode Metadata to: {0}", fullPath);
|
||||
_logger.Debug("Writing Track Metadata to: {0}", fullPath);
|
||||
SaveMetadataFile(fullPath, episodeMetadata.Contents);
|
||||
|
||||
metadata.Hash = hash;
|
||||
@@ -275,32 +328,32 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private List<MetadataFile> ProcessSeriesImages(IMetadata consumer, Series series, List<MetadataFile> existingMetadataFiles)
|
||||
private List<MetadataFile> ProcessArtistImages(IMetadata consumer, Artist artist, List<MetadataFile> existingMetadataFiles)
|
||||
{
|
||||
var result = new List<MetadataFile>();
|
||||
|
||||
foreach (var image in consumer.SeriesImages(series))
|
||||
foreach (var image in consumer.ArtistImages(artist))
|
||||
{
|
||||
var fullPath = Path.Combine(series.Path, image.RelativePath);
|
||||
var fullPath = Path.Combine(artist.Path, image.RelativePath);
|
||||
|
||||
if (_diskProvider.FileExists(fullPath))
|
||||
{
|
||||
_logger.Debug("Series image already exists: {0}", fullPath);
|
||||
_logger.Debug("Artist image already exists: {0}", fullPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
var metadata = GetMetadataFile(series, existingMetadataFiles, c => c.Type == MetadataType.SeriesImage &&
|
||||
var metadata = GetMetadataFile(artist, existingMetadataFiles, c => c.Type == MetadataType.ArtistImage &&
|
||||
c.RelativePath == image.RelativePath) ??
|
||||
new MetadataFile
|
||||
{
|
||||
SeriesId = series.Id,
|
||||
ArtistId = artist.Id,
|
||||
Consumer = consumer.GetType().Name,
|
||||
Type = MetadataType.SeriesImage,
|
||||
Type = MetadataType.ArtistImage,
|
||||
RelativePath = image.RelativePath,
|
||||
Extension = Path.GetExtension(fullPath)
|
||||
};
|
||||
|
||||
DownloadImage(series, image);
|
||||
DownloadImage(artist, image);
|
||||
|
||||
result.Add(metadata);
|
||||
}
|
||||
@@ -308,36 +361,38 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<MetadataFile> ProcessSeasonImages(IMetadata consumer, Series series, List<MetadataFile> existingMetadataFiles)
|
||||
private List<MetadataFile> ProcessAlbumImages(IMetadata consumer, Artist artist, List<MetadataFile> existingMetadataFiles)
|
||||
{
|
||||
var result = new List<MetadataFile>();
|
||||
|
||||
foreach (var season in series.Seasons)
|
||||
var albums = _albumService.GetAlbumsByArtist(artist.Id);
|
||||
|
||||
foreach (var album in albums)
|
||||
{
|
||||
foreach (var image in consumer.SeasonImages(series, season))
|
||||
foreach (var image in consumer.AlbumImages(artist, album))
|
||||
{
|
||||
var fullPath = Path.Combine(series.Path, image.RelativePath);
|
||||
var fullPath = Path.Combine(artist.Path, image.RelativePath);
|
||||
|
||||
if (_diskProvider.FileExists(fullPath))
|
||||
{
|
||||
_logger.Debug("Season image already exists: {0}", fullPath);
|
||||
_logger.Debug("Album image already exists: {0}", fullPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
var metadata = GetMetadataFile(series, existingMetadataFiles, c => c.Type == MetadataType.SeasonImage &&
|
||||
c.SeasonNumber == season.SeasonNumber &&
|
||||
var metadata = GetMetadataFile(artist, existingMetadataFiles, c => c.Type == MetadataType.AlbumImage &&
|
||||
c.AlbumId == album.Id &&
|
||||
c.RelativePath == image.RelativePath) ??
|
||||
new MetadataFile
|
||||
{
|
||||
SeriesId = series.Id,
|
||||
SeasonNumber = season.SeasonNumber,
|
||||
ArtistId = artist.Id,
|
||||
AlbumId = album.Id,
|
||||
Consumer = consumer.GetType().Name,
|
||||
Type = MetadataType.SeasonImage,
|
||||
Type = MetadataType.AlbumImage,
|
||||
RelativePath = image.RelativePath,
|
||||
Extension = Path.GetExtension(fullPath)
|
||||
};
|
||||
|
||||
DownloadImage(series, image);
|
||||
DownloadImage(artist, image);
|
||||
|
||||
result.Add(metadata);
|
||||
}
|
||||
@@ -346,26 +401,26 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<MetadataFile> ProcessEpisodeImages(IMetadata consumer, Series series, EpisodeFile episodeFile, List<MetadataFile> existingMetadataFiles)
|
||||
private List<MetadataFile> ProcessEpisodeImages(IMetadata consumer, Artist artist, TrackFile trackFile, List<MetadataFile> existingMetadataFiles)
|
||||
{
|
||||
var result = new List<MetadataFile>();
|
||||
|
||||
foreach (var image in consumer.EpisodeImages(series, episodeFile))
|
||||
foreach (var image in consumer.TrackImages(artist, trackFile))
|
||||
{
|
||||
var fullPath = Path.Combine(series.Path, image.RelativePath);
|
||||
var fullPath = Path.Combine(artist.Path, image.RelativePath);
|
||||
|
||||
if (_diskProvider.FileExists(fullPath))
|
||||
{
|
||||
_logger.Debug("Episode image already exists: {0}", fullPath);
|
||||
_logger.Debug("Track image already exists: {0}", fullPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
var existingMetadata = GetMetadataFile(series, existingMetadataFiles, c => c.Type == MetadataType.EpisodeImage &&
|
||||
c.EpisodeFileId == episodeFile.Id);
|
||||
var existingMetadata = GetMetadataFile(artist, existingMetadataFiles, c => c.Type == MetadataType.TrackImage &&
|
||||
c.TrackFileId == trackFile.Id);
|
||||
|
||||
if (existingMetadata != null)
|
||||
{
|
||||
var existingFullPath = Path.Combine(series.Path, existingMetadata.RelativePath);
|
||||
var existingFullPath = Path.Combine(artist.Path, existingMetadata.RelativePath);
|
||||
if (fullPath.PathNotEquals(existingFullPath))
|
||||
{
|
||||
_diskTransferService.TransferFile(existingFullPath, fullPath, TransferMode.Move);
|
||||
@@ -378,16 +433,16 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
var metadata = existingMetadata ??
|
||||
new MetadataFile
|
||||
{
|
||||
SeriesId = series.Id,
|
||||
SeasonNumber = episodeFile.SeasonNumber,
|
||||
EpisodeFileId = episodeFile.Id,
|
||||
ArtistId = artist.Id,
|
||||
AlbumId = trackFile.AlbumId,
|
||||
TrackFileId = trackFile.Id,
|
||||
Consumer = consumer.GetType().Name,
|
||||
Type = MetadataType.EpisodeImage,
|
||||
Type = MetadataType.TrackImage,
|
||||
RelativePath = image.RelativePath,
|
||||
Extension = Path.GetExtension(fullPath)
|
||||
};
|
||||
|
||||
DownloadImage(series, image);
|
||||
DownloadImage(artist, image);
|
||||
|
||||
result.Add(metadata);
|
||||
}
|
||||
@@ -395,9 +450,9 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
return result;
|
||||
}
|
||||
|
||||
private void DownloadImage(Series series, ImageFileResult image)
|
||||
private void DownloadImage(Artist artist, ImageFileResult image)
|
||||
{
|
||||
var fullPath = Path.Combine(series.Path, image.RelativePath);
|
||||
var fullPath = Path.Combine(artist.Path, image.RelativePath);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -413,11 +468,11 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
_logger.Warn(ex, "Couldn't download image {0} for {1}. {2}", image.Url, series, ex.Message);
|
||||
_logger.Warn(ex, "Couldn't download image {0} for {1}. {2}", image.Url, artist, ex.Message);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex, "Couldn't download image {0} for {1}. {2}", image.Url, series, ex.Message);
|
||||
_logger.Error(ex, "Couldn't download image {0} for {1}. {2}", image.Url, artist, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,7 +482,7 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
_mediaFileAttributeService.SetFilePermissions(path);
|
||||
}
|
||||
|
||||
private MetadataFile GetMetadataFile(Series series, List<MetadataFile> existingMetadataFiles, Func<MetadataFile, bool> predicate)
|
||||
private MetadataFile GetMetadataFile(Artist artist, List<MetadataFile> existingMetadataFiles, Func<MetadataFile, bool> predicate)
|
||||
{
|
||||
var matchingMetadataFiles = existingMetadataFiles.Where(predicate).ToList();
|
||||
|
||||
@@ -439,7 +494,7 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
//Remove duplicate metadata files from DB and disk
|
||||
foreach (var file in matchingMetadataFiles.Skip(1))
|
||||
{
|
||||
var path = Path.Combine(series.Path, file.RelativePath);
|
||||
var path = Path.Combine(artist.Path, file.RelativePath);
|
||||
|
||||
_logger.Debug("Removing duplicate Metadata file: {0}", path);
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
namespace NzbDrone.Core.Extras.Metadata
|
||||
namespace NzbDrone.Core.Extras.Metadata
|
||||
{
|
||||
public enum MetadataType
|
||||
{
|
||||
Unknown = 0,
|
||||
SeriesMetadata = 1,
|
||||
EpisodeMetadata = 2,
|
||||
SeriesImage = 3,
|
||||
SeasonImage = 4,
|
||||
EpisodeImage = 5
|
||||
ArtistMetadata = 1,
|
||||
TrackMetadata = 2,
|
||||
ArtistImage = 3,
|
||||
AlbumImage = 4,
|
||||
TrackImage = 5,
|
||||
AlbumMetadata = 6
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user