Rework Movie Metadata data model

This commit is contained in:
Qstick 2022-03-20 10:55:47 -05:00
parent 1576bf1f17
commit 6a03eddda9
126 changed files with 1695 additions and 1031 deletions

View file

@ -116,10 +116,11 @@ class NamingModal extends Component {
const movieTokens = [
{ token: '{Movie Title}', example: 'Movie\'s Title' },
{ token: '{Movie Title:DE}', example: 'Filetitle' },
{ token: '{Movie Title:DE}', example: 'Titel des Films' },
{ token: '{Movie CleanTitle}', example: 'Movies Title' },
{ token: '{Movie TitleThe}', example: 'Movie\'s Title, The' },
{ token: '{Movie OriginalTitle}', example: 'Τίτλος ταινίας' },
{ token: '{Movie CleanOriginalTitle}', example: 'Τίτλος ταινίας' },
{ token: '{Movie TitleFirstCharacter}', example: 'M' },
{ token: '{Movie Collection}', example: 'The Movie Collection' },
{ token: '{Movie Certification}', example: 'R' },

View file

@ -0,0 +1,303 @@
using System;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Datastore.Migration;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Datastore.Migration
{
[TestFixture]
public class movie_metadataFixture : MigrationTest<movie_metadata>
{
[Test]
public void should_add_metadata_from_movie_and_link_back_to_movie()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Movies").Row(new
{
Monitored = true,
Title = "Title",
CleanTitle = "CleanTitle",
Status = 3,
MinimumAvailability = 4,
Images = new[] { new { CoverType = "Poster" } }.ToJson(),
Recommendations = new[] { 1 }.ToJson(),
Runtime = 90,
OriginalLanguage = 1,
ProfileId = 1,
MovieFileId = 0,
Path = string.Format("/Movies/{0}", "Title"),
TitleSlug = 123456,
TmdbId = 132456,
Added = DateTime.UtcNow,
Collection = new { Name = "Some Collection", TmdbId = 11 }.ToJson(),
LastInfoSync = DateTime.UtcNow,
});
});
var metadata = db.Query<MovieMetadata207>("SELECT \"Id\", \"Title\", \"TmdbId\" FROM \"MovieMetadata\"");
metadata.Should().HaveCount(1);
metadata.First().TmdbId.Should().Be(132456);
metadata.First().Title.Should().Be("Title");
var movies = db.Query<Movie207>("SELECT \"Id\", \"MovieMetadataId\" FROM \"Movies\"");
movies.Should().HaveCount(1);
movies.First().MovieMetadataId.Should().Be(metadata.First().Id);
}
[Test]
public void should_link_metadata_to_credits()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Movies").Row(new
{
Id = 5,
Monitored = true,
Title = "Title",
CleanTitle = "CleanTitle",
Status = 3,
MinimumAvailability = 4,
Images = new[] { new { CoverType = "Poster" } }.ToJson(),
Recommendations = new[] { 1 }.ToJson(),
Runtime = 90,
OriginalLanguage = 1,
ProfileId = 1,
MovieFileId = 0,
Path = string.Format("/Movies/{0}", "Title"),
TitleSlug = 123456,
TmdbId = 132456,
Added = DateTime.UtcNow,
Collection = new { Name = "Some Collection", TmdbId = 11 }.ToJson(),
LastInfoSync = DateTime.UtcNow,
});
c.Insert.IntoTable("Credits").Row(new
{
MovieId = 5,
CreditTmdbId = 123,
PersonTmdbId = 456,
Order = 1,
Type = 1,
Name = "Some Person",
Images = new[] { new { CoverType = "Poster" } }.ToJson()
});
});
var metadata = db.Query<MovieMetadata207>("SELECT \"Id\", \"Title\", \"TmdbId\" FROM \"MovieMetadata\"");
metadata.Should().HaveCount(1);
metadata.First().TmdbId.Should().Be(132456);
metadata.First().Title.Should().Be("Title");
var movies = db.Query<Movie207>("SELECT \"Id\", \"MovieMetadataId\" FROM \"Credits\"");
movies.Should().HaveCount(1);
movies.First().MovieMetadataId.Should().Be(metadata.First().Id);
}
[Test]
public void should_link_metadata_to_alt_title()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Movies").Row(new
{
Id = 5,
Monitored = true,
Title = "Title",
CleanTitle = "CleanTitle",
Status = 3,
MinimumAvailability = 4,
Images = new[] { new { CoverType = "Poster" } }.ToJson(),
Recommendations = new[] { 1 }.ToJson(),
Runtime = 90,
OriginalLanguage = 1,
ProfileId = 1,
MovieFileId = 0,
Path = string.Format("/Movies/{0}", "Title"),
TitleSlug = 123456,
TmdbId = 132456,
Added = DateTime.UtcNow,
Collection = new { Name = "Some Collection", TmdbId = 11 }.ToJson(),
LastInfoSync = DateTime.UtcNow,
});
c.Insert.IntoTable("AlternativeTitles").Row(new
{
MovieId = 5,
Title = "Some Alt",
CleanTitle = "somealt",
SourceType = 1,
SourceId = 1,
Votes = 0,
VoteCount = 0,
Language = 1
});
});
var metadata = db.Query<MovieMetadata207>("SELECT \"Id\", \"Title\", \"TmdbId\" FROM \"MovieMetadata\"");
metadata.Should().HaveCount(1);
metadata.First().TmdbId.Should().Be(132456);
metadata.First().Title.Should().Be("Title");
var movies = db.Query<Movie207>("SELECT \"Id\", \"MovieMetadataId\" FROM \"AlternativeTitles\"");
movies.Should().HaveCount(1);
movies.First().MovieMetadataId.Should().Be(metadata.First().Id);
}
[Test]
public void should_link_metadata_to_translation()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Movies").Row(new
{
Id = 5,
Monitored = true,
Title = "Title",
CleanTitle = "CleanTitle",
Status = 3,
MinimumAvailability = 4,
Images = new[] { new { CoverType = "Poster" } }.ToJson(),
Recommendations = new[] { 1 }.ToJson(),
Runtime = 90,
OriginalLanguage = 1,
ProfileId = 1,
MovieFileId = 0,
Path = string.Format("/Movies/{0}", "Title"),
TitleSlug = 123456,
TmdbId = 132456,
Added = DateTime.UtcNow,
Collection = new { Name = "Some Collection", TmdbId = 11 }.ToJson(),
LastInfoSync = DateTime.UtcNow,
});
c.Insert.IntoTable("MovieTranslations").Row(new
{
MovieId = 5,
Title = "Some Trans",
Language = 1
});
});
var metadata = db.Query<MovieMetadata207>("SELECT \"Id\", \"Title\", \"TmdbId\" FROM \"MovieMetadata\"");
metadata.Should().HaveCount(1);
metadata.First().TmdbId.Should().Be(132456);
metadata.First().Title.Should().Be("Title");
var movies = db.Query<Movie207>("SELECT \"Id\", \"MovieMetadataId\" FROM \"MovieTranslations\"");
movies.Should().HaveCount(1);
movies.First().MovieMetadataId.Should().Be(metadata.First().Id);
}
[Test]
public void should_add_metadata_from_list_and_link_back()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("ImportListMovies").Row(new
{
Title = "Title",
Status = 3,
Images = new[] { new { CoverType = "Poster" } }.ToJson(),
Runtime = 90,
TmdbId = 123456,
ListId = 4,
Translations = new[] { new { } }.ToJson(),
Collection = new { Name = "Some Collection", TmdbId = 11 }.ToJson(),
});
});
var metadata = db.Query<MovieMetadata207>("SELECT \"Id\", \"Title\", \"TmdbId\" FROM \"MovieMetadata\"");
metadata.Should().HaveCount(1);
metadata.First().TmdbId.Should().Be(123456);
metadata.First().Title.Should().Be("Title");
var movies = db.Query<Movie207>("SELECT \"Id\", \"MovieMetadataId\" FROM \"ImportListMovies\"");
movies.Should().HaveCount(1);
movies.First().MovieMetadataId.Should().Be(metadata.First().Id);
}
[Test]
public void should_not_duplicate_metadata()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Movies").Row(new
{
Monitored = true,
Title = "Title",
CleanTitle = "CleanTitle",
Status = 3,
MinimumAvailability = 4,
Images = new[] { new { CoverType = "Poster" } }.ToJson(),
Recommendations = new[] { 1 }.ToJson(),
Runtime = 90,
OriginalLanguage = 1,
ProfileId = 1,
MovieFileId = 0,
Path = string.Format("/Movies/{0}", "Title"),
TitleSlug = 123456,
TmdbId = 123456,
Added = DateTime.UtcNow,
Collection = new { Name = "Some Collection", TmdbId = 11 }.ToJson(),
LastInfoSync = DateTime.UtcNow,
});
c.Insert.IntoTable("ImportListMovies").Row(new
{
Title = "Title",
Status = 3,
Images = new[] { new { CoverType = "Poster" } }.ToJson(),
Runtime = 90,
TmdbId = 123456,
ListId = 4,
Translations = new[] { new { } }.ToJson(),
Collection = new { Name = "Some Collection", TmdbId = 11 }.ToJson(),
});
});
var metadata = db.Query<MovieMetadata207>("SELECT \"Id\", \"Title\", \"TmdbId\" FROM \"MovieMetadata\"");
metadata.Should().HaveCount(1);
metadata.First().TmdbId.Should().Be(123456);
metadata.First().Title.Should().Be("Title");
var movies = db.Query<Movie207>("SELECT \"Id\", \"MovieMetadataId\" FROM \"Movies\"");
movies.Should().HaveCount(1);
movies.First().MovieMetadataId.Should().Be(metadata.First().Id);
var listMovies = db.Query<Movie207>("SELECT \"Id\", \"MovieMetadataId\" FROM \"ImportListMovies\"");
listMovies.Should().HaveCount(1);
listMovies.First().MovieMetadataId.Should().Be(metadata.First().Id);
}
}
public class MovieMetadata207
{
public int Id { get; set; }
public int TmdbId { get; set; }
public string Title { get; set; }
public bool Monitored { get; set; }
}
public class Movie207
{
public int Id { get; set; }
public int MovieMetadataId { get; set; }
}
}

View file

@ -27,6 +27,11 @@ private WhereBuilderPostgres Where(Expression<Func<Movie, bool>> filter)
return new WhereBuilderPostgres(filter, true, 0);
}
private WhereBuilderPostgres WhereMeta(Expression<Func<MovieMetadata, bool>> filter)
{
return new WhereBuilderPostgres(filter, true, 0);
}
[Test]
public void postgres_where_equal_const()
{
@ -86,36 +91,36 @@ public void postgres_where_allows_abstract_condition_if_not_requiresConcreteCond
[Test]
public void postgres_where_string_is_null()
{
_subject = Where(x => x.CleanTitle == null);
_subject = WhereMeta(x => x.CleanTitle == null);
_subject.ToString().Should().Be($"(\"Movies\".\"CleanTitle\" IS NULL)");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"CleanTitle\" IS NULL)");
}
[Test]
public void postgres_where_string_is_null_value()
{
string cleanTitle = null;
_subject = Where(x => x.CleanTitle == cleanTitle);
_subject = WhereMeta(x => x.CleanTitle == cleanTitle);
_subject.ToString().Should().Be($"(\"Movies\".\"CleanTitle\" IS NULL)");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"CleanTitle\" IS NULL)");
}
[Test]
public void postgres_where_equal_null_property()
{
var movie = new Movie { CleanTitle = null };
_subject = Where(x => x.CleanTitle == movie.CleanTitle);
var movie = new MovieMetadata { CleanTitle = null };
_subject = WhereMeta(x => x.CleanTitle == movie.CleanTitle);
_subject.ToString().Should().Be($"(\"Movies\".\"CleanTitle\" IS NULL)");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"CleanTitle\" IS NULL)");
}
[Test]
public void postgres_where_column_contains_string()
{
var test = "small";
_subject = Where(x => x.CleanTitle.Contains(test));
_subject = WhereMeta(x => x.CleanTitle.Contains(test));
_subject.ToString().Should().Be($"(\"Movies\".\"CleanTitle\" ILIKE '%' || @Clause1_P1 || '%')");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"CleanTitle\" ILIKE '%' || @Clause1_P1 || '%')");
_subject.Parameters.Get<string>("Clause1_P1").Should().Be(test);
}
@ -123,9 +128,9 @@ public void postgres_where_column_contains_string()
public void postgres_where_string_contains_column()
{
var test = "small";
_subject = Where(x => test.Contains(x.CleanTitle));
_subject = WhereMeta(x => test.Contains(x.CleanTitle));
_subject.ToString().Should().Be($"(@Clause1_P1 ILIKE '%' || \"Movies\".\"CleanTitle\" || '%')");
_subject.ToString().Should().Be($"(@Clause1_P1 ILIKE '%' || \"MovieMetadata\".\"CleanTitle\" || '%')");
_subject.Parameters.Get<string>("Clause1_P1").Should().Be(test);
}
@ -133,9 +138,9 @@ public void postgres_where_string_contains_column()
public void postgres_where_column_starts_with_string()
{
var test = "small";
_subject = Where(x => x.CleanTitle.StartsWith(test));
_subject = WhereMeta(x => x.CleanTitle.StartsWith(test));
_subject.ToString().Should().Be($"(\"Movies\".\"CleanTitle\" ILIKE @Clause1_P1 || '%')");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"CleanTitle\" ILIKE @Clause1_P1 || '%')");
_subject.Parameters.Get<string>("Clause1_P1").Should().Be(test);
}
@ -143,9 +148,9 @@ public void postgres_where_column_starts_with_string()
public void postgres_where_column_ends_with_string()
{
var test = "small";
_subject = Where(x => x.CleanTitle.EndsWith(test));
_subject = WhereMeta(x => x.CleanTitle.EndsWith(test));
_subject.ToString().Should().Be($"(\"Movies\".\"CleanTitle\" ILIKE '%' || @Clause1_P1)");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"CleanTitle\" ILIKE '%' || @Clause1_P1)");
_subject.Parameters.Get<string>("Clause1_P1").Should().Be(test);
}
@ -162,9 +167,9 @@ public void postgres_where_in_list()
public void postgres_where_in_list_2()
{
var list = new List<int> { 1, 2, 3 };
_subject = Where(x => x.CleanTitle == "test" && list.Contains(x.Id));
_subject = WhereMeta(x => x.CleanTitle == "test" && list.Contains(x.Id));
_subject.ToString().Should().Be($"((\"Movies\".\"CleanTitle\" = @Clause1_P1) AND (\"Movies\".\"Id\" = ANY (('{{1, 2, 3}}'))))");
_subject.ToString().Should().Be($"((\"MovieMetadata\".\"CleanTitle\" = @Clause1_P1) AND (\"MovieMetadata\".\"Id\" = ANY (('{{1, 2, 3}}'))))");
}
[Test]
@ -172,35 +177,35 @@ public void postgres_where_in_string_list()
{
var list = new List<string> { "first", "second", "third" };
_subject = Where(x => list.Contains(x.CleanTitle));
_subject = WhereMeta(x => list.Contains(x.CleanTitle));
_subject.ToString().Should().Be($"(\"Movies\".\"CleanTitle\" = ANY (@Clause1_P1))");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"CleanTitle\" = ANY (@Clause1_P1))");
}
[Test]
public void enum_as_int()
{
_subject = Where(x => x.Status == MovieStatusType.Announced);
_subject = WhereMeta(x => x.Status == MovieStatusType.Announced);
_subject.ToString().Should().Be($"(\"Movies\".\"Status\" = @Clause1_P1)");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"Status\" = @Clause1_P1)");
}
[Test]
public void enum_in_list()
{
var allowed = new List<MovieStatusType> { MovieStatusType.Announced, MovieStatusType.InCinemas };
_subject = Where(x => allowed.Contains(x.Status));
_subject = WhereMeta(x => allowed.Contains(x.Status));
_subject.ToString().Should().Be($"(\"Movies\".\"Status\" = ANY (@Clause1_P1))");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"Status\" = ANY (@Clause1_P1))");
}
[Test]
public void enum_in_array()
{
var allowed = new MovieStatusType[] { MovieStatusType.Announced, MovieStatusType.InCinemas };
_subject = Where(x => allowed.Contains(x.Status));
_subject = WhereMeta(x => allowed.Contains(x.Status));
_subject.ToString().Should().Be($"(\"Movies\".\"Status\" = ANY (@Clause1_P1))");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"Status\" = ANY (@Clause1_P1))");
}
}
}

View file

@ -27,6 +27,11 @@ private WhereBuilderSqlite Where(Expression<Func<Movie, bool>> filter)
return new WhereBuilderSqlite(filter, true, 0);
}
private WhereBuilderSqlite WhereMeta(Expression<Func<MovieMetadata, bool>> filter)
{
return new WhereBuilderSqlite(filter, true, 0);
}
[Test]
public void where_equal_const()
{
@ -86,36 +91,36 @@ public void where_allows_abstract_condition_if_not_requiresConcreteCondition()
[Test]
public void where_string_is_null()
{
_subject = Where(x => x.CleanTitle == null);
_subject = WhereMeta(x => x.CleanTitle == null);
_subject.ToString().Should().Be($"(\"Movies\".\"CleanTitle\" IS NULL)");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"CleanTitle\" IS NULL)");
}
[Test]
public void where_string_is_null_value()
{
string cleanTitle = null;
_subject = Where(x => x.CleanTitle == cleanTitle);
_subject = WhereMeta(x => x.CleanTitle == cleanTitle);
_subject.ToString().Should().Be($"(\"Movies\".\"CleanTitle\" IS NULL)");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"CleanTitle\" IS NULL)");
}
[Test]
public void where_equal_null_property()
{
var movie = new Movie { CleanTitle = null };
_subject = Where(x => x.CleanTitle == movie.CleanTitle);
var movie = new MovieMetadata { CleanTitle = null };
_subject = WhereMeta(x => x.CleanTitle == movie.CleanTitle);
_subject.ToString().Should().Be($"(\"Movies\".\"CleanTitle\" IS NULL)");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"CleanTitle\" IS NULL)");
}
[Test]
public void where_column_contains_string()
{
var test = "small";
_subject = Where(x => x.CleanTitle.Contains(test));
_subject = WhereMeta(x => x.CleanTitle.Contains(test));
_subject.ToString().Should().Be($"(\"Movies\".\"CleanTitle\" LIKE '%' || @Clause1_P1 || '%')");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"CleanTitle\" LIKE '%' || @Clause1_P1 || '%')");
_subject.Parameters.Get<string>("Clause1_P1").Should().Be(test);
}
@ -123,9 +128,9 @@ public void where_column_contains_string()
public void where_string_contains_column()
{
var test = "small";
_subject = Where(x => test.Contains(x.CleanTitle));
_subject = WhereMeta(x => test.Contains(x.CleanTitle));
_subject.ToString().Should().Be($"(@Clause1_P1 LIKE '%' || \"Movies\".\"CleanTitle\" || '%')");
_subject.ToString().Should().Be($"(@Clause1_P1 LIKE '%' || \"MovieMetadata\".\"CleanTitle\" || '%')");
_subject.Parameters.Get<string>("Clause1_P1").Should().Be(test);
}
@ -133,9 +138,9 @@ public void where_string_contains_column()
public void where_column_starts_with_string()
{
var test = "small";
_subject = Where(x => x.CleanTitle.StartsWith(test));
_subject = WhereMeta(x => x.CleanTitle.StartsWith(test));
_subject.ToString().Should().Be($"(\"Movies\".\"CleanTitle\" LIKE @Clause1_P1 || '%')");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"CleanTitle\" LIKE @Clause1_P1 || '%')");
_subject.Parameters.Get<string>("Clause1_P1").Should().Be(test);
}
@ -143,9 +148,9 @@ public void where_column_starts_with_string()
public void where_column_ends_with_string()
{
var test = "small";
_subject = Where(x => x.CleanTitle.EndsWith(test));
_subject = WhereMeta(x => x.CleanTitle.EndsWith(test));
_subject.ToString().Should().Be($"(\"Movies\".\"CleanTitle\" LIKE '%' || @Clause1_P1)");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"CleanTitle\" LIKE '%' || @Clause1_P1)");
_subject.Parameters.Get<string>("Clause1_P1").Should().Be(test);
}
@ -164,9 +169,9 @@ public void where_in_list()
public void where_in_list_2()
{
var list = new List<int> { 1, 2, 3 };
_subject = Where(x => x.CleanTitle == "test" && list.Contains(x.Id));
_subject = WhereMeta(x => x.CleanTitle == "test" && list.Contains(x.Id));
_subject.ToString().Should().Be($"((\"Movies\".\"CleanTitle\" = @Clause1_P1) AND (\"Movies\".\"Id\" IN (1, 2, 3)))");
_subject.ToString().Should().Be($"((\"MovieMetadata\".\"CleanTitle\" = @Clause1_P1) AND (\"MovieMetadata\".\"Id\" IN (1, 2, 3)))");
}
[Test]
@ -174,35 +179,35 @@ public void where_in_string_list()
{
var list = new List<string> { "first", "second", "third" };
_subject = Where(x => list.Contains(x.CleanTitle));
_subject = WhereMeta(x => list.Contains(x.CleanTitle));
_subject.ToString().Should().Be($"(\"Movies\".\"CleanTitle\" IN @Clause1_P1)");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"CleanTitle\" IN @Clause1_P1)");
}
[Test]
public void enum_as_int()
{
_subject = Where(x => x.Status == MovieStatusType.Announced);
_subject = WhereMeta(x => x.Status == MovieStatusType.Announced);
_subject.ToString().Should().Be($"(\"Movies\".\"Status\" = @Clause1_P1)");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"Status\" = @Clause1_P1)");
}
[Test]
public void enum_in_list()
{
var allowed = new List<MovieStatusType> { MovieStatusType.Announced, MovieStatusType.InCinemas };
_subject = Where(x => allowed.Contains(x.Status));
_subject = WhereMeta(x => allowed.Contains(x.Status));
_subject.ToString().Should().Be($"(\"Movies\".\"Status\" IN @Clause1_P1)");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"Status\" IN @Clause1_P1)");
}
[Test]
public void enum_in_array()
{
var allowed = new MovieStatusType[] { MovieStatusType.Announced, MovieStatusType.InCinemas };
_subject = Where(x => allowed.Contains(x.Status));
_subject = WhereMeta(x => allowed.Contains(x.Status));
_subject.ToString().Should().Be($"(\"Movies\".\"Status\" IN @Clause1_P1)");
_subject.ToString().Should().Be($"(\"MovieMetadata\".\"Status\" IN @Clause1_P1)");
}
}
}

View file

@ -53,7 +53,7 @@ public void Setup()
[TestCase(60, 1000, false)]
public void single_episode(int runtime, int sizeInMegaBytes, bool expectedResult)
{
_movie.Runtime = runtime;
_movie.MovieMetadata.Value.Runtime = runtime;
_remoteMovie.Movie = _movie;
_remoteMovie.Release.Size = sizeInMegaBytes.Megabytes();
@ -63,7 +63,7 @@ public void single_episode(int runtime, int sizeInMegaBytes, bool expectedResult
[Test]
public void should_return_true_if_size_is_zero()
{
_movie.Runtime = 120;
_movie.MovieMetadata.Value.Runtime = 120;
_remoteMovie.Movie = _movie;
_remoteMovie.Release.Size = 0;
_qualityType.MinSize = 10;
@ -75,7 +75,7 @@ public void should_return_true_if_size_is_zero()
[Test]
public void should_return_true_if_unlimited_30_minute()
{
_movie.Runtime = 30;
_movie.MovieMetadata.Value.Runtime = 30;
_remoteMovie.Movie = _movie;
_remoteMovie.Release.Size = 18457280000;
_qualityType.MaxSize = null;
@ -86,7 +86,7 @@ public void should_return_true_if_unlimited_30_minute()
[Test]
public void should_return_true_if_unlimited_60_minute()
{
_movie.Runtime = 60;
_movie.MovieMetadata.Value.Runtime = 60;
_remoteMovie.Movie = _movie;
_remoteMovie.Release.Size = 36857280000;
_qualityType.MaxSize = null;
@ -97,7 +97,7 @@ public void should_return_true_if_unlimited_60_minute()
[Test]
public void should_use_110_minutes_if_runtime_is_0()
{
_movie.Runtime = 0;
_movie.MovieMetadata.Value.Runtime = 0;
_remoteMovie.Movie = _movie;
_remoteMovie.Release.Size = 1095.Megabytes();

View file

@ -31,7 +31,10 @@ public void Setup()
{
Language = Language.English
},
OriginalLanguage = Language.French
MovieMetadata = new MovieMetadata
{
OriginalLanguage = Language.French
}
}
};
}

View file

@ -66,7 +66,7 @@ private RemoteMovie GivenRemoteMovie(QualityModel quality, int age = 0, long siz
MinFormatScore = 0
})
.With(m => m.Title = "A Movie")
.With(m => m.Runtime = runtime).Build();
.With(m => m.MovieMetadata.Value.Runtime = runtime).Build();
remoteMovie.Release = new ReleaseInfo();
remoteMovie.Release.PublishDate = DateTime.Now.AddDays(-age);

View file

@ -32,16 +32,16 @@ private void GivenMovie(int amount, int deleted)
{
movie = Builder<Movie>.CreateListOfSize(amount)
.All()
.With(v => v.Status = MovieStatusType.Released)
.With(v => v.MovieMetadata.Value.Status = MovieStatusType.Released)
.BuildList();
}
else
{
movie = Builder<Movie>.CreateListOfSize(amount)
.All()
.With(v => v.Status = MovieStatusType.Released)
.With(v => v.MovieMetadata.Value.Status = MovieStatusType.Released)
.Random(deleted)
.With(v => v.Status = MovieStatusType.Deleted)
.With(v => v.MovieMetadata.Value.Status = MovieStatusType.Deleted)
.BuildList();
}

View file

@ -16,7 +16,7 @@ public class CleanupOrphanedAlternativeTitleFixture : DbTest<CleanupOrphanedAlte
public void should_delete_orphaned_alternative_title_items()
{
var altTitle = Builder<AlternativeTitle>.CreateNew()
.With(h => h.MovieId = default)
.With(h => h.MovieMetadataId = default)
.With(h => h.Language = Language.English)
.BuildNew();
@ -28,14 +28,14 @@ public void should_delete_orphaned_alternative_title_items()
[Test]
public void should_not_delete_unorphaned_alternative_title_items()
{
var movie = Builder<Movie>.CreateNew().BuildNew();
var movieMetadata = Builder<MovieMetadata>.CreateNew().BuildNew();
Db.Insert(movie);
Db.Insert(movieMetadata);
var altTitle = Builder<AlternativeTitle>.CreateNew()
.With(h => h.MovieId = default)
.With(h => h.MovieMetadataId = default)
.With(h => h.Language = Language.English)
.With(b => b.MovieId = movie.Id)
.With(b => b.MovieMetadataId = movieMetadata.Id)
.BuildNew();
Db.Insert(altTitle);

View file

@ -15,7 +15,7 @@ public class CleanupOrphanedCreditsFixture : DbTest<CleanupOrphanedCredits, Cred
public void should_delete_orphaned_credit_items()
{
var credit = Builder<Credit>.CreateNew()
.With(h => h.MovieId = default)
.With(h => h.MovieMetadataId = default)
.With(h => h.Name = "Some Credit")
.BuildNew();
@ -27,14 +27,14 @@ public void should_delete_orphaned_credit_items()
[Test]
public void should_not_delete_unorphaned_credit_items()
{
var movie = Builder<Movie>.CreateNew().BuildNew();
var movieMetadata = Builder<MovieMetadata>.CreateNew().BuildNew();
Db.Insert(movie);
Db.Insert(movieMetadata);
var credit = Builder<Credit>.CreateNew()
.With(h => h.MovieId = default)
.With(h => h.MovieMetadataId = default)
.With(h => h.Name = "Some Credit")
.With(b => b.MovieId = movie.Id)
.With(b => b.MovieMetadataId = movieMetadata.Id)
.BuildNew();
Db.Insert(credit);

View file

@ -0,0 +1,60 @@
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Housekeeping.Housekeepers;
using NzbDrone.Core.ImportLists.ImportListMovies;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Movies.Translations;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
{
[TestFixture]
public class CleanupOrphanedMovieMetadataFixture : DbTest<CleanupOrphanedMovieMetadata, MovieMetadata>
{
[Test]
public void should_delete_orphaned_movie_metadata_items()
{
var metadata = Builder<MovieMetadata>.CreateNew().BuildNew();
Db.Insert(metadata);
Subject.Clean();
AllStoredModels.Should().BeEmpty();
}
[Test]
public void should_not_delete_unorphaned_movie_metadata_items()
{
var movieMetadata = Builder<MovieMetadata>.CreateNew().BuildNew();
Db.Insert(movieMetadata);
var movie = Builder<Movie>.CreateNew()
.With(b => b.MovieMetadataId = movieMetadata.Id)
.BuildNew();
Db.Insert(movie);
Subject.Clean();
AllStoredModels.Should().HaveCount(1);
}
[Test]
public void should_not_delete_unorphaned_movie_metadata_items_for_lists()
{
var movieMetadata = Builder<MovieMetadata>.CreateNew().BuildNew();
Db.Insert(movieMetadata);
var movie = Builder<ImportListMovie>.CreateNew()
.With(b => b.MovieMetadataId = movieMetadata.Id)
.BuildNew();
Db.Insert(movie);
Subject.Clean();
AllStoredModels.Should().HaveCount(1);
}
}
}

View file

@ -16,7 +16,7 @@ public class CleanupOrphanedMovieTranslationsFixture : DbTest<CleanupOrphanedMov
public void should_delete_orphaned_movie_translation_items()
{
var translation = Builder<MovieTranslation>.CreateNew()
.With(h => h.MovieId = default)
.With(h => h.MovieMetadataId = default)
.With(h => h.Language = Language.English)
.BuildNew();
@ -28,14 +28,14 @@ public void should_delete_orphaned_movie_translation_items()
[Test]
public void should_not_delete_unorphaned_movie_translation_items()
{
var movie = Builder<Movie>.CreateNew().BuildNew();
var movieMetadata = Builder<MovieMetadata>.CreateNew().BuildNew();
Db.Insert(movie);
Db.Insert(movieMetadata);
var translation = Builder<MovieTranslation>.CreateNew()
.With(h => h.MovieId = default)
.With(h => h.MovieMetadataId = default)
.With(h => h.Language = Language.English)
.With(b => b.MovieId = movie.Id)
.With(b => b.MovieMetadataId = movieMetadata.Id)
.BuildNew();
Db.Insert(translation);

View file

@ -38,8 +38,8 @@ public void Setup()
.Build().ToList();
Mocker.GetMock<ISearchForNewMovie>()
.Setup(v => v.MapMovieToTmdbMovie(It.IsAny<Movie>()))
.Returns<Movie>(m => new Movie { TmdbId = m.TmdbId });
.Setup(v => v.MapMovieToTmdbMovie(It.IsAny<MovieMetadata>()))
.Returns<MovieMetadata>(m => new MovieMetadata { TmdbId = m.TmdbId });
}
private void GivenList(int id, bool enabled, bool enabledAuto, ImportListFetchResult fetchResult)

View file

@ -27,7 +27,7 @@ public void Setup()
_movie = Builder<Movie>.CreateNew()
.With(v => v.Id = 2)
.With(v => v.Images = new List<MediaCover.MediaCover> { new MediaCover.MediaCover(MediaCoverTypes.Poster, "") })
.With(v => v.MovieMetadata.Value.Images = new List<MediaCover.MediaCover> { new MediaCover.MediaCover(MediaCoverTypes.Poster, "") })
.Build();
Mocker.GetMock<IMovieService>().Setup(m => m.GetMovie(It.Is<int>(id => id == _movie.Id))).Returns(_movie);

View file

@ -255,7 +255,7 @@ public void should_delete_folder_if_files_were_imported_and_only_sample_files_re
.Returns(imported.Select(i => new ImportResult(i)).ToList());
Mocker.GetMock<IDetectSample>()
.Setup(s => s.IsSample(It.IsAny<Movie>(),
.Setup(s => s.IsSample(It.IsAny<MovieMetadata>(),
It.IsAny<string>()))
.Returns(DetectSampleResult.Sample);
@ -324,7 +324,7 @@ public void should_not_delete_if_there_is_large_rar_file()
.Returns(imported.Select(i => new ImportResult(i)).ToList());
Mocker.GetMock<IDetectSample>()
.Setup(s => s.IsSample(It.IsAny<Movie>(),
.Setup(s => s.IsSample(It.IsAny<MovieMetadata>(),
It.IsAny<string>()))
.Returns(DetectSampleResult.Sample);
@ -431,7 +431,7 @@ public void should_not_delete_if_no_files_were_imported()
.Returns(new List<ImportResult>());
Mocker.GetMock<IDetectSample>()
.Setup(s => s.IsSample(It.IsAny<Movie>(),
.Setup(s => s.IsSample(It.IsAny<MovieMetadata>(),
It.IsAny<string>()))
.Returns(DetectSampleResult.Sample);

View file

@ -24,7 +24,7 @@ public class AggregateLanguageFixture : CoreTest<AggregateLanguage>
public void Setup()
{
_movie = Builder<Movie>.CreateNew()
.With(m => m.OriginalLanguage = Language.English)
.With(m => m.MovieMetadata.Value.OriginalLanguage = Language.English)
.Build();
_localMovie = Builder<LocalMovie>.CreateNew()
@ -72,7 +72,7 @@ public void should_return_default_if_no_info_is_known()
{
var result = Subject.Aggregate(_localMovie, null, false);
result.Languages.Should().Contain(_movie.OriginalLanguage);
result.Languages.Should().Contain(_movie.MovieMetadata.Value.OriginalLanguage);
}
[Test]

View file

@ -16,20 +16,20 @@ namespace NzbDrone.Core.Test.MediaFiles.MovieImport
[TestFixture]
public class DetectSampleFixture : CoreTest<DetectSample>
{
private Movie _movie;
private MovieMetadata _movie;
private LocalMovie _localMovie;
[SetUp]
public void Setup()
{
_movie = Builder<Movie>.CreateNew()
_movie = Builder<MovieMetadata>.CreateNew()
.With(s => s.Runtime = 30)
.Build();
_localMovie = new LocalMovie
{
Path = @"C:\Test\30 Rock\30.rock.s01e01.avi",
Movie = _movie,
Movie = new Movie { MovieMetadata = _movie },
Quality = new QualityModel(Quality.HDTV720p)
};
}
@ -96,7 +96,7 @@ public void should_use_runtime()
{
GivenRuntime(120);
Subject.IsSample(_localMovie.Movie,
Subject.IsSample(_localMovie.Movie.MovieMetadata,
_localMovie.Path);
Mocker.GetMock<IVideoFileInfoReader>().Verify(v => v.GetRunTime(It.IsAny<string>()), Times.Once());
@ -152,7 +152,7 @@ public void should_return_indeterminate_if_mediainfo_result_is_null()
.Setup(s => s.GetRunTime(It.IsAny<string>()))
.Returns((TimeSpan?)null);
Subject.IsSample(_localMovie.Movie,
Subject.IsSample(_localMovie.Movie.MovieMetadata,
_localMovie.Path).Should().Be(DetectSampleResult.Indeterminate);
ExceptionVerification.ExpectedErrors(1);
@ -160,13 +160,13 @@ public void should_return_indeterminate_if_mediainfo_result_is_null()
private void ShouldBeSample()
{
Subject.IsSample(_localMovie.Movie,
Subject.IsSample(_localMovie.Movie.MovieMetadata,
_localMovie.Path).Should().Be(DetectSampleResult.Sample);
}
private void ShouldBeNotSample()
{
Subject.IsSample(_localMovie.Movie,
Subject.IsSample(_localMovie.Movie.MovieMetadata,
_localMovie.Path).Should().Be(DetectSampleResult.NotSample);
}
}

View file

@ -29,7 +29,7 @@ public void should_be_able_to_get_movie_detail(int tmdbId, string title)
details.Title.Should().Be(title);
}
private void ValidateMovie(Movie movie)
private void ValidateMovie(MovieMetadata movie)
{
movie.Should().NotBeNull();
movie.Title.Should().NotBeNullOrWhiteSpace();
@ -41,7 +41,6 @@ private void ValidateMovie(Movie movie)
movie.ImdbId.Should().NotBeNullOrWhiteSpace();
movie.Studio.Should().NotBeNullOrWhiteSpace();
movie.Runtime.Should().BeGreaterThan(0);
movie.TitleSlug.Should().NotBeNullOrWhiteSpace();
//series.TvRageId.Should().BeGreaterThan(0);
movie.TmdbId.Should().BeGreaterThan(0);

View file

@ -20,14 +20,13 @@ namespace NzbDrone.Core.Test.MovieTests
[TestFixture]
public class AddMovieFixture : CoreTest<AddMovieService>
{
private Movie _fakeMovie;
private MovieMetadata _fakeMovie;
[SetUp]
public void Setup()
{
_fakeMovie = Builder<Movie>
_fakeMovie = Builder<MovieMetadata>
.CreateNew()
.With(s => s.Path = null)
.Build();
}
@ -35,7 +34,7 @@ private void GivenValidMovie(int tmdbId)
{
Mocker.GetMock<IProvideMovieInfo>()
.Setup(s => s.GetMovieInfo(tmdbId))
.Returns(new Tuple<Movie, List<Credit>>(_fakeMovie, new List<Credit>()));
.Returns(new Tuple<MovieMetadata, List<Credit>>(_fakeMovie, new List<Credit>()));
}
private void GivenValidPath()

View file

@ -18,16 +18,17 @@ public class AlternativeTitleServiceFixture : CoreTest<AlternativeTitleService>
private AlternativeTitle _title2;
private AlternativeTitle _title3;
private Movie _movie;
private MovieMetadata _movie;
[SetUp]
public void Setup()
{
var titles = Builder<AlternativeTitle>.CreateListOfSize(3).All().With(t => t.MovieId = 0).Build();
var titles = Builder<AlternativeTitle>.CreateListOfSize(3).All().With(t => t.MovieMetadataId = 0).Build();
_title1 = titles[0];
_title2 = titles[1];
_title3 = titles[2];
_movie = Builder<Movie>.CreateNew()
_movie = Builder<MovieMetadata>.CreateNew()
.With(m => m.CleanTitle = "myothertitle")
.With(m => m.Id = 1)
.Build();
@ -35,7 +36,7 @@ public void Setup()
private void GivenExistingTitles(params AlternativeTitle[] titles)
{
Mocker.GetMock<IAlternativeTitleRepository>().Setup(r => r.FindByMovieId(_movie.Id))
Mocker.GetMock<IAlternativeTitleRepository>().Setup(r => r.FindByMovieMetadataId(_movie.Id))
.Returns(titles.ToList());
}
@ -72,7 +73,7 @@ public void should_not_insert_main_title()
{
GivenExistingTitles();
var titles = new List<AlternativeTitle> { _title1 };
var movie = Builder<Movie>.CreateNew().With(m => m.CleanTitle = _title1.CleanTitle).Build();
var movie = Builder<MovieMetadata>.CreateNew().With(m => m.CleanTitle = _title1.CleanTitle).Build();
Subject.UpdateTitles(titles, movie);
@ -87,8 +88,8 @@ public void should_update_movie_id()
Subject.UpdateTitles(titles, _movie);
_title1.MovieId.Should().Be(_movie.Id);
_title2.MovieId.Should().Be(_movie.Id);
_title1.MovieMetadataId.Should().Be(_movie.Id);
_title2.MovieMetadataId.Should().Be(_movie.Id);
}
[Test]

View file

@ -32,18 +32,18 @@ public void should_delete_credits_by_movieId()
var credits = Builder<Credit>.CreateListOfSize(5)
.TheFirst(1)
.With(c => c.Id = 0)
.With(c => c.MovieId = _movie2.Id)
.With(c => c.MovieMetadataId = _movie2.Id)
.TheRest()
.With(c => c.Id = 0)
.With(c => c.MovieId = _movie1.Id)
.With(c => c.MovieMetadataId = _movie1.Id)
.BuildListOfNew();
Db.InsertMany(credits);
Subject.DeleteForMovies(new List<int> { _movie1.Id });
var removedMovieCredits = Subject.FindByMovieId(_movie1.Id);
var nonRemovedMovieCredits = Subject.FindByMovieId(_movie2.Id);
var removedMovieCredits = Subject.FindByMovieMetadataId(_movie1.Id);
var nonRemovedMovieCredits = Subject.FindByMovieMetadataId(_movie2.Id);
removedMovieCredits.Should().HaveCount(0);
nonRemovedMovieCredits.Should().HaveCount(1);

View file

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
@ -18,25 +18,25 @@ public class CreditServiceFixture : CoreTest<CreditService>
private Credit _credit2;
private Credit _credit3;
private Movie _movie;
private MovieMetadata _movie;
[SetUp]
public void Setup()
{
var credits = Builder<Credit>.CreateListOfSize(3)
.All()
.With(t => t.MovieId = 0).Build();
.With(t => t.MovieMetadataId = 0).Build();
_credit1 = credits[0];
_credit2 = credits[1];
_credit3 = credits[2];
_movie = Builder<Movie>.CreateNew().With(m => m.Id = 1).Build();
_movie = Builder<MovieMetadata>.CreateNew().With(m => m.Id = 1).Build();
}
private void GivenExistingCredits(params Credit[] credits)
{
Mocker.GetMock<ICreditRepository>().Setup(r => r.FindByMovieId(_movie.Id))
Mocker.GetMock<ICreditRepository>().Setup(r => r.FindByMovieMetadataId(_movie.Id))
.Returns(credits.ToList());
}
@ -77,8 +77,8 @@ public void should_update_movie_id()
Subject.UpdateCredits(titles, _movie);
_credit1.MovieId.Should().Be(_movie.Id);
_credit2.MovieId.Should().Be(_movie.Id);
_credit1.MovieMetadataId.Should().Be(_movie.Id);
_credit2.MovieMetadataId.Should().Be(_movie.Id);
}
[Test]

View file

@ -21,9 +21,9 @@ public void Setup()
private void SetMovieProperties(DateTime? cinema, DateTime? physical, DateTime? digital, MovieStatusType minimumAvailability)
{
_movie.InCinemas = cinema;
_movie.PhysicalRelease = physical;
_movie.DigitalRelease = digital;
_movie.MovieMetadata.Value.InCinemas = cinema;
_movie.MovieMetadata.Value.PhysicalRelease = physical;
_movie.MovieMetadata.Value.DigitalRelease = digital;
_movie.MinimumAvailability = minimumAvailability;
}

View file

@ -0,0 +1,62 @@
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.MovieTests.MovieMetadataRepositoryTests
{
[TestFixture]
public class MovieMetadataRepositoryFixture : DbTest<MovieMetadataRepository, MovieMetadata>
{
private MovieMetadataRepository _movieMetadataRepo;
private List<MovieMetadata> _metadataList;
[SetUp]
public void Setup()
{
_movieMetadataRepo = Mocker.Resolve<MovieMetadataRepository>();
_metadataList = Builder<MovieMetadata>.CreateListOfSize(10).All().With(x => x.Id = 0).BuildList();
}
[Test]
public void upsert_many_should_insert_list_of_new()
{
var updated = _movieMetadataRepo.UpsertMany(_metadataList);
AllStoredModels.Should().HaveCount(_metadataList.Count);
updated.Should().BeTrue();
}
[Test]
public void upsert_many_should_upsert_existing_with_id_0()
{
var clone = _metadataList.JsonClone();
var updated = _movieMetadataRepo.UpsertMany(clone);
updated.Should().BeTrue();
AllStoredModels.Should().HaveCount(_metadataList.Count);
updated = _movieMetadataRepo.UpsertMany(_metadataList);
updated.Should().BeFalse();
AllStoredModels.Should().HaveCount(_metadataList.Count);
}
[Test]
public void upsert_many_should_upsert_mixed_list_of_old_and_new()
{
var clone = _metadataList.Take(5).ToList().JsonClone();
var updated = _movieMetadataRepo.UpsertMany(clone);
updated.Should().BeTrue();
AllStoredModels.Should().HaveCount(clone.Count);
updated = _movieMetadataRepo.UpsertMany(_metadataList);
updated.Should().BeTrue();
AllStoredModels.Should().HaveCount(_metadataList.Count);
}
}
}

View file

@ -19,15 +19,15 @@ public void Setup()
{
_candidates = Builder<Movie>.CreateListOfSize(3)
.TheFirst(1)
.With(x => x.CleanTitle = "batman")
.With(x => x.MovieMetadata.Value.CleanTitle = "batman")
.With(x => x.Year = 2000)
.TheNext(1)
.With(x => x.CleanTitle = "batman")
.With(x => x.MovieMetadata.Value.CleanTitle = "batman")
.With(x => x.Year = 1999)
.TheRest()
.With(x => x.CleanTitle = "darkknight")
.With(x => x.MovieMetadata.Value.CleanTitle = "darkknight")
.With(x => x.Year = 2008)
.With(x => x.AlternativeTitles = new List<AlternativeTitle>
.With(x => x.MovieMetadata.Value.AlternativeTitles = new List<AlternativeTitle>
{
new AlternativeTitle
{

View file

@ -1,79 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.MovieTests
{
[TestFixture]
public class MovieTitleSlugValidatorFixture : CoreTest<MovieTitleSlugValidator>
{
private List<Movie> _movies;
private TestValidator<Movie> _validator;
[SetUp]
public void Setup()
{
_movies = Builder<Movie>.CreateListOfSize(1)
.Build()
.ToList();
_validator = new TestValidator<Movie>
{
v => v.RuleFor(s => s.TitleSlug).SetValidator(Subject)
};
Mocker.GetMock<IMovieService>()
.Setup(s => s.AllMovieTitleSlugs())
.Returns(_movies.ToDictionary(m => m.Id, m => m.TitleSlug));
}
[Test]
public void should_not_be_valid_if_there_is_an_existing_movie_with_the_same_title_slug()
{
Mocker.GetMock<IMovieService>()
.Setup(s => s.GetMovie(_movies.First().Id))
.Returns(_movies.First());
var movie = Builder<Movie>.CreateNew()
.With(s => s.Id = 100)
.With(s => s.TitleSlug = _movies.First().TitleSlug)
.Build();
_validator.Validate(movie).IsValid.Should().BeFalse();
}
[Test]
public void should_be_valid_if_there_is_not_an_existing_movie_with_the_same_title_slug()
{
var movie = Builder<Movie>.CreateNew()
.With(s => s.TitleSlug = "MyTitleSlug")
.Build();
_validator.Validate(movie).IsValid.Should().BeTrue();
}
[Test]
public void should_be_valid_if_there_is_an_existing_movie_with_a_null_title_slug()
{
_movies.First().TitleSlug = null;
var movie = Builder<Movie>.CreateNew()
.With(s => s.TitleSlug = "MyTitleSlug")
.Build();
_validator.Validate(movie).IsValid.Should().BeTrue();
}
[Test]
public void should_be_valid_when_updating_an_existing_movie()
{
_validator.Validate(_movies.First().JsonClone()).IsValid.Should().BeTrue();
}
}
}

View file

@ -18,17 +18,26 @@ namespace NzbDrone.Core.Test.MovieTests
[TestFixture]
public class RefreshMovieServiceFixture : CoreTest<RefreshMovieService>
{
private Movie _movie;
private MovieMetadata _movie;
private Movie _existingMovie;
[SetUp]
public void Setup()
{
_movie = Builder<Movie>.CreateNew()
_movie = Builder<MovieMetadata>.CreateNew()
.With(s => s.Status = MovieStatusType.Released)
.Build();
_existingMovie = Builder<Movie>.CreateNew()
.With(s => s.MovieMetadata.Value.Status = MovieStatusType.Released)
.Build();
Mocker.GetMock<IMovieService>()
.Setup(s => s.GetMovie(_movie.Id))
.Returns(_existingMovie);
Mocker.GetMock<IMovieMetadataService>()
.Setup(s => s.Get(_movie.Id))
.Returns(_movie);
Mocker.GetMock<IProvideMovieInfo>()
@ -36,11 +45,11 @@ public void Setup()
.Callback<int>((i) => { throw new MovieNotFoundException(i); });
}
private void GivenNewMovieInfo(Movie movie)
private void GivenNewMovieInfo(MovieMetadata movie)
{
Mocker.GetMock<IProvideMovieInfo>()
.Setup(s => s.GetMovieInfo(_movie.TmdbId))
.Returns(new Tuple<Movie, List<Credit>>(movie, new List<Credit>()));
.Returns(new Tuple<MovieMetadata, List<Credit>>(movie, new List<Credit>()));
}
[Test]
@ -53,8 +62,8 @@ public void should_update_imdb_id_if_changed()
Subject.Execute(new RefreshMovieCommand(new List<int> { _movie.Id }));
Mocker.GetMock<IMovieService>()
.Verify(v => v.UpdateMovie(It.Is<List<Movie>>(s => s.First().ImdbId == newMovieInfo.ImdbId), true));
Mocker.GetMock<IMovieMetadataService>()
.Verify(v => v.Upsert(It.Is<MovieMetadata>(s => s.ImdbId == newMovieInfo.ImdbId)));
}
[Test]
@ -62,8 +71,8 @@ public void should_log_error_if_tmdb_id_not_found()
{
Subject.Execute(new RefreshMovieCommand(new List<int> { _movie.Id }));
Mocker.GetMock<IMovieService>()
.Verify(v => v.UpdateMovie(It.Is<Movie>(s => s.Status == MovieStatusType.Deleted)), Times.Once());
Mocker.GetMock<IMovieMetadataService>()
.Verify(v => v.Upsert(It.Is<MovieMetadata>(s => s.Status == MovieStatusType.Deleted)), Times.Once());
ExceptionVerification.ExpectedErrors(1);
}
@ -78,8 +87,8 @@ public void should_update_if_tmdb_id_changed()
Subject.Execute(new RefreshMovieCommand(new List<int> { _movie.Id }));
Mocker.GetMock<IMovieService>()
.Verify(v => v.UpdateMovie(It.Is<List<Movie>>(s => s.First().TmdbId == newMovieInfo.TmdbId), true));
Mocker.GetMock<IMovieMetadataService>()
.Verify(v => v.Upsert(It.Is<MovieMetadata>(s => s.TmdbId == newMovieInfo.TmdbId)));
ExceptionVerification.ExpectedWarns(1);
}
@ -89,8 +98,8 @@ public void should_mark_as_deleted_if_tmdb_id_not_found()
{
Subject.Execute(new RefreshMovieCommand(new List<int> { _movie.Id }));
Mocker.GetMock<IMovieService>()
.Verify(v => v.UpdateMovie(It.Is<Movie>(s => s.Status == MovieStatusType.Deleted)), Times.Once());
Mocker.GetMock<IMovieMetadataService>()
.Verify(v => v.Upsert(It.Is<MovieMetadata>(s => s.Status == MovieStatusType.Deleted)), Times.Once());
ExceptionVerification.ExpectedErrors(1);
}
@ -102,8 +111,8 @@ public void should_not_remark_as_deleted_if_tmdb_id_not_found()
Subject.Execute(new RefreshMovieCommand(new List<int> { _movie.Id }));
Mocker.GetMock<IMovieService>()
.Verify(v => v.UpdateMovie(It.IsAny<Movie>()), Times.Never());
Mocker.GetMock<IMovieMetadataService>()
.Verify(v => v.Upsert(It.IsAny<MovieMetadata>()), Times.Never());
ExceptionVerification.ExpectedErrors(1);
}

View file

@ -10,12 +10,12 @@ namespace NzbDrone.Core.Test.MovieTests
[TestFixture]
public class ShouldRefreshMovieFixture : TestBase<ShouldRefreshMovie>
{
private Movie _movie;
private MovieMetadata _movie;
[SetUp]
public void Setup()
{
_movie = Builder<Movie>.CreateNew()
_movie = Builder<MovieMetadata>.CreateNew()
.With(v => v.Status = MovieStatusType.InCinemas)
.With(m => m.PhysicalRelease = DateTime.Today.AddDays(-100))
.Build();

View file

@ -50,7 +50,7 @@ public void Setup()
_movie = Builder<Movie>
.CreateNew()
.With(s => s.Title = "South Park")
.With(s => s.OriginalTitle = "South of the Park")
.With(s => s.MovieMetadata.Value.OriginalTitle = "South of the Park")
.Build();
_namingConfig = NamingConfig.Default;
@ -206,7 +206,7 @@ public void should_cleanup_Movie_Title()
public void should_replace_movie_original_title()
{
_namingConfig.StandardMovieFormat = "{Movie OriginalTitle}";
_movie.OriginalTitle = "South of the Park";
_movie.MovieMetadata.Value.OriginalTitle = "South of the Park";
Subject.BuildFileName(_movie, _movieFile)
.Should().Be("South of the Park");
@ -216,7 +216,7 @@ public void should_replace_movie_original_title()
public void should_replace_movie_certification()
{
_namingConfig.StandardMovieFormat = "{Movie Certification}";
_movie.Certification = "R";
_movie.MovieMetadata.Value.Certification = "R";
Subject.BuildFileName(_movie, _movieFile)
.Should().Be("R");
@ -226,7 +226,7 @@ public void should_replace_movie_certification()
public void should_replace_movie_collection()
{
_namingConfig.StandardMovieFormat = "{Movie Collection}";
_movie.Collection = new MovieCollection { Name = "South Part Collection" };
_movie.MovieMetadata.Value.Collection = new MovieCollection { Name = "South Part Collection" };
Subject.BuildFileName(_movie, _movieFile)
.Should().Be("South Part Collection");

View file

@ -16,7 +16,10 @@ public void should_add_movie_original_language()
var releaseInfo = new ParsedMovieInfo();
var movie = new Movies.Movie
{
OriginalLanguage = Language.English
MovieMetadata = new Movies.MovieMetadata
{
OriginalLanguage = Language.English
}
};
var result = Subject.AugmentMovieInfo(releaseInfo, movie);
result.ExtraInfo.Should().ContainKey("OriginalLanguage");

View file

@ -36,11 +36,11 @@ public void Setup()
{
_movie = Builder<Movie>.CreateNew()
.With(m => m.Title = "Fack Ju Göthe 2")
.With(m => m.CleanTitle = "fackjugoethe2")
.With(m => m.MovieMetadata.Value.CleanTitle = "fackjugoethe2")
.With(m => m.Year = 2015)
.With(m => m.AlternativeTitles = new List<AlternativeTitle> { new AlternativeTitle("Fack Ju Göthe 2: Same same") })
.With(m => m.Translations = new List<MovieTranslation> { new MovieTranslation { Title = "Translated Title", CleanTitle = "translatedtitle" } })
.With(m => m.OriginalLanguage = Language.English)
.With(m => m.MovieMetadata.Value.AlternativeTitles = new List<AlternativeTitle> { new AlternativeTitle("Fack Ju Göthe 2: Same same") })
.With(m => m.MovieMetadata.Value.Translations = new List<MovieTranslation> { new MovieTranslation { Title = "Translated Title", CleanTitle = "translatedtitle" } })
.With(m => m.MovieMetadata.Value.OriginalLanguage = Language.English)
.Build();
_parsedMovieInfo = new ParsedMovieInfo
@ -66,14 +66,14 @@ public void Setup()
_alternativeTitleInfo = new ParsedMovieInfo
{
MovieTitles = new List<string> { _movie.AlternativeTitles.First().Title },
MovieTitles = new List<string> { _movie.MovieMetadata.Value.AlternativeTitles.First().Title },
Languages = new List<Language> { Language.English },
Year = _movie.Year,
};
_translationTitleInfo = new ParsedMovieInfo
{
MovieTitles = new List<string> { _movie.Translations.First().Title },
MovieTitles = new List<string> { _movie.MovieMetadata.Value.Translations.First().Title },
Languages = new List<Language> { Language.English },
Year = _movie.Year,
};

View file

@ -76,20 +76,20 @@ public static List<CustomFormat> ParseCustomFormat(MovieFile movieFile, List<Cus
var info = new ParsedMovieInfo
{
MovieTitles = new List<string>() { movieFile.Movie.Title },
MovieTitles = new List<string>() { movieFile.Movie.MovieMetadata.Value.Title },
SimpleReleaseTitle = sceneName.SimplifyReleaseTitle(),
Quality = movieFile.Quality,
Languages = movieFile.Languages,
ReleaseGroup = movieFile.ReleaseGroup,
Edition = movieFile.Edition,
Year = movieFile.Movie.Year,
ImdbId = movieFile.Movie.ImdbId,
Year = movieFile.Movie.MovieMetadata.Value.Year,
ImdbId = movieFile.Movie.MovieMetadata.Value.ImdbId,
ExtraInfo = new Dictionary<string, object>
{
{ "IndexerFlags", movieFile.IndexerFlags },
{ "Size", movieFile.Size },
{ "Filename", Path.GetFileName(movieFile.RelativePath) },
{ "OriginalLanguage", movieFile.Movie.OriginalLanguage }
{ "OriginalLanguage", movieFile.Movie.MovieMetadata.Value.OriginalLanguage }
}
};
@ -114,14 +114,14 @@ public List<CustomFormat> ParseCustomFormat(Blocklist blocklist)
var info = new ParsedMovieInfo
{
MovieTitles = new List<string>() { movie.Title },
MovieTitles = new List<string>() { movie.MovieMetadata.Value.Title },
SimpleReleaseTitle = parsed?.SimpleReleaseTitle ?? blocklist.SourceTitle.SimplifyReleaseTitle(),
Quality = blocklist.Quality,
Languages = blocklist.Languages,
ReleaseGroup = parsed?.ReleaseGroup,
Edition = parsed?.Edition,
Year = movie.Year,
ImdbId = movie.ImdbId,
Year = movie.MovieMetadata.Value.Year,
ImdbId = movie.MovieMetadata.Value.ImdbId,
ExtraInfo = new Dictionary<string, object>
{
{ "IndexerFlags", blocklist.IndexerFlags },
@ -142,14 +142,14 @@ public List<CustomFormat> ParseCustomFormat(MovieHistory history)
var info = new ParsedMovieInfo
{
MovieTitles = new List<string>() { movie.Title },
MovieTitles = new List<string>() { movie.MovieMetadata.Value.Title },
SimpleReleaseTitle = parsed?.SimpleReleaseTitle ?? history.SourceTitle.SimplifyReleaseTitle(),
Quality = history.Quality,
Languages = history.Languages,
ReleaseGroup = parsed?.ReleaseGroup,
Edition = parsed?.Edition,
Year = movie.Year,
ImdbId = movie.ImdbId,
Year = movie.MovieMetadata.Value.Year,
ImdbId = movie.MovieMetadata.Value.ImdbId,
ExtraInfo = new Dictionary<string, object>
{
{ "IndexerFlags", flags },

View file

@ -47,13 +47,6 @@ public static SqlBuilder Where<TModel>(this SqlBuilder builder, Expression<Func<
return builder.Where(wb.ToString(), wb.Parameters);
}
public static SqlBuilder WherePostgres<TModel>(this SqlBuilder builder, Expression<Func<TModel, bool>> filter)
{
var wb = new WhereBuilderPostgres(filter, true, builder.Sequence);
return builder.Where(wb.ToString(), wb.Parameters);
}
public static SqlBuilder OrWhere<TModel>(this SqlBuilder builder, Expression<Func<TModel, bool>> filter)
{
var wb = GetWhereBuilder(builder.DatabaseType, filter, true, builder.Sequence);

View file

@ -0,0 +1,150 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(207)]
public class movie_metadata : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Create.TableForModel("MovieMetadata")
.WithColumn("TmdbId").AsInt32().Unique()
.WithColumn("ImdbId").AsString().Nullable()
.WithColumn("Images").AsString()
.WithColumn("Genres").AsString().Nullable()
.WithColumn("Title").AsString()
.WithColumn("SortTitle").AsString().Nullable()
.WithColumn("CleanTitle").AsString().Nullable().Indexed()
.WithColumn("OriginalTitle").AsString().Nullable()
.WithColumn("CleanOriginalTitle").AsString().Nullable().Indexed()
.WithColumn("OriginalLanguage").AsInt32()
.WithColumn("Status").AsInt32()
.WithColumn("LastInfoSync").AsDateTime().Nullable()
.WithColumn("Runtime").AsInt32()
.WithColumn("InCinemas").AsDateTime().Nullable()
.WithColumn("PhysicalRelease").AsDateTime().Nullable()
.WithColumn("DigitalRelease").AsDateTime().Nullable()
.WithColumn("Year").AsInt32().Nullable()
.WithColumn("SecondaryYear").AsInt32().Nullable()
.WithColumn("Ratings").AsString().Nullable()
.WithColumn("Recommendations").AsString()
.WithColumn("Certification").AsString().Nullable()
.WithColumn("YouTubeTrailerId").AsString().Nullable()
.WithColumn("Collection").AsString().Nullable()
.WithColumn("Studio").AsString().Nullable()
.WithColumn("Overview").AsString().Nullable()
.WithColumn("Website").AsString().Nullable()
.WithColumn("Popularity").AsFloat().Nullable();
// Transfer metadata from Movies to MovieMetadata
Execute.Sql(@"INSERT INTO ""MovieMetadata"" (""TmdbId"", ""ImdbId"", ""Title"", ""SortTitle"", ""CleanTitle"", ""OriginalTitle"", ""CleanOriginalTitle"", ""OriginalLanguage"", ""Overview"", ""Status"", ""LastInfoSync"", ""Images"", ""Genres"", ""Ratings"", ""Runtime"", ""InCinemas"", ""PhysicalRelease"", ""DigitalRelease"", ""Year"", ""SecondaryYear"", ""Recommendations"", ""Certification"", ""YouTubeTrailerId"", ""Studio"", ""Collection"", ""Website"")
SELECT ""TmdbId"", ""ImdbId"", ""Title"", ""SortTitle"", ""CleanTitle"", ""OriginalTitle"", ""CleanTitle"", ""OriginalLanguage"", ""Overview"", ""Status"", ""LastInfoSync"", ""Images"", ""Genres"", ""Ratings"", ""Runtime"", ""InCinemas"", ""PhysicalRelease"", ""DigitalRelease"", ""Year"", ""SecondaryYear"", ""Recommendations"", ""Certification"", ""YouTubeTrailerId"", ""Studio"", ""Collection"", ""Website""
FROM ""Movies""");
// Transfer metadata from ImportListMovies to MovieMetadata if not already in
Execute.Sql(@"INSERT INTO ""MovieMetadata"" (""TmdbId"", ""ImdbId"", ""Title"", ""SortTitle"", ""CleanTitle"", ""OriginalTitle"", ""CleanOriginalTitle"", ""OriginalLanguage"", ""Overview"", ""Status"", ""LastInfoSync"", ""Images"", ""Genres"", ""Ratings"", ""Runtime"", ""InCinemas"", ""PhysicalRelease"", ""DigitalRelease"", ""Year"", ""Recommendations"", ""Certification"", ""YouTubeTrailerId"", ""Studio"", ""Collection"", ""Website"")
SELECT ""TmdbId"", ""ImdbId"", ""Title"", ""SortTitle"", ""Title"", ""OriginalTitle"", ""OriginalTitle"", 1, ""Overview"", ""Status"", ""LastInfoSync"", ""Images"", ""Genres"", ""Ratings"", ""Runtime"", ""InCinemas"", ""PhysicalRelease"", ""DigitalRelease"", ""Year"", '[]', ""Certification"", ""YouTubeTrailerId"", ""Studio"", ""Collection"", ""Website""
FROM ""ImportListMovies""
WHERE ""ImportListMovies"".""TmdbId"" NOT IN ( SELECT ""MovieMetadata"".""TmdbId"" FROM ""MovieMetadata"" )");
// Add an MovieMetadataId column to Movies
Alter.Table("Movies").AddColumn("MovieMetadataId").AsInt32().WithDefaultValue(0);
Alter.Table("AlternativeTitles").AddColumn("MovieMetadataId").AsInt32().WithDefaultValue(0);
Alter.Table("Credits").AddColumn("MovieMetadataId").AsInt32().WithDefaultValue(0);
Alter.Table("MovieTranslations").AddColumn("MovieMetadataId").AsInt32().WithDefaultValue(0);
Alter.Table("ImportListMovies").AddColumn("MovieMetadataId").AsInt32().WithDefaultValue(0).Indexed();
// Update MovieMetadataId
Execute.Sql(@"UPDATE ""Movies""
SET ""MovieMetadataId"" = (SELECT ""MovieMetadata"".""Id""
FROM ""MovieMetadata""
WHERE ""MovieMetadata"".""TmdbId"" = ""Movies"".""TmdbId"")");
Execute.Sql(@"UPDATE ""AlternativeTitles""
SET ""MovieMetadataId"" = (SELECT ""Movies"".""MovieMetadataId""
FROM ""Movies""
WHERE ""Movies"".""Id"" = ""AlternativeTitles"".""MovieId"")");
Execute.Sql(@"UPDATE ""Credits""
SET ""MovieMetadataId"" = (SELECT ""Movies"".""MovieMetadataId""
FROM ""Movies""
WHERE ""Movies"".""Id"" = ""Credits"".""MovieId"")");
Execute.Sql(@"UPDATE ""MovieTranslations""
SET ""MovieMetadataId"" = (SELECT ""Movies"".""MovieMetadataId""
FROM ""Movies""
WHERE ""Movies"".""Id"" = ""MovieTranslations"".""MovieId"")");
Execute.Sql(@"UPDATE ""ImportListMovies""
SET ""MovieMetadataId"" = (SELECT ""MovieMetadata"".""Id""
FROM ""MovieMetadata""
WHERE ""MovieMetadata"".""TmdbId"" = ""ImportListMovies"".""TmdbId"")");
// Alter MovieMetadataId column to be unique on Movies
Alter.Table("Movies").AlterColumn("MovieMetadataId").AsInt32().Unique();
// Remove Movie Link from Metadata Tables
Delete.Column("MovieId").FromTable("AlternativeTitles");
Delete.Column("MovieId").FromTable("Credits");
Delete.Column("MovieId").FromTable("MovieTranslations");
// Remove the columns in Movies now in MovieMetadata
Delete.Column("TmdbId")
.Column("ImdbId")
.Column("Title")
.Column("SortTitle")
.Column("CleanTitle")
.Column("OriginalTitle")
.Column("OriginalLanguage")
.Column("Overview")
.Column("Status")
.Column("LastInfoSync")
.Column("Images")
.Column("Genres")
.Column("Ratings")
.Column("Runtime")
.Column("InCinemas")
.Column("PhysicalRelease")
.Column("DigitalRelease")
.Column("Year")
.Column("SecondaryYear")
.Column("Recommendations")
.Column("Certification")
.Column("YouTubeTrailerId")
.Column("Studio")
.Column("Collection")
.Column("Website")
// as well as the ones no longer used
.Column("LastDiskSync")
.Column("TitleSlug")
.FromTable("Movies");
// Remove the columns in ImportListMovies now in MovieMetadata
Delete.Column("TmdbId")
.Column("ImdbId")
.Column("Title")
.Column("SortTitle")
.Column("Overview")
.Column("Status")
.Column("LastInfoSync")
.Column("OriginalTitle")
.Column("Translations")
.Column("Images")
.Column("Genres")
.Column("Ratings")
.Column("Runtime")
.Column("InCinemas")
.Column("PhysicalRelease")
.Column("DigitalRelease")
.Column("Year")
.Column("Certification")
.Column("YouTubeTrailerId")
.Column("Studio")
.Column("Collection")
.Column("Website")
.FromTable("ImportListMovies");
}
}
}

View file

@ -109,9 +109,18 @@ public static void Map()
Mapper.Entity<Movie>("Movies").RegisterModel()
.Ignore(s => s.RootFolderPath)
.Ignore(s => s.Translations);
.Ignore(s => s.Title)
.Ignore(s => s.Year)
.Ignore(s => s.TmdbId)
.Ignore(s => s.ImdbId)
.HasOne(a => a.MovieMetadata, a => a.MovieMetadataId);
Mapper.Entity<ImportListMovie>("ImportListMovies").RegisterModel();
Mapper.Entity<ImportListMovie>("ImportListMovies").RegisterModel()
.Ignore(s => s.Title)
.Ignore(s => s.Year)
.Ignore(s => s.TmdbId)
.Ignore(s => s.ImdbId)
.HasOne(a => a.MovieMetadata, a => a.MovieMetadataId);
Mapper.Entity<AlternativeTitle>("AlternativeTitles").RegisterModel();
@ -156,6 +165,9 @@ public static void Map()
Mapper.Entity<DownloadHistory>("DownloadHistory").RegisterModel();
Mapper.Entity<UpdateHistory>("UpdateHistory").RegisterModel();
Mapper.Entity<MovieMetadata>("MovieMetadata").RegisterModel()
.Ignore(s => s.Translations);
}
private static void RegisterMappers()

View file

@ -174,9 +174,9 @@ private int CompareSize(DownloadDecision x, DownloadDecision y)
var preferredSize = _qualityDefinitionService.Get(remoteMovie.ParsedMovieInfo.Quality.Quality).PreferredSize;
// If no value for preferred it means unlimited so fallback to sort largest is best
if (preferredSize.HasValue && remoteMovie.Movie.Runtime > 0)
if (preferredSize.HasValue && remoteMovie.Movie.MovieMetadata.Value.Runtime > 0)
{
var preferredMovieSize = remoteMovie.Movie.Runtime * preferredSize.Value.Megabytes();
var preferredMovieSize = remoteMovie.Movie.MovieMetadata.Value.Runtime * preferredSize.Value.Megabytes();
// Calculate closest to the preferred size
return Math.Abs((remoteMovie.Release.Size - preferredMovieSize).Round(200.Megabytes())) * (-1);

View file

@ -34,10 +34,10 @@ public Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase searchCrit
var qualityDefinition = _qualityDefinitionService.Get(quality);
if (subject.Movie.Runtime == 0)
if (subject.Movie.MovieMetadata.Value.Runtime == 0)
{
_logger.Warn("{0} has no runtime information using median movie runtime of 110 minutes.", subject.Movie);
subject.Movie.Runtime = 110;
subject.Movie.MovieMetadata.Value.Runtime = 110;
}
if (qualityDefinition.MinSize.HasValue)
@ -45,7 +45,7 @@ public Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase searchCrit
var minSize = qualityDefinition.MinSize.Value.Megabytes();
//Multiply maxSize by Series.Runtime
minSize = minSize * subject.Movie.Runtime;
minSize = minSize * subject.Movie.MovieMetadata.Value.Runtime;
//If the parsed size is smaller than minSize we don't want it
if (subject.Release.Size < minSize)
@ -61,7 +61,7 @@ public Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase searchCrit
{
_logger.Debug("Max size is unlimited, skipping check");
}
else if (subject.Movie.Runtime == 0)
else if (subject.Movie.MovieMetadata.Value.Runtime == 0)
{
_logger.Debug("Movie runtime is 0, unable to validate size until it is available, rejecting");
return Decision.Reject("Movie runtime is 0, unable to validate size until it is available");
@ -71,7 +71,7 @@ public Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase searchCrit
var maxSize = qualityDefinition.MaxSize.Value.Megabytes();
//Multiply maxSize by Series.Runtime
maxSize = maxSize * subject.Movie.Runtime;
maxSize = maxSize * subject.Movie.MovieMetadata.Value.Runtime;
//If the parsed size is greater than maxSize we don't want it
if (subject.Release.Size > maxSize)

View file

@ -27,7 +27,7 @@ public virtual Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase se
return Decision.Accept();
}
var originalLanguage = subject.Movie.OriginalLanguage;
var originalLanguage = subject.Movie.MovieMetadata.Value.OriginalLanguage;
if (wantedLanguage == Language.Original)
{

View file

@ -68,7 +68,7 @@ protected override string AddFromMagnetLink(RemoteMovie remoteMovie, string hash
_proxy.SetTorrentLabel(actualHash, Settings.MovieCategory, Settings);
}
var isRecentMovie = remoteMovie.Movie.IsRecentMovie;
var isRecentMovie = remoteMovie.Movie.MovieMetadata.Value.IsRecentMovie;
if ((isRecentMovie && Settings.RecentMoviePriority == (int)DelugePriority.First) ||
(!isRecentMovie && Settings.OlderMoviePriority == (int)DelugePriority.First))
@ -95,7 +95,7 @@ protected override string AddFromTorrentFile(RemoteMovie remoteMovie, string has
_proxy.SetTorrentLabel(actualHash, Settings.MovieCategory, Settings);
}
var isRecentMovie = remoteMovie.Movie.IsRecentMovie;
var isRecentMovie = remoteMovie.Movie.MovieMetadata.Value.IsRecentMovie;
if ((isRecentMovie && Settings.RecentMoviePriority == (int)DelugePriority.First) ||
(!isRecentMovie && Settings.OlderMoviePriority == (int)DelugePriority.First))

View file

@ -52,7 +52,7 @@ private static IEnumerable<string> HandleTags(RemoteMovie remoteMovie, FloodSett
switch (additionalTag)
{
case (int)AdditionalTags.Collection:
result.Add(remoteMovie.Movie.Collection.Name);
result.Add(remoteMovie.Movie.MovieMetadata.Value.Collection.Name);
break;
case (int)AdditionalTags.Quality:
result.Add(remoteMovie.ParsedMovieInfo.Quality.Quality.ToString());
@ -70,7 +70,7 @@ private static IEnumerable<string> HandleTags(RemoteMovie remoteMovie, FloodSett
result.Add(remoteMovie.Release.Indexer);
break;
case (int)AdditionalTags.Studio:
result.Add(remoteMovie.Movie.Studio);
result.Add(remoteMovie.Movie.MovieMetadata.Value.Studio);
break;
default:
throw new DownloadClientException("Unexpected additional tag ID");

View file

@ -34,7 +34,7 @@ public NzbVortex(INzbVortexProxy proxy,
protected override string AddFromNzbFile(RemoteMovie remoteMovie, string filename, byte[] fileContents)
{
var priority = remoteMovie.Movie.IsRecentMovie ? Settings.RecentMoviePriority : Settings.OlderMoviePriority;
var priority = remoteMovie.Movie.MovieMetadata.Value.IsRecentMovie ? Settings.RecentMoviePriority : Settings.OlderMoviePriority;
var response = _proxy.DownloadNzb(fileContents, filename, priority, Settings);

View file

@ -40,7 +40,7 @@ protected override string AddFromNzbFile(RemoteMovie remoteMovie, string filenam
{
var category = Settings.MovieCategory;
var priority = remoteMovie.Movie.IsRecentMovie ? Settings.RecentMoviePriority : Settings.OlderMoviePriority;
var priority = remoteMovie.Movie.MovieMetadata.Value.IsRecentMovie ? Settings.RecentMoviePriority : Settings.OlderMoviePriority;
var addpaused = Settings.AddPaused;
var response = _proxy.DownloadNzb(fileContent, filename, category, priority, addpaused, Settings);

View file

@ -73,7 +73,7 @@ protected override string AddFromMagnetLink(RemoteMovie remoteMovie, string hash
var setShareLimits = remoteMovie.SeedConfiguration != null && (remoteMovie.SeedConfiguration.Ratio.HasValue || remoteMovie.SeedConfiguration.SeedTime.HasValue);
var addHasSetShareLimits = setShareLimits && ProxyApiVersion >= new Version(2, 8, 1);
var isRecentMovie = remoteMovie.Movie.IsRecentMovie;
var isRecentMovie = remoteMovie.Movie.MovieMetadata.Value.IsRecentMovie;
var moveToTop = (isRecentMovie && Settings.RecentMoviePriority == (int)QBittorrentPriority.First) || (!isRecentMovie && Settings.OlderMoviePriority == (int)QBittorrentPriority.First);
var forceStart = (QBittorrentState)Settings.InitialState == QBittorrentState.ForceStart;
@ -132,7 +132,7 @@ protected override string AddFromTorrentFile(RemoteMovie remoteMovie, string has
{
var setShareLimits = remoteMovie.SeedConfiguration != null && (remoteMovie.SeedConfiguration.Ratio.HasValue || remoteMovie.SeedConfiguration.SeedTime.HasValue);
var addHasSetShareLimits = setShareLimits && ProxyApiVersion >= new Version(2, 8, 1);
var isRecentMovie = remoteMovie.Movie.IsRecentMovie;
var isRecentMovie = remoteMovie.Movie.MovieMetadata.Value.IsRecentMovie;
var moveToTop = (isRecentMovie && Settings.RecentMoviePriority == (int)QBittorrentPriority.First) || (!isRecentMovie && Settings.OlderMoviePriority == (int)QBittorrentPriority.First);
var forceStart = (QBittorrentState)Settings.InitialState == QBittorrentState.ForceStart;

View file

@ -40,7 +40,7 @@ public Sabnzbd(ISabnzbdProxy proxy,
protected override string AddFromNzbFile(RemoteMovie remoteMovie, string filename, byte[] fileContent)
{
var category = Settings.MovieCategory;
var priority = remoteMovie.Movie.IsRecentMovie ? Settings.RecentMoviePriority : Settings.OlderMoviePriority;
var priority = remoteMovie.Movie.MovieMetadata.Value.IsRecentMovie ? Settings.RecentMoviePriority : Settings.OlderMoviePriority;
var response = _proxy.DownloadNzb(fileContent, filename, category, priority, Settings);

View file

@ -194,7 +194,7 @@ protected override string AddFromMagnetLink(RemoteMovie remoteMovie, string hash
_proxy.AddTorrentFromUrl(magnetLink, GetDownloadDirectory(), Settings);
_proxy.SetTorrentSeedingConfiguration(hash, remoteMovie.SeedConfiguration, Settings);
var isRecentMovie = remoteMovie.Movie.IsRecentMovie;
var isRecentMovie = remoteMovie.Movie.MovieMetadata.Value.IsRecentMovie;
if ((isRecentMovie && Settings.RecentMoviePriority == (int)TransmissionPriority.First) ||
(!isRecentMovie && Settings.OlderMoviePriority == (int)TransmissionPriority.First))
@ -210,7 +210,7 @@ protected override string AddFromTorrentFile(RemoteMovie remoteMovie, string has
_proxy.AddTorrentFromData(fileContent, GetDownloadDirectory(), Settings);
_proxy.SetTorrentSeedingConfiguration(hash, remoteMovie.SeedConfiguration, Settings);
var isRecentMovie = remoteMovie.Movie.IsRecentMovie;
var isRecentMovie = remoteMovie.Movie.MovieMetadata.Value.IsRecentMovie;
if ((isRecentMovie && Settings.RecentMoviePriority == (int)TransmissionPriority.First) ||
(!isRecentMovie && Settings.OlderMoviePriority == (int)TransmissionPriority.First))

View file

@ -72,7 +72,7 @@ public override void MarkItemAsImported(DownloadClientItem downloadClientItem)
protected override string AddFromMagnetLink(RemoteMovie remoteMovie, string hash, string magnetLink)
{
var priority = (RTorrentPriority)(remoteMovie.Movie.IsRecentMovie ? Settings.RecentMoviePriority : Settings.OlderMoviePriority);
var priority = (RTorrentPriority)(remoteMovie.Movie.MovieMetadata.Value.IsRecentMovie ? Settings.RecentMoviePriority : Settings.OlderMoviePriority);
_proxy.AddTorrentFromUrl(magnetLink, Settings.MovieCategory, priority, Settings.MovieDirectory, Settings);
@ -92,7 +92,7 @@ protected override string AddFromMagnetLink(RemoteMovie remoteMovie, string hash
protected override string AddFromTorrentFile(RemoteMovie remoteMovie, string hash, string filename, byte[] fileContent)
{
var priority = (RTorrentPriority)(remoteMovie.Movie.IsRecentMovie ? Settings.RecentMoviePriority : Settings.OlderMoviePriority);
var priority = (RTorrentPriority)(remoteMovie.Movie.MovieMetadata.Value.IsRecentMovie ? Settings.RecentMoviePriority : Settings.OlderMoviePriority);
_proxy.AddTorrentFromFile(filename, fileContent, Settings.MovieCategory, priority, Settings.MovieDirectory, Settings);

View file

@ -64,7 +64,7 @@ protected override string AddFromMagnetLink(RemoteMovie remoteMovie, string hash
_proxy.SetTorrentLabel(hash, Settings.MovieCategory, Settings);
}
var isRecentMovie = remoteMovie.Movie.IsRecentMovie;
var isRecentMovie = remoteMovie.Movie.MovieMetadata.Value.IsRecentMovie;
if ((isRecentMovie && Settings.RecentMoviePriority == (int)UTorrentPriority.First) ||
(!isRecentMovie && Settings.OlderMoviePriority == (int)UTorrentPriority.First))
@ -87,7 +87,7 @@ protected override string AddFromTorrentFile(RemoteMovie remoteMovie, string has
_proxy.SetTorrentLabel(hash, Settings.MovieCategory, Settings);
}
var isRecentEpisode = remoteMovie.Movie.IsRecentMovie;
var isRecentEpisode = remoteMovie.Movie.MovieMetadata.Value.IsRecentMovie;
if ((isRecentEpisode && Settings.RecentMoviePriority == (int)UTorrentPriority.First) ||
(!isRecentEpisode && Settings.OlderMoviePriority == (int)UTorrentPriority.First))

View file

@ -67,19 +67,19 @@ public override MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFil
{
var movieElement = new XElement("Movie");
movieElement.Add(new XElement("id", movie.ImdbId));
movieElement.Add(new XElement("Status", movie.Status));
movieElement.Add(new XElement("id", movie.MovieMetadata.Value.ImdbId));
movieElement.Add(new XElement("Status", movie.MovieMetadata.Value.Status));
movieElement.Add(new XElement("Added", movie.Added.ToString("MM/dd/yyyy HH:mm:ss tt")));
movieElement.Add(new XElement("LockData", "false"));
movieElement.Add(new XElement("Overview", movie.Overview));
movieElement.Add(new XElement("Overview", movie.MovieMetadata.Value.Overview));
movieElement.Add(new XElement("LocalTitle", movie.Title));
movieElement.Add(new XElement("Rating", movie.Ratings.Tmdb?.Value ?? 0));
movieElement.Add(new XElement("Rating", movie.MovieMetadata.Value.Ratings.Tmdb?.Value ?? 0));
movieElement.Add(new XElement("ProductionYear", movie.Year));
movieElement.Add(new XElement("RunningTime", movie.Runtime));
movieElement.Add(new XElement("IMDB", movie.ImdbId));
movieElement.Add(new XElement("Genres", movie.Genres.Select(genre => new XElement("Genre", genre))));
movieElement.Add(new XElement("RunningTime", movie.MovieMetadata.Value.Runtime));
movieElement.Add(new XElement("IMDB", movie.MovieMetadata.Value.ImdbId));
movieElement.Add(new XElement("Genres", movie.MovieMetadata.Value.Genres.Select(genre => new XElement("Genre", genre))));
var doc = new XDocument(movieElement);
doc.Save(xw);

View file

@ -118,9 +118,9 @@ public override MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFil
var details = new XElement("video");
details.Add(new XElement("title", movie.Title));
details.Add(new XElement("genre", string.Join(" / ", movie.Genres)));
details.Add(new XElement("description", movie.Overview));
details.Add(new XElement("length", movie.Runtime));
details.Add(new XElement("genre", string.Join(" / ", movie.MovieMetadata.Value.Genres)));
details.Add(new XElement("description", movie.MovieMetadata.Value.Overview));
details.Add(new XElement("length", movie.MovieMetadata.Value.Runtime));
doc.Add(details);
doc.Save(xw);
@ -139,7 +139,7 @@ public override List<ImageFileResult> MovieImages(Movie movie)
return new List<ImageFileResult>();
}
var image = movie.Images.SingleOrDefault(c => c.CoverType == MediaCoverTypes.Poster) ?? movie.Images.FirstOrDefault();
var image = movie.MovieMetadata.Value.Images.SingleOrDefault(c => c.CoverType == MediaCoverTypes.Poster) ?? movie.MovieMetadata.Value.Images.FirstOrDefault();
if (image == null)
{
_logger.Trace("Failed to find suitable Movie image for movie {0}.", movie.Title);

View file

@ -113,8 +113,8 @@ public override MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFil
var details = new XElement("details");
details.Add(new XElement("id", movie.Id));
details.Add(new XElement("title", movie.Title));
details.Add(new XElement("genre", string.Join(" / ", movie.Genres)));
details.Add(new XElement("overview", movie.Overview));
details.Add(new XElement("genre", string.Join(" / ", movie.MovieMetadata.Value.Genres)));
details.Add(new XElement("overview", movie.MovieMetadata.Value.Overview));
doc.Add(details);
doc.Save(xw);
@ -136,7 +136,7 @@ public override List<ImageFileResult> MovieImages(Movie movie)
}
//Because we only support one image, attempt to get the Poster type, then if that fails grab the first
var image = movie.Images.SingleOrDefault(c => c.CoverType == MediaCoverTypes.Poster) ?? movie.Images.FirstOrDefault();
var image = movie.MovieMetadata.Value.Images.SingleOrDefault(c => c.CoverType == MediaCoverTypes.Poster) ?? movie.MovieMetadata.Value.Images.FirstOrDefault();
if (image == null)
{
_logger.Trace("Failed to find suitable Movie image for movie {0}.", movie.Title);

View file

@ -123,14 +123,14 @@ public override MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFil
_logger.Debug("Generating Movie Metadata for: {0}", Path.Combine(movie.Path, movieFile.RelativePath));
var movieMetadataLanguage = (Settings.MovieMetadataLanguage == (int)Language.Original) ?
(int)movie.OriginalLanguage :
(int)movie.MovieMetadata.Value.OriginalLanguage :
Settings.MovieMetadataLanguage;
var movieTranslations = _movieTranslationsService.GetAllTranslationsForMovie(movie.Id);
var selectedSettingsLanguage = Language.FindById(movieMetadataLanguage);
var movieTranslation = movieTranslations.FirstOrDefault(mt => mt.Language == selectedSettingsLanguage);
var credits = _creditService.GetAllCreditsForMovie(movie.Id);
var credits = _creditService.GetAllCreditsForMovie(movie.MovieMetadataId);
var watched = GetExistingWatchedStatus(movie, movieFile.RelativePath);
@ -142,44 +142,44 @@ public override MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFil
using (var xw = XmlWriter.Create(sb, xws))
{
var doc = new XDocument();
var thumbnail = movie.Images.SingleOrDefault(i => i.CoverType == MediaCoverTypes.Screenshot);
var posters = movie.Images.Where(i => i.CoverType == MediaCoverTypes.Poster);
var fanarts = movie.Images.Where(i => i.CoverType == MediaCoverTypes.Fanart);
var thumbnail = movie.MovieMetadata.Value.Images.SingleOrDefault(i => i.CoverType == MediaCoverTypes.Screenshot);
var posters = movie.MovieMetadata.Value.Images.Where(i => i.CoverType == MediaCoverTypes.Poster);
var fanarts = movie.MovieMetadata.Value.Images.Where(i => i.CoverType == MediaCoverTypes.Fanart);
var details = new XElement("movie");
details.Add(new XElement("title", movieTranslation?.Title ?? movie.Title));
details.Add(new XElement("originaltitle", movie.OriginalTitle));
details.Add(new XElement("originaltitle", movie.MovieMetadata.Value.OriginalTitle));
details.Add(new XElement("sorttitle", movie.SortTitle));
details.Add(new XElement("sorttitle", movie.MovieMetadata.Value.SortTitle));
if (movie.Ratings.Tmdb?.Votes > 0 || movie.Ratings.Imdb?.Votes > 0)
if (movie.MovieMetadata.Value.Ratings.Tmdb?.Votes > 0 || movie.MovieMetadata.Value.Ratings.Imdb?.Votes > 0)
{
var setRating = new XElement("ratings");
if (movie.Ratings.Tmdb?.Votes > 0)
if (movie.MovieMetadata.Value.Ratings.Tmdb?.Votes > 0)
{
var setRatethemoviedb = new XElement("rating", new XAttribute("name", "themoviedb"), new XAttribute("max", "10"), new XAttribute("default", "true"));
setRatethemoviedb.Add(new XElement("value", movie.Ratings.Tmdb.Value));
setRatethemoviedb.Add(new XElement("votes", movie.Ratings.Tmdb.Votes));
setRatethemoviedb.Add(new XElement("value", movie.MovieMetadata.Value.Ratings.Tmdb.Value));
setRatethemoviedb.Add(new XElement("votes", movie.MovieMetadata.Value.Ratings.Tmdb.Votes));
setRating.Add(setRatethemoviedb);
}
if (movie.Ratings.Imdb?.Votes > 0)
if (movie.MovieMetadata.Value.Ratings.Imdb?.Votes > 0)
{
var setRateImdb = new XElement("rating", new XAttribute("name", "imdb"), new XAttribute("max", "10"));
setRateImdb.Add(new XElement("value", movie.Ratings.Imdb.Value));
setRateImdb.Add(new XElement("votes", movie.Ratings.Imdb.Votes));
setRateImdb.Add(new XElement("value", movie.MovieMetadata.Value.Ratings.Imdb.Value));
setRateImdb.Add(new XElement("votes", movie.MovieMetadata.Value.Ratings.Imdb.Votes));
setRating.Add(setRateImdb);
}
details.Add(setRating);
}
if (movie.Ratings?.Tmdb?.Votes > 0)
if (movie.MovieMetadata.Value.Ratings?.Tmdb?.Votes > 0)
{
details.Add(new XElement("rating", movie.Ratings.Tmdb.Value));
details.Add(new XElement("rating", movie.MovieMetadata.Value.Ratings.Tmdb.Value));
}
details.Add(new XElement("userrating"));
@ -188,11 +188,11 @@ public override MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFil
details.Add(new XElement("outline"));
details.Add(new XElement("plot", movieTranslation?.Overview ?? movie.Overview));
details.Add(new XElement("plot", movieTranslation?.Overview ?? movie.MovieMetadata.Value.Overview));
details.Add(new XElement("tagline"));
details.Add(new XElement("runtime", movie.Runtime));
details.Add(new XElement("runtime", movie.MovieMetadata.Value.Runtime));
if (thumbnail != null)
{
@ -221,9 +221,9 @@ public override MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFil
details.Add(fanartElement);
}
if (movie.Certification.IsNotNullOrWhiteSpace())
if (movie.MovieMetadata.Value.Certification.IsNotNullOrWhiteSpace())
{
details.Add(new XElement("mpaa", movie.Certification));
details.Add(new XElement("mpaa", movie.MovieMetadata.Value.Certification));
}
details.Add(new XElement("playcount"));
@ -237,25 +237,25 @@ public override MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFil
uniqueId.SetAttributeValue("default", true);
details.Add(uniqueId);
if (movie.ImdbId.IsNotNullOrWhiteSpace())
if (movie.MovieMetadata.Value.ImdbId.IsNotNullOrWhiteSpace())
{
var imdbId = new XElement("uniqueid", movie.ImdbId);
var imdbId = new XElement("uniqueid", movie.MovieMetadata.Value.ImdbId);
imdbId.SetAttributeValue("type", "imdb");
details.Add(imdbId);
}
foreach (var genre in movie.Genres)
foreach (var genre in movie.MovieMetadata.Value.Genres)
{
details.Add(new XElement("genre", genre));
}
details.Add(new XElement("country"));
if (movie.Collection?.Name != null)
if (movie.MovieMetadata.Value.Collection?.Name != null)
{
var setElement = new XElement("set");
setElement.Add(new XElement("name", movie.Collection.Name));
setElement.Add(new XElement("name", movie.MovieMetadata.Value.Collection.Name));
setElement.Add(new XElement("overview"));
details.Add(setElement);
@ -284,16 +284,16 @@ public override MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFil
}
}
if (movie.InCinemas.HasValue)
if (movie.MovieMetadata.Value.InCinemas.HasValue)
{
details.Add(new XElement("premiered", movie.InCinemas.Value.ToString("yyyy-MM-dd")));
details.Add(new XElement("premiered", movie.MovieMetadata.Value.InCinemas.Value.ToString("yyyy-MM-dd")));
}
details.Add(new XElement("year", movie.Year));
details.Add(new XElement("studio", movie.Studio));
details.Add(new XElement("studio", movie.MovieMetadata.Value.Studio));
details.Add(new XElement("trailer", "plugin://plugin.video.youtube/play/?video_id=" + movie.YouTubeTrailerId));
details.Add(new XElement("trailer", "plugin://plugin.video.youtube/play/?video_id=" + movie.MovieMetadata.Value.YouTubeTrailerId));
if (movieFile.MediaInfo != null)
{
@ -369,10 +369,10 @@ public override MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFil
if (Settings.MovieMetadataURL)
{
xmlResult += "https://www.themoviedb.org/movie/" + movie.TmdbId;
xmlResult += "https://www.themoviedb.org/movie/" + movie.MovieMetadata.Value.TmdbId;
xmlResult += Environment.NewLine;
xmlResult += "https://www.imdb.com/title/" + movie.ImdbId;
xmlResult += "https://www.imdb.com/title/" + movie.MovieMetadata.Value.ImdbId;
xmlResult += Environment.NewLine;
}
@ -393,7 +393,7 @@ public override List<ImageFileResult> MovieImages(Movie movie)
private IEnumerable<ImageFileResult> ProcessMovieImages(Movie movie)
{
foreach (var image in movie.Images)
foreach (var image in movie.MovieMetadata.Value.Images)
{
var source = _mediaCoverService.GetCoverPath(movie.Id, image.CoverType);
var destination = image.CoverType.ToString().ToLowerInvariant() + Path.GetExtension(source);

View file

@ -21,7 +21,7 @@ public RemovedMovieCheck(IMovieService movieService, ILocalizationService locali
public override HealthCheck Check()
{
var deletedMovie = _movieService.GetAllMovies().Where(v => v.Status == MovieStatusType.Deleted).ToList();
var deletedMovie = _movieService.GetAllMovies().Where(v => v.MovieMetadata.Value.Status == MovieStatusType.Deleted).ToList();
if (deletedMovie.Empty())
{
@ -40,12 +40,12 @@ public override HealthCheck Check()
public bool ShouldCheckOnEvent(MoviesDeletedEvent message)
{
return message.Movies.Any(m => m.Status == MovieStatusType.Deleted);
return message.Movies.Any(m => m.MovieMetadata.Value.Status == MovieStatusType.Deleted);
}
public bool ShouldCheckOnEvent(MovieUpdatedEvent message)
{
return message.Movie.Status == MovieStatusType.Deleted;
return message.Movie.MovieMetadata.Value.Status == MovieStatusType.Deleted;
}
}
}

View file

@ -1,4 +1,4 @@
using Dapper;
using Dapper;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Housekeeping.Housekeepers
@ -19,9 +19,9 @@ public void Clean()
mapper.Execute(@"DELETE FROM ""AlternativeTitles""
WHERE ""Id"" IN (
SELECT ""AlternativeTitles"".""Id"" FROM ""AlternativeTitles""
LEFT OUTER JOIN ""Movies""
ON ""AlternativeTitles"".""MovieId"" = ""Movies"".""Id""
WHERE ""Movies"".""Id"" IS NULL)");
LEFT OUTER JOIN ""MovieMetadata""
ON ""AlternativeTitles"".""MovieMetadataId"" = ""MovieMetadata"".""Id""
WHERE ""MovieMetadata"".""Id"" IS NULL)");
}
}
}

View file

@ -19,9 +19,9 @@ public void Clean()
mapper.Execute(@"DELETE FROM ""Credits""
WHERE ""Id"" IN (
SELECT ""Credits"".""Id"" FROM ""Credits""
LEFT OUTER JOIN ""Movies""
ON ""Credits"".""MovieId"" = ""Movies"".""Id""
WHERE ""Movies"".""Id"" IS NULL)");
LEFT OUTER JOIN ""MovieMetadata""
ON ""Credits"".""MovieMetadataId"" = ""MovieMetadata"".""Id""
WHERE ""MovieMetadata"".""Id"" IS NULL)");
}
}
}

View file

@ -0,0 +1,28 @@
using Dapper;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Housekeeping.Housekeepers
{
public class CleanupOrphanedMovieMetadata : IHousekeepingTask
{
private readonly IMainDatabase _database;
public CleanupOrphanedMovieMetadata(IMainDatabase database)
{
_database = database;
}
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""MovieMetadata""
WHERE ""Id"" IN (
SELECT ""MovieMetadata"".""Id"" FROM ""MovieMetadata""
LEFT OUTER JOIN ""Movies"" ON ""Movies"".""MovieMetadataId"" = ""MovieMetadata"".""Id""
LEFT OUTER JOIN ""ImportListMovies"" ON ""ImportListMovies"".""MovieMetadataId"" = ""MovieMetadata"".""Id""
WHERE ""Movies"".""Id"" IS NULL AND ""ImportListMovies"".""Id"" IS NULL)");
}
}
}
}

View file

@ -19,9 +19,9 @@ public void Clean()
mapper.Execute(@"DELETE FROM ""MovieTranslations""
WHERE ""Id"" IN (
SELECT ""MovieTranslations"".""Id"" FROM ""MovieTranslations""
LEFT OUTER JOIN ""Movies""
ON ""MovieTranslations"".""MovieId"" = ""Movies"".""Id""
WHERE ""Movies"".""Id"" IS NULL)");
LEFT OUTER JOIN ""MovieMetadata""
ON ""MovieTranslations"".""MovieMetadataId"" = ""MovieMetadata"".""Id""
WHERE ""MovieMetadata"".""Id"" IS NULL)");
}
}
}

View file

@ -24,18 +24,21 @@ public class FetchAndParseImportListService : IFetchAndParseImportList
private readonly IImportListStatusService _importListStatusService;
private readonly IImportListMovieService _listMovieService;
private readonly ISearchForNewMovie _movieSearch;
private readonly IMovieMetadataService _movieMetadataService;
private readonly Logger _logger;
public FetchAndParseImportListService(IImportListFactory importListFactory,
IImportListStatusService importListStatusService,
IImportListMovieService listMovieService,
ISearchForNewMovie movieSearch,
IMovieMetadataService movieMetadataService,
Logger logger)
{
_importListFactory = importListFactory;
_importListStatusService = importListStatusService;
_listMovieService = listMovieService;
_movieSearch = movieSearch;
_movieMetadataService = movieMetadataService;
_logger = logger;
}
@ -173,33 +176,16 @@ public ImportListFetchResult FetchSingleList(ImportListDefinition definition)
private ImportListMovie MapMovieReport(ImportListMovie report)
{
var mappedMovie = _movieSearch.MapMovieToTmdbMovie(new Movie { Title = report.Title, TmdbId = report.TmdbId, ImdbId = report.ImdbId, Year = report.Year });
var mappedMovie = _movieSearch.MapMovieToTmdbMovie(new MovieMetadata { Title = report.Title, TmdbId = report.TmdbId, ImdbId = report.ImdbId, Year = report.Year });
_movieMetadataService.Upsert(mappedMovie);
var mappedListMovie = new ImportListMovie { ListId = report.ListId };
if (mappedMovie != null)
{
mappedListMovie.TmdbId = mappedMovie.TmdbId;
mappedListMovie.ImdbId = mappedMovie.ImdbId;
mappedListMovie.Title = mappedMovie.Title;
mappedListMovie.SortTitle = mappedMovie?.SortTitle;
mappedListMovie.Year = mappedMovie.Year;
mappedListMovie.Overview = mappedMovie.Overview;
mappedListMovie.Ratings = mappedMovie.Ratings;
mappedListMovie.Studio = mappedMovie.Studio;
mappedListMovie.Certification = mappedMovie.Certification;
mappedListMovie.Collection = mappedMovie.Collection;
mappedListMovie.Status = mappedMovie.Status;
mappedListMovie.Images = mappedMovie.Images;
mappedListMovie.Website = mappedMovie.Website;
mappedListMovie.YouTubeTrailerId = mappedMovie.YouTubeTrailerId;
mappedListMovie.Translations = mappedMovie.Translations;
mappedListMovie.InCinemas = mappedMovie.InCinemas;
mappedListMovie.PhysicalRelease = mappedMovie.PhysicalRelease;
mappedListMovie.DigitalRelease = mappedMovie.DigitalRelease;
mappedListMovie.Genres = mappedMovie.Genres;
mappedListMovie.Runtime = mappedMovie.Runtime;
mappedListMovie.OriginalTitle = mappedMovie.OriginalTitle;
mappedListMovie.MovieMetadata = mappedMovie;
mappedListMovie.MovieMetadataId = mappedMovie.Id;
}
return mappedListMovie;

View file

@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Movies.Translations;
namespace NzbDrone.Core.ImportLists.ImportListMovies
{
@ -10,37 +7,35 @@ public class ImportListMovie : ModelBase
{
public ImportListMovie()
{
Images = new List<MediaCover.MediaCover>();
Genres = new List<string>();
Translations = new List<MovieTranslation>();
Ratings = new Ratings();
MovieMetadata = new MovieMetadata();
}
public int TmdbId { get; set; }
public string ImdbId { get; set; }
public string Title { get; set; }
public string SortTitle { get; set; }
public MovieStatusType Status { get; set; }
public string Overview { get; set; }
public DateTime? LastInfoSync { get; set; }
public int Runtime { get; set; }
public List<MediaCover.MediaCover> Images { get; set; }
public string Website { get; set; }
public int Year { get; set; }
public Ratings Ratings { get; set; }
public List<string> Genres { get; set; }
public MovieCollection Collection { get; set; }
public string Certification { get; set; }
public DateTime? InCinemas { get; set; }
public DateTime? PhysicalRelease { get; set; }
public DateTime? DigitalRelease { get; set; }
public List<MovieTranslation> Translations { get; set; }
public string YouTubeTrailerId { get; set; }
public string Studio { get; set; }
public string OriginalTitle { get; set; }
public int ListId { get; set; }
public int MovieMetadataId { get; set; }
public LazyLoaded<MovieMetadata> MovieMetadata { get; set; }
public string Title
{
get { return MovieMetadata.Value.Title; }
set { MovieMetadata.Value.Title = value; }
}
public int TmdbId
{
get { return MovieMetadata.Value.TmdbId; }
set { MovieMetadata.Value.TmdbId = value; }
}
public string ImdbId
{
get { return MovieMetadata.Value.ImdbId; }
set { MovieMetadata.Value.ImdbId = value; }
}
public int Year
{
get { return MovieMetadata.Value.Year; }
set { MovieMetadata.Value.Year = value; }
}
}
}

View file

@ -48,11 +48,6 @@ public override ImportListFetchResult Fetch()
{
TmdbId = remoteMovie.TmdbId,
Title = remoteMovie.Title,
SortTitle = remoteMovie.SortTitle,
Overview = remoteMovie.Overview,
Images = remoteMovie.Images.Select(x => MapImage(x, Settings.BaseUrl)).ToList(),
PhysicalRelease = remoteMovie.PhysicalRelease,
InCinemas = remoteMovie.InCinemas,
Year = remoteMovie.Year
});
}

View file

@ -36,10 +36,7 @@ protected ImportListMovie MapListMovie(MovieResultResource movieResult)
var movie = new ImportListMovie
{
TmdbId = movieResult.Id,
Overview = movieResult.Overview,
Title = movieResult.Title,
SortTitle = Parser.Parser.NormalizeTitle(movieResult.Title),
Images = new List<MediaCover.MediaCover>(),
};
if (movieResult.ReleaseDate.IsNotNullOrWhiteSpace())
@ -48,8 +45,6 @@ protected ImportListMovie MapListMovie(MovieResultResource movieResult)
movie.Year = releaseDate.Year;
}
movie.Images.AddIfNotNull(MapPosterImage(movieResult.PosterPath));
return movie;
}

View file

@ -49,7 +49,7 @@ public ReleaseSearchService(IIndexerFactory indexerFactory,
public List<DownloadDecision> MovieSearch(int movieId, bool userInvokedSearch, bool interactiveSearch)
{
var movie = _movieService.GetMovie(movieId);
movie.Translations = _movieTranslationService.GetAllTranslationsForMovie(movie.Id);
movie.MovieMetadata.Value.Translations = _movieTranslationService.GetAllTranslationsForMovie(movie.Id);
return MovieSearch(movie, userInvokedSearch, interactiveSearch);
}
@ -81,8 +81,8 @@ private TSpec Get<TSpec>(Movie movie, bool userInvokedSearch, bool interactiveSe
var queryTranlations = new List<string>
{
movie.Title,
movie.OriginalTitle
movie.MovieMetadata.Value.Title,
movie.MovieMetadata.Value.OriginalTitle
};
//Add Translation of wanted languages to search query

View file

@ -24,9 +24,9 @@ public virtual IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria
{
var pageableRequests = new IndexerPageableRequestChain();
if (searchCriteria.Movie.ImdbId.IsNotNullOrWhiteSpace())
if (searchCriteria.Movie.MovieMetadata.Value.ImdbId.IsNotNullOrWhiteSpace())
{
pageableRequests.Add(GetRequest("search-torrents", string.Format("&type=imdb&query={0}", searchCriteria.Movie.ImdbId)));
pageableRequests.Add(GetRequest("search-torrents", string.Format("&type=imdb&query={0}", searchCriteria.Movie.MovieMetadata.Value.ImdbId)));
}
else
{

View file

@ -35,12 +35,12 @@ public virtual IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria
private bool TryAddSearchParameters(TorrentQuery query, SearchCriteriaBase searchCriteria)
{
if (searchCriteria.Movie.ImdbId.IsNullOrWhiteSpace())
if (searchCriteria.Movie.MovieMetadata.Value.ImdbId.IsNullOrWhiteSpace())
{
return false;
}
var imdbId = int.Parse(searchCriteria.Movie.ImdbId.Substring(2));
var imdbId = int.Parse(searchCriteria.Movie.MovieMetadata.Value.ImdbId.Substring(2));
if (imdbId != 0)
{

View file

@ -115,8 +115,8 @@ public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchC
private void AddMovieIdPageableRequests(IndexerPageableRequestChain chain, int maxPages, IEnumerable<int> categories, SearchCriteriaBase searchCriteria)
{
var includeTmdbSearch = SupportsTmdbSearch && searchCriteria.Movie.TmdbId > 0;
var includeImdbSearch = SupportsImdbSearch && searchCriteria.Movie.ImdbId.IsNotNullOrWhiteSpace();
var includeTmdbSearch = SupportsTmdbSearch && searchCriteria.Movie.MovieMetadata.Value.TmdbId > 0;
var includeImdbSearch = SupportsImdbSearch && searchCriteria.Movie.MovieMetadata.Value.ImdbId.IsNotNullOrWhiteSpace();
if (SupportsAggregatedIdSearch && (includeTmdbSearch || includeImdbSearch))
{
@ -124,12 +124,12 @@ private void AddMovieIdPageableRequests(IndexerPageableRequestChain chain, int m
if (includeTmdbSearch)
{
ids += "&tmdbid=" + searchCriteria.Movie.TmdbId;
ids += "&tmdbid=" + searchCriteria.Movie.MovieMetadata.Value.TmdbId;
}
if (includeImdbSearch)
{
ids += "&imdbid=" + searchCriteria.Movie.ImdbId.Substring(2);
ids += "&imdbid=" + searchCriteria.Movie.MovieMetadata.Value.ImdbId.Substring(2);
}
chain.Add(GetPagedRequests(maxPages, categories, "movie", ids));
@ -141,14 +141,14 @@ private void AddMovieIdPageableRequests(IndexerPageableRequestChain chain, int m
chain.Add(GetPagedRequests(maxPages,
categories,
"movie",
string.Format("&tmdbid={0}", searchCriteria.Movie.TmdbId)));
string.Format("&tmdbid={0}", searchCriteria.Movie.MovieMetadata.Value.TmdbId)));
}
else if (includeImdbSearch)
{
chain.Add(GetPagedRequests(maxPages,
categories,
"movie",
string.Format("&imdbid={0}", searchCriteria.Movie.ImdbId.Substring(2))));
string.Format("&imdbid={0}", searchCriteria.Movie.MovieMetadata.Value.ImdbId.Substring(2))));
}
}

View file

@ -29,9 +29,9 @@ public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchC
{
var pageableRequests = new IndexerPageableRequestChain();
if (searchCriteria.Movie.ImdbId.IsNotNullOrWhiteSpace())
if (searchCriteria.Movie.MovieMetadata.Value.ImdbId.IsNotNullOrWhiteSpace())
{
pageableRequests.Add(GetRequest(searchCriteria.Movie.ImdbId));
pageableRequests.Add(GetRequest(searchCriteria.Movie.MovieMetadata.Value.ImdbId));
}
else if (searchCriteria.Movie.Year > 0)
{

View file

@ -87,11 +87,11 @@ private IEnumerable<IndexerRequest> GetMovieRequest(MovieSearchCriteria searchCr
requestBuilder.AddQueryParam("mode", "search");
if (searchCriteria.Movie.ImdbId.IsNotNullOrWhiteSpace())
if (searchCriteria.Movie.MovieMetadata.Value.ImdbId.IsNotNullOrWhiteSpace())
{
requestBuilder.AddQueryParam("search_imdb", searchCriteria.Movie.ImdbId);
requestBuilder.AddQueryParam("search_imdb", searchCriteria.Movie.MovieMetadata.Value.ImdbId);
}
else if (searchCriteria.Movie.TmdbId > 0)
else if (searchCriteria.Movie.MovieMetadata.Value.TmdbId > 0)
{
requestBuilder.AddQueryParam("search_themoviedb", searchCriteria.Movie.TmdbId);
}

View file

@ -1,3 +1,4 @@
using Equ;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.MediaCover
@ -12,7 +13,7 @@ public enum MediaCoverTypes
Headshot = 5
}
public class MediaCover : IEmbeddedDocument
public class MediaCover : MemberwiseEquatable<MediaCover>, IEmbeddedDocument
{
public MediaCoverTypes CoverType { get; set; }
public string Url { get; set; }

View file

@ -145,7 +145,7 @@ private bool EnsureCovers(Movie movie)
bool updated = false;
var toResize = new List<Tuple<MediaCover, bool>>();
foreach (var cover in movie.Images)
foreach (var cover in movie.MovieMetadata.Value.Images)
{
var fileName = GetCoverPath(movie.Id, cover.CoverType);
var alreadyExists = false;

View file

@ -133,7 +133,7 @@ public bool ShouldDeleteFolder(DirectoryInfo directoryInfo, Movie movie)
return false;
}
if (_detectSample.IsSample(movie, videoFile) != DetectSampleResult.Sample)
if (_detectSample.IsSample(movie.MovieMetadata, videoFile) != DetectSampleResult.Sample)
{
_logger.Warn("Non-sample file detected: [{0}]", videoFile);
return false;

View file

@ -22,7 +22,7 @@ public AggregateLanguage(IEnumerable<IAugmentLanguage> augmentLanguages,
public LocalMovie Aggregate(LocalMovie localMovie, DownloadClientItem downloadClientItem, bool otherFiles)
{
var languages = new List<Language> { localMovie.Movie?.OriginalLanguage ?? Language.Unknown };
var languages = new List<Language> { localMovie.Movie?.MovieMetadata.Value.OriginalLanguage ?? Language.Unknown };
var languagesConfidence = Confidence.Default;
foreach (var augmentLanguage in _augmentLanguages)

View file

@ -9,7 +9,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport
{
public interface IDetectSample
{
DetectSampleResult IsSample(Movie movie, string path);
DetectSampleResult IsSample(MovieMetadata movie, string path);
}
public class DetectSample : IDetectSample
@ -23,7 +23,7 @@ public DetectSample(IVideoFileInfoReader videoFileInfoReader, Logger logger)
_logger = logger;
}
public DetectSampleResult IsSample(Movie movie, string path)
public DetectSampleResult IsSample(MovieMetadata movie, string path)
{
var extension = Path.GetExtension(path);
@ -75,7 +75,7 @@ public DetectSampleResult IsSample(Movie movie, string path)
return DetectSampleResult.NotSample;
}
private int GetMinimumAllowedRuntime(Movie movie)
private int GetMinimumAllowedRuntime(MovieMetadata movie)
{
//Anime short - 15 seconds
if (movie.Runtime <= 3)

View file

@ -78,7 +78,7 @@ public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie mo
downloadClientItemInfo = _parsingService.EnhanceMovieInfo(downloadClientItemInfo);
}
var nonSampleVideoFileCount = GetNonSampleVideoFileCount(newFiles, movie);
var nonSampleVideoFileCount = GetNonSampleVideoFileCount(newFiles, movie.MovieMetadata);
var decisions = new List<ImportDecision>();
@ -187,7 +187,7 @@ private Rejection EvaluateSpec(IImportDecisionEngineSpecification spec, LocalMov
return null;
}
private int GetNonSampleVideoFileCount(List<string> videoFiles, Movie movie)
private int GetNonSampleVideoFileCount(List<string> videoFiles, MovieMetadata movie)
{
return videoFiles.Count(file =>
{

View file

@ -104,8 +104,8 @@ public ManualImportItem ReprocessItem(string path, string downloadId, int movieI
if (languageParse.Count <= 1 && languageParse.First() == Language.Unknown && movie != null)
{
languageParse = new List<Language> { movie.OriginalLanguage };
_logger.Debug("Language couldn't be parsed from release, fallback to movie original language: {0}", movie.OriginalLanguage.Name);
languageParse = new List<Language> { movie.MovieMetadata.Value.OriginalLanguage };
_logger.Debug("Language couldn't be parsed from release, fallback to movie original language: {0}", movie.MovieMetadata.Value.OriginalLanguage.Name);
}
var localMovie = new LocalMovie

View file

@ -25,7 +25,7 @@ public Decision IsSatisfiedBy(LocalMovie localMovie, DownloadClientItem download
return Decision.Accept();
}
var sample = _detectSample.IsSample(localMovie.Movie, localMovie.Path);
var sample = _detectSample.IsSample(localMovie.Movie.MovieMetadata, localMovie.Path);
if (sample == DetectSampleResult.Sample)
{

View file

@ -49,7 +49,7 @@ private bool ChangeFileDate(MovieFile movieFile, Movie movie)
{
case FileDateType.Release:
{
var releaseDate = movie.PhysicalRelease ?? movie.DigitalRelease;
var releaseDate = movie.MovieMetadata.Value.PhysicalRelease ?? movie.MovieMetadata.Value.DigitalRelease;
if (releaseDate.HasValue == false)
{
@ -61,7 +61,7 @@ private bool ChangeFileDate(MovieFile movieFile, Movie movie)
case FileDateType.Cinemas:
{
var airDate = movie.InCinemas;
var airDate = movie.MovieMetadata.Value.InCinemas;
if (airDate.HasValue == false)
{

View file

@ -7,9 +7,9 @@ namespace NzbDrone.Core.MetadataSource
{
public interface IProvideMovieInfo
{
Movie GetMovieByImdbId(string imdbId);
Tuple<Movie, List<Credit>> GetMovieInfo(int tmdbId);
List<Movie> GetBulkMovieInfo(List<int> tmdbIds);
MovieMetadata GetMovieByImdbId(string imdbId);
Tuple<MovieMetadata, List<Credit>> GetMovieInfo(int tmdbId);
List<MovieMetadata> GetBulkMovieInfo(List<int> tmdbIds);
HashSet<int> GetChangedMovies(DateTime startTime);
}

View file

@ -7,6 +7,6 @@ public interface ISearchForNewMovie
{
List<Movie> SearchForNewMovie(string title);
Movie MapMovieToTmdbMovie(Movie movie);
MovieMetadata MapMovieToTmdbMovie(MovieMetadata movie);
}
}

View file

@ -38,5 +38,6 @@ public class MovieResource
public string OriginalLanguage { get; set; }
public string Homepage { get; set; }
public List<RecommendationResource> Recommendations { get; set; }
public float? Popularity { get; set; }
}
}

View file

@ -28,12 +28,14 @@ public class SkyHookProxy : IProvideMovieInfo, ISearchForNewMovie
private readonly IHttpRequestBuilderFactory _radarrMetadata;
private readonly IConfigService _configService;
private readonly IMovieService _movieService;
private readonly IMovieMetadataService _movieMetadataService;
private readonly IMovieTranslationService _movieTranslationService;
public SkyHookProxy(IHttpClient httpClient,
IRadarrCloudRequestBuilder requestBuilder,
IConfigService configService,
IMovieService movieService,
IMovieMetadataService movieMetadataService,
IMovieTranslationService movieTranslationService,
Logger logger)
{
@ -41,6 +43,7 @@ public SkyHookProxy(IHttpClient httpClient,
_radarrMetadata = requestBuilder.RadarrMetadata;
_configService = configService;
_movieService = movieService;
_movieMetadataService = movieMetadataService;
_movieTranslationService = movieTranslationService;
_logger = logger;
@ -65,7 +68,7 @@ public HashSet<int> GetChangedMovies(DateTime startTime)
return new HashSet<int>(response.Resource);
}
public Tuple<Movie, List<Credit>> GetMovieInfo(int tmdbId)
public Tuple<MovieMetadata, List<Credit>> GetMovieInfo(int tmdbId)
{
var httpRequest = _radarrMetadata.Create()
.SetSegment("route", "movie")
@ -95,10 +98,10 @@ public Tuple<Movie, List<Credit>> GetMovieInfo(int tmdbId)
var movie = MapMovie(httpResponse.Resource);
return new Tuple<Movie, List<Credit>>(movie, credits.ToList());
return new Tuple<MovieMetadata, List<Credit>>(movie, credits.ToList());
}
public List<Movie> GetBulkMovieInfo(List<int> tmdbIds)
public List<MovieMetadata> GetBulkMovieInfo(List<int> tmdbIds)
{
var httpRequest = _radarrMetadata.Create()
.SetSegment("route", "movie/bulk")
@ -123,7 +126,7 @@ public List<Movie> GetBulkMovieInfo(List<int> tmdbIds)
return movies;
}
public Movie GetMovieByImdbId(string imdbId)
public MovieMetadata GetMovieByImdbId(string imdbId)
{
imdbId = Parser.Parser.NormalizeImdbId(imdbId);
@ -159,18 +162,18 @@ public Movie GetMovieByImdbId(string imdbId)
return movie;
}
public Movie MapMovie(MovieResource resource)
public MovieMetadata MapMovie(MovieResource resource)
{
var movie = new Movie();
var movie = new MovieMetadata();
var altTitles = new List<AlternativeTitle>();
movie.TmdbId = resource.TmdbId;
movie.ImdbId = resource.ImdbId;
movie.Title = resource.Title;
movie.OriginalTitle = resource.OriginalTitle;
movie.TitleSlug = resource.TitleSlug;
movie.CleanTitle = resource.Title.CleanMovieTitle();
movie.SortTitle = Parser.Parser.NormalizeTitle(resource.Title);
movie.CleanOriginalTitle = resource.OriginalTitle.CleanMovieTitle();
movie.Overview = resource.Overview;
movie.AlternativeTitles.AddRange(resource.AlternativeTitles.Select(MapAlternativeTitle));
@ -192,18 +195,26 @@ public Movie MapMovie(MovieResource resource)
movie.SecondaryYear = resource.Premier?.Year;
}
movie.Images = resource.Images.Select(MapImage).ToList();
if (resource.Runtime != null)
{
movie.Runtime = resource.Runtime.Value;
}
if (resource.Popularity != null)
{
movie.Popularity = resource.Popularity.Value;
}
var certificationCountry = _configService.CertificationCountry.ToString();
movie.Certification = resource.Certifications.FirstOrDefault(m => m.Country == certificationCountry)?.Certification;
movie.Ratings = MapRatings(resource.MovieRatings) ?? new Ratings();
movie.TmdbId = resource.TmdbId;
movie.Genres = resource.Genres;
movie.Images = resource.Images.Select(MapImage).ToList();
//movie.Genres = resource.Genres;
movie.Recommendations = resource.Recommendations?.Select(r => r.TmdbId).ToList() ?? new List<int>();
//Workaround due to metadata change until cache cleans up
@ -266,7 +277,7 @@ private string StripTrailingTheFromTitle(string title)
return title;
}
public Movie MapMovieToTmdbMovie(Movie movie)
public MovieMetadata MapMovieToTmdbMovie(MovieMetadata movie)
{
try
{
@ -274,12 +285,14 @@ public Movie MapMovieToTmdbMovie(Movie movie)
if (movie.TmdbId > 0)
{
newMovie = _movieService.FindByTmdbId(movie.TmdbId);
newMovie = _movieMetadataService.FindByTmdbId(movie.TmdbId);
if (newMovie == null)
if (newMovie != null)
{
newMovie = GetMovieInfo(movie.TmdbId).Item1;
return newMovie;
}
newMovie = GetMovieInfo(movie.TmdbId).Item1;
}
else if (movie.ImdbId.IsNotNullOrWhiteSpace())
{
@ -293,7 +306,7 @@ public Movie MapMovieToTmdbMovie(Movie movie)
yearStr = $" {movie.Year}";
}
newMovie = SearchForNewMovie(movie.Title + yearStr).FirstOrDefault();
newMovie = SearchForNewMovie(movie.Title + yearStr).FirstOrDefault().MovieMetadata;
}
if (newMovie == null)
@ -302,14 +315,6 @@ public Movie MapMovieToTmdbMovie(Movie movie)
return null;
}
newMovie.Path = movie.Path;
newMovie.RootFolderPath = movie.RootFolderPath;
newMovie.ProfileId = movie.ProfileId;
newMovie.Monitored = movie.Monitored;
newMovie.MovieFile = movie.MovieFile;
newMovie.MinimumAvailability = movie.MinimumAvailability;
newMovie.Tags = movie.Tags;
return newMovie;
}
catch (Exception ex)
@ -347,7 +352,7 @@ public List<Movie> SearchForNewMovie(string title)
try
{
var movieLookup = GetMovieByImdbId(parserResult.ImdbId);
return movieLookup == null ? new List<Movie>() : new List<Movie> { _movieService.FindByTmdbId(movieLookup.TmdbId) ?? movieLookup };
return movieLookup == null ? new List<Movie>() : new List<Movie> { _movieService.FindByTmdbId(movieLookup.TmdbId) ?? new Movie { MovieMetadata = movieLookup } };
}
catch (Exception)
{
@ -360,7 +365,7 @@ public List<Movie> SearchForNewMovie(string title)
try
{
var movieLookup = GetMovieInfo(parserResult.TmdbId).Item1;
return movieLookup == null ? new List<Movie>() : new List<Movie> { _movieService.FindByTmdbId(movieLookup.TmdbId) ?? movieLookup };
return movieLookup == null ? new List<Movie>() : new List<Movie> { _movieService.FindByTmdbId(movieLookup.TmdbId) ?? new Movie { MovieMetadata = movieLookup } };
}
catch (Exception)
{
@ -385,7 +390,7 @@ public List<Movie> SearchForNewMovie(string title)
try
{
var movieLookup = GetMovieByImdbId(imdbid);
return movieLookup == null ? new List<Movie>() : new List<Movie> { _movieService.FindByTmdbId(movieLookup.TmdbId) ?? movieLookup };
return movieLookup == null ? new List<Movie>() : new List<Movie> { _movieService.FindByTmdbId(movieLookup.TmdbId) ?? new Movie { MovieMetadata = movieLookup } };
}
catch (MovieNotFoundException)
{
@ -407,7 +412,7 @@ public List<Movie> SearchForNewMovie(string title)
try
{
var movieLookup = GetMovieInfo(tmdbid).Item1;
return movieLookup == null ? new List<Movie>() : new List<Movie> { _movieService.FindByTmdbId(movieLookup.TmdbId) ?? movieLookup };
return movieLookup == null ? new List<Movie>() : new List<Movie> { _movieService.FindByTmdbId(movieLookup.TmdbId) ?? new Movie { MovieMetadata = movieLookup } };
}
catch (MovieNotFoundException)
{
@ -455,11 +460,11 @@ private Movie MapSearchResult(MovieResource result)
if (movie == null)
{
movie = MapMovie(result);
movie = new Movie { MovieMetadata = MapMovie(result) };
}
else
{
movie.Translations = _movieTranslationService.GetAllTranslationsForMovie(movie.Id);
movie.MovieMetadata.Value.Translations = _movieTranslationService.GetAllTranslationsForMovie(movie.Id);
}
return movie;

View file

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using FluentValidation;
using FluentValidation.Results;
using NLog;
@ -9,6 +10,7 @@
using NzbDrone.Core.MetadataSource;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Parser;
using NzbDrone.Core.RootFolders;
namespace NzbDrone.Core.Movies
{
@ -21,18 +23,21 @@ public interface IAddMovieService
public class AddMovieService : IAddMovieService
{
private readonly IMovieService _movieService;
private readonly IMovieMetadataService _movieMetadataService;
private readonly IProvideMovieInfo _movieInfo;
private readonly IBuildFileNames _fileNameBuilder;
private readonly IAddMovieValidator _addMovieValidator;
private readonly Logger _logger;
public AddMovieService(IMovieService movieService,
IMovieMetadataService movieMetadataService,
IProvideMovieInfo movieInfo,
IBuildFileNames fileNameBuilder,
IAddMovieValidator addMovieValidator,
Logger logger)
{
_movieService = movieService;
_movieMetadataService = movieMetadataService;
_movieInfo = movieInfo;
_fileNameBuilder = fileNameBuilder;
_addMovieValidator = addMovieValidator;
@ -47,6 +52,10 @@ public Movie AddMovie(Movie newMovie)
newMovie = SetPropertiesAndValidate(newMovie);
_logger.Info("Adding Movie {0} Path: [{1}]", newMovie, newMovie.Path);
_movieMetadataService.Upsert(newMovie.MovieMetadata.Value);
newMovie.MovieMetadataId = newMovie.MovieMetadata.Value.Id;
_movieService.AddMovie(newMovie);
return newMovie;
@ -65,6 +74,7 @@ public List<Movie> AddMovies(List<Movie> newMovies, bool ignoreErrors = false)
{
var movie = AddSkyhookData(m);
movie = SetPropertiesAndValidate(movie);
movie.Added = added;
moviesToAdd.Add(movie);
}
@ -79,16 +89,19 @@ public List<Movie> AddMovies(List<Movie> newMovies, bool ignoreErrors = false)
}
}
_movieMetadataService.UpsertMany(moviesToAdd.Select(x => x.MovieMetadata.Value).ToList());
moviesToAdd.ForEach(x => x.MovieMetadataId = x.MovieMetadata.Value.Id);
return _movieService.AddMovies(moviesToAdd);
}
private Movie AddSkyhookData(Movie newMovie)
{
Movie movie;
var movie = new Movie();
try
{
movie = _movieInfo.GetMovieInfo(newMovie.TmdbId).Item1;
movie.MovieMetadata = _movieInfo.GetMovieInfo(newMovie.TmdbId).Item1;
}
catch (MovieNotFoundException)
{
@ -113,8 +126,8 @@ private Movie SetPropertiesAndValidate(Movie newMovie)
newMovie.Path = Path.Combine(newMovie.RootFolderPath, folderName);
}
newMovie.CleanTitle = newMovie.Title.CleanMovieTitle();
newMovie.SortTitle = MovieTitleNormalizer.Normalize(newMovie.Title, newMovie.TmdbId);
newMovie.MovieMetadata.Value.CleanTitle = newMovie.Title.CleanMovieTitle();
newMovie.MovieMetadata.Value.SortTitle = MovieTitleNormalizer.Normalize(newMovie.Title, newMovie.TmdbId);
newMovie.Added = DateTime.UtcNow;
var validationResult = _addMovieValidator.Validate(newMovie);

View file

@ -14,8 +14,7 @@ public class AddMovieValidator : AbstractValidator<Movie>, IAddMovieValidator
public AddMovieValidator(RootFolderValidator rootFolderValidator,
RecycleBinValidator recycleBinValidator,
MoviePathValidator moviePathValidator,
MovieAncestorValidator movieAncestorValidator,
MovieTitleSlugValidator movieTitleSlugValidator)
MovieAncestorValidator movieAncestorValidator)
{
RuleFor(c => c.Path).Cascade(CascadeMode.StopOnFirstFailure)
.IsValidPath()
@ -23,8 +22,6 @@ public AddMovieValidator(RootFolderValidator rootFolderValidator,
.SetValidator(recycleBinValidator)
.SetValidator(moviePathValidator)
.SetValidator(movieAncestorValidator);
RuleFor(c => c.TitleSlug).SetValidator(movieTitleSlugValidator);
}
}
}

View file

@ -7,7 +7,7 @@ namespace NzbDrone.Core.Movies.AlternativeTitles
public class AlternativeTitle : ModelBase
{
public SourceType SourceType { get; set; }
public int MovieId { get; set; }
public int MovieMetadataId { get; set; }
public string Title { get; set; }
public string CleanTitle { get; set; }
public int SourceId { get; set; }

View file

@ -9,7 +9,7 @@ public interface IAlternativeTitleRepository : IBasicRepository<AlternativeTitle
{
AlternativeTitle FindBySourceId(int sourceId);
List<AlternativeTitle> FindBySourceIds(List<int> sourceIds);
List<AlternativeTitle> FindByMovieId(int movieId);
List<AlternativeTitle> FindByMovieMetadataId(int movieId);
void DeleteForMovies(List<int> movieIds);
}
@ -30,14 +30,14 @@ public List<AlternativeTitle> FindBySourceIds(List<int> sourceIds)
return Query(x => sourceIds.Contains(x.SourceId));
}
public List<AlternativeTitle> FindByMovieId(int movieId)
public List<AlternativeTitle> FindByMovieMetadataId(int movieId)
{
return Query(x => x.MovieId == movieId);
return Query(x => x.MovieMetadataId == movieId);
}
public void DeleteForMovies(List<int> movieIds)
{
Delete(x => movieIds.Contains(x.MovieId));
Delete(x => movieIds.Contains(x.MovieMetadataId));
}
}
}

View file

@ -11,11 +11,11 @@ namespace NzbDrone.Core.Movies.AlternativeTitles
public interface IAlternativeTitleService
{
List<AlternativeTitle> GetAllTitlesForMovie(int movieId);
AlternativeTitle AddAltTitle(AlternativeTitle title, Movie movie);
List<AlternativeTitle> AddAltTitles(List<AlternativeTitle> titles, Movie movie);
AlternativeTitle AddAltTitle(AlternativeTitle title, MovieMetadata movie);
List<AlternativeTitle> AddAltTitles(List<AlternativeTitle> titles, MovieMetadata movie);
AlternativeTitle GetById(int id);
List<AlternativeTitle> GetAllTitles();
List<AlternativeTitle> UpdateTitles(List<AlternativeTitle> titles, Movie movie);
List<AlternativeTitle> UpdateTitles(List<AlternativeTitle> titles, MovieMetadata movie);
}
public class AlternativeTitleService : IAlternativeTitleService, IHandleAsync<MoviesDeletedEvent>
@ -38,18 +38,18 @@ public AlternativeTitleService(IAlternativeTitleRepository titleRepo,
public List<AlternativeTitle> GetAllTitlesForMovie(int movieId)
{
return _titleRepo.FindByMovieId(movieId).ToList();
return _titleRepo.FindByMovieMetadataId(movieId).ToList();
}
public AlternativeTitle AddAltTitle(AlternativeTitle title, Movie movie)
public AlternativeTitle AddAltTitle(AlternativeTitle title, MovieMetadata movie)
{
title.MovieId = movie.Id;
title.MovieMetadataId = movie.Id;
return _titleRepo.Insert(title);
}
public List<AlternativeTitle> AddAltTitles(List<AlternativeTitle> titles, Movie movie)
public List<AlternativeTitle> AddAltTitles(List<AlternativeTitle> titles, MovieMetadata movie)
{
titles.ForEach(t => t.MovieId = movie.Id);
titles.ForEach(t => t.MovieMetadataId = movie.Id);
_titleRepo.InsertMany(titles);
return titles;
}
@ -69,12 +69,12 @@ public void RemoveTitle(AlternativeTitle title)
_titleRepo.Delete(title);
}
public List<AlternativeTitle> UpdateTitles(List<AlternativeTitle> titles, Movie movie)
public List<AlternativeTitle> UpdateTitles(List<AlternativeTitle> titles, MovieMetadata movie)
{
int movieId = movie.Id;
// First update the movie ids so we can correlate them later.
titles.ForEach(t => t.MovieId = movieId);
titles.ForEach(t => t.MovieMetadataId = movieId);
// Then make sure none of them are the same as the main title.
titles = titles.Where(t => t.CleanTitle != movie.CleanTitle).ToList();
@ -83,10 +83,10 @@ public List<AlternativeTitle> UpdateTitles(List<AlternativeTitle> titles, Movie
titles = titles.DistinctBy(t => t.CleanTitle).ToList();
// Make sure we are not adding titles that exist for other movies (until language PR goes in)
titles = titles.Where(t => !_titleRepo.All().Any(e => e.CleanTitle == t.CleanTitle && e.MovieId != t.MovieId)).ToList();
titles = titles.Where(t => !_titleRepo.All().Any(e => e.CleanTitle == t.CleanTitle && e.MovieMetadataId != t.MovieMetadataId)).ToList();
// Now find titles to delete, update and insert.
var existingTitles = _titleRepo.FindByMovieId(movieId);
var existingTitles = _titleRepo.FindByMovieMetadataId(movieId);
var insert = titles.Where(t => !existingTitles.Contains(t));
var update = existingTitles.Where(t => titles.Contains(t));
@ -101,7 +101,8 @@ public List<AlternativeTitle> UpdateTitles(List<AlternativeTitle> titles, Movie
public void HandleAsync(MoviesDeletedEvent message)
{
_titleRepo.DeleteForMovies(message.Movies.Select(m => m.Id).ToList());
// TODO hanlde metadata delete instead of movie delete
_titleRepo.DeleteForMovies(message.Movies.Select(m => m.MovieMetadataId).ToList());
}
}
}

View file

@ -13,7 +13,7 @@ public Credit()
public string Name { get; set; }
public string CreditTmdbId { get; set; }
public int PersonTmdbId { get; set; }
public int MovieId { get; set; }
public int MovieMetadataId { get; set; }
public List<MediaCover.MediaCover> Images { get; set; }
public string Department { get; set; }
public string Job { get; set; }

View file

@ -6,7 +6,7 @@ namespace NzbDrone.Core.Movies.Credits
{
public interface ICreditRepository : IBasicRepository<Credit>
{
List<Credit> FindByMovieId(int movieId);
List<Credit> FindByMovieMetadataId(int movieId);
void DeleteForMovies(List<int> movieIds);
}
@ -17,14 +17,14 @@ public CreditRepository(IMainDatabase database, IEventAggregator eventAggregator
{
}
public List<Credit> FindByMovieId(int movieId)
public List<Credit> FindByMovieMetadataId(int movieId)
{
return Query(x => x.MovieId == movieId);
return Query(x => x.MovieMetadataId == movieId);
}
public void DeleteForMovies(List<int> movieIds)
{
Delete(x => movieIds.Contains(x.MovieId));
Delete(x => movieIds.Contains(x.MovieMetadataId));
}
}
}

View file

@ -9,11 +9,11 @@ namespace NzbDrone.Core.Movies.Credits
public interface ICreditService
{
List<Credit> GetAllCreditsForMovie(int movieId);
Credit AddCredit(Credit credit, Movie movie);
List<Credit> AddCredits(List<Credit> credits, Movie movie);
Credit AddCredit(Credit credit, MovieMetadata movie);
List<Credit> AddCredits(List<Credit> credits, MovieMetadata movie);
Credit GetById(int id);
List<Credit> GetAllCredits();
List<Credit> UpdateCredits(List<Credit> credits, Movie movie);
List<Credit> UpdateCredits(List<Credit> credits, MovieMetadata movie);
}
public class CreditService : ICreditService, IHandleAsync<MoviesDeletedEvent>
@ -27,18 +27,18 @@ public CreditService(ICreditRepository creditRepo)
public List<Credit> GetAllCreditsForMovie(int movieId)
{
return _creditRepo.FindByMovieId(movieId).ToList();
return _creditRepo.FindByMovieMetadataId(movieId).ToList();
}
public Credit AddCredit(Credit credit, Movie movie)
public Credit AddCredit(Credit credit, MovieMetadata movie)
{
credit.MovieId = movie.Id;
credit.MovieMetadataId = movie.Id;
return _creditRepo.Insert(credit);
}
public List<Credit> AddCredits(List<Credit> credits, Movie movie)
public List<Credit> AddCredits(List<Credit> credits, MovieMetadata movie)
{
credits.ForEach(t => t.MovieId = movie.Id);
credits.ForEach(t => t.MovieMetadataId = movie.Id);
_creditRepo.InsertMany(credits);
return credits;
}
@ -58,15 +58,15 @@ public void RemoveTitle(Credit credit)
_creditRepo.Delete(credit);
}
public List<Credit> UpdateCredits(List<Credit> credits, Movie movie)
public List<Credit> UpdateCredits(List<Credit> credits, MovieMetadata movie)
{
int movieId = movie.Id;
// First update the movie ids so we can correlate them later.
credits.ForEach(t => t.MovieId = movieId);
credits.ForEach(t => t.MovieMetadataId = movieId);
// Now find credits to delete, update and insert.
var existingCredits = _creditRepo.FindByMovieId(movieId);
var existingCredits = _creditRepo.FindByMovieMetadataId(movieId);
// Should never have multiple credits with same credit_id, but check to ensure incase TMDB is on fritz
var dupeFreeCredits = credits.DistinctBy(m => m.CreditTmdbId).ToList();
@ -86,7 +86,8 @@ public List<Credit> UpdateCredits(List<Credit> credits, Movie movie)
public void HandleAsync(MoviesDeletedEvent message)
{
_creditRepo.DeleteForMovies(message.Movies.Select(m => m.Id).ToList());
// TODO handle metadata deletions and not movie deletions
_creditRepo.DeleteForMovies(message.Movies.Select(m => m.MovieMetadataId).ToList());
}
}
}

View file

@ -0,0 +1,41 @@
using System;
using Equ;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Movies
{
public abstract class Entity<T> : ModelBase, IEquatable<T>
where T : Entity<T>
{
private static readonly MemberwiseEqualityComparer<T> _comparer =
MemberwiseEqualityComparer<T>.ByProperties;
public virtual void UseDbFieldsFrom(T other)
{
Id = other.Id;
}
public virtual void UseMetadataFrom(T other)
{
}
public virtual void ApplyChanges(T other)
{
}
public bool Equals(T other)
{
return _comparer.Equals(this as T, other);
}
public override bool Equals(object obj)
{
return Equals(obj as T);
}
public override int GetHashCode()
{
return _comparer.GetHashCode(this as T);
}
}
}

View file

@ -2,10 +2,7 @@
using System.Collections.Generic;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Languages;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Movies.AlternativeTitles;
using NzbDrone.Core.Movies.Translations;
using NzbDrone.Core.Profiles;
namespace NzbDrone.Core.Movies
@ -14,79 +11,54 @@ public class Movie : ModelBase
{
public Movie()
{
Images = new List<MediaCover.MediaCover>();
Genres = new List<string>();
Tags = new HashSet<int>();
AlternativeTitles = new List<AlternativeTitle>();
Translations = new List<MovieTranslation>();
Recommendations = new List<int>();
OriginalLanguage = Language.English;
Ratings = new Ratings();
MovieMetadata = new MovieMetadata();
}
public int TmdbId { get; set; }
public string ImdbId { get; set; }
public string Title { get; set; }
public string CleanTitle { get; set; }
public string SortTitle { get; set; }
public MovieStatusType Status { get; set; }
public string Overview { get; set; }
public int MovieMetadataId { get; set; }
public bool Monitored { get; set; }
public MovieStatusType MinimumAvailability { get; set; }
public int ProfileId { get; set; }
public DateTime? LastInfoSync { get; set; }
public int Runtime { get; set; }
public List<MediaCover.MediaCover> Images { get; set; }
public string TitleSlug { get; set; }
public string Website { get; set; }
public string Path { get; set; }
public int Year { get; set; }
public Ratings Ratings { get; set; }
public List<string> Genres { get; set; }
public MovieCollection Collection { get; set; }
public LazyLoaded<MovieMetadata> MovieMetadata { get; set; }
public string Certification { get; set; }
public string RootFolderPath { get; set; }
public DateTime Added { get; set; }
public DateTime? InCinemas { get; set; }
public DateTime? PhysicalRelease { get; set; }
public DateTime? DigitalRelease { get; set; }
public Profile Profile { get; set; }
public HashSet<int> Tags { get; set; }
public AddMovieOptions AddOptions { get; set; }
public MovieFile MovieFile { get; set; }
public int MovieFileId { get; set; }
//Get Loaded via a Join Query
public List<AlternativeTitle> AlternativeTitles { get; set; }
public List<MovieTranslation> Translations { get; set; }
public int? SecondaryYear { get; set; }
public string YouTubeTrailerId { get; set; }
public string Studio { get; set; }
public string OriginalTitle { get; set; }
public Language OriginalLanguage { get; set; }
public List<int> Recommendations { get; set; }
public bool HasFile => MovieFileId > 0;
public bool IsRecentMovie
//compatibility properties
public string Title
{
get
{
if (PhysicalRelease.HasValue)
{
return PhysicalRelease.Value >= DateTime.UtcNow.AddDays(-21);
}
if (InCinemas.HasValue)
{
return InCinemas.Value >= DateTime.UtcNow.AddDays(-120);
}
return true;
}
get { return MovieMetadata.Value.Title; }
set { MovieMetadata.Value.Title = value; }
}
public bool HasFile => MovieFileId > 0;
public int TmdbId
{
get { return MovieMetadata.Value.TmdbId; }
set { MovieMetadata.Value.TmdbId = value; }
}
public string ImdbId
{
get { return MovieMetadata.Value.ImdbId; }
set { MovieMetadata.Value.ImdbId = value; }
}
public int Year
{
get { return MovieMetadata.Value.Year; }
set { MovieMetadata.Value.Year = value; }
}
public string FolderName()
{
@ -112,27 +84,27 @@ public bool IsAvailable(int delay = 0)
{
minimumAvailabilityDate = DateTime.MinValue;
}
else if (MinimumAvailability == MovieStatusType.InCinemas && InCinemas.HasValue)
else if (MinimumAvailability == MovieStatusType.InCinemas && MovieMetadata.Value.InCinemas.HasValue)
{
minimumAvailabilityDate = InCinemas.Value;
minimumAvailabilityDate = MovieMetadata.Value.InCinemas.Value;
}
else
{
if (PhysicalRelease.HasValue && DigitalRelease.HasValue)
if (MovieMetadata.Value.PhysicalRelease.HasValue && MovieMetadata.Value.DigitalRelease.HasValue)
{
minimumAvailabilityDate = new DateTime(Math.Min(PhysicalRelease.Value.Ticks, DigitalRelease.Value.Ticks));
minimumAvailabilityDate = new DateTime(Math.Min(MovieMetadata.Value.PhysicalRelease.Value.Ticks, MovieMetadata.Value.DigitalRelease.Value.Ticks));
}
else if (PhysicalRelease.HasValue)
else if (MovieMetadata.Value.PhysicalRelease.HasValue)
{
minimumAvailabilityDate = PhysicalRelease.Value;
minimumAvailabilityDate = MovieMetadata.Value.PhysicalRelease.Value;
}
else if (DigitalRelease.HasValue)
else if (MovieMetadata.Value.DigitalRelease.HasValue)
{
minimumAvailabilityDate = DigitalRelease.Value;
minimumAvailabilityDate = MovieMetadata.Value.DigitalRelease.Value;
}
else
{
minimumAvailabilityDate = InCinemas.HasValue ? InCinemas.Value.AddDays(90) : DateTime.MaxValue;
minimumAvailabilityDate = MovieMetadata.Value.InCinemas.HasValue ? MovieMetadata.Value.InCinemas.Value.AddDays(90) : DateTime.MaxValue;
}
}
@ -144,20 +116,13 @@ public bool IsAvailable(int delay = 0)
return DateTime.Now >= minimumAvailabilityDate.AddDays((double)delay);
}
public DateTime PhysicalReleaseDate()
{
return PhysicalRelease ?? (InCinemas?.AddDays(90) ?? DateTime.MaxValue);
}
public override string ToString()
{
return string.Format("[{1} ({2})][{0}, {3}]", ImdbId, Title.NullSafe(), Year.NullSafe(), TmdbId);
return string.Format("[{1} ({2})][{0}, {3}]", MovieMetadata.Value.ImdbId, MovieMetadata.Value.Title.NullSafe(), MovieMetadata.Value.Year.NullSafe(), MovieMetadata.Value.TmdbId);
}
public void ApplyChanges(Movie otherMovie)
{
TmdbId = otherMovie.TmdbId;
Path = otherMovie.Path;
ProfileId = otherMovie.ProfileId;

View file

@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using Equ;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Movies.AlternativeTitles;
using NzbDrone.Core.Movies.Translations;
namespace NzbDrone.Core.Movies
{
public class MovieMetadata : Entity<MovieMetadata>
{
public MovieMetadata()
{
AlternativeTitles = new List<AlternativeTitle>();
Translations = new List<MovieTranslation>();
Images = new List<MediaCover.MediaCover>();
Genres = new List<string>();
OriginalLanguage = Language.English;
Recommendations = new List<int>();
Ratings = new Ratings();
}
public int TmdbId { get; set; }
public List<MediaCover.MediaCover> Images { get; set; }
public List<string> Genres { get; set; }
public DateTime? InCinemas { get; set; }
public DateTime? PhysicalRelease { get; set; }
public DateTime? DigitalRelease { get; set; }
public string Certification { get; set; }
public int Year { get; set; }
public Ratings Ratings { get; set; }
public MovieCollection Collection { get; set; }
public DateTime? LastInfoSync { get; set; }
public int Runtime { get; set; }
public string Website { get; set; }
public string ImdbId { get; set; }
public string Title { get; set; }
public string CleanTitle { get; set; }
public string SortTitle { get; set; }
public MovieStatusType Status { get; set; }
public string Overview { get; set; }
//Get Loaded via a Join Query
public List<AlternativeTitle> AlternativeTitles { get; set; }
public List<MovieTranslation> Translations { get; set; }
public int? SecondaryYear { get; set; }
public string YouTubeTrailerId { get; set; }
public string Studio { get; set; }
public string OriginalTitle { get; set; }
public string CleanOriginalTitle { get; set; }
public Language OriginalLanguage { get; set; }
public List<int> Recommendations { get; set; }
public float Popularity { get; set; }
[MemberwiseEqualityIgnore]
public bool IsRecentMovie
{
get
{
if (PhysicalRelease.HasValue)
{
return PhysicalRelease.Value >= DateTime.UtcNow.AddDays(-21);
}
if (InCinemas.HasValue)
{
return InCinemas.Value >= DateTime.UtcNow.AddDays(-120);
}
return true;
}
}
public DateTime PhysicalReleaseDate()
{
return PhysicalRelease ?? (InCinemas?.AddDays(90) ?? DateTime.MaxValue);
}
}
}

View file

@ -0,0 +1,72 @@
using System.Collections.Generic;
using System.Linq;
using NLog;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Movies
{
public interface IMovieMetadataRepository : IBasicRepository<MovieMetadata>
{
MovieMetadata FindByTmdbId(int tmdbId);
List<MovieMetadata> FindById(List<int> tmdbIds);
bool UpsertMany(List<MovieMetadata> data);
}
public class MovieMetadataRepository : BasicRepository<MovieMetadata>, IMovieMetadataRepository
{
private readonly Logger _logger;
public MovieMetadataRepository(IMainDatabase database, IEventAggregator eventAggregator, Logger logger)
: base(database, eventAggregator)
{
_logger = logger;
}
public MovieMetadata FindByTmdbId(int tmdbid)
{
return Query(x => x.TmdbId == tmdbid).FirstOrDefault();
}
public List<MovieMetadata> FindById(List<int> tmdbIds)
{
return Query(x => Enumerable.Contains(tmdbIds, x.TmdbId));
}
public bool UpsertMany(List<MovieMetadata> data)
{
var existingMetadata = FindById(data.Select(x => x.TmdbId).ToList());
var updateMetadataList = new List<MovieMetadata>();
var addMetadataList = new List<MovieMetadata>();
int upToDateMetadataCount = 0;
foreach (var meta in data)
{
var existing = existingMetadata.SingleOrDefault(x => x.TmdbId == meta.TmdbId);
if (existing != null)
{
meta.UseDbFieldsFrom(existing);
if (!meta.Equals(existing))
{
updateMetadataList.Add(meta);
}
else
{
upToDateMetadataCount++;
}
}
else
{
addMetadataList.Add(meta);
}
}
UpdateMany(updateMetadataList);
InsertMany(addMetadataList);
_logger.Debug($"{upToDateMetadataCount} movie metadata up to date; Updating {updateMetadataList.Count}, Adding {addMetadataList.Count} movie metadata entries.");
return updateMetadataList.Count > 0 || addMetadataList.Count > 0;
}
}
}

View file

@ -0,0 +1,42 @@
using System.Collections.Generic;
namespace NzbDrone.Core.Movies
{
public interface IMovieMetadataService
{
MovieMetadata Get(int id);
MovieMetadata FindByTmdbId(int tmdbid);
bool Upsert(MovieMetadata movie);
bool UpsertMany(List<MovieMetadata> movies);
}
public class MovieMetadataService : IMovieMetadataService
{
private readonly IMovieMetadataRepository _movieMetadataRepository;
public MovieMetadataService(IMovieMetadataRepository movieMetadataRepository)
{
_movieMetadataRepository = movieMetadataRepository;
}
public MovieMetadata FindByTmdbId(int tmdbid)
{
return _movieMetadataRepository.FindByTmdbId(tmdbid);
}
public MovieMetadata Get(int id)
{
return _movieMetadataRepository.Get(id);
}
public bool Upsert(MovieMetadata movie)
{
return _movieMetadataRepository.UpsertMany(new List<MovieMetadata> { movie });
}
public bool UpsertMany(List<MovieMetadata> movies)
{
return _movieMetadataRepository.UpsertMany(movies);
}
}
}

View file

@ -20,7 +20,6 @@ public interface IMovieRepository : IBasicRepository<Movie>
Movie FindByImdbId(string imdbid);
Movie FindByTmdbId(int tmdbid);
List<Movie> FindByTmdbId(List<int> tmdbids);
Movie FindByTitleSlug(string slug);
List<Movie> MoviesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored);
PagingSpec<Movie> MoviesWithoutFiles(PagingSpec<Movie> pagingSpec);
List<Movie> GetMoviesByFileId(int fileId);
@ -28,7 +27,6 @@ public interface IMovieRepository : IBasicRepository<Movie>
PagingSpec<Movie> MoviesWhereCutoffUnmet(PagingSpec<Movie> pagingSpec, List<QualitiesBelowCutoff> qualitiesBelowCutoff);
Movie FindByPath(string path);
Dictionary<int, string> AllMoviePaths();
Dictionary<int, string> AllMovieTitleSlugs();
List<int> AllMovieTmdbIds();
Dictionary<int, List<int>> AllMovieTags();
List<int> GetRecommendations();
@ -51,10 +49,11 @@ public MovieRepository(IMainDatabase database,
protected override SqlBuilder Builder() => new SqlBuilder(_database.DatabaseType)
.Join<Movie, Profile>((m, p) => m.ProfileId == p.Id)
.LeftJoin<Movie, AlternativeTitle>((m, t) => m.Id == t.MovieId)
.LeftJoin<Movie, MovieFile>((m, f) => m.Id == f.MovieId);
.Join<Movie, MovieMetadata>((m, p) => m.MovieMetadataId == p.Id)
.LeftJoin<Movie, MovieFile>((m, f) => m.Id == f.MovieId)
.LeftJoin<MovieMetadata, AlternativeTitle>((mm, t) => mm.Id == t.MovieMetadataId);
private Movie Map(Dictionary<int, Movie> dict, Movie movie, Profile profile, AlternativeTitle altTitle, MovieFile movieFile, MovieTranslation translation = null)
private Movie Map(Dictionary<int, Movie> dict, Movie movie, Profile profile, MovieFile movieFile, AlternativeTitle altTitle = null, MovieTranslation translation = null)
{
Movie movieEntry;
@ -68,12 +67,12 @@ private Movie Map(Dictionary<int, Movie> dict, Movie movie, Profile profile, Alt
if (altTitle != null)
{
movieEntry.AlternativeTitles.Add(altTitle);
movieEntry.MovieMetadata.Value.AlternativeTitles.Add(altTitle);
}
if (translation != null)
{
movieEntry.Translations.Add(translation);
movieEntry.MovieMetadata.Value.Translations.Add(translation);
}
return movieEntry;
@ -83,9 +82,9 @@ protected override List<Movie> Query(SqlBuilder builder)
{
var movieDictionary = new Dictionary<int, Movie>();
_ = _database.QueryJoined<Movie, Profile, AlternativeTitle, MovieFile>(
_ = _database.QueryJoined<Movie, Profile, MovieFile, AlternativeTitle>(
builder,
(movie, profile, altTitle, file) => Map(movieDictionary, movie, profile, altTitle, file));
(movie, profile, file, altTitle) => Map(movieDictionary, movie, profile, file, altTitle));
return movieDictionary.Values.ToList();
}
@ -95,23 +94,25 @@ public override IEnumerable<Movie> All()
// the skips the join on profile and alternative title and populates manually
// to avoid repeatedly deserializing the same profile / movie
var builder = new SqlBuilder(_database.DatabaseType)
.LeftJoin<Movie, MovieFile>((m, f) => m.MovieFileId == f.Id);
.LeftJoin<Movie, MovieFile>((m, f) => m.MovieFileId == f.Id)
.LeftJoin<Movie, MovieMetadata>((m, f) => m.MovieMetadataId == f.Id);
var profiles = _profileRepository.All().ToDictionary(x => x.Id);
var titles = _alternativeTitleRepository.All()
.GroupBy(x => x.MovieId)
.GroupBy(x => x.MovieMetadataId)
.ToDictionary(x => x.Key, y => y.ToList());
return _database.QueryJoined<Movie, MovieFile>(
return _database.QueryJoined<Movie, MovieFile, MovieMetadata>(
builder,
(movie, file) =>
(movie, file, metadata) =>
{
movie.MovieFile = file;
movie.MovieMetadata = metadata;
movie.Profile = profiles[movie.ProfileId];
if (titles.TryGetValue(movie.Id, out var altTitles))
if (titles.TryGetValue(movie.MovieMetadataId, out var altTitles))
{
movie.AlternativeTitles = altTitles;
movie.MovieMetadata.Value.AlternativeTitles = altTitles;
}
return movie;
@ -142,30 +143,15 @@ private List<Movie> FindByMovieTitles(List<string> titles)
{
var movieDictionary = new Dictionary<int, Movie>();
SqlBuilder builder;
if (_database.DatabaseType == DatabaseType.PostgreSQL)
{
builder = new SqlBuilder(_database.DatabaseType)
.LeftJoin<Movie, AlternativeTitle>((m, t) => m.Id == t.MovieId)
.LeftJoin<Movie, MovieFile>((m, f) => m.Id == f.MovieId)
.LeftJoin<Movie, MovieTranslation>((m, tr) => m.Id == tr.MovieId)
var builder = new SqlBuilder(_database.DatabaseType)
.Join<Movie, Profile>((m, p) => m.ProfileId == p.Id)
.WherePostgres<Movie>(x => titles.Contains(x.CleanTitle));
}
else
{
builder = new SqlBuilder(_database.DatabaseType)
.LeftJoin<Movie, AlternativeTitle>((m, t) => m.Id == t.MovieId)
.Join<Movie, MovieMetadata>((m, p) => m.MovieMetadataId == p.Id)
.LeftJoin<Movie, MovieFile>((m, f) => m.Id == f.MovieId)
.LeftJoin<Movie, MovieTranslation>((m, tr) => m.Id == tr.MovieId)
.Join<Movie, Profile>((m, p) => m.ProfileId == p.Id)
.Where<Movie>(x => titles.Contains(x.CleanTitle));
}
.Where<MovieMetadata>(x => titles.Contains(x.CleanTitle) || titles.Contains(x.CleanOriginalTitle));
_ = _database.QueryJoined<Movie, Profile, AlternativeTitle, MovieFile, MovieTranslation>(
_ = _database.QueryJoined<Movie, Profile, MovieFile>(
builder,
(movie, profile, altTitle, file, trans) => Map(movieDictionary, movie, profile, altTitle, file, trans));
(movie, profile, file) => Map(movieDictionary, movie, profile, file));
return movieDictionary.Values.ToList();
}
@ -174,32 +160,18 @@ private List<Movie> FindByAltTitles(List<string> titles)
{
var movieDictionary = new Dictionary<int, Movie>();
SqlBuilder builder;
var builder = new SqlBuilder(_database.DatabaseType)
.Join<AlternativeTitle, MovieMetadata>((t, mm) => t.MovieMetadataId == mm.Id)
.Join<MovieMetadata, Movie>((mm, m) => mm.Id == m.MovieMetadataId)
.Join<Movie, Profile>((m, p) => m.ProfileId == p.Id)
.LeftJoin<Movie, MovieFile>((m, f) => m.Id == f.MovieId)
.Where<AlternativeTitle>(x => titles.Contains(x.CleanTitle));
if (_database.DatabaseType == DatabaseType.PostgreSQL)
{
builder = new SqlBuilder(_database.DatabaseType)
.LeftJoin<Movie, Profile>((m, p) => m.ProfileId == p.Id)
.LeftJoin<Movie, MovieFile>((m, f) => m.Id == f.MovieId)
.LeftJoin<Movie, MovieTranslation>((m, tr) => m.Id == tr.MovieId)
.Join<AlternativeTitle, Movie>((t, m) => t.MovieId == m.Id)
.WherePostgres<AlternativeTitle>(x => titles.Contains(x.CleanTitle));
}
else
{
builder = new SqlBuilder(_database.DatabaseType)
.LeftJoin<AlternativeTitle, Movie>((t, m) => t.MovieId == m.Id)
.LeftJoin<Movie, MovieFile>((m, f) => m.Id == f.MovieId)
.LeftJoin<Movie, MovieTranslation>((m, tr) => m.Id == tr.MovieId)
.Join<Movie, Profile>((m, p) => m.ProfileId == p.Id)
.Where<AlternativeTitle>(x => titles.Contains(x.CleanTitle));
}
_ = _database.QueryJoined<AlternativeTitle, Profile, Movie, MovieFile, MovieTranslation>(
_ = _database.QueryJoined<AlternativeTitle, Profile, Movie, MovieFile>(
builder,
(altTitle, profile, movie, file, trans) =>
(altTitle, profile, movie, file) =>
{
_ = Map(movieDictionary, movie, profile, altTitle, file, trans);
_ = Map(movieDictionary, movie, profile, file, altTitle);
return null;
});
@ -210,32 +182,18 @@ private List<Movie> FindByTransTitles(List<string> titles)
{
var movieDictionary = new Dictionary<int, Movie>();
SqlBuilder builder;
if (_database.DatabaseType == DatabaseType.PostgreSQL)
{
builder = new SqlBuilder(_database.DatabaseType)
.LeftJoin<Movie, Profile>((m, p) => m.ProfileId == p.Id)
.LeftJoin<Movie, AlternativeTitle>((m, t) => m.Id == t.MovieId)
.LeftJoin<Movie, MovieFile>((m, f) => m.Id == f.MovieId)
.Join<MovieTranslation, Movie>((tr, m) => tr.MovieId == m.Id)
.WherePostgres<MovieTranslation>(x => titles.Contains(x.CleanTitle));
}
else
{
builder = new SqlBuilder(_database.DatabaseType)
.LeftJoin<MovieTranslation, Movie>((tr, m) => tr.MovieId == m.Id)
.LeftJoin<Movie, AlternativeTitle>((m, t) => m.Id == t.MovieId)
.LeftJoin<Movie, MovieFile>((m, f) => m.Id == f.MovieId)
var builder = new SqlBuilder(_database.DatabaseType)
.Join<MovieTranslation, MovieMetadata>((t, mm) => t.MovieMetadataId == mm.Id)
.Join<MovieMetadata, Movie>((mm, m) => mm.Id == m.MovieMetadataId)
.Join<Movie, Profile>((m, p) => m.ProfileId == p.Id)
.LeftJoin<Movie, MovieFile>((m, f) => m.Id == f.MovieId)
.Where<MovieTranslation>(x => titles.Contains(x.CleanTitle));
}
_ = _database.QueryJoined<MovieTranslation, Profile, Movie, MovieFile, AlternativeTitle>(
_ = _database.QueryJoined<MovieTranslation, Profile, Movie, MovieFile>(
builder,
(trans, profile, movie, file, altTitle) =>
(trans, profile, movie, file) =>
{
_ = Map(movieDictionary, movie, profile, altTitle, file, trans);
_ = Map(movieDictionary, movie, profile, file, null, trans);
return null;
});
@ -245,12 +203,12 @@ private List<Movie> FindByTransTitles(List<string> titles)
public Movie FindByImdbId(string imdbid)
{
var imdbIdWithPrefix = Parser.Parser.NormalizeImdbId(imdbid);
return imdbIdWithPrefix == null ? null : Query(x => x.ImdbId == imdbIdWithPrefix).FirstOrDefault();
return imdbIdWithPrefix == null ? null : Query(x => x.MovieMetadata.Value.ImdbId == imdbIdWithPrefix).FirstOrDefault();
}
public Movie FindByTmdbId(int tmdbid)
{
return Query(x => x.TmdbId == tmdbid).FirstOrDefault();
return Query(x => x.MovieMetadata.Value.TmdbId == tmdbid).FirstOrDefault();
}
public List<Movie> FindByTmdbId(List<int> tmdbids)
@ -268,18 +226,13 @@ public void SetFileId(int fileId, int movieId)
SetFields(new Movie { Id = movieId, MovieFileId = fileId }, movie => movie.MovieFileId);
}
public Movie FindByTitleSlug(string slug)
{
return Query(x => x.TitleSlug == slug).FirstOrDefault();
}
public List<Movie> MoviesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored)
{
var builder = Builder()
.Where<Movie>(m =>
(m.InCinemas >= start && m.InCinemas <= end) ||
(m.PhysicalRelease >= start && m.PhysicalRelease <= end) ||
(m.DigitalRelease >= start && m.DigitalRelease <= end));
(m.MovieMetadata.Value.InCinemas >= start && m.MovieMetadata.Value.InCinemas <= end) ||
(m.MovieMetadata.Value.PhysicalRelease >= start && m.MovieMetadata.Value.PhysicalRelease <= end) ||
(m.MovieMetadata.Value.DigitalRelease >= start && m.MovieMetadata.Value.DigitalRelease <= end));
if (!includeUnmonitored)
{
@ -341,20 +294,11 @@ public Dictionary<int, string> AllMoviePaths()
}
}
public Dictionary<int, string> AllMovieTitleSlugs()
{
using (var conn = _database.OpenConnection())
{
var strSql = "SELECT \"Id\" AS \"Key\", \"TitleSlug\" AS \"Value\" FROM \"Movies\"";
return conn.Query<KeyValuePair<int, string>>(strSql).ToDictionary(x => x.Key, x => x.Value);
}
}
public List<int> AllMovieTmdbIds()
{
using (var conn = _database.OpenConnection())
{
return conn.Query<int>("SELECT \"TmdbId\" FROM \"Movies\"").ToList();
return conn.Query<int>("SELECT \"TmdbId\" FROM \"MovieMetadata\" JOIN \"Movies\" ON (\"Movies\".\"MovieMetadataId\" = \"MovieMetadata\".\"Id\")").ToList();
}
}
@ -383,14 +327,14 @@ public List<int> GetRecommendations()
recommendations = conn.Query<int>(@"SELECT DISTINCT ""Rec"" FROM (
SELECT DISTINCT ""Rec"" FROM
(
SELECT DISTINCT CAST(""value"" AS INT) AS ""Rec"" FROM ""Movies"", json_array_elements_text((""Movies"".""Recommendations"")::json)
WHERE CAST(""value"" AS INT) NOT IN (SELECT ""TmdbId"" FROM ""Movies"" union SELECT ""TmdbId"" from ""ImportExclusions"" as sub1) LIMIT 10
SELECT DISTINCT CAST(""value"" AS INT) AS ""Rec"" FROM ""MovieMetadata"", json_array_elements_text((""MovieMetadata"".""Recommendations"")::json)
WHERE CAST(""value"" AS INT) NOT IN (SELECT ""TmdbId"" FROM ""MovieMetadata"" union SELECT ""TmdbId"" from ""ImportExclusions"" as sub1) LIMIT 10
) as sub2
UNION
SELECT ""Rec"" FROM
(
SELECT CAST(""value"" AS INT) AS ""Rec"" FROM ""Movies"", json_array_elements_text((""Movies"".""Recommendations"")::json)
WHERE CAST(""value"" AS INT) NOT IN (SELECT ""TmdbId"" FROM ""Movies"" union SELECT ""TmdbId"" from ""ImportExclusions"" as sub2)
SELECT CAST(""value"" AS INT) AS ""Rec"" FROM ""MovieMetadata"", json_array_elements_text((""MovieMetadata"".""Recommendations"")::json)
WHERE CAST(""value"" AS INT) NOT IN (SELECT ""TmdbId"" FROM ""MovieMetadata"" union SELECT ""TmdbId"" from ""ImportExclusions"" as sub2)
GROUP BY ""Rec"" ORDER BY count(*) DESC LIMIT 120
) as sub4
) as sub5
@ -401,14 +345,14 @@ WHERE CAST(""value"" AS INT) NOT IN (SELECT ""TmdbId"" FROM ""Movies"" union SEL
recommendations = conn.Query<int>(@"SELECT DISTINCT ""Rec"" FROM (
SELECT DISTINCT ""Rec"" FROM
(
SELECT DISTINCT CAST(""j"".""value"" AS INT) AS ""Rec"" FROM ""Movies"" CROSS JOIN json_each(""Movies"".""Recommendations"") AS ""j""
WHERE ""Rec"" NOT IN (SELECT ""TmdbId"" FROM ""Movies"" union SELECT ""TmdbId"" from ""ImportExclusions"") LIMIT 10
SELECT DISTINCT CAST(""j"".""value"" AS INT) AS ""Rec"" FROM ""MovieMetadata"" CROSS JOIN json_each(""MovieMetadata"".""Recommendations"") AS ""j""
WHERE ""Rec"" NOT IN (SELECT ""TmdbId"" FROM ""MovieMetadata"" union SELECT ""TmdbId"" from ""ImportExclusions"") LIMIT 10
)
UNION
SELECT ""Rec"" FROM
(
SELECT CAST(""j"".""value"" AS INT) AS ""Rec"" FROM ""Movies"" CROSS JOIN json_each(""Movies"".""Recommendations"") AS ""j""
WHERE ""Rec"" NOT IN (SELECT ""TmdbId"" FROM ""Movies"" union SELECT ""TmdbId"" from ""ImportExclusions"")
SELECT CAST(""j"".""value"" AS INT) AS ""Rec"" FROM ""MovieMetadata"" CROSS JOIN json_each(""MovieMetadata"".""Recommendations"") AS ""j""
WHERE ""Rec"" NOT IN (SELECT ""TmdbId"" FROM ""MovieMetadata"" union SELECT ""TmdbId"" from ""ImportExclusions"")
GROUP BY ""Rec"" ORDER BY count(*) DESC LIMIT 120
)
)

View file

@ -29,11 +29,9 @@ public interface IMovieService
Movie FindByTitle(string title, int year);
Movie FindByTitle(List<string> titles, int? year, List<string> otherTitles, List<Movie> candidates);
List<Movie> FindByTitleCandidates(List<string> titles, out List<string> otherTitles);
Movie FindByTitleSlug(string slug);
Movie FindByPath(string path);
Dictionary<int, string> AllMoviePaths();
List<int> AllMovieTmdbIds();
Dictionary<int, string> AllMovieTitleSlugs();
bool MovieExists(Movie movie);
List<Movie> GetMoviesByFileId(int fileId);
List<Movie> GetMoviesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored);
@ -120,18 +118,18 @@ public Movie FindByTitle(string title, int year)
public Movie FindByTitle(List<string> cleanTitles, int? year, List<string> otherTitles, List<Movie> candidates)
{
var result = candidates.Where(x => cleanTitles.Contains(x.CleanTitle)).FirstWithYear(year);
var result = candidates.Where(x => cleanTitles.Contains(x.MovieMetadata.Value.CleanTitle)).FirstWithYear(year);
if (result == null)
{
result =
candidates.Where(movie => otherTitles.Contains(movie.CleanTitle)).FirstWithYear(year);
candidates.Where(movie => otherTitles.Contains(movie.MovieMetadata.Value.CleanTitle)).FirstWithYear(year);
}
if (result == null)
{
result = candidates
.Where(m => m.AlternativeTitles.Any(t => cleanTitles.Contains(t.CleanTitle) ||
.Where(m => m.MovieMetadata.Value.AlternativeTitles.Any(t => cleanTitles.Contains(t.CleanTitle) ||
otherTitles.Contains(t.CleanTitle)))
.FirstWithYear(year);
}
@ -139,7 +137,7 @@ public Movie FindByTitle(List<string> cleanTitles, int? year, List<string> other
if (result == null)
{
result = candidates
.Where(m => m.Translations.Any(t => cleanTitles.Contains(t.CleanTitle) ||
.Where(m => m.MovieMetadata.Value.Translations.Any(t => cleanTitles.Contains(t.CleanTitle) ||
otherTitles.Contains(t.CleanTitle)))
.FirstWithYear(year);
}
@ -201,11 +199,6 @@ public Dictionary<int, string> AllMoviePaths()
return _movieRepository.AllMoviePaths();
}
public Dictionary<int, string> AllMovieTitleSlugs()
{
return _movieRepository.AllMovieTitleSlugs();
}
public List<int> AllMovieTmdbIds()
{
return _movieRepository.AllMovieTmdbIds();
@ -300,11 +293,6 @@ public List<Movie> GetMoviesByFileId(int fileId)
return _movieRepository.GetMoviesByFileId(fileId);
}
public Movie FindByTitleSlug(string slug)
{
return _movieRepository.FindByTitleSlug(slug);
}
public List<Movie> GetMoviesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored)
{
var movies = _movieRepository.MoviesBetweenDates(start.ToUniversalTime(), end.ToUniversalTime(), includeUnmonitored);
@ -375,7 +363,7 @@ public List<Movie> FilterExistingMovies(List<Movie> movies)
var ret = withTmdbid.ExceptBy(m => m.TmdbId, allMovies, m => m.TmdbId, EqualityComparer<int>.Default)
.Union(withImdbid.ExceptBy(m => m.ImdbId, allMovies, m => m.ImdbId, EqualityComparer<string>.Default))
.Union(rest.ExceptBy(m => m.Title.CleanMovieTitle(), allMovies, m => m.CleanTitle, EqualityComparer<string>.Default)).ToList();
.Union(rest.ExceptBy(m => m.Title.CleanMovieTitle(), allMovies, m => m.MovieMetadata.Value.CleanTitle, EqualityComparer<string>.Default)).ToList();
return ret;
}

View file

@ -1,47 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using FluentValidation.Validators;
using NzbDrone.Common.Extensions;
namespace NzbDrone.Core.Movies
{
public class MovieTitleSlugValidator : PropertyValidator
{
private readonly IMovieService _movieService;
public MovieTitleSlugValidator(IMovieService movieService)
: base("Title slug '{slug}' is in use by movie '{movieTitle}'")
{
_movieService = movieService;
}
protected override bool IsValid(PropertyValidatorContext context)
{
if (context.PropertyValue == null)
{
return true;
}
dynamic instance = context.ParentContext.InstanceToValidate;
var instanceId = (int)instance.Id;
var slug = context.PropertyValue.ToString();
var conflictingId = _movieService.AllMovieTitleSlugs()
.FirstOrDefault(s => s.Value.IsNotNullOrWhiteSpace() &&
s.Value.Equals(context.PropertyValue.ToString()) &&
s.Key != instanceId);
if (conflictingId.Equals(default(KeyValuePair<int, string>)))
{
return true;
}
var conflictingMovie = _movieService.GetMovie(conflictingId.Key);
context.MessageFormatter.AppendArgument("slug", slug);
context.MessageFormatter.AppendArgument("movieTitle", conflictingMovie.Title);
return false;
}
}
}

View file

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
namespace NzbDrone.Core.Movies
@ -7,7 +7,7 @@ public static class EnumerableExtensions
{
public static Movie FirstWithYear(this IEnumerable<Movie> query, int? year)
{
return year.HasValue ? query.FirstOrDefault(movie => movie.Year == year || movie.SecondaryYear == year) : query.FirstOrDefault();
return year.HasValue ? query.FirstOrDefault(movie => movie.Year == year || movie.MovieMetadata.Value.SecondaryYear == year) : query.FirstOrDefault();
}
}
}

View file

@ -1,8 +1,9 @@
using Equ;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Movies
{
public class Ratings : IEmbeddedDocument
public class Ratings : MemberwiseEquatable<Ratings>, IEmbeddedDocument
{
public RatingChild Imdb { get; set; }
public RatingChild Tmdb { get; set; }

View file

@ -23,6 +23,7 @@ public class RefreshMovieService : IExecute<RefreshMovieCommand>
{
private readonly IProvideMovieInfo _movieInfo;
private readonly IMovieService _movieService;
private readonly IMovieMetadataService _movieMetadataService;
private readonly IMovieTranslationService _movieTranslationService;
private readonly IAlternativeTitleService _titleService;
private readonly ICreditService _creditService;
@ -35,6 +36,7 @@ public class RefreshMovieService : IExecute<RefreshMovieCommand>
public RefreshMovieService(IProvideMovieInfo movieInfo,
IMovieService movieService,
IMovieMetadataService movieMetadataService,
IMovieTranslationService movieTranslationService,
IAlternativeTitleService titleService,
ICreditService creditService,
@ -46,6 +48,7 @@ public RefreshMovieService(IProvideMovieInfo movieInfo,
{
_movieInfo = movieInfo;
_movieService = movieService;
_movieMetadataService = movieMetadataService;
_movieTranslationService = movieTranslationService;
_titleService = titleService;
_creditService = creditService;
@ -61,10 +64,11 @@ private Movie RefreshMovieInfo(int movieId)
// Get the movie before updating, that way any changes made to the movie after the refresh started,
// but before this movie was refreshed won't be lost.
var movie = _movieService.GetMovie(movieId);
var movieMetadata = _movieMetadataService.Get(movie.MovieMetadataId);
_logger.ProgressInfo("Updating info for {0}", movie.Title);
Movie movieInfo;
MovieMetadata movieInfo;
List<Credit> credits;
try
@ -75,10 +79,10 @@ private Movie RefreshMovieInfo(int movieId)
}
catch (MovieNotFoundException)
{
if (movie.Status != MovieStatusType.Deleted)
if (movieMetadata.Status != MovieStatusType.Deleted)
{
movie.Status = MovieStatusType.Deleted;
_movieService.UpdateMovie(movie);
movieMetadata.Status = MovieStatusType.Deleted;
_movieMetadataService.Upsert(movieMetadata);
_logger.Debug("Movie marked as deleted on TMDb for {0}", movie.Title);
_eventAggregator.PublishEvent(new MovieUpdatedEvent(movie));
}
@ -86,56 +90,47 @@ private Movie RefreshMovieInfo(int movieId)
throw;
}
if (movie.TmdbId != movieInfo.TmdbId)
if (movieMetadata.TmdbId != movieInfo.TmdbId)
{
_logger.Warn("Movie '{0}' (TMDb: {1}) was replaced with '{2}' (TMDb: {3}), because the original was a duplicate.", movie.Title, movie.TmdbId, movieInfo.Title, movieInfo.TmdbId);
movie.TmdbId = movieInfo.TmdbId;
movieMetadata.TmdbId = movieInfo.TmdbId;
}
movie.Title = movieInfo.Title;
movie.TitleSlug = movieInfo.TitleSlug;
movie.ImdbId = movieInfo.ImdbId;
movie.Overview = movieInfo.Overview;
movie.Status = movieInfo.Status;
movie.CleanTitle = movieInfo.CleanTitle;
movie.SortTitle = movieInfo.SortTitle;
movie.LastInfoSync = DateTime.UtcNow;
movie.Runtime = movieInfo.Runtime;
movie.Images = movieInfo.Images;
movie.Ratings = movieInfo.Ratings;
movie.Collection = movieInfo.Collection;
movie.Genres = movieInfo.Genres;
movie.Certification = movieInfo.Certification;
movie.InCinemas = movieInfo.InCinemas;
movie.Website = movieInfo.Website;
movieMetadata.Title = movieInfo.Title;
movieMetadata.ImdbId = movieInfo.ImdbId;
movieMetadata.Overview = movieInfo.Overview;
movieMetadata.Status = movieInfo.Status;
movieMetadata.CleanTitle = movieInfo.CleanTitle;
movieMetadata.SortTitle = movieInfo.SortTitle;
movieMetadata.LastInfoSync = DateTime.UtcNow;
movieMetadata.Runtime = movieInfo.Runtime;
movieMetadata.Ratings = movieInfo.Ratings;
movieMetadata.Collection = movieInfo.Collection;
movie.Year = movieInfo.Year;
movie.SecondaryYear = movieInfo.SecondaryYear;
movie.PhysicalRelease = movieInfo.PhysicalRelease;
movie.DigitalRelease = movieInfo.DigitalRelease;
movie.YouTubeTrailerId = movieInfo.YouTubeTrailerId;
movie.Studio = movieInfo.Studio;
movie.OriginalTitle = movieInfo.OriginalTitle;
movie.OriginalLanguage = movieInfo.OriginalLanguage;
movie.Recommendations = movieInfo.Recommendations;
//movie.Genres = movieInfo.Genres;
movieMetadata.Certification = movieInfo.Certification;
movieMetadata.InCinemas = movieInfo.InCinemas;
movieMetadata.Website = movieInfo.Website;
try
{
movie.Path = new DirectoryInfo(movie.Path).FullName;
movie.Path = movie.Path.GetActualCasing();
}
catch (Exception e)
{
_logger.Warn(e, "Couldn't update movie path for " + movie.Path);
}
movieMetadata.Year = movieInfo.Year;
movieMetadata.SecondaryYear = movieInfo.SecondaryYear;
movieMetadata.PhysicalRelease = movieInfo.PhysicalRelease;
movieMetadata.DigitalRelease = movieInfo.DigitalRelease;
movieMetadata.YouTubeTrailerId = movieInfo.YouTubeTrailerId;
movieMetadata.Studio = movieInfo.Studio;
movieMetadata.OriginalTitle = movieInfo.OriginalTitle;
movieMetadata.CleanOriginalTitle = movieInfo.CleanOriginalTitle;
movieMetadata.OriginalLanguage = movieInfo.OriginalLanguage;
movieMetadata.Recommendations = movieInfo.Recommendations;
movieMetadata.Popularity = movieInfo.Popularity;
movie.AlternativeTitles = _titleService.UpdateTitles(movieInfo.AlternativeTitles, movie);
_movieTranslationService.UpdateTranslations(movieInfo.Translations, movie);
movieMetadata.AlternativeTitles = _titleService.UpdateTitles(movieInfo.AlternativeTitles, movieMetadata);
_movieTranslationService.UpdateTranslations(movieInfo.Translations, movieMetadata);
_movieService.UpdateMovie(new List<Movie> { movie }, true);
_creditService.UpdateCredits(credits, movie);
_movieMetadataService.Upsert(movieMetadata);
_creditService.UpdateCredits(credits, movieMetadata);
_logger.Debug("Finished movie refresh for {0}", movie.Title);
_logger.Debug("Finished movie metadata refresh for {0}", movieMetadata.Title);
_eventAggregator.PublishEvent(new MovieUpdatedEvent(movie));
return movie;
@ -208,7 +203,8 @@ public void Execute(RefreshMovieCommand message)
}
else
{
var allMovie = _movieService.GetAllMovies().OrderBy(c => c.SortTitle).ToList();
// TODO refresh all moviemetadata here, even if not used by a Movie
var allMovie = _movieService.GetAllMovies().OrderBy(c => c.MovieMetadata.Value.SortTitle).ToList();
var updatedTMDBMovies = new HashSet<int>();
@ -220,7 +216,7 @@ public void Execute(RefreshMovieCommand message)
foreach (var movie in allMovie)
{
var movieLocal = movie;
if ((updatedTMDBMovies.Count == 0 && _checkIfMovieShouldBeRefreshed.ShouldRefresh(movie)) || updatedTMDBMovies.Contains(movie.TmdbId) || message.Trigger == CommandTrigger.Manual)
if ((updatedTMDBMovies.Count == 0 && _checkIfMovieShouldBeRefreshed.ShouldRefresh(movie.MovieMetadata)) || updatedTMDBMovies.Contains(movie.TmdbId) || message.Trigger == CommandTrigger.Manual)
{
try
{

View file

@ -5,7 +5,7 @@ namespace NzbDrone.Core.Movies
{
public interface ICheckIfMovieShouldBeRefreshed
{
bool ShouldRefresh(Movie movie);
bool ShouldRefresh(MovieMetadata movie);
}
public class ShouldRefreshMovie : ICheckIfMovieShouldBeRefreshed
@ -17,7 +17,7 @@ public ShouldRefreshMovie(Logger logger)
_logger = logger;
}
public bool ShouldRefresh(Movie movie)
public bool ShouldRefresh(MovieMetadata movie)
{
//return false;
if (movie.LastInfoSync < DateTime.UtcNow.AddDays(-180))

View file

@ -5,7 +5,7 @@ namespace NzbDrone.Core.Movies.Translations
{
public class MovieTranslation : ModelBase
{
public int MovieId { get; set; }
public int MovieMetadataId { get; set; }
public string Title { get; set; }
public string CleanTitle { get; set; }
public string Overview { get; set; }

Some files were not shown because too many files have changed in this diff Show more