mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-23 06:45:19 -07:00
PreDB Integration. Update Library is advisable
This commit is contained in:
parent
3cf5301e46
commit
149c5292f1
16 changed files with 302 additions and 18 deletions
|
@ -29,7 +29,7 @@ namespace NzbDrone.Api.Movie
|
|||
int tmdbId = -1;
|
||||
if(Int32.TryParse(Request.Query.tmdbId, out tmdbId))
|
||||
{
|
||||
var result = _movieInfo.GetMovieInfo(tmdbId, null);
|
||||
var result = _movieInfo.GetMovieInfo(tmdbId, null, true);
|
||||
return result.ToResource().AsResponse();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
using System.Data;
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(135)]
|
||||
public class add_haspredbentry_to_movies : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Alter.Table("Movies").AddColumn("HasPreDBEntry").AsBoolean().WithDefaultValue(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ using NzbDrone.Core.Messaging.Events;
|
|||
using NzbDrone.Core.NetImport;
|
||||
using NzbDrone.Core.Tv.Commands;
|
||||
using NzbDrone.Core.Update.Commands;
|
||||
using NzbDrone.Core.MetadataSource.PreDB;
|
||||
|
||||
namespace NzbDrone.Core.Jobs
|
||||
{
|
||||
|
@ -72,6 +73,7 @@ namespace NzbDrone.Core.Jobs
|
|||
var defaultTasks = new[]
|
||||
{
|
||||
new ScheduledTask{ Interval = 0.25f, TypeName = typeof(CheckForFinishedDownloadCommand).FullName},
|
||||
new ScheduledTask{ Interval = 1*60, TypeName = typeof(PreDBSyncCommand).FullName},
|
||||
new ScheduledTask{ Interval = 5, TypeName = typeof(MessagingCleanupCommand).FullName},
|
||||
new ScheduledTask{ Interval = updateInterval, TypeName = typeof(ApplicationUpdateCommand).FullName},
|
||||
// new ScheduledTask{ Interval = 3*60, TypeName = typeof(UpdateSceneMappingCommand).FullName},
|
||||
|
|
|
@ -8,6 +8,6 @@ namespace NzbDrone.Core.MetadataSource
|
|||
public interface IProvideMovieInfo
|
||||
{
|
||||
Movie GetMovieInfo(string ImdbId);
|
||||
Movie GetMovieInfo(int TmdbId, Profile profile);
|
||||
Movie GetMovieInfo(int TmdbId, Profile profile, bool hasPreDBEntry);
|
||||
}
|
||||
}
|
14
src/NzbDrone.Core/MetadataSource/PreDB/PreDBResult.cs
Normal file
14
src/NzbDrone.Core/MetadataSource/PreDB/PreDBResult.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.MetadataSource.PreDB
|
||||
{
|
||||
class PreDBResult
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public string Link { get; set; }
|
||||
|
||||
}
|
||||
}
|
194
src/NzbDrone.Core/MetadataSource/PreDB/PreDBService.cs
Normal file
194
src/NzbDrone.Core/MetadataSource/PreDB/PreDBService.cs
Normal file
|
@ -0,0 +1,194 @@
|
|||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.Pending;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using System.ServiceModel.Syndication;
|
||||
using System.Xml;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Tv;
|
||||
using System;
|
||||
using System.IO;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.IndexerSearch;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
|
||||
namespace NzbDrone.Core.MetadataSource.PreDB
|
||||
{
|
||||
public interface IPreDBService
|
||||
{
|
||||
bool HasReleases(Movie movie);
|
||||
}
|
||||
|
||||
public class PreDBService : IPreDBService, IExecute<PreDBSyncCommand>
|
||||
{
|
||||
private readonly IFetchAndParseRss _rssFetcherAndParser;
|
||||
private readonly IMakeDownloadDecision _downloadDecisionMaker;
|
||||
private readonly IProcessDownloadDecisions _processDownloadDecisions;
|
||||
private readonly IPendingReleaseService _pendingReleaseService;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly IMovieService _movieService;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IParsingService _parsingService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public PreDBService(
|
||||
IFetchAndParseRss rssFetcherAndParser,
|
||||
IMakeDownloadDecision downloadDecisionMaker,
|
||||
IProcessDownloadDecisions processDownloadDecisions,
|
||||
IPendingReleaseService pendingReleaseService,
|
||||
IEventAggregator eventAggregator,
|
||||
IMovieService movieService,
|
||||
IHttpClient httpClient,
|
||||
IParsingService parsingService,
|
||||
Logger logger)
|
||||
{
|
||||
_rssFetcherAndParser = rssFetcherAndParser;
|
||||
_downloadDecisionMaker = downloadDecisionMaker;
|
||||
_processDownloadDecisions = processDownloadDecisions;
|
||||
_pendingReleaseService = pendingReleaseService;
|
||||
_eventAggregator = eventAggregator;
|
||||
_movieService = movieService;
|
||||
_httpClient = httpClient;
|
||||
_parsingService = parsingService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
private List<PreDBResult> GetResults(string category = "", string search = "")
|
||||
{
|
||||
var builder = new HttpRequestBuilder("http://predb.me").AddQueryParam("rss", "1");
|
||||
if (category.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
builder.AddQueryParam("cats", category);
|
||||
}
|
||||
|
||||
if (search.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
builder.AddQueryParam("search", search);
|
||||
}
|
||||
|
||||
var request = builder.Build();
|
||||
|
||||
request.AllowAutoRedirect = true;
|
||||
request.SuppressHttpError = true;
|
||||
|
||||
var response = _httpClient.Get(request);
|
||||
|
||||
if (response.StatusCode != System.Net.HttpStatusCode.OK)
|
||||
{
|
||||
_logger.Warn("Non 200 StatusCode {0} encountered while searching PreDB.", response.StatusCode);
|
||||
return new List<PreDBResult>();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var reader = XmlReader.Create(new StringReader(response.Content));
|
||||
|
||||
var items = SyndicationFeed.Load(reader);
|
||||
|
||||
var results = new List<PreDBResult>();
|
||||
|
||||
foreach (SyndicationItem item in items.Items)
|
||||
{
|
||||
var result = new PreDBResult();
|
||||
result.Title = item.Title.Text;
|
||||
result.Link = item.Links[0].Uri.ToString();
|
||||
results.Add(result);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex, "Error while searching PreDB.");
|
||||
}
|
||||
|
||||
return new List<PreDBResult>();
|
||||
}
|
||||
|
||||
private List<Movie> FindMatchesToResults(List<PreDBResult> results)
|
||||
{
|
||||
var matches = new List<Movie>();
|
||||
|
||||
foreach (PreDBResult result in results)
|
||||
{
|
||||
var parsedInfo = Parser.Parser.ParseMovieTitle(result.Title);
|
||||
|
||||
if (parsedInfo != null)
|
||||
{
|
||||
var movie = _movieService.FindByTitle(parsedInfo.MovieTitle, parsedInfo.Year);
|
||||
|
||||
if (movie != null)
|
||||
{
|
||||
matches.Add(movie);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private List<Movie> Sync()
|
||||
{
|
||||
_logger.ProgressInfo("Starting PreDB Sync");
|
||||
|
||||
var results = GetResults("movies");
|
||||
|
||||
var matches = FindMatchesToResults(results);
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
public void Execute(PreDBSyncCommand message)
|
||||
{
|
||||
var haveNewReleases = Sync();
|
||||
|
||||
foreach (Movie movie in haveNewReleases)
|
||||
{
|
||||
if (!movie.HasPreDBEntry)
|
||||
{
|
||||
movie.HasPreDBEntry = true;
|
||||
_movieService.UpdateMovie(movie);
|
||||
}
|
||||
|
||||
if (movie.Monitored)
|
||||
{
|
||||
//Maybe auto search each movie once?
|
||||
}
|
||||
}
|
||||
|
||||
_eventAggregator.PublishEvent(new PreDBSyncCompleteEvent(haveNewReleases));
|
||||
}
|
||||
|
||||
public bool HasReleases(Movie movie)
|
||||
{
|
||||
var results = GetResults("movies", movie.Title);
|
||||
|
||||
foreach (PreDBResult result in results)
|
||||
{
|
||||
var parsed = Parser.Parser.ParseMovieTitle(result.Title);
|
||||
if (parsed == null)
|
||||
{
|
||||
parsed = new Parser.Model.ParsedMovieInfo { MovieTitle = result.Title, Year = 0 };
|
||||
}
|
||||
var match = _parsingService.Map(parsed, "", new MovieSearchCriteria { Movie = movie });
|
||||
|
||||
if (match != null && match.Movie != null && match.Movie.Id == movie.Id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
10
src/NzbDrone.Core/MetadataSource/PreDB/PreDBSyncCommand.cs
Normal file
10
src/NzbDrone.Core/MetadataSource/PreDB/PreDBSyncCommand.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using NzbDrone.Core.Messaging.Commands;
|
||||
|
||||
namespace NzbDrone.Core.MetadataSource.PreDB
|
||||
{
|
||||
public class PreDBSyncCommand : Command
|
||||
{
|
||||
|
||||
public override bool SendUpdatesToClient => true;
|
||||
}
|
||||
}
|
19
src/NzbDrone.Core/MetadataSource/PreDB/PreDBSyncEvent.cs
Normal file
19
src/NzbDrone.Core/MetadataSource/PreDB/PreDBSyncEvent.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using NzbDrone.Common.Messaging;
|
||||
using NzbDrone.Core.Download;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.MetadataSource.PreDB
|
||||
{
|
||||
public class PreDBSyncCompleteEvent : IEvent
|
||||
{
|
||||
public List<Movie> NewlyReleased { get; private set; }
|
||||
|
||||
public PreDBSyncCompleteEvent(List<Movie> newlyReleased)
|
||||
{
|
||||
NewlyReleased = newlyReleased;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,6 +9,8 @@ using NzbDrone.Common.Http;
|
|||
using NzbDrone.Core.Exceptions;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.MetadataSource.SkyHook.Resource;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using NzbDrone.Core.MetadataSource.PreDB;
|
||||
using NzbDrone.Core.Tv;
|
||||
using System.Threading;
|
||||
using NzbDrone.Core.Parser;
|
||||
|
@ -25,14 +27,16 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
|||
private readonly IHttpRequestBuilderFactory _movieBuilder;
|
||||
private readonly ITmdbConfigService _configService;
|
||||
private readonly IMovieService _movieService;
|
||||
private readonly IPreDBService _predbService;
|
||||
|
||||
public SkyHookProxy(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBuilder, ITmdbConfigService configService, IMovieService movieService, Logger logger)
|
||||
public SkyHookProxy(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBuilder, ITmdbConfigService configService, IMovieService movieService, IPreDBService predbService, Logger logger)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_requestBuilder = requestBuilder.SkyHookTvdb;
|
||||
_movieBuilder = requestBuilder.TMDB;
|
||||
_configService = configService;
|
||||
_movieService = movieService;
|
||||
_predbService = predbService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
@ -66,7 +70,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
|||
return new Tuple<Series, List<Episode>>(series, episodes.ToList());
|
||||
}
|
||||
|
||||
public Movie GetMovieInfo(int TmdbId, Profile profile = null)
|
||||
public Movie GetMovieInfo(int TmdbId, Profile profile = null, bool hasPreDBEntry = false)
|
||||
{
|
||||
var langCode = profile != null ? IsoLanguages.Get(profile.Language).TwoLetterCode : "us";
|
||||
|
||||
|
@ -235,12 +239,25 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
|||
{
|
||||
movie.Status = MovieStatusType.Announced;
|
||||
}
|
||||
|
||||
//since TMDB lacks alot of information lets assume that stuff is released if its been in cinemas for longer than 3 months.
|
||||
if (!movie.PhysicalRelease.HasValue && (movie.Status == MovieStatusType.InCinemas) && (((DateTime.Now).Subtract(movie.InCinemas.Value)).TotalSeconds > 60*60*24*30*3))
|
||||
{
|
||||
movie.Status = MovieStatusType.Released;
|
||||
}
|
||||
|
||||
if (!hasPreDBEntry)
|
||||
{
|
||||
if (_predbService.HasReleases(movie))
|
||||
{
|
||||
movie.HasPreDBEntry = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
movie.HasPreDBEntry = false;
|
||||
}
|
||||
}
|
||||
|
||||
//this matches with the old behavior before the creation of the MovieStatusType.InCinemas
|
||||
/*if (resource.status == "Released")
|
||||
{
|
||||
|
|
|
@ -99,6 +99,7 @@
|
|||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Web.Extensions" />
|
||||
|
@ -890,6 +891,10 @@
|
|||
<Compile Include="Messaging\IProcessMessage.cs" />
|
||||
<Compile Include="MetadataSource\IProvideMovieInfo.cs" />
|
||||
<Compile Include="MetadataSource\ISearchForNewMovie.cs" />
|
||||
<Compile Include="MetadataSource\PreDB\PreDBResult.cs" />
|
||||
<Compile Include="MetadataSource\PreDB\PreDBSyncCommand.cs" />
|
||||
<Compile Include="MetadataSource\PreDB\PreDBSyncEvent.cs" />
|
||||
<Compile Include="MetadataSource\PreDB\PreDBService.cs" />
|
||||
<Compile Include="MetadataSource\SkyHook\Resource\ActorResource.cs" />
|
||||
<Compile Include="MetadataSource\SkyHook\Resource\ConfigurationResource.cs" />
|
||||
<Compile Include="MetadataSource\SkyHook\Resource\EpisodeResource.cs" />
|
||||
|
@ -1260,6 +1265,7 @@
|
|||
<Compile Include="Validation\UrlValidator.cs" />
|
||||
<Compile Include="Datastore\Migration\131_make_parsed_episode_info_nullable.cs" />
|
||||
<Compile Include="Housekeeping\Housekeepers\FixWronglyMatchedMovieFiles.cs" />
|
||||
<Compile Include="Datastore\Migration\135_add_haspredbentry_to_movies.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include=".NETFramework,Version=v4.0,Profile=Client">
|
||||
|
|
|
@ -47,6 +47,7 @@ namespace NzbDrone.Core.Tv
|
|||
public HashSet<int> Tags { get; set; }
|
||||
public AddMovieOptions AddOptions { get; set; }
|
||||
public LazyLoaded<MovieFile> MovieFile { get; set; }
|
||||
public bool HasPreDBEntry { get; set; }
|
||||
public int MovieFileId { get; set; }
|
||||
public List<string> AlternativeTitles { get; set; }
|
||||
public string YouTubeTrailerId{ get; set; }
|
||||
|
@ -73,13 +74,19 @@ namespace NzbDrone.Core.Tv
|
|||
else
|
||||
MinimumAvailabilityDate = DateTime.MaxValue;
|
||||
break;
|
||||
//TODO: might need to handle PreDB but for now treat the same as Released
|
||||
|
||||
case MovieStatusType.Released:
|
||||
case MovieStatusType.PreDB:
|
||||
default:
|
||||
MinimumAvailabilityDate = PhysicalRelease.HasValue ? PhysicalRelease.Value : (InCinemas.HasValue ? InCinemas.Value.AddDays(90) : DateTime.MaxValue);
|
||||
break;
|
||||
}
|
||||
|
||||
if (HasPreDBEntry && MinimumAvailability == MovieStatusType.PreDB)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return DateTime.Now >= MinimumAvailabilityDate.AddDays(delay);
|
||||
}
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ namespace NzbDrone.Core.Tv
|
|||
((v.MinimumAvailability == MovieStatusType.Released && v.Status >= MovieStatusType.Released) ||
|
||||
(v.MinimumAvailability == MovieStatusType.InCinemas && v.Status >= MovieStatusType.InCinemas) ||
|
||||
(v.MinimumAvailability == MovieStatusType.Announced && v.Status >= MovieStatusType.Announced) ||
|
||||
(v.MinimumAvailability == MovieStatusType.PreDB && v.Status >= MovieStatusType.Released));
|
||||
(v.MinimumAvailability == MovieStatusType.PreDB && v.Status >= MovieStatusType.Released || v.HasPreDBEntry == true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace NzbDrone.Core.Tv
|
|||
|
||||
try
|
||||
{
|
||||
movieInfo = _movieInfo.GetMovieInfo(movie.TmdbId, movie.Profile);
|
||||
movieInfo = _movieInfo.GetMovieInfo(movie.TmdbId, movie.Profile, movie.HasPreDBEntry);
|
||||
}
|
||||
catch (MovieNotFoundException)
|
||||
{
|
||||
|
@ -86,6 +86,7 @@ namespace NzbDrone.Core.Tv
|
|||
movie.PhysicalRelease = movieInfo.PhysicalRelease;
|
||||
movie.YouTubeTrailerId = movieInfo.YouTubeTrailerId;
|
||||
movie.Studio = movieInfo.Studio;
|
||||
movie.HasPreDBEntry = movieInfo.HasPreDBEntry;
|
||||
|
||||
try
|
||||
{
|
||||
|
|
|
@ -12,10 +12,6 @@ module.exports = NzbDroneCell.extend({
|
|||
var timeSince = new Date().getTime() - date.getTime();
|
||||
var numOfMonths = timeSince / 1000 / 60 / 60 / 24 / 30;
|
||||
|
||||
if (status === 'released') {
|
||||
this.$el.html('<i class="icon-sonarr-movie-released grid-icon" title="Released"></i>');
|
||||
this._setStatusWeight(3);
|
||||
}
|
||||
|
||||
if (status === 'inCinemas') {
|
||||
this.$el.html('<i class="icon-sonarr-movie-cinemas grid-icon" title="In Cinemas"></i>');
|
||||
|
|
|
@ -92,7 +92,7 @@ Handlebars.registerHelper('GetStatus', function() {
|
|||
return new Handlebars.SafeString('<i class="icon-sonarr-movie-released grid-icon" title=""></i> Released');
|
||||
}
|
||||
|
||||
else if (!monitored) {
|
||||
if (!monitored) {
|
||||
return new Handlebars.SafeString('<i class="icon-sonarr-series-unmonitored grid-icon" title=""></i> Not Monitored');
|
||||
}
|
||||
});
|
||||
|
@ -105,16 +105,13 @@ Handlebars.registerHelper('GetBannerStatus', function() {
|
|||
//var timeSince = new Date().getTime() - date.getTime();
|
||||
//var numOfMonths = timeSince / 1000 / 60 / 60 / 24 / 30;
|
||||
|
||||
if (status === "announced") {
|
||||
return new Handlebars.SafeString('<div class="announced-banner"><i class="icon-sonarr-movie-announced grid-icon" title=""></i> Announced</div>');
|
||||
}
|
||||
|
||||
if (status === "inCinemas") {
|
||||
return new Handlebars.SafeString('<div class="cinemas-banner"><i class="icon-sonarr-movie-cinemas grid-icon" title=""></i> In Cinemas</div>');
|
||||
}
|
||||
|
||||
if (status === 'released') {
|
||||
return new Handlebars.SafeString('<div class="released-banner"><i class="icon-sonarr-movie-released grid-icon" title=""></i> Released</div>');
|
||||
if (status === "announced") {
|
||||
return new Handlebars.SafeString('<div class="announced-banner"><i class="icon-sonarr-movie-announced grid-icon" title=""></i> Announced</div>');
|
||||
}
|
||||
else if (!monitored) {
|
||||
return new Handlebars.SafeString('<div class="announced-banner"><i class="icon-sonarr-series-unmonitored grid-icon" title=""></i> Not Monitored</div>');
|
||||
|
|
|
@ -126,6 +126,12 @@ module.exports = Marionette.Layout.extend({
|
|||
command : 'rsssync',
|
||||
errorMessage : 'RSS Sync Failed!'
|
||||
},
|
||||
{
|
||||
title : "PreDB Sync",
|
||||
icon : "icon-sonarr-refresh",
|
||||
command : "predbsync",
|
||||
errorMessage : "PreDB Sync Failed!"
|
||||
},
|
||||
{
|
||||
title : 'Update Library',
|
||||
icon : 'icon-sonarr-refresh',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue