diff --git a/frontend/src/Artist/Details/AlbumRow.js b/frontend/src/Artist/Details/AlbumRow.js index 0c9f27cf3..8f27f9ed2 100644 --- a/frontend/src/Artist/Details/AlbumRow.js +++ b/frontend/src/Artist/Details/AlbumRow.js @@ -67,7 +67,6 @@ class AlbumRow extends Component { title, isSaving, artistMonitored, - path, columns } = this.props; @@ -122,16 +121,6 @@ class AlbumRow extends Component { ); } - if (name === 'path') { - return ( - - { - path - } - - ); - } - if (name === 'mediumCount') { return ( @@ -221,7 +210,6 @@ AlbumRow.propTypes = { unverifiedSceneNumbering: PropTypes.bool, artistMonitored: PropTypes.bool.isRequired, statistics: PropTypes.object.isRequired, - path: PropTypes.string, mediaInfo: PropTypes.object, alternateTitles: PropTypes.arrayOf(PropTypes.object).isRequired, columns: PropTypes.arrayOf(PropTypes.object).isRequired, diff --git a/frontend/src/Store/Actions/episodeActions.js b/frontend/src/Store/Actions/episodeActions.js index 0e1859444..5ef09261e 100644 --- a/frontend/src/Store/Actions/episodeActions.js +++ b/frontend/src/Store/Actions/episodeActions.js @@ -39,11 +39,6 @@ export const defaultState = { label: 'Title', isVisible: true }, - { - name: 'path', - label: 'Path', - isVisible: false - }, { name: 'releaseDate', label: 'Release Date', diff --git a/src/Lidarr.Api.V1/Albums/AlbumResource.cs b/src/Lidarr.Api.V1/Albums/AlbumResource.cs index a7043a37f..018e70997 100644 --- a/src/Lidarr.Api.V1/Albums/AlbumResource.cs +++ b/src/Lidarr.Api.V1/Albums/AlbumResource.cs @@ -16,7 +16,6 @@ namespace Lidarr.Api.V1.Albums public List AlbumLabel { get; set; } public string ForeignAlbumId { get; set; } public bool Monitored { get; set; } - public string Path { get; set; } public int ProfileId { get; set; } public int Duration { get; set; } public string AlbumType { get; set; } @@ -57,7 +56,6 @@ namespace Lidarr.Api.V1.Albums ArtistId = model.ArtistId, AlbumLabel = model.Label, ForeignAlbumId = model.ForeignAlbumId, - Path = model.Path, ProfileId = model.ProfileId, Monitored = model.Monitored, ReleaseDate = model.ReleaseDate, diff --git a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupDuplicateMetadataFilesFixture.cs b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupDuplicateMetadataFilesFixture.cs index 2f4180a89..8fc699cfa 100644 --- a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupDuplicateMetadataFilesFixture.cs +++ b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupDuplicateMetadataFilesFixture.cs @@ -66,12 +66,13 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers } [Test] - public void should_not_delete_metadata_files_when_they_are_for_the_same_track_but_different_consumers() + public void should_not_delete_metadata_files_when_they_are_for_the_same_album_but_different_consumers() { var files = Builder.CreateListOfSize(2) .All() - .With(m => m.Type = MetadataType.TrackMetadata) - .With(m => m.TrackFileId = 1) + .With(m => m.Type = MetadataType.AlbumMetadata) + .With(m => m.ArtistId = 1) + .With(m => m.AlbumId = 1) .BuildListOfNew(); Db.InsertMany(files); @@ -80,12 +81,13 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers } [Test] - public void should_not_delete_metadata_files_for_different_track() + public void should_not_delete_metadata_files_for_different_album() { var files = Builder.CreateListOfSize(2) .All() - .With(m => m.Type = MetadataType.TrackMetadata) + .With(m => m.Type = MetadataType.AlbumMetadata) .With(m => m.Consumer = "XbmcMetadata") + .With(m => m.ArtistId = 1) .BuildListOfNew(); Db.InsertMany(files); @@ -94,12 +96,13 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers } [Test] - public void should_delete_metadata_files_when_they_are_for_the_same_track_and_consumer() + public void should_delete_metadata_files_when_they_are_for_the_same_album_and_consumer() { var files = Builder.CreateListOfSize(2) .All() - .With(m => m.Type = MetadataType.TrackMetadata) - .With(m => m.TrackFileId = 1) + .With(m => m.Type = MetadataType.AlbumMetadata) + .With(m => m.ArtistId = 1) + .With(m => m.AlbumId = 1) .With(m => m.Consumer = "XbmcMetadata") .BuildListOfNew(); @@ -109,10 +112,10 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers } [Test] - public void should_not_delete_metadata_files_when_there_is_only_one_for_that_track_and_consumer() + public void should_not_delete_metadata_files_when_there_is_only_one_for_that_album_and_consumer() { var file = Builder.CreateNew() - .BuildNew(); + .BuildNew(); Db.Insert(file); Subject.Clean(); @@ -120,11 +123,11 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers } [Test] - public void should_not_delete_image_when_they_are_for_the_same_track_but_different_consumers() + public void should_not_delete_metadata_files_when_they_are_for_the_same_track_but_different_consumers() { var files = Builder.CreateListOfSize(2) .All() - .With(m => m.Type = MetadataType.TrackImage) + .With(m => m.Type = MetadataType.TrackMetadata) .With(m => m.TrackFileId = 1) .BuildListOfNew(); @@ -134,11 +137,11 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers } [Test] - public void should_not_delete_image_for_different_track() + public void should_not_delete_metadata_files_for_different_track() { var files = Builder.CreateListOfSize(2) .All() - .With(m => m.Type = MetadataType.TrackImage) + .With(m => m.Type = MetadataType.TrackMetadata) .With(m => m.Consumer = "XbmcMetadata") .BuildListOfNew(); @@ -148,11 +151,11 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers } [Test] - public void should_delete_image_when_they_are_for_the_same_track_and_consumer() + public void should_delete_metadata_files_when_they_are_for_the_same_track_and_consumer() { var files = Builder.CreateListOfSize(2) .All() - .With(m => m.Type = MetadataType.TrackImage) + .With(m => m.Type = MetadataType.TrackMetadata) .With(m => m.TrackFileId = 1) .With(m => m.Consumer = "XbmcMetadata") .BuildListOfNew(); @@ -163,7 +166,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers } [Test] - public void should_not_delete_image_when_there_is_only_one_for_that_track_and_consumer() + public void should_not_delete_metadata_files_when_there_is_only_one_for_that_track_and_consumer() { var file = Builder.CreateNew() .BuildNew(); diff --git a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedMetadataFilesFixture.cs b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedMetadataFilesFixture.cs index 843622445..ed8877812 100644 --- a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedMetadataFilesFixture.cs +++ b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedMetadataFilesFixture.cs @@ -93,10 +93,15 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers var artist = Builder.CreateNew() .BuildNew(); + var album = Builder.CreateNew() + .BuildNew(); + Db.Insert(artist); + Db.Insert(album); var metadataFile = Builder.CreateNew() .With(m => m.ArtistId = artist.Id) + .With(m => m.AlbumId = album.Id) .With(m => m.TrackFileId = 10) .BuildNew(); @@ -134,18 +139,39 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers } [Test] - public void should_delete_track_metadata_files_that_have_trackfileid_of_zero() + public void should_delete_album_metadata_files_that_have_albumid_of_zero() { var artist = Builder.CreateNew() - .BuildNew(); + .BuildNew(); Db.Insert(artist); var metadataFile = Builder.CreateNew() - .With(m => m.ArtistId = artist.Id) - .With(m => m.Type = MetadataType.TrackMetadata) - .With(m => m.TrackFileId = 0) - .BuildNew(); + .With(m => m.ArtistId = artist.Id) + .With(m => m.Type = MetadataType.AlbumMetadata) + .With(m => m.AlbumId = 0) + .With(m => m.TrackFileId = null) + .BuildNew(); + + Db.Insert(metadataFile); + Subject.Clean(); + AllStoredModels.Should().HaveCount(0); + } + + [Test] + public void should_delete_album_image_files_that_have_albumid_of_zero() + { + var artist = Builder.CreateNew() + .BuildNew(); + + Db.Insert(artist); + + var metadataFile = Builder.CreateNew() + .With(m => m.ArtistId = artist.Id) + .With(m => m.Type = MetadataType.AlbumImage) + .With(m => m.AlbumId = 0) + .With(m => m.TrackFileId = null) + .BuildNew(); Db.Insert(metadataFile); Subject.Clean(); @@ -153,7 +179,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers } [Test] - public void should_delete_track_image_files_that_have_trackfileid_of_zero() + public void should_delete_track_metadata_files_that_have_trackfileid_of_zero() { var artist = Builder.CreateNew() .BuildNew(); @@ -161,10 +187,10 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers Db.Insert(artist); var metadataFile = Builder.CreateNew() - .With(m => m.ArtistId = artist.Id) - .With(m => m.Type = MetadataType.TrackImage) - .With(m => m.TrackFileId = 0) - .BuildNew(); + .With(m => m.ArtistId = artist.Id) + .With(m => m.Type = MetadataType.TrackMetadata) + .With(m => m.TrackFileId = 0) + .BuildNew(); Db.Insert(metadataFile); Subject.Clean(); diff --git a/src/NzbDrone.Core.Test/Metadata/Consumers/Roksbox/FindMetadataFileFixture.cs b/src/NzbDrone.Core.Test/Metadata/Consumers/Roksbox/FindMetadataFileFixture.cs index 9e7326d1f..5e47ee97c 100644 --- a/src/NzbDrone.Core.Test/Metadata/Consumers/Roksbox/FindMetadataFileFixture.cs +++ b/src/NzbDrone.Core.Test/Metadata/Consumers/Roksbox/FindMetadataFileFixture.cs @@ -13,66 +13,65 @@ namespace NzbDrone.Core.Test.Metadata.Consumers.Roksbox [TestFixture] public class FindMetadataFileFixture : CoreTest { - private Artist _series; + private Artist _artist; [SetUp] public void Setup() { - _series = Builder.CreateNew() - .With(s => s.Path = @"C:\Test\TV\The.Series".AsOsAgnostic()) + _artist = Builder.CreateNew() + .With(s => s.Path = @"C:\Test\Music\The.Artist".AsOsAgnostic()) .Build(); } [Test] public void should_return_null_if_filename_is_not_handled() { - var path = Path.Combine(_series.Path, "file.jpg"); + var path = Path.Combine(_artist.Path, "file.jpg"); - Subject.FindMetadataFile(_series, path).Should().BeNull(); + Subject.FindMetadataFile(_artist, path).Should().BeNull(); } [TestCase("Specials")] [TestCase("specials")] [TestCase("Season 1")] - public void should_return_season_image(string folder) + public void should_return_album_image(string folder) { - var path = Path.Combine(_series.Path, folder, folder + ".jpg"); + var path = Path.Combine(_artist.Path, folder, folder + ".jpg"); - Subject.FindMetadataFile(_series, path).Type.Should().Be(MetadataType.AlbumImage); + Subject.FindMetadataFile(_artist, path).Type.Should().Be(MetadataType.AlbumImage); } [TestCase(".xml", MetadataType.TrackMetadata)] - [TestCase(".jpg", MetadataType.TrackImage)] - public void should_return_metadata_for_episode_if_valid_file_for_episode(string extension, MetadataType type) + public void should_return_metadata_for_track_if_valid_file_for_track(string extension, MetadataType type) { - var path = Path.Combine(_series.Path, "the.series.s01e01.episode" + extension); + var path = Path.Combine(_artist.Path, "the.artist.s01e01.track" + extension); - Subject.FindMetadataFile(_series, path).Type.Should().Be(type); + Subject.FindMetadataFile(_artist, path).Type.Should().Be(type); } [TestCase(".xml")] [TestCase(".jpg")] - public void should_return_null_if_not_valid_file_for_episode(string extension) + public void should_return_null_if_not_valid_file_for_track(string extension) { - var path = Path.Combine(_series.Path, "the.series.episode" + extension); + var path = Path.Combine(_artist.Path, "the.artist.track" + extension); - Subject.FindMetadataFile(_series, path).Should().BeNull(); + Subject.FindMetadataFile(_artist, path).Should().BeNull(); } [Test] public void should_not_return_metadata_if_image_file_is_a_thumb() { - var path = Path.Combine(_series.Path, "the.series.s01e01.episode-thumb.jpg"); + var path = Path.Combine(_artist.Path, "the.artist.s01e01.track-thumb.jpg"); - Subject.FindMetadataFile(_series, path).Should().BeNull(); + Subject.FindMetadataFile(_artist, path).Should().BeNull(); } [Test] - public void should_return_series_image_for_folder_jpg_in_series_folder() + public void should_return_artist_image_for_folder_jpg_in_artist_folder() { - var path = Path.Combine(_series.Path, new DirectoryInfo(_series.Path).Name + ".jpg"); + var path = Path.Combine(_artist.Path, new DirectoryInfo(_artist.Path).Name + ".jpg"); - Subject.FindMetadataFile(_series, path).Type.Should().Be(MetadataType.ArtistImage); + Subject.FindMetadataFile(_artist, path).Type.Should().Be(MetadataType.ArtistImage); } } } diff --git a/src/NzbDrone.Core.Test/Metadata/Consumers/Wdtv/FindMetadataFileFixture.cs b/src/NzbDrone.Core.Test/Metadata/Consumers/Wdtv/FindMetadataFileFixture.cs index e3d956b71..1c1ac264b 100644 --- a/src/NzbDrone.Core.Test/Metadata/Consumers/Wdtv/FindMetadataFileFixture.cs +++ b/src/NzbDrone.Core.Test/Metadata/Consumers/Wdtv/FindMetadataFileFixture.cs @@ -13,58 +13,57 @@ namespace NzbDrone.Core.Test.Metadata.Consumers.Wdtv [TestFixture] public class FindMetadataFileFixture : CoreTest { - private Artist _series; + private Artist _artist; [SetUp] public void Setup() { - _series = Builder.CreateNew() - .With(s => s.Path = @"C:\Test\TV\The.Series".AsOsAgnostic()) + _artist = Builder.CreateNew() + .With(s => s.Path = @"C:\Test\Music\The.Artist".AsOsAgnostic()) .Build(); } [Test] public void should_return_null_if_filename_is_not_handled() { - var path = Path.Combine(_series.Path, "file.jpg"); + var path = Path.Combine(_artist.Path, "file.jpg"); - Subject.FindMetadataFile(_series, path).Should().BeNull(); + Subject.FindMetadataFile(_artist, path).Should().BeNull(); } [TestCase("Specials")] [TestCase("specials")] [TestCase("Season 1")] - public void should_return_season_image(string folder) + public void should_return_album_image(string folder) { - var path = Path.Combine(_series.Path, folder, "folder.jpg"); + var path = Path.Combine(_artist.Path, folder, "folder.jpg"); - Subject.FindMetadataFile(_series, path).Type.Should().Be(MetadataType.AlbumImage); + Subject.FindMetadataFile(_artist, path).Type.Should().Be(MetadataType.AlbumImage); } [TestCase(".xml", MetadataType.TrackMetadata)] - [TestCase(".metathumb", MetadataType.TrackImage)] - public void should_return_metadata_for_episode_if_valid_file_for_episode(string extension, MetadataType type) + public void should_return_metadata_for_track_if_valid_file_for_track(string extension, MetadataType type) { - var path = Path.Combine(_series.Path, "the.series.s01e01.episode" + extension); + var path = Path.Combine(_artist.Path, "the.artist.s01e01.track" + extension); - Subject.FindMetadataFile(_series, path).Type.Should().Be(type); + Subject.FindMetadataFile(_artist, path).Type.Should().Be(type); } [TestCase(".xml")] [TestCase(".metathumb")] - public void should_return_null_if_not_valid_file_for_episode(string extension) + public void should_return_null_if_not_valid_file_for_track(string extension) { - var path = Path.Combine(_series.Path, "the.series.episode" + extension); + var path = Path.Combine(_artist.Path, "the.artist.track" + extension); - Subject.FindMetadataFile(_series, path).Should().BeNull(); + Subject.FindMetadataFile(_artist, path).Should().BeNull(); } [Test] - public void should_return_series_image_for_folder_jpg_in_series_folder() + public void should_return_artist_image_for_folder_jpg_in_artist_folder() { - var path = Path.Combine(_series.Path, "folder.jpg"); + var path = Path.Combine(_artist.Path, "folder.jpg"); - Subject.FindMetadataFile(_series, path).Type.Should().Be(MetadataType.ArtistImage); + Subject.FindMetadataFile(_artist, path).Type.Should().Be(MetadataType.ArtistImage); } } } diff --git a/src/NzbDrone.Core.Test/OrganizerTests/BuildFilePathFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/BuildFilePathFixture.cs index 0d41c5a31..0af5aad66 100644 --- a/src/NzbDrone.Core.Test/OrganizerTests/BuildFilePathFixture.cs +++ b/src/NzbDrone.Core.Test/OrganizerTests/BuildFilePathFixture.cs @@ -1,4 +1,4 @@ -using FizzWare.NBuilder; +using FizzWare.NBuilder; using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.Organizer; @@ -37,7 +37,6 @@ namespace NzbDrone.Core.Test.OrganizerTests var fakeAlbum = Builder.CreateNew() .With(s => s.Title = "Fake: Album") - .With(s => s.Path = @"C:\Test\Fake- The Artist\Fake- Album".AsOsAgnostic()) .Build(); namingConfig.AlbumFolderFormat = "{Artist Name} {Album Title}"; @@ -45,4 +44,4 @@ namespace NzbDrone.Core.Test.OrganizerTests Subject.BuildTrackFilePath(fakeArtist, fakeAlbum, filename, ".flac").Should().Be(expectedPath.AsOsAgnostic()); } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Core/Datastore/Migration/007_change_album_path_to_relative.cs b/src/NzbDrone.Core/Datastore/Migration/007_change_album_path_to_relative.cs new file mode 100644 index 000000000..cafeff1e0 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/007_change_album_path_to_relative.cs @@ -0,0 +1,14 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(7)] + public class change_album_path_to_relative : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Delete.Column("Path").FromTable("Albums"); + } + } +} diff --git a/src/NzbDrone.Core/Extras/ExtraService.cs b/src/NzbDrone.Core/Extras/ExtraService.cs index 0c9851b9d..85604773c 100644 --- a/src/NzbDrone.Core/Extras/ExtraService.cs +++ b/src/NzbDrone.Core/Extras/ExtraService.cs @@ -27,7 +27,6 @@ namespace NzbDrone.Core.Extras IHandle { private readonly IMediaFileService _mediaFileService; - //private readonly IEpisodeService _episodeService; private readonly IAlbumService _albumService; private readonly ITrackService _trackService; private readonly IDiskProvider _diskProvider; @@ -36,7 +35,6 @@ namespace NzbDrone.Core.Extras private readonly Logger _logger; public ExtraService(IMediaFileService mediaFileService, - //IEpisodeService episodeService, IAlbumService albumService, ITrackService trackService, IDiskProvider diskProvider, @@ -45,7 +43,6 @@ namespace NzbDrone.Core.Extras Logger logger) { _mediaFileService = mediaFileService; - //_episodeService = episodeService; _albumService = albumService; _trackService = trackService; _diskProvider = diskProvider; @@ -111,22 +108,23 @@ namespace NzbDrone.Core.Extras public void Handle(MediaCoversUpdatedEvent message) { var artist = message.Artist; - var albums = _albumService.GetAlbumsByArtist(artist.Id); + var trackFiles = GetTrackFiles(artist.Id); foreach (var extraFileManager in _extraFileManagers) { - extraFileManager.CreateAfterArtistScan(artist, albums, trackFiles); + extraFileManager.CreateAfterArtistScan(artist, trackFiles); } } public void Handle(TrackFolderCreatedEvent message) { var artist = message.Artist; + var album = _albumService.GetAlbum(message.TrackFile.AlbumId); foreach (var extraFileManager in _extraFileManagers) { - extraFileManager.CreateAfterTrackImport(artist, message.ArtistFolder, message.AlbumFolder); + extraFileManager.CreateAfterTrackImport(artist, album, message.ArtistFolder, message.AlbumFolder); } } diff --git a/src/NzbDrone.Core/Extras/Files/ExtraFileManager.cs b/src/NzbDrone.Core/Extras/Files/ExtraFileManager.cs index b0599bff6..187e8e2b6 100644 --- a/src/NzbDrone.Core/Extras/Files/ExtraFileManager.cs +++ b/src/NzbDrone.Core/Extras/Files/ExtraFileManager.cs @@ -14,9 +14,9 @@ namespace NzbDrone.Core.Extras.Files public interface IManageExtraFiles { int Order { get; } - IEnumerable CreateAfterArtistScan(Artist artist, List albums, List trackFiles); + IEnumerable CreateAfterArtistScan(Artist artist, List trackFiles); IEnumerable CreateAfterTrackImport(Artist artist, TrackFile trackFile); - IEnumerable CreateAfterTrackImport(Artist artist, string artistFolder, string albumFolder); + IEnumerable CreateAfterTrackImport(Artist artist, Album album, string artistFolder, string albumFolder); IEnumerable MoveFilesAfterRename(Artist artist, List trackFiles); ExtraFile Import(Artist artist, TrackFile trackFile, string path, string extension, bool readOnly); } @@ -42,9 +42,9 @@ namespace NzbDrone.Core.Extras.Files } public abstract int Order { get; } - public abstract IEnumerable CreateAfterArtistScan(Artist artist, List albums, List trackFiles); + public abstract IEnumerable CreateAfterArtistScan(Artist artist, List trackFiles); public abstract IEnumerable CreateAfterTrackImport(Artist artist, TrackFile trackFile); - public abstract IEnumerable CreateAfterTrackImport(Artist artist, string artistFolder, string albumFolder); + public abstract IEnumerable CreateAfterTrackImport(Artist artist, Album album, string artistFolder, string albumFolder); public abstract IEnumerable MoveFilesAfterRename(Artist artist, List trackFiles); public abstract ExtraFile Import(Artist artist, TrackFile trackFile, string path, string extension, bool readOnly); diff --git a/src/NzbDrone.Core/Extras/Lyrics/LyricService.cs b/src/NzbDrone.Core/Extras/Lyrics/LyricService.cs index 679157989..b476c5490 100644 --- a/src/NzbDrone.Core/Extras/Lyrics/LyricService.cs +++ b/src/NzbDrone.Core/Extras/Lyrics/LyricService.cs @@ -32,7 +32,7 @@ namespace NzbDrone.Core.Extras.Lyrics public override int Order => 1; - public override IEnumerable CreateAfterArtistScan(Artist artist, List albums, List trackFiles) + public override IEnumerable CreateAfterArtistScan(Artist artist, List trackFiles) { return Enumerable.Empty(); } @@ -42,7 +42,7 @@ namespace NzbDrone.Core.Extras.Lyrics return Enumerable.Empty(); } - public override IEnumerable CreateAfterTrackImport(Artist artist, string artistFolder, string albumFolder) + public override IEnumerable CreateAfterTrackImport(Artist artist, Album album, string artistFolder, string albumFolder) { return Enumerable.Empty(); } diff --git a/src/NzbDrone.Core/Extras/Metadata/Consumers/MediaBrowser/MediaBrowserMetadata.cs b/src/NzbDrone.Core/Extras/Metadata/Consumers/MediaBrowser/MediaBrowserMetadata.cs index 9c1dd86a7..9fc771d2b 100644 --- a/src/NzbDrone.Core/Extras/Metadata/Consumers/MediaBrowser/MediaBrowserMetadata.cs +++ b/src/NzbDrone.Core/Extras/Metadata/Consumers/MediaBrowser/MediaBrowserMetadata.cs @@ -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(); } - public override List AlbumImages(Artist artist, Album season) + public override List AlbumImages(Artist artist, Album album, string albumFolder) { return new List(); } diff --git a/src/NzbDrone.Core/Extras/Metadata/Consumers/MediaBrowser/MediaBrowserMetadataSettings.cs b/src/NzbDrone.Core/Extras/Metadata/Consumers/MediaBrowser/MediaBrowserMetadataSettings.cs index c81e4924b..bf2f3c3ae 100644 --- a/src/NzbDrone.Core/Extras/Metadata/Consumers/MediaBrowser/MediaBrowserMetadataSettings.cs +++ b/src/NzbDrone.Core/Extras/Metadata/Consumers/MediaBrowser/MediaBrowserMetadataSettings.cs @@ -7,9 +7,6 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.MediaBrowser { public class MediaBrowserSettingsValidator : AbstractValidator { - public MediaBrowserSettingsValidator() - { - } } public class MediaBrowserMetadataSettings : IProviderConfig diff --git a/src/NzbDrone.Core/Extras/Metadata/Consumers/Roksbox/RoksboxMetadata.cs b/src/NzbDrone.Core/Extras/Metadata/Consumers/Roksbox/RoksboxMetadata.cs index e2229cc07..e8cf1ca59 100644 --- a/src/NzbDrone.Core/Extras/Metadata/Consumers/Roksbox/RoksboxMetadata.cs +++ b/src/NzbDrone.Core/Extras/Metadata/Consumers/Roksbox/RoksboxMetadata.cs @@ -31,7 +31,6 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox _logger = logger; } - private static List ValidCertification = new List { "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 (?\d+))|(?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{ new ImageFileResult(destination, source) }; } - public override List AlbumImages(Artist artist, Album album) + public override List AlbumImages(Artist artist, Album album, string albumFolder) { - if (!Settings.AlbumImages) - { - return new List(); - } - - 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(); - } - - //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(); - } - - var filename = Path.GetFileName(albumFolder) + ".jpg"; - var path = artist.Path.GetRelativePath(Path.Combine(artist.Path, albumFolder, filename)); - - return new List { new ImageFileResult(path, image.Url) }; + return new List(); } public override List TrackImages(Artist artist, TrackFile trackFile) diff --git a/src/NzbDrone.Core/Extras/Metadata/Consumers/Roksbox/RoksboxMetadataSettings.cs b/src/NzbDrone.Core/Extras/Metadata/Consumers/Roksbox/RoksboxMetadataSettings.cs index 9e5f18eaf..366be26b4 100644 --- a/src/NzbDrone.Core/Extras/Metadata/Consumers/Roksbox/RoksboxMetadataSettings.cs +++ b/src/NzbDrone.Core/Extras/Metadata/Consumers/Roksbox/RoksboxMetadataSettings.cs @@ -7,9 +7,6 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox { public class RoksboxSettingsValidator : AbstractValidator { - 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; diff --git a/src/NzbDrone.Core/Extras/Metadata/Consumers/Wdtv/WdtvMetadata.cs b/src/NzbDrone.Core/Extras/Metadata/Consumers/Wdtv/WdtvMetadata.cs index 25f1c236a..f9896a1a7 100644 --- a/src/NzbDrone.Core/Extras/Metadata/Consumers/Wdtv/WdtvMetadata.cs +++ b/src/NzbDrone.Core/Extras/Metadata/Consumers/Wdtv/WdtvMetadata.cs @@ -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 AlbumImages(Artist artist, Album album) + public override List AlbumImages(Artist artist, Album album, string albumFolder) { if (!Settings.AlbumImages) { diff --git a/src/NzbDrone.Core/Extras/Metadata/Consumers/Wdtv/WdtvMetadataSettings.cs b/src/NzbDrone.Core/Extras/Metadata/Consumers/Wdtv/WdtvMetadataSettings.cs index 8b954c653..32102cc15 100644 --- a/src/NzbDrone.Core/Extras/Metadata/Consumers/Wdtv/WdtvMetadataSettings.cs +++ b/src/NzbDrone.Core/Extras/Metadata/Consumers/Wdtv/WdtvMetadataSettings.cs @@ -7,9 +7,6 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv { public class WdtvSettingsValidator : AbstractValidator { - 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; diff --git a/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadata.cs b/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadata.cs index 12bb5daf5..747a20920 100644 --- a/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadata.cs +++ b/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadata.cs @@ -27,9 +27,8 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc _logger = logger; } - private static readonly Regex ArtistImagesRegex = new Regex(@"^(?poster|banner|fanart|logo)\.(?:png|jpg)", RegexOptions.Compiled | RegexOptions.IgnoreCase); - private static readonly Regex AlbumImagesRegex = new Regex(@"^season(?\d{2,}|-all|-specials)-(?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(@"^(?poster|banner|fanart|logo)\.(?:png|jpg|jpeg)", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex AlbumImagesRegex = new Regex(@"^(?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 ArtistImages(Artist artist) @@ -324,14 +295,14 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc return ProcessArtistImages(artist).ToList(); } - public override List AlbumImages(Artist artist, Album album) + public override List AlbumImages(Artist artist, Album album, string albumPath) { if (!Settings.AlbumImages) { return new List(); } - return ProcessAlbumImages(album).ToList(); + return ProcessAlbumImages(artist, album, albumPath).ToList(); } public override List TrackImages(Artist artist, TrackFile trackFile) @@ -351,24 +322,21 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc } } - private IEnumerable ProcessAlbumImages(Album album) + private IEnumerable 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) - { - return Path.ChangeExtension(episodeFilePath, "nfo"); - } - - private string GetEpisodeImageFilename(string episodeFilePath) + private string GetTrackMetadataFilename(string trackFilePath) { - return Path.ChangeExtension(episodeFilePath, "").Trim('.') + "-thumb.jpg"; + return Path.ChangeExtension(trackFilePath, "nfo"); } private string GetAudioCodec(string audioCodec) diff --git a/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadataSettings.cs b/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadataSettings.cs index f093f82ca..6879ae79e 100644 --- a/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadataSettings.cs +++ b/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadataSettings.cs @@ -7,9 +7,6 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc { public class XbmcSettingsValidator : AbstractValidator { - 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() diff --git a/src/NzbDrone.Core/Extras/Metadata/ExistingMetadataImporter.cs b/src/NzbDrone.Core/Extras/Metadata/ExistingMetadataImporter.cs index be52758d0..363f85c58 100644 --- a/src/NzbDrone.Core/Extras/Metadata/ExistingMetadataImporter.cs +++ b/src/NzbDrone.Core/Extras/Metadata/ExistingMetadataImporter.cs @@ -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; } diff --git a/src/NzbDrone.Core/Extras/Metadata/IMetadata.cs b/src/NzbDrone.Core/Extras/Metadata/IMetadata.cs index 31c3cc17f..7abee9e8b 100644 --- a/src/NzbDrone.Core/Extras/Metadata/IMetadata.cs +++ b/src/NzbDrone.Core/Extras/Metadata/IMetadata.cs @@ -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 ArtistImages(Artist artist); - List AlbumImages(Artist artist, Album album); + List AlbumImages(Artist artist, Album album, string albumPath); List TrackImages(Artist artist, TrackFile trackFile); } } diff --git a/src/NzbDrone.Core/Extras/Metadata/MetadataBase.cs b/src/NzbDrone.Core/Extras/Metadata/MetadataBase.cs index 4897d2cdf..fc6899f99 100644 --- a/src/NzbDrone.Core/Extras/Metadata/MetadataBase.cs +++ b/src/NzbDrone.Core/Extras/Metadata/MetadataBase.cs @@ -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 ArtistImages(Artist artist); - public abstract List AlbumImages(Artist artist, Album album); + public abstract List AlbumImages(Artist artist, Album album, string albumPath); public abstract List TrackImages(Artist artist, TrackFile trackFile); public virtual object RequestAction(string action, IDictionary query) { return null; } diff --git a/src/NzbDrone.Core/Extras/Metadata/MetadataService.cs b/src/NzbDrone.Core/Extras/Metadata/MetadataService.cs index 9d6383fd9..ca66db98d 100644 --- a/src/NzbDrone.Core/Extras/Metadata/MetadataService.cs +++ b/src/NzbDrone.Core/Extras/Metadata/MetadataService.cs @@ -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 CreateAfterArtistScan(Artist artist, List albums, List trackFiles) + public override IEnumerable CreateAfterArtistScan(Artist artist, List 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())); - files.AddRange(ProcessEpisodeImages(consumer, artist, trackFile, new List())); + files.AddIfNotNull(ProcessTrackMetadata(consumer, artist, trackFile, new List())); } _metadataFileService.Upsert(files); @@ -107,7 +108,7 @@ namespace NzbDrone.Core.Extras.Metadata return files; } - public override IEnumerable CreateAfterTrackImport(Artist artist, string artistFolder, string albumFolder) + public override IEnumerable 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(); + 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 existingMetadataFiles) + private MetadataFile ProcessAlbumMetadata(IMetadata consumer, Artist artist, Album album, string albumPath, List 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 existingMetadataFiles) + private MetadataFile ProcessTrackMetadata(IMetadata consumer, Artist artist, TrackFile trackFile, List 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 ProcessAlbumImages(IMetadata consumer, Artist artist, List existingMetadataFiles) + private List ProcessAlbumImages(IMetadata consumer, Artist artist, Album album, string albumFolder, List existingMetadataFiles) { var result = new List(); - 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 ProcessEpisodeImages(IMetadata consumer, Artist artist, TrackFile trackFile, List existingMetadataFiles) - { - var result = new List(); - - 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{ 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); diff --git a/src/NzbDrone.Core/Extras/Others/OtherExtraService.cs b/src/NzbDrone.Core/Extras/Others/OtherExtraService.cs index 664d212d5..609740978 100644 --- a/src/NzbDrone.Core/Extras/Others/OtherExtraService.cs +++ b/src/NzbDrone.Core/Extras/Others/OtherExtraService.cs @@ -28,7 +28,7 @@ namespace NzbDrone.Core.Extras.Others public override int Order => 2; - public override IEnumerable CreateAfterArtistScan(Artist artist, List albums, List trackFiles) + public override IEnumerable CreateAfterArtistScan(Artist artist, List trackFiles) { return Enumerable.Empty(); } @@ -38,7 +38,7 @@ namespace NzbDrone.Core.Extras.Others return Enumerable.Empty(); } - public override IEnumerable CreateAfterTrackImport(Artist artist, string artistFolder, string albumFolder) + public override IEnumerable CreateAfterTrackImport(Artist artist, Album album, string artistFolder, string albumFolder) { return Enumerable.Empty(); } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupDuplicateMetadataFiles.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupDuplicateMetadataFiles.cs index 5f21924ed..f7df1b567 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupDuplicateMetadataFiles.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupDuplicateMetadataFiles.cs @@ -14,6 +14,7 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers public void Clean() { DeleteDuplicateArtistMetadata(); + DeleteDuplicateAlbumMetadata(); DeleteDuplicateTrackMetadata(); DeleteDuplicateTrackImages(); } diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedMetadataFiles.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedMetadataFiles.cs index 20fca61b7..f83359ec1 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedMetadataFiles.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedMetadataFiles.cs @@ -16,6 +16,7 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers DeleteOrphanedByArtist(); DeleteOrphanedByAlbum(); DeleteOrphanedByTrackFile(); + DeleteWhereAlbumIdIsZero(); DeleteWhereTrackFileIsZero(); } @@ -57,6 +58,17 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers AND TrackFiles.Id IS NULL)"); } + private void DeleteWhereAlbumIdIsZero() + { + var mapper = _database.GetDataMapper(); + + mapper.ExecuteNonQuery(@"DELETE FROM MetadataFiles + WHERE Id IN ( + SELECT Id FROM MetadataFiles + WHERE Type IN (4, 6) + AND AlbumId = 0)"); + } + private void DeleteWhereTrackFileIsZero() { var mapper = _database.GetDataMapper(); diff --git a/src/NzbDrone.Core/MediaFiles/RenameTrackFileService.cs b/src/NzbDrone.Core/MediaFiles/RenameTrackFileService.cs index e4dff636b..ec8c9a3b6 100644 --- a/src/NzbDrone.Core/MediaFiles/RenameTrackFileService.cs +++ b/src/NzbDrone.Core/MediaFiles/RenameTrackFileService.cs @@ -144,9 +144,10 @@ namespace NzbDrone.Core.MediaFiles if (renamed.Any()) { - _diskProvider.RemoveEmptySubfolders(artist.Path); - _eventAggregator.PublishEvent(new ArtistRenamedEvent(artist)); + + _logger.Debug("Removing Empty Subfolders from: {0}", artist.Path); + _diskProvider.RemoveEmptySubfolders(artist.Path); } } diff --git a/src/NzbDrone.Core/Music/Album.cs b/src/NzbDrone.Core/Music/Album.cs index 74cb25cb0..2b83f6f92 100644 --- a/src/NzbDrone.Core/Music/Album.cs +++ b/src/NzbDrone.Core/Music/Album.cs @@ -2,8 +2,6 @@ using NzbDrone.Common.Extensions; using NzbDrone.Core.Datastore; using System; using System.Collections.Generic; -using System.Linq; -using System.Text; namespace NzbDrone.Core.Music { @@ -24,12 +22,9 @@ namespace NzbDrone.Core.Music public string CleanTitle { get; set; } public DateTime? ReleaseDate { get; set; } public List Label { get; set; } - //public int TrackCount { get; set; } - public string Path { get; set; } public int ProfileId { get; set; } public int Duration { get; set; } public List Tracks { get; set; } - //public int DiscCount { get; set; } public bool Monitored { get; set; } public List Images { get; set; } public List Genres { get; set; } diff --git a/src/NzbDrone.Core/Music/AlbumRepository.cs b/src/NzbDrone.Core/Music/AlbumRepository.cs index 439e9c698..6e295b3be 100644 --- a/src/NzbDrone.Core/Music/AlbumRepository.cs +++ b/src/NzbDrone.Core/Music/AlbumRepository.cs @@ -8,12 +8,12 @@ using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Languages; using NzbDrone.Core.Qualities; using Marr.Data.QGen; +using NzbDrone.Common.Extensions; namespace NzbDrone.Core.Music { public interface IAlbumRepository : IBasicRepository { - bool AlbumPathExists(string path); List GetAlbums(int artistId); Album FindByName(string cleanTitle); Album FindByTitle(int artistId, string title); @@ -37,11 +37,6 @@ namespace NzbDrone.Core.Music } - public bool AlbumPathExists(string path) - { - return Query.Where(c => c.Path == path).Any(); - } - public List GetAlbums(int artistId) { return Query.Where(s => s.ArtistId == artistId).ToList(); diff --git a/src/NzbDrone.Core/Music/AlbumService.cs b/src/NzbDrone.Core/Music/AlbumService.cs index 8bc71f8d8..ea57b19b2 100644 --- a/src/NzbDrone.Core/Music/AlbumService.cs +++ b/src/NzbDrone.Core/Music/AlbumService.cs @@ -33,7 +33,6 @@ namespace NzbDrone.Core.Music void InsertMany(List albums); void UpdateMany(List albums); void DeleteMany(List albums); - bool AlbumPathExists(string folder); void RemoveAddOptions(Album album); } @@ -67,11 +66,6 @@ namespace NzbDrone.Core.Music return newAlbum; } - public bool AlbumPathExists(string folder) - { - return _albumRepository.AlbumPathExists(folder); - } - public void DeleteAlbum(int albumId, bool deleteFiles) { var album = _albumRepository.Get(albumId); @@ -89,7 +83,6 @@ namespace NzbDrone.Core.Music return _albumRepository.FindByTitle(artistId, title); } - public Album FindByTitleInexact(string title) { throw new NotImplementedException(); diff --git a/src/NzbDrone.Core/Music/RefreshAlbumService.cs b/src/NzbDrone.Core/Music/RefreshAlbumService.cs index abd6220a4..da8d63041 100644 --- a/src/NzbDrone.Core/Music/RefreshAlbumService.cs +++ b/src/NzbDrone.Core/Music/RefreshAlbumService.cs @@ -62,11 +62,6 @@ namespace NzbDrone.Core.Music albumToUpdate.ProfileId = artist.ProfileId; albumToUpdate.Added = DateTime.UtcNow; - if (string.IsNullOrWhiteSpace(albumToUpdate.Path)) - { - albumToUpdate.Path = _fileNameBuilder.BuildAlbumPath(artist, album); - } - newList.Add(albumToUpdate); } diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index d0f214d26..55668eea2 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -178,6 +178,7 @@ + diff --git a/src/NzbDrone.Core/Parser/ParsingService.cs b/src/NzbDrone.Core/Parser/ParsingService.cs index 754f29798..397de7bf4 100644 --- a/src/NzbDrone.Core/Parser/ParsingService.cs +++ b/src/NzbDrone.Core/Parser/ParsingService.cs @@ -20,6 +20,7 @@ namespace NzbDrone.Core.Parser List GetAlbums(ParsedAlbumInfo parsedAlbumInfo, Artist artist, SearchCriteriaBase searchCriteria = null); // Music stuff here + Album GetLocalAlbum(string filename, Artist artist); LocalTrack GetLocalTrack(string filename, Artist artist); LocalTrack GetLocalTrack(string filename, Artist artist, ParsedTrackInfo folderInfo); @@ -30,11 +31,13 @@ namespace NzbDrone.Core.Parser private readonly IArtistService _artistService; private readonly IAlbumService _albumService; private readonly ITrackService _trackService; + private readonly IMediaFileService _mediaFileService; private readonly Logger _logger; public ParsingService(ITrackService trackService, IArtistService artistService, IAlbumService albumService, + IMediaFileService mediaFileService, // ISceneMappingService sceneMappingService, Logger logger) { @@ -42,6 +45,7 @@ namespace NzbDrone.Core.Parser _artistService = artistService; // _sceneMappingService = sceneMappingService; _trackService = trackService; + _mediaFileService = mediaFileService; _logger = logger; } @@ -174,6 +178,24 @@ namespace NzbDrone.Core.Parser return artist; } + public Album GetLocalAlbum(string filename, Artist artist) + { + + if (Path.HasExtension(filename)) + { + filename = Path.GetDirectoryName(filename); + } + + filename = artist.Path.GetRelativePath(filename); + + var tracksInAlbum = _mediaFileService.GetFilesByArtist(artist.Id) + .FindAll(s => Path.GetDirectoryName(s.RelativePath) == filename) + .DistinctBy(s => s.AlbumId) + .ToList(); + + return tracksInAlbum.Count == 1 ? _albumService.GetAlbum(tracksInAlbum.First().AlbumId) : null; + } + public LocalTrack GetLocalTrack(string filename, Artist artist) { return GetLocalTrack(filename, artist, null);