mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-23 14:55:20 -07:00
Changed: Alternative Titles were reworked greatly. This should speed up RSS Sync massively, especially for large libraries (up to 4x).
This commit is contained in:
parent
8927e7c2c6
commit
cfcb66fba1
63 changed files with 1480 additions and 100 deletions
|
@ -1,4 +1,5 @@
|
||||||
using System.Text;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using Marr.Data.Mapping;
|
using Marr.Data.Mapping;
|
||||||
using Marr.Data.QGen.Dialects;
|
using Marr.Data.QGen.Dialects;
|
||||||
|
|
||||||
|
@ -131,6 +132,15 @@ namespace Marr.Data.QGen
|
||||||
sql.Append(OrderBy.ToString());
|
sql.Append(OrderBy.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void BuildGroupBy(StringBuilder sql)
|
||||||
|
{
|
||||||
|
var baseTable = this.Tables.First();
|
||||||
|
var primaryKeyColumn = baseTable.Columns.Single(c => c.ColumnInfo.IsPrimaryKey);
|
||||||
|
|
||||||
|
string token = this.Dialect.CreateToken(string.Concat(baseTable.Alias, ".", primaryKeyColumn.ColumnInfo.Name));
|
||||||
|
sql.AppendFormat(" GROUP BY {0}", token);
|
||||||
|
}
|
||||||
|
|
||||||
private string TranslateJoin(JoinType join)
|
private string TranslateJoin(JoinType join)
|
||||||
{
|
{
|
||||||
switch (join)
|
switch (join)
|
||||||
|
|
|
@ -16,6 +16,19 @@ namespace Marr.Data.QGen
|
||||||
StringBuilder sql = new StringBuilder();
|
StringBuilder sql = new StringBuilder();
|
||||||
|
|
||||||
BuildSelectCountClause(sql);
|
BuildSelectCountClause(sql);
|
||||||
|
|
||||||
|
if (_innerQuery.IsJoin)
|
||||||
|
{
|
||||||
|
sql.Append(" FROM (");
|
||||||
|
_innerQuery.BuildSelectClause(sql);
|
||||||
|
_innerQuery.BuildFromClause(sql);
|
||||||
|
_innerQuery.BuildJoinClauses(sql);
|
||||||
|
_innerQuery.BuildGroupBy(sql);
|
||||||
|
sql.Append(") ");
|
||||||
|
|
||||||
|
return sql.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
_innerQuery.BuildFromClause(sql);
|
_innerQuery.BuildFromClause(sql);
|
||||||
_innerQuery.BuildJoinClauses(sql);
|
_innerQuery.BuildJoinClauses(sql);
|
||||||
_innerQuery.BuildWhereClause(sql);
|
_innerQuery.BuildWhereClause(sql);
|
||||||
|
|
|
@ -46,7 +46,7 @@ namespace NzbDrone.Api.Indexers
|
||||||
GetResourceAll = GetReleases;
|
GetResourceAll = GetReleases;
|
||||||
Post["/"] = x => DownloadRelease(this.Bind<ReleaseResource>());
|
Post["/"] = x => DownloadRelease(this.Bind<ReleaseResource>());
|
||||||
|
|
||||||
PostValidator.RuleFor(s => s.DownloadAllowed).Equal(true);
|
//PostValidator.RuleFor(s => s.DownloadAllowed).Equal(true);
|
||||||
PostValidator.RuleFor(s => s.Guid).NotEmpty();
|
PostValidator.RuleFor(s => s.Guid).NotEmpty();
|
||||||
|
|
||||||
_remoteEpisodeCache = cacheManager.GetCache<RemoteEpisode>(GetType(), "remoteEpisodes");
|
_remoteEpisodeCache = cacheManager.GetCache<RemoteEpisode>(GetType(), "remoteEpisodes");
|
||||||
|
@ -70,7 +70,7 @@ namespace NzbDrone.Api.Indexers
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_downloadService.DownloadReport(remoteMovie);
|
_downloadService.DownloadReport(remoteMovie, false);
|
||||||
}
|
}
|
||||||
catch (ReleaseDownloadException ex)
|
catch (ReleaseDownloadException ex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,6 +8,7 @@ using NzbDrone.Core.Indexers;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.DecisionEngine;
|
using NzbDrone.Core.DecisionEngine;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using NzbDrone.Core.Datastore.Migration;
|
||||||
|
|
||||||
namespace NzbDrone.Api.Indexers
|
namespace NzbDrone.Api.Indexers
|
||||||
{
|
{
|
||||||
|
@ -29,8 +30,8 @@ namespace NzbDrone.Api.Indexers
|
||||||
public bool FullSeason { get; set; }
|
public bool FullSeason { get; set; }
|
||||||
public int SeasonNumber { get; set; }
|
public int SeasonNumber { get; set; }
|
||||||
public Language Language { get; set; }
|
public Language Language { get; set; }
|
||||||
public string AirDate { get; set; }
|
public int Year { get; set; }
|
||||||
public string SeriesTitle { get; set; }
|
public string MovieTitle { get; set; }
|
||||||
public int[] EpisodeNumbers { get; set; }
|
public int[] EpisodeNumbers { get; set; }
|
||||||
public int[] AbsoluteEpisodeNumbers { get; set; }
|
public int[] AbsoluteEpisodeNumbers { get; set; }
|
||||||
public bool Approved { get; set; }
|
public bool Approved { get; set; }
|
||||||
|
@ -43,8 +44,9 @@ namespace NzbDrone.Api.Indexers
|
||||||
public string CommentUrl { get; set; }
|
public string CommentUrl { get; set; }
|
||||||
public string DownloadUrl { get; set; }
|
public string DownloadUrl { get; set; }
|
||||||
public string InfoUrl { get; set; }
|
public string InfoUrl { get; set; }
|
||||||
public bool DownloadAllowed { get; set; }
|
public MappingResultType MappingResult { get; set; }
|
||||||
public int ReleaseWeight { get; set; }
|
public int ReleaseWeight { get; set; }
|
||||||
|
public int SuspectedMovieId { get; set; }
|
||||||
|
|
||||||
public IEnumerable<string> IndexerFlags { get; set; }
|
public IEnumerable<string> IndexerFlags { get; set; }
|
||||||
|
|
||||||
|
@ -88,11 +90,12 @@ namespace NzbDrone.Api.Indexers
|
||||||
var parsedEpisodeInfo = model.RemoteEpisode.ParsedEpisodeInfo;
|
var parsedEpisodeInfo = model.RemoteEpisode.ParsedEpisodeInfo;
|
||||||
var remoteEpisode = model.RemoteEpisode;
|
var remoteEpisode = model.RemoteEpisode;
|
||||||
var torrentInfo = (model.RemoteEpisode.Release as TorrentInfo) ?? new TorrentInfo();
|
var torrentInfo = (model.RemoteEpisode.Release as TorrentInfo) ?? new TorrentInfo();
|
||||||
var downloadAllowed = model.RemoteEpisode.DownloadAllowed;
|
var mappingResult = MappingResultType.Success;
|
||||||
if (model.IsForMovie)
|
if (model.IsForMovie)
|
||||||
{
|
{
|
||||||
downloadAllowed = model.RemoteMovie.DownloadAllowed;
|
mappingResult = model.RemoteMovie.MappingResult;
|
||||||
var parsedMovieInfo = model.RemoteMovie.ParsedMovieInfo;
|
var parsedMovieInfo = model.RemoteMovie.ParsedMovieInfo;
|
||||||
|
var movieId = model.RemoteMovie.Movie?.Id ?? 0;
|
||||||
|
|
||||||
return new ReleaseResource
|
return new ReleaseResource
|
||||||
{
|
{
|
||||||
|
@ -111,8 +114,8 @@ namespace NzbDrone.Api.Indexers
|
||||||
//FullSeason = parsedMovieInfo.FullSeason,
|
//FullSeason = parsedMovieInfo.FullSeason,
|
||||||
//SeasonNumber = parsedMovieInfo.SeasonNumber,
|
//SeasonNumber = parsedMovieInfo.SeasonNumber,
|
||||||
Language = parsedMovieInfo.Language,
|
Language = parsedMovieInfo.Language,
|
||||||
AirDate = "",
|
Year = parsedMovieInfo.Year,
|
||||||
SeriesTitle = parsedMovieInfo.MovieTitle,
|
MovieTitle = parsedMovieInfo.MovieTitle,
|
||||||
EpisodeNumbers = new int[0],
|
EpisodeNumbers = new int[0],
|
||||||
AbsoluteEpisodeNumbers = new int[0],
|
AbsoluteEpisodeNumbers = new int[0],
|
||||||
Approved = model.Approved,
|
Approved = model.Approved,
|
||||||
|
@ -125,9 +128,11 @@ namespace NzbDrone.Api.Indexers
|
||||||
CommentUrl = releaseInfo.CommentUrl,
|
CommentUrl = releaseInfo.CommentUrl,
|
||||||
DownloadUrl = releaseInfo.DownloadUrl,
|
DownloadUrl = releaseInfo.DownloadUrl,
|
||||||
InfoUrl = releaseInfo.InfoUrl,
|
InfoUrl = releaseInfo.InfoUrl,
|
||||||
DownloadAllowed = downloadAllowed,
|
MappingResult = mappingResult,
|
||||||
//ReleaseWeight
|
//ReleaseWeight
|
||||||
|
|
||||||
|
SuspectedMovieId = movieId,
|
||||||
|
|
||||||
MagnetUrl = torrentInfo.MagnetUrl,
|
MagnetUrl = torrentInfo.MagnetUrl,
|
||||||
InfoHash = torrentInfo.InfoHash,
|
InfoHash = torrentInfo.InfoHash,
|
||||||
Seeders = torrentInfo.Seeders,
|
Seeders = torrentInfo.Seeders,
|
||||||
|
@ -161,8 +166,8 @@ namespace NzbDrone.Api.Indexers
|
||||||
FullSeason = parsedEpisodeInfo.FullSeason,
|
FullSeason = parsedEpisodeInfo.FullSeason,
|
||||||
SeasonNumber = parsedEpisodeInfo.SeasonNumber,
|
SeasonNumber = parsedEpisodeInfo.SeasonNumber,
|
||||||
Language = parsedEpisodeInfo.Language,
|
Language = parsedEpisodeInfo.Language,
|
||||||
AirDate = parsedEpisodeInfo.AirDate,
|
//AirDate = parsedEpisodeInfo.AirDate,
|
||||||
SeriesTitle = parsedEpisodeInfo.SeriesTitle,
|
//SeriesTitle = parsedEpisodeInfo.SeriesTitle,
|
||||||
EpisodeNumbers = parsedEpisodeInfo.EpisodeNumbers,
|
EpisodeNumbers = parsedEpisodeInfo.EpisodeNumbers,
|
||||||
AbsoluteEpisodeNumbers = parsedEpisodeInfo.AbsoluteEpisodeNumbers,
|
AbsoluteEpisodeNumbers = parsedEpisodeInfo.AbsoluteEpisodeNumbers,
|
||||||
Approved = model.Approved,
|
Approved = model.Approved,
|
||||||
|
@ -175,7 +180,7 @@ namespace NzbDrone.Api.Indexers
|
||||||
CommentUrl = releaseInfo.CommentUrl,
|
CommentUrl = releaseInfo.CommentUrl,
|
||||||
DownloadUrl = releaseInfo.DownloadUrl,
|
DownloadUrl = releaseInfo.DownloadUrl,
|
||||||
InfoUrl = releaseInfo.InfoUrl,
|
InfoUrl = releaseInfo.InfoUrl,
|
||||||
DownloadAllowed = downloadAllowed,
|
//DownloadAllowed = downloadAllowed,
|
||||||
//ReleaseWeight
|
//ReleaseWeight
|
||||||
|
|
||||||
MagnetUrl = torrentInfo.MagnetUrl,
|
MagnetUrl = torrentInfo.MagnetUrl,
|
||||||
|
|
57
src/NzbDrone.Api/Movies/AlternativeTitleModule.cs
Normal file
57
src/NzbDrone.Api/Movies/AlternativeTitleModule.cs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Marr.Data;
|
||||||
|
using Nancy;
|
||||||
|
using NzbDrone.Api;
|
||||||
|
using NzbDrone.Api.Movie;
|
||||||
|
using NzbDrone.Common.Cache;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Core.MediaCover;
|
||||||
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.MetadataSource;
|
||||||
|
using NzbDrone.Core.MetadataSource.RadarrAPI;
|
||||||
|
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||||
|
using NzbDrone.Core.RootFolders;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
using NzbDrone.Core.Tv.Events;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Movie
|
||||||
|
{
|
||||||
|
public class AlternativeTitleModule : NzbDroneRestModule<AlternativeTitleResource>
|
||||||
|
{
|
||||||
|
private readonly IAlternativeTitleService _altTitleService;
|
||||||
|
private readonly IMovieService _movieService;
|
||||||
|
private readonly IRadarrAPIClient _radarrApi;
|
||||||
|
private readonly IEventAggregator _eventAggregator;
|
||||||
|
|
||||||
|
public AlternativeTitleModule(IAlternativeTitleService altTitleService, IMovieService movieService, IRadarrAPIClient radarrApi, IEventAggregator eventAggregator)
|
||||||
|
: base("/alttitle")
|
||||||
|
{
|
||||||
|
_altTitleService = altTitleService;
|
||||||
|
_movieService = movieService;
|
||||||
|
_radarrApi = radarrApi;
|
||||||
|
CreateResource = AddTitle;
|
||||||
|
GetResourceById = GetTitle;
|
||||||
|
_eventAggregator = eventAggregator;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int AddTitle(AlternativeTitleResource altTitle)
|
||||||
|
{
|
||||||
|
var title = altTitle.ToModel();
|
||||||
|
var movie = _movieService.GetMovie(altTitle.MovieId);
|
||||||
|
var newTitle = _radarrApi.AddNewAlternativeTitle(title, movie.TmdbId);
|
||||||
|
|
||||||
|
var addedTitle = _altTitleService.AddAltTitle(newTitle, movie);
|
||||||
|
_eventAggregator.PublishEvent(new MovieUpdatedEvent(movie));
|
||||||
|
return addedTitle.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AlternativeTitleResource GetTitle(int id)
|
||||||
|
{
|
||||||
|
return _altTitleService.GetById(id).ToResource();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
63
src/NzbDrone.Api/Movies/AlternativeYearModule.cs
Normal file
63
src/NzbDrone.Api/Movies/AlternativeYearModule.cs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Marr.Data;
|
||||||
|
using Nancy;
|
||||||
|
using NzbDrone.Api;
|
||||||
|
using NzbDrone.Api.Movie;
|
||||||
|
using NzbDrone.Common.Cache;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Common.Messaging;
|
||||||
|
using NzbDrone.Core.MediaCover;
|
||||||
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.MetadataSource;
|
||||||
|
using NzbDrone.Core.MetadataSource.RadarrAPI;
|
||||||
|
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||||
|
using NzbDrone.Core.RootFolders;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
using NzbDrone.Core.Tv.Events;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Movie
|
||||||
|
{
|
||||||
|
public class AlternativeYearModule : NzbDroneRestModule<AlternativeYearResource>
|
||||||
|
{
|
||||||
|
private readonly IMovieService _movieService;
|
||||||
|
private readonly IRadarrAPIClient _radarrApi;
|
||||||
|
private readonly ICached<int> _yearCache;
|
||||||
|
private readonly IEventAggregator _eventAggregator;
|
||||||
|
|
||||||
|
public AlternativeYearModule(IMovieService movieService, IRadarrAPIClient radarrApi, ICacheManager cacheManager, IEventAggregator eventAggregator)
|
||||||
|
: base("/altyear")
|
||||||
|
{
|
||||||
|
_movieService = movieService;
|
||||||
|
_radarrApi = radarrApi;
|
||||||
|
CreateResource = AddYear;
|
||||||
|
GetResourceById = GetYear;
|
||||||
|
_yearCache = cacheManager.GetCache<int>(GetType(), "altYears");
|
||||||
|
_eventAggregator = eventAggregator;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int AddYear(AlternativeYearResource altYear)
|
||||||
|
{
|
||||||
|
var id = new Random().Next();
|
||||||
|
_yearCache.Set(id.ToString(), altYear.Year, TimeSpan.FromMinutes(1));
|
||||||
|
var movie = _movieService.GetMovie(altYear.MovieId);
|
||||||
|
var newYear = _radarrApi.AddNewAlternativeYear(altYear.Year, movie.TmdbId);
|
||||||
|
movie.SecondaryYear = newYear.Year;
|
||||||
|
movie.SecondaryYearSourceId = newYear.SourceId;
|
||||||
|
_movieService.UpdateMovie(movie);
|
||||||
|
_eventAggregator.PublishEvent(new MovieUpdatedEvent(movie));
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AlternativeYearResource GetYear(int id)
|
||||||
|
{
|
||||||
|
return new AlternativeYearResource
|
||||||
|
{
|
||||||
|
Year = _yearCache.Find(id.ToString())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
75
src/NzbDrone.Api/Movies/AlternativeYearResource.cs
Normal file
75
src/NzbDrone.Api/Movies/AlternativeYearResource.cs
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NzbDrone.Api.REST;
|
||||||
|
using NzbDrone.Core.MediaCover;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
|
using NzbDrone.Api.Series;
|
||||||
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||||
|
using NzbDrone.Core.Parser;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Movie
|
||||||
|
{
|
||||||
|
public class AlternativeYearResource : RestResource
|
||||||
|
{
|
||||||
|
public AlternativeYearResource()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Todo: Sorters should be done completely on the client
|
||||||
|
//Todo: Is there an easy way to keep IgnoreArticlesWhenSorting in sync between, Series, History, Missing?
|
||||||
|
//Todo: We should get the entire Profile instead of ID and Name separately
|
||||||
|
|
||||||
|
public int MovieId { get; set; }
|
||||||
|
public int Year { get; set; }
|
||||||
|
|
||||||
|
//TODO: Add series statistics as a property of the series (instead of individual properties)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*public static class AlternativeYearResourceMapper
|
||||||
|
{
|
||||||
|
/*public static AlternativeYearResource ToResource(this AlternativeTitle model)
|
||||||
|
{
|
||||||
|
if (model == null) return null;
|
||||||
|
|
||||||
|
AlternativeTitleResource resource = null;
|
||||||
|
|
||||||
|
return new AlternativeTitleResource
|
||||||
|
{
|
||||||
|
Id = model.Id,
|
||||||
|
SourceType = model.SourceType,
|
||||||
|
MovieId = model.MovieId,
|
||||||
|
Title = model.Title,
|
||||||
|
SourceId = model.SourceId,
|
||||||
|
Votes = model.Votes,
|
||||||
|
VoteCount = model.VoteCount,
|
||||||
|
Language = model.Language
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AlternativeTitle ToModel(this AlternativeTitleResource resource)
|
||||||
|
{
|
||||||
|
if (resource == null) return null;
|
||||||
|
|
||||||
|
return new AlternativeTitle
|
||||||
|
{
|
||||||
|
Id = resource.Id,
|
||||||
|
SourceType = resource.SourceType,
|
||||||
|
MovieId = resource.MovieId,
|
||||||
|
Title = resource.Title,
|
||||||
|
SourceId = resource.SourceId,
|
||||||
|
Votes = resource.Votes,
|
||||||
|
VoteCount = resource.VoteCount,
|
||||||
|
Language = resource.Language
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<AlternativeTitleResource> ToResource(this IEnumerable<AlternativeTitle> movies)
|
||||||
|
{
|
||||||
|
return movies.Select(ToResource).ToList();
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
|
@ -119,6 +119,9 @@
|
||||||
<Compile Include="Frontend\Mappers\RobotsTxtMapper.cs" />
|
<Compile Include="Frontend\Mappers\RobotsTxtMapper.cs" />
|
||||||
<Compile Include="Indexers\ReleaseModuleBase.cs" />
|
<Compile Include="Indexers\ReleaseModuleBase.cs" />
|
||||||
<Compile Include="Indexers\ReleasePushModule.cs" />
|
<Compile Include="Indexers\ReleasePushModule.cs" />
|
||||||
|
<Compile Include="Movies\AlternativeTitleModule.cs" />
|
||||||
|
<Compile Include="Movies\AlternativeYearResource.cs" />
|
||||||
|
<Compile Include="Movies\AlternativeYearModule.cs" />
|
||||||
<Compile Include="Movies\MovieModuleWithSignalR.cs" />
|
<Compile Include="Movies\MovieModuleWithSignalR.cs" />
|
||||||
<Compile Include="Movies\MovieBulkImportModule.cs" />
|
<Compile Include="Movies\MovieBulkImportModule.cs" />
|
||||||
<Compile Include="Movies\MovieFileModule.cs" />
|
<Compile Include="Movies\MovieFileModule.cs" />
|
||||||
|
@ -240,7 +243,7 @@
|
||||||
<Compile Include="RootFolders\RootFolderModule.cs" />
|
<Compile Include="RootFolders\RootFolderModule.cs" />
|
||||||
<Compile Include="RootFolders\RootFolderResource.cs" />
|
<Compile Include="RootFolders\RootFolderResource.cs" />
|
||||||
<Compile Include="SeasonPass\SeasonPassResource.cs" />
|
<Compile Include="SeasonPass\SeasonPassResource.cs" />
|
||||||
<Compile Include="Series\AlternateTitleResource.cs" />
|
<Compile Include="Series\AlternativeTitleResource.cs" />
|
||||||
<Compile Include="Series\MovieFileResource.cs" />
|
<Compile Include="Series\MovieFileResource.cs" />
|
||||||
<Compile Include="Series\FetchMovieListModule.cs" />
|
<Compile Include="Series\FetchMovieListModule.cs" />
|
||||||
<Compile Include="Series\SeasonResource.cs" />
|
<Compile Include="Series\SeasonResource.cs" />
|
||||||
|
|
|
@ -105,7 +105,7 @@ namespace NzbDrone.Api.Queue
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
_downloadService.DownloadReport(pendingRelease.RemoteMovie);
|
_downloadService.DownloadReport(pendingRelease.RemoteMovie, false);
|
||||||
|
|
||||||
return resource.AsResponse();
|
return resource.AsResponse();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
namespace NzbDrone.Api.Series
|
|
||||||
{
|
|
||||||
public class AlternateTitleResource
|
|
||||||
{
|
|
||||||
public string Title { get; set; }
|
|
||||||
public int? SeasonNumber { get; set; }
|
|
||||||
public int? SceneSeasonNumber { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
81
src/NzbDrone.Api/Series/AlternativeTitleResource.cs
Normal file
81
src/NzbDrone.Api/Series/AlternativeTitleResource.cs
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NzbDrone.Api.REST;
|
||||||
|
using NzbDrone.Core.MediaCover;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
|
using NzbDrone.Api.Series;
|
||||||
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||||
|
using NzbDrone.Core.Parser;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Movie
|
||||||
|
{
|
||||||
|
public class AlternativeTitleResource : RestResource
|
||||||
|
{
|
||||||
|
public AlternativeTitleResource()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Todo: Sorters should be done completely on the client
|
||||||
|
//Todo: Is there an easy way to keep IgnoreArticlesWhenSorting in sync between, Series, History, Missing?
|
||||||
|
//Todo: We should get the entire Profile instead of ID and Name separately
|
||||||
|
|
||||||
|
public SourceType SourceType { get; set; }
|
||||||
|
public int MovieId { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string CleanTitle { get; set; }
|
||||||
|
public int SourceId { get; set; }
|
||||||
|
public int Votes { get; set; }
|
||||||
|
public int VoteCount { get; set; }
|
||||||
|
public Language Language { get; set; }
|
||||||
|
|
||||||
|
//TODO: Add series statistics as a property of the series (instead of individual properties)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AlternativeTitleResourceMapper
|
||||||
|
{
|
||||||
|
public static AlternativeTitleResource ToResource(this AlternativeTitle model)
|
||||||
|
{
|
||||||
|
if (model == null) return null;
|
||||||
|
|
||||||
|
AlternativeTitleResource resource = null;
|
||||||
|
|
||||||
|
return new AlternativeTitleResource
|
||||||
|
{
|
||||||
|
Id = model.Id,
|
||||||
|
SourceType = model.SourceType,
|
||||||
|
MovieId = model.MovieId,
|
||||||
|
Title = model.Title,
|
||||||
|
SourceId = model.SourceId,
|
||||||
|
Votes = model.Votes,
|
||||||
|
VoteCount = model.VoteCount,
|
||||||
|
Language = model.Language
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AlternativeTitle ToModel(this AlternativeTitleResource resource)
|
||||||
|
{
|
||||||
|
if (resource == null) return null;
|
||||||
|
|
||||||
|
return new AlternativeTitle
|
||||||
|
{
|
||||||
|
Id = resource.Id,
|
||||||
|
SourceType = resource.SourceType,
|
||||||
|
MovieId = resource.MovieId,
|
||||||
|
Title = resource.Title,
|
||||||
|
SourceId = resource.SourceId,
|
||||||
|
Votes = resource.Votes,
|
||||||
|
VoteCount = resource.VoteCount,
|
||||||
|
Language = resource.Language
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<AlternativeTitleResource> ToResource(this IEnumerable<AlternativeTitle> movies)
|
||||||
|
{
|
||||||
|
return movies.Select(ToResource).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,7 +21,9 @@ namespace NzbDrone.Api.Movie
|
||||||
|
|
||||||
//View Only
|
//View Only
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public List<AlternateTitleResource> AlternateTitles { get; set; }
|
public List<AlternativeTitleResource> AlternativeTitles { get; set; }
|
||||||
|
public int? SecondaryYear { get; set; }
|
||||||
|
public int SecondaryYearSourceId { get; set; }
|
||||||
public string SortTitle { get; set; }
|
public string SortTitle { get; set; }
|
||||||
public long? SizeOnDisk { get; set; }
|
public long? SizeOnDisk { get; set; }
|
||||||
public MovieStatusType Status { get; set; }
|
public MovieStatusType Status { get; set; }
|
||||||
|
@ -62,7 +64,7 @@ namespace NzbDrone.Api.Movie
|
||||||
public DateTime Added { get; set; }
|
public DateTime Added { get; set; }
|
||||||
public AddMovieOptions AddOptions { get; set; }
|
public AddMovieOptions AddOptions { get; set; }
|
||||||
public Ratings Ratings { get; set; }
|
public Ratings Ratings { get; set; }
|
||||||
public List<string> AlternativeTitles { get; set; }
|
//public List<string> AlternativeTitles { get; set; }
|
||||||
public MovieFileResource MovieFile { get; set; }
|
public MovieFileResource MovieFile { get; set; }
|
||||||
|
|
||||||
//TODO: Add series statistics as a property of the series (instead of individual properties)
|
//TODO: Add series statistics as a property of the series (instead of individual properties)
|
||||||
|
@ -108,6 +110,8 @@ namespace NzbDrone.Api.Movie
|
||||||
movieFile = model.MovieFile.Value.ToResource();
|
movieFile = model.MovieFile.Value.ToResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//model.AlternativeTitles.LazyLoad();
|
||||||
|
|
||||||
return new MovieResource
|
return new MovieResource
|
||||||
{
|
{
|
||||||
Id = model.Id,
|
Id = model.Id,
|
||||||
|
@ -131,6 +135,8 @@ namespace NzbDrone.Api.Movie
|
||||||
Images = model.Images,
|
Images = model.Images,
|
||||||
|
|
||||||
Year = model.Year,
|
Year = model.Year,
|
||||||
|
SecondaryYear = model.SecondaryYear,
|
||||||
|
SecondaryYearSourceId = model.SecondaryYearSourceId,
|
||||||
|
|
||||||
Path = model.Path,
|
Path = model.Path,
|
||||||
ProfileId = model.ProfileId,
|
ProfileId = model.ProfileId,
|
||||||
|
@ -156,7 +162,7 @@ namespace NzbDrone.Api.Movie
|
||||||
Tags = model.Tags,
|
Tags = model.Tags,
|
||||||
Added = model.Added,
|
Added = model.Added,
|
||||||
AddOptions = model.AddOptions,
|
AddOptions = model.AddOptions,
|
||||||
AlternativeTitles = model.AlternativeTitles,
|
AlternativeTitles = model.AlternativeTitles.ToResource(),
|
||||||
Ratings = model.Ratings,
|
Ratings = model.Ratings,
|
||||||
MovieFile = movieFile,
|
MovieFile = movieFile,
|
||||||
YouTubeTrailerId = model.YouTubeTrailerId,
|
YouTubeTrailerId = model.YouTubeTrailerId,
|
||||||
|
@ -189,6 +195,8 @@ namespace NzbDrone.Api.Movie
|
||||||
Images = resource.Images,
|
Images = resource.Images,
|
||||||
|
|
||||||
Year = resource.Year,
|
Year = resource.Year,
|
||||||
|
SecondaryYear = resource.SecondaryYear,
|
||||||
|
SecondaryYearSourceId = resource.SecondaryYearSourceId,
|
||||||
|
|
||||||
Path = resource.Path,
|
Path = resource.Path,
|
||||||
ProfileId = resource.ProfileId,
|
ProfileId = resource.ProfileId,
|
||||||
|
@ -209,7 +217,7 @@ namespace NzbDrone.Api.Movie
|
||||||
Tags = resource.Tags,
|
Tags = resource.Tags,
|
||||||
Added = resource.Added,
|
Added = resource.Added,
|
||||||
AddOptions = resource.AddOptions,
|
AddOptions = resource.AddOptions,
|
||||||
AlternativeTitles = resource.AlternativeTitles,
|
//AlternativeTitles = resource.AlternativeTitles,
|
||||||
Ratings = resource.Ratings,
|
Ratings = resource.Ratings,
|
||||||
YouTubeTrailerId = resource.YouTubeTrailerId,
|
YouTubeTrailerId = resource.YouTubeTrailerId,
|
||||||
Studio = resource.Studio
|
Studio = resource.Studio
|
||||||
|
|
|
@ -199,7 +199,7 @@ namespace NzbDrone.Api.Series
|
||||||
|
|
||||||
if (mappings == null) return;
|
if (mappings == null) return;
|
||||||
|
|
||||||
resource.AlternateTitles = mappings.Select(v => new AlternateTitleResource { Title = v.Title, SeasonNumber = v.SeasonNumber, SceneSeasonNumber = v.SceneSeasonNumber }).ToList();
|
//resource.AlternateTitles = mappings.Select(v => new AlternateTitleResource { Title = v.Title, SeasonNumber = v.SeasonNumber, SceneSeasonNumber = v.SceneSeasonNumber }).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Handle(EpisodeImportedEvent message)
|
public void Handle(EpisodeImportedEvent message)
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace NzbDrone.Api.Series
|
||||||
|
|
||||||
//View Only
|
//View Only
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public List<AlternateTitleResource> AlternateTitles { get; set; }
|
//public List<AlternativeTitleResource> AlternateTitles { get; set; }
|
||||||
public string SortTitle { get; set; }
|
public string SortTitle { get; set; }
|
||||||
|
|
||||||
public int SeasonCount
|
public int SeasonCount
|
||||||
|
|
|
@ -263,7 +263,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
|
|
||||||
result.Should().HaveCount(1);
|
result.Should().HaveCount(1);
|
||||||
|
|
||||||
result.First().RemoteMovie.DownloadAllowed.Should().BeFalse();
|
//result.First().RemoteMovie.DownloadAllowed.Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -278,7 +278,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
|
|
||||||
result.Should().HaveCount(1);
|
result.Should().HaveCount(1);
|
||||||
|
|
||||||
result.First().RemoteMovie.DownloadAllowed.Should().BeFalse();
|
//result.First().RemoteMovie.DownloadAllowed.Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|
|
@ -76,7 +76,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
|
||||||
decisions.Add(new DownloadDecision(remoteMovie));
|
decisions.Add(new DownloadDecision(remoteMovie));
|
||||||
|
|
||||||
Subject.ProcessDecisions(decisions);
|
Subject.ProcessDecisions(decisions);
|
||||||
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteMovie>()), Times.Once());
|
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteMovie>(), false), Times.Once());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -89,7 +89,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
|
||||||
decisions.Add(new DownloadDecision(remoteMovie));
|
decisions.Add(new DownloadDecision(remoteMovie));
|
||||||
|
|
||||||
Subject.ProcessDecisions(decisions);
|
Subject.ProcessDecisions(decisions);
|
||||||
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteMovie>()), Times.Once());
|
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteMovie>(), false), Times.Once());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -157,7 +157,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
|
||||||
var decisions = new List<DownloadDecision>();
|
var decisions = new List<DownloadDecision>();
|
||||||
decisions.Add(new DownloadDecision(remoteMovie));
|
decisions.Add(new DownloadDecision(remoteMovie));
|
||||||
|
|
||||||
Mocker.GetMock<IDownloadService>().Setup(s => s.DownloadReport(It.IsAny<RemoteMovie>())).Throws(new Exception());
|
Mocker.GetMock<IDownloadService>().Setup(s => s.DownloadReport(It.IsAny<RemoteMovie>(), false)).Throws(new Exception());
|
||||||
Subject.ProcessDecisions(decisions).Grabbed.Should().BeEmpty();
|
Subject.ProcessDecisions(decisions).Grabbed.Should().BeEmpty();
|
||||||
ExceptionVerification.ExpectedWarns(1);
|
ExceptionVerification.ExpectedWarns(1);
|
||||||
}
|
}
|
||||||
|
@ -183,7 +183,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
|
||||||
decisions.Add(new DownloadDecision(remoteMovie));
|
decisions.Add(new DownloadDecision(remoteMovie));
|
||||||
|
|
||||||
Subject.ProcessDecisions(decisions);
|
Subject.ProcessDecisions(decisions);
|
||||||
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteMovie>()), Times.Never());
|
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteMovie>(), false), Times.Never());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|
|
@ -6,7 +6,9 @@ using FluentAssertions;
|
||||||
using Moq;
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using NzbDrone.Core.DataAugmentation.Scene;
|
using NzbDrone.Core.DataAugmentation.Scene;
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
|
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||||
using NzbDrone.Core.Parser;
|
using NzbDrone.Core.Parser;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
|
@ -43,7 +45,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests
|
||||||
.With(m => m.Title = "Fack Ju Göthe 2")
|
.With(m => m.Title = "Fack Ju Göthe 2")
|
||||||
.With(m => m.CleanTitle = "fackjugoethe2")
|
.With(m => m.CleanTitle = "fackjugoethe2")
|
||||||
.With(m => m.Year = 2015)
|
.With(m => m.Year = 2015)
|
||||||
.With(m => m.AlternativeTitles = new List<string> { "Fack Ju Göthe 2: Same same" })
|
.With(m => m.AlternativeTitles = new LazyList<AlternativeTitle>( new List<AlternativeTitle> {new AlternativeTitle("Fack Ju Göthe 2: Same same")}))
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
_episodes = Builder<Episode>.CreateListOfSize(1)
|
_episodes = Builder<Episode>.CreateListOfSize(1)
|
||||||
|
@ -80,7 +82,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests
|
||||||
|
|
||||||
_alternativeTitleInfo = new ParsedMovieInfo
|
_alternativeTitleInfo = new ParsedMovieInfo
|
||||||
{
|
{
|
||||||
MovieTitle = _movie.AlternativeTitles.First(),
|
MovieTitle = _movie.AlternativeTitles.First().Title,
|
||||||
Year = _movie.Year,
|
Year = _movie.Year,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -307,6 +307,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
||||||
|
|
||||||
[TestCase("Movie.Title.2016.1080p.KORSUB.WEBRip.x264.AAC2.0-RADARR", "korsub")]
|
[TestCase("Movie.Title.2016.1080p.KORSUB.WEBRip.x264.AAC2.0-RADARR", "korsub")]
|
||||||
[TestCase("Movie.Title.2016.1080p.KORSUBS.WEBRip.x264.AAC2.0-RADARR", "korsubs")]
|
[TestCase("Movie.Title.2016.1080p.KORSUBS.WEBRip.x264.AAC2.0-RADARR", "korsubs")]
|
||||||
|
[TestCase("Wonder Woman 2017 HC 720p HDRiP DD5 1 x264-LEGi0N", "Generic Hardcoded Subs")]
|
||||||
public void should_parse_hardcoded_subs(string postTitle, string sub)
|
public void should_parse_hardcoded_subs(string postTitle, string sub)
|
||||||
{
|
{
|
||||||
QualityParser.ParseQuality(postTitle).HardcodedSubs.Should().Be(sub);
|
QualityParser.ParseQuality(postTitle).HardcodedSubs.Should().Be(sub);
|
||||||
|
|
|
@ -3,8 +3,10 @@ using System.Collections.Generic;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
|
using System.Web.Hosting;
|
||||||
using Marr.Data;
|
using Marr.Data;
|
||||||
using Marr.Data.QGen;
|
using Marr.Data.QGen;
|
||||||
|
using NLog;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Datastore.Events;
|
using NzbDrone.Core.Datastore.Events;
|
||||||
using NzbDrone.Core.Datastore.Extensions;
|
using NzbDrone.Core.Datastore.Extensions;
|
||||||
|
@ -48,7 +50,7 @@ namespace NzbDrone.Core.Datastore
|
||||||
_eventAggregator = eventAggregator;
|
_eventAggregator = eventAggregator;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected QueryBuilder<TModel> Query => DataMapper.Query<TModel>();
|
protected QueryBuilder<TModel> Query => AddJoinQueries(DataMapper.Query<TModel>());
|
||||||
|
|
||||||
protected void Delete(Expression<Func<TModel, bool>> filter)
|
protected void Delete(Expression<Func<TModel, bool>> filter)
|
||||||
{
|
{
|
||||||
|
@ -246,18 +248,23 @@ namespace NzbDrone.Core.Datastore
|
||||||
|
|
||||||
public virtual PagingSpec<TModel> GetPaged(PagingSpec<TModel> pagingSpec)
|
public virtual PagingSpec<TModel> GetPaged(PagingSpec<TModel> pagingSpec)
|
||||||
{
|
{
|
||||||
pagingSpec.Records = GetPagedQuery(Query, pagingSpec).ToList();
|
pagingSpec.Records = GetPagedQuery(Query, pagingSpec).Skip(pagingSpec.PagingOffset())
|
||||||
|
.Take(pagingSpec.PageSize).ToList();
|
||||||
pagingSpec.TotalRecords = GetPagedQuery(Query, pagingSpec).GetRowCount();
|
pagingSpec.TotalRecords = GetPagedQuery(Query, pagingSpec).GetRowCount();
|
||||||
|
|
||||||
|
var queryStr = GetPagedQuery(Query, pagingSpec).BuildQuery();
|
||||||
|
var beforeQuery = Query.BuildQuery();
|
||||||
|
|
||||||
|
pagingSpec.SortKey = beforeQuery;
|
||||||
|
pagingSpec.SortKey = queryStr;
|
||||||
|
|
||||||
return pagingSpec;
|
return pagingSpec;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual SortBuilder<TModel> GetPagedQuery(QueryBuilder<TModel> query, PagingSpec<TModel> pagingSpec)
|
protected virtual SortBuilder<TModel> GetPagedQuery(QueryBuilder<TModel> query, PagingSpec<TModel> pagingSpec)
|
||||||
{
|
{
|
||||||
return query.Where(pagingSpec.FilterExpression)
|
return query.Where(pagingSpec.FilterExpression)
|
||||||
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection())
|
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection());
|
||||||
.Skip(pagingSpec.PagingOffset())
|
|
||||||
.Take(pagingSpec.PageSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ModelCreated(TModel model)
|
protected void ModelCreated(TModel model)
|
||||||
|
@ -283,6 +290,11 @@ namespace NzbDrone.Core.Datastore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual QueryBuilder<TModel> AddJoinQueries(QueryBuilder<TModel> baseQuery)
|
||||||
|
{
|
||||||
|
return baseQuery;
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual bool PublishModelEvents => false;
|
protected virtual bool PublishModelEvents => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,12 +28,12 @@ namespace NzbDrone.Core.Datastore.Extensions
|
||||||
return mapBuilder.Relationships.AutoMapComplexTypeProperties<ILazyLoaded>();
|
return mapBuilder.Relationships.AutoMapComplexTypeProperties<ILazyLoaded>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RelationshipBuilder<TParent> HasMany<TParent, TChild>(this RelationshipBuilder<TParent> relationshipBuilder, Expression<Func<TParent, LazyList<TChild>>> portalExpression, Func<TParent, int> childIdSelector)
|
public static RelationshipBuilder<TParent> HasMany<TParent, TChild>(this RelationshipBuilder<TParent> relationshipBuilder, Expression<Func<TParent, LazyList<TChild>>> portalExpression, Func<TChild, int> parentIdSelector)
|
||||||
where TParent : ModelBase
|
where TParent : ModelBase
|
||||||
where TChild : ModelBase
|
where TChild : ModelBase
|
||||||
{
|
{
|
||||||
return relationshipBuilder.For(portalExpression.GetMemberName())
|
return relationshipBuilder.For(portalExpression.GetMemberName())
|
||||||
.LazyLoad((db, parent) => db.Query<TChild>().Where(c => c.Id == childIdSelector(parent)).ToList());
|
.LazyLoad((db, parent) => db.Query<TChild>().Where(c => parentIdSelector(c) == parent.Id).ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetMemberName<T, TMember>(this Expression<Func<T, TMember>> member)
|
private static string GetMemberName<T, TMember>(this Expression<Func<T, TMember>> member)
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
using System.Data;
|
||||||
|
using FluentMigrator;
|
||||||
|
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||||
|
using System.Text;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Globalization;
|
||||||
|
using Marr.Data.QGen;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Datastore.Migration
|
||||||
|
{
|
||||||
|
[Migration(140)]
|
||||||
|
public class add_alternative_titles_table : NzbDroneMigrationBase
|
||||||
|
{
|
||||||
|
protected override void MainDbUpgrade()
|
||||||
|
{
|
||||||
|
if (!this.Schema.Schema("dbo").Table("alternative_titles").Exists())
|
||||||
|
{
|
||||||
|
Create.TableForModel("AlternativeTitles")
|
||||||
|
.WithColumn("MovieId").AsInt64().NotNullable()
|
||||||
|
.WithColumn("Title").AsString().NotNullable()
|
||||||
|
.WithColumn("CleanTitle").AsString().NotNullable()
|
||||||
|
.WithColumn("SourceType").AsInt64().WithDefault(0)
|
||||||
|
.WithColumn("SourceId").AsInt64().WithDefault(0)
|
||||||
|
.WithColumn("Votes").AsInt64().WithDefault(0)
|
||||||
|
.WithColumn("VoteCount").AsInt64().WithDefault(0)
|
||||||
|
.WithColumn("Language").AsInt64().WithDefault(0);
|
||||||
|
|
||||||
|
Delete.Column("AlternativeTitles").FromTable("Movies");
|
||||||
|
}
|
||||||
|
|
||||||
|
Alter.Table("Movies").AddColumn("SecondaryYear").AsInt32().Nullable();
|
||||||
|
Alter.Table("Movies").AddColumn("SecondaryYearSourceId").AsInt64().Nullable().WithDefault(0);
|
||||||
|
|
||||||
|
Execute.WithConnection(AddExisting);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddExisting(IDbConnection conn, IDbTransaction tran)
|
||||||
|
{
|
||||||
|
using (IDbCommand getSeriesCmd = conn.CreateCommand())
|
||||||
|
{
|
||||||
|
getSeriesCmd.Transaction = tran;
|
||||||
|
getSeriesCmd.CommandText = @"SELECT Key, Value FROM Config WHERE Key = 'importexclusions'";
|
||||||
|
TextInfo textInfo = new CultureInfo("en-US", false).TextInfo;
|
||||||
|
using (IDataReader seriesReader = getSeriesCmd.ExecuteReader())
|
||||||
|
{
|
||||||
|
while (seriesReader.Read())
|
||||||
|
{
|
||||||
|
var Key = seriesReader.GetString(0);
|
||||||
|
var Value = seriesReader.GetString(1);
|
||||||
|
|
||||||
|
var importExclusions = Value.Split(',').Select(x => {
|
||||||
|
return string.Format("(\"{0}\", \"{1}\")", Regex.Replace(x, @"^.*\-(.*)$", "$1"),
|
||||||
|
textInfo.ToTitleCase(string.Join(" ", x.Split('-').DropLast(1))));
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
using (IDbCommand updateCmd = conn.CreateCommand())
|
||||||
|
{
|
||||||
|
updateCmd.Transaction = tran;
|
||||||
|
updateCmd.CommandText = "INSERT INTO ImportExclusions (tmdbid, MovieTitle) VALUES " + string.Join(", ", importExclusions);
|
||||||
|
|
||||||
|
updateCmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,6 +36,45 @@ using NzbDrone.Core.Extras.Subtitles;
|
||||||
using NzbDrone.Core.Messaging.Commands;
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
using NzbDrone.Core.NetImport;
|
using NzbDrone.Core.NetImport;
|
||||||
using NzbDrone.Core.NetImport.ImportExclusions;
|
using NzbDrone.Core.NetImport.ImportExclusions;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Marr.Data;
|
||||||
|
using Marr.Data.Mapping;
|
||||||
|
using NzbDrone.Common.Reflection;
|
||||||
|
using NzbDrone.Core.Blacklisting;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
using NzbDrone.Core.DataAugmentation.Scene;
|
||||||
|
using NzbDrone.Core.Datastore.Converters;
|
||||||
|
using NzbDrone.Core.Datastore.Extensions;
|
||||||
|
using NzbDrone.Core.Download;
|
||||||
|
using NzbDrone.Core.Download.Pending;
|
||||||
|
using NzbDrone.Core.Indexers;
|
||||||
|
using NzbDrone.Core.Instrumentation;
|
||||||
|
using NzbDrone.Core.Jobs;
|
||||||
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.Profiles.Delay;
|
||||||
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
|
using NzbDrone.Core.Notifications;
|
||||||
|
using NzbDrone.Core.Organizer;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
using NzbDrone.Core.Profiles;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
|
using NzbDrone.Core.Restrictions;
|
||||||
|
using NzbDrone.Core.RootFolders;
|
||||||
|
using NzbDrone.Core.SeriesStats;
|
||||||
|
using NzbDrone.Core.Tags;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
using NzbDrone.Common.Disk;
|
||||||
|
using NzbDrone.Core.Authentication;
|
||||||
|
using NzbDrone.Core.Extras.Metadata;
|
||||||
|
using NzbDrone.Core.Extras.Metadata.Files;
|
||||||
|
using NzbDrone.Core.Extras.Others;
|
||||||
|
using NzbDrone.Core.Extras.Subtitles;
|
||||||
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
|
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||||
|
using NzbDrone.Core.NetImport;
|
||||||
|
using NzbDrone.Core.NetImport.ImportExclusions;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Datastore
|
namespace NzbDrone.Core.Datastore
|
||||||
{
|
{
|
||||||
|
@ -107,6 +146,13 @@ namespace NzbDrone.Core.Datastore
|
||||||
.HasOne(s => s.Profile, s => s.ProfileId)
|
.HasOne(s => s.Profile, s => s.ProfileId)
|
||||||
.HasOne(m => m.MovieFile, m => m.MovieFileId);
|
.HasOne(m => m.MovieFile, m => m.MovieFileId);
|
||||||
|
|
||||||
|
Mapper.Entity<AlternativeTitle>().RegisterModel("AlternativeTitles")
|
||||||
|
.For(t => t.Id)
|
||||||
|
.SetAltName("AltTitle_Id")
|
||||||
|
.Relationship()
|
||||||
|
.HasOne(t => t.Movie, t => t.MovieId);
|
||||||
|
|
||||||
|
|
||||||
Mapper.Entity<ImportExclusion>().RegisterModel("ImportExclusions");
|
Mapper.Entity<ImportExclusion>().RegisterModel("ImportExclusions");
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -113,11 +113,11 @@ namespace NzbDrone.Core.DecisionEngine
|
||||||
var remoteMovie = result.RemoteMovie;
|
var remoteMovie = result.RemoteMovie;
|
||||||
|
|
||||||
remoteMovie.Release = report;
|
remoteMovie.Release = report;
|
||||||
|
remoteMovie.MappingResult = result.MappingResultType;
|
||||||
|
|
||||||
if (result.MappingResultType != MappingResultType.Success && result.MappingResultType != MappingResultType.SuccessLenientMapping)
|
if (result.MappingResultType != MappingResultType.Success && result.MappingResultType != MappingResultType.SuccessLenientMapping)
|
||||||
{
|
{
|
||||||
var rejection = result.ToRejection();
|
var rejection = result.ToRejection();
|
||||||
remoteMovie.Movie = null; // HACK: For now!
|
|
||||||
decision = new DownloadDecision(remoteMovie, rejection);
|
decision = new DownloadDecision(remoteMovie, rejection);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ namespace NzbDrone.Core.DecisionEngine
|
||||||
{
|
{
|
||||||
if (parsedMovieInfo.Quality.HardcodedSubs.IsNotNullOrWhiteSpace())
|
if (parsedMovieInfo.Quality.HardcodedSubs.IsNotNullOrWhiteSpace())
|
||||||
{
|
{
|
||||||
remoteMovie.DownloadAllowed = true;
|
//remoteMovie.DownloadAllowed = true;
|
||||||
if (_configService.AllowHardcodedSubs)
|
if (_configService.AllowHardcodedSubs)
|
||||||
{
|
{
|
||||||
decision = GetDecisionForReport(remoteMovie, searchCriteria);
|
decision = GetDecisionForReport(remoteMovie, searchCriteria);
|
||||||
|
@ -146,7 +146,7 @@ namespace NzbDrone.Core.DecisionEngine
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
remoteMovie.DownloadAllowed = true;
|
//remoteMovie.DownloadAllowed = true;
|
||||||
decision = GetDecisionForReport(remoteMovie, searchCriteria);
|
decision = GetDecisionForReport(remoteMovie, searchCriteria);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Core.Profiles.Delay;
|
using NzbDrone.Core.Profiles.Delay;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
|
using NzbDrone.Core.Parser;
|
||||||
|
|
||||||
namespace NzbDrone.Core.DecisionEngine
|
namespace NzbDrone.Core.DecisionEngine
|
||||||
{
|
{
|
||||||
|
@ -36,13 +37,13 @@ namespace NzbDrone.Core.DecisionEngine
|
||||||
|
|
||||||
public List<DownloadDecision> PrioritizeDecisionsForMovies(List<DownloadDecision> decisions)
|
public List<DownloadDecision> PrioritizeDecisionsForMovies(List<DownloadDecision> decisions)
|
||||||
{
|
{
|
||||||
return decisions.Where(c => c.RemoteMovie.Movie != null)
|
return decisions.Where(c => c.RemoteMovie.MappingResult == MappingResultType.Success || c.RemoteMovie.MappingResult == MappingResultType.SuccessLenientMapping)
|
||||||
.GroupBy(c => c.RemoteMovie.Movie.Id, (movieId, downloadDecisions) =>
|
.GroupBy(c => c.RemoteMovie.Movie.Id, (movieId, downloadDecisions) =>
|
||||||
{
|
{
|
||||||
return downloadDecisions.OrderByDescending(decision => decision, new DownloadDecisionComparer(_delayProfileService, _configService));
|
return downloadDecisions.OrderByDescending(decision => decision, new DownloadDecisionComparer(_delayProfileService, _configService));
|
||||||
})
|
})
|
||||||
.SelectMany(c => c)
|
.SelectMany(c => c)
|
||||||
.Union(decisions.Where(c => c.RemoteMovie.Movie == null))
|
.Union(decisions.Where(c => c.RemoteMovie.MappingResult != MappingResultType.Success || c.RemoteMovie.MappingResult != MappingResultType.SuccessLenientMapping))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace NzbDrone.Core.Download
|
||||||
public interface IDownloadService
|
public interface IDownloadService
|
||||||
{
|
{
|
||||||
void DownloadReport(RemoteEpisode remoteEpisode);
|
void DownloadReport(RemoteEpisode remoteEpisode);
|
||||||
void DownloadReport(RemoteMovie remoteMovie);
|
void DownloadReport(RemoteMovie remoteMovie, bool forceDownload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ namespace NzbDrone.Core.Download
|
||||||
_eventAggregator.PublishEvent(episodeGrabbedEvent);
|
_eventAggregator.PublishEvent(episodeGrabbedEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DownloadReport(RemoteMovie remoteMovie)
|
public void DownloadReport(RemoteMovie remoteMovie, bool foceDownload = false)
|
||||||
{
|
{
|
||||||
//Ensure.That(remoteEpisode.Series, () => remoteEpisode.Series).IsNotNull();
|
//Ensure.That(remoteEpisode.Series, () => remoteEpisode.Series).IsNotNull();
|
||||||
//Ensure.That(remoteEpisode.Episodes, () => remoteEpisode.Episodes).HasItems(); TODO update this shit
|
//Ensure.That(remoteEpisode.Episodes, () => remoteEpisode.Episodes).HasItems(); TODO update this shit
|
||||||
|
|
|
@ -88,7 +88,7 @@ namespace NzbDrone.Core.Download
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_downloadService.DownloadReport(remoteMovie);
|
_downloadService.DownloadReport(remoteMovie, false);
|
||||||
grabbed.Add(report);
|
grabbed.Add(report);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|
|
@ -59,7 +59,7 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var searchTitle = System.Web.HttpUtility.UrlPathEncode(Parser.Parser.ReplaceGermanUmlauts(Parser.Parser.NormalizeTitle(searchCriteria.Movie.Title)));
|
var searchTitle = System.Web.HttpUtility.UrlPathEncode(Parser.Parser.ReplaceGermanUmlauts(Parser.Parser.NormalizeTitle(searchCriteria.Movie.Title)));
|
||||||
var altTitles = searchCriteria.Movie.AlternativeTitles.DistinctBy(t => Parser.Parser.CleanSeriesTitle(t)).Take(5).ToList();
|
var altTitles = searchCriteria.Movie.AlternativeTitles.Take(5).Select(t => t.Title).ToList();
|
||||||
|
|
||||||
var realMaxPages = (int)MaxPages / (altTitles.Count() + 1);
|
var realMaxPages = (int)MaxPages / (altTitles.Count() + 1);
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,10 @@ using NzbDrone.Core.Configuration;
|
||||||
using System;
|
using System;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using NzbDrone.Core.MetadataSource.SkyHook.Resource;
|
using NzbDrone.Core.MetadataSource.SkyHook.Resource;
|
||||||
|
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||||
|
using NzbDrone.Core.Parser;
|
||||||
|
|
||||||
namespace NzbDrone.Core.MetadataSource.RadarrAPI
|
namespace NzbDrone.Core.MetadataSource.RadarrAPI
|
||||||
{
|
{
|
||||||
|
@ -11,6 +14,10 @@ namespace NzbDrone.Core.MetadataSource.RadarrAPI
|
||||||
{
|
{
|
||||||
IHttpRequestBuilderFactory RadarrAPI { get; }
|
IHttpRequestBuilderFactory RadarrAPI { get; }
|
||||||
List<MovieResult> DiscoverMovies(string action, Func<HttpRequest, HttpRequest> enhanceRequest);
|
List<MovieResult> DiscoverMovies(string action, Func<HttpRequest, HttpRequest> enhanceRequest);
|
||||||
|
List<AlternativeTitle> AlternativeTitlesForMovie(int TmdbId);
|
||||||
|
Tuple<List<AlternativeTitle>, AlternativeYear> AlternativeTitlesAndYearForMovie(int tmdbId);
|
||||||
|
AlternativeTitle AddNewAlternativeTitle(AlternativeTitle title, int TmdbId);
|
||||||
|
AlternativeYear AddNewAlternativeYear(int year, int tmdbId);
|
||||||
string APIURL { get; }
|
string APIURL { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +72,7 @@ namespace NzbDrone.Core.MetadataSource.RadarrAPI
|
||||||
{
|
{
|
||||||
var error = JsonConvert.DeserializeObject<RadarrError>(response.Content);
|
var error = JsonConvert.DeserializeObject<RadarrError>(response.Content);
|
||||||
|
|
||||||
if (error != null && error.Errors.Count != 0)
|
if (error != null && error.Errors != null && error.Errors.Count != 0)
|
||||||
{
|
{
|
||||||
throw new RadarrAPIException(error);
|
throw new RadarrAPIException(error);
|
||||||
}
|
}
|
||||||
|
@ -96,6 +103,83 @@ namespace NzbDrone.Core.MetadataSource.RadarrAPI
|
||||||
return Execute<List<MovieResult>>(request);
|
return Execute<List<MovieResult>>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<AlternativeTitle> AlternativeTitlesForMovie(int TmdbId)
|
||||||
|
{
|
||||||
|
var request = RadarrAPI.Create().SetSegment("route", "mappings").SetSegment("action", "find").AddQueryParam("tmdbid", TmdbId).Build();
|
||||||
|
|
||||||
|
var mappings = Execute<Mapping>(request);
|
||||||
|
|
||||||
|
var titles = new List<NzbDrone.Core.Movies.AlternativeTitles.AlternativeTitle>();
|
||||||
|
|
||||||
|
foreach (var altTitle in mappings.Mappings.Titles)
|
||||||
|
{
|
||||||
|
titles.Add(new NzbDrone.Core.Movies.AlternativeTitles.AlternativeTitle(altTitle.Info.AkaTitle, SourceType.Mappings, altTitle.Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
return titles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tuple<List<AlternativeTitle>, AlternativeYear> AlternativeTitlesAndYearForMovie(int tmdbId)
|
||||||
|
{
|
||||||
|
var request = RadarrAPI.Create().SetSegment("route", "mappings").SetSegment("action", "find").AddQueryParam("tmdbid", tmdbId).Build();
|
||||||
|
|
||||||
|
var mappings = Execute<Mapping>(request);
|
||||||
|
|
||||||
|
var titles = new List<NzbDrone.Core.Movies.AlternativeTitles.AlternativeTitle>();
|
||||||
|
|
||||||
|
foreach (var altTitle in mappings.Mappings.Titles)
|
||||||
|
{
|
||||||
|
titles.Add(new NzbDrone.Core.Movies.AlternativeTitles.AlternativeTitle(altTitle.Info.AkaTitle, SourceType.Mappings, altTitle.Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
var year = mappings.Mappings.Years.Where(y => y.Votes >= 3).OrderBy(y => y.Votes).FirstOrDefault();
|
||||||
|
|
||||||
|
AlternativeYear newYear = null;
|
||||||
|
|
||||||
|
if (year != null)
|
||||||
|
{
|
||||||
|
newYear = new AlternativeYear
|
||||||
|
{
|
||||||
|
Year = year.Info.AkaYear,
|
||||||
|
SourceId = year.Id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Tuple<List<AlternativeTitle>, AlternativeYear>(titles, newYear);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlternativeTitle AddNewAlternativeTitle(AlternativeTitle title, int TmdbId)
|
||||||
|
{
|
||||||
|
var request = RadarrAPI.Create().SetSegment("route", "mappings").SetSegment("action", "add")
|
||||||
|
.AddQueryParam("tmdbid", TmdbId).AddQueryParam("type", "title")
|
||||||
|
.AddQueryParam("language", IsoLanguages.Get(title.Language).TwoLetterCode)
|
||||||
|
.AddQueryParam("aka_title", title.Title).Build();
|
||||||
|
|
||||||
|
var newMapping = Execute<AddTitleMapping>(request);
|
||||||
|
|
||||||
|
var newTitle = new AlternativeTitle(newMapping.Info.AkaTitle, SourceType.Mappings, newMapping.Id, title.Language);
|
||||||
|
newTitle.VoteCount = newMapping.VoteCount;
|
||||||
|
newTitle.Votes = newMapping.Votes;
|
||||||
|
|
||||||
|
return newTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlternativeYear AddNewAlternativeYear(int year, int tmdbId)
|
||||||
|
{
|
||||||
|
var request = RadarrAPI.Create().SetSegment("route", "mappings").SetSegment("action", "add")
|
||||||
|
.AddQueryParam("tmdbid", tmdbId).AddQueryParam("type", "year")
|
||||||
|
.AddQueryParam("aka_year", year).Build();
|
||||||
|
|
||||||
|
var newYear = Execute<AddYearMapping>(request);
|
||||||
|
|
||||||
|
return new AlternativeYear
|
||||||
|
{
|
||||||
|
Year = newYear.Info.AkaYear,
|
||||||
|
SourceId = newYear.Id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public IHttpRequestBuilderFactory RadarrAPI { get; private set; }
|
public IHttpRequestBuilderFactory RadarrAPI { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,21 +27,183 @@ namespace NzbDrone.Core.MetadataSource.RadarrAPI
|
||||||
|
|
||||||
public class RadarrAPIException : Exception
|
public class RadarrAPIException : Exception
|
||||||
{
|
{
|
||||||
RadarrError APIErrors;
|
public RadarrError APIErrors;
|
||||||
|
|
||||||
public RadarrAPIException(RadarrError apiError) : base(HumanReadable(apiError))
|
public RadarrAPIException(RadarrError apiError) : base(HumanReadable(apiError))
|
||||||
{
|
{
|
||||||
|
APIErrors = apiError;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string HumanReadable(RadarrError APIErrors)
|
private static string HumanReadable(RadarrError apiErrors)
|
||||||
{
|
{
|
||||||
var firstError = APIErrors.Errors.First();
|
var firstError = apiErrors.Errors.First();
|
||||||
var details = string.Join("\n", APIErrors.Errors.Select(error =>
|
var details = string.Join("\n", apiErrors.Errors.Select(error =>
|
||||||
{
|
{
|
||||||
return $"{error.Title} ({error.Status}, RayId: {error.RayId}), Details: {error.Detail}";
|
return $"{error.Title} ({error.Status}, RayId: {error.RayId}), Details: {error.Detail}";
|
||||||
}));
|
}));
|
||||||
return $"Error while calling api: {firstError.Title}\nFull error(s): {details}";
|
return $"Error while calling api: {firstError.Title}\nFull error(s): {details}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class TitleInfo
|
||||||
|
{
|
||||||
|
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("aka_title")]
|
||||||
|
public string AkaTitle { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("aka_clean_title")]
|
||||||
|
public string AkaCleanTitle { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class YearInfo
|
||||||
|
{
|
||||||
|
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("aka_year")]
|
||||||
|
public int AkaYear { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Title
|
||||||
|
{
|
||||||
|
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("tmdbid")]
|
||||||
|
public int Tmdbid { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("votes")]
|
||||||
|
public int Votes { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("vote_count")]
|
||||||
|
public int VoteCount { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("locked")]
|
||||||
|
public bool Locked { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("info_type")]
|
||||||
|
public string InfoType { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("info_id")]
|
||||||
|
public int InfoId { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("info")]
|
||||||
|
public TitleInfo Info { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Year
|
||||||
|
{
|
||||||
|
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("tmdbid")]
|
||||||
|
public int Tmdbid { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("votes")]
|
||||||
|
public int Votes { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("vote_count")]
|
||||||
|
public int VoteCount { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("locked")]
|
||||||
|
public bool Locked { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("info_type")]
|
||||||
|
public string InfoType { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("info_id")]
|
||||||
|
public int InfoId { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("info")]
|
||||||
|
public YearInfo Info { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Mappings
|
||||||
|
{
|
||||||
|
|
||||||
|
[JsonProperty("titles")]
|
||||||
|
public IList<Title> Titles { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("years")]
|
||||||
|
public IList<Year> Years { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Mapping
|
||||||
|
{
|
||||||
|
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("title")]
|
||||||
|
public string Title { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("imdb_id")]
|
||||||
|
public string ImdbId { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("mappings")]
|
||||||
|
public Mappings Mappings { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AddTitleMapping
|
||||||
|
{
|
||||||
|
|
||||||
|
[JsonProperty("tmdbid")]
|
||||||
|
public string Tmdbid { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("info_type")]
|
||||||
|
public string InfoType { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("info_id")]
|
||||||
|
public int InfoId { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("info")]
|
||||||
|
public TitleInfo Info { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("votes")]
|
||||||
|
public int Votes { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("vote_count")]
|
||||||
|
public int VoteCount { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("locked")]
|
||||||
|
public bool Locked { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AddYearMapping
|
||||||
|
{
|
||||||
|
|
||||||
|
[JsonProperty("tmdbid")]
|
||||||
|
public string Tmdbid { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("info_type")]
|
||||||
|
public string InfoType { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("info_id")]
|
||||||
|
public int InfoId { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("info")]
|
||||||
|
public YearInfo Info { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("votes")]
|
||||||
|
public int Votes { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("vote_count")]
|
||||||
|
public int VoteCount { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("locked")]
|
||||||
|
public bool Locked { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.ServiceModel;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Cloud;
|
using NzbDrone.Common.Cloud;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
|
@ -19,6 +20,7 @@ using NzbDrone.Common.Serializer;
|
||||||
using NzbDrone.Core.NetImport.ImportExclusions;
|
using NzbDrone.Core.NetImport.ImportExclusions;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.MetadataSource.RadarrAPI;
|
using NzbDrone.Core.MetadataSource.RadarrAPI;
|
||||||
|
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||||
|
|
||||||
namespace NzbDrone.Core.MetadataSource.SkyHook
|
namespace NzbDrone.Core.MetadataSource.SkyHook
|
||||||
{
|
{
|
||||||
|
@ -33,12 +35,13 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
||||||
private readonly IMovieService _movieService;
|
private readonly IMovieService _movieService;
|
||||||
private readonly IPreDBService _predbService;
|
private readonly IPreDBService _predbService;
|
||||||
private readonly IImportExclusionsService _exclusionService;
|
private readonly IImportExclusionsService _exclusionService;
|
||||||
|
private readonly IAlternativeTitleService _altTitleService;
|
||||||
private readonly IRadarrAPIClient _radarrAPI;
|
private readonly IRadarrAPIClient _radarrAPI;
|
||||||
|
|
||||||
private readonly IHttpRequestBuilderFactory _apiBuilder;
|
private readonly IHttpRequestBuilderFactory _apiBuilder;
|
||||||
|
|
||||||
public SkyHookProxy(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBuilder, ITmdbConfigService configService, IMovieService movieService,
|
public SkyHookProxy(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBuilder, ITmdbConfigService configService, IMovieService movieService,
|
||||||
IPreDBService predbService, IImportExclusionsService exclusionService, IRadarrAPIClient radarrAPI, Logger logger)
|
IPreDBService predbService, IImportExclusionsService exclusionService, IAlternativeTitleService altTitleService, IRadarrAPIClient radarrAPI, Logger logger)
|
||||||
{
|
{
|
||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
_requestBuilder = requestBuilder.SkyHookTvdb;
|
_requestBuilder = requestBuilder.SkyHookTvdb;
|
||||||
|
@ -47,6 +50,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
||||||
_movieService = movieService;
|
_movieService = movieService;
|
||||||
_predbService = predbService;
|
_predbService = predbService;
|
||||||
_exclusionService = exclusionService;
|
_exclusionService = exclusionService;
|
||||||
|
_altTitleService = altTitleService;
|
||||||
_radarrAPI = radarrAPI;
|
_radarrAPI = radarrAPI;
|
||||||
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
@ -133,21 +137,28 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
||||||
}
|
}
|
||||||
|
|
||||||
var movie = new Movie();
|
var movie = new Movie();
|
||||||
|
var altTitles = new List<AlternativeTitle>();
|
||||||
|
|
||||||
if (langCode != "us")
|
if (langCode != "en")
|
||||||
{
|
{
|
||||||
movie.AlternativeTitles.Add(resource.original_title);
|
var iso = IsoLanguages.Find(resource.original_language);
|
||||||
|
if (iso != null)
|
||||||
|
{
|
||||||
|
altTitles.Add(new AlternativeTitle(resource.original_title, SourceType.TMDB, TmdbId, iso.Language));
|
||||||
|
}
|
||||||
|
|
||||||
|
//movie.AlternativeTitles.Add(resource.original_title);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var alternativeTitle in resource.alternative_titles.titles)
|
foreach (var alternativeTitle in resource.alternative_titles.titles)
|
||||||
{
|
{
|
||||||
if (alternativeTitle.iso_3166_1.ToLower() == langCode)
|
if (alternativeTitle.iso_3166_1.ToLower() == langCode)
|
||||||
{
|
{
|
||||||
movie.AlternativeTitles.Add(alternativeTitle.title);
|
altTitles.Add(new AlternativeTitle(alternativeTitle.title, SourceType.TMDB, TmdbId, IsoLanguages.Find(alternativeTitle.iso_3166_1.ToLower()).Language));
|
||||||
}
|
}
|
||||||
else if (alternativeTitle.iso_3166_1.ToLower() == "us")
|
else if (alternativeTitle.iso_3166_1.ToLower() == "us")
|
||||||
{
|
{
|
||||||
movie.AlternativeTitles.Add(alternativeTitle.title);
|
altTitles.Add(new AlternativeTitle(alternativeTitle.title, SourceType.TMDB, TmdbId, Language.English));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,6 +332,8 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
movie.AlternativeTitles.AddRange(altTitles);
|
||||||
|
|
||||||
return movie;
|
return movie;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
using System;
|
||||||
|
using Marr.Data;
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
using NzbDrone.Core.Parser;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Movies.AlternativeTitles
|
||||||
|
{
|
||||||
|
public class AlternativeTitle : ModelBase
|
||||||
|
{
|
||||||
|
public SourceType SourceType { get; set; }
|
||||||
|
public int MovieId { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string CleanTitle { get; set; }
|
||||||
|
public int SourceId { get; set; }
|
||||||
|
public int Votes { get; set; }
|
||||||
|
public int VoteCount { get; set; }
|
||||||
|
public Language Language { get; set; }
|
||||||
|
public LazyLoaded<Movie> Movie { get; set; }
|
||||||
|
|
||||||
|
public AlternativeTitle()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlternativeTitle(string title, SourceType sourceType = SourceType.TMDB, int sourceId = 0, Language language = Language.English)
|
||||||
|
{
|
||||||
|
Title = title;
|
||||||
|
CleanTitle = title.CleanSeriesTitle();
|
||||||
|
SourceType = sourceType;
|
||||||
|
SourceId = sourceId;
|
||||||
|
Language = language;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsTrusted(int minVotes = 3)
|
||||||
|
{
|
||||||
|
switch (SourceType)
|
||||||
|
{
|
||||||
|
case SourceType.TMDB:
|
||||||
|
return Votes >= minVotes;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
var item = obj as AlternativeTitle;
|
||||||
|
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return item.CleanTitle == this.CleanTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override String ToString()
|
||||||
|
{
|
||||||
|
return Title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SourceType
|
||||||
|
{
|
||||||
|
TMDB = 0,
|
||||||
|
Mappings = 1,
|
||||||
|
User = 2,
|
||||||
|
Indexer = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AlternativeYear
|
||||||
|
{
|
||||||
|
public int Year { get; set; }
|
||||||
|
public int SourceId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Movies.AlternativeTitles
|
||||||
|
{
|
||||||
|
public interface IAlternativeTitleRepository : IBasicRepository<AlternativeTitle>
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AlternativeTitleRepository : BasicRepository<AlternativeTitle>, IAlternativeTitleRepository
|
||||||
|
{
|
||||||
|
protected IMainDatabase _database;
|
||||||
|
|
||||||
|
public AlternativeTitleRepository(IMainDatabase database, IEventAggregator eventAggregator)
|
||||||
|
: base(database, eventAggregator)
|
||||||
|
{
|
||||||
|
_database = database;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common.EnsureThat;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Core.DataAugmentation.Scene;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.Organizer;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
using NzbDrone.Core.Tv.Events;
|
||||||
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.MediaFiles.Events;
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Movies.AlternativeTitles
|
||||||
|
{
|
||||||
|
public interface IAlternativeTitleService
|
||||||
|
{
|
||||||
|
List<AlternativeTitle> GetAllTitlesForMovie(Movie movie);
|
||||||
|
AlternativeTitle AddAltTitle(AlternativeTitle title, Movie movie);
|
||||||
|
List<AlternativeTitle> AddAltTitles(List<AlternativeTitle> titles, Movie movie);
|
||||||
|
AlternativeTitle GetById(int id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AlternativeTitleService : IAlternativeTitleService
|
||||||
|
{
|
||||||
|
private readonly IAlternativeTitleRepository _titleRepo;
|
||||||
|
private readonly IConfigService _configService;
|
||||||
|
private readonly IEventAggregator _eventAggregator;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
|
||||||
|
public AlternativeTitleService(IAlternativeTitleRepository titleRepo,
|
||||||
|
IEventAggregator eventAggregator,
|
||||||
|
IConfigService configService,
|
||||||
|
Logger logger)
|
||||||
|
{
|
||||||
|
_titleRepo = titleRepo;
|
||||||
|
_eventAggregator = eventAggregator;
|
||||||
|
_configService = configService;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AlternativeTitle> GetAllTitlesForMovie(Movie movie)
|
||||||
|
{
|
||||||
|
return _titleRepo.All().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlternativeTitle AddAltTitle(AlternativeTitle title, Movie movie)
|
||||||
|
{
|
||||||
|
title.MovieId = movie.Id;
|
||||||
|
return _titleRepo.Insert(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AlternativeTitle> AddAltTitles(List<AlternativeTitle> titles, Movie movie)
|
||||||
|
{
|
||||||
|
titles.ForEach(t => t.MovieId = movie.Id);
|
||||||
|
_titleRepo.InsertMany(titles);
|
||||||
|
return titles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlternativeTitle GetById(int id)
|
||||||
|
{
|
||||||
|
return _titleRepo.Get(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -125,6 +125,7 @@
|
||||||
<Compile Include="Authentication\UserRepository.cs" />
|
<Compile Include="Authentication\UserRepository.cs" />
|
||||||
<Compile Include="Authentication\UserService.cs" />
|
<Compile Include="Authentication\UserService.cs" />
|
||||||
<Compile Include="Datastore\Migration\123_create_netimport_table.cs" />
|
<Compile Include="Datastore\Migration\123_create_netimport_table.cs" />
|
||||||
|
<Compile Include="Datastore\Migration\140_add_alternative_titles_table.cs" />
|
||||||
<Compile Include="MediaFiles\Events\MovieFileUpdatedEvent.cs" />
|
<Compile Include="MediaFiles\Events\MovieFileUpdatedEvent.cs" />
|
||||||
<Compile Include="Datastore\Migration\134_add_remux_qualities_for_the_wankers.cs" />
|
<Compile Include="Datastore\Migration\134_add_remux_qualities_for_the_wankers.cs" />
|
||||||
<Compile Include="Datastore\Migration\129_add_parsed_movie_info_to_pending_release.cs" />
|
<Compile Include="Datastore\Migration\129_add_parsed_movie_info_to_pending_release.cs" />
|
||||||
|
@ -134,6 +135,9 @@
|
||||||
<Compile Include="Datastore\Migration\133_add_minimumavailability.cs" />
|
<Compile Include="Datastore\Migration\133_add_minimumavailability.cs" />
|
||||||
<Compile Include="IndexerSearch\CutoffUnmetMoviesSearchCommand.cs" />
|
<Compile Include="IndexerSearch\CutoffUnmetMoviesSearchCommand.cs" />
|
||||||
<Compile Include="Indexers\HDBits\HDBitsInfo.cs" />
|
<Compile Include="Indexers\HDBits\HDBitsInfo.cs" />
|
||||||
|
<Compile Include="Movies\AlternativeTitles\AlternativeTitle.cs" />
|
||||||
|
<Compile Include="Movies\AlternativeTitles\AlternativeTitleRepository.cs" />
|
||||||
|
<Compile Include="Movies\AlternativeTitles\AlternativeTitleService.cs" />
|
||||||
<Compile Include="NetImport\NetImportListLevels.cs" />
|
<Compile Include="NetImport\NetImportListLevels.cs" />
|
||||||
<Compile Include="NetImport\TMDb\TMDbLanguageCodes.cs" />
|
<Compile Include="NetImport\TMDb\TMDbLanguageCodes.cs" />
|
||||||
<Compile Include="NetImport\TMDb\TMDbSettings.cs" />
|
<Compile Include="NetImport\TMDb\TMDbSettings.cs" />
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace NzbDrone.Core.Parser.Model
|
||||||
public ParsedEpisodeInfo ParsedEpisodeInfo { get; set; } //TODO: Change to ParsedMovieInfo, for now though ParsedEpisodeInfo will do.
|
public ParsedEpisodeInfo ParsedEpisodeInfo { get; set; } //TODO: Change to ParsedMovieInfo, for now though ParsedEpisodeInfo will do.
|
||||||
public ParsedMovieInfo ParsedMovieInfo { get; set; }
|
public ParsedMovieInfo ParsedMovieInfo { get; set; }
|
||||||
public Movie Movie { get; set; }
|
public Movie Movie { get; set; }
|
||||||
public bool DownloadAllowed { get; set; }
|
public MappingResultType MappingResult { get; set; }
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,6 +9,7 @@ using NzbDrone.Core.DataAugmentation.Scene;
|
||||||
using NzbDrone.Core.DecisionEngine;
|
using NzbDrone.Core.DecisionEngine;
|
||||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.Parser.RomanNumerals;
|
using NzbDrone.Core.Parser.RomanNumerals;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
|
@ -381,7 +382,7 @@ namespace NzbDrone.Core.Parser
|
||||||
{
|
{
|
||||||
var movie = _movieService.FindByImdbId(imdbId);
|
var movie = _movieService.FindByImdbId(imdbId);
|
||||||
//Should fix practically all problems, where indexer is shite at adding correct imdbids to movies.
|
//Should fix practically all problems, where indexer is shite at adding correct imdbids to movies.
|
||||||
if (movie != null && parsedMovieInfo.Year > 1800 && parsedMovieInfo.Year != movie.Year)
|
if (movie != null && parsedMovieInfo.Year > 1800 && (parsedMovieInfo.Year != movie.Year && movie.SecondaryYear != parsedMovieInfo.Year))
|
||||||
{
|
{
|
||||||
result = new MappingResult { Movie = movie, MappingResultType = MappingResultType.WrongYear};
|
result = new MappingResult { Movie = movie, MappingResultType = MappingResultType.WrongYear};
|
||||||
return false;
|
return false;
|
||||||
|
@ -458,9 +459,9 @@ namespace NzbDrone.Core.Parser
|
||||||
|
|
||||||
possibleTitles.Add(searchCriteria.Movie.CleanTitle);
|
possibleTitles.Add(searchCriteria.Movie.CleanTitle);
|
||||||
|
|
||||||
foreach (string altTitle in searchCriteria.Movie.AlternativeTitles)
|
foreach (AlternativeTitle altTitle in searchCriteria.Movie.AlternativeTitles)
|
||||||
{
|
{
|
||||||
possibleTitles.Add(altTitle.CleanSeriesTitle());
|
possibleTitles.Add(altTitle.CleanTitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
string cleanTitle = parsedMovieInfo.MovieTitle.CleanSeriesTitle();
|
string cleanTitle = parsedMovieInfo.MovieTitle.CleanSeriesTitle();
|
||||||
|
@ -494,7 +495,7 @@ namespace NzbDrone.Core.Parser
|
||||||
|
|
||||||
if (possibleMovie != null)
|
if (possibleMovie != null)
|
||||||
{
|
{
|
||||||
if (parsedMovieInfo.Year < 1800 || possibleMovie.Year == parsedMovieInfo.Year)
|
if (parsedMovieInfo.Year < 1800 || possibleMovie.Year == parsedMovieInfo.Year || possibleMovie.SecondaryYear == parsedMovieInfo.Year)
|
||||||
{
|
{
|
||||||
result = new MappingResult { Movie = possibleMovie, MappingResultType = MappingResultType.Success };
|
result = new MappingResult { Movie = possibleMovie, MappingResultType = MappingResultType.Success };
|
||||||
return true;
|
return true;
|
||||||
|
@ -509,7 +510,7 @@ namespace NzbDrone.Core.Parser
|
||||||
cleanTitle.Contains(searchCriteria.Movie.CleanTitle))
|
cleanTitle.Contains(searchCriteria.Movie.CleanTitle))
|
||||||
{
|
{
|
||||||
possibleMovie = searchCriteria.Movie;
|
possibleMovie = searchCriteria.Movie;
|
||||||
if (parsedMovieInfo.Year > 1800 && parsedMovieInfo.Year == possibleMovie.Year)
|
if (parsedMovieInfo.Year > 1800 && parsedMovieInfo.Year == possibleMovie.Year || possibleMovie.SecondaryYear == parsedMovieInfo.Year)
|
||||||
{
|
{
|
||||||
result = new MappingResult {Movie = possibleMovie, MappingResultType = MappingResultType.SuccessLenientMapping};
|
result = new MappingResult {Movie = possibleMovie, MappingResultType = MappingResultType.SuccessLenientMapping};
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -6,6 +6,8 @@ using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.Profiles;
|
using NzbDrone.Core.Profiles;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using NzbDrone.Core.Movies;
|
||||||
|
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Tv
|
namespace NzbDrone.Core.Tv
|
||||||
{
|
{
|
||||||
|
@ -17,7 +19,7 @@ namespace NzbDrone.Core.Tv
|
||||||
Genres = new List<string>();
|
Genres = new List<string>();
|
||||||
Actors = new List<Actor>();
|
Actors = new List<Actor>();
|
||||||
Tags = new HashSet<int>();
|
Tags = new HashSet<int>();
|
||||||
AlternativeTitles = new List<string>();
|
AlternativeTitles = new List<AlternativeTitle>();
|
||||||
}
|
}
|
||||||
public int TmdbId { get; set; }
|
public int TmdbId { get; set; }
|
||||||
public string ImdbId { get; set; }
|
public string ImdbId { get; set; }
|
||||||
|
@ -52,7 +54,10 @@ namespace NzbDrone.Core.Tv
|
||||||
public LazyLoaded<MovieFile> MovieFile { get; set; }
|
public LazyLoaded<MovieFile> MovieFile { get; set; }
|
||||||
public bool HasPreDBEntry { get; set; }
|
public bool HasPreDBEntry { get; set; }
|
||||||
public int MovieFileId { get; set; }
|
public int MovieFileId { get; set; }
|
||||||
public List<string> AlternativeTitles { get; set; }
|
//Get Loaded via a Join Query
|
||||||
|
public List<AlternativeTitle> AlternativeTitles { get; set; }
|
||||||
|
public int? SecondaryYear { get; set; }
|
||||||
|
public int SecondaryYearSourceId { get; set; }
|
||||||
public string YouTubeTrailerId{ get; set; }
|
public string YouTubeTrailerId{ get; set; }
|
||||||
public string Studio { get; set; }
|
public string Studio { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.Datastore.Extensions;
|
using NzbDrone.Core.Datastore.Extensions;
|
||||||
using Marr.Data.QGen;
|
using Marr.Data.QGen;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||||
using NzbDrone.Core.Parser.RomanNumerals;
|
using NzbDrone.Core.Parser.RomanNumerals;
|
||||||
using NzbDrone.Core.Qualities;
|
using NzbDrone.Core.Qualities;
|
||||||
using CoreParser = NzbDrone.Core.Parser.Parser;
|
using CoreParser = NzbDrone.Core.Parser.Parser;
|
||||||
|
@ -103,7 +104,7 @@ namespace NzbDrone.Core.Tv
|
||||||
|
|
||||||
public override PagingSpec<Movie> GetPaged(PagingSpec<Movie> pagingSpec)
|
public override PagingSpec<Movie> GetPaged(PagingSpec<Movie> pagingSpec)
|
||||||
{
|
{
|
||||||
if (pagingSpec.SortKey == "downloadedQuality")
|
/*if (pagingSpec.SortKey == "downloadedQuality")
|
||||||
{
|
{
|
||||||
var mapper = _database.GetDataMapper();
|
var mapper = _database.GetDataMapper();
|
||||||
var offset = pagingSpec.PagingOffset();
|
var offset = pagingSpec.PagingOffset();
|
||||||
|
@ -113,7 +114,7 @@ namespace NzbDrone.Core.Tv
|
||||||
{
|
{
|
||||||
direction = "DESC";
|
direction = "DESC";
|
||||||
}
|
}
|
||||||
var q = mapper.Query<Movie>($"SELECT * from \"Movies\" , \"MovieFiles\", \"QualityDefinitions\" WHERE Movies.MovieFileId=MovieFiles.Id AND instr(MovieFiles.Quality, ('quality\": ' || QualityDefinitions.Quality || \",\")) > 0 ORDER BY QualityDefinitions.Title {direction} LIMIT {offset},{limit};");
|
var q = Query.Select($"SELECT * from \"Movies\" , \"MovieFiles\", \"QualityDefinitions\" WHERE Movies.MovieFileId=MovieFiles.Id AND instr(MovieFiles.Quality, ('quality\": ' || QualityDefinitions.Quality || \",\")) > 0 ORDER BY QualityDefinitions.Title {direction} LIMIT {offset},{limit};");
|
||||||
var q2 = mapper.Query<Movie>("SELECT * from \"Movies\" , \"MovieFiles\", \"QualityDefinitions\" WHERE Movies.MovieFileId=MovieFiles.Id AND instr(MovieFiles.Quality, ('quality\": ' || QualityDefinitions.Quality || \",\")) > 0 ORDER BY QualityDefinitions.Title ASC;");
|
var q2 = mapper.Query<Movie>("SELECT * from \"Movies\" , \"MovieFiles\", \"QualityDefinitions\" WHERE Movies.MovieFileId=MovieFiles.Id AND instr(MovieFiles.Quality, ('quality\": ' || QualityDefinitions.Quality || \",\")) > 0 ORDER BY QualityDefinitions.Title ASC;");
|
||||||
|
|
||||||
//var ok = q.BuildQuery();
|
//var ok = q.BuildQuery();
|
||||||
|
@ -122,9 +123,11 @@ namespace NzbDrone.Core.Tv
|
||||||
pagingSpec.TotalRecords = q2.Count();
|
pagingSpec.TotalRecords = q2.Count();
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else*/
|
||||||
{
|
{
|
||||||
pagingSpec = base.GetPaged(pagingSpec);
|
pagingSpec = base.GetPaged(pagingSpec);
|
||||||
|
//pagingSpec.Records = GetPagedQuery(Query, pagingSpec).ToList();
|
||||||
|
//pagingSpec.TotalRecords = GetPagedQuery(Query, pagingSpec).GetRowCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pagingSpec.Records.Count == 0 && pagingSpec.Page != 1)
|
if (pagingSpec.Records.Count == 0 && pagingSpec.Page != 1)
|
||||||
|
@ -137,6 +140,22 @@ namespace NzbDrone.Core.Tv
|
||||||
return pagingSpec;
|
return pagingSpec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*protected override SortBuilder<Movie> GetPagedQuery(QueryBuilder<Movie> query, PagingSpec<Movie> pagingSpec)
|
||||||
|
{
|
||||||
|
return DataMapper.Query<Movie>().Join<Movie, AlternativeTitle>(JoinType.Left, m => m.AlternativeTitles,
|
||||||
|
(m, t) => m.Id == t.MovieId).Where(pagingSpec.FilterExpression)
|
||||||
|
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection())
|
||||||
|
.Skip(pagingSpec.PagingOffset())
|
||||||
|
.Take(pagingSpec.PageSize);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*protected override SortBuilder<Movie> GetPagedQuery(QueryBuilder<Movie> query, PagingSpec<Movie> pagingSpec)
|
||||||
|
{
|
||||||
|
var newQuery = base.GetPagedQuery(query.Join<Movie, AlternativeTitle>(JoinType.Left, m => m.JoinAlternativeTitles, (movie, title) => title.MovieId == movie.Id), pagingSpec);
|
||||||
|
System.Console.WriteLine(newQuery.ToString());
|
||||||
|
return newQuery;
|
||||||
|
}*/
|
||||||
|
|
||||||
public SortBuilder<Movie> GetMoviesWithoutFilesQuery(PagingSpec<Movie> pagingSpec)
|
public SortBuilder<Movie> GetMoviesWithoutFilesQuery(PagingSpec<Movie> pagingSpec)
|
||||||
{
|
{
|
||||||
return Query.Where(pagingSpec.FilterExpression)
|
return Query.Where(pagingSpec.FilterExpression)
|
||||||
|
@ -247,24 +266,41 @@ namespace NzbDrone.Core.Tv
|
||||||
|
|
||||||
if (result == null)
|
if (result == null)
|
||||||
{
|
{
|
||||||
IEnumerable<Movie> movies = All();
|
/*IEnumerable<Movie> movies = All();
|
||||||
Func<string, string> titleCleaner = title => CoreParser.CleanSeriesTitle(title.ToLower());
|
Func<string, string> titleCleaner = title => CoreParser.CleanSeriesTitle(title.ToLower());
|
||||||
Func<IEnumerable<string>, string, bool> altTitleComparer =
|
Func<IEnumerable<AlternativeTitle>, string, bool> altTitleComparer =
|
||||||
(alternativeTitles, atitle) =>
|
(alternativeTitles, atitle) =>
|
||||||
alternativeTitles.Any(altTitle => titleCleaner(altTitle) == atitle);
|
alternativeTitles.Any(altTitle => altTitle.CleanTitle == atitle);*/
|
||||||
|
|
||||||
result = movies.Where(m => altTitleComparer(m.AlternativeTitles, cleanTitle) ||
|
/*result = movies.Where(m => altTitleComparer(m.AlternativeTitles, cleanTitle) ||
|
||||||
altTitleComparer(m.AlternativeTitles, cleanTitleWithRomanNumbers) ||
|
altTitleComparer(m.AlternativeTitles, cleanTitleWithRomanNumbers) ||
|
||||||
altTitleComparer(m.AlternativeTitles, cleanTitleWithArabicNumbers)).FirstWithYear(year);
|
altTitleComparer(m.AlternativeTitles, cleanTitleWithArabicNumbers)).FirstWithYear(year);*/
|
||||||
|
|
||||||
|
//result = Query.Join<Movie, AlternativeTitle>(JoinType.Inner, m => m._newAltTitles,
|
||||||
|
//(m, t) => m.Id == t.MovieId && (t.CleanTitle == cleanTitle)).FirstWithYear(year);
|
||||||
|
result = Query.Where<AlternativeTitle>(t =>
|
||||||
|
t.CleanTitle == cleanTitle || t.CleanTitle == cleanTitleWithArabicNumbers
|
||||||
|
|| t.CleanTitle == cleanTitleWithRomanNumbers).FirstWithYear(year);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
/*return year.HasValue
|
/*return year.HasValue
|
||||||
? results?.FirstOrDefault(movie => movie.Year == year.Value)
|
? results?.FirstOrDefault(movie => movie.Year == year.Value)
|
||||||
|
|
||||||
|
|
||||||
: results?.FirstOrDefault();*/
|
: results?.FirstOrDefault();*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override QueryBuilder<Movie> AddJoinQueries(QueryBuilder<Movie> baseQuery)
|
||||||
|
{
|
||||||
|
baseQuery = base.AddJoinQueries(baseQuery);
|
||||||
|
baseQuery = baseQuery.Join<Movie, AlternativeTitle>(JoinType.Left, m => m.AlternativeTitles,
|
||||||
|
(m, t) => m.Id == t.MovieId);
|
||||||
|
|
||||||
|
return baseQuery;
|
||||||
|
}
|
||||||
|
|
||||||
public Movie FindByTmdbId(int tmdbid)
|
public Movie FindByTmdbId(int tmdbid)
|
||||||
{
|
{
|
||||||
return Query.Where(m => m.TmdbId == tmdbid).FirstOrDefault();
|
return Query.Where(m => m.TmdbId == tmdbid).FirstOrDefault();
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace NzbDrone.Core
|
||||||
{
|
{
|
||||||
public static Movie FirstWithYear(this SortBuilder<Movie> query, int? year)
|
public static Movie FirstWithYear(this SortBuilder<Movie> query, int? year)
|
||||||
{
|
{
|
||||||
return year.HasValue ? query.FirstOrDefault(movie => movie.Year == year) : query.FirstOrDefault();
|
return year.HasValue ? query.FirstOrDefault(movie => movie.Year == year || movie.SecondaryYear == year) : query.FirstOrDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ namespace NzbDrone.Core
|
||||||
{
|
{
|
||||||
public static Movie FirstWithYear(this IEnumerable<Movie> query, int? year)
|
public static Movie FirstWithYear(this IEnumerable<Movie> query, int? year)
|
||||||
{
|
{
|
||||||
return year.HasValue ? query.FirstOrDefault(movie => movie.Year == year) : query.FirstOrDefault();
|
return year.HasValue ? query.FirstOrDefault(movie => movie.Year == year || movie.SecondaryYear == year) : query.FirstOrDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@ using NzbDrone.Core.MetadataSource;
|
||||||
using NzbDrone.Core.Tv.Commands;
|
using NzbDrone.Core.Tv.Commands;
|
||||||
using NzbDrone.Core.Tv.Events;
|
using NzbDrone.Core.Tv.Events;
|
||||||
using NzbDrone.Core.MediaFiles.Commands;
|
using NzbDrone.Core.MediaFiles.Commands;
|
||||||
|
using NzbDrone.Core.MetadataSource.RadarrAPI;
|
||||||
|
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Tv
|
namespace NzbDrone.Core.Tv
|
||||||
{
|
{
|
||||||
|
@ -21,26 +23,33 @@ namespace NzbDrone.Core.Tv
|
||||||
{
|
{
|
||||||
private readonly IProvideMovieInfo _movieInfo;
|
private readonly IProvideMovieInfo _movieInfo;
|
||||||
private readonly IMovieService _movieService;
|
private readonly IMovieService _movieService;
|
||||||
|
private readonly IAlternativeTitleService _titleService;
|
||||||
private readonly IRefreshEpisodeService _refreshEpisodeService;
|
private readonly IRefreshEpisodeService _refreshEpisodeService;
|
||||||
private readonly IEventAggregator _eventAggregator;
|
private readonly IEventAggregator _eventAggregator;
|
||||||
private readonly IManageCommandQueue _commandQueueManager;
|
private readonly IManageCommandQueue _commandQueueManager;
|
||||||
private readonly IDiskScanService _diskScanService;
|
private readonly IDiskScanService _diskScanService;
|
||||||
private readonly ICheckIfMovieShouldBeRefreshed _checkIfMovieShouldBeRefreshed;
|
private readonly ICheckIfMovieShouldBeRefreshed _checkIfMovieShouldBeRefreshed;
|
||||||
|
private readonly IRadarrAPIClient _apiClient;
|
||||||
|
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public RefreshMovieService(IProvideMovieInfo movieInfo,
|
public RefreshMovieService(IProvideMovieInfo movieInfo,
|
||||||
IMovieService movieService,
|
IMovieService movieService,
|
||||||
|
IAlternativeTitleService titleService,
|
||||||
IRefreshEpisodeService refreshEpisodeService,
|
IRefreshEpisodeService refreshEpisodeService,
|
||||||
IEventAggregator eventAggregator,
|
IEventAggregator eventAggregator,
|
||||||
IDiskScanService diskScanService,
|
IDiskScanService diskScanService,
|
||||||
|
IRadarrAPIClient apiClient,
|
||||||
ICheckIfMovieShouldBeRefreshed checkIfMovieShouldBeRefreshed,
|
ICheckIfMovieShouldBeRefreshed checkIfMovieShouldBeRefreshed,
|
||||||
IManageCommandQueue commandQueue,
|
IManageCommandQueue commandQueue,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
{
|
{
|
||||||
_movieInfo = movieInfo;
|
_movieInfo = movieInfo;
|
||||||
_movieService = movieService;
|
_movieService = movieService;
|
||||||
|
_titleService = titleService;
|
||||||
_refreshEpisodeService = refreshEpisodeService;
|
_refreshEpisodeService = refreshEpisodeService;
|
||||||
_eventAggregator = eventAggregator;
|
_eventAggregator = eventAggregator;
|
||||||
|
_apiClient = apiClient;
|
||||||
_commandQueueManager = commandQueue;
|
_commandQueueManager = commandQueue;
|
||||||
_diskScanService = diskScanService;
|
_diskScanService = diskScanService;
|
||||||
_checkIfMovieShouldBeRefreshed = checkIfMovieShouldBeRefreshed;
|
_checkIfMovieShouldBeRefreshed = checkIfMovieShouldBeRefreshed;
|
||||||
|
@ -85,7 +94,7 @@ namespace NzbDrone.Core.Tv
|
||||||
movie.Certification = movieInfo.Certification;
|
movie.Certification = movieInfo.Certification;
|
||||||
movie.InCinemas = movieInfo.InCinemas;
|
movie.InCinemas = movieInfo.InCinemas;
|
||||||
movie.Website = movieInfo.Website;
|
movie.Website = movieInfo.Website;
|
||||||
movie.AlternativeTitles = movieInfo.AlternativeTitles;
|
//movie.AlternativeTitles = movieInfo.AlternativeTitles;
|
||||||
movie.Year = movieInfo.Year;
|
movie.Year = movieInfo.Year;
|
||||||
movie.PhysicalRelease = movieInfo.PhysicalRelease;
|
movie.PhysicalRelease = movieInfo.PhysicalRelease;
|
||||||
movie.YouTubeTrailerId = movieInfo.YouTubeTrailerId;
|
movie.YouTubeTrailerId = movieInfo.YouTubeTrailerId;
|
||||||
|
@ -102,8 +111,47 @@ namespace NzbDrone.Core.Tv
|
||||||
_logger.Warn(e, "Couldn't update movie path for " + movie.Path);
|
_logger.Warn(e, "Couldn't update movie path for " + movie.Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
movieInfo.AlternativeTitles = movieInfo.AlternativeTitles.Where(t => t.CleanTitle != movie.CleanTitle)
|
||||||
|
.DistinctBy(t => t.CleanTitle)
|
||||||
|
.ExceptBy(t => t.CleanTitle, movie.AlternativeTitles, t => t.CleanTitle, EqualityComparer<string>.Default).ToList();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var mappings = _apiClient.AlternativeTitlesAndYearForMovie(movieInfo.TmdbId);
|
||||||
|
var mappingsTitles = mappings.Item1;
|
||||||
|
|
||||||
|
movie.AlternativeTitles.AddRange(_titleService.AddAltTitles(movieInfo.AlternativeTitles, movie));
|
||||||
|
|
||||||
|
mappingsTitles = mappingsTitles.ExceptBy(t => t.CleanTitle, movie.AlternativeTitles,
|
||||||
|
t => t.CleanTitle, EqualityComparer<string>.Default).ToList();
|
||||||
|
|
||||||
|
movie.AlternativeTitles.AddRange(_titleService.AddAltTitles(mappingsTitles, movie));
|
||||||
|
|
||||||
|
if (mappings.Item2 != null)
|
||||||
|
{
|
||||||
|
movie.SecondaryYear = mappings.Item2.Year;
|
||||||
|
movie.SecondaryYearSourceId = mappings.Item2.SourceId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (RadarrAPIException ex)
|
||||||
|
{
|
||||||
|
//Not that wild, could just be a 404.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
_movieService.UpdateMovie(movie);
|
_movieService.UpdateMovie(movie);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var newTitles = movieInfo.AlternativeTitles.Except(movie.AlternativeTitles);
|
||||||
|
//_titleService.AddAltTitles(newTitles.ToList(), movie);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Debug(e, "Failed adding alternative titles.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
_logger.Debug("Finished movie refresh for {0}", movie.Title);
|
_logger.Debug("Finished movie refresh for {0}", movie.Title);
|
||||||
_eventAggregator.PublishEvent(new MovieUpdatedEvent(movie));
|
_eventAggregator.PublishEvent(new MovieUpdatedEvent(movie));
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ namespace NzbDrone.Core.Tv
|
||||||
|
|
||||||
public bool ShouldRefresh(Movie movie)
|
public bool ShouldRefresh(Movie movie)
|
||||||
{
|
{
|
||||||
|
//return false;
|
||||||
if (movie.LastInfoSync < DateTime.UtcNow.AddDays(-30))
|
if (movie.LastInfoSync < DateTime.UtcNow.AddDays(-30))
|
||||||
{
|
{
|
||||||
_logger.Trace("Movie {0} last updated more than 30 days ago, should refresh.", movie.Title);
|
_logger.Trace("Movie {0} last updated more than 30 days ago, should refresh.", movie.Title);
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace NzbDrone.Integration.Test.ApiTests
|
||||||
releaseResource.Age.Should().BeGreaterOrEqualTo(-1);
|
releaseResource.Age.Should().BeGreaterOrEqualTo(-1);
|
||||||
releaseResource.Title.Should().NotBeNullOrWhiteSpace();
|
releaseResource.Title.Should().NotBeNullOrWhiteSpace();
|
||||||
releaseResource.DownloadUrl.Should().NotBeNullOrWhiteSpace();
|
releaseResource.DownloadUrl.Should().NotBeNullOrWhiteSpace();
|
||||||
releaseResource.SeriesTitle.Should().NotBeNullOrWhiteSpace();
|
releaseResource.MovieTitle.Should().NotBeNullOrWhiteSpace();
|
||||||
//TODO: uncomment these after moving to restsharp for rss
|
//TODO: uncomment these after moving to restsharp for rss
|
||||||
//releaseResource.NzbInfoUrl.Should().NotBeNullOrWhiteSpace();
|
//releaseResource.NzbInfoUrl.Should().NotBeNullOrWhiteSpace();
|
||||||
//releaseResource.Size.Should().BeGreaterThan(0);
|
//releaseResource.Size.Should().BeGreaterThan(0);
|
||||||
|
|
|
@ -268,6 +268,11 @@
|
||||||
.fa-icon-color(@brand-warning);
|
.fa-icon-color(@brand-warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-radarr-download-warning {
|
||||||
|
.fa-icon-content(@fa-var-download);
|
||||||
|
.fa-icon-color(@brand-warning);
|
||||||
|
}
|
||||||
|
|
||||||
.icon-sonarr-shutdown {
|
.icon-sonarr-shutdown {
|
||||||
.fa-icon-content(@fa-var-power-off);
|
.fa-icon-content(@fa-var-power-off);
|
||||||
.fa-icon-color(@brand-danger);
|
.fa-icon-color(@brand-danger);
|
||||||
|
|
|
@ -64,6 +64,11 @@ Handlebars.registerHelper('alternativeTitlesString', function() {
|
||||||
if (titles.length === 0) {
|
if (titles.length === 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
titles = _.map(titles, function(item){
|
||||||
|
return item.title;
|
||||||
|
});
|
||||||
|
|
||||||
if (titles.length === 1) {
|
if (titles.length === 1) {
|
||||||
return titles[0];
|
return titles[0];
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ var EpisodeFileEditorLayout = require('../../EpisodeFile/Editor/EpisodeFileEdito
|
||||||
var HistoryLayout = require('../History/MovieHistoryLayout');
|
var HistoryLayout = require('../History/MovieHistoryLayout');
|
||||||
var SearchLayout = require('../Search/MovieSearchLayout');
|
var SearchLayout = require('../Search/MovieSearchLayout');
|
||||||
var FilesLayout = require("../Files/FilesLayout");
|
var FilesLayout = require("../Files/FilesLayout");
|
||||||
|
var TitlesLayout = require("../Titles/TitlesLayout");
|
||||||
require('backstrech');
|
require('backstrech');
|
||||||
require('../../Mixins/backbone.signalr.mixin');
|
require('../../Mixins/backbone.signalr.mixin');
|
||||||
|
|
||||||
|
@ -24,7 +25,8 @@ module.exports = Marionette.Layout.extend({
|
||||||
info : '#info',
|
info : '#info',
|
||||||
search : '#movie-search',
|
search : '#movie-search',
|
||||||
history : '#movie-history',
|
history : '#movie-history',
|
||||||
files : "#movie-files"
|
files : "#movie-files",
|
||||||
|
titles: "#movie-titles",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,7 +41,8 @@ module.exports = Marionette.Layout.extend({
|
||||||
manualSearch : '.x-manual-search',
|
manualSearch : '.x-manual-search',
|
||||||
history : '.x-movie-history',
|
history : '.x-movie-history',
|
||||||
search : '.x-movie-search',
|
search : '.x-movie-search',
|
||||||
files : ".x-movie-files"
|
files : ".x-movie-files",
|
||||||
|
titles: ".x-movie-titles",
|
||||||
},
|
},
|
||||||
|
|
||||||
events : {
|
events : {
|
||||||
|
@ -53,6 +56,7 @@ module.exports = Marionette.Layout.extend({
|
||||||
'click .x-movie-history' : '_showHistory',
|
'click .x-movie-history' : '_showHistory',
|
||||||
'click .x-movie-search' : '_showSearch',
|
'click .x-movie-search' : '_showSearch',
|
||||||
"click .x-movie-files" : "_showFiles",
|
"click .x-movie-files" : "_showFiles",
|
||||||
|
"click .x-movie-titles" : "_showTitles",
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize : function() {
|
initialize : function() {
|
||||||
|
@ -83,6 +87,7 @@ module.exports = Marionette.Layout.extend({
|
||||||
this.searchLayout.startManualSearch = true;
|
this.searchLayout.startManualSearch = true;
|
||||||
|
|
||||||
this.filesLayout = new FilesLayout({ model : this.model });
|
this.filesLayout = new FilesLayout({ model : this.model });
|
||||||
|
this.titlesLayout = new TitlesLayout({ model : this.model });
|
||||||
|
|
||||||
this._showBackdrop();
|
this._showBackdrop();
|
||||||
this._showSeasons();
|
this._showSeasons();
|
||||||
|
@ -170,6 +175,15 @@ module.exports = Marionette.Layout.extend({
|
||||||
this.files.show(this.filesLayout);
|
this.files.show(this.filesLayout);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_showTitles : function(e) {
|
||||||
|
if (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ui.titles.tab("show");
|
||||||
|
this.titles.show(this.titlesLayout);
|
||||||
|
},
|
||||||
|
|
||||||
_toggleMonitored : function() {
|
_toggleMonitored : function() {
|
||||||
var savePromise = this.model.save('monitored', !this.model.get('monitored'), { wait : true });
|
var savePromise = this.model.save('monitored', !this.model.get('monitored'), { wait : true });
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
<div>
|
<div>
|
||||||
<h1 class="header-text">
|
<h1 class="header-text">
|
||||||
<i class="x-monitored" title="Toggle monitored state for movie"/>
|
<i class="x-monitored" title="Toggle monitored state for movie"/>
|
||||||
{{title}}
|
{{title}} <span class="year">({{year}}{{#if secondaryYear}} / <a href="https://mappings.radarr.video/mapping/{{secondaryYearSourceId}}" target="_blank"><span title="Secondary year pulled from Radarr Mappings.
|
||||||
|
Click to head on over there and tell us whether this is correct or not.">{{secondaryYear}}</span></a>{{/if}})</span>
|
||||||
<div class="movie-actions pull-right">
|
<div class="movie-actions pull-right">
|
||||||
<div class="x-episode-file-editor">
|
<div class="x-episode-file-editor">
|
||||||
<i class="icon-sonarr-episode-file" title="Modify movie files"/>
|
<i class="icon-sonarr-episode-file" title="Modify movie files"/>
|
||||||
|
@ -43,11 +44,13 @@
|
||||||
<li><a href="#movie-history" class="x-movie-history">History</a></li>
|
<li><a href="#movie-history" class="x-movie-history">History</a></li>
|
||||||
<li><a href="#movie-search" class="x-movie-search">Search</a></li>
|
<li><a href="#movie-search" class="x-movie-search">Search</a></li>
|
||||||
<li><a href="#movie-files" class="x-movie-files">Files</a></li>
|
<li><a href="#movie-files" class="x-movie-files">Files</a></li>
|
||||||
|
<li><a href="#movie-titles" class="x-movie-titles">Titles</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div class="tab-pane" id="movie-history"/>
|
<div class="tab-pane" id="movie-history"/>
|
||||||
<div class="tab-pane" id="movie-search"/>
|
<div class="tab-pane" id="movie-search"/>
|
||||||
<div class="tab-pane" id="movie-files"/>
|
<div class="tab-pane" id="movie-files"/>
|
||||||
|
<div class="tab-pane" id="movie-titles"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
22
src/UI/Movies/Titles/LanguageCell.js
Normal file
22
src/UI/Movies/Titles/LanguageCell.js
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
var NzbDroneCell = require('../../Cells/NzbDroneCell');
|
||||||
|
|
||||||
|
module.exports = NzbDroneCell.extend({
|
||||||
|
className : 'language-cell',
|
||||||
|
|
||||||
|
render : function() {
|
||||||
|
this.$el.empty();
|
||||||
|
|
||||||
|
var language = this.model.get("language");
|
||||||
|
|
||||||
|
this.$el.html(this.toTitleCase(language));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
toTitleCase : function(str)
|
||||||
|
{
|
||||||
|
return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
5
src/UI/Movies/Titles/NoTitlesView.js
Normal file
5
src/UI/Movies/Titles/NoTitlesView.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
var Marionette = require('marionette');
|
||||||
|
|
||||||
|
module.exports = Marionette.ItemView.extend({
|
||||||
|
template : 'Movies/Titles/NoTitlesViewTemplate'
|
||||||
|
});
|
3
src/UI/Movies/Titles/NoTitlesViewTemplate.hbs
Normal file
3
src/UI/Movies/Titles/NoTitlesViewTemplate.hbs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<p class="text-warning">
|
||||||
|
No alternative titles for this movie.
|
||||||
|
</p>
|
42
src/UI/Movies/Titles/SourceCell.js
Normal file
42
src/UI/Movies/Titles/SourceCell.js
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
var NzbDroneCell = require('../../Cells/NzbDroneCell');
|
||||||
|
|
||||||
|
module.exports = NzbDroneCell.extend({
|
||||||
|
className : 'title-source-cell',
|
||||||
|
|
||||||
|
render : function() {
|
||||||
|
this.$el.empty();
|
||||||
|
|
||||||
|
var link = undefined;
|
||||||
|
var sourceTitle = this.model.get("sourceType");
|
||||||
|
var sourceId = this.model.get("sourceId");
|
||||||
|
|
||||||
|
switch (sourceTitle) {
|
||||||
|
case "tmdb":
|
||||||
|
sourceTitle = "TMDB";
|
||||||
|
link = "https://themoviedb.org/movie/" + sourceId;
|
||||||
|
break;
|
||||||
|
case "mappings":
|
||||||
|
sourceTitle = "Radarr Mappings";
|
||||||
|
link = "https://mappings.radarr.video/mapping/" + sourceId;
|
||||||
|
break;
|
||||||
|
case "user":
|
||||||
|
sourceTitle = "Force Download";
|
||||||
|
break;
|
||||||
|
case "indexer":
|
||||||
|
sourceTitle = "Indexer";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var a = "{0}";
|
||||||
|
|
||||||
|
if (link) {
|
||||||
|
a = "<a href='"+link+"' target='_blank'>{0}</a>"
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$el.html(a.format(sourceTitle));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
6
src/UI/Movies/Titles/TitleCell.js
Normal file
6
src/UI/Movies/Titles/TitleCell.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
var TemplatedCell = require('../../Cells/TemplatedCell');
|
||||||
|
|
||||||
|
module.exports = TemplatedCell.extend({
|
||||||
|
className : 'series-title-cell',
|
||||||
|
template : 'Movies/Titles/TitleTemplate'
|
||||||
|
});
|
3
src/UI/Movies/Titles/TitleModel.js
Normal file
3
src/UI/Movies/Titles/TitleModel.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
var Backbone = require('backbone');
|
||||||
|
|
||||||
|
module.exports = Backbone.Model.extend({});
|
1
src/UI/Movies/Titles/TitleTemplate.hbs
Normal file
1
src/UI/Movies/Titles/TitleTemplate.hbs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{{this}}
|
30
src/UI/Movies/Titles/TitlesCollection.js
Normal file
30
src/UI/Movies/Titles/TitlesCollection.js
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
var PagableCollection = require('backbone.pageable');
|
||||||
|
var TitleModel = require('./TitleModel');
|
||||||
|
var AsSortedCollection = require('../../Mixins/AsSortedCollection');
|
||||||
|
|
||||||
|
var Collection = PagableCollection.extend({
|
||||||
|
url : window.NzbDrone.ApiRoot + "/aka",
|
||||||
|
model : TitleModel,
|
||||||
|
|
||||||
|
state : {
|
||||||
|
pageSize : 2000,
|
||||||
|
sortKey : 'title',
|
||||||
|
order : -1
|
||||||
|
},
|
||||||
|
|
||||||
|
mode : 'client',
|
||||||
|
|
||||||
|
sortMappings : {
|
||||||
|
"source" : {
|
||||||
|
sortKey : "sourceType"
|
||||||
|
},
|
||||||
|
"language" : {
|
||||||
|
sortKey : "language"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
Collection = AsSortedCollection.call(Collection);
|
||||||
|
|
||||||
|
module.exports = Collection;
|
117
src/UI/Movies/Titles/TitlesLayout.js
Normal file
117
src/UI/Movies/Titles/TitlesLayout.js
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
var vent = require('vent');
|
||||||
|
var Marionette = require('marionette');
|
||||||
|
var Backgrid = require('backgrid');
|
||||||
|
//var ButtonsView = require('./ButtonsView');
|
||||||
|
//var ManualSearchLayout = require('./ManualLayout');
|
||||||
|
var TitlesCollection = require('./TitlesCollection');
|
||||||
|
var CommandController = require('../../Commands/CommandController');
|
||||||
|
var LoadingView = require('../../Shared/LoadingView');
|
||||||
|
var NoResultsView = require('./NoTitlesView');
|
||||||
|
var TitleModel = require("./TitleModel");
|
||||||
|
var TitleCell = require("./TitleCell");
|
||||||
|
var SourceCell = require("./SourceCell");
|
||||||
|
var LanguageCell = require("./LanguageCell");
|
||||||
|
|
||||||
|
module.exports = Marionette.Layout.extend({
|
||||||
|
template : 'Movies/Titles/TitlesLayoutTemplate',
|
||||||
|
|
||||||
|
regions : {
|
||||||
|
main : '#movie-titles-region',
|
||||||
|
grid : "#movie-titles-grid"
|
||||||
|
},
|
||||||
|
|
||||||
|
events : {
|
||||||
|
'click .x-search-auto' : '_searchAuto',
|
||||||
|
'click .x-search-manual' : '_searchManual',
|
||||||
|
'click .x-search-back' : '_showButtons'
|
||||||
|
},
|
||||||
|
|
||||||
|
columns : [
|
||||||
|
{
|
||||||
|
name : 'title',
|
||||||
|
label : 'Title',
|
||||||
|
cell : Backgrid.StringCell
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : "this",
|
||||||
|
label : "Source",
|
||||||
|
cell : SourceCell,
|
||||||
|
sortKey : "sourceType",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : "this",
|
||||||
|
label : "Language",
|
||||||
|
cell : LanguageCell
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
|
||||||
|
initialize : function(movie) {
|
||||||
|
this.titlesCollection = new TitlesCollection();
|
||||||
|
var titles = movie.model.get("alternativeTitles");
|
||||||
|
this.movie = movie;
|
||||||
|
this.titlesCollection.add(titles);
|
||||||
|
//this.listenTo(this.releaseCollection, 'sync', this._showSearchResults);
|
||||||
|
this.listenTo(this.model, 'change', function(model, options) {
|
||||||
|
if (options && options.changeSource === 'signalr') {
|
||||||
|
this._refresh(model);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//vent.on(vent.Commands.MovieFileEdited, this._showGrid, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
_refresh : function(model) {
|
||||||
|
this.titlesCollection = new TitlesCollection();
|
||||||
|
var file = model.get("alternativeTitles");
|
||||||
|
this.titlesCollection.add(file);
|
||||||
|
|
||||||
|
|
||||||
|
this.onShow();
|
||||||
|
},
|
||||||
|
|
||||||
|
_refreshClose : function(options) {
|
||||||
|
this.titlesCollection = new TitlesCollection();
|
||||||
|
var file = this.movie.model.get("alternativeTitles");
|
||||||
|
this.titlesCollection.add(file);
|
||||||
|
this._showGrid();
|
||||||
|
},
|
||||||
|
|
||||||
|
onShow : function() {
|
||||||
|
this.grid.show(new Backgrid.Grid({
|
||||||
|
row : Backgrid.Row,
|
||||||
|
columns : this.columns,
|
||||||
|
collection : this.titlesCollection,
|
||||||
|
className : 'table table-hover'
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_showGrid : function() {
|
||||||
|
this.regionManager.get('grid').show(new Backgrid.Grid({
|
||||||
|
row : Backgrid.Row,
|
||||||
|
columns : this.columns,
|
||||||
|
collection : this.titlesCollection,
|
||||||
|
className : 'table table-hover'
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_showMainView : function() {
|
||||||
|
this.main.show(this.mainView);
|
||||||
|
},
|
||||||
|
|
||||||
|
_showButtons : function() {
|
||||||
|
this._showMainView();
|
||||||
|
},
|
||||||
|
|
||||||
|
_showSearchResults : function() {
|
||||||
|
if (this.releaseCollection.length === 0) {
|
||||||
|
this.mainView = new NoResultsView();
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
//this.mainView = new ManualSearchLayout({ collection : this.releaseCollection });
|
||||||
|
}
|
||||||
|
|
||||||
|
this._showMainView();
|
||||||
|
}
|
||||||
|
});
|
3
src/UI/Movies/Titles/TitlesLayoutTemplate.hbs
Normal file
3
src/UI/Movies/Titles/TitlesLayoutTemplate.hbs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<div id="movie-titles-region">
|
||||||
|
<div id="movie-titles-grid" class="table-responsive"></div>
|
||||||
|
</div>
|
|
@ -534,3 +534,9 @@
|
||||||
list-style-type : none;
|
list-style-type : none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header-text {
|
||||||
|
.year {
|
||||||
|
color : gray;
|
||||||
|
}
|
||||||
|
}
|
6
src/UI/Release/AlternativeTitleModel.js
Normal file
6
src/UI/Release/AlternativeTitleModel.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
var Backbone = require('backbone');
|
||||||
|
var _ = require('underscore');
|
||||||
|
|
||||||
|
module.exports = Backbone.Model.extend({
|
||||||
|
urlRoot : window.NzbDrone.ApiRoot + '/alttitle',
|
||||||
|
});
|
6
src/UI/Release/AlternativeYearModel.js
Normal file
6
src/UI/Release/AlternativeYearModel.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
var Backbone = require('backbone');
|
||||||
|
var _ = require('underscore');
|
||||||
|
|
||||||
|
module.exports = Backbone.Model.extend({
|
||||||
|
urlRoot : window.NzbDrone.ApiRoot + '/altyear',
|
||||||
|
});
|
|
@ -1,4 +1,6 @@
|
||||||
var Backgrid = require('backgrid');
|
var Backgrid = require('backgrid');
|
||||||
|
var AppLayout = require('../AppLayout');
|
||||||
|
var ForceDownloadView = require('./ForceDownloadView');
|
||||||
|
|
||||||
module.exports = Backgrid.Cell.extend({
|
module.exports = Backgrid.Cell.extend({
|
||||||
className : 'download-report-cell',
|
className : 'download-report-cell',
|
||||||
|
@ -8,7 +10,12 @@ module.exports = Backgrid.Cell.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
_onClick : function() {
|
_onClick : function() {
|
||||||
if (!this.model.get('downloadAllowed')) {
|
if (!this.model.downloadOk()) {
|
||||||
|
var view = new ForceDownloadView({
|
||||||
|
release : this.model
|
||||||
|
});
|
||||||
|
AppLayout.modalRegion.show(view);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,10 +45,11 @@ module.exports = Backgrid.Cell.extend({
|
||||||
|
|
||||||
if (this.model.get('queued')) {
|
if (this.model.get('queued')) {
|
||||||
this.$el.html('<i class="icon-sonarr-downloading" title="Added to downloaded queue" />');
|
this.$el.html('<i class="icon-sonarr-downloading" title="Added to downloaded queue" />');
|
||||||
} else if (this.model.get('downloadAllowed')) {
|
} else if (this.model.downloadOk()) {
|
||||||
this.$el.html('<i class="icon-sonarr-download" title="Add to download queue" />');
|
this.$el.html('<i class="icon-sonarr-download" title="Add to download queue" />');
|
||||||
} else {
|
} else if (this.model.forceDownloadOk()){
|
||||||
this.className = 'no-download-report-cell';
|
this.$el.html('<i class="icon-radarr-download-warning" title="Force add to download queue."/>');
|
||||||
|
this.className = 'force-download-report-cell';
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|
81
src/UI/Release/ForceDownloadView.js
Normal file
81
src/UI/Release/ForceDownloadView.js
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
var _ = require('underscore');
|
||||||
|
var $ = require('jquery');
|
||||||
|
var vent = require('vent');
|
||||||
|
var AppLayout = require('../AppLayout');
|
||||||
|
var Marionette = require('marionette');
|
||||||
|
var Config = require('../Config');
|
||||||
|
var LanguageCollection = require('../Settings/Profile/Language/LanguageCollection');
|
||||||
|
var AltTitleModel = require("./AlternativeTitleModel");
|
||||||
|
var AltYearModel = require("./AlternativeYearModel");
|
||||||
|
var Messenger = require('../Shared/Messenger');
|
||||||
|
require('../Form/FormBuilder');
|
||||||
|
require('bootstrap');
|
||||||
|
|
||||||
|
module.exports = Marionette.ItemView.extend({
|
||||||
|
template : 'Release/ForceDownloadViewTemplate',
|
||||||
|
|
||||||
|
events : {
|
||||||
|
'click .x-download' : '_forceDownload',
|
||||||
|
},
|
||||||
|
|
||||||
|
ui : {
|
||||||
|
titleMapping : "#title-mapping",
|
||||||
|
yearMapping : "#year-mapping",
|
||||||
|
language : "#language-selection",
|
||||||
|
indicator : ".x-indicator",
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize : function(options) {
|
||||||
|
this.release = options.release;
|
||||||
|
this.templateHelpers = {};
|
||||||
|
|
||||||
|
this._configureTemplateHelpers();
|
||||||
|
},
|
||||||
|
|
||||||
|
onShow : function() {
|
||||||
|
if (this.release.get("mappingResult") == "wrongYear") {
|
||||||
|
this.ui.titleMapping.hide();
|
||||||
|
} else {
|
||||||
|
this.ui.yearMapping.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_configureTemplateHelpers : function() {
|
||||||
|
this.templateHelpers.release = this.release.toJSON();
|
||||||
|
this.templateHelpers.languages = LanguageCollection.toJSON()
|
||||||
|
},
|
||||||
|
|
||||||
|
_forceDownload : function() {
|
||||||
|
this.ui.indicator.show();
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (this.release.get("mappingResult") == "wrongYear") {
|
||||||
|
var altYear = new AltYearModel({
|
||||||
|
movieId : this.release.get("suspectedMovieId"),
|
||||||
|
year : this.release.get("year")
|
||||||
|
});
|
||||||
|
this.savePromise = altYear.save();
|
||||||
|
} else {
|
||||||
|
var altTitle = new AltTitleModel({
|
||||||
|
movieId : this.release.get("suspectedMovieId"),
|
||||||
|
title : this.release.get("movieTitle"),
|
||||||
|
language : this.ui.language.val(),
|
||||||
|
});
|
||||||
|
|
||||||
|
this.savePromise = altTitle.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.savePromise.always(function(){
|
||||||
|
self.ui.indicator.hide();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.savePromise.success(function(){
|
||||||
|
self.release.save(null, {
|
||||||
|
success : function() {
|
||||||
|
self.release.set('queued', true);
|
||||||
|
vent.trigger(vent.Commands.CloseModalCommand);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
44
src/UI/Release/ForceDownloadViewTemplate.hbs
Normal file
44
src/UI/Release/ForceDownloadViewTemplate.hbs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" aria-hidden="true" data-dismiss="modal">×</button>
|
||||||
|
<h3>Force Download</h3>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body indexer-modal">
|
||||||
|
<div id="title-mapping">
|
||||||
|
<p>The title "{{release.movieTitle}}" could not be found amongst the alternative titles of the movie. This could lead to problems when Radarr wants to import your movie.
|
||||||
|
If you click force download below, the title will be added to the alternative titles using the language selected below.</p>
|
||||||
|
<div class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">Language</label>
|
||||||
|
|
||||||
|
<div class="col-sm-5">
|
||||||
|
<select id="language-selection" class="form-control" name="language">
|
||||||
|
{{#each languages}}
|
||||||
|
{{#unless_eq nameLower compare="unknown"}}
|
||||||
|
<option value="{{nameLower}}" {{#if_eq nameLower compare="english"}} selected {{/if_eq}}>{{name}}</option>
|
||||||
|
{{/unless_eq}}
|
||||||
|
{{/each}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-1 help-inline">
|
||||||
|
<i class="icon-sonarr-form-info" title="Language of the alternative title."/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div id="year-mapping">
|
||||||
|
<p>The year {{release.year}} does not match the expected release year. This could lead to problems when Radarr wants to import your movie.
|
||||||
|
If you click force download below, the year will be added as a secondary year for this movie.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<span class="indicator x-indicator"><i class="icon-sonarr-spinner fa-spin"></i></span>
|
||||||
|
<button class="btn" data-dismiss="modal">Cancel</button>
|
||||||
|
|
||||||
|
<div class="btn-group">
|
||||||
|
<button class="btn btn-primary x-download">Force Download</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1,3 +1,11 @@
|
||||||
var Backbone = require('backbone');
|
var Backbone = require('backbone');
|
||||||
|
|
||||||
module.exports = Backbone.Model.extend({});
|
module.exports = Backbone.Model.extend({
|
||||||
|
downloadOk : function() {
|
||||||
|
return this.get("mappingResult") == "success" || this.get("mappingResult") == "successLenientMapping";
|
||||||
|
},
|
||||||
|
|
||||||
|
forceDownloadOk : function() {
|
||||||
|
return this.get("mappingResult") == "wrongYear" || this.get("mappingResult") == "wrongTitle";
|
||||||
|
}
|
||||||
|
});
|
Loading…
Add table
Add a link
Reference in a new issue