mirror of
https://github.com/Radarr/Radarr.git
synced 2024-11-04 10:02:40 +01:00
Fixed a few things with displaying the Movie Details Page. Implemented the first round of Searching for and Downloading movie Releases. ATM this is still a bit hacky and alot of things need to be cleaned up. However, one can now manually search for and download (only in qBittorrent) a movie torrent.
This commit is contained in:
parent
16e35f68bb
commit
2a3b0304cb
@ -82,6 +82,11 @@ private List<ReleaseResource> GetReleases()
|
|||||||
return GetEpisodeReleases(Request.Query.episodeId);
|
return GetEpisodeReleases(Request.Query.episodeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Request.Query.movieId != null)
|
||||||
|
{
|
||||||
|
return GetMovieReleases(Request.Query.movieId);
|
||||||
|
}
|
||||||
|
|
||||||
return GetRss();
|
return GetRss();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,6 +107,27 @@ private List<ReleaseResource> GetEpisodeReleases(int episodeId)
|
|||||||
return new List<ReleaseResource>();
|
return new List<ReleaseResource>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<ReleaseResource> GetMovieReleases(int movieId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var decisions = _nzbSearchService.MovieSearch(movieId, true);
|
||||||
|
var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisionsForMovies(decisions);
|
||||||
|
|
||||||
|
return MapDecisions(prioritizedDecisions);
|
||||||
|
}
|
||||||
|
catch (NotImplementedException ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "One or more indexer you selected does not support movie search yet: " + ex.Message);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Movie search failed: " + ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new List<ReleaseResource>();
|
||||||
|
}
|
||||||
|
|
||||||
private List<ReleaseResource> GetRss()
|
private List<ReleaseResource> GetRss()
|
||||||
{
|
{
|
||||||
var reports = _rssFetcherAndParser.Fetch();
|
var reports = _rssFetcherAndParser.Fetch();
|
||||||
|
@ -86,6 +86,11 @@ public static ReleaseResource ToResource(this DownloadDecision model)
|
|||||||
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;
|
||||||
|
if (model.IsForMovie)
|
||||||
|
{
|
||||||
|
downloadAllowed = model.RemoteMovie.DownloadAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Clean this mess up. don't mix data from multiple classes, use sub-resources instead? (Got a huge Deja Vu, didn't we talk about this already once?)
|
// TODO: Clean this mess up. don't mix data from multiple classes, use sub-resources instead? (Got a huge Deja Vu, didn't we talk about this already once?)
|
||||||
return new ReleaseResource
|
return new ReleaseResource
|
||||||
@ -119,7 +124,7 @@ public static ReleaseResource ToResource(this DownloadDecision model)
|
|||||||
CommentUrl = releaseInfo.CommentUrl,
|
CommentUrl = releaseInfo.CommentUrl,
|
||||||
DownloadUrl = releaseInfo.DownloadUrl,
|
DownloadUrl = releaseInfo.DownloadUrl,
|
||||||
InfoUrl = releaseInfo.InfoUrl,
|
InfoUrl = releaseInfo.InfoUrl,
|
||||||
DownloadAllowed = remoteEpisode.DownloadAllowed,
|
DownloadAllowed = downloadAllowed,
|
||||||
//ReleaseWeight
|
//ReleaseWeight
|
||||||
|
|
||||||
MagnetUrl = torrentInfo.MagnetUrl,
|
MagnetUrl = torrentInfo.MagnetUrl,
|
||||||
|
@ -178,8 +178,9 @@ public void should_not_add_to_downloaded_list_when_download_fails()
|
|||||||
public void should_return_an_empty_list_when_none_are_appproved()
|
public void should_return_an_empty_list_when_none_are_appproved()
|
||||||
{
|
{
|
||||||
var decisions = new List<DownloadDecision>();
|
var decisions = new List<DownloadDecision>();
|
||||||
decisions.Add(new DownloadDecision(null, new Rejection("Failure!")));
|
RemoteEpisode ep = null;
|
||||||
decisions.Add(new DownloadDecision(null, new Rejection("Failure!")));
|
decisions.Add(new DownloadDecision(ep, new Rejection("Failure!")));
|
||||||
|
decisions.Add(new DownloadDecision(ep, new Rejection("Failure!")));
|
||||||
|
|
||||||
Subject.GetQualifiedReports(decisions).Should().BeEmpty();
|
Subject.GetQualifiedReports(decisions).Should().BeEmpty();
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,10 @@ namespace NzbDrone.Core.DecisionEngine
|
|||||||
public class DownloadDecision
|
public class DownloadDecision
|
||||||
{
|
{
|
||||||
public RemoteEpisode RemoteEpisode { get; private set; }
|
public RemoteEpisode RemoteEpisode { get; private set; }
|
||||||
|
|
||||||
|
public RemoteMovie RemoteMovie { get; private set; }
|
||||||
|
|
||||||
|
public bool IsForMovie = false;
|
||||||
public IEnumerable<Rejection> Rejections { get; private set; }
|
public IEnumerable<Rejection> Rejections { get; private set; }
|
||||||
|
|
||||||
public bool Approved => !Rejections.Any();
|
public bool Approved => !Rejections.Any();
|
||||||
@ -30,6 +34,23 @@ public bool Rejected
|
|||||||
public DownloadDecision(RemoteEpisode episode, params Rejection[] rejections)
|
public DownloadDecision(RemoteEpisode episode, params Rejection[] rejections)
|
||||||
{
|
{
|
||||||
RemoteEpisode = episode;
|
RemoteEpisode = episode;
|
||||||
|
RemoteMovie = new RemoteMovie
|
||||||
|
{
|
||||||
|
Release = episode.Release,
|
||||||
|
ParsedEpisodeInfo = episode.ParsedEpisodeInfo
|
||||||
|
};
|
||||||
|
Rejections = rejections.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DownloadDecision(RemoteMovie movie, params Rejection[] rejections)
|
||||||
|
{
|
||||||
|
RemoteMovie = movie;
|
||||||
|
RemoteEpisode = new RemoteEpisode
|
||||||
|
{
|
||||||
|
Release = movie.Release,
|
||||||
|
ParsedEpisodeInfo = movie.ParsedEpisodeInfo
|
||||||
|
};
|
||||||
|
IsForMovie = true;
|
||||||
Rejections = rejections.ToList();
|
Rejections = rejections.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,9 +37,83 @@ public List<DownloadDecision> GetRssDecision(List<ReleaseInfo> reports)
|
|||||||
|
|
||||||
public List<DownloadDecision> GetSearchDecision(List<ReleaseInfo> reports, SearchCriteriaBase searchCriteriaBase)
|
public List<DownloadDecision> GetSearchDecision(List<ReleaseInfo> reports, SearchCriteriaBase searchCriteriaBase)
|
||||||
{
|
{
|
||||||
|
if (searchCriteriaBase.Movie != null)
|
||||||
|
{
|
||||||
|
return GetMovieDecisions(reports, searchCriteriaBase).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
return GetDecisions(reports, searchCriteriaBase).ToList();
|
return GetDecisions(reports, searchCriteriaBase).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IEnumerable<DownloadDecision> GetMovieDecisions(List<ReleaseInfo> reports, SearchCriteriaBase searchCriteria = null)
|
||||||
|
{
|
||||||
|
if (reports.Any())
|
||||||
|
{
|
||||||
|
_logger.ProgressInfo("Processing {0} releases", reports.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.ProgressInfo("No results found");
|
||||||
|
}
|
||||||
|
|
||||||
|
var reportNumber = 1;
|
||||||
|
|
||||||
|
foreach (var report in reports)
|
||||||
|
{
|
||||||
|
DownloadDecision decision = null;
|
||||||
|
_logger.ProgressTrace("Processing release {0}/{1}", reportNumber, reports.Count);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var parsedEpisodeInfo = Parser.Parser.ParseTitle(report.Title);
|
||||||
|
|
||||||
|
if (parsedEpisodeInfo != null && !parsedEpisodeInfo.SeriesTitle.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
RemoteMovie remoteEpisode = _parsingService.Map(parsedEpisodeInfo, "", searchCriteria);
|
||||||
|
remoteEpisode.Release = report;
|
||||||
|
|
||||||
|
if (remoteEpisode.Movie == null)
|
||||||
|
{
|
||||||
|
//remoteEpisode.DownloadAllowed = true; //Fuck you :)
|
||||||
|
//decision = GetDecisionForReport(remoteEpisode, searchCriteria);
|
||||||
|
decision = new DownloadDecision(remoteEpisode, new Rejection("Unknown release. Movie not Found."));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
remoteEpisode.DownloadAllowed = true;
|
||||||
|
//decision = GetDecisionForReport(remoteEpisode, searchCriteria); TODO: Rewrite this for movies!
|
||||||
|
decision = new DownloadDecision(remoteEpisode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error(e, "Couldn't process release.");
|
||||||
|
|
||||||
|
var remoteEpisode = new RemoteEpisode { Release = report };
|
||||||
|
decision = new DownloadDecision(remoteEpisode, new Rejection("Unexpected error processing release"));
|
||||||
|
}
|
||||||
|
|
||||||
|
reportNumber++;
|
||||||
|
|
||||||
|
if (decision != null)
|
||||||
|
{
|
||||||
|
if (decision.Rejections.Any())
|
||||||
|
{
|
||||||
|
_logger.Debug("Release rejected for the following reasons: {0}", string.Join(", ", decision.Rejections));
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Debug("Release accepted");
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return decision;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private IEnumerable<DownloadDecision> GetDecisions(List<ReleaseInfo> reports, SearchCriteriaBase searchCriteria = null)
|
private IEnumerable<DownloadDecision> GetDecisions(List<ReleaseInfo> reports, SearchCriteriaBase searchCriteria = null)
|
||||||
{
|
{
|
||||||
if (reports.Any())
|
if (reports.Any())
|
||||||
@ -82,7 +156,7 @@ private IEnumerable<DownloadDecision> GetDecisions(List<ReleaseInfo> reports, Se
|
|||||||
{
|
{
|
||||||
//remoteEpisode.DownloadAllowed = true; //Fuck you :)
|
//remoteEpisode.DownloadAllowed = true; //Fuck you :)
|
||||||
//decision = GetDecisionForReport(remoteEpisode, searchCriteria);
|
//decision = GetDecisionForReport(remoteEpisode, searchCriteria);
|
||||||
decision = new DownloadDecision(remoteEpisode, new Rejection("Unknown release. Movie not Found."));
|
decision = new DownloadDecision(remoteEpisode, new Rejection("Unknown release. Series not Found."));
|
||||||
}
|
}
|
||||||
else if (remoteEpisode.Episodes.Empty())
|
else if (remoteEpisode.Episodes.Empty())
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,7 @@ namespace NzbDrone.Core.DecisionEngine
|
|||||||
public interface IPrioritizeDownloadDecision
|
public interface IPrioritizeDownloadDecision
|
||||||
{
|
{
|
||||||
List<DownloadDecision> PrioritizeDecisions(List<DownloadDecision> decisions);
|
List<DownloadDecision> PrioritizeDecisions(List<DownloadDecision> decisions);
|
||||||
|
List<DownloadDecision> PrioritizeDecisionsForMovies(List<DownloadDecision> decisions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DownloadDecisionPriorizationService : IPrioritizeDownloadDecision
|
public class DownloadDecisionPriorizationService : IPrioritizeDownloadDecision
|
||||||
@ -29,5 +30,17 @@ public List<DownloadDecision> PrioritizeDecisions(List<DownloadDecision> decisio
|
|||||||
.Union(decisions.Where(c => c.RemoteEpisode.Series == null))
|
.Union(decisions.Where(c => c.RemoteEpisode.Series == null))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<DownloadDecision> PrioritizeDecisionsForMovies(List<DownloadDecision> decisions)
|
||||||
|
{
|
||||||
|
return decisions.Where(c => c.RemoteMovie.Movie != null)
|
||||||
|
/*.GroupBy(c => c.RemoteMovie.Movie.Id, (movieId, downloadDecisions) =>
|
||||||
|
{
|
||||||
|
return downloadDecisions.OrderByDescending(decision => decision, new DownloadDecisionComparer(_delayProfileService));
|
||||||
|
})
|
||||||
|
.SelectMany(c => c)*/
|
||||||
|
.Union(decisions.Where(c => c.RemoteMovie.Movie == null))
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ protected override string AddFromMagnetLink(RemoteEpisode remoteEpisode, string
|
|||||||
_proxy.SetTorrentLabel(hash.ToLower(), Settings.TvCategory, Settings);
|
_proxy.SetTorrentLabel(hash.ToLower(), Settings.TvCategory, Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
var isRecentEpisode = remoteEpisode.IsRecentEpisode();
|
var isRecentEpisode = true;//remoteEpisode.IsRecentEpisode(); TODO: Update to use RemoteMovie!
|
||||||
|
|
||||||
if (isRecentEpisode && Settings.RecentTvPriority == (int)QBittorrentPriority.First ||
|
if (isRecentEpisode && Settings.RecentTvPriority == (int)QBittorrentPriority.First ||
|
||||||
!isRecentEpisode && Settings.OlderTvPriority == (int)QBittorrentPriority.First)
|
!isRecentEpisode && Settings.OlderTvPriority == (int)QBittorrentPriority.First)
|
||||||
|
@ -41,8 +41,8 @@ public DownloadService(IProvideDownloadClient downloadClientProvider,
|
|||||||
|
|
||||||
public void DownloadReport(RemoteEpisode remoteEpisode)
|
public void DownloadReport(RemoteEpisode remoteEpisode)
|
||||||
{
|
{
|
||||||
Ensure.That(remoteEpisode.Series, () => remoteEpisode.Series).IsNotNull();
|
//Ensure.That(remoteEpisode.Series, () => remoteEpisode.Series).IsNotNull();
|
||||||
Ensure.That(remoteEpisode.Episodes, () => remoteEpisode.Episodes).HasItems();
|
//Ensure.That(remoteEpisode.Episodes, () => remoteEpisode.Episodes).HasItems(); TODO update this shit
|
||||||
|
|
||||||
var downloadTitle = remoteEpisode.Release.Title;
|
var downloadTitle = remoteEpisode.Release.Title;
|
||||||
var downloadClient = _downloadClientProvider.GetDownloadClient(remoteEpisode.Release.DownloadProtocol);
|
var downloadClient = _downloadClientProvider.GetDownloadClient(remoteEpisode.Release.DownloadProtocol);
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
namespace NzbDrone.Core.IndexerSearch.Definitions
|
||||||
|
{
|
||||||
|
public class MovieSearchCriteria : SearchCriteriaBase
|
||||||
|
{
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format("[{0}]", Movie.Title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,8 @@ public abstract class SearchCriteriaBase
|
|||||||
private static readonly Regex BeginningThe = new Regex(@"^the\s", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
private static readonly Regex BeginningThe = new Regex(@"^the\s", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
|
|
||||||
public Series Series { get; set; }
|
public Series Series { get; set; }
|
||||||
|
|
||||||
|
public Movie Movie { get; set; }
|
||||||
public List<string> SceneTitles { get; set; }
|
public List<string> SceneTitles { get; set; }
|
||||||
public List<Episode> Episodes { get; set; }
|
public List<Episode> Episodes { get; set; }
|
||||||
public virtual bool MonitoredEpisodesOnly { get; set; }
|
public virtual bool MonitoredEpisodesOnly { get; set; }
|
||||||
|
@ -19,6 +19,8 @@ public interface ISearchForNzb
|
|||||||
{
|
{
|
||||||
List<DownloadDecision> EpisodeSearch(int episodeId, bool userInvokedSearch);
|
List<DownloadDecision> EpisodeSearch(int episodeId, bool userInvokedSearch);
|
||||||
List<DownloadDecision> EpisodeSearch(Episode episode, bool userInvokedSearch);
|
List<DownloadDecision> EpisodeSearch(Episode episode, bool userInvokedSearch);
|
||||||
|
List<DownloadDecision> MovieSearch(int movieId, bool userInvokedSearch);
|
||||||
|
List<DownloadDecision> MovieSearch(Movie movie, bool userInvokedSearch);
|
||||||
List<DownloadDecision> SeasonSearch(int seriesId, int seasonNumber, bool missingOnly, bool userInvokedSearch);
|
List<DownloadDecision> SeasonSearch(int seriesId, int seasonNumber, bool missingOnly, bool userInvokedSearch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,6 +31,7 @@ public class NzbSearchService : ISearchForNzb
|
|||||||
private readonly ISeriesService _seriesService;
|
private readonly ISeriesService _seriesService;
|
||||||
private readonly IEpisodeService _episodeService;
|
private readonly IEpisodeService _episodeService;
|
||||||
private readonly IMakeDownloadDecision _makeDownloadDecision;
|
private readonly IMakeDownloadDecision _makeDownloadDecision;
|
||||||
|
private readonly IMovieService _movieService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public NzbSearchService(IIndexerFactory indexerFactory,
|
public NzbSearchService(IIndexerFactory indexerFactory,
|
||||||
@ -36,6 +39,7 @@ public NzbSearchService(IIndexerFactory indexerFactory,
|
|||||||
ISeriesService seriesService,
|
ISeriesService seriesService,
|
||||||
IEpisodeService episodeService,
|
IEpisodeService episodeService,
|
||||||
IMakeDownloadDecision makeDownloadDecision,
|
IMakeDownloadDecision makeDownloadDecision,
|
||||||
|
IMovieService movieService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
{
|
{
|
||||||
_indexerFactory = indexerFactory;
|
_indexerFactory = indexerFactory;
|
||||||
@ -43,6 +47,7 @@ public NzbSearchService(IIndexerFactory indexerFactory,
|
|||||||
_seriesService = seriesService;
|
_seriesService = seriesService;
|
||||||
_episodeService = episodeService;
|
_episodeService = episodeService;
|
||||||
_makeDownloadDecision = makeDownloadDecision;
|
_makeDownloadDecision = makeDownloadDecision;
|
||||||
|
_movieService = movieService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +58,20 @@ public List<DownloadDecision> EpisodeSearch(int episodeId, bool userInvokedSearc
|
|||||||
return EpisodeSearch(episode, userInvokedSearch);
|
return EpisodeSearch(episode, userInvokedSearch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<DownloadDecision> MovieSearch(int movieId, bool userInvokedSearch)
|
||||||
|
{
|
||||||
|
var movie = _movieService.GetMovie(movieId);
|
||||||
|
|
||||||
|
return MovieSearch(movie, userInvokedSearch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DownloadDecision> MovieSearch(Movie movie, bool userInvokedSearch)
|
||||||
|
{
|
||||||
|
var searchSpec = Get<MovieSearchCriteria>(movie, userInvokedSearch);
|
||||||
|
|
||||||
|
return Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec);
|
||||||
|
}
|
||||||
|
|
||||||
public List<DownloadDecision> EpisodeSearch(Episode episode, bool userInvokedSearch)
|
public List<DownloadDecision> EpisodeSearch(Episode episode, bool userInvokedSearch)
|
||||||
{
|
{
|
||||||
var series = _seriesService.GetSeries(episode.SeriesId);
|
var series = _seriesService.GetSeries(episode.SeriesId);
|
||||||
@ -245,6 +264,23 @@ private List<DownloadDecision> SearchAnimeSeason(Series series, List<Episode> ep
|
|||||||
return spec;
|
return spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TSpec Get<TSpec>(Movie movie, bool userInvokedSearch) where TSpec : SearchCriteriaBase, new()
|
||||||
|
{
|
||||||
|
var spec = new TSpec();
|
||||||
|
|
||||||
|
spec.Movie = movie;
|
||||||
|
/*spec.SceneTitles = _sceneMapping.GetSceneNames(series.TvdbId,
|
||||||
|
episodes.Select(e => e.SeasonNumber).Distinct().ToList(),
|
||||||
|
episodes.Select(e => e.SceneSeasonNumber ?? e.SeasonNumber).Distinct().ToList());
|
||||||
|
|
||||||
|
spec.Episodes = episodes;
|
||||||
|
|
||||||
|
spec.SceneTitles.Add(series.Title);*/
|
||||||
|
spec.UserInvokedSearch = userInvokedSearch;
|
||||||
|
|
||||||
|
return spec;
|
||||||
|
}
|
||||||
|
|
||||||
private List<DownloadDecision> Dispatch(Func<IIndexer, IEnumerable<ReleaseInfo>> searchAction, SearchCriteriaBase criteriaBase)
|
private List<DownloadDecision> Dispatch(Func<IIndexer, IEnumerable<ReleaseInfo>> searchAction, SearchCriteriaBase criteriaBase)
|
||||||
{
|
{
|
||||||
var indexers = _indexerFactory.SearchEnabled();
|
var indexers = _indexerFactory.SearchEnabled();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
|
|
||||||
@ -22,6 +23,11 @@ public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearch
|
|||||||
return new IndexerPageableRequestChain();
|
return new IndexerPageableRequestChain();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
return new IndexerPageableRequestChain();
|
||||||
|
}
|
||||||
|
|
||||||
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
|
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
|
||||||
{
|
{
|
||||||
return new IndexerPageableRequestChain();
|
return new IndexerPageableRequestChain();
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers.BroadcastheNet
|
namespace NzbDrone.Core.Indexers.BroadcastheNet
|
||||||
{
|
{
|
||||||
@ -189,5 +190,10 @@ private IEnumerable<IndexerRequest> GetPagedRequests(int maxPages, BroadcastheNe
|
|||||||
yield return new IndexerRequest(builder.Build());
|
yield return new IndexerRequest(builder.Build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
return new IndexerPageableRequestChain();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
@ -84,5 +85,10 @@ private string CleanTitle(string title)
|
|||||||
{
|
{
|
||||||
return RemoveCharactersRegex.Replace(title, "");
|
return RemoveCharactersRegex.Replace(title, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
return new IndexerPageableRequestChain();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Common.Serializer;
|
using NzbDrone.Common.Serializer;
|
||||||
@ -128,5 +129,10 @@ private IEnumerable<IndexerRequest> GetRequest(TorrentQuery query)
|
|||||||
|
|
||||||
yield return new IndexerRequest(request);
|
yield return new IndexerRequest(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
return new IndexerPageableRequestChain();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,18 @@ public override IList<ReleaseInfo> Fetch(SpecialEpisodeSearchCriteria searchCrit
|
|||||||
return FetchReleases(generator.GetSearchRequests(searchCriteria));
|
return FetchReleases(generator.GetSearchRequests(searchCriteria));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override IList<ReleaseInfo> Fetch(MovieSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
if (!SupportsSearch)
|
||||||
|
{
|
||||||
|
return new List<ReleaseInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var generator = GetRequestGenerator();
|
||||||
|
|
||||||
|
return FetchReleases(generator.GetSearchRequests(searchCriteria));
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual IList<ReleaseInfo> FetchReleases(IndexerPageableRequestChain pageableRequestChain, bool isRecent = false)
|
protected virtual IList<ReleaseInfo> FetchReleases(IndexerPageableRequestChain pageableRequestChain, bool isRecent = false)
|
||||||
{
|
{
|
||||||
var releases = new List<ReleaseInfo>();
|
var releases = new List<ReleaseInfo>();
|
||||||
|
@ -17,5 +17,6 @@ public interface IIndexer : IProvider
|
|||||||
IList<ReleaseInfo> Fetch(DailyEpisodeSearchCriteria searchCriteria);
|
IList<ReleaseInfo> Fetch(DailyEpisodeSearchCriteria searchCriteria);
|
||||||
IList<ReleaseInfo> Fetch(AnimeEpisodeSearchCriteria searchCriteria);
|
IList<ReleaseInfo> Fetch(AnimeEpisodeSearchCriteria searchCriteria);
|
||||||
IList<ReleaseInfo> Fetch(SpecialEpisodeSearchCriteria searchCriteria);
|
IList<ReleaseInfo> Fetch(SpecialEpisodeSearchCriteria searchCriteria);
|
||||||
|
IList<ReleaseInfo> Fetch(MovieSearchCriteria searchCriteria);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,5 +10,6 @@ public interface IIndexerRequestGenerator
|
|||||||
IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria);
|
IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria);
|
||||||
IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria);
|
IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria);
|
||||||
IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria);
|
IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria);
|
||||||
|
IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
|
|
||||||
@ -22,6 +23,11 @@ public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearch
|
|||||||
return new IndexerPageableRequestChain();
|
return new IndexerPageableRequestChain();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
return new IndexerPageableRequestChain();
|
||||||
|
}
|
||||||
|
|
||||||
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
|
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
|
||||||
{
|
{
|
||||||
return new IndexerPageableRequestChain();
|
return new IndexerPageableRequestChain();
|
||||||
|
@ -67,6 +67,7 @@ public virtual IEnumerable<ProviderDefinition> DefaultDefinitions
|
|||||||
public abstract IList<ReleaseInfo> Fetch(DailyEpisodeSearchCriteria searchCriteria);
|
public abstract IList<ReleaseInfo> Fetch(DailyEpisodeSearchCriteria searchCriteria);
|
||||||
public abstract IList<ReleaseInfo> Fetch(AnimeEpisodeSearchCriteria searchCriteria);
|
public abstract IList<ReleaseInfo> Fetch(AnimeEpisodeSearchCriteria searchCriteria);
|
||||||
public abstract IList<ReleaseInfo> Fetch(SpecialEpisodeSearchCriteria searchCriteria);
|
public abstract IList<ReleaseInfo> Fetch(SpecialEpisodeSearchCriteria searchCriteria);
|
||||||
|
public abstract IList<ReleaseInfo> Fetch(MovieSearchCriteria searchCriteria);
|
||||||
|
|
||||||
protected virtual IList<ReleaseInfo> CleanupReleases(IEnumerable<ReleaseInfo> releases)
|
protected virtual IList<ReleaseInfo> CleanupReleases(IEnumerable<ReleaseInfo> releases)
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
@ -147,5 +148,10 @@ private string PrepareQuery(string query)
|
|||||||
{
|
{
|
||||||
return query.Replace('+', ' ');
|
return query.Replace('+', ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
return new IndexerPageableRequestChain();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
@ -273,5 +274,10 @@ private static string NewsnabifyTitle(string title)
|
|||||||
{
|
{
|
||||||
return title.Replace("+", "%20");
|
return title.Replace("+", "%20");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
return new IndexerPageableRequestChain();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
|
|
||||||
@ -102,5 +103,10 @@ private string PrepareQuery(string query)
|
|||||||
{
|
{
|
||||||
return query.Replace(' ', '+');
|
return query.Replace(' ', '+');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
return new IndexerPageableRequestChain();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
@ -101,5 +102,10 @@ private IEnumerable<IndexerRequest> GetPagedRequests(string query)
|
|||||||
|
|
||||||
yield return new IndexerRequest(url.ToString(), HttpAccept.Rss);
|
yield return new IndexerRequest(url.ToString(), HttpAccept.Rss);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
return new IndexerPageableRequestChain();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
@ -88,13 +89,12 @@ private IEnumerable<IndexerRequest> GetPagedRequests(string mode, int? tvdbId, s
|
|||||||
|
|
||||||
if (tvdbId.HasValue)
|
if (tvdbId.HasValue)
|
||||||
{
|
{
|
||||||
string imdbId = string.Format("tt{0:D7}", tvdbId);
|
requestBuilder.AddQueryParam("search_tvdb", tvdbId.Value);
|
||||||
requestBuilder.AddQueryParam("search_imdb", imdbId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (query.IsNotNullOrWhiteSpace())
|
if (query.IsNotNullOrWhiteSpace())
|
||||||
{
|
{
|
||||||
//requestBuilder.AddQueryParam("search_string", string.Format(query, args));
|
requestBuilder.AddQueryParam("search_string", string.Format(query, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Settings.RankedOnly)
|
if (!Settings.RankedOnly)
|
||||||
@ -102,6 +102,36 @@ private IEnumerable<IndexerRequest> GetPagedRequests(string mode, int? tvdbId, s
|
|||||||
requestBuilder.AddQueryParam("ranked", "0");
|
requestBuilder.AddQueryParam("ranked", "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
requestBuilder.AddQueryParam("category", "tv");
|
||||||
|
requestBuilder.AddQueryParam("limit", "100");
|
||||||
|
requestBuilder.AddQueryParam("token", _tokenProvider.GetToken(Settings));
|
||||||
|
requestBuilder.AddQueryParam("format", "json_extended");
|
||||||
|
requestBuilder.AddQueryParam("app_id", "Sonarr");
|
||||||
|
|
||||||
|
yield return new IndexerRequest(requestBuilder.Build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<IndexerRequest> GetMovieRequest(MovieSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
var requestBuilder = new HttpRequestBuilder(Settings.BaseUrl)
|
||||||
|
.Resource("/pubapi_v2.php")
|
||||||
|
.Accept(HttpAccept.Json);
|
||||||
|
|
||||||
|
if (Settings.CaptchaToken.IsNotNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
requestBuilder.UseSimplifiedUserAgent = true;
|
||||||
|
requestBuilder.SetCookie("cf_clearance", Settings.CaptchaToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
requestBuilder.AddQueryParam("mode", "search");
|
||||||
|
|
||||||
|
requestBuilder.AddQueryParam("search_imdb", searchCriteria.Movie.ImdbId);
|
||||||
|
|
||||||
|
if (!Settings.RankedOnly)
|
||||||
|
{
|
||||||
|
requestBuilder.AddQueryParam("ranked", "0");
|
||||||
|
}
|
||||||
|
|
||||||
requestBuilder.AddQueryParam("category", "movies");
|
requestBuilder.AddQueryParam("category", "movies");
|
||||||
requestBuilder.AddQueryParam("limit", "100");
|
requestBuilder.AddQueryParam("limit", "100");
|
||||||
requestBuilder.AddQueryParam("token", _tokenProvider.GetToken(Settings));
|
requestBuilder.AddQueryParam("token", _tokenProvider.GetToken(Settings));
|
||||||
@ -110,5 +140,18 @@ private IEnumerable<IndexerRequest> GetPagedRequests(string mode, int? tvdbId, s
|
|||||||
|
|
||||||
yield return new IndexerRequest(requestBuilder.Build());
|
yield return new IndexerRequest(requestBuilder.Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
var pageableRequests = new IndexerPageableRequestChain();
|
||||||
|
|
||||||
|
pageableRequests.Add(GetMovieRequest(searchCriteria));
|
||||||
|
|
||||||
|
return pageableRequests;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using NzbDrone.Common.Http;
|
using System;
|
||||||
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers
|
namespace NzbDrone.Core.Indexers
|
||||||
@ -22,6 +23,11 @@ public virtual IndexerPageableRequestChain GetRecentRequests()
|
|||||||
return pageableRequests;
|
return pageableRequests;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria)
|
public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria)
|
||||||
{
|
{
|
||||||
return new IndexerPageableRequestChain();
|
return new IndexerPageableRequestChain();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
@ -23,6 +24,11 @@ public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearch
|
|||||||
return new IndexerPageableRequestChain();
|
return new IndexerPageableRequestChain();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
return new IndexerPageableRequestChain();
|
||||||
|
}
|
||||||
|
|
||||||
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
|
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
|
||||||
{
|
{
|
||||||
return new IndexerPageableRequestChain();
|
return new IndexerPageableRequestChain();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
|
|
||||||
@ -22,6 +23,11 @@ public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearch
|
|||||||
return new IndexerPageableRequestChain();
|
return new IndexerPageableRequestChain();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
return new IndexerPageableRequestChain();
|
||||||
|
}
|
||||||
|
|
||||||
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
|
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
|
||||||
{
|
{
|
||||||
return new IndexerPageableRequestChain();
|
return new IndexerPageableRequestChain();
|
||||||
|
@ -7,7 +7,9 @@
|
|||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Indexers.Newznab;
|
using NzbDrone.Core.Indexers.Newznab;
|
||||||
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
using NzbDrone.Core.Parser;
|
using NzbDrone.Core.Parser;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.ThingiProvider;
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers.Torznab
|
namespace NzbDrone.Core.Indexers.Torznab
|
||||||
@ -110,5 +112,6 @@ protected virtual ValidationFailure TestCapabilities()
|
|||||||
return new ValidationFailure(string.Empty, "Unable to connect to indexer, check the log for more details");
|
return new ValidationFailure(string.Empty, "Unable to connect to indexer, check the log for more details");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
using NLog;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NLog;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
using NzbDrone.Core.Parser;
|
using NzbDrone.Core.Parser;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.ThingiProvider;
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers.Wombles
|
namespace NzbDrone.Core.Indexers.Wombles
|
||||||
|
20
src/NzbDrone.Core/MediaFiles/Commands/RescanMovieCommand.cs
Normal file
20
src/NzbDrone.Core/MediaFiles/Commands/RescanMovieCommand.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.Commands
|
||||||
|
{
|
||||||
|
public class RescanMovieCommand : Command
|
||||||
|
{
|
||||||
|
public int? MovieId { get; set; }
|
||||||
|
|
||||||
|
public override bool SendUpdatesToClient => true;
|
||||||
|
|
||||||
|
public RescanMovieCommand()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public RescanMovieCommand(int movieId)
|
||||||
|
{
|
||||||
|
MovieId = movieId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||||||
public interface IDiskScanService
|
public interface IDiskScanService
|
||||||
{
|
{
|
||||||
void Scan(Series series);
|
void Scan(Series series);
|
||||||
|
void Scan(Movie movie);
|
||||||
string[] GetVideoFiles(string path, bool allDirectories = true);
|
string[] GetVideoFiles(string path, bool allDirectories = true);
|
||||||
string[] GetNonVideoFiles(string path, bool allDirectories = true);
|
string[] GetNonVideoFiles(string path, bool allDirectories = true);
|
||||||
List<string> FilterFiles(Series series, IEnumerable<string> files);
|
List<string> FilterFiles(Series series, IEnumerable<string> files);
|
||||||
@ -30,6 +31,8 @@ public interface IDiskScanService
|
|||||||
public class DiskScanService :
|
public class DiskScanService :
|
||||||
IDiskScanService,
|
IDiskScanService,
|
||||||
IHandle<SeriesUpdatedEvent>,
|
IHandle<SeriesUpdatedEvent>,
|
||||||
|
IHandle<MovieUpdatedEvent>,
|
||||||
|
IExecute<RescanMovieCommand>,
|
||||||
IExecute<RescanSeriesCommand>
|
IExecute<RescanSeriesCommand>
|
||||||
{
|
{
|
||||||
private readonly IDiskProvider _diskProvider;
|
private readonly IDiskProvider _diskProvider;
|
||||||
@ -39,6 +42,7 @@ public class DiskScanService :
|
|||||||
private readonly ISeriesService _seriesService;
|
private readonly ISeriesService _seriesService;
|
||||||
private readonly IMediaFileTableCleanupService _mediaFileTableCleanupService;
|
private readonly IMediaFileTableCleanupService _mediaFileTableCleanupService;
|
||||||
private readonly IEventAggregator _eventAggregator;
|
private readonly IEventAggregator _eventAggregator;
|
||||||
|
private readonly IMovieService _movieService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public DiskScanService(IDiskProvider diskProvider,
|
public DiskScanService(IDiskProvider diskProvider,
|
||||||
@ -48,6 +52,7 @@ public DiskScanService(IDiskProvider diskProvider,
|
|||||||
ISeriesService seriesService,
|
ISeriesService seriesService,
|
||||||
IMediaFileTableCleanupService mediaFileTableCleanupService,
|
IMediaFileTableCleanupService mediaFileTableCleanupService,
|
||||||
IEventAggregator eventAggregator,
|
IEventAggregator eventAggregator,
|
||||||
|
IMovieService movieService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
{
|
{
|
||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
||||||
@ -57,6 +62,7 @@ public DiskScanService(IDiskProvider diskProvider,
|
|||||||
_seriesService = seriesService;
|
_seriesService = seriesService;
|
||||||
_mediaFileTableCleanupService = mediaFileTableCleanupService;
|
_mediaFileTableCleanupService = mediaFileTableCleanupService;
|
||||||
_eventAggregator = eventAggregator;
|
_eventAggregator = eventAggregator;
|
||||||
|
_movieService = movieService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,6 +127,64 @@ public void Scan(Series series)
|
|||||||
_eventAggregator.PublishEvent(new SeriesScannedEvent(series));
|
_eventAggregator.PublishEvent(new SeriesScannedEvent(series));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Scan(Movie movie)
|
||||||
|
{
|
||||||
|
var rootFolder = _diskProvider.GetParentFolder(movie.Path);
|
||||||
|
|
||||||
|
if (!_diskProvider.FolderExists(rootFolder))
|
||||||
|
{
|
||||||
|
_logger.Warn("Series' root folder ({0}) doesn't exist.", rootFolder);
|
||||||
|
_eventAggregator.PublishEvent(new MovieScanSkippedEvent(movie, MovieScanSkippedReason.RootFolderDoesNotExist));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_diskProvider.GetDirectories(rootFolder).Empty())
|
||||||
|
{
|
||||||
|
_logger.Warn("Series' root folder ({0}) is empty.", rootFolder);
|
||||||
|
_eventAggregator.PublishEvent(new MovieScanSkippedEvent(movie, MovieScanSkippedReason.RootFolderIsEmpty));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.ProgressInfo("Scanning disk for {0}", movie.Title);
|
||||||
|
|
||||||
|
if (!_diskProvider.FolderExists(movie.Path))
|
||||||
|
{
|
||||||
|
if (_configService.CreateEmptySeriesFolders &&
|
||||||
|
_diskProvider.FolderExists(rootFolder))
|
||||||
|
{
|
||||||
|
_logger.Debug("Creating missing series folder: {0}", movie.Path);
|
||||||
|
_diskProvider.CreateFolder(movie.Path);
|
||||||
|
SetPermissions(movie.Path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Debug("Series folder doesn't exist: {0}", movie.Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
_eventAggregator.PublishEvent(new MovieScanSkippedEvent(movie, MovieScanSkippedReason.MovieFolderDoesNotExist));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var videoFilesStopwatch = Stopwatch.StartNew();
|
||||||
|
var mediaFileList = FilterFiles(movie, GetVideoFiles(movie.Path)).ToList();
|
||||||
|
|
||||||
|
videoFilesStopwatch.Stop();
|
||||||
|
_logger.Trace("Finished getting episode files for: {0} [{1}]", movie, videoFilesStopwatch.Elapsed);
|
||||||
|
|
||||||
|
_logger.Debug("{0} Cleaning up media files in DB", movie);
|
||||||
|
_mediaFileTableCleanupService.Clean(movie, mediaFileList);
|
||||||
|
|
||||||
|
var decisionsStopwatch = Stopwatch.StartNew();
|
||||||
|
var decisions = _importDecisionMaker.GetImportDecisions(mediaFileList, movie);
|
||||||
|
decisionsStopwatch.Stop();
|
||||||
|
_logger.Trace("Import decisions complete for: {0} [{1}]", movie, decisionsStopwatch.Elapsed);
|
||||||
|
|
||||||
|
_importApprovedEpisodes.Import(decisions, false);
|
||||||
|
|
||||||
|
_logger.Info("Completed scanning disk for {0}", movie.Title);
|
||||||
|
_eventAggregator.PublishEvent(new MovieScannedEvent(movie));
|
||||||
|
}
|
||||||
|
|
||||||
public string[] GetVideoFiles(string path, bool allDirectories = true)
|
public string[] GetVideoFiles(string path, bool allDirectories = true)
|
||||||
{
|
{
|
||||||
_logger.Debug("Scanning '{0}' for video files", path);
|
_logger.Debug("Scanning '{0}' for video files", path);
|
||||||
@ -156,6 +220,13 @@ public List<string> FilterFiles(Series series, IEnumerable<string> files)
|
|||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<string> FilterFiles(Movie movie, IEnumerable<string> files)
|
||||||
|
{
|
||||||
|
return files.Where(file => !ExcludedSubFoldersRegex.IsMatch(movie.Path.GetRelativePath(file)))
|
||||||
|
.Where(file => !ExcludedFilesRegex.IsMatch(Path.GetFileName(file)))
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
private void SetPermissions(string path)
|
private void SetPermissions(string path)
|
||||||
{
|
{
|
||||||
if (!_configService.SetPermissionsLinux)
|
if (!_configService.SetPermissionsLinux)
|
||||||
@ -182,6 +253,28 @@ public void Handle(SeriesUpdatedEvent message)
|
|||||||
Scan(message.Series);
|
Scan(message.Series);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Handle(MovieUpdatedEvent message)
|
||||||
|
{
|
||||||
|
Scan(message.Movie);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(RescanMovieCommand message)
|
||||||
|
{
|
||||||
|
if (message.MovieId.HasValue)
|
||||||
|
{
|
||||||
|
var series = _movieService.GetMovie(message.MovieId.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var allMovies = _movieService.GetAllMovies();
|
||||||
|
|
||||||
|
foreach (var movie in allMovies)
|
||||||
|
{
|
||||||
|
Scan(movie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Execute(RescanSeriesCommand message)
|
public void Execute(RescanSeriesCommand message)
|
||||||
{
|
{
|
||||||
if (message.SeriesId.HasValue)
|
if (message.SeriesId.HasValue)
|
||||||
|
@ -18,6 +18,8 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||||||
public interface IMakeImportDecision
|
public interface IMakeImportDecision
|
||||||
{
|
{
|
||||||
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Series series);
|
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Series series);
|
||||||
|
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie);
|
||||||
|
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, ParsedEpisodeInfo folderInfo, bool sceneSource); //TODO: Needs changing to ParsedMovieInfo!!
|
||||||
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Series series, ParsedEpisodeInfo folderInfo, bool sceneSource);
|
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Series series, ParsedEpisodeInfo folderInfo, bool sceneSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +55,11 @@ public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Series s
|
|||||||
return GetImportDecisions(videoFiles, series, null, false);
|
return GetImportDecisions(videoFiles, series, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie)
|
||||||
|
{
|
||||||
|
return GetImportDecisions(videoFiles, movie, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Series series, ParsedEpisodeInfo folderInfo, bool sceneSource)
|
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Series series, ParsedEpisodeInfo folderInfo, bool sceneSource)
|
||||||
{
|
{
|
||||||
var newFiles = _mediaFileService.FilterExistingFiles(videoFiles.ToList(), series);
|
var newFiles = _mediaFileService.FilterExistingFiles(videoFiles.ToList(), series);
|
||||||
@ -70,6 +77,75 @@ public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Series s
|
|||||||
return decisions;
|
return decisions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, ParsedEpisodeInfo folderInfo, bool sceneSource)
|
||||||
|
{
|
||||||
|
var newFiles = _mediaFileService.FilterExistingFiles(videoFiles.ToList(), movie);
|
||||||
|
|
||||||
|
_logger.Debug("Analyzing {0}/{1} files.", newFiles.Count, videoFiles.Count());
|
||||||
|
|
||||||
|
var shouldUseFolderName = ShouldUseFolderName(videoFiles, movie, folderInfo);
|
||||||
|
var decisions = new List<ImportDecision>();
|
||||||
|
|
||||||
|
foreach (var file in newFiles)
|
||||||
|
{
|
||||||
|
decisions.AddIfNotNull(GetDecision(file, movie, folderInfo, sceneSource, shouldUseFolderName));
|
||||||
|
}
|
||||||
|
|
||||||
|
return decisions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImportDecision GetDecision(string file, Movie movie, ParsedEpisodeInfo folderInfo, bool sceneSource, bool shouldUseFolderName)
|
||||||
|
{
|
||||||
|
ImportDecision decision = null;
|
||||||
|
|
||||||
|
/*try
|
||||||
|
{
|
||||||
|
var localEpisode = _parsingService.GetLocalEpisode(file, movie, shouldUseFolderName ? folderInfo : null, sceneSource);
|
||||||
|
|
||||||
|
if (localEpisode != null)
|
||||||
|
{
|
||||||
|
localEpisode.Quality = GetQuality(folderInfo, localEpisode.Quality, movie);
|
||||||
|
localEpisode.Size = _diskProvider.GetFileSize(file);
|
||||||
|
|
||||||
|
_logger.Debug("Size: {0}", localEpisode.Size);
|
||||||
|
|
||||||
|
//TODO: make it so media info doesn't ruin the import process of a new series
|
||||||
|
if (sceneSource)
|
||||||
|
{
|
||||||
|
localEpisode.MediaInfo = _videoFileInfoReader.GetMediaInfo(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localEpisode.Episodes.Empty())
|
||||||
|
{
|
||||||
|
decision = new ImportDecision(localEpisode, new Rejection("Invalid season or episode"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
decision = GetDecision(localEpisode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
localEpisode = new LocalEpisode();
|
||||||
|
localEpisode.Path = file;
|
||||||
|
|
||||||
|
decision = new ImportDecision(localEpisode, new Rejection("Unable to parse file"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error(e, "Couldn't import file. " + file);
|
||||||
|
|
||||||
|
var localEpisode = new LocalEpisode { Path = file };
|
||||||
|
decision = new ImportDecision(localEpisode, new Rejection("Unexpected error processing file"));
|
||||||
|
}*/
|
||||||
|
|
||||||
|
decision = new ImportDecision(null, new Rejection("IMPLEMENTATION MISSING!!!"));
|
||||||
|
|
||||||
|
return decision;
|
||||||
|
}
|
||||||
|
|
||||||
private ImportDecision GetDecision(string file, Series series, ParsedEpisodeInfo folderInfo, bool sceneSource, bool shouldUseFolderName)
|
private ImportDecision GetDecision(string file, Series series, ParsedEpisodeInfo folderInfo, bool sceneSource, bool shouldUseFolderName)
|
||||||
{
|
{
|
||||||
ImportDecision decision = null;
|
ImportDecision decision = null;
|
||||||
@ -182,6 +258,40 @@ private bool ShouldUseFolderName(List<string> videoFiles, Series series, ParsedE
|
|||||||
}) == 1;
|
}) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool ShouldUseFolderName(List<string> videoFiles, Movie movie, ParsedEpisodeInfo folderInfo)
|
||||||
|
{
|
||||||
|
if (folderInfo == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (folderInfo.FullSeason)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return videoFiles.Count(file =>
|
||||||
|
{
|
||||||
|
var size = _diskProvider.GetFileSize(file);
|
||||||
|
var fileQuality = QualityParser.ParseQuality(file);
|
||||||
|
//var sample = null;//_detectSample.IsSample(movie, GetQuality(folderInfo, fileQuality, movie), file, size, folderInfo.IsPossibleSpecialEpisode); //Todo to this
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
//if (sample)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SceneChecker.IsSceneTitle(Path.GetFileName(file)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
private QualityModel GetQuality(ParsedEpisodeInfo folderInfo, QualityModel fileQuality, Series series)
|
private QualityModel GetQuality(ParsedEpisodeInfo folderInfo, QualityModel fileQuality, Series series)
|
||||||
{
|
{
|
||||||
if (UseFolderQuality(folderInfo, fileQuality, series))
|
if (UseFolderQuality(folderInfo, fileQuality, series))
|
||||||
|
24
src/NzbDrone.Core/MediaFiles/Events/MovieScanSkippedEvent.cs
Normal file
24
src/NzbDrone.Core/MediaFiles/Events/MovieScanSkippedEvent.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using NzbDrone.Common.Messaging;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.Events
|
||||||
|
{
|
||||||
|
public class MovieScanSkippedEvent : IEvent
|
||||||
|
{
|
||||||
|
public Movie Movie { get; private set; }
|
||||||
|
public MovieScanSkippedReason Reason { get; set; }
|
||||||
|
|
||||||
|
public MovieScanSkippedEvent(Movie movie, MovieScanSkippedReason reason)
|
||||||
|
{
|
||||||
|
Movie = movie;
|
||||||
|
Reason = reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum MovieScanSkippedReason
|
||||||
|
{
|
||||||
|
RootFolderDoesNotExist,
|
||||||
|
RootFolderIsEmpty,
|
||||||
|
MovieFolderDoesNotExist
|
||||||
|
}
|
||||||
|
}
|
15
src/NzbDrone.Core/MediaFiles/Events/MovieScannedEvent.cs
Normal file
15
src/NzbDrone.Core/MediaFiles/Events/MovieScannedEvent.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using NzbDrone.Common.Messaging;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.Events
|
||||||
|
{
|
||||||
|
public class MovieScannedEvent : IEvent
|
||||||
|
{
|
||||||
|
public Movie Movie { get; private set; }
|
||||||
|
|
||||||
|
public MovieScannedEvent(Movie movie)
|
||||||
|
{
|
||||||
|
Movie = movie;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,9 +16,11 @@ public interface IMediaFileService
|
|||||||
void Update(EpisodeFile episodeFile);
|
void Update(EpisodeFile episodeFile);
|
||||||
void Delete(EpisodeFile episodeFile, DeleteMediaFileReason reason);
|
void Delete(EpisodeFile episodeFile, DeleteMediaFileReason reason);
|
||||||
List<EpisodeFile> GetFilesBySeries(int seriesId);
|
List<EpisodeFile> GetFilesBySeries(int seriesId);
|
||||||
|
List<EpisodeFile> GetFilesByMovie(int movieId);
|
||||||
List<EpisodeFile> GetFilesBySeason(int seriesId, int seasonNumber);
|
List<EpisodeFile> GetFilesBySeason(int seriesId, int seasonNumber);
|
||||||
List<EpisodeFile> GetFilesWithoutMediaInfo();
|
List<EpisodeFile> GetFilesWithoutMediaInfo();
|
||||||
List<string> FilterExistingFiles(List<string> files, Series series);
|
List<string> FilterExistingFiles(List<string> files, Series series);
|
||||||
|
List<string> FilterExistingFiles(List<string> files, Movie movie);
|
||||||
EpisodeFile Get(int id);
|
EpisodeFile Get(int id);
|
||||||
List<EpisodeFile> Get(IEnumerable<int> ids);
|
List<EpisodeFile> Get(IEnumerable<int> ids);
|
||||||
|
|
||||||
@ -64,6 +66,11 @@ public List<EpisodeFile> GetFilesBySeries(int seriesId)
|
|||||||
return _mediaFileRepository.GetFilesBySeries(seriesId);
|
return _mediaFileRepository.GetFilesBySeries(seriesId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<EpisodeFile> GetFilesByMovie(int movieId)
|
||||||
|
{
|
||||||
|
return _mediaFileRepository.GetFilesBySeries(movieId); //TODO: Update implementation for movie files.
|
||||||
|
}
|
||||||
|
|
||||||
public List<EpisodeFile> GetFilesBySeason(int seriesId, int seasonNumber)
|
public List<EpisodeFile> GetFilesBySeason(int seriesId, int seasonNumber)
|
||||||
{
|
{
|
||||||
return _mediaFileRepository.GetFilesBySeason(seriesId, seasonNumber);
|
return _mediaFileRepository.GetFilesBySeason(seriesId, seasonNumber);
|
||||||
@ -83,6 +90,15 @@ public List<string> FilterExistingFiles(List<string> files, Series series)
|
|||||||
return files.Except(seriesFiles, PathEqualityComparer.Instance).ToList();
|
return files.Except(seriesFiles, PathEqualityComparer.Instance).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<string> FilterExistingFiles(List<string> files, Movie movie)
|
||||||
|
{
|
||||||
|
var seriesFiles = GetFilesBySeries(movie.Id).Select(f => Path.Combine(movie.Path, f.RelativePath)).ToList();
|
||||||
|
|
||||||
|
if (!seriesFiles.Any()) return files;
|
||||||
|
|
||||||
|
return files.Except(seriesFiles, PathEqualityComparer.Instance).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
public EpisodeFile Get(int id)
|
public EpisodeFile Get(int id)
|
||||||
{
|
{
|
||||||
return _mediaFileRepository.Get(id);
|
return _mediaFileRepository.Get(id);
|
||||||
|
@ -11,6 +11,8 @@ namespace NzbDrone.Core.MediaFiles
|
|||||||
public interface IMediaFileTableCleanupService
|
public interface IMediaFileTableCleanupService
|
||||||
{
|
{
|
||||||
void Clean(Series series, List<string> filesOnDisk);
|
void Clean(Series series, List<string> filesOnDisk);
|
||||||
|
|
||||||
|
void Clean(Movie movie, List<string> filesOnDisk);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MediaFileTableCleanupService : IMediaFileTableCleanupService
|
public class MediaFileTableCleanupService : IMediaFileTableCleanupService
|
||||||
@ -84,5 +86,64 @@ public void Clean(Series series, List<string> filesOnDisk)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Clean(Movie movie, List<string> filesOnDisk)
|
||||||
|
{
|
||||||
|
|
||||||
|
//TODO: Update implementation for movies.
|
||||||
|
var seriesFiles = _mediaFileService.GetFilesBySeries(movie.Id);
|
||||||
|
var episodes = _episodeService.GetEpisodeBySeries(movie.Id);
|
||||||
|
|
||||||
|
var filesOnDiskKeys = new HashSet<string>(filesOnDisk, PathEqualityComparer.Instance);
|
||||||
|
|
||||||
|
foreach (var seriesFile in seriesFiles)
|
||||||
|
{
|
||||||
|
var episodeFile = seriesFile;
|
||||||
|
var episodeFilePath = Path.Combine(movie.Path, episodeFile.RelativePath);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!filesOnDiskKeys.Contains(episodeFilePath))
|
||||||
|
{
|
||||||
|
_logger.Debug("File [{0}] no longer exists on disk, removing from db", episodeFilePath);
|
||||||
|
_mediaFileService.Delete(seriesFile, DeleteMediaFileReason.MissingFromDisk);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (episodes.None(e => e.EpisodeFileId == episodeFile.Id))
|
||||||
|
{
|
||||||
|
_logger.Debug("File [{0}] is not assigned to any episodes, removing from db", episodeFilePath);
|
||||||
|
_mediaFileService.Delete(episodeFile, DeleteMediaFileReason.NoLinkedEpisodes);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// var localEpsiode = _parsingService.GetLocalEpisode(episodeFile.Path, series);
|
||||||
|
//
|
||||||
|
// if (localEpsiode == null || episodes.Count != localEpsiode.Episodes.Count)
|
||||||
|
// {
|
||||||
|
// _logger.Debug("File [{0}] parsed episodes has changed, removing from db", episodeFile.Path);
|
||||||
|
// _mediaFileService.Delete(episodeFile);
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var errorMessage = string.Format("Unable to cleanup EpisodeFile in DB: {0}", episodeFile.Id);
|
||||||
|
_logger.Error(ex, errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var e in episodes)
|
||||||
|
{
|
||||||
|
var episode = e;
|
||||||
|
|
||||||
|
if (episode.EpisodeFileId > 0 && seriesFiles.None(f => f.Id == episode.EpisodeFileId))
|
||||||
|
{
|
||||||
|
episode.EpisodeFileId = 0;
|
||||||
|
_episodeService.UpdateEpisode(episode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -562,6 +562,7 @@
|
|||||||
<Compile Include="Http\CloudFlare\CloudFlareHttpInterceptor.cs" />
|
<Compile Include="Http\CloudFlare\CloudFlareHttpInterceptor.cs" />
|
||||||
<Compile Include="Http\HttpProxySettingsProvider.cs" />
|
<Compile Include="Http\HttpProxySettingsProvider.cs" />
|
||||||
<Compile Include="Http\TorcacheHttpInterceptor.cs" />
|
<Compile Include="Http\TorcacheHttpInterceptor.cs" />
|
||||||
|
<Compile Include="IndexerSearch\Definitions\MovieSearchCriteria.cs" />
|
||||||
<Compile Include="Indexers\BitMeTv\BitMeTv.cs" />
|
<Compile Include="Indexers\BitMeTv\BitMeTv.cs" />
|
||||||
<Compile Include="Indexers\BitMeTv\BitMeTvSettings.cs" />
|
<Compile Include="Indexers\BitMeTv\BitMeTvSettings.cs" />
|
||||||
<Compile Include="Indexers\BitMeTv\BitMeTvRequestGenerator.cs" />
|
<Compile Include="Indexers\BitMeTv\BitMeTvRequestGenerator.cs" />
|
||||||
@ -695,6 +696,7 @@
|
|||||||
<Compile Include="MediaFiles\Commands\BackendCommandAttribute.cs" />
|
<Compile Include="MediaFiles\Commands\BackendCommandAttribute.cs" />
|
||||||
<Compile Include="MediaFiles\Commands\CleanUpRecycleBinCommand.cs" />
|
<Compile Include="MediaFiles\Commands\CleanUpRecycleBinCommand.cs" />
|
||||||
<Compile Include="MediaFiles\Commands\DownloadedEpisodesScanCommand.cs" />
|
<Compile Include="MediaFiles\Commands\DownloadedEpisodesScanCommand.cs" />
|
||||||
|
<Compile Include="MediaFiles\Commands\RescanMovieCommand.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeImport\ImportMode.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\ImportMode.cs" />
|
||||||
<Compile Include="MediaFiles\Commands\RenameFilesCommand.cs" />
|
<Compile Include="MediaFiles\Commands\RenameFilesCommand.cs" />
|
||||||
<Compile Include="MediaFiles\Commands\RenameSeriesCommand.cs" />
|
<Compile Include="MediaFiles\Commands\RenameSeriesCommand.cs" />
|
||||||
@ -737,6 +739,8 @@
|
|||||||
<Compile Include="MediaFiles\Events\EpisodeImportedEvent.cs" />
|
<Compile Include="MediaFiles\Events\EpisodeImportedEvent.cs" />
|
||||||
<Compile Include="MediaFiles\Events\MovieRenamedEvent.cs" />
|
<Compile Include="MediaFiles\Events\MovieRenamedEvent.cs" />
|
||||||
<Compile Include="MediaFiles\Events\SeriesRenamedEvent.cs" />
|
<Compile Include="MediaFiles\Events\SeriesRenamedEvent.cs" />
|
||||||
|
<Compile Include="MediaFiles\Events\MovieScannedEvent.cs" />
|
||||||
|
<Compile Include="MediaFiles\Events\MovieScanSkippedEvent.cs" />
|
||||||
<Compile Include="MediaFiles\Events\SeriesScanSkippedEvent.cs" />
|
<Compile Include="MediaFiles\Events\SeriesScanSkippedEvent.cs" />
|
||||||
<Compile Include="MediaFiles\Events\SeriesScannedEvent.cs" />
|
<Compile Include="MediaFiles\Events\SeriesScannedEvent.cs" />
|
||||||
<Compile Include="MediaFiles\FileDateType.cs" />
|
<Compile Include="MediaFiles\FileDateType.cs" />
|
||||||
@ -868,6 +872,7 @@
|
|||||||
<Compile Include="Parser\IsoLanguage.cs" />
|
<Compile Include="Parser\IsoLanguage.cs" />
|
||||||
<Compile Include="Parser\IsoLanguages.cs" />
|
<Compile Include="Parser\IsoLanguages.cs" />
|
||||||
<Compile Include="Parser\LanguageParser.cs" />
|
<Compile Include="Parser\LanguageParser.cs" />
|
||||||
|
<Compile Include="Parser\Model\RemoteMovie.cs" />
|
||||||
<Compile Include="Profiles\Delay\DelayProfile.cs" />
|
<Compile Include="Profiles\Delay\DelayProfile.cs" />
|
||||||
<Compile Include="Profiles\Delay\DelayProfileService.cs" />
|
<Compile Include="Profiles\Delay\DelayProfileService.cs" />
|
||||||
<Compile Include="Profiles\Delay\DelayProfileTagInUseValidator.cs" />
|
<Compile Include="Profiles\Delay\DelayProfileTagInUseValidator.cs" />
|
||||||
@ -1053,6 +1058,7 @@
|
|||||||
<Compile Include="Tv\Actor.cs" />
|
<Compile Include="Tv\Actor.cs" />
|
||||||
<Compile Include="Tv\AddSeriesOptions.cs" />
|
<Compile Include="Tv\AddSeriesOptions.cs" />
|
||||||
<Compile Include="Tv\Commands\MoveSeriesCommand.cs" />
|
<Compile Include="Tv\Commands\MoveSeriesCommand.cs" />
|
||||||
|
<Compile Include="Tv\Commands\RefreshMovieCommand.cs" />
|
||||||
<Compile Include="Tv\Commands\RefreshSeriesCommand.cs" />
|
<Compile Include="Tv\Commands\RefreshSeriesCommand.cs" />
|
||||||
<Compile Include="Tv\Episode.cs" />
|
<Compile Include="Tv\Episode.cs" />
|
||||||
<Compile Include="Tv\EpisodeAddedService.cs" />
|
<Compile Include="Tv\EpisodeAddedService.cs" />
|
||||||
@ -1070,6 +1076,7 @@
|
|||||||
<Compile Include="Tv\Events\MovieEditedEvent.cs" />
|
<Compile Include="Tv\Events\MovieEditedEvent.cs" />
|
||||||
<Compile Include="Tv\Events\SeriesEditedEvent.cs" />
|
<Compile Include="Tv\Events\SeriesEditedEvent.cs" />
|
||||||
<Compile Include="Tv\Events\SeriesMovedEvent.cs" />
|
<Compile Include="Tv\Events\SeriesMovedEvent.cs" />
|
||||||
|
<Compile Include="Tv\Events\MovieRefreshStartingEvent.cs" />
|
||||||
<Compile Include="Tv\Events\SeriesRefreshStartingEvent.cs" />
|
<Compile Include="Tv\Events\SeriesRefreshStartingEvent.cs" />
|
||||||
<Compile Include="Tv\Events\MovieUpdateEvent.cs" />
|
<Compile Include="Tv\Events\MovieUpdateEvent.cs" />
|
||||||
<Compile Include="Tv\Events\SeriesUpdatedEvent.cs" />
|
<Compile Include="Tv\Events\SeriesUpdatedEvent.cs" />
|
||||||
@ -1077,12 +1084,15 @@
|
|||||||
<Compile Include="Tv\MoveSeriesService.cs" />
|
<Compile Include="Tv\MoveSeriesService.cs" />
|
||||||
<Compile Include="Tv\Ratings.cs" />
|
<Compile Include="Tv\Ratings.cs" />
|
||||||
<Compile Include="Tv\RefreshEpisodeService.cs" />
|
<Compile Include="Tv\RefreshEpisodeService.cs" />
|
||||||
|
<Compile Include="Tv\RefreshMovieService.cs" />
|
||||||
<Compile Include="Tv\RefreshSeriesService.cs" />
|
<Compile Include="Tv\RefreshSeriesService.cs" />
|
||||||
<Compile Include="Tv\Season.cs" />
|
<Compile Include="Tv\Season.cs" />
|
||||||
<Compile Include="Tv\Movie.cs" />
|
<Compile Include="Tv\Movie.cs" />
|
||||||
<Compile Include="Tv\Series.cs" />
|
<Compile Include="Tv\Series.cs" />
|
||||||
|
<Compile Include="Tv\MovieAddedHandler.cs" />
|
||||||
<Compile Include="Tv\SeriesAddedHandler.cs" />
|
<Compile Include="Tv\SeriesAddedHandler.cs" />
|
||||||
<Compile Include="Tv\MovieRepository.cs" />
|
<Compile Include="Tv\MovieRepository.cs" />
|
||||||
|
<Compile Include="Tv\MovieEditedService.cs" />
|
||||||
<Compile Include="Tv\SeriesScannedHandler.cs" />
|
<Compile Include="Tv\SeriesScannedHandler.cs" />
|
||||||
<Compile Include="Tv\SeriesEditedService.cs" />
|
<Compile Include="Tv\SeriesEditedService.cs" />
|
||||||
<Compile Include="Tv\SeriesRepository.cs" />
|
<Compile Include="Tv\SeriesRepository.cs" />
|
||||||
@ -1095,6 +1105,7 @@
|
|||||||
<Compile Include="Tv\MovieTitleNormalizer.cs" />
|
<Compile Include="Tv\MovieTitleNormalizer.cs" />
|
||||||
<Compile Include="Tv\SeriesTitleNormalizer.cs" />
|
<Compile Include="Tv\SeriesTitleNormalizer.cs" />
|
||||||
<Compile Include="Tv\SeriesTypes.cs" />
|
<Compile Include="Tv\SeriesTypes.cs" />
|
||||||
|
<Compile Include="Tv\ShouldRefreshMovie.cs" />
|
||||||
<Compile Include="Tv\ShouldRefreshSeries.cs" />
|
<Compile Include="Tv\ShouldRefreshSeries.cs" />
|
||||||
<Compile Include="Update\Commands\ApplicationUpdateCommand.cs" />
|
<Compile Include="Update\Commands\ApplicationUpdateCommand.cs" />
|
||||||
<Compile Include="Update\InstallUpdateService.cs" />
|
<Compile Include="Update\InstallUpdateService.cs" />
|
||||||
|
20
src/NzbDrone.Core/Parser/Model/RemoteMovie.cs
Normal file
20
src/NzbDrone.Core/Parser/Model/RemoteMovie.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Parser.Model
|
||||||
|
{
|
||||||
|
public class RemoteMovie
|
||||||
|
{
|
||||||
|
public ReleaseInfo Release { get; set; }
|
||||||
|
public ParsedEpisodeInfo ParsedEpisodeInfo { get; set; } //TODO: Change to ParsedMovieInfo, for now though ParsedEpisodeInfo will do.
|
||||||
|
public Movie Movie { get; set; }
|
||||||
|
public bool DownloadAllowed { get; set; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Release.Title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@ public interface IParsingService
|
|||||||
Series GetSeries(string title);
|
Series GetSeries(string title);
|
||||||
RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null);
|
RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null);
|
||||||
RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int seriesId, IEnumerable<int> episodeIds);
|
RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int seriesId, IEnumerable<int> episodeIds);
|
||||||
|
RemoteMovie Map(ParsedEpisodeInfo parsedEpisodeInfo, string imdbId, SearchCriteriaBase searchCriteria = null);
|
||||||
List<Episode> GetEpisodes(ParsedEpisodeInfo parsedEpisodeInfo, Series series, bool sceneSource, SearchCriteriaBase searchCriteria = null);
|
List<Episode> GetEpisodes(ParsedEpisodeInfo parsedEpisodeInfo, Series series, bool sceneSource, SearchCriteriaBase searchCriteria = null);
|
||||||
ParsedEpisodeInfo ParseSpecialEpisodeTitle(string title, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null);
|
ParsedEpisodeInfo ParseSpecialEpisodeTitle(string title, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null);
|
||||||
}
|
}
|
||||||
@ -27,16 +28,19 @@ public class ParsingService : IParsingService
|
|||||||
private readonly IEpisodeService _episodeService;
|
private readonly IEpisodeService _episodeService;
|
||||||
private readonly ISeriesService _seriesService;
|
private readonly ISeriesService _seriesService;
|
||||||
private readonly ISceneMappingService _sceneMappingService;
|
private readonly ISceneMappingService _sceneMappingService;
|
||||||
|
private readonly IMovieService _movieService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public ParsingService(IEpisodeService episodeService,
|
public ParsingService(IEpisodeService episodeService,
|
||||||
ISeriesService seriesService,
|
ISeriesService seriesService,
|
||||||
ISceneMappingService sceneMappingService,
|
ISceneMappingService sceneMappingService,
|
||||||
|
IMovieService movieService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
{
|
{
|
||||||
_episodeService = episodeService;
|
_episodeService = episodeService;
|
||||||
_seriesService = seriesService;
|
_seriesService = seriesService;
|
||||||
_sceneMappingService = sceneMappingService;
|
_sceneMappingService = sceneMappingService;
|
||||||
|
_movieService = movieService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,6 +138,25 @@ public RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tv
|
|||||||
return remoteEpisode;
|
return remoteEpisode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RemoteMovie Map(ParsedEpisodeInfo parsedEpisodeInfo, string imdbId, SearchCriteriaBase searchCriteria = null)
|
||||||
|
{
|
||||||
|
var remoteEpisode = new RemoteMovie
|
||||||
|
{
|
||||||
|
ParsedEpisodeInfo = parsedEpisodeInfo,
|
||||||
|
};
|
||||||
|
|
||||||
|
var movie = GetMovie(parsedEpisodeInfo, imdbId, searchCriteria);
|
||||||
|
|
||||||
|
if (movie == null)
|
||||||
|
{
|
||||||
|
return remoteEpisode;
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteEpisode.Movie = movie;
|
||||||
|
|
||||||
|
return remoteEpisode;
|
||||||
|
}
|
||||||
|
|
||||||
public RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int seriesId, IEnumerable<int> episodeIds)
|
public RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int seriesId, IEnumerable<int> episodeIds)
|
||||||
{
|
{
|
||||||
return new RemoteEpisode
|
return new RemoteEpisode
|
||||||
@ -248,6 +271,39 @@ private ParsedEpisodeInfo ParseSpecialEpisodeTitle(string title, Series series)
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Movie GetMovie(ParsedEpisodeInfo parsedEpisodeInfo, string imdbId, SearchCriteriaBase searchCriteria)
|
||||||
|
{
|
||||||
|
if (searchCriteria != null)
|
||||||
|
{
|
||||||
|
if (searchCriteria.Movie.CleanTitle == parsedEpisodeInfo.SeriesTitle.CleanSeriesTitle())
|
||||||
|
{
|
||||||
|
return searchCriteria.Movie;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imdbId.IsNotNullOrWhiteSpace() && imdbId == searchCriteria.Movie.ImdbId)
|
||||||
|
{
|
||||||
|
//TODO: If series is found by TvdbId, we should report it as a scene naming exception, since it will fail to import
|
||||||
|
return searchCriteria.Movie;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Movie movie = _movieService.FindByTitle(parsedEpisodeInfo.SeriesTitle);
|
||||||
|
|
||||||
|
if (movie == null && imdbId.IsNotNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
//TODO: If series is found by TvdbId, we should report it as a scene naming exception, since it will fail to import
|
||||||
|
movie = _movieService.FindByImdbId(imdbId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (movie == null)
|
||||||
|
{
|
||||||
|
_logger.Debug("No matching movie {0}", parsedEpisodeInfo.SeriesTitle);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return movie;
|
||||||
|
}
|
||||||
|
|
||||||
private Series GetSeries(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria)
|
private Series GetSeries(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria)
|
||||||
{
|
{
|
||||||
Series series = null;
|
Series series = null;
|
||||||
|
22
src/NzbDrone.Core/Tv/Commands/RefreshMovieCommand.cs
Normal file
22
src/NzbDrone.Core/Tv/Commands/RefreshMovieCommand.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Tv.Commands
|
||||||
|
{
|
||||||
|
public class RefreshMovieCommand : Command
|
||||||
|
{
|
||||||
|
public int? MovieId { get; set; }
|
||||||
|
|
||||||
|
public RefreshMovieCommand()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public RefreshMovieCommand(int? movieId)
|
||||||
|
{
|
||||||
|
MovieId = movieId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool SendUpdatesToClient => true;
|
||||||
|
|
||||||
|
public override bool UpdateScheduledTask => !MovieId.HasValue;
|
||||||
|
}
|
||||||
|
}
|
14
src/NzbDrone.Core/Tv/Events/MovieRefreshStartingEvent.cs
Normal file
14
src/NzbDrone.Core/Tv/Events/MovieRefreshStartingEvent.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using NzbDrone.Common.Messaging;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Tv.Events
|
||||||
|
{
|
||||||
|
public class MovieRefreshStartingEvent : IEvent
|
||||||
|
{
|
||||||
|
public bool ManualTrigger { get; set; }
|
||||||
|
|
||||||
|
public MovieRefreshStartingEvent(bool manualTrigger)
|
||||||
|
{
|
||||||
|
ManualTrigger = manualTrigger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
src/NzbDrone.Core/Tv/MovieAddedHandler.cs
Normal file
22
src/NzbDrone.Core/Tv/MovieAddedHandler.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.Tv.Commands;
|
||||||
|
using NzbDrone.Core.Tv.Events;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Tv
|
||||||
|
{
|
||||||
|
public class MovieAddedHandler : IHandle<MovieAddedEvent>
|
||||||
|
{
|
||||||
|
private readonly IManageCommandQueue _commandQueueManager;
|
||||||
|
|
||||||
|
public MovieAddedHandler(IManageCommandQueue commandQueueManager)
|
||||||
|
{
|
||||||
|
_commandQueueManager = commandQueueManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(MovieAddedEvent message)
|
||||||
|
{
|
||||||
|
_commandQueueManager.Push(new RefreshMovieCommand(message.Movie.Id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
src/NzbDrone.Core/Tv/MovieEditedService.cs
Normal file
25
src/NzbDrone.Core/Tv/MovieEditedService.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.Tv.Commands;
|
||||||
|
using NzbDrone.Core.Tv.Events;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Tv
|
||||||
|
{
|
||||||
|
public class MovieEditedService : IHandle<MovieEditedEvent>
|
||||||
|
{
|
||||||
|
private readonly IManageCommandQueue _commandQueueManager;
|
||||||
|
|
||||||
|
public MovieEditedService(IManageCommandQueue commandQueueManager)
|
||||||
|
{
|
||||||
|
_commandQueueManager = commandQueueManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(MovieEditedEvent message)
|
||||||
|
{
|
||||||
|
if (message.Movie.ImdbId != message.OldMovie.ImdbId)
|
||||||
|
{
|
||||||
|
_commandQueueManager.Push(new RefreshMovieCommand(message.Movie.Id)); //Probably not needed, as metadata should stay the same.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
144
src/NzbDrone.Core/Tv/RefreshMovieService.cs
Normal file
144
src/NzbDrone.Core/Tv/RefreshMovieService.cs
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Common.Instrumentation.Extensions;
|
||||||
|
//using NzbDrone.Core.DataAugmentation.DailyMovie;
|
||||||
|
using NzbDrone.Core.Exceptions;
|
||||||
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.MetadataSource;
|
||||||
|
using NzbDrone.Core.Tv.Commands;
|
||||||
|
using NzbDrone.Core.Tv.Events;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Tv
|
||||||
|
{
|
||||||
|
public class RefreshMovieService : IExecute<RefreshMovieCommand>
|
||||||
|
{
|
||||||
|
private readonly IProvideMovieInfo _movieInfo;
|
||||||
|
private readonly IMovieService _movieService;
|
||||||
|
private readonly IRefreshEpisodeService _refreshEpisodeService;
|
||||||
|
private readonly IEventAggregator _eventAggregator;
|
||||||
|
private readonly IDiskScanService _diskScanService;
|
||||||
|
private readonly ICheckIfMovieShouldBeRefreshed _checkIfMovieShouldBeRefreshed;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public RefreshMovieService(IProvideMovieInfo movieInfo,
|
||||||
|
IMovieService movieService,
|
||||||
|
IRefreshEpisodeService refreshEpisodeService,
|
||||||
|
IEventAggregator eventAggregator,
|
||||||
|
IDiskScanService diskScanService,
|
||||||
|
ICheckIfMovieShouldBeRefreshed checkIfMovieShouldBeRefreshed,
|
||||||
|
Logger logger)
|
||||||
|
{
|
||||||
|
_movieInfo = movieInfo;
|
||||||
|
_movieService = movieService;
|
||||||
|
_refreshEpisodeService = refreshEpisodeService;
|
||||||
|
_eventAggregator = eventAggregator;
|
||||||
|
_diskScanService = diskScanService;
|
||||||
|
_checkIfMovieShouldBeRefreshed = checkIfMovieShouldBeRefreshed;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshMovieInfo(Movie movie)
|
||||||
|
{
|
||||||
|
_logger.ProgressInfo("Updating Info for {0}", movie.Title);
|
||||||
|
|
||||||
|
Movie movieInfo;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
movieInfo = _movieInfo.GetMovieInfo(movie.ImdbId);
|
||||||
|
}
|
||||||
|
catch (MovieNotFoundException)
|
||||||
|
{
|
||||||
|
_logger.Error("Movie '{0}' (imdbid {1}) was not found, it may have been removed from TheTVDB.", movie.Title, movie.ImdbId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (movie.ImdbId != movieInfo.ImdbId)
|
||||||
|
{
|
||||||
|
_logger.Warn("Movie '{0}' (tvdbid {1}) was replaced with '{2}' (tvdbid {3}), because the original was a duplicate.", movie.Title, movie.ImdbId, movieInfo.Title, movieInfo.ImdbId);
|
||||||
|
movie.ImdbId = movieInfo.ImdbId;
|
||||||
|
}
|
||||||
|
|
||||||
|
movie.Title = movieInfo.Title;
|
||||||
|
movie.TitleSlug = movieInfo.TitleSlug;
|
||||||
|
movie.ImdbId = movieInfo.ImdbId;
|
||||||
|
movie.Overview = movieInfo.Overview;
|
||||||
|
movie.Status = movieInfo.Status;
|
||||||
|
movie.CleanTitle = movieInfo.CleanTitle;
|
||||||
|
movie.SortTitle = movieInfo.SortTitle;
|
||||||
|
movie.LastInfoSync = DateTime.UtcNow;
|
||||||
|
movie.Runtime = movieInfo.Runtime;
|
||||||
|
movie.Images = movieInfo.Images;
|
||||||
|
movie.Ratings = movieInfo.Ratings;
|
||||||
|
movie.Actors = movieInfo.Actors;
|
||||||
|
movie.Genres = movieInfo.Genres;
|
||||||
|
movie.Certification = movieInfo.Certification;
|
||||||
|
movie.InCinemas = movieInfo.InCinemas;
|
||||||
|
movie.Year = movieInfo.Year;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
movie.Path = new DirectoryInfo(movie.Path).FullName;
|
||||||
|
movie.Path = movie.Path.GetActualCasing();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Warn(e, "Couldn't update movie path for " + movie.Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
_movieService.UpdateMovie(movie);
|
||||||
|
|
||||||
|
_logger.Debug("Finished movie refresh for {0}", movie.Title);
|
||||||
|
_eventAggregator.PublishEvent(new MovieUpdatedEvent(movie));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(RefreshMovieCommand message)
|
||||||
|
{
|
||||||
|
_eventAggregator.PublishEvent(new MovieRefreshStartingEvent(message.Trigger == CommandTrigger.Manual));
|
||||||
|
|
||||||
|
if (message.MovieId.HasValue)
|
||||||
|
{
|
||||||
|
var movie = _movieService.GetMovie(message.MovieId.Value);
|
||||||
|
RefreshMovieInfo(movie);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var allMovie = _movieService.GetAllMovies().OrderBy(c => c.SortTitle).ToList();
|
||||||
|
|
||||||
|
foreach (var movie in allMovie)
|
||||||
|
{
|
||||||
|
if (message.Trigger == CommandTrigger.Manual || _checkIfMovieShouldBeRefreshed.ShouldRefresh(movie))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RefreshMovieInfo(movie);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error(e, "Couldn't refresh info for {0}".Inject(movie));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Info("Skipping refresh of movie: {0}", movie.Title);
|
||||||
|
_diskScanService.Scan(movie);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error(e, "Couldn't rescan movie {0}".Inject(movie));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
src/NzbDrone.Core/Tv/ShouldRefreshMovie.cs
Normal file
47
src/NzbDrone.Core/Tv/ShouldRefreshMovie.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using NLog;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Tv
|
||||||
|
{
|
||||||
|
public interface ICheckIfMovieShouldBeRefreshed
|
||||||
|
{
|
||||||
|
bool ShouldRefresh(Movie movie);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ShouldRefreshMovie : ICheckIfMovieShouldBeRefreshed
|
||||||
|
{
|
||||||
|
private readonly IEpisodeService _episodeService;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public ShouldRefreshMovie(IEpisodeService episodeService, Logger logger)
|
||||||
|
{
|
||||||
|
_episodeService = episodeService;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShouldRefresh(Movie movie)
|
||||||
|
{
|
||||||
|
if (movie.LastInfoSync < DateTime.UtcNow.AddDays(-30))
|
||||||
|
{
|
||||||
|
_logger.Trace("Movie {0} last updated more than 30 days ago, should refresh.", movie.Title);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (movie.LastInfoSync >= DateTime.UtcNow.AddHours(-6))
|
||||||
|
{
|
||||||
|
_logger.Trace("Movie {0} last updated less than 6 hours ago, should not be refreshed.", movie.Title);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (movie.Status != MovieStatusType.TBA)
|
||||||
|
{
|
||||||
|
_logger.Trace("Movie {0} is announced or released, should refresh.", movie.Title); //We probably have to change this.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Trace("Movie {0} ended long ago, should not be refreshed.", movie.Title);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -127,4 +127,4 @@ module.exports = Marionette.Layout.extend({
|
|||||||
this.ui.monitored.removeClass('icon-sonarr-monitored');
|
this.ui.monitored.removeClass('icon-sonarr-monitored');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -31,6 +31,16 @@ Handlebars.registerHelper('tvdbUrl', function() {
|
|||||||
return 'http://imdb.com/title/tt' + this.imdbId;
|
return 'http://imdb.com/title/tt' + this.imdbId;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Handlebars.registerHelper('inCinemas', function() {
|
||||||
|
var monthNames = ["January", "February", "March", "April", "May", "June",
|
||||||
|
"July", "August", "September", "October", "November", "December"
|
||||||
|
];
|
||||||
|
var cinemasDate = new Date(this.inCinemas);
|
||||||
|
var year = cinemasDate.getFullYear();
|
||||||
|
var month = monthNames[cinemasDate.getMonth()];
|
||||||
|
return "In Cinemas " + month + " " + year;
|
||||||
|
})
|
||||||
|
|
||||||
Handlebars.registerHelper('tvRageUrl', function() {
|
Handlebars.registerHelper('tvRageUrl', function() {
|
||||||
return 'http://www.tvrage.com/shows/id-' + this.tvRageId;
|
return 'http://www.tvrage.com/shows/id-' + this.tvRageId;
|
||||||
});
|
});
|
||||||
|
@ -4,15 +4,15 @@ module.exports = Marionette.ItemView.extend({
|
|||||||
template : 'Movies/Details/InfoViewTemplate',
|
template : 'Movies/Details/InfoViewTemplate',
|
||||||
|
|
||||||
initialize : function(options) {
|
initialize : function(options) {
|
||||||
this.episodeFileCollection = options.episodeFileCollection;
|
//this.episodeFileCollection = options.episodeFileCollection;
|
||||||
|
|
||||||
this.listenTo(this.model, 'change', this.render);
|
this.listenTo(this.model, 'change', this.render);
|
||||||
this.listenTo(this.episodeFileCollection, 'sync', this.render);
|
//this.listenTo(this.episodeFileCollection, 'sync', this.render); TODO: Update this;
|
||||||
},
|
},
|
||||||
|
|
||||||
templateHelpers : function() {
|
templateHelpers : function() {
|
||||||
return {
|
return {
|
||||||
fileCount : this.episodeFileCollection.length
|
fileCount : 0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -21,10 +21,10 @@
|
|||||||
<span class="label label-info"> {{fileCount}} files</span>
|
<span class="label label-info"> {{fileCount}} files</span>
|
||||||
{{/if_eq}}
|
{{/if_eq}}
|
||||||
|
|
||||||
{{#if_eq status compare="continuing"}}
|
{{#if_eq status compare="released"}}
|
||||||
<span class="label label-info">Continuing</span>
|
<span class="label label-info">{{inCinemas}}</span>
|
||||||
{{else}}
|
{{else}}
|
||||||
<span class="label label-default">Ended</span>
|
<span class="label label-default">Announced</span>
|
||||||
{{/if_eq}}
|
{{/if_eq}}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
@ -36,14 +36,6 @@
|
|||||||
{{#if imdbId}}
|
{{#if imdbId}}
|
||||||
<a href="{{imdbUrl}}" class="label label-info">IMDB</a>
|
<a href="{{imdbUrl}}" class="label label-info">IMDB</a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if tvRageId}}
|
|
||||||
<a href="{{tvRageUrl}}" class="label label-info">TV Rage</a>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if tvMazeId}}
|
|
||||||
<a href="{{tvMazeUrl}}" class="label label-info">TV Maze</a>
|
|
||||||
{{/if}}
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,6 +9,8 @@ var InfoView = require('./InfoView');
|
|||||||
var CommandController = require('../../Commands/CommandController');
|
var CommandController = require('../../Commands/CommandController');
|
||||||
var LoadingView = require('../../Shared/LoadingView');
|
var LoadingView = require('../../Shared/LoadingView');
|
||||||
var EpisodeFileEditorLayout = require('../../EpisodeFile/Editor/EpisodeFileEditorLayout');
|
var EpisodeFileEditorLayout = require('../../EpisodeFile/Editor/EpisodeFileEditorLayout');
|
||||||
|
var HistoryLayout = require('../History/MovieHistoryLayout');
|
||||||
|
var SearchLayout = require('../Search/MovieSearchLayout');
|
||||||
require('backstrech');
|
require('backstrech');
|
||||||
require('../../Mixins/backbone.signalr.mixin');
|
require('../../Mixins/backbone.signalr.mixin');
|
||||||
|
|
||||||
@ -18,9 +20,12 @@ module.exports = Marionette.Layout.extend({
|
|||||||
|
|
||||||
regions : {
|
regions : {
|
||||||
seasons : '#seasons',
|
seasons : '#seasons',
|
||||||
info : '#info'
|
info : '#info',
|
||||||
|
search : '#movie-search',
|
||||||
|
history : '#movie-history'
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
ui : {
|
ui : {
|
||||||
header : '.x-header',
|
header : '.x-header',
|
||||||
monitored : '.x-monitored',
|
monitored : '.x-monitored',
|
||||||
@ -29,7 +34,9 @@ module.exports = Marionette.Layout.extend({
|
|||||||
rename : '.x-rename',
|
rename : '.x-rename',
|
||||||
search : '.x-search',
|
search : '.x-search',
|
||||||
poster : '.x-movie-poster',
|
poster : '.x-movie-poster',
|
||||||
manualSearch : '.x-manual-search'
|
manualSearch : '.x-manual-search',
|
||||||
|
history : '.x-movie-history',
|
||||||
|
search : '.x-movie-search'
|
||||||
},
|
},
|
||||||
|
|
||||||
events : {
|
events : {
|
||||||
@ -39,7 +46,9 @@ module.exports = Marionette.Layout.extend({
|
|||||||
'click .x-refresh' : '_refreshMovies',
|
'click .x-refresh' : '_refreshMovies',
|
||||||
'click .x-rename' : '_renameMovies',
|
'click .x-rename' : '_renameMovies',
|
||||||
'click .x-search' : '_moviesSearch',
|
'click .x-search' : '_moviesSearch',
|
||||||
'click .x-manual-search' : '_manualSearchM'
|
'click .x-manual-search' : '_showSearch',
|
||||||
|
'click .x-movie-history' : '_showHistory',
|
||||||
|
'click .x-movie-search' : '_showSearch'
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize : function() {
|
initialize : function() {
|
||||||
@ -60,17 +69,21 @@ module.exports = Marionette.Layout.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onShow : function() {
|
onShow : function() {
|
||||||
|
this.searchLayout = new SearchLayout({ model : this.model });
|
||||||
|
this.searchLayout.startManualSearch = true;
|
||||||
|
|
||||||
this._showBackdrop();
|
this._showBackdrop();
|
||||||
this._showSeasons();
|
this._showSeasons();
|
||||||
this._setMonitoredState();
|
this._setMonitoredState();
|
||||||
this._showInfo();
|
this._showInfo();
|
||||||
|
this._showHistory();
|
||||||
},
|
},
|
||||||
|
|
||||||
onRender : function() {
|
onRender : function() {
|
||||||
CommandController.bindToCommand({
|
CommandController.bindToCommand({
|
||||||
element : this.ui.refresh,
|
element : this.ui.refresh,
|
||||||
command : {
|
command : {
|
||||||
name : 'refreshMovies'
|
name : 'refreshMovie'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
CommandController.bindToCommand({
|
CommandController.bindToCommand({
|
||||||
@ -110,6 +123,26 @@ module.exports = Marionette.Layout.extend({
|
|||||||
return undefined;
|
return undefined;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_showHistory : function(e) {
|
||||||
|
if (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ui.history.tab('show');
|
||||||
|
this.history.show(new HistoryLayout({
|
||||||
|
model : this.model
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_showSearch : function(e) {
|
||||||
|
if (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ui.search.tab('show');
|
||||||
|
this.search.show(this.searchLayout);
|
||||||
|
},
|
||||||
|
|
||||||
_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 });
|
||||||
|
|
||||||
@ -138,8 +171,8 @@ module.exports = Marionette.Layout.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_refreshMovies : function() {
|
_refreshMovies : function() {
|
||||||
CommandController.Execute('refreshMovies', {
|
CommandController.Execute('refreshMovie', {
|
||||||
name : 'refreshMovies',
|
name : 'refreshMovie',
|
||||||
movieId : this.model.id
|
movieId : this.model.id
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -198,8 +231,7 @@ module.exports = Marionette.Layout.extend({
|
|||||||
|
|
||||||
_showInfo : function() {
|
_showInfo : function() {
|
||||||
this.info.show(new InfoView({
|
this.info.show(new InfoView({
|
||||||
model : this.model,
|
model : this.model
|
||||||
episodeFileCollection : this.episodeFileCollection
|
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -212,9 +244,9 @@ module.exports = Marionette.Layout.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_refresh : function() {
|
_refresh : function() {
|
||||||
this.seasonCollection.add(this.model.get('seasons'), { merge : true });
|
//this.seasonCollection.add(this.model.get('seasons'), { merge : true });
|
||||||
this.episodeCollection.fetch();
|
//this.episodeCollection.fetch();
|
||||||
this.episodeFileCollection.fetch();
|
//this.episodeFileCollection.fetch();
|
||||||
|
|
||||||
this._setMonitoredState();
|
this._setMonitoredState();
|
||||||
this._showInfo();
|
this._showInfo();
|
||||||
@ -252,11 +284,11 @@ module.exports = Marionette.Layout.extend({
|
|||||||
|
|
||||||
_manualSearchM : function() {
|
_manualSearchM : function() {
|
||||||
console.warn("Manual Search started");
|
console.warn("Manual Search started");
|
||||||
console.warn(this.model.get("moviesId"));
|
console.warn(this.model.id);
|
||||||
console.warn(this.model)
|
console.warn(this.model)
|
||||||
console.warn(this.episodeCollection);
|
console.warn(this.episodeCollection);
|
||||||
vent.trigger(vent.Commands.ShowEpisodeDetails, {
|
vent.trigger(vent.Commands.ShowEpisodeDetails, {
|
||||||
episode : this.episodeCollection.models[0],
|
episode : this.model,
|
||||||
hideMoviesLink : true,
|
hideMoviesLink : true,
|
||||||
openingTab : 'search'
|
openingTab : 'search'
|
||||||
});
|
});
|
||||||
|
@ -35,4 +35,13 @@
|
|||||||
<div id="info" class="movie-info"></div>
|
<div id="info" class="movie-info"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="seasons"></div>
|
<div id="seasons">
|
||||||
|
<ul class="nav nav-tabs" id="myTab">
|
||||||
|
<li><a href="#movie-history" class="x-movie-history">History</a></li>
|
||||||
|
<li><a href="#movie-search" class="x-movie-search">Search</a></li>
|
||||||
|
</ul>
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="tab-pane" id="movie-history"/>
|
||||||
|
<div class="tab-pane" id="movie-search"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
35
src/UI/Movies/History/MovieHistoryActionsCell.js
Normal file
35
src/UI/Movies/History/MovieHistoryActionsCell.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
var $ = require('jquery');
|
||||||
|
var vent = require('vent');
|
||||||
|
var Marionette = require('marionette');
|
||||||
|
var NzbDroneCell = require('../../Cells/NzbDroneCell');
|
||||||
|
|
||||||
|
module.exports = NzbDroneCell.extend({
|
||||||
|
className : 'episode-actions-cell',
|
||||||
|
|
||||||
|
events : {
|
||||||
|
'click .x-failed' : '_markAsFailed'
|
||||||
|
},
|
||||||
|
|
||||||
|
render : function() {
|
||||||
|
this.$el.empty();
|
||||||
|
|
||||||
|
if (this.model.get('eventType') === 'grabbed') {
|
||||||
|
this.$el.html('<i class="icon-sonarr-delete x-failed" title="Mark download as failed"></i>');
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
_markAsFailed : function() {
|
||||||
|
var url = window.NzbDrone.ApiRoot + '/history/failed';
|
||||||
|
var data = {
|
||||||
|
id : this.model.get('id')
|
||||||
|
};
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url : url,
|
||||||
|
type : 'POST',
|
||||||
|
data : data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
28
src/UI/Movies/History/MovieHistoryDetailsCell.js
Normal file
28
src/UI/Movies/History/MovieHistoryDetailsCell.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
var $ = require('jquery');
|
||||||
|
var vent = require('vent');
|
||||||
|
var Marionette = require('marionette');
|
||||||
|
var NzbDroneCell = require('../../Cells/NzbDroneCell');
|
||||||
|
var HistoryDetailsView = require('../../Activity/History/Details/HistoryDetailsView');
|
||||||
|
require('bootstrap');
|
||||||
|
|
||||||
|
module.exports = NzbDroneCell.extend({
|
||||||
|
className : 'episode-history-details-cell',
|
||||||
|
|
||||||
|
render : function() {
|
||||||
|
this.$el.empty();
|
||||||
|
this.$el.html('<i class="icon-sonarr-form-info"></i>');
|
||||||
|
|
||||||
|
var html = new HistoryDetailsView({ model : this.model }).render().$el;
|
||||||
|
|
||||||
|
this.$el.popover({
|
||||||
|
content : html,
|
||||||
|
html : true,
|
||||||
|
trigger : 'hover',
|
||||||
|
title : 'Details',
|
||||||
|
placement : 'left',
|
||||||
|
container : this.$el
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
});
|
83
src/UI/Movies/History/MovieHistoryLayout.js
Normal file
83
src/UI/Movies/History/MovieHistoryLayout.js
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
var Marionette = require('marionette');
|
||||||
|
var Backgrid = require('backgrid');
|
||||||
|
var HistoryCollection = require('../../Activity/History/HistoryCollection');
|
||||||
|
var EventTypeCell = require('../../Cells/EventTypeCell');
|
||||||
|
var QualityCell = require('../../Cells/QualityCell');
|
||||||
|
var RelativeDateCell = require('../../Cells/RelativeDateCell');
|
||||||
|
var EpisodeHistoryActionsCell = require('./MovieHistoryActionsCell');
|
||||||
|
var EpisodeHistoryDetailsCell = require('./MovieHistoryDetailsCell');
|
||||||
|
var NoHistoryView = require('./NoHistoryView');
|
||||||
|
var LoadingView = require('../../Shared/LoadingView');
|
||||||
|
|
||||||
|
module.exports = Marionette.Layout.extend({
|
||||||
|
template : 'Movies/History/MovieHistoryLayoutTemplate',
|
||||||
|
|
||||||
|
regions : {
|
||||||
|
historyTable : '.history-table'
|
||||||
|
},
|
||||||
|
|
||||||
|
columns : [
|
||||||
|
{
|
||||||
|
name : 'eventType',
|
||||||
|
label : '',
|
||||||
|
cell : EventTypeCell,
|
||||||
|
cellValue : 'this'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'sourceTitle',
|
||||||
|
label : 'Source Title',
|
||||||
|
cell : 'string'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'quality',
|
||||||
|
label : 'Quality',
|
||||||
|
cell : QualityCell
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'date',
|
||||||
|
label : 'Date',
|
||||||
|
cell : RelativeDateCell
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'this',
|
||||||
|
label : '',
|
||||||
|
cell : EpisodeHistoryDetailsCell,
|
||||||
|
sortable : false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'this',
|
||||||
|
label : '',
|
||||||
|
cell : EpisodeHistoryActionsCell,
|
||||||
|
sortable : false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
initialize : function(options) {
|
||||||
|
this.model = options.model;
|
||||||
|
|
||||||
|
this.collection = new HistoryCollection({
|
||||||
|
episodeId : this.model.id,
|
||||||
|
tableName : 'episodeHistory'
|
||||||
|
});
|
||||||
|
this.collection.fetch();
|
||||||
|
this.listenTo(this.collection, 'sync', this._showTable);
|
||||||
|
},
|
||||||
|
|
||||||
|
onRender : function() {
|
||||||
|
this.historyTable.show(new LoadingView());
|
||||||
|
},
|
||||||
|
|
||||||
|
_showTable : function() {
|
||||||
|
if (this.collection.any()) {
|
||||||
|
this.historyTable.show(new Backgrid.Grid({
|
||||||
|
collection : this.collection,
|
||||||
|
columns : this.columns,
|
||||||
|
className : 'table table-hover table-condensed'
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
this.historyTable.show(new NoHistoryView());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
1
src/UI/Movies/History/MovieHistoryLayoutTemplate.hbs
Normal file
1
src/UI/Movies/History/MovieHistoryLayoutTemplate.hbs
Normal file
@ -0,0 +1 @@
|
|||||||
|
<div class="history-table table-responsive"></div>
|
5
src/UI/Movies/History/NoHistoryView.js
Normal file
5
src/UI/Movies/History/NoHistoryView.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
var Marionette = require('marionette');
|
||||||
|
|
||||||
|
module.exports = Marionette.ItemView.extend({
|
||||||
|
template : 'Movies/History/NoHistoryViewTemplate'
|
||||||
|
});
|
3
src/UI/Movies/History/NoHistoryViewTemplate.hbs
Normal file
3
src/UI/Movies/History/NoHistoryViewTemplate.hbs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<p class="text-warning">
|
||||||
|
No history for this episode.
|
||||||
|
</p>
|
@ -16,7 +16,7 @@ module.exports = Marionette.ItemView.extend({
|
|||||||
CommandController.bindToCommand({
|
CommandController.bindToCommand({
|
||||||
element : this.ui.refresh,
|
element : this.ui.refresh,
|
||||||
command : {
|
command : {
|
||||||
name : 'refreshSeries',
|
name : 'refreshMovie',
|
||||||
seriesId : this.model.get('id')
|
seriesId : this.model.get('id')
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -27,9 +27,9 @@ module.exports = Marionette.ItemView.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_refreshSeries : function() {
|
_refreshSeries : function() {
|
||||||
CommandController.Execute('refreshSeries', {
|
CommandController.Execute('refreshMovie', {
|
||||||
name : 'refreshSeries',
|
name : 'refreshMovie',
|
||||||
seriesId : this.model.id
|
movieId : this.model.id
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -103,7 +103,7 @@ module.exports = Marionette.Layout.extend({
|
|||||||
{
|
{
|
||||||
title : 'Update Library',
|
title : 'Update Library',
|
||||||
icon : 'icon-sonarr-refresh',
|
icon : 'icon-sonarr-refresh',
|
||||||
command : 'refreshseries',
|
command : 'refreshmovie',
|
||||||
successMessage : 'Library was updated!',
|
successMessage : 'Library was updated!',
|
||||||
errorMessage : 'Library update failed!'
|
errorMessage : 'Library update failed!'
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
<div class="center">
|
<div class="center">
|
||||||
<div class="series-poster-container x-series-poster-container">
|
<div class="series-poster-container x-series-poster-container">
|
||||||
<div class="series-controls x-series-controls">
|
<div class="series-controls x-series-controls">
|
||||||
<i class="icon-sonarr-refresh x-refresh" title="Refresh Series"/>
|
<i class="icon-sonarr-refresh x-refresh" title="Refresh Movie"/>
|
||||||
<i class="icon-sonarr-edit x-edit" title="Edit Series"/>
|
<i class="icon-sonarr-edit x-edit" title="Edit Movie"/>
|
||||||
</div>
|
</div>
|
||||||
{{#unless_eq status compare="continuing"}}
|
{{#unless_eq status compare="released"}}
|
||||||
<div class="ended-banner">Ended</div>
|
<div class="ended-banner">Released</div>
|
||||||
{{/unless_eq}}
|
{{/unless_eq}}
|
||||||
<a href="{{route}}">
|
<a href="{{route}}">
|
||||||
{{poster}}
|
{{poster}}
|
||||||
|
@ -3,6 +3,7 @@ var AppLayout = require('../AppLayout');
|
|||||||
var MoviesCollection = require('./MoviesCollection');
|
var MoviesCollection = require('./MoviesCollection');
|
||||||
var MoviesIndexLayout = require('./Index/MoviesIndexLayout');
|
var MoviesIndexLayout = require('./Index/MoviesIndexLayout');
|
||||||
var MoviesDetailsLayout = require('./Details/MoviesDetailsLayout');
|
var MoviesDetailsLayout = require('./Details/MoviesDetailsLayout');
|
||||||
|
var SeriesDetailsLayout = require('../Series/Details/SeriesDetailsLayout');
|
||||||
|
|
||||||
module.exports = NzbDroneController.extend({
|
module.exports = NzbDroneController.extend({
|
||||||
_originalInit : NzbDroneController.prototype.initialize,
|
_originalInit : NzbDroneController.prototype.initialize,
|
||||||
@ -22,10 +23,13 @@ module.exports = NzbDroneController.extend({
|
|||||||
|
|
||||||
seriesDetails : function(query) {
|
seriesDetails : function(query) {
|
||||||
var series = MoviesCollection.where({ titleSlug : query });
|
var series = MoviesCollection.where({ titleSlug : query });
|
||||||
|
|
||||||
if (series.length !== 0) {
|
if (series.length !== 0) {
|
||||||
var targetMovie = series[0];
|
var targetMovie = series[0];
|
||||||
|
console.log(AppLayout.mainRegion);
|
||||||
|
|
||||||
this.setTitle(targetMovie.get('title'));
|
this.setTitle(targetMovie.get('title'));
|
||||||
|
//this.showNotFound();
|
||||||
|
//this.showMainRegion(new SeriesDetailsLayout({model : targetMovie}));
|
||||||
this.showMainRegion(new MoviesDetailsLayout({ model : targetMovie }));
|
this.showMainRegion(new MoviesDetailsLayout({ model : targetMovie }));
|
||||||
} else {
|
} else {
|
||||||
this.showNotFound();
|
this.showNotFound();
|
||||||
|
5
src/UI/Movies/Search/ButtonsView.js
Normal file
5
src/UI/Movies/Search/ButtonsView.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
var Marionette = require('marionette');
|
||||||
|
|
||||||
|
module.exports = Marionette.ItemView.extend({
|
||||||
|
template : 'Movies/Search/ButtonsViewTemplate'
|
||||||
|
});
|
4
src/UI/Movies/Search/ButtonsViewTemplate.hbs
Normal file
4
src/UI/Movies/Search/ButtonsViewTemplate.hbs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<div class="search-buttons">
|
||||||
|
<button class="btn btn-lg btn-block x-search-auto"><i class="icon-sonarr-search-automatic"/> Automatic Search</button>
|
||||||
|
<button class="btn btn-lg btn-block btn-primary x-search-manual"><i class="icon-sonarr-search-manual"/> Manual Search</button>
|
||||||
|
</div>
|
86
src/UI/Movies/Search/ManualLayout.js
Normal file
86
src/UI/Movies/Search/ManualLayout.js
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
var Marionette = require('marionette');
|
||||||
|
var Backgrid = require('backgrid');
|
||||||
|
var ReleaseTitleCell = require('../../Cells/ReleaseTitleCell');
|
||||||
|
var FileSizeCell = require('../../Cells/FileSizeCell');
|
||||||
|
var QualityCell = require('../../Cells/QualityCell');
|
||||||
|
var ApprovalStatusCell = require('../../Cells/ApprovalStatusCell');
|
||||||
|
var DownloadReportCell = require('../../Release/DownloadReportCell');
|
||||||
|
var AgeCell = require('../../Release/AgeCell');
|
||||||
|
var ProtocolCell = require('../../Release/ProtocolCell');
|
||||||
|
var PeersCell = require('../../Release/PeersCell');
|
||||||
|
|
||||||
|
module.exports = Marionette.Layout.extend({
|
||||||
|
template : 'Movies/Search/ManualLayoutTemplate',
|
||||||
|
|
||||||
|
regions : {
|
||||||
|
grid : '#episode-release-grid'
|
||||||
|
},
|
||||||
|
|
||||||
|
columns : [
|
||||||
|
{
|
||||||
|
name : 'protocol',
|
||||||
|
label : 'Source',
|
||||||
|
cell : ProtocolCell
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'age',
|
||||||
|
label : 'Age',
|
||||||
|
cell : AgeCell
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'title',
|
||||||
|
label : 'Title',
|
||||||
|
cell : ReleaseTitleCell
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'indexer',
|
||||||
|
label : 'Indexer',
|
||||||
|
cell : Backgrid.StringCell
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'size',
|
||||||
|
label : 'Size',
|
||||||
|
cell : FileSizeCell
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'seeders',
|
||||||
|
label : 'Peers',
|
||||||
|
cell : PeersCell
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'quality',
|
||||||
|
label : 'Quality',
|
||||||
|
cell : QualityCell
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'rejections',
|
||||||
|
label : '<i class="icon-sonarr-header-rejections" />',
|
||||||
|
tooltip : 'Rejections',
|
||||||
|
cell : ApprovalStatusCell,
|
||||||
|
sortable : true,
|
||||||
|
sortType : 'fixed',
|
||||||
|
direction : 'ascending',
|
||||||
|
title : 'Release Rejected'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'download',
|
||||||
|
label : '<i class="icon-sonarr-download" />',
|
||||||
|
tooltip : 'Auto-Search Prioritization',
|
||||||
|
cell : DownloadReportCell,
|
||||||
|
sortable : true,
|
||||||
|
sortType : 'fixed',
|
||||||
|
direction : 'ascending'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
onShow : function() {
|
||||||
|
if (!this.isClosed) {
|
||||||
|
this.grid.show(new Backgrid.Grid({
|
||||||
|
row : Backgrid.Row,
|
||||||
|
columns : this.columns,
|
||||||
|
collection : this.collection,
|
||||||
|
className : 'table table-hover'
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
2
src/UI/Movies/Search/ManualLayoutTemplate.hbs
Normal file
2
src/UI/Movies/Search/ManualLayoutTemplate.hbs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<div id="episode-release-grid" class="table-responsive"></div>
|
||||||
|
<button class="btn x-search-back">Back</button>
|
82
src/UI/Movies/Search/MovieSearchLayout.js
Normal file
82
src/UI/Movies/Search/MovieSearchLayout.js
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
var vent = require('vent');
|
||||||
|
var Marionette = require('marionette');
|
||||||
|
var ButtonsView = require('./ButtonsView');
|
||||||
|
var ManualSearchLayout = require('./ManualLayout');
|
||||||
|
var ReleaseCollection = require('../../Release/ReleaseCollection');
|
||||||
|
var CommandController = require('../../Commands/CommandController');
|
||||||
|
var LoadingView = require('../../Shared/LoadingView');
|
||||||
|
var NoResultsView = require('./NoResultsView');
|
||||||
|
|
||||||
|
module.exports = Marionette.Layout.extend({
|
||||||
|
template : 'Movies/Search/MovieSearchLayoutTemplate',
|
||||||
|
|
||||||
|
regions : {
|
||||||
|
main : '#episode-search-region'
|
||||||
|
},
|
||||||
|
|
||||||
|
events : {
|
||||||
|
'click .x-search-auto' : '_searchAuto',
|
||||||
|
'click .x-search-manual' : '_searchManual',
|
||||||
|
'click .x-search-back' : '_showButtons'
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize : function() {
|
||||||
|
this.mainView = new ButtonsView();
|
||||||
|
this.releaseCollection = new ReleaseCollection();
|
||||||
|
|
||||||
|
this.listenTo(this.releaseCollection, 'sync', this._showSearchResults);
|
||||||
|
},
|
||||||
|
|
||||||
|
onShow : function() {
|
||||||
|
if (this.startManualSearch) {
|
||||||
|
this._searchManual();
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
this._showMainView();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_searchAuto : function(e) {
|
||||||
|
if (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandController.Execute('episodeSearch', {
|
||||||
|
episodeIds : [this.model.get('id')]
|
||||||
|
});
|
||||||
|
|
||||||
|
vent.trigger(vent.Commands.CloseModalCommand);
|
||||||
|
},
|
||||||
|
|
||||||
|
_searchManual : function(e) {
|
||||||
|
if (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mainView = new LoadingView();
|
||||||
|
this._showMainView();
|
||||||
|
this.releaseCollection.fetchMovieReleases(this.model.id);
|
||||||
|
},
|
||||||
|
|
||||||
|
_showMainView : function() {
|
||||||
|
this.main.show(this.mainView);
|
||||||
|
},
|
||||||
|
|
||||||
|
_showButtons : function() {
|
||||||
|
this.mainView = new ButtonsView();
|
||||||
|
this._showMainView();
|
||||||
|
},
|
||||||
|
|
||||||
|
_showSearchResults : function() {
|
||||||
|
if (this.releaseCollection.length === 0) {
|
||||||
|
this.mainView = new NoResultsView();
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
this.mainView = new ManualSearchLayout({ collection : this.releaseCollection });
|
||||||
|
}
|
||||||
|
|
||||||
|
this._showMainView();
|
||||||
|
}
|
||||||
|
});
|
1
src/UI/Movies/Search/MovieSearchLayoutTemplate.hbs
Normal file
1
src/UI/Movies/Search/MovieSearchLayoutTemplate.hbs
Normal file
@ -0,0 +1 @@
|
|||||||
|
<div id="episode-search-region"></div>
|
5
src/UI/Movies/Search/NoResultsView.js
Normal file
5
src/UI/Movies/Search/NoResultsView.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
var Marionette = require('marionette');
|
||||||
|
|
||||||
|
module.exports = Marionette.ItemView.extend({
|
||||||
|
template : 'Movies/Search/NoResultsViewTemplate'
|
||||||
|
});
|
1
src/UI/Movies/Search/NoResultsViewTemplate.hbs
Normal file
1
src/UI/Movies/Search/NoResultsViewTemplate.hbs
Normal file
@ -0,0 +1 @@
|
|||||||
|
<div>No results found</div>
|
@ -2,7 +2,7 @@ var _ = require('underscore');
|
|||||||
var $ = require('jquery');
|
var $ = require('jquery');
|
||||||
var vent = require('vent');
|
var vent = require('vent');
|
||||||
var Backbone = require('backbone');
|
var Backbone = require('backbone');
|
||||||
var SeriesCollection = require('../Series/SeriesCollection');
|
var SeriesCollection = require('../Movies/MoviesCollection');
|
||||||
require('typeahead');
|
require('typeahead');
|
||||||
|
|
||||||
vent.on(vent.Hotkeys.NavbarSearch, function() {
|
vent.on(vent.Hotkeys.NavbarSearch, function() {
|
||||||
@ -32,6 +32,6 @@ $.fn.bindSearch = function() {
|
|||||||
$(this).on('typeahead:selected typeahead:autocompleted', function(e, series) {
|
$(this).on('typeahead:selected typeahead:autocompleted', function(e, series) {
|
||||||
this.blur();
|
this.blur();
|
||||||
$(this).val('');
|
$(this).val('');
|
||||||
Backbone.history.navigate('/series/{0}'.format(series.titleSlug), { trigger : true });
|
Backbone.history.navigate('/movies/{0}'.format(series.titleSlug), { trigger : true });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -48,9 +48,14 @@ var Collection = PagableCollection.extend({
|
|||||||
|
|
||||||
fetchEpisodeReleases : function(episodeId) {
|
fetchEpisodeReleases : function(episodeId) {
|
||||||
return this.fetch({ data : { episodeId : episodeId } });
|
return this.fetch({ data : { episodeId : episodeId } });
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchMovieReleases : function(movieId) {
|
||||||
|
return this.fetch({ data : { movieId : movieId}});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Collection = AsSortedCollection.call(Collection);
|
Collection = AsSortedCollection.call(Collection);
|
||||||
|
|
||||||
module.exports = Collection;
|
module.exports = Collection;
|
||||||
|
@ -8,10 +8,10 @@ module.exports = NzbDroneController.extend({
|
|||||||
_originalInit : NzbDroneController.prototype.initialize,
|
_originalInit : NzbDroneController.prototype.initialize,
|
||||||
|
|
||||||
initialize : function() {
|
initialize : function() {
|
||||||
this.route('', this.series);
|
//this.route('', this.series);
|
||||||
this.route('series', this.series);
|
this.route('series', this.series);
|
||||||
this.route('series/:query', this.seriesDetails);
|
this.route('series/:query', this.seriesDetails);
|
||||||
|
|
||||||
this._originalInit.apply(this, arguments);
|
this._originalInit.apply(this, arguments);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -21,10 +21,13 @@ module.exports = NzbDroneController.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
seriesDetails : function(query) {
|
seriesDetails : function(query) {
|
||||||
|
console.warn(AppLayout.mainRegion)
|
||||||
|
|
||||||
var series = SeriesCollection.where({ titleSlug : query });
|
var series = SeriesCollection.where({ titleSlug : query });
|
||||||
|
|
||||||
if (series.length !== 0) {
|
if (series.length !== 0) {
|
||||||
var targetSeries = series[0];
|
var targetSeries = series[0];
|
||||||
|
|
||||||
this.setTitle(targetSeries.get('title'));
|
this.setTitle(targetSeries.get('title'));
|
||||||
this.showMainRegion(new SeriesDetailsLayout({ model : targetSeries }));
|
this.showMainRegion(new SeriesDetailsLayout({ model : targetSeries }));
|
||||||
} else {
|
} else {
|
||||||
|
@ -19,6 +19,7 @@ module.exports = Marionette.AppRouter.extend({
|
|||||||
vent.on(vent.Commands.EditSeriesCommand, this._editSeries, this);
|
vent.on(vent.Commands.EditSeriesCommand, this._editSeries, this);
|
||||||
vent.on(vent.Commands.DeleteSeriesCommand, this._deleteSeries, this);
|
vent.on(vent.Commands.DeleteSeriesCommand, this._deleteSeries, this);
|
||||||
vent.on(vent.Commands.ShowEpisodeDetails, this._showEpisode, this);
|
vent.on(vent.Commands.ShowEpisodeDetails, this._showEpisode, this);
|
||||||
|
vent.on(vent.Commands.ShowMovieDetails, this._showMovie, this);
|
||||||
vent.on(vent.Commands.ShowHistoryDetails, this._showHistory, this);
|
vent.on(vent.Commands.ShowHistoryDetails, this._showHistory, this);
|
||||||
vent.on(vent.Commands.ShowLogDetails, this._showLogDetails, this);
|
vent.on(vent.Commands.ShowLogDetails, this._showLogDetails, this);
|
||||||
vent.on(vent.Commands.ShowRenamePreview, this._showRenamePreview, this);
|
vent.on(vent.Commands.ShowRenamePreview, this._showRenamePreview, this);
|
||||||
@ -62,6 +63,15 @@ module.exports = Marionette.AppRouter.extend({
|
|||||||
AppLayout.modalRegion.show(view);
|
AppLayout.modalRegion.show(view);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_showMovie : function(options) {
|
||||||
|
var view = new MoviesDetailsLayout({
|
||||||
|
model : options.movie,
|
||||||
|
hideSeriesLink : options.hideSeriesLink,
|
||||||
|
openingTab : options.openingTab
|
||||||
|
});
|
||||||
|
AppLayout.modalRegion.show(view);
|
||||||
|
},
|
||||||
|
|
||||||
_showHistory : function(options) {
|
_showHistory : function(options) {
|
||||||
var view = new HistoryDetailsLayout({ model : options.model });
|
var view = new HistoryDetailsLayout({ model : options.model });
|
||||||
AppLayout.modalRegion.show(view);
|
AppLayout.modalRegion.show(view);
|
||||||
@ -90,4 +100,4 @@ module.exports = Marionette.AppRouter.extend({
|
|||||||
_closeFileBrowser : function() {
|
_closeFileBrowser : function() {
|
||||||
AppLayout.modalRegion2.closeModal();
|
AppLayout.modalRegion2.closeModal();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -5,7 +5,8 @@ var RouteBinder = require('./jQuery/RouteBinder');
|
|||||||
var SignalRBroadcaster = require('./Shared/SignalRBroadcaster');
|
var SignalRBroadcaster = require('./Shared/SignalRBroadcaster');
|
||||||
var NavbarLayout = require('./Navbar/NavbarLayout');
|
var NavbarLayout = require('./Navbar/NavbarLayout');
|
||||||
var AppLayout = require('./AppLayout');
|
var AppLayout = require('./AppLayout');
|
||||||
var SeriesController = require('./Movies/MoviesController');
|
var MoviesController = require('./Movies/MoviesController');
|
||||||
|
var SeriesController = require('./Series/SeriesController');
|
||||||
var Router = require('./Router');
|
var Router = require('./Router');
|
||||||
var ModalController = require('./Shared/Modal/ModalController');
|
var ModalController = require('./Shared/Modal/ModalController');
|
||||||
var ControlPanelController = require('./Shared/ControlPanel/ControlPanelController');
|
var ControlPanelController = require('./Shared/ControlPanel/ControlPanelController');
|
||||||
@ -20,6 +21,7 @@ require('./Hotkeys/Hotkeys');
|
|||||||
require('./Shared/piwikCheck');
|
require('./Shared/piwikCheck');
|
||||||
require('./Shared/VersionChangeMonitor');
|
require('./Shared/VersionChangeMonitor');
|
||||||
|
|
||||||
|
new MoviesController();
|
||||||
new SeriesController();
|
new SeriesController();
|
||||||
new ModalController();
|
new ModalController();
|
||||||
new ControlPanelController();
|
new ControlPanelController();
|
||||||
|
@ -18,6 +18,7 @@ vent.Commands = {
|
|||||||
OpenModal2Command : 'OpenModal2Command',
|
OpenModal2Command : 'OpenModal2Command',
|
||||||
CloseModal2Command : 'CloseModal2Command',
|
CloseModal2Command : 'CloseModal2Command',
|
||||||
ShowEpisodeDetails : 'ShowEpisodeDetails',
|
ShowEpisodeDetails : 'ShowEpisodeDetails',
|
||||||
|
ShowMovieDetails : 'ShowMovieDetails',
|
||||||
ShowHistoryDetails : 'ShowHistoryDetails',
|
ShowHistoryDetails : 'ShowHistoryDetails',
|
||||||
ShowLogDetails : 'ShowLogDetails',
|
ShowLogDetails : 'ShowLogDetails',
|
||||||
SaveSettings : 'saveSettings',
|
SaveSettings : 'saveSettings',
|
||||||
@ -36,4 +37,4 @@ vent.Hotkeys = {
|
|||||||
ShowHotkeys : 'hotkeys:show'
|
ShowHotkeys : 'hotkeys:show'
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = vent;
|
module.exports = vent;
|
||||||
|
Loading…
Reference in New Issue
Block a user