mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-20 05:23:31 -07:00
Merge remote-tracking branch 'refs/remotes/galli-leo/develop' into develop
This commit is contained in:
commit
1488c0a0fc
35 changed files with 634 additions and 63 deletions
|
@ -3,6 +3,7 @@ using Nancy;
|
||||||
using NzbDrone.Api.Episodes;
|
using NzbDrone.Api.Episodes;
|
||||||
using NzbDrone.Api.Extensions;
|
using NzbDrone.Api.Extensions;
|
||||||
using NzbDrone.Api.Series;
|
using NzbDrone.Api.Series;
|
||||||
|
using NzbDrone.Api.Movie;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.DecisionEngine;
|
using NzbDrone.Core.DecisionEngine;
|
||||||
using NzbDrone.Core.Download;
|
using NzbDrone.Core.Download;
|
||||||
|
@ -34,12 +35,18 @@ namespace NzbDrone.Api.History
|
||||||
|
|
||||||
resource.Series = model.Series.ToResource();
|
resource.Series = model.Series.ToResource();
|
||||||
resource.Episode = model.Episode.ToResource();
|
resource.Episode = model.Episode.ToResource();
|
||||||
|
resource.Movie = model.Movie.ToResource();
|
||||||
|
|
||||||
if (model.Series != null)
|
if (model.Series != null)
|
||||||
{
|
{
|
||||||
resource.QualityCutoffNotMet = _qualityUpgradableSpecification.CutoffNotMet(model.Series.Profile.Value, model.Quality);
|
resource.QualityCutoffNotMet = _qualityUpgradableSpecification.CutoffNotMet(model.Series.Profile.Value, model.Quality);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (model.Movie != null)
|
||||||
|
{
|
||||||
|
resource.QualityCutoffNotMet = _qualityUpgradableSpecification.CutoffNotMet(model.Movie.Profile.Value, model.Quality);
|
||||||
|
}
|
||||||
|
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +54,8 @@ namespace NzbDrone.Api.History
|
||||||
{
|
{
|
||||||
var episodeId = Request.Query.EpisodeId;
|
var episodeId = Request.Query.EpisodeId;
|
||||||
|
|
||||||
|
var movieId = Request.Query.MovieId;
|
||||||
|
|
||||||
var pagingSpec = pagingResource.MapToPagingSpec<HistoryResource, Core.History.History>("date", SortDirection.Descending);
|
var pagingSpec = pagingResource.MapToPagingSpec<HistoryResource, Core.History.History>("date", SortDirection.Descending);
|
||||||
|
|
||||||
if (pagingResource.FilterKey == "eventType")
|
if (pagingResource.FilterKey == "eventType")
|
||||||
|
@ -61,6 +70,12 @@ namespace NzbDrone.Api.History
|
||||||
pagingSpec.FilterExpression = h => h.EpisodeId == i;
|
pagingSpec.FilterExpression = h => h.EpisodeId == i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (movieId.HasValue)
|
||||||
|
{
|
||||||
|
int i = (int)movieId;
|
||||||
|
pagingSpec.FilterExpression = h => h.MovieId == i;
|
||||||
|
}
|
||||||
|
|
||||||
return ApplyToPage(_historyService.Paged, pagingSpec, MapToResource);
|
return ApplyToPage(_historyService.Paged, pagingSpec, MapToResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using NzbDrone.Api.Episodes;
|
using NzbDrone.Api.Episodes;
|
||||||
using NzbDrone.Api.REST;
|
using NzbDrone.Api.REST;
|
||||||
using NzbDrone.Api.Series;
|
using NzbDrone.Api.Series;
|
||||||
|
using NzbDrone.Api.Movie;
|
||||||
using NzbDrone.Core.History;
|
using NzbDrone.Core.History;
|
||||||
using NzbDrone.Core.Qualities;
|
using NzbDrone.Core.Qualities;
|
||||||
|
|
||||||
|
@ -12,6 +13,7 @@ namespace NzbDrone.Api.History
|
||||||
public class HistoryResource : RestResource
|
public class HistoryResource : RestResource
|
||||||
{
|
{
|
||||||
public int EpisodeId { get; set; }
|
public int EpisodeId { get; set; }
|
||||||
|
public int MovieId { get; set; }
|
||||||
public int SeriesId { get; set; }
|
public int SeriesId { get; set; }
|
||||||
public string SourceTitle { get; set; }
|
public string SourceTitle { get; set; }
|
||||||
public QualityModel Quality { get; set; }
|
public QualityModel Quality { get; set; }
|
||||||
|
@ -22,7 +24,7 @@ namespace NzbDrone.Api.History
|
||||||
public HistoryEventType EventType { get; set; }
|
public HistoryEventType EventType { get; set; }
|
||||||
|
|
||||||
public Dictionary<string, string> Data { get; set; }
|
public Dictionary<string, string> Data { get; set; }
|
||||||
|
public MovieResource Movie { get; set; }
|
||||||
public EpisodeResource Episode { get; set; }
|
public EpisodeResource Episode { get; set; }
|
||||||
public SeriesResource Series { get; set; }
|
public SeriesResource Series { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -39,6 +41,7 @@ namespace NzbDrone.Api.History
|
||||||
|
|
||||||
EpisodeId = model.EpisodeId,
|
EpisodeId = model.EpisodeId,
|
||||||
SeriesId = model.SeriesId,
|
SeriesId = model.SeriesId,
|
||||||
|
MovieId = model.MovieId,
|
||||||
SourceTitle = model.SourceTitle,
|
SourceTitle = model.SourceTitle,
|
||||||
Quality = model.Quality,
|
Quality = model.Quality,
|
||||||
//QualityCutoffNotMet
|
//QualityCutoffNotMet
|
||||||
|
|
|
@ -26,6 +26,7 @@ namespace NzbDrone.Api.Indexers
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
private readonly ICached<RemoteEpisode> _remoteEpisodeCache;
|
private readonly ICached<RemoteEpisode> _remoteEpisodeCache;
|
||||||
|
private readonly ICached<RemoteMovie> _remoteMovieCache;
|
||||||
|
|
||||||
public ReleaseModule(IFetchAndParseRss rssFetcherAndParser,
|
public ReleaseModule(IFetchAndParseRss rssFetcherAndParser,
|
||||||
ISearchForNzb nzbSearchService,
|
ISearchForNzb nzbSearchService,
|
||||||
|
@ -49,6 +50,7 @@ namespace NzbDrone.Api.Indexers
|
||||||
PostValidator.RuleFor(s => s.Guid).NotEmpty();
|
PostValidator.RuleFor(s => s.Guid).NotEmpty();
|
||||||
|
|
||||||
_remoteEpisodeCache = cacheManager.GetCache<RemoteEpisode>(GetType(), "remoteEpisodes");
|
_remoteEpisodeCache = cacheManager.GetCache<RemoteEpisode>(GetType(), "remoteEpisodes");
|
||||||
|
_remoteMovieCache = cacheManager.GetCache<RemoteMovie>(GetType(), "remoteMovies");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Response DownloadRelease(ReleaseResource release)
|
private Response DownloadRelease(ReleaseResource release)
|
||||||
|
@ -59,9 +61,28 @@ namespace NzbDrone.Api.Indexers
|
||||||
{
|
{
|
||||||
_logger.Debug("Couldn't find requested release in cache, cache timeout probably expired.");
|
_logger.Debug("Couldn't find requested release in cache, cache timeout probably expired.");
|
||||||
|
|
||||||
|
var remoteMovie = _remoteMovieCache.Find(release.Guid);
|
||||||
|
|
||||||
|
if (remoteMovie == null)
|
||||||
|
{
|
||||||
return new NotFoundResponse();
|
return new NotFoundResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_downloadService.DownloadReport(remoteMovie);
|
||||||
|
}
|
||||||
|
catch (ReleaseDownloadException ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, ex.Message);
|
||||||
|
throw new NzbDroneClientException(HttpStatusCode.Conflict, "Getting release from indexer failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
return release.AsResponse();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_downloadService.DownloadReport(remoteEpisode);
|
_downloadService.DownloadReport(remoteEpisode);
|
||||||
|
@ -138,8 +159,16 @@ namespace NzbDrone.Api.Indexers
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override ReleaseResource MapDecision(DownloadDecision decision, int initialWeight)
|
protected override ReleaseResource MapDecision(DownloadDecision decision, int initialWeight)
|
||||||
|
{
|
||||||
|
if (decision.IsForMovie)
|
||||||
|
{
|
||||||
|
_remoteMovieCache.Set(decision.RemoteMovie.Release.Guid, decision.RemoteMovie, TimeSpan.FromMinutes(30));
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
_remoteEpisodeCache.Set(decision.RemoteEpisode.Release.Guid, decision.RemoteEpisode, TimeSpan.FromMinutes(30));
|
_remoteEpisodeCache.Set(decision.RemoteEpisode.Release.Guid, decision.RemoteEpisode, TimeSpan.FromMinutes(30));
|
||||||
|
}
|
||||||
|
|
||||||
return base.MapDecision(decision, initialWeight);
|
return base.MapDecision(decision, initialWeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ using NzbDrone.Api.REST;
|
||||||
using NzbDrone.Core.Qualities;
|
using NzbDrone.Core.Qualities;
|
||||||
using NzbDrone.Api.Series;
|
using NzbDrone.Api.Series;
|
||||||
using NzbDrone.Api.Episodes;
|
using NzbDrone.Api.Episodes;
|
||||||
|
using NzbDrone.Api.Movie;
|
||||||
using NzbDrone.Core.Download.TrackedDownloads;
|
using NzbDrone.Core.Download.TrackedDownloads;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -14,6 +15,7 @@ namespace NzbDrone.Api.Queue
|
||||||
{
|
{
|
||||||
public SeriesResource Series { get; set; }
|
public SeriesResource Series { get; set; }
|
||||||
public EpisodeResource Episode { get; set; }
|
public EpisodeResource Episode { get; set; }
|
||||||
|
public MovieResource Movie { get; set; }
|
||||||
public QualityModel Quality { get; set; }
|
public QualityModel Quality { get; set; }
|
||||||
public decimal Size { get; set; }
|
public decimal Size { get; set; }
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
|
@ -49,7 +51,8 @@ namespace NzbDrone.Api.Queue
|
||||||
TrackedDownloadStatus = model.TrackedDownloadStatus,
|
TrackedDownloadStatus = model.TrackedDownloadStatus,
|
||||||
StatusMessages = model.StatusMessages,
|
StatusMessages = model.StatusMessages,
|
||||||
DownloadId = model.DownloadId,
|
DownloadId = model.DownloadId,
|
||||||
Protocol = model.Protocol
|
Protocol = model.Protocol,
|
||||||
|
Movie = model.Movie.ToResource()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,8 @@ namespace NzbDrone.Core.Datastore.Migration
|
||||||
.WithColumn("Quality").AsString()
|
.WithColumn("Quality").AsString()
|
||||||
.WithColumn("Indexer").AsString()
|
.WithColumn("Indexer").AsString()
|
||||||
.WithColumn("NzbInfoUrl").AsString().Nullable()
|
.WithColumn("NzbInfoUrl").AsString().Nullable()
|
||||||
.WithColumn("ReleaseGroup").AsString().Nullable();
|
.WithColumn("ReleaseGroup").AsString().Nullable()
|
||||||
|
.WithColumn("MovieId").AsInt32().WithDefaultValue(0);
|
||||||
|
|
||||||
Create.TableForModel("Notifications")
|
Create.TableForModel("Notifications")
|
||||||
.WithColumn("Name").AsString()
|
.WithColumn("Name").AsString()
|
||||||
|
|
|
@ -58,6 +58,32 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic
|
||||||
return GetDownloadClientId(strmFile);
|
return GetDownloadClientId(strmFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string Download(RemoteMovie remoteEpisode)
|
||||||
|
{
|
||||||
|
var url = remoteEpisode.Release.DownloadUrl;
|
||||||
|
var title = remoteEpisode.Release.Title;
|
||||||
|
|
||||||
|
if (remoteEpisode.ParsedEpisodeInfo.FullSeason)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("Full season releases are not supported with Pneumatic.");
|
||||||
|
}
|
||||||
|
|
||||||
|
title = FileNameBuilder.CleanFileName(title);
|
||||||
|
|
||||||
|
//Save to the Pneumatic directory (The user will need to ensure its accessible by XBMC)
|
||||||
|
var nzbFile = Path.Combine(Settings.NzbFolder, title + ".nzb");
|
||||||
|
|
||||||
|
_logger.Debug("Downloading NZB from: {0} to: {1}", url, nzbFile);
|
||||||
|
_httpClient.DownloadFile(url, nzbFile);
|
||||||
|
|
||||||
|
_logger.Debug("NZB Download succeeded, saved to: {0}", nzbFile);
|
||||||
|
|
||||||
|
var strmFile = WriteStrmFile(title, nzbFile);
|
||||||
|
|
||||||
|
|
||||||
|
return GetDownloadClientId(strmFile);
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsConfigured => !string.IsNullOrWhiteSpace(Settings.NzbFolder);
|
public bool IsConfigured => !string.IsNullOrWhiteSpace(Settings.NzbFolder);
|
||||||
|
|
||||||
public override IEnumerable<DownloadClientItem> GetItems()
|
public override IEnumerable<DownloadClientItem> GetItems()
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||||
_proxy.SetTorrentLabel(hash.ToLower(), Settings.TvCategory, Settings);
|
_proxy.SetTorrentLabel(hash.ToLower(), Settings.TvCategory, Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
var isRecentEpisode = true;//remoteEpisode.IsRecentEpisode(); TODO: Update to use RemoteMovie!
|
var isRecentEpisode = remoteEpisode.IsRecentEpisode();
|
||||||
|
|
||||||
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)
|
||||||
|
@ -71,6 +71,46 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override string AddFromMagnetLink(RemoteMovie remoteEpisode, string hash, string magnetLink)
|
||||||
|
{
|
||||||
|
_proxy.AddTorrentFromUrl(magnetLink, Settings);
|
||||||
|
|
||||||
|
if (Settings.TvCategory.IsNotNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
_proxy.SetTorrentLabel(hash.ToLower(), Settings.TvCategory, Settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*var isRecentEpisode = remoteEpisode.IsRecentEpisode();
|
||||||
|
|
||||||
|
if (isRecentEpisode && Settings.RecentTvPriority == (int)QBittorrentPriority.First ||
|
||||||
|
!isRecentEpisode && Settings.OlderTvPriority == (int)QBittorrentPriority.First)
|
||||||
|
{
|
||||||
|
_proxy.MoveTorrentToTopInQueue(hash.ToLower(), Settings);
|
||||||
|
}*/ //TODO: Maybe reimplement for movies
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string AddFromTorrentFile(RemoteMovie remoteEpisode, string hash, string filename, Byte[] fileContent)
|
||||||
|
{
|
||||||
|
_proxy.AddTorrentFromFile(filename, fileContent, Settings);
|
||||||
|
|
||||||
|
if (Settings.TvCategory.IsNotNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
_proxy.SetTorrentLabel(hash.ToLower(), Settings.TvCategory, Settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*var isRecentEpisode = remoteEpisode.IsRecentEpisode();
|
||||||
|
|
||||||
|
if (isRecentEpisode && Settings.RecentTvPriority == (int)QBittorrentPriority.First ||
|
||||||
|
!isRecentEpisode && Settings.OlderTvPriority == (int)QBittorrentPriority.First)
|
||||||
|
{
|
||||||
|
_proxy.MoveTorrentToTopInQueue(hash.ToLower(), Settings);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
public override string Name => "qBittorrent";
|
public override string Name => "qBittorrent";
|
||||||
|
|
||||||
public override IEnumerable<DownloadClientItem> GetItems()
|
public override IEnumerable<DownloadClientItem> GetItems()
|
||||||
|
|
|
@ -57,6 +57,7 @@ namespace NzbDrone.Core.Download
|
||||||
get;
|
get;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public abstract string Download(RemoteEpisode remoteEpisode);
|
public abstract string Download(RemoteEpisode remoteEpisode);
|
||||||
public abstract IEnumerable<DownloadClientItem> GetItems();
|
public abstract IEnumerable<DownloadClientItem> GetItems();
|
||||||
public abstract void RemoveItem(string downloadId, bool deleteData);
|
public abstract void RemoveItem(string downloadId, bool deleteData);
|
||||||
|
@ -147,5 +148,7 @@ namespace NzbDrone.Core.Download
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract string Download(RemoteMovie remoteMovie);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ namespace NzbDrone.Core.Download
|
||||||
public interface IDownloadService
|
public interface IDownloadService
|
||||||
{
|
{
|
||||||
void DownloadReport(RemoteEpisode remoteEpisode);
|
void DownloadReport(RemoteEpisode remoteEpisode);
|
||||||
|
void DownloadReport(RemoteMovie remoteMovie);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,5 +92,62 @@ namespace NzbDrone.Core.Download
|
||||||
_logger.ProgressInfo("Report sent to {0}. {1}", downloadClient.Definition.Name, downloadTitle);
|
_logger.ProgressInfo("Report sent to {0}. {1}", downloadClient.Definition.Name, downloadTitle);
|
||||||
_eventAggregator.PublishEvent(episodeGrabbedEvent);
|
_eventAggregator.PublishEvent(episodeGrabbedEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DownloadReport(RemoteMovie remoteMovie)
|
||||||
|
{
|
||||||
|
//Ensure.That(remoteEpisode.Series, () => remoteEpisode.Series).IsNotNull();
|
||||||
|
//Ensure.That(remoteEpisode.Episodes, () => remoteEpisode.Episodes).HasItems(); TODO update this shit
|
||||||
|
|
||||||
|
var downloadTitle = remoteMovie.Release.Title;
|
||||||
|
var downloadClient = _downloadClientProvider.GetDownloadClient(remoteMovie.Release.DownloadProtocol);
|
||||||
|
|
||||||
|
if (downloadClient == null)
|
||||||
|
{
|
||||||
|
_logger.Warn("{0} Download client isn't configured yet.", remoteMovie.Release.DownloadProtocol);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit grabs to 2 per second.
|
||||||
|
if (remoteMovie.Release.DownloadUrl.IsNotNullOrWhiteSpace() && !remoteMovie.Release.DownloadUrl.StartsWith("magnet:"))
|
||||||
|
{
|
||||||
|
var url = new HttpUri(remoteMovie.Release.DownloadUrl);
|
||||||
|
_rateLimitService.WaitAndPulse(url.Host, TimeSpan.FromSeconds(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
string downloadClientId = "";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
downloadClientId = downloadClient.Download(remoteMovie);
|
||||||
|
_indexerStatusService.RecordSuccess(remoteMovie.Release.IndexerId);
|
||||||
|
}
|
||||||
|
catch (NotImplementedException ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "The download client you are using is currently not configured to download movies. Please choose another one.");
|
||||||
|
}
|
||||||
|
catch (ReleaseDownloadException ex)
|
||||||
|
{
|
||||||
|
var http429 = ex.InnerException as TooManyRequestsException;
|
||||||
|
if (http429 != null)
|
||||||
|
{
|
||||||
|
_indexerStatusService.RecordFailure(remoteMovie.Release.IndexerId, http429.RetryAfter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_indexerStatusService.RecordFailure(remoteMovie.Release.IndexerId);
|
||||||
|
}
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
var episodeGrabbedEvent = new MovieGrabbedEvent(remoteMovie);
|
||||||
|
episodeGrabbedEvent.DownloadClient = downloadClient.GetType().Name;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(downloadClientId))
|
||||||
|
{
|
||||||
|
episodeGrabbedEvent.DownloadId = downloadClientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.ProgressInfo("Report sent to {0}. {1}", downloadClient.Definition.Name, downloadTitle);
|
||||||
|
_eventAggregator.PublishEvent(episodeGrabbedEvent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,6 +10,7 @@ namespace NzbDrone.Core.Download
|
||||||
DownloadProtocol Protocol { get; }
|
DownloadProtocol Protocol { get; }
|
||||||
|
|
||||||
string Download(RemoteEpisode remoteEpisode);
|
string Download(RemoteEpisode remoteEpisode);
|
||||||
|
string Download(RemoteMovie remoteMovie);
|
||||||
IEnumerable<DownloadClientItem> GetItems();
|
IEnumerable<DownloadClientItem> GetItems();
|
||||||
void RemoveItem(string downloadId, bool deleteData);
|
void RemoveItem(string downloadId, bool deleteData);
|
||||||
DownloadClientStatus GetStatus();
|
DownloadClientStatus GetStatus();
|
||||||
|
|
17
src/NzbDrone.Core/Download/MovieGrabbedEvent.cs
Normal file
17
src/NzbDrone.Core/Download/MovieGrabbedEvent.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
using NzbDrone.Common.Messaging;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download
|
||||||
|
{
|
||||||
|
public class MovieGrabbedEvent : IEvent
|
||||||
|
{
|
||||||
|
public RemoteMovie Movie { get; private set; }
|
||||||
|
public string DownloadClient { get; set; }
|
||||||
|
public string DownloadId { get; set; }
|
||||||
|
|
||||||
|
public MovieGrabbedEvent(RemoteMovie movie)
|
||||||
|
{
|
||||||
|
Movie = movie;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,6 +33,7 @@ namespace NzbDrone.Core.Download.Pending
|
||||||
public class PendingReleaseService : IPendingReleaseService,
|
public class PendingReleaseService : IPendingReleaseService,
|
||||||
IHandle<SeriesDeletedEvent>,
|
IHandle<SeriesDeletedEvent>,
|
||||||
IHandle<EpisodeGrabbedEvent>,
|
IHandle<EpisodeGrabbedEvent>,
|
||||||
|
IHandle<MovieGrabbedEvent>,
|
||||||
IHandle<RssSyncCompleteEvent>
|
IHandle<RssSyncCompleteEvent>
|
||||||
{
|
{
|
||||||
private readonly IIndexerStatusService _indexerStatusService;
|
private readonly IIndexerStatusService _indexerStatusService;
|
||||||
|
@ -341,6 +342,11 @@ namespace NzbDrone.Core.Download.Pending
|
||||||
RemoveGrabbed(message.Episode);
|
RemoveGrabbed(message.Episode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Handle(MovieGrabbedEvent message)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public void Handle(RssSyncCompleteEvent message)
|
public void Handle(RssSyncCompleteEvent message)
|
||||||
{
|
{
|
||||||
RemoveRejected(message.ProcessedDecisions.Rejected);
|
RemoveRejected(message.ProcessedDecisions.Rejected);
|
||||||
|
|
|
@ -40,21 +40,29 @@ namespace NzbDrone.Core.Download
|
||||||
|
|
||||||
protected abstract string AddFromMagnetLink(RemoteEpisode remoteEpisode, string hash, string magnetLink);
|
protected abstract string AddFromMagnetLink(RemoteEpisode remoteEpisode, string hash, string magnetLink);
|
||||||
protected abstract string AddFromTorrentFile(RemoteEpisode remoteEpisode, string hash, string filename, byte[] fileContent);
|
protected abstract string AddFromTorrentFile(RemoteEpisode remoteEpisode, string hash, string filename, byte[] fileContent);
|
||||||
|
protected virtual string AddFromMagnetLink(RemoteMovie remoteMovie, string hash, string magnetLink)
|
||||||
public override string Download(RemoteEpisode remoteEpisode)
|
|
||||||
{
|
{
|
||||||
var torrentInfo = remoteEpisode.Release as TorrentInfo;
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
protected virtual string AddFromTorrentFile(RemoteMovie remoteMovie, string hash, string filename, byte[] fileContent)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Download(RemoteMovie remoteMovie)
|
||||||
|
{
|
||||||
|
var torrentInfo = remoteMovie.Release as TorrentInfo;
|
||||||
|
|
||||||
string magnetUrl = null;
|
string magnetUrl = null;
|
||||||
string torrentUrl = null;
|
string torrentUrl = null;
|
||||||
|
|
||||||
if (remoteEpisode.Release.DownloadUrl.IsNotNullOrWhiteSpace() && remoteEpisode.Release.DownloadUrl.StartsWith("magnet:"))
|
if (remoteMovie.Release.DownloadUrl.IsNotNullOrWhiteSpace() && remoteMovie.Release.DownloadUrl.StartsWith("magnet:"))
|
||||||
{
|
{
|
||||||
magnetUrl = remoteEpisode.Release.DownloadUrl;
|
magnetUrl = remoteMovie.Release.DownloadUrl;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
torrentUrl = remoteEpisode.Release.DownloadUrl;
|
torrentUrl = remoteMovie.Release.DownloadUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (torrentInfo != null && !torrentInfo.MagnetUrl.IsNullOrWhiteSpace())
|
if (torrentInfo != null && !torrentInfo.MagnetUrl.IsNullOrWhiteSpace())
|
||||||
|
@ -68,7 +76,7 @@ namespace NzbDrone.Core.Download
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return DownloadFromWebUrl(remoteEpisode, torrentUrl);
|
return DownloadFromWebUrl(remoteMovie, torrentUrl);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -85,11 +93,11 @@ namespace NzbDrone.Core.Download
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return DownloadFromMagnetUrl(remoteEpisode, magnetUrl);
|
return DownloadFromMagnetUrl(remoteMovie, magnetUrl);
|
||||||
}
|
}
|
||||||
catch (NotSupportedException ex)
|
catch (NotSupportedException ex)
|
||||||
{
|
{
|
||||||
throw new ReleaseDownloadException(remoteEpisode.Release, "Magnet not supported by download client. ({0})", ex.Message);
|
throw new ReleaseDownloadException(remoteMovie.Release, "Magnet not supported by download client. ({0})", ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,13 +107,13 @@ namespace NzbDrone.Core.Download
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return DownloadFromMagnetUrl(remoteEpisode, magnetUrl);
|
return DownloadFromMagnetUrl(remoteMovie, magnetUrl);
|
||||||
}
|
}
|
||||||
catch (NotSupportedException ex)
|
catch (NotSupportedException ex)
|
||||||
{
|
{
|
||||||
if (torrentUrl.IsNullOrWhiteSpace())
|
if (torrentUrl.IsNullOrWhiteSpace())
|
||||||
{
|
{
|
||||||
throw new ReleaseDownloadException(remoteEpisode.Release, "Magnet not supported by download client. ({0})", ex.Message);
|
throw new ReleaseDownloadException(remoteMovie.Release, "Magnet not supported by download client. ({0})", ex.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Debug("Magnet not supported by download client, trying torrent. ({0})", ex.Message);
|
_logger.Debug("Magnet not supported by download client, trying torrent. ({0})", ex.Message);
|
||||||
|
@ -114,13 +122,193 @@ namespace NzbDrone.Core.Download
|
||||||
|
|
||||||
if (torrentUrl.IsNotNullOrWhiteSpace())
|
if (torrentUrl.IsNotNullOrWhiteSpace())
|
||||||
{
|
{
|
||||||
return DownloadFromWebUrl(remoteEpisode, torrentUrl);
|
return DownloadFromWebUrl(remoteMovie, torrentUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string Download(RemoteEpisode remoteMovie)
|
||||||
|
{
|
||||||
|
var torrentInfo = remoteMovie.Release as TorrentInfo;
|
||||||
|
|
||||||
|
string magnetUrl = null;
|
||||||
|
string torrentUrl = null;
|
||||||
|
|
||||||
|
if (remoteMovie.Release.DownloadUrl.IsNotNullOrWhiteSpace() && remoteMovie.Release.DownloadUrl.StartsWith("magnet:"))
|
||||||
|
{
|
||||||
|
magnetUrl = remoteMovie.Release.DownloadUrl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
torrentUrl = remoteMovie.Release.DownloadUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (torrentInfo != null && !torrentInfo.MagnetUrl.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
magnetUrl = torrentInfo.MagnetUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PreferTorrentFile)
|
||||||
|
{
|
||||||
|
if (torrentUrl.IsNotNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return DownloadFromWebUrl(remoteMovie, torrentUrl);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (!magnetUrl.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Debug("Torrent download failed, trying magnet. ({0})", ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (magnetUrl.IsNotNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return DownloadFromMagnetUrl(remoteMovie, magnetUrl);
|
||||||
|
}
|
||||||
|
catch (NotSupportedException ex)
|
||||||
|
{
|
||||||
|
throw new ReleaseDownloadException(remoteMovie.Release, "Magnet not supported by download client. ({0})", ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (magnetUrl.IsNotNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return DownloadFromMagnetUrl(remoteMovie, magnetUrl);
|
||||||
|
}
|
||||||
|
catch (NotSupportedException ex)
|
||||||
|
{
|
||||||
|
if (torrentUrl.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
throw new ReleaseDownloadException(remoteMovie.Release, "Magnet not supported by download client. ({0})", ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Debug("Magnet not supported by download client, trying torrent. ({0})", ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (torrentUrl.IsNotNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
return DownloadFromWebUrl(remoteMovie, torrentUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string DownloadFromWebUrl(RemoteMovie remoteEpisode, string torrentUrl)
|
||||||
|
{
|
||||||
|
byte[] torrentFile = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var request = new HttpRequest(torrentUrl);
|
||||||
|
request.Headers.Accept = "application/x-bittorrent";
|
||||||
|
request.AllowAutoRedirect = false;
|
||||||
|
|
||||||
|
var response = _httpClient.Get(request);
|
||||||
|
|
||||||
|
if (response.StatusCode == HttpStatusCode.SeeOther || response.StatusCode == HttpStatusCode.Found)
|
||||||
|
{
|
||||||
|
var locationHeader = response.Headers.GetSingleValue("Location");
|
||||||
|
|
||||||
|
_logger.Trace("Torrent request is being redirected to: {0}", locationHeader);
|
||||||
|
|
||||||
|
if (locationHeader != null)
|
||||||
|
{
|
||||||
|
if (locationHeader.StartsWith("magnet:"))
|
||||||
|
{
|
||||||
|
return DownloadFromMagnetUrl(remoteEpisode, locationHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DownloadFromWebUrl(remoteEpisode, locationHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new WebException("Remote website tried to redirect without providing a location.");
|
||||||
|
}
|
||||||
|
|
||||||
|
torrentFile = response.ResponseData;
|
||||||
|
|
||||||
|
_logger.Debug("Downloading torrent for episode '{0}' finished ({1} bytes from {2})", remoteEpisode.Release.Title, torrentFile.Length, torrentUrl);
|
||||||
|
}
|
||||||
|
catch (HttpException ex)
|
||||||
|
{
|
||||||
|
if ((int)ex.Response.StatusCode == 429)
|
||||||
|
{
|
||||||
|
_logger.Error("API Grab Limit reached for {0}", torrentUrl);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Downloading torrent file for episode '{0}' failed ({1})", remoteEpisode.Release.Title, torrentUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ReleaseDownloadException(remoteEpisode.Release, "Downloading torrent failed", ex);
|
||||||
|
}
|
||||||
|
catch (WebException ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Downloading torrent file for episode '{0}' failed ({1})", remoteEpisode.Release.Title, torrentUrl);
|
||||||
|
|
||||||
|
throw new ReleaseDownloadException(remoteEpisode.Release, "Downloading torrent failed", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
var filename = string.Format("{0}.torrent", FileNameBuilder.CleanFileName(remoteEpisode.Release.Title));
|
||||||
|
var hash = _torrentFileInfoReader.GetHashFromTorrentFile(torrentFile);
|
||||||
|
var actualHash = AddFromTorrentFile(remoteEpisode, hash, filename, torrentFile);
|
||||||
|
|
||||||
|
if (actualHash.IsNotNullOrWhiteSpace() && hash != actualHash)
|
||||||
|
{
|
||||||
|
_logger.Debug(
|
||||||
|
"{0} did not return the expected InfoHash for '{1}', Sonarr could potentially lose track of the download in progress.",
|
||||||
|
Definition.Implementation, remoteEpisode.Release.DownloadUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
return actualHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string DownloadFromMagnetUrl(RemoteMovie remoteEpisode, string magnetUrl)
|
||||||
|
{
|
||||||
|
string hash = null;
|
||||||
|
string actualHash = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
hash = new MagnetLink(magnetUrl).InfoHash.ToHex();
|
||||||
|
}
|
||||||
|
catch (FormatException ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Failed to parse magnetlink for episode '{0}': '{1}'", remoteEpisode.Release.Title, magnetUrl);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hash != null)
|
||||||
|
{
|
||||||
|
actualHash = AddFromMagnetLink(remoteEpisode, hash, magnetUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actualHash.IsNotNullOrWhiteSpace() && hash != actualHash)
|
||||||
|
{
|
||||||
|
_logger.Debug(
|
||||||
|
"{0} did not return the expected InfoHash for '{1}', Sonarr could potentially lose track of the download in progress.",
|
||||||
|
Definition.Implementation, remoteEpisode.Release.DownloadUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
return actualHash;
|
||||||
|
}
|
||||||
|
|
||||||
private string DownloadFromWebUrl(RemoteEpisode remoteEpisode, string torrentUrl)
|
private string DownloadFromWebUrl(RemoteEpisode remoteEpisode, string torrentUrl)
|
||||||
{
|
{
|
||||||
byte[] torrentFile = null;
|
byte[] torrentFile = null;
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
public TrackedDownloadStage State { get; set; }
|
public TrackedDownloadStage State { get; set; }
|
||||||
public TrackedDownloadStatus Status { get; private set; }
|
public TrackedDownloadStatus Status { get; private set; }
|
||||||
public RemoteEpisode RemoteEpisode { get; set; }
|
public RemoteEpisode RemoteEpisode { get; set; }
|
||||||
|
public RemoteMovie RemoteMovie { get; set; }
|
||||||
public TrackedDownloadStatusMessage[] StatusMessages { get; private set; }
|
public TrackedDownloadStatusMessage[] StatusMessages { get; private set; }
|
||||||
public DownloadProtocol Protocol { get; set; }
|
public DownloadProtocol Protocol { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
if (parsedEpisodeInfo != null)
|
if (parsedEpisodeInfo != null)
|
||||||
{
|
{
|
||||||
trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0, 0);
|
trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0, 0);
|
||||||
|
trackedDownload.RemoteMovie = _parsingService.Map(parsedEpisodeInfo, "", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (historyItems.Any())
|
if (historyItems.Any())
|
||||||
|
@ -69,10 +70,10 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
var firstHistoryItem = historyItems.OrderByDescending(h => h.Date).First();
|
var firstHistoryItem = historyItems.OrderByDescending(h => h.Date).First();
|
||||||
trackedDownload.State = GetStateFromHistory(firstHistoryItem.EventType);
|
trackedDownload.State = GetStateFromHistory(firstHistoryItem.EventType);
|
||||||
|
|
||||||
if (parsedEpisodeInfo == null ||
|
if ((parsedEpisodeInfo == null ||
|
||||||
trackedDownload.RemoteEpisode == null ||
|
trackedDownload.RemoteEpisode == null ||
|
||||||
trackedDownload.RemoteEpisode.Series == null ||
|
trackedDownload.RemoteEpisode.Series == null ||
|
||||||
trackedDownload.RemoteEpisode.Episodes.Empty())
|
trackedDownload.RemoteEpisode.Episodes.Empty()) && trackedDownload.RemoteMovie == null)
|
||||||
{
|
{
|
||||||
// Try parsing the original source title and if that fails, try parsing it as a special
|
// Try parsing the original source title and if that fails, try parsing it as a special
|
||||||
// TODO: Pass the TVDB ID and TVRage IDs in as well so we have a better chance for finding the item
|
// TODO: Pass the TVDB ID and TVRage IDs in as well so we have a better chance for finding the item
|
||||||
|
@ -85,7 +86,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trackedDownload.RemoteEpisode == null)
|
if (trackedDownload.RemoteEpisode == null && trackedDownload.RemoteMovie == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Exceptions;
|
using NzbDrone.Core.Exceptions;
|
||||||
|
@ -31,6 +32,11 @@ namespace NzbDrone.Core.Download
|
||||||
|
|
||||||
protected abstract string AddFromNzbFile(RemoteEpisode remoteEpisode, string filename, byte[] fileContent);
|
protected abstract string AddFromNzbFile(RemoteEpisode remoteEpisode, string filename, byte[] fileContent);
|
||||||
|
|
||||||
|
protected virtual string AddFromNzbFile(RemoteMovie remoteMovie, string filename, byte[] fileContents)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
public override string Download(RemoteEpisode remoteEpisode)
|
public override string Download(RemoteEpisode remoteEpisode)
|
||||||
{
|
{
|
||||||
var url = remoteEpisode.Release.DownloadUrl;
|
var url = remoteEpisode.Release.DownloadUrl;
|
||||||
|
@ -67,5 +73,42 @@ namespace NzbDrone.Core.Download
|
||||||
_logger.Info("Adding report [{0}] to the queue.", remoteEpisode.Release.Title);
|
_logger.Info("Adding report [{0}] to the queue.", remoteEpisode.Release.Title);
|
||||||
return AddFromNzbFile(remoteEpisode, filename, nzbData);
|
return AddFromNzbFile(remoteEpisode, filename, nzbData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string Download(RemoteMovie remoteEpisode)
|
||||||
|
{
|
||||||
|
var url = remoteEpisode.Release.DownloadUrl;
|
||||||
|
var filename = FileNameBuilder.CleanFileName(remoteEpisode.Release.Title) + ".nzb";
|
||||||
|
|
||||||
|
byte[] nzbData;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
nzbData = _httpClient.Get(new HttpRequest(url)).ResponseData;
|
||||||
|
|
||||||
|
_logger.Debug("Downloaded nzb for episode '{0}' finished ({1} bytes from {2})", remoteEpisode.Release.Title, nzbData.Length, url);
|
||||||
|
}
|
||||||
|
catch (HttpException ex)
|
||||||
|
{
|
||||||
|
if ((int)ex.Response.StatusCode == 429)
|
||||||
|
{
|
||||||
|
_logger.Error("API Grab Limit reached for {0}", url);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Downloading nzb for episode '{0}' failed ({1})", remoteEpisode.Release.Title, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ReleaseDownloadException(remoteEpisode.Release, "Downloading nzb failed", ex);
|
||||||
|
}
|
||||||
|
catch (WebException ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Downloading nzb for episode '{0}' failed ({1})", remoteEpisode.Release.Title, url);
|
||||||
|
|
||||||
|
throw new ReleaseDownloadException(remoteEpisode.Release, "Downloading nzb failed", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Info("Adding report [{0}] to the queue.", remoteEpisode.Release.Title);
|
||||||
|
return AddFromNzbFile(remoteEpisode, filename, nzbData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,11 @@ namespace NzbDrone.Core.History
|
||||||
|
|
||||||
public int EpisodeId { get; set; }
|
public int EpisodeId { get; set; }
|
||||||
public int SeriesId { get; set; }
|
public int SeriesId { get; set; }
|
||||||
|
public int MovieId { get; set; }
|
||||||
public string SourceTitle { get; set; }
|
public string SourceTitle { get; set; }
|
||||||
public QualityModel Quality { get; set; }
|
public QualityModel Quality { get; set; }
|
||||||
public DateTime Date { get; set; }
|
public DateTime Date { get; set; }
|
||||||
|
public Movie Movie { get; set; }
|
||||||
public Episode Episode { get; set; }
|
public Episode Episode { get; set; }
|
||||||
public Series Series { get; set; }
|
public Series Series { get; set; }
|
||||||
public HistoryEventType EventType { get; set; }
|
public HistoryEventType EventType { get; set; }
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Marr.Data.QGen;
|
using Marr.Data.QGen;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
|
@ -16,6 +17,7 @@ namespace NzbDrone.Core.History
|
||||||
List<History> FindByDownloadId(string downloadId);
|
List<History> FindByDownloadId(string downloadId);
|
||||||
List<History> FindDownloadHistory(int idSeriesId, QualityModel quality);
|
List<History> FindDownloadHistory(int idSeriesId, QualityModel quality);
|
||||||
void DeleteForSeries(int seriesId);
|
void DeleteForSeries(int seriesId);
|
||||||
|
History MostRecentForMovie(int movieId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HistoryRepository : BasicRepository<History>, IHistoryRepository
|
public class HistoryRepository : BasicRepository<History>, IHistoryRepository
|
||||||
|
@ -71,10 +73,20 @@ namespace NzbDrone.Core.History
|
||||||
|
|
||||||
protected override SortBuilder<History> GetPagedQuery(QueryBuilder<History> query, PagingSpec<History> pagingSpec)
|
protected override SortBuilder<History> GetPagedQuery(QueryBuilder<History> query, PagingSpec<History> pagingSpec)
|
||||||
{
|
{
|
||||||
var baseQuery = query.Join<History, Series>(JoinType.Inner, h => h.Series, (h, s) => h.SeriesId == s.Id)
|
var baseQuery = query/*.Join<History, Series>(JoinType.Inner, h => h.Series, (h, s) => h.SeriesId == s.Id)
|
||||||
.Join<History, Episode>(JoinType.Inner, h => h.Episode, (h, e) => h.EpisodeId == e.Id);
|
.Join<History, Episode>(JoinType.Inner, h => h.Episode, (h, e) => h.EpisodeId == e.Id)*/
|
||||||
|
.Join<History, Movie>(JoinType.Inner, h => h.Movie, (h, e) => h.MovieId == e.Id);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return base.GetPagedQuery(baseQuery, pagingSpec);
|
return base.GetPagedQuery(baseQuery, pagingSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public History MostRecentForMovie(int movieId)
|
||||||
|
{
|
||||||
|
return Query.Where(h => h.MovieId == movieId)
|
||||||
|
.OrderByDescending(h => h.Date)
|
||||||
|
.FirstOrDefault();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,6 +20,7 @@ namespace NzbDrone.Core.History
|
||||||
{
|
{
|
||||||
QualityModel GetBestQualityInHistory(Profile profile, int episodeId);
|
QualityModel GetBestQualityInHistory(Profile profile, int episodeId);
|
||||||
PagingSpec<History> Paged(PagingSpec<History> pagingSpec);
|
PagingSpec<History> Paged(PagingSpec<History> pagingSpec);
|
||||||
|
History MostRecentForMovie(int movieId);
|
||||||
History MostRecentForEpisode(int episodeId);
|
History MostRecentForEpisode(int episodeId);
|
||||||
History MostRecentForDownloadId(string downloadId);
|
History MostRecentForDownloadId(string downloadId);
|
||||||
History Get(int historyId);
|
History Get(int historyId);
|
||||||
|
@ -29,6 +30,7 @@ namespace NzbDrone.Core.History
|
||||||
|
|
||||||
public class HistoryService : IHistoryService,
|
public class HistoryService : IHistoryService,
|
||||||
IHandle<EpisodeGrabbedEvent>,
|
IHandle<EpisodeGrabbedEvent>,
|
||||||
|
IHandle<MovieGrabbedEvent>,
|
||||||
IHandle<EpisodeImportedEvent>,
|
IHandle<EpisodeImportedEvent>,
|
||||||
IHandle<DownloadFailedEvent>,
|
IHandle<DownloadFailedEvent>,
|
||||||
IHandle<EpisodeFileDeletedEvent>,
|
IHandle<EpisodeFileDeletedEvent>,
|
||||||
|
@ -53,6 +55,11 @@ namespace NzbDrone.Core.History
|
||||||
return _historyRepository.MostRecentForEpisode(episodeId);
|
return _historyRepository.MostRecentForEpisode(episodeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public History MostRecentForMovie(int movieId)
|
||||||
|
{
|
||||||
|
return _historyRepository.MostRecentForMovie(movieId);
|
||||||
|
}
|
||||||
|
|
||||||
public History MostRecentForDownloadId(string downloadId)
|
public History MostRecentForDownloadId(string downloadId)
|
||||||
{
|
{
|
||||||
return _historyRepository.MostRecentForDownloadId(downloadId);
|
return _historyRepository.MostRecentForDownloadId(downloadId);
|
||||||
|
@ -138,7 +145,8 @@ namespace NzbDrone.Core.History
|
||||||
SourceTitle = message.Episode.Release.Title,
|
SourceTitle = message.Episode.Release.Title,
|
||||||
SeriesId = episode.SeriesId,
|
SeriesId = episode.SeriesId,
|
||||||
EpisodeId = episode.Id,
|
EpisodeId = episode.Id,
|
||||||
DownloadId = message.DownloadId
|
DownloadId = message.DownloadId,
|
||||||
|
MovieId = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
history.Data.Add("Indexer", message.Episode.Release.Indexer);
|
history.Data.Add("Indexer", message.Episode.Release.Indexer);
|
||||||
|
@ -172,6 +180,50 @@ namespace NzbDrone.Core.History
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Handle(MovieGrabbedEvent message)
|
||||||
|
{
|
||||||
|
var history = new History
|
||||||
|
{
|
||||||
|
EventType = HistoryEventType.Grabbed,
|
||||||
|
Date = DateTime.UtcNow,
|
||||||
|
Quality = message.Movie.ParsedEpisodeInfo.Quality,
|
||||||
|
SourceTitle = message.Movie.Release.Title,
|
||||||
|
SeriesId = 0,
|
||||||
|
EpisodeId = 0,
|
||||||
|
DownloadId = message.DownloadId,
|
||||||
|
MovieId = message.Movie.Movie.Id
|
||||||
|
};
|
||||||
|
|
||||||
|
history.Data.Add("Indexer", message.Movie.Release.Indexer);
|
||||||
|
history.Data.Add("NzbInfoUrl", message.Movie.Release.InfoUrl);
|
||||||
|
history.Data.Add("ReleaseGroup", message.Movie.ParsedEpisodeInfo.ReleaseGroup);
|
||||||
|
history.Data.Add("Age", message.Movie.Release.Age.ToString());
|
||||||
|
history.Data.Add("AgeHours", message.Movie.Release.AgeHours.ToString());
|
||||||
|
history.Data.Add("AgeMinutes", message.Movie.Release.AgeMinutes.ToString());
|
||||||
|
history.Data.Add("PublishedDate", message.Movie.Release.PublishDate.ToString("s") + "Z");
|
||||||
|
history.Data.Add("DownloadClient", message.DownloadClient);
|
||||||
|
history.Data.Add("Size", message.Movie.Release.Size.ToString());
|
||||||
|
history.Data.Add("DownloadUrl", message.Movie.Release.DownloadUrl);
|
||||||
|
history.Data.Add("Guid", message.Movie.Release.Guid);
|
||||||
|
history.Data.Add("TvdbId", message.Movie.Release.TvdbId.ToString());
|
||||||
|
history.Data.Add("TvRageId", message.Movie.Release.TvRageId.ToString());
|
||||||
|
history.Data.Add("Protocol", ((int)message.Movie.Release.DownloadProtocol).ToString());
|
||||||
|
|
||||||
|
if (!message.Movie.ParsedEpisodeInfo.ReleaseHash.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
history.Data.Add("ReleaseHash", message.Movie.ParsedEpisodeInfo.ReleaseHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
var torrentRelease = message.Movie.Release as TorrentInfo;
|
||||||
|
|
||||||
|
if (torrentRelease != null)
|
||||||
|
{
|
||||||
|
history.Data.Add("TorrentInfoHash", torrentRelease.InfoHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
_historyRepository.Insert(history);
|
||||||
|
}
|
||||||
|
|
||||||
public void Handle(EpisodeImportedEvent message)
|
public void Handle(EpisodeImportedEvent message)
|
||||||
{
|
{
|
||||||
if (!message.NewDownload)
|
if (!message.NewDownload)
|
||||||
|
@ -196,7 +248,10 @@ namespace NzbDrone.Core.History
|
||||||
SourceTitle = message.ImportedEpisode.SceneName ?? Path.GetFileNameWithoutExtension(message.EpisodeInfo.Path),
|
SourceTitle = message.ImportedEpisode.SceneName ?? Path.GetFileNameWithoutExtension(message.EpisodeInfo.Path),
|
||||||
SeriesId = message.ImportedEpisode.SeriesId,
|
SeriesId = message.ImportedEpisode.SeriesId,
|
||||||
EpisodeId = episode.Id,
|
EpisodeId = episode.Id,
|
||||||
DownloadId = downloadId
|
DownloadId = downloadId,
|
||||||
|
MovieId = 0,
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//Won't have a value since we publish this event before saving to DB.
|
//Won't have a value since we publish this event before saving to DB.
|
||||||
|
@ -249,6 +304,7 @@ namespace NzbDrone.Core.History
|
||||||
SourceTitle = message.EpisodeFile.Path,
|
SourceTitle = message.EpisodeFile.Path,
|
||||||
SeriesId = message.EpisodeFile.SeriesId,
|
SeriesId = message.EpisodeFile.SeriesId,
|
||||||
EpisodeId = episode.Id,
|
EpisodeId = episode.Id,
|
||||||
|
MovieId = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
history.Data.Add("Reason", message.Reason.ToString());
|
history.Data.Add("Reason", message.Reason.ToString());
|
||||||
|
|
|
@ -457,6 +457,7 @@
|
||||||
<Compile Include="Download\Clients\Vuze\Vuze.cs" />
|
<Compile Include="Download\Clients\Vuze\Vuze.cs" />
|
||||||
<Compile Include="Download\CompletedDownloadService.cs" />
|
<Compile Include="Download\CompletedDownloadService.cs" />
|
||||||
<Compile Include="Download\DownloadEventHub.cs" />
|
<Compile Include="Download\DownloadEventHub.cs" />
|
||||||
|
<Compile Include="Download\MovieGrabbedEvent.cs" />
|
||||||
<Compile Include="Download\TrackedDownloads\DownloadMonitoringService.cs" />
|
<Compile Include="Download\TrackedDownloads\DownloadMonitoringService.cs" />
|
||||||
<Compile Include="Download\TrackedDownloads\TrackedDownload.cs" />
|
<Compile Include="Download\TrackedDownloads\TrackedDownload.cs" />
|
||||||
<Compile Include="Download\TrackedDownloads\TrackedDownloadService.cs" />
|
<Compile Include="Download\TrackedDownloads\TrackedDownloadService.cs" />
|
||||||
|
|
|
@ -13,6 +13,7 @@ namespace NzbDrone.Core.Queue
|
||||||
{
|
{
|
||||||
public Series Series { get; set; }
|
public Series Series { get; set; }
|
||||||
public Episode Episode { get; set; }
|
public Episode Episode { get; set; }
|
||||||
|
public Movie Movie { get; set; }
|
||||||
public QualityModel Quality { get; set; }
|
public QualityModel Quality { get; set; }
|
||||||
public decimal Size { get; set; }
|
public decimal Size { get; set; }
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
|
@ -24,6 +25,7 @@ namespace NzbDrone.Core.Queue
|
||||||
public List<TrackedDownloadStatusMessage> StatusMessages { get; set; }
|
public List<TrackedDownloadStatusMessage> StatusMessages { get; set; }
|
||||||
public string DownloadId { get; set; }
|
public string DownloadId { get; set; }
|
||||||
public RemoteEpisode RemoteEpisode { get; set; }
|
public RemoteEpisode RemoteEpisode { get; set; }
|
||||||
|
public RemoteMovie RemoteMovie { get; set; }
|
||||||
public DownloadProtocol Protocol { get; set; }
|
public DownloadProtocol Protocol { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,12 +51,42 @@ namespace NzbDrone.Core.Queue
|
||||||
yield return MapEpisode(trackedDownload, episode);
|
yield return MapEpisode(trackedDownload, episode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (trackedDownload.RemoteMovie.Movie != null)
|
||||||
{
|
{
|
||||||
// FIXME: Present queue items with unknown series/episodes
|
yield return MapMovie(trackedDownload, trackedDownload.RemoteMovie.Movie);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Queue MapMovie(TrackedDownload trackedDownload, Movie movie)
|
||||||
|
{
|
||||||
|
var queue = new Queue
|
||||||
|
{
|
||||||
|
Id = HashConverter.GetHashInt31(string.Format("trackedDownload-{0}", trackedDownload.DownloadItem.DownloadId)),
|
||||||
|
Series = null,
|
||||||
|
Episode = null,
|
||||||
|
Quality = trackedDownload.RemoteMovie.ParsedEpisodeInfo.Quality,
|
||||||
|
Title = trackedDownload.DownloadItem.Title,
|
||||||
|
Size = trackedDownload.DownloadItem.TotalSize,
|
||||||
|
Sizeleft = trackedDownload.DownloadItem.RemainingSize,
|
||||||
|
Timeleft = trackedDownload.DownloadItem.RemainingTime,
|
||||||
|
Status = trackedDownload.DownloadItem.Status.ToString(),
|
||||||
|
TrackedDownloadStatus = trackedDownload.Status.ToString(),
|
||||||
|
StatusMessages = trackedDownload.StatusMessages.ToList(),
|
||||||
|
RemoteEpisode = trackedDownload.RemoteEpisode,
|
||||||
|
RemoteMovie = trackedDownload.RemoteMovie,
|
||||||
|
DownloadId = trackedDownload.DownloadItem.DownloadId,
|
||||||
|
Protocol = trackedDownload.Protocol,
|
||||||
|
Movie = movie
|
||||||
|
};
|
||||||
|
|
||||||
|
if (queue.Timeleft.HasValue)
|
||||||
|
{
|
||||||
|
queue.EstimatedCompletionTime = DateTime.UtcNow.Add(queue.Timeleft.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
|
|
||||||
private Queue MapEpisode(TrackedDownload trackedDownload, Episode episode)
|
private Queue MapEpisode(TrackedDownload trackedDownload, Episode episode)
|
||||||
{
|
{
|
||||||
var queue = new Queue
|
var queue = new Queue
|
||||||
|
|
|
@ -50,16 +50,20 @@ var Collection = PageableCollection.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
sortMappings : {
|
sortMappings : {
|
||||||
'series' : { sortKey : 'series.sortTitle' }
|
'movie' : { sortKey : 'movie.sortTitle' }
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize : function(options) {
|
initialize : function(options) {
|
||||||
delete this.queryParams.episodeId;
|
delete this.queryParams.episodeId;
|
||||||
|
delete this.queryParams.movieId;
|
||||||
|
|
||||||
if (options) {
|
if (options) {
|
||||||
if (options.episodeId) {
|
if (options.episodeId) {
|
||||||
this.queryParams.episodeId = options.episodeId;
|
this.queryParams.episodeId = options.episodeId;
|
||||||
}
|
}
|
||||||
|
if (options.movieId) {
|
||||||
|
this.queryParams.movieId = options.movieId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ var Marionette = require('marionette');
|
||||||
var Backgrid = require('backgrid');
|
var Backgrid = require('backgrid');
|
||||||
var HistoryCollection = require('./HistoryCollection');
|
var HistoryCollection = require('./HistoryCollection');
|
||||||
var EventTypeCell = require('../../Cells/EventTypeCell');
|
var EventTypeCell = require('../../Cells/EventTypeCell');
|
||||||
var SeriesTitleCell = require('../../Cells/SeriesTitleCell');
|
var MovieTitleCell = require('../../Cells/MovieTitleCell');
|
||||||
var EpisodeNumberCell = require('../../Cells/EpisodeNumberCell');
|
var EpisodeNumberCell = require('../../Cells/EpisodeNumberCell');
|
||||||
var EpisodeTitleCell = require('../../Cells/EpisodeTitleCell');
|
var EpisodeTitleCell = require('../../Cells/EpisodeTitleCell');
|
||||||
var HistoryQualityCell = require('./HistoryQualityCell');
|
var HistoryQualityCell = require('./HistoryQualityCell');
|
||||||
|
@ -29,11 +29,11 @@ module.exports = Marionette.Layout.extend({
|
||||||
cellValue : 'this'
|
cellValue : 'this'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name : 'series',
|
name : 'movies',
|
||||||
label : 'Series',
|
label : 'Movie Title',
|
||||||
cell : SeriesTitleCell
|
cell : MovieTitleCell
|
||||||
},
|
},
|
||||||
{
|
/*{
|
||||||
name : 'episode',
|
name : 'episode',
|
||||||
label : 'Episode',
|
label : 'Episode',
|
||||||
cell : EpisodeNumberCell,
|
cell : EpisodeNumberCell,
|
||||||
|
@ -44,7 +44,7 @@ module.exports = Marionette.Layout.extend({
|
||||||
label : 'Episode Title',
|
label : 'Episode Title',
|
||||||
cell : EpisodeTitleCell,
|
cell : EpisodeTitleCell,
|
||||||
sortable : false
|
sortable : false
|
||||||
},
|
},*/
|
||||||
{
|
{
|
||||||
name : 'this',
|
name : 'this',
|
||||||
label : 'Quality',
|
label : 'Quality',
|
||||||
|
|
|
@ -1,12 +1,20 @@
|
||||||
var Backbone = require('backbone');
|
var Backbone = require('backbone');
|
||||||
var SeriesModel = require('../../Series/SeriesModel');
|
var SeriesModel = require('../../Series/SeriesModel');
|
||||||
var EpisodeModel = require('../../Series/EpisodeModel');
|
var EpisodeModel = require('../../Series/EpisodeModel');
|
||||||
|
var MovieModel = require('../../Movies/MovieModel');
|
||||||
|
|
||||||
module.exports = Backbone.Model.extend({
|
module.exports = Backbone.Model.extend({
|
||||||
parse : function(model) {
|
parse : function(model) {
|
||||||
|
if (model.series) {
|
||||||
model.series = new SeriesModel(model.series);
|
model.series = new SeriesModel(model.series);
|
||||||
model.episode = new EpisodeModel(model.episode);
|
model.episode = new EpisodeModel(model.episode);
|
||||||
model.episode.set('series', model.series);
|
model.episode.set('series', model.series);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (model.movie) {
|
||||||
|
model.movie = new MovieModel(model.movie);
|
||||||
|
}
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
});
|
});
|
|
@ -35,6 +35,14 @@ var QueueCollection = PageableCollection.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
movie : {
|
||||||
|
sortValue : function(model, attr) {
|
||||||
|
var movie = model.get(attr);
|
||||||
|
|
||||||
|
return movie.get('sortTitle');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
episode : {
|
episode : {
|
||||||
sortValue : function(model, attr) {
|
sortValue : function(model, attr) {
|
||||||
var episode = model.get('episode');
|
var episode = model.get('episode');
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
var Marionette = require('marionette');
|
var Marionette = require('marionette');
|
||||||
var Backgrid = require('backgrid');
|
var Backgrid = require('backgrid');
|
||||||
var QueueCollection = require('./QueueCollection');
|
var QueueCollection = require('./QueueCollection');
|
||||||
var SeriesTitleCell = require('../../Cells/SeriesTitleCell');
|
var SeriesTitleCell = require('../../Cells/MovieTitleCell');
|
||||||
var EpisodeNumberCell = require('../../Cells/EpisodeNumberCell');
|
var EpisodeNumberCell = require('../../Cells/EpisodeNumberCell');
|
||||||
var EpisodeTitleCell = require('../../Cells/EpisodeTitleCell');
|
var EpisodeTitleCell = require('../../Cells/EpisodeTitleCell');
|
||||||
var QualityCell = require('../../Cells/QualityCell');
|
var QualityCell = require('../../Cells/QualityCell');
|
||||||
|
@ -28,11 +28,11 @@ module.exports = Marionette.Layout.extend({
|
||||||
cellValue : 'this'
|
cellValue : 'this'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name : 'series',
|
name : 'movie',
|
||||||
label : 'Series',
|
label : 'Movie',
|
||||||
cell : SeriesTitleCell
|
cell : SeriesTitleCell
|
||||||
},
|
},
|
||||||
{
|
/*{
|
||||||
name : 'episode',
|
name : 'episode',
|
||||||
label : 'Episode',
|
label : 'Episode',
|
||||||
cell : EpisodeNumberCell
|
cell : EpisodeNumberCell
|
||||||
|
@ -42,7 +42,7 @@ module.exports = Marionette.Layout.extend({
|
||||||
label : 'Episode Title',
|
label : 'Episode Title',
|
||||||
cell : EpisodeTitleCell,
|
cell : EpisodeTitleCell,
|
||||||
cellValue : 'episode'
|
cellValue : 'episode'
|
||||||
},
|
},*/
|
||||||
{
|
{
|
||||||
name : 'quality',
|
name : 'quality',
|
||||||
label : 'Quality',
|
label : 'Quality',
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
var Backbone = require('backbone');
|
var Backbone = require('backbone');
|
||||||
var SeriesModel = require('../../Series/SeriesModel');
|
var SeriesModel = require('../../Series/SeriesModel');
|
||||||
var EpisodeModel = require('../../Series/EpisodeModel');
|
var EpisodeModel = require('../../Series/EpisodeModel');
|
||||||
|
var MovieModel = require('../../Movies/MovieModel');
|
||||||
|
|
||||||
module.exports = Backbone.Model.extend({
|
module.exports = Backbone.Model.extend({
|
||||||
parse : function(model) {
|
parse : function(model) {
|
||||||
model.series = new SeriesModel(model.series);
|
model.series = new SeriesModel(model.series);
|
||||||
model.episode = new EpisodeModel(model.episode);
|
model.episode = new EpisodeModel(model.episode);
|
||||||
model.episode.set('series', model.series);
|
model.episode.set('series', model.series);
|
||||||
|
model.movie = new MovieModel(model.movie);
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
});
|
});
|
11
src/UI/Cells/MovieTitleCell.js
Normal file
11
src/UI/Cells/MovieTitleCell.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
var TemplatedCell = require('./TemplatedCell');
|
||||||
|
|
||||||
|
module.exports = TemplatedCell.extend({
|
||||||
|
className : 'series-title-cell',
|
||||||
|
template : 'Cells/SeriesTitleTemplate',
|
||||||
|
|
||||||
|
render : function() {
|
||||||
|
this.$el.html(this.model.get("movie").get("title")); //Hack, but somehow handlebar helper does not work.
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
});
|
|
@ -35,7 +35,7 @@
|
||||||
<div id="info" class="movie-info"></div>
|
<div id="info" class="movie-info"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="seasons">
|
<div id="movie-info">
|
||||||
<ul class="nav nav-tabs" id="myTab">
|
<ul class="nav nav-tabs" id="myTab">
|
||||||
<li><a href="#movie-history" class="x-movie-history">History</a></li>
|
<li><a href="#movie-history" class="x-movie-history">History</a></li>
|
||||||
<li><a href="#movie-search" class="x-movie-search">Search</a></li>
|
<li><a href="#movie-search" class="x-movie-search">Search</a></li>
|
||||||
|
|
|
@ -56,7 +56,7 @@ module.exports = Marionette.Layout.extend({
|
||||||
this.model = options.model;
|
this.model = options.model;
|
||||||
|
|
||||||
this.collection = new HistoryCollection({
|
this.collection = new HistoryCollection({
|
||||||
episodeId : this.model.id,
|
movieId : this.model.id,
|
||||||
tableName : 'episodeHistory'
|
tableName : 'episodeHistory'
|
||||||
});
|
});
|
||||||
this.collection.fetch();
|
this.collection.fetch();
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
<p class="text-warning">
|
<p class="text-warning">
|
||||||
No history for this episode.
|
No history for this movie.
|
||||||
</p>
|
</p>
|
|
@ -272,7 +272,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.episode-detail-modal {
|
#movie-info {
|
||||||
|
|
||||||
.episode-info {
|
.episode-info {
|
||||||
margin-bottom : 10px;
|
margin-bottom : 10px;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue