mirror of
https://github.com/Readarr/Readarr.git
synced 2026-04-25 22:36:59 -04:00
Fixes Misc Issues with Album Metadata Extrafiles (#145)
* Fixes Misc Issues with Album Metadata Extrafiles * Fixed: Move Empty Subfolders to after ArtistRenamedEvent and Metadata mover * Remove Path from Album Table, Fix Wdtv, MediaBrowser, Roksbox * Remove Album Path from UI * Remove Comments and add Jpeg extension to XMBC image regex
This commit is contained in:
@@ -73,7 +73,6 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.MediaBrowser
|
||||
artistElement.Add(new XElement("LocalTitle", artist.Name));
|
||||
|
||||
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");
|
||||
|
||||
@@ -98,7 +97,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.MediaBrowser
|
||||
}
|
||||
}
|
||||
|
||||
public override MetadataFileResult AlbumMetadata(Artist artist, Album album)
|
||||
public override MetadataFileResult AlbumMetadata(Artist artist, Album album, string albumPath)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -113,7 +112,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.MediaBrowser
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> AlbumImages(Artist artist, Album season)
|
||||
public override List<ImageFileResult> AlbumImages(Artist artist, Album album, string albumFolder)
|
||||
{
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
-3
@@ -7,9 +7,6 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.MediaBrowser
|
||||
{
|
||||
public class MediaBrowserSettingsValidator : AbstractValidator<MediaBrowserMetadataSettings>
|
||||
{
|
||||
public MediaBrowserSettingsValidator()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class MediaBrowserMetadataSettings : IProviderConfig
|
||||
|
||||
@@ -31,7 +31,6 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
private static List<string> ValidCertification = new List<string> { "G", "NC-17", "PG", "PG-13", "R", "UR", "UNRATED", "NR", "TV-Y", "TV-Y7", "TV-Y7-FV", "TV-G", "TV-PG", "TV-14", "TV-MA" };
|
||||
private static readonly Regex SeasonImagesRegex = new Regex(@"^(season (?<season>\d+))|(?<specials>specials)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public override string Name => "Roksbox";
|
||||
@@ -40,11 +39,6 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
||||
{
|
||||
var trackFilePath = Path.Combine(artist.Path, trackFile.RelativePath);
|
||||
|
||||
if (metadataFile.Type == MetadataType.TrackImage)
|
||||
{
|
||||
return GetTrackImageFilename(trackFilePath);
|
||||
}
|
||||
|
||||
if (metadataFile.Type == MetadataType.TrackMetadata)
|
||||
{
|
||||
return GetTrackMetadataFilename(trackFilePath);
|
||||
@@ -104,16 +98,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
||||
{
|
||||
metadata.Type = MetadataType.TrackMetadata;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
if (extension == ".jpg")
|
||||
{
|
||||
if (!Path.GetFileNameWithoutExtension(filename).EndsWith("-thumb"))
|
||||
{
|
||||
metadata.Type = MetadataType.TrackImage;
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -125,14 +110,14 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
||||
return null;
|
||||
}
|
||||
|
||||
public override MetadataFileResult AlbumMetadata(Artist artist, Album album)
|
||||
public override MetadataFileResult AlbumMetadata(Artist artist, Album album, string albumPath)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override MetadataFileResult TrackMetadata(Artist artist, TrackFile trackFile)
|
||||
{
|
||||
if (!Settings.EpisodeMetadata)
|
||||
if (!Settings.TrackMetadata)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -151,11 +136,9 @@ 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} - {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));
|
||||
var details = new XElement("song");
|
||||
details.Add(new XElement("title", track.Title));
|
||||
details.Add(new XElement("performingartist", artist.Name));
|
||||
|
||||
doc.Add(details);
|
||||
doc.Save(xw);
|
||||
@@ -188,34 +171,9 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
||||
return new List<ImageFileResult>{ new ImageFileResult(destination, source) };
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> AlbumImages(Artist artist, Album album)
|
||||
public override List<ImageFileResult> AlbumImages(Artist artist, Album album, string albumFolder)
|
||||
{
|
||||
if (!Settings.AlbumImages)
|
||||
{
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
var albumFolders = GetAlbumFolders(artist);
|
||||
|
||||
string albumFolder;
|
||||
if (!albumFolders.TryGetValue(album.ArtistId, out albumFolder))
|
||||
{
|
||||
_logger.Trace("Failed to find album folder for artit {0}, album {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 = album.Images.SingleOrDefault(c => c.CoverType == MediaCoverTypes.Poster) ?? album.Images.FirstOrDefault();
|
||||
if (image == null)
|
||||
{
|
||||
_logger.Trace("Failed to find suitable album image for artist {0}, album {1}.", artist.Name, album.Title);
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
var filename = Path.GetFileName(albumFolder) + ".jpg";
|
||||
var path = artist.Path.GetRelativePath(Path.Combine(artist.Path, albumFolder, filename));
|
||||
|
||||
return new List<ImageFileResult> { new ImageFileResult(path, image.Url) };
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> TrackImages(Artist artist, TrackFile trackFile)
|
||||
|
||||
@@ -7,9 +7,6 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
||||
{
|
||||
public class RoksboxSettingsValidator : AbstractValidator<RoksboxMetadataSettings>
|
||||
{
|
||||
public RoksboxSettingsValidator()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class RoksboxMetadataSettings : IProviderConfig
|
||||
@@ -18,23 +15,19 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
||||
|
||||
public RoksboxMetadataSettings()
|
||||
{
|
||||
EpisodeMetadata = true;
|
||||
TrackMetadata = 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(0, Label = "Track Metadata", Type = FieldType.Checkbox, HelpText = "Season##\\filename.xml")]
|
||||
public bool TrackMetadata { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Artist Images", Type = FieldType.Checkbox, HelpText = "Artist Title.jpg")]
|
||||
public bool ArtistImages { 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; }
|
||||
|
||||
public bool IsValid => true;
|
||||
|
||||
|
||||
@@ -39,11 +39,6 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
||||
{
|
||||
var trackFilePath = Path.Combine(artist.Path, trackFile.RelativePath);
|
||||
|
||||
if (metadataFile.Type == MetadataType.TrackImage)
|
||||
{
|
||||
return GetTrackImageFilename(trackFilePath);
|
||||
}
|
||||
|
||||
if (metadataFile.Type == MetadataType.TrackMetadata)
|
||||
{
|
||||
return GetTrackMetadataFilename(trackFilePath);
|
||||
@@ -102,9 +97,6 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
||||
case ".xml":
|
||||
metadata.Type = MetadataType.TrackMetadata;
|
||||
return metadata;
|
||||
case ".metathumb":
|
||||
metadata.Type = MetadataType.TrackImage;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -118,14 +110,14 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
||||
return null;
|
||||
}
|
||||
|
||||
public override MetadataFileResult AlbumMetadata(Artist artist, Album album)
|
||||
public override MetadataFileResult AlbumMetadata(Artist artist, Album album, string albumPath)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override MetadataFileResult TrackMetadata(Artist artist, TrackFile trackFile)
|
||||
{
|
||||
if (!Settings.EpisodeMetadata)
|
||||
if (!Settings.TrackMetadata)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -150,7 +142,6 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
||||
details.Add(new XElement("artist_name", artist.Name));
|
||||
details.Add(new XElement("track_name", track.Title));
|
||||
details.Add(new XElement("track_number", track.AbsoluteTrackNumber.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))));
|
||||
|
||||
|
||||
@@ -195,7 +186,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
||||
};
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> AlbumImages(Artist artist, Album album)
|
||||
public override List<ImageFileResult> AlbumImages(Artist artist, Album album, string albumFolder)
|
||||
{
|
||||
if (!Settings.AlbumImages)
|
||||
{
|
||||
|
||||
@@ -7,9 +7,6 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
||||
{
|
||||
public class WdtvSettingsValidator : AbstractValidator<WdtvMetadataSettings>
|
||||
{
|
||||
public WdtvSettingsValidator()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class WdtvMetadataSettings : IProviderConfig
|
||||
@@ -18,23 +15,19 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
||||
|
||||
public WdtvMetadataSettings()
|
||||
{
|
||||
EpisodeMetadata = true;
|
||||
TrackMetadata = true;
|
||||
ArtistImages = true;
|
||||
AlbumImages = true;
|
||||
EpisodeImages = true;
|
||||
}
|
||||
|
||||
[FieldDefinition(0, Label = "Episode Metadata", Type = FieldType.Checkbox)]
|
||||
public bool EpisodeMetadata { get; set; }
|
||||
[FieldDefinition(0, Label = "Track Metadata", Type = FieldType.Checkbox)]
|
||||
public bool TrackMetadata { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Artist Images", Type = FieldType.Checkbox)]
|
||||
public bool ArtistImages { 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; }
|
||||
|
||||
public bool IsValid => true;
|
||||
|
||||
|
||||
@@ -27,9 +27,8 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
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);
|
||||
private static readonly Regex ArtistImagesRegex = new Regex(@"^(?<type>poster|banner|fanart|logo)\.(?:png|jpg|jpeg)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex AlbumImagesRegex = new Regex(@"^(?<type>cover|disc)\.(?:png|jpg|jpeg)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public override string Name => "Kodi (XBMC) / Emby";
|
||||
|
||||
@@ -37,14 +36,9 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
{
|
||||
var trackFilePath = Path.Combine(artist.Path, trackFile.RelativePath);
|
||||
|
||||
if (metadataFile.Type == MetadataType.TrackImage)
|
||||
{
|
||||
return GetEpisodeImageFilename(trackFilePath);
|
||||
}
|
||||
|
||||
if (metadataFile.Type == MetadataType.TrackMetadata)
|
||||
{
|
||||
return GetEpisodeMetadataFilename(trackFilePath);
|
||||
return GetTrackMetadataFilename(trackFilePath);
|
||||
}
|
||||
|
||||
_logger.Debug("Unknown episode file metadata: {0}", metadataFile.RelativePath);
|
||||
@@ -70,36 +64,11 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
return metadata;
|
||||
}
|
||||
|
||||
var seasonMatch = AlbumImagesRegex.Match(filename);
|
||||
var albumMatch = AlbumImagesRegex.Match(filename);
|
||||
|
||||
if (seasonMatch.Success)
|
||||
if (albumMatch.Success)
|
||||
{
|
||||
metadata.Type = MetadataType.AlbumImage;
|
||||
|
||||
var seasonNumberMatch = seasonMatch.Groups["season"].Value;
|
||||
int seasonNumber;
|
||||
|
||||
if (seasonNumberMatch.Contains("specials"))
|
||||
{
|
||||
metadata.AlbumId = 0;
|
||||
}
|
||||
|
||||
else if (int.TryParse(seasonNumberMatch, out seasonNumber))
|
||||
{
|
||||
metadata.AlbumId = seasonNumber;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
if (EpisodeImageRegex.IsMatch(filename))
|
||||
{
|
||||
metadata.Type = MetadataType.TrackImage;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@@ -186,7 +155,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
}
|
||||
}
|
||||
|
||||
public override MetadataFileResult AlbumMetadata(Artist artist, Album album)
|
||||
public override MetadataFileResult AlbumMetadata(Artist artist, Album album, string albumPath)
|
||||
{
|
||||
if (!Settings.AlbumMetadata)
|
||||
{
|
||||
@@ -217,9 +186,11 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
var doc = new XDocument(albumElement);
|
||||
doc.Save(xw);
|
||||
|
||||
_logger.Debug("Saving album.nfo for {0}", artist.Name);
|
||||
_logger.Debug("Saving album.nfo for {0}", album.Title);
|
||||
|
||||
var fileName = Path.Combine(albumPath, "album.nfo");
|
||||
|
||||
return new MetadataFileResult("album.nfo", doc.ToString());
|
||||
return new MetadataFileResult(fileName, doc.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,7 +282,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
}
|
||||
}
|
||||
|
||||
return new MetadataFileResult(GetEpisodeMetadataFilename(trackFile.RelativePath), xmlResult.Trim(Environment.NewLine.ToCharArray()));
|
||||
return new MetadataFileResult(GetTrackMetadataFilename(trackFile.RelativePath), xmlResult.Trim(Environment.NewLine.ToCharArray()));
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> ArtistImages(Artist artist)
|
||||
@@ -324,14 +295,14 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
return ProcessArtistImages(artist).ToList();
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> AlbumImages(Artist artist, Album album)
|
||||
public override List<ImageFileResult> AlbumImages(Artist artist, Album album, string albumPath)
|
||||
{
|
||||
if (!Settings.AlbumImages)
|
||||
{
|
||||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
return ProcessAlbumImages(album).ToList();
|
||||
return ProcessAlbumImages(artist, album, albumPath).ToList();
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> TrackImages(Artist artist, TrackFile trackFile)
|
||||
@@ -351,24 +322,21 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<ImageFileResult> ProcessAlbumImages(Album album)
|
||||
private IEnumerable<ImageFileResult> ProcessAlbumImages(Artist artist, Album album, string albumPath)
|
||||
{
|
||||
foreach (var image in album.Images)
|
||||
{
|
||||
var destination = image.CoverType.ToString().ToLowerInvariant() + Path.GetExtension(image.Url);
|
||||
// TODO: Make Source fallback to URL if local does not exist
|
||||
// var source = _mediaCoverService.GetCoverPath(album.ArtistId, image.CoverType, null, album.Id);
|
||||
var destination = Path.Combine(albumPath, image.CoverType.ToString().ToLowerInvariant() + Path.GetExtension(image.Url));
|
||||
|
||||
yield return new ImageFileResult(destination, image.Url);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetEpisodeMetadataFilename(string episodeFilePath)
|
||||
private string GetTrackMetadataFilename(string trackFilePath)
|
||||
{
|
||||
return Path.ChangeExtension(episodeFilePath, "nfo");
|
||||
}
|
||||
|
||||
private string GetEpisodeImageFilename(string episodeFilePath)
|
||||
{
|
||||
return Path.ChangeExtension(episodeFilePath, "").Trim('.') + "-thumb.jpg";
|
||||
return Path.ChangeExtension(trackFilePath, "nfo");
|
||||
}
|
||||
|
||||
private string GetAudioCodec(string audioCodec)
|
||||
|
||||
@@ -7,9 +7,6 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
{
|
||||
public class XbmcSettingsValidator : AbstractValidator<XbmcMetadataSettings>
|
||||
{
|
||||
public XbmcSettingsValidator()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class XbmcMetadataSettings : IProviderConfig
|
||||
@@ -23,7 +20,6 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
TrackMetadata = true;
|
||||
ArtistImages = true;
|
||||
AlbumImages = true;
|
||||
EpisodeImages = true;
|
||||
}
|
||||
|
||||
[FieldDefinition(0, Label = "Artist Metadata", Type = FieldType.Checkbox)]
|
||||
@@ -41,9 +37,6 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||
[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()
|
||||
|
||||
@@ -57,8 +57,20 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
continue;
|
||||
}
|
||||
|
||||
if (metadata.Type == MetadataType.TrackImage ||
|
||||
metadata.Type == MetadataType.TrackMetadata)
|
||||
if (metadata.Type == MetadataType.AlbumImage || metadata.Type == MetadataType.AlbumMetadata)
|
||||
{
|
||||
var localAlbum = _parsingService.GetLocalAlbum(possibleMetadataFile, artist);
|
||||
|
||||
if (localAlbum == null)
|
||||
{
|
||||
_logger.Debug("Extra file folder has multiple Albums: {0}", possibleMetadataFile);
|
||||
continue;
|
||||
}
|
||||
|
||||
metadata.AlbumId = localAlbum.Id;
|
||||
}
|
||||
|
||||
if (metadata.Type == MetadataType.TrackMetadata)
|
||||
{
|
||||
var localTrack = _parsingService.GetLocalTrack(possibleMetadataFile, artist);
|
||||
|
||||
@@ -70,7 +82,7 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
|
||||
if (localTrack.Tracks.Empty())
|
||||
{
|
||||
_logger.Debug("Cannot find related episodes for: {0}", possibleMetadataFile);
|
||||
_logger.Debug("Cannot find related tracks for: {0}", possibleMetadataFile);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -79,8 +91,7 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
_logger.Debug("Extra file: {0} does not match existing files.", possibleMetadataFile);
|
||||
continue;
|
||||
}
|
||||
|
||||
metadata.AlbumId = localTrack.Album.Id;
|
||||
|
||||
metadata.TrackFileId = localTrack.Tracks.First().TrackFileId;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,12 +9,13 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
public interface IMetadata : IProvider
|
||||
{
|
||||
string GetFilenameAfterMove(Artist artist, TrackFile trackFile, MetadataFile metadataFile);
|
||||
string GetFilenameAfterMove(Artist artist, string albumPath, MetadataFile metadataFile);
|
||||
MetadataFile FindMetadataFile(Artist artist, string path);
|
||||
MetadataFileResult ArtistMetadata(Artist artist);
|
||||
MetadataFileResult AlbumMetadata(Artist artist, Album album);
|
||||
MetadataFileResult AlbumMetadata(Artist artist, Album album, string albumPath);
|
||||
MetadataFileResult TrackMetadata(Artist artist, TrackFile trackFile);
|
||||
List<ImageFileResult> ArtistImages(Artist artist);
|
||||
List<ImageFileResult> AlbumImages(Artist artist, Album album);
|
||||
List<ImageFileResult> AlbumImages(Artist artist, Album album, string albumPath);
|
||||
List<ImageFileResult> TrackImages(Artist artist, TrackFile trackFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,13 +35,21 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
return newFileName;
|
||||
}
|
||||
|
||||
public virtual string GetFilenameAfterMove(Artist artist, string albumPath, MetadataFile metadataFile)
|
||||
{
|
||||
var existingFilename = Path.GetFileName(metadataFile.RelativePath);
|
||||
var newFileName = Path.Combine(artist.Path, albumPath, existingFilename);
|
||||
|
||||
return newFileName;
|
||||
}
|
||||
|
||||
public abstract MetadataFile FindMetadataFile(Artist artist, string path);
|
||||
|
||||
public abstract MetadataFileResult ArtistMetadata(Artist artist);
|
||||
public abstract MetadataFileResult AlbumMetadata(Artist artist, Album album);
|
||||
public abstract MetadataFileResult AlbumMetadata(Artist artist, Album album, string albumPath);
|
||||
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> AlbumImages(Artist artist, Album album, string albumPath);
|
||||
public abstract List<ImageFileResult> TrackImages(Artist artist, TrackFile trackFile);
|
||||
|
||||
public virtual object RequestAction(string action, IDictionary<string, string> query) { return null; }
|
||||
|
||||
@@ -12,6 +12,7 @@ using NzbDrone.Core.Extras.Files;
|
||||
using NzbDrone.Core.Extras.Metadata.Files;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Core.Organizer;
|
||||
|
||||
namespace NzbDrone.Core.Extras.Metadata
|
||||
{
|
||||
@@ -52,7 +53,7 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
|
||||
public override int Order => 0;
|
||||
|
||||
public override IEnumerable<ExtraFile> CreateAfterArtistScan(Artist artist, List<Album> albums, List<TrackFile> trackFiles)
|
||||
public override IEnumerable<ExtraFile> CreateAfterArtistScan(Artist artist, List<TrackFile> trackFiles)
|
||||
{
|
||||
var metadataFiles = _metadataFileService.GetFilesByArtist(artist.Id);
|
||||
_cleanMetadataService.Clean(artist);
|
||||
@@ -71,18 +72,20 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
|
||||
files.AddIfNotNull(ProcessArtistMetadata(consumer, artist, consumerFiles));
|
||||
files.AddRange(ProcessArtistImages(consumer, artist, consumerFiles));
|
||||
files.AddRange(ProcessAlbumImages(consumer, artist, consumerFiles));
|
||||
|
||||
var albumGroups = trackFiles.GroupBy(s => Path.GetDirectoryName(s.RelativePath)).ToList();
|
||||
|
||||
foreach (var album in albums)
|
||||
foreach (var group in albumGroups)
|
||||
{
|
||||
album.Artist = artist;
|
||||
files.AddIfNotNull(ProcessAlbumMetadata(consumer, album, consumerFiles));
|
||||
}
|
||||
var album = _albumService.GetAlbum(group.First().AlbumId);
|
||||
var albumFolder = group.Key;
|
||||
files.AddIfNotNull(ProcessAlbumMetadata(consumer, artist, album, albumFolder, consumerFiles));
|
||||
files.AddRange(ProcessAlbumImages(consumer, artist, album, albumFolder, consumerFiles));
|
||||
|
||||
foreach (var trackFile in trackFiles)
|
||||
{
|
||||
files.AddIfNotNull(ProcessEpisodeMetadata(consumer, artist, trackFile, consumerFiles));
|
||||
files.AddRange(ProcessEpisodeImages(consumer, artist, trackFile, consumerFiles));
|
||||
foreach (var trackFile in group)
|
||||
{
|
||||
files.AddIfNotNull(ProcessTrackMetadata(consumer, artist, trackFile, consumerFiles));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,9 +100,7 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
|
||||
foreach (var consumer in _metadataFactory.Enabled())
|
||||
{
|
||||
|
||||
files.AddIfNotNull(ProcessEpisodeMetadata(consumer, artist, trackFile, new List<MetadataFile>()));
|
||||
files.AddRange(ProcessEpisodeImages(consumer, artist, trackFile, new List<MetadataFile>()));
|
||||
files.AddIfNotNull(ProcessTrackMetadata(consumer, artist, trackFile, new List<MetadataFile>()));
|
||||
}
|
||||
|
||||
_metadataFileService.Upsert(files);
|
||||
@@ -107,7 +108,7 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
return files;
|
||||
}
|
||||
|
||||
public override IEnumerable<ExtraFile> CreateAfterTrackImport(Artist artist, string artistFolder, string albumFolder)
|
||||
public override IEnumerable<ExtraFile> CreateAfterTrackImport(Artist artist, Album album, string artistFolder, string albumFolder)
|
||||
{
|
||||
var metadataFiles = _metadataFileService.GetFilesByArtist(artist.Id);
|
||||
|
||||
@@ -127,11 +128,6 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
files.AddIfNotNull(ProcessArtistMetadata(consumer, artist, consumerFiles));
|
||||
files.AddRange(ProcessArtistImages(consumer, artist, consumerFiles));
|
||||
}
|
||||
|
||||
if (albumFolder.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
files.AddRange(ProcessAlbumImages(consumer, artist, consumerFiles));
|
||||
}
|
||||
}
|
||||
|
||||
_metadataFileService.Upsert(files);
|
||||
@@ -143,12 +139,42 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
{
|
||||
var metadataFiles = _metadataFileService.GetFilesByArtist(artist.Id);
|
||||
var movedFiles = new List<MetadataFile>();
|
||||
var distinctTrackFilePaths = trackFiles.DistinctBy(s => Path.GetDirectoryName(s.RelativePath)).ToList();
|
||||
|
||||
// TODO: Move EpisodeImage and EpisodeMetadata metadata files, instead of relying on consumers to do it
|
||||
// (Xbmc's EpisodeImage is more than just the extension)
|
||||
|
||||
foreach (var consumer in _metadataFactory.GetAvailableProviders())
|
||||
{
|
||||
foreach (var filePath in distinctTrackFilePaths)
|
||||
{
|
||||
var metadataFilesForConsumer = GetMetadataFilesForConsumer(consumer, metadataFiles)
|
||||
.Where(m => m.AlbumId == filePath.AlbumId)
|
||||
.Where(m => m.Type == MetadataType.AlbumImage || m.Type == MetadataType.AlbumMetadata)
|
||||
.ToList();
|
||||
|
||||
foreach (var metadataFile in metadataFilesForConsumer)
|
||||
{
|
||||
var newFileName = consumer.GetFilenameAfterMove(artist, Path.GetDirectoryName(filePath.RelativePath), metadataFile);
|
||||
var existingFileName = Path.Combine(artist.Path, metadataFile.RelativePath);
|
||||
|
||||
if (newFileName.PathNotEquals(existingFileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
_diskProvider.MoveFile(existingFileName, newFileName);
|
||||
metadataFile.RelativePath = artist.Path.GetRelativePath(newFileName);
|
||||
movedFiles.Add(metadataFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warn(ex, "Unable to move metadata file after rename: {0}", existingFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach (var trackFile in trackFiles)
|
||||
{
|
||||
var metadataFilesForConsumer = GetMetadataFilesForConsumer(consumer, metadataFiles).Where(m => m.TrackFileId == trackFile.Id).ToList();
|
||||
@@ -233,9 +259,9 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private MetadataFile ProcessAlbumMetadata(IMetadata consumer, Album album, List<MetadataFile> existingMetadataFiles)
|
||||
private MetadataFile ProcessAlbumMetadata(IMetadata consumer, Artist artist, Album album, string albumPath, List<MetadataFile> existingMetadataFiles)
|
||||
{
|
||||
var albumMetadata = consumer.AlbumMetadata(album.Artist, album);
|
||||
var albumMetadata = consumer.AlbumMetadata(artist, album, albumPath);
|
||||
|
||||
if (albumMetadata == null)
|
||||
{
|
||||
@@ -244,10 +270,10 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
|
||||
var hash = albumMetadata.Contents.SHA256Hash();
|
||||
|
||||
var metadata = GetMetadataFile(album.Artist, existingMetadataFiles, e => e.Type == MetadataType.AlbumMetadata && e.AlbumId == album.Id) ??
|
||||
var metadata = GetMetadataFile(artist, existingMetadataFiles, e => e.Type == MetadataType.AlbumMetadata && e.AlbumId == album.Id) ??
|
||||
new MetadataFile
|
||||
{
|
||||
ArtistId = album.ArtistId,
|
||||
ArtistId = artist.Id,
|
||||
AlbumId = album.Id,
|
||||
Consumer = consumer.GetType().Name,
|
||||
Type = MetadataType.AlbumMetadata
|
||||
@@ -265,7 +291,7 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
return null;
|
||||
}
|
||||
|
||||
var fullPath = Path.Combine(album.Path, albumMetadata.RelativePath);
|
||||
var fullPath = Path.Combine(artist.Path, albumMetadata.RelativePath);
|
||||
|
||||
_logger.Debug("Writing Album Metadata to: {0}", fullPath);
|
||||
SaveMetadataFile(fullPath, albumMetadata.Contents);
|
||||
@@ -277,16 +303,16 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private MetadataFile ProcessEpisodeMetadata(IMetadata consumer, Artist artist, TrackFile trackFile, List<MetadataFile> existingMetadataFiles)
|
||||
private MetadataFile ProcessTrackMetadata(IMetadata consumer, Artist artist, TrackFile trackFile, List<MetadataFile> existingMetadataFiles)
|
||||
{
|
||||
var episodeMetadata = consumer.TrackMetadata(artist, trackFile);
|
||||
var trackMetadata = consumer.TrackMetadata(artist, trackFile);
|
||||
|
||||
if (episodeMetadata == null)
|
||||
if (trackMetadata == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var fullPath = Path.Combine(artist.Path, episodeMetadata.RelativePath);
|
||||
var fullPath = Path.Combine(artist.Path, trackMetadata.RelativePath);
|
||||
|
||||
var existingMetadata = GetMetadataFile(artist, existingMetadataFiles, c => c.Type == MetadataType.TrackMetadata &&
|
||||
c.TrackFileId == trackFile.Id);
|
||||
@@ -297,11 +323,11 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
if (fullPath.PathNotEquals(existingFullPath))
|
||||
{
|
||||
_diskTransferService.TransferFile(existingFullPath, fullPath, TransferMode.Move);
|
||||
existingMetadata.RelativePath = episodeMetadata.RelativePath;
|
||||
existingMetadata.RelativePath = trackMetadata.RelativePath;
|
||||
}
|
||||
}
|
||||
|
||||
var hash = episodeMetadata.Contents.SHA256Hash();
|
||||
var hash = trackMetadata.Contents.SHA256Hash();
|
||||
|
||||
var metadata = existingMetadata ??
|
||||
new MetadataFile
|
||||
@@ -311,7 +337,7 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
TrackFileId = trackFile.Id,
|
||||
Consumer = consumer.GetType().Name,
|
||||
Type = MetadataType.TrackMetadata,
|
||||
RelativePath = episodeMetadata.RelativePath,
|
||||
RelativePath = trackMetadata.RelativePath,
|
||||
Extension = Path.GetExtension(fullPath)
|
||||
};
|
||||
|
||||
@@ -321,7 +347,7 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
}
|
||||
|
||||
_logger.Debug("Writing Track Metadata to: {0}", fullPath);
|
||||
SaveMetadataFile(fullPath, episodeMetadata.Contents);
|
||||
SaveMetadataFile(fullPath, trackMetadata.Contents);
|
||||
|
||||
metadata.Hash = hash;
|
||||
|
||||
@@ -361,92 +387,39 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<MetadataFile> ProcessAlbumImages(IMetadata consumer, Artist artist, List<MetadataFile> existingMetadataFiles)
|
||||
private List<MetadataFile> ProcessAlbumImages(IMetadata consumer, Artist artist, Album album, string albumFolder, List<MetadataFile> existingMetadataFiles)
|
||||
{
|
||||
var result = new List<MetadataFile>();
|
||||
|
||||
var albums = _albumService.GetAlbumsByArtist(artist.Id);
|
||||
|
||||
foreach (var album in albums)
|
||||
{
|
||||
foreach (var image in consumer.AlbumImages(artist, album))
|
||||
{
|
||||
var fullPath = Path.Combine(artist.Path, image.RelativePath);
|
||||
|
||||
if (_diskProvider.FileExists(fullPath))
|
||||
{
|
||||
_logger.Debug("Album image already exists: {0}", fullPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
var metadata = GetMetadataFile(artist, existingMetadataFiles, c => c.Type == MetadataType.AlbumImage &&
|
||||
c.AlbumId == album.Id &&
|
||||
c.RelativePath == image.RelativePath) ??
|
||||
new MetadataFile
|
||||
{
|
||||
ArtistId = artist.Id,
|
||||
AlbumId = album.Id,
|
||||
Consumer = consumer.GetType().Name,
|
||||
Type = MetadataType.AlbumImage,
|
||||
RelativePath = image.RelativePath,
|
||||
Extension = Path.GetExtension(fullPath)
|
||||
};
|
||||
|
||||
DownloadImage(album, image);
|
||||
|
||||
result.Add(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<MetadataFile> ProcessEpisodeImages(IMetadata consumer, Artist artist, TrackFile trackFile, List<MetadataFile> existingMetadataFiles)
|
||||
{
|
||||
var result = new List<MetadataFile>();
|
||||
|
||||
foreach (var image in consumer.TrackImages(artist, trackFile))
|
||||
foreach (var image in consumer.AlbumImages(artist, album, albumFolder))
|
||||
{
|
||||
var fullPath = Path.Combine(artist.Path, image.RelativePath);
|
||||
|
||||
if (_diskProvider.FileExists(fullPath))
|
||||
{
|
||||
_logger.Debug("Track image already exists: {0}", fullPath);
|
||||
_logger.Debug("Album image already exists: {0}", fullPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
var existingMetadata = GetMetadataFile(artist, existingMetadataFiles, c => c.Type == MetadataType.TrackImage &&
|
||||
c.TrackFileId == trackFile.Id);
|
||||
|
||||
if (existingMetadata != null)
|
||||
{
|
||||
var existingFullPath = Path.Combine(artist.Path, existingMetadata.RelativePath);
|
||||
if (fullPath.PathNotEquals(existingFullPath))
|
||||
{
|
||||
_diskTransferService.TransferFile(existingFullPath, fullPath, TransferMode.Move);
|
||||
existingMetadata.RelativePath = image.RelativePath;
|
||||
|
||||
return new List<MetadataFile>{ existingMetadata };
|
||||
}
|
||||
}
|
||||
|
||||
var metadata = existingMetadata ??
|
||||
new MetadataFile
|
||||
{
|
||||
ArtistId = artist.Id,
|
||||
AlbumId = trackFile.AlbumId,
|
||||
TrackFileId = trackFile.Id,
|
||||
Consumer = consumer.GetType().Name,
|
||||
Type = MetadataType.TrackImage,
|
||||
RelativePath = image.RelativePath,
|
||||
Extension = Path.GetExtension(fullPath)
|
||||
};
|
||||
var metadata = GetMetadataFile(artist, existingMetadataFiles, c => c.Type == MetadataType.AlbumImage &&
|
||||
c.AlbumId == album.Id &&
|
||||
c.RelativePath == image.RelativePath) ??
|
||||
new MetadataFile
|
||||
{
|
||||
ArtistId = artist.Id,
|
||||
AlbumId = album.Id,
|
||||
Consumer = consumer.GetType().Name,
|
||||
Type = MetadataType.AlbumImage,
|
||||
RelativePath = image.RelativePath,
|
||||
Extension = Path.GetExtension(fullPath)
|
||||
};
|
||||
|
||||
DownloadImage(artist, image);
|
||||
|
||||
result.Add(metadata);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -476,32 +449,6 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
}
|
||||
}
|
||||
|
||||
private void DownloadImage(Album album, ImageFileResult image)
|
||||
{
|
||||
var fullPath = Path.Combine(album.Path, image.RelativePath);
|
||||
|
||||
try
|
||||
{
|
||||
if (image.Url.StartsWith("http"))
|
||||
{
|
||||
_httpClient.DownloadFile(image.Url, fullPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
_diskProvider.CopyFile(image.Url, fullPath);
|
||||
}
|
||||
_mediaFileAttributeService.SetFilePermissions(fullPath);
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
_logger.Warn(ex, "Couldn't download image {0} for {1}. {2}", image.Url, album, ex.Message);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex, "Couldn't download image {0} for {1}. {2}", image.Url, album, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveMetadataFile(string path, string contents)
|
||||
{
|
||||
_diskProvider.WriteAllText(path, contents);
|
||||
|
||||
Reference in New Issue
Block a user