1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-03-23 17:14:46 -04:00

Compare commits

..

1 Commits

Author SHA1 Message Date
Keivan Beigi
a34e69b35b Notification API Cleanup 2016-12-27 23:52:20 -08:00
246 changed files with 411 additions and 7640 deletions

BIN
.DS_Store vendored

Binary file not shown.

1
.gitignore vendored
View File

@@ -130,7 +130,6 @@ output/*
#OS X metadata files
._*
.DS_Store
_start
_temp_*/**/*

View File

@@ -1,9 +0,0 @@
language: csharp
solution: src/NzbDrone.sln
script: # the following commands are just examples, use whatever your build process requires
- ./build.sh
- chmod +x test.sh
# - ./test.sh Linux Unit Takes far too long, maybe even crashes travis :/
install:
- sudo apt-get install nodejs
- sudo apt-get install npm

View File

@@ -19,16 +19,13 @@ gulp.task('less', function() {
paths.src.root + 'Series/series.less',
paths.src.root + 'Activity/activity.less',
paths.src.root + 'AddSeries/addSeries.less',
paths.src.root + 'AddMovies/addMovies.less',
paths.src.root + 'Calendar/calendar.less',
paths.src.root + 'Cells/cells.less',
paths.src.root + 'ManualImport/manualimport.less',
paths.src.root + 'Settings/settings.less',
paths.src.root + 'System/Logs/logs.less',
paths.src.root + 'System/Update/update.less',
paths.src.root + 'System/Info/info.less',
paths.src.root + 'Movies/movies.less',
paths.src.root + 'System/Info/info.less'
];
return gulp.src(src)

View File

@@ -1,20 +1,7 @@
# Radarr [![Build Status](https://travis-ci.org/galli-leo/Radarr.svg?branch=develop)](https://travis-ci.org/galli-leo/Radarr)#
# Sonarr #
This fork of Sonarr aims to turn it into something like Couchpotato.
## Currently working:
* Adding new movies (Note: Movies are currently added as one series with one season and one episode. This will change in the future)
* Manually searching for releases of movies.
* Automatically searching for releases.
* Rarbg.to indexer (Other indexers are coming, I just need to find the right categories)
* Everything that has nothing to do with series from Sonarr should be working as well.
## Planned Features:
* Scanning PreDB to know when a new release is available.
* Fixing the other Indexers.
* Fixing how movies are stored and displayed.
* Importing of Sonarr config.
* New TorrentPotato Indexer.
Sonarr is a PVR for Usenet and BitTorrent users. It can monitor multiple RSS feeds for new episodes of your favorite shows and will grab, sort and rename them. It can also be configured to automatically upgrade the quality of files already downloaded when a better quality format becomes available.
## Major Features Include: ##
@@ -30,8 +17,6 @@ This fork of Sonarr aims to turn it into something like Couchpotato.
* Full support for specials and multi-episode releases
* And a beautiful UI
## Download
The latest precompiled binary versions can be found here: https://github.com/galli-leo/Radarr/releases.
## Configuring Development Environment: ##

BIN
src/.DS_Store vendored

Binary file not shown.

View File

@@ -3,7 +3,6 @@ using Nancy;
using NzbDrone.Api.Episodes;
using NzbDrone.Api.Extensions;
using NzbDrone.Api.Series;
using NzbDrone.Api.Movie;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
@@ -35,18 +34,12 @@ namespace NzbDrone.Api.History
resource.Series = model.Series.ToResource();
resource.Episode = model.Episode.ToResource();
resource.Movie = model.Movie.ToResource();
if (model.Series != null)
{
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;
}
@@ -54,8 +47,6 @@ namespace NzbDrone.Api.History
{
var episodeId = Request.Query.EpisodeId;
var movieId = Request.Query.MovieId;
var pagingSpec = pagingResource.MapToPagingSpec<HistoryResource, Core.History.History>("date", SortDirection.Descending);
if (pagingResource.FilterKey == "eventType")
@@ -70,12 +61,6 @@ namespace NzbDrone.Api.History
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);
}

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using NzbDrone.Api.Episodes;
using NzbDrone.Api.REST;
using NzbDrone.Api.Series;
using NzbDrone.Api.Movie;
using NzbDrone.Core.History;
using NzbDrone.Core.Qualities;
@@ -13,7 +12,6 @@ namespace NzbDrone.Api.History
public class HistoryResource : RestResource
{
public int EpisodeId { get; set; }
public int MovieId { get; set; }
public int SeriesId { get; set; }
public string SourceTitle { get; set; }
public QualityModel Quality { get; set; }
@@ -24,7 +22,7 @@ namespace NzbDrone.Api.History
public HistoryEventType EventType { get; set; }
public Dictionary<string, string> Data { get; set; }
public MovieResource Movie { get; set; }
public EpisodeResource Episode { get; set; }
public SeriesResource Series { get; set; }
}
@@ -41,7 +39,6 @@ namespace NzbDrone.Api.History
EpisodeId = model.EpisodeId,
SeriesId = model.SeriesId,
MovieId = model.MovieId,
SourceTitle = model.SourceTitle,
Quality = model.Quality,
//QualityCutoffNotMet

View File

@@ -26,7 +26,6 @@ namespace NzbDrone.Api.Indexers
private readonly Logger _logger;
private readonly ICached<RemoteEpisode> _remoteEpisodeCache;
private readonly ICached<RemoteMovie> _remoteMovieCache;
public ReleaseModule(IFetchAndParseRss rssFetcherAndParser,
ISearchForNzb nzbSearchService,
@@ -50,7 +49,6 @@ namespace NzbDrone.Api.Indexers
PostValidator.RuleFor(s => s.Guid).NotEmpty();
_remoteEpisodeCache = cacheManager.GetCache<RemoteEpisode>(GetType(), "remoteEpisodes");
_remoteMovieCache = cacheManager.GetCache<RemoteMovie>(GetType(), "remoteMovies");
}
private Response DownloadRelease(ReleaseResource release)
@@ -61,26 +59,7 @@ namespace NzbDrone.Api.Indexers
{
_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();
}
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();
return new NotFoundResponse();
}
try
@@ -103,11 +82,6 @@ namespace NzbDrone.Api.Indexers
return GetEpisodeReleases(Request.Query.episodeId);
}
if (Request.Query.movieId != null)
{
return GetMovieReleases(Request.Query.movieId);
}
return GetRss();
}
@@ -128,27 +102,6 @@ namespace NzbDrone.Api.Indexers
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()
{
var reports = _rssFetcherAndParser.Fetch();
@@ -160,15 +113,7 @@ namespace NzbDrone.Api.Indexers
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);
}
}

View File

@@ -86,11 +86,6 @@ namespace NzbDrone.Api.Indexers
var parsedEpisodeInfo = model.RemoteEpisode.ParsedEpisodeInfo;
var remoteEpisode = model.RemoteEpisode;
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?)
return new ReleaseResource
@@ -124,7 +119,7 @@ namespace NzbDrone.Api.Indexers
CommentUrl = releaseInfo.CommentUrl,
DownloadUrl = releaseInfo.DownloadUrl,
InfoUrl = releaseInfo.InfoUrl,
DownloadAllowed = downloadAllowed,
DownloadAllowed = remoteEpisode.DownloadAllowed,
//ReleaseWeight
MagnetUrl = torrentInfo.MagnetUrl,

View File

@@ -231,11 +231,8 @@
<Compile Include="Series\SeasonResource.cs" />
<Compile Include="SeasonPass\SeasonPassModule.cs" />
<Compile Include="Series\SeriesEditorModule.cs" />
<Compile Include="Series\MovieLookupModule.cs" />
<Compile Include="Series\SeriesLookupModule.cs" />
<Compile Include="Series\MovieModule.cs" />
<Compile Include="Series\SeriesModule.cs" />
<Compile Include="Series\MovieResource.cs" />
<Compile Include="Series\SeriesResource.cs" />
<Compile Include="Series\SeasonStatisticsResource.cs" />
<Compile Include="System\Backup\BackupModule.cs" />

View File

@@ -4,7 +4,6 @@ using NzbDrone.Api.REST;
using NzbDrone.Core.Qualities;
using NzbDrone.Api.Series;
using NzbDrone.Api.Episodes;
using NzbDrone.Api.Movie;
using NzbDrone.Core.Download.TrackedDownloads;
using NzbDrone.Core.Indexers;
using System.Linq;
@@ -15,7 +14,6 @@ namespace NzbDrone.Api.Queue
{
public SeriesResource Series { get; set; }
public EpisodeResource Episode { get; set; }
public MovieResource Movie { get; set; }
public QualityModel Quality { get; set; }
public decimal Size { get; set; }
public string Title { get; set; }
@@ -51,8 +49,7 @@ namespace NzbDrone.Api.Queue
TrackedDownloadStatus = model.TrackedDownloadStatus,
StatusMessages = model.StatusMessages,
DownloadId = model.DownloadId,
Protocol = model.Protocol,
Movie = model.Movie.ToResource()
Protocol = model.Protocol
};
}

View File

@@ -1,44 +0,0 @@
using System.Collections.Generic;
using Nancy;
using NzbDrone.Api.Extensions;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MetadataSource;
using System.Linq;
namespace NzbDrone.Api.Movie
{
public class MovieLookupModule : NzbDroneRestModule<MovieResource>
{
private readonly ISearchForNewMovie _searchProxy;
public MovieLookupModule(ISearchForNewMovie searchProxy)
: base("/movies/lookup")
{
_searchProxy = searchProxy;
Get["/"] = x => Search();
}
private Response Search()
{
var imdbResults = _searchProxy.SearchForNewMovie((string)Request.Query.term);
return MapToResource(imdbResults).AsResponse();
}
private static IEnumerable<MovieResource> MapToResource(IEnumerable<Core.Tv.Movie> movies)
{
foreach (var currentSeries in movies)
{
var resource = currentSeries.ToResource();
var poster = currentSeries.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster);
if (poster != null)
{
resource.RemotePoster = poster.Url;
}
yield return resource;
}
}
}
}

View File

@@ -1,225 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FluentValidation;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.MovieStats;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Tv.Events;
using NzbDrone.Core.Validation.Paths;
using NzbDrone.Core.DataAugmentation.Scene;
using NzbDrone.Core.Validation;
using NzbDrone.SignalR;
namespace NzbDrone.Api.Movie
{
public class MovieModule : NzbDroneRestModuleWithSignalR<MovieResource, Core.Tv.Movie>,
IHandle<EpisodeImportedEvent>,
IHandle<EpisodeFileDeletedEvent>,
IHandle<MovieUpdatedEvent>,
IHandle<MovieEditedEvent>,
IHandle<MovieDeletedEvent>,
IHandle<MovieRenamedEvent>,
IHandle<MediaCoversUpdatedEvent>
{
private readonly IMovieService _moviesService;
private readonly IMovieStatisticsService _moviesStatisticsService;
private readonly IMapCoversToLocal _coverMapper;
public MovieModule(IBroadcastSignalRMessage signalRBroadcaster,
IMovieService moviesService,
IMovieStatisticsService moviesStatisticsService,
ISceneMappingService sceneMappingService,
IMapCoversToLocal coverMapper,
RootFolderValidator rootFolderValidator,
MoviePathValidator moviesPathValidator,
MovieExistsValidator moviesExistsValidator,
DroneFactoryValidator droneFactoryValidator,
MovieAncestorValidator moviesAncestorValidator,
ProfileExistsValidator profileExistsValidator
)
: base(signalRBroadcaster)
{
_moviesService = moviesService;
_moviesStatisticsService = moviesStatisticsService;
_coverMapper = coverMapper;
GetResourceAll = AllMovie;
GetResourceById = GetMovie;
CreateResource = AddMovie;
UpdateResource = UpdateMovie;
DeleteResource = DeleteMovie;
Validation.RuleBuilderExtensions.ValidId(SharedValidator.RuleFor(s => s.ProfileId));
SharedValidator.RuleFor(s => s.Path)
.Cascade(CascadeMode.StopOnFirstFailure)
.IsValidPath()
.SetValidator(rootFolderValidator)
.SetValidator(moviesPathValidator)
.SetValidator(droneFactoryValidator)
.SetValidator(moviesAncestorValidator)
.When(s => !s.Path.IsNullOrWhiteSpace());
SharedValidator.RuleFor(s => s.ProfileId).SetValidator(profileExistsValidator);
PostValidator.RuleFor(s => s.Path).IsValidPath().When(s => s.RootFolderPath.IsNullOrWhiteSpace());
PostValidator.RuleFor(s => s.RootFolderPath).IsValidPath().When(s => s.Path.IsNullOrWhiteSpace());
PostValidator.RuleFor(s => s.Title).NotEmpty();
PostValidator.RuleFor(s => s.ImdbId).NotNull().NotEmpty().SetValidator(moviesExistsValidator);
PutValidator.RuleFor(s => s.Path).IsValidPath();
}
private MovieResource GetMovie(int id)
{
var movies = _moviesService.GetMovie(id);
return MapToResource(movies);
}
private MovieResource MapToResource(Core.Tv.Movie movies)
{
if (movies == null) return null;
var resource = movies.ToResource();
MapCoversToLocal(resource);
FetchAndLinkMovieStatistics(resource);
PopulateAlternateTitles(resource);
return resource;
}
private List<MovieResource> AllMovie()
{
var moviesStats = _moviesStatisticsService.MovieStatistics();
var moviesResources = _moviesService.GetAllMovies().ToResource();
MapCoversToLocal(moviesResources.ToArray());
LinkMovieStatistics(moviesResources, moviesStats);
PopulateAlternateTitles(moviesResources);
return moviesResources;
}
private int AddMovie(MovieResource moviesResource)
{
var model = moviesResource.ToModel();
return _moviesService.AddMovie(model).Id;
}
private void UpdateMovie(MovieResource moviesResource)
{
var model = moviesResource.ToModel(_moviesService.GetMovie(moviesResource.Id));
_moviesService.UpdateMovie(model);
BroadcastResourceChange(ModelAction.Updated, moviesResource);
}
private void DeleteMovie(int id)
{
var deleteFiles = false;
var deleteFilesQuery = Request.Query.deleteFiles;
if (deleteFilesQuery.HasValue)
{
deleteFiles = Convert.ToBoolean(deleteFilesQuery.Value);
}
_moviesService.DeleteMovie(id, deleteFiles);
}
private void MapCoversToLocal(params MovieResource[] movies)
{
foreach (var moviesResource in movies)
{
_coverMapper.ConvertToLocalUrls(moviesResource.Id, moviesResource.Images);
}
}
private void FetchAndLinkMovieStatistics(MovieResource resource)
{
LinkMovieStatistics(resource, _moviesStatisticsService.MovieStatistics(resource.Id));
}
private void LinkMovieStatistics(List<MovieResource> resources, List<MovieStatistics> moviesStatistics)
{
var dictMovieStats = moviesStatistics.ToDictionary(v => v.MovieId);
foreach (var movies in resources)
{
var stats = dictMovieStats.GetValueOrDefault(movies.Id);
if (stats == null) continue;
LinkMovieStatistics(movies, stats);
}
}
private void LinkMovieStatistics(MovieResource resource, MovieStatistics moviesStatistics)
{
resource.SizeOnDisk = moviesStatistics.SizeOnDisk;
}
private void PopulateAlternateTitles(List<MovieResource> resources)
{
foreach (var resource in resources)
{
PopulateAlternateTitles(resource);
}
}
private void PopulateAlternateTitles(MovieResource resource)
{
//var mappings = null;//_sceneMappingService.FindByTvdbId(resource.TvdbId);
//if (mappings == null) return;
//resource.AlternateTitles = mappings.Select(v => new AlternateTitleResource { Title = v.Title, SeasonNumber = v.SeasonNumber, SceneSeasonNumber = v.SceneSeasonNumber }).ToList();
}
public void Handle(EpisodeImportedEvent message)
{
//BroadcastResourceChange(ModelAction.Updated, message.ImportedEpisode.MovieId);
}
public void Handle(EpisodeFileDeletedEvent message)
{
if (message.Reason == DeleteMediaFileReason.Upgrade) return;
//BroadcastResourceChange(ModelAction.Updated, message.EpisodeFile.MovieId);
}
public void Handle(MovieUpdatedEvent message)
{
BroadcastResourceChange(ModelAction.Updated, message.Movie.Id);
}
public void Handle(MovieEditedEvent message)
{
BroadcastResourceChange(ModelAction.Updated, message.Movie.Id);
}
public void Handle(MovieDeletedEvent message)
{
BroadcastResourceChange(ModelAction.Deleted, message.Movie.ToResource());
}
public void Handle(MovieRenamedEvent message)
{
BroadcastResourceChange(ModelAction.Updated, message.Movie.Id);
}
public void Handle(MediaCoversUpdatedEvent message)
{
//BroadcastResourceChange(ModelAction.Updated, message.Movie.Id);
}
}
}

View File

@@ -1,183 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Api.REST;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.Tv;
using NzbDrone.Api.Series;
namespace NzbDrone.Api.Movie
{
public class MovieResource : RestResource
{
public MovieResource()
{
Monitored = true;
}
//Todo: Sorters should be done completely on the client
//Todo: Is there an easy way to keep IgnoreArticlesWhenSorting in sync between, Series, History, Missing?
//Todo: We should get the entire Profile instead of ID and Name separately
//View Only
public string Title { get; set; }
public List<AlternateTitleResource> AlternateTitles { get; set; }
public string SortTitle { get; set; }
public long? SizeOnDisk { get; set; }
public MovieStatusType Status { get; set; }
public string Overview { get; set; }
public DateTime? InCinemas { get; set; }
public List<MediaCover> Images { get; set; }
public string RemotePoster { get; set; }
public int Year { get; set; }
//View & Edit
public string Path { get; set; }
public int ProfileId { get; set; }
//Editing Only
public bool Monitored { get; set; }
public int Runtime { get; set; }
public DateTime? LastInfoSync { get; set; }
public string CleanTitle { get; set; }
public string ImdbId { get; set; }
public string TitleSlug { get; set; }
public string RootFolderPath { get; set; }
public string Certification { get; set; }
public List<string> Genres { get; set; }
public HashSet<int> Tags { get; set; }
public DateTime Added { get; set; }
public AddMovieOptions AddOptions { get; set; }
public Ratings Ratings { get; set; }
//TODO: Add series statistics as a property of the series (instead of individual properties)
//Used to support legacy consumers
public int QualityProfileId
{
get
{
return ProfileId;
}
set
{
if (value > 0 && ProfileId == 0)
{
ProfileId = value;
}
}
}
}
public static class MovieResourceMapper
{
public static MovieResource ToResource(this Core.Tv.Movie model)
{
if (model == null) return null;
return new MovieResource
{
Id = model.Id,
Title = model.Title,
//AlternateTitles
SortTitle = model.SortTitle,
InCinemas = model.InCinemas,
//TotalEpisodeCount
//EpisodeCount
//EpisodeFileCount
//SizeOnDisk
Status = model.Status,
Overview = model.Overview,
//NextAiring
//PreviousAiring
Images = model.Images,
Year = model.Year,
Path = model.Path,
ProfileId = model.ProfileId,
Monitored = model.Monitored,
Runtime = model.Runtime,
LastInfoSync = model.LastInfoSync,
CleanTitle = model.CleanTitle,
ImdbId = model.ImdbId,
TitleSlug = model.TitleSlug,
RootFolderPath = model.RootFolderPath,
Certification = model.Certification,
Genres = model.Genres,
Tags = model.Tags,
Added = model.Added,
AddOptions = model.AddOptions,
Ratings = model.Ratings
};
}
public static Core.Tv.Movie ToModel(this MovieResource resource)
{
if (resource == null) return null;
return new Core.Tv.Movie
{
Id = resource.Id,
Title = resource.Title,
//AlternateTitles
SortTitle = resource.SortTitle,
InCinemas = resource.InCinemas,
//TotalEpisodeCount
//EpisodeCount
//EpisodeFileCount
//SizeOnDisk
Overview = resource.Overview,
//NextAiring
//PreviousAiring
Images = resource.Images,
Year = resource.Year,
Path = resource.Path,
ProfileId = resource.ProfileId,
Monitored = resource.Monitored,
Runtime = resource.Runtime,
LastInfoSync = resource.LastInfoSync,
CleanTitle = resource.CleanTitle,
ImdbId = resource.ImdbId,
TitleSlug = resource.TitleSlug,
RootFolderPath = resource.RootFolderPath,
Certification = resource.Certification,
Genres = resource.Genres,
Tags = resource.Tags,
Added = resource.Added,
AddOptions = resource.AddOptions,
Ratings = resource.Ratings
};
}
public static Core.Tv.Movie ToModel(this MovieResource resource, Core.Tv.Movie movie)
{
movie.ImdbId = resource.ImdbId;
movie.Path = resource.Path;
movie.ProfileId = resource.ProfileId;
movie.Monitored = resource.Monitored;
movie.RootFolderPath = resource.RootFolderPath;
movie.Tags = resource.Tags;
movie.AddOptions = resource.AddOptions;
return movie;
}
public static List<MovieResource> ToResource(this IEnumerable<Core.Tv.Movie> movies)
{
return movies.Select(ToResource).ToList();
}
}
}

View File

@@ -34,7 +34,7 @@ namespace NzbDrone.Common.EnvironmentInfo
}
else
{
AppDataFolder = Path.Combine(Environment.GetFolderPath(DATA_SPECIAL_FOLDER, Environment.SpecialFolderOption.None), "Radarr");
AppDataFolder = Path.Combine(Environment.GetFolderPath(DATA_SPECIAL_FOLDER, Environment.SpecialFolderOption.None), "NzbDrone");
}
StartUpFolder = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;

View File

@@ -178,9 +178,8 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
public void should_return_an_empty_list_when_none_are_appproved()
{
var decisions = new List<DownloadDecision>();
RemoteEpisode ep = null;
decisions.Add(new DownloadDecision(ep, new Rejection("Failure!")));
decisions.Add(new DownloadDecision(ep, new Rejection("Failure!")));
decisions.Add(new DownloadDecision(null, new Rejection("Failure!")));
decisions.Add(new DownloadDecision(null, new Rejection("Failure!")));
Subject.GetQualifiedReports(decisions).Should().BeEmpty();
}

View File

@@ -0,0 +1,120 @@
using System;
using FluentAssertions;
using FluentValidation.Results;
using NUnit.Framework;
using NzbDrone.Core.Notifications;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Validation;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.NotificationTests
{
[TestFixture]
public class NotificationBaseFixture : TestBase
{
class TestSetting : IProviderConfig
{
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult();
}
}
class TestNotificationWithOnDownload : NotificationBase<TestSetting>
{
public override string Name => "TestNotification";
public override string Link => "";
public override ValidationResult Test()
{
throw new NotImplementedException();
}
public override void OnDownload(DownloadMessage downloadMessage)
{
TestLogger.Info("OnDownload was called");
}
}
class TestNotificationWithAllEvents : NotificationBase<TestSetting>
{
public override string Name => "TestNotification";
public override string Link => "";
public override ValidationResult Test()
{
throw new NotImplementedException();
}
public override void OnGrab(GrabMessage grabMessage)
{
TestLogger.Info("OnGrab was called");
}
public override void OnDownload(DownloadMessage message)
{
TestLogger.Info("OnDownload was called");
}
public override void OnRename(Series series)
{
TestLogger.Info("OnRename was called");
}
}
class TestNotificationWithNoEvents : NotificationBase<TestSetting>
{
public override string Name => "TestNotification";
public override string Link => "";
public override ValidationResult Test()
{
throw new NotImplementedException();
}
}
[Test]
public void should_support_OnUpgrade_should_link_to_OnDownload()
{
var notification = new TestNotificationWithOnDownload();
notification.SupportsOnDownload.Should().BeTrue();
notification.SupportsOnUpgrade.Should().BeTrue();
notification.SupportsOnGrab.Should().BeFalse();
notification.SupportsOnRename.Should().BeFalse();
}
[Test]
public void should_support_all_if_implemented()
{
var notification = new TestNotificationWithAllEvents();
notification.SupportsOnGrab.Should().BeTrue();
notification.SupportsOnDownload.Should().BeTrue();
notification.SupportsOnUpgrade.Should().BeTrue();
notification.SupportsOnRename.Should().BeTrue();
}
[Test]
public void should_support_none_if_none_are_implemented()
{
var notification = new TestNotificationWithNoEvents();
notification.SupportsOnGrab.Should().BeFalse();
notification.SupportsOnDownload.Should().BeFalse();
notification.SupportsOnUpgrade.Should().BeFalse();
notification.SupportsOnRename.Should().BeFalse();
}
}
}

View File

@@ -288,6 +288,7 @@
<Compile Include="MetadataSource\SkyHook\SkyHookProxySearchFixture.cs" />
<Compile Include="MetadataSource\SearchSeriesComparerFixture.cs" />
<Compile Include="MetadataSource\SkyHook\SkyHookProxyFixture.cs" />
<Compile Include="NotificationTests\NotificationBaseFixture.cs" />
<Compile Include="NotificationTests\SynologyIndexerFixture.cs" />
<Compile Include="OrganizerTests\FileNameBuilderTests\CleanTitleFixture.cs" />
<Compile Include="OrganizerTests\FileNameBuilderTests\EpisodeTitleCollapseFixture.cs" />

View File

@@ -41,32 +41,6 @@ namespace NzbDrone.Core.Datastore.Migration
.WithColumn("FirstAired").AsDateTime().Nullable()
.WithColumn("NextAiring").AsDateTime().Nullable();
Create.TableForModel("Movies")
.WithColumn("ImdbId").AsString().Unique()
.WithColumn("Title").AsString()
.WithColumn("TitleSlug").AsString().Unique()
.WithColumn("SortTitle").AsString().Nullable()
.WithColumn("CleanTitle").AsString()
.WithColumn("Status").AsInt32()
.WithColumn("Overview").AsString().Nullable()
.WithColumn("Images").AsString()
.WithColumn("Path").AsString()
.WithColumn("Monitored").AsBoolean()
.WithColumn("ProfileId").AsInt32()
.WithColumn("LastInfoSync").AsDateTime().Nullable()
.WithColumn("LastDiskSync").AsDateTime().Nullable()
.WithColumn("Runtime").AsInt32()
.WithColumn("InCinemas").AsDateTime().Nullable()
.WithColumn("Year").AsInt32().Nullable()
.WithColumn("Added").AsDateTime().Nullable()
.WithColumn("Actors").AsString().Nullable()
.WithColumn("Ratings").AsString().Nullable()
.WithColumn("Genres").AsString().Nullable()
.WithColumn("Tags").AsString().Nullable()
.WithColumn("Certification").AsString().Nullable()
.WithColumn("AddOptions").AsString().Nullable();
Create.TableForModel("Seasons")
.WithColumn("SeriesId").AsInt32()
.WithColumn("SeasonNumber").AsInt32()
@@ -105,8 +79,7 @@ namespace NzbDrone.Core.Datastore.Migration
.WithColumn("Quality").AsString()
.WithColumn("Indexer").AsString()
.WithColumn("NzbInfoUrl").AsString().Nullable()
.WithColumn("ReleaseGroup").AsString().Nullable()
.WithColumn("MovieId").AsInt32().WithDefaultValue(0);
.WithColumn("ReleaseGroup").AsString().Nullable();
Create.TableForModel("Notifications")
.WithColumn("Name").AsString()

View File

@@ -21,12 +21,11 @@ namespace NzbDrone.Core.Datastore.Migration
//Add HeldReleases
Create.TableForModel("PendingReleases")
.WithColumn("SeriesId").AsInt32().WithDefaultValue(0)
.WithColumn("SeriesId").AsInt32()
.WithColumn("Title").AsString()
.WithColumn("Added").AsDateTime()
.WithColumn("ParsedEpisodeInfo").AsString()
.WithColumn("Release").AsString()
.WithColumn("MovieId").AsInt32().WithDefaultValue(0);
.WithColumn("Release").AsString();
}
}
}

View File

@@ -76,11 +76,6 @@ namespace NzbDrone.Core.Datastore
.Relationship()
.HasOne(s => s.Profile, s => s.ProfileId);
Mapper.Entity<Movie>().RegisterModel("Movies")
.Ignore(s => s.RootFolderPath)
.Relationship()
.HasOne(s => s.Profile, s => s.ProfileId);
Mapper.Entity<EpisodeFile>().RegisterModel("EpisodeFiles")
.Ignore(f => f.Path)
.Relationships.AutoMapICollectionOrComplexProperties()

View File

@@ -7,10 +7,6 @@ namespace NzbDrone.Core.DecisionEngine
public class DownloadDecision
{
public RemoteEpisode RemoteEpisode { get; private set; }
public RemoteMovie RemoteMovie { get; private set; }
public bool IsForMovie = false;
public IEnumerable<Rejection> Rejections { get; private set; }
public bool Approved => !Rejections.Any();
@@ -34,23 +30,6 @@ namespace NzbDrone.Core.DecisionEngine
public DownloadDecision(RemoteEpisode episode, params Rejection[] rejections)
{
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();
}

View File

@@ -37,83 +37,9 @@ namespace NzbDrone.Core.DecisionEngine
public List<DownloadDecision> GetSearchDecision(List<ReleaseInfo> reports, SearchCriteriaBase searchCriteriaBase)
{
if (searchCriteriaBase.Movie != null)
{
return GetMovieDecisions(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)
{
if (reports.Any())
@@ -154,9 +80,7 @@ namespace NzbDrone.Core.DecisionEngine
if (remoteEpisode.Series == null)
{
//remoteEpisode.DownloadAllowed = true; //Fuck you :)
//decision = GetDecisionForReport(remoteEpisode, searchCriteria);
decision = new DownloadDecision(remoteEpisode, new Rejection("Unknown release. Series not Found."));
decision = new DownloadDecision(remoteEpisode, new Rejection("Unknown Series"));
}
else if (remoteEpisode.Episodes.Empty())
{
@@ -219,9 +143,8 @@ namespace NzbDrone.Core.DecisionEngine
{
e.Data.Add("report", remoteEpisode.Release.ToJson());
e.Data.Add("parsed", remoteEpisode.ParsedEpisodeInfo.ToJson());
_logger.Error(e, "Couldn't evaluate decision on " + remoteEpisode.Release.Title + ", with spec: " + spec.GetType().Name);
//return new Rejection(string.Format("{0}: {1}", spec.GetType().Name, e.Message));//TODO UPDATE SPECS!
//return null;
_logger.Error(e, "Couldn't evaluate decision on " + remoteEpisode.Release.Title);
return new Rejection(string.Format("{0}: {1}", spec.GetType().Name, e.Message));
}
return null;

View File

@@ -7,7 +7,6 @@ namespace NzbDrone.Core.DecisionEngine
public interface IPrioritizeDownloadDecision
{
List<DownloadDecision> PrioritizeDecisions(List<DownloadDecision> decisions);
List<DownloadDecision> PrioritizeDecisionsForMovies(List<DownloadDecision> decisions);
}
public class DownloadDecisionPriorizationService : IPrioritizeDownloadDecision
@@ -30,17 +29,5 @@ namespace NzbDrone.Core.DecisionEngine
.Union(decisions.Where(c => c.RemoteEpisode.Series == null))
.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();
}
}
}

View File

@@ -30,7 +30,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
if (subject.Episodes.Any(e => !e.AirDateUtc.HasValue || e.AirDateUtc.Value.After(DateTime.UtcNow)))
{
_logger.Debug("Full season release {0} rejected. All episodes haven't aired yet.", subject.Release.Title);
//return Decision.Reject("Full season release rejected. All episodes haven't aired yet.");
return Decision.Reject("Full season release rejected. All episodes haven't aired yet.");
}
}

View File

@@ -28,8 +28,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.Search
if (singleEpisodeSpec.SeasonNumber != remoteEpisode.ParsedEpisodeInfo.SeasonNumber)
{
_logger.Debug("Season number does not match searched season number, skipping.");
//return Decision.Reject("Wrong season");
//Unnecessary for Movies
return Decision.Reject("Wrong season");
}
return Decision.Accept();

View File

@@ -29,19 +29,19 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.Search
if (singleEpisodeSpec.SeasonNumber != remoteEpisode.ParsedEpisodeInfo.SeasonNumber)
{
_logger.Debug("Season number does not match searched season number, skipping.");
//return Decision.Reject("Wrong season");
return Decision.Reject("Wrong season");
}
if (!remoteEpisode.ParsedEpisodeInfo.EpisodeNumbers.Any())
{
_logger.Debug("Full season result during single episode search, skipping.");
//return Decision.Reject("Full season pack");
return Decision.Reject("Full season pack");
}
if (!remoteEpisode.ParsedEpisodeInfo.EpisodeNumbers.Contains(singleEpisodeSpec.EpisodeNumber))
{
_logger.Debug("Episode number does not match searched episode number, skipping.");
//return Decision.Reject("Wrong episode");
return Decision.Reject("Wrong episode");
}
return Decision.Accept();

View File

@@ -58,32 +58,6 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic
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 override IEnumerable<DownloadClientItem> GetItems()

View File

@@ -71,46 +71,6 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
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 IEnumerable<DownloadClientItem> GetItems()

View File

@@ -28,7 +28,6 @@ namespace NzbDrone.Core.Download
private readonly IHistoryService _historyService;
private readonly IDownloadedEpisodesImportService _downloadedEpisodesImportService;
private readonly IParsingService _parsingService;
private readonly IMovieService _movieService;
private readonly Logger _logger;
private readonly ISeriesService _seriesService;
@@ -38,7 +37,6 @@ namespace NzbDrone.Core.Download
IDownloadedEpisodesImportService downloadedEpisodesImportService,
IParsingService parsingService,
ISeriesService seriesService,
IMovieService movieService,
Logger logger)
{
_configService = configService;
@@ -46,7 +44,6 @@ namespace NzbDrone.Core.Download
_historyService = historyService;
_downloadedEpisodesImportService = downloadedEpisodesImportService;
_parsingService = parsingService;
_movieService = movieService;
_logger = logger;
_seriesService = seriesService;
}
@@ -91,31 +88,19 @@ namespace NzbDrone.Core.Download
return;
}
var series = _parsingService.GetSeries(trackedDownload.DownloadItem.Title);
if (series == null)
{
if (historyItem != null)
{
//series = _seriesService.GetSeries(historyItem.SeriesId);
series = _seriesService.GetSeries(historyItem.SeriesId);
}
if (series == null)
{
var movie = _parsingService.GetMovie(trackedDownload.DownloadItem.Title);
if (movie == null)
{
movie = _movieService.GetMovie(historyItem.MovieId);
if (movie == null)
{
trackedDownload.Warn("Movie title mismatch, automatic import is not possible.");
}
}
//trackedDownload.Warn("Series title mismatch, automatic import is not possible.");
//return;
trackedDownload.Warn("Series title mismatch, automatic import is not possible.");
return;
}
}
}

View File

@@ -57,7 +57,6 @@ namespace NzbDrone.Core.Download
get;
}
public abstract string Download(RemoteEpisode remoteEpisode);
public abstract IEnumerable<DownloadClientItem> GetItems();
public abstract void RemoveItem(string downloadId, bool deleteData);
@@ -148,7 +147,5 @@ namespace NzbDrone.Core.Download
return null;
}
public abstract string Download(RemoteMovie remoteMovie);
}
}

View File

@@ -15,7 +15,6 @@ namespace NzbDrone.Core.Download
public interface IDownloadService
{
void DownloadReport(RemoteEpisode remoteEpisode);
void DownloadReport(RemoteMovie remoteMovie);
}
@@ -42,8 +41,8 @@ namespace NzbDrone.Core.Download
public void DownloadReport(RemoteEpisode remoteEpisode)
{
//Ensure.That(remoteEpisode.Series, () => remoteEpisode.Series).IsNotNull();
//Ensure.That(remoteEpisode.Episodes, () => remoteEpisode.Episodes).HasItems(); TODO update this shit
Ensure.That(remoteEpisode.Series, () => remoteEpisode.Series).IsNotNull();
Ensure.That(remoteEpisode.Episodes, () => remoteEpisode.Episodes).HasItems();
var downloadTitle = remoteEpisode.Release.Title;
var downloadClient = _downloadClientProvider.GetDownloadClient(remoteEpisode.Release.DownloadProtocol);
@@ -92,62 +91,5 @@ namespace NzbDrone.Core.Download
_logger.ProgressInfo("Report sent to {0}. {1}", downloadClient.Definition.Name, downloadTitle);
_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);
}
}
}

View File

@@ -10,7 +10,6 @@ namespace NzbDrone.Core.Download
DownloadProtocol Protocol { get; }
string Download(RemoteEpisode remoteEpisode);
string Download(RemoteMovie remoteMovie);
IEnumerable<DownloadClientItem> GetItems();
void RemoveItem(string downloadId, bool deleteData);
DownloadClientStatus GetStatus();

View File

@@ -1,17 +0,0 @@
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;
}
}
}

View File

@@ -7,7 +7,6 @@ namespace NzbDrone.Core.Download.Pending
public class PendingRelease : ModelBase
{
public int SeriesId { get; set; }
public int MovieId { get; set; }
public string Title { get; set; }
public DateTime Added { get; set; }
public ParsedEpisodeInfo ParsedEpisodeInfo { get; set; }
@@ -15,6 +14,5 @@ namespace NzbDrone.Core.Download.Pending
//Not persisted
public RemoteEpisode RemoteEpisode { get; set; }
public RemoteMovie RemoteMovie { get; set; }
}
}

View File

@@ -33,7 +33,6 @@ namespace NzbDrone.Core.Download.Pending
public class PendingReleaseService : IPendingReleaseService,
IHandle<SeriesDeletedEvent>,
IHandle<EpisodeGrabbedEvent>,
IHandle<MovieGrabbedEvent>,
IHandle<RssSyncCompleteEvent>
{
private readonly IIndexerStatusService _indexerStatusService;
@@ -342,11 +341,6 @@ namespace NzbDrone.Core.Download.Pending
RemoveGrabbed(message.Episode);
}
public void Handle(MovieGrabbedEvent message)
{
//RemoveGrabbed(message.Movie);
}
public void Handle(RssSyncCompleteEvent message)
{
RemoveRejected(message.ProcessedDecisions.Rejected);

View File

@@ -32,112 +32,53 @@ namespace NzbDrone.Core.Download
public ProcessedDecisions ProcessDecisions(List<DownloadDecision> decisions)
{
//var qualifiedReports = GetQualifiedReports(decisions);
var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(decisions);
var qualifiedReports = GetQualifiedReports(decisions);
var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(qualifiedReports);
var grabbed = new List<DownloadDecision>();
var pending = new List<DownloadDecision>();
foreach (var report in prioritizedDecisions)
{
var remoteEpisode = report.RemoteEpisode;
if (report.IsForMovie)
var episodeIds = remoteEpisode.Episodes.Select(e => e.Id).ToList();
//Skip if already grabbed
if (grabbed.SelectMany(r => r.RemoteEpisode.Episodes)
.Select(e => e.Id)
.ToList()
.Intersect(episodeIds)
.Any())
{
var remoteMovie = report.RemoteMovie;
if (report.TemporarilyRejected)
{
_pendingReleaseService.Add(report);
pending.Add(report);
continue;
}
if (remoteMovie == null || remoteMovie.Movie == null)
{
continue;
}
List<int> movieIds = new List<int> { remoteMovie.Movie.Id };
//Skip if already grabbed
if (grabbed.Select(r => r.RemoteMovie.Movie)
.Select(e => e.Id)
.ToList()
.Intersect(movieIds)
.Any())
{
continue;
}
if (pending.Select(r => r.RemoteMovie.Movie)
.Select(e => e.Id)
.ToList()
.Intersect(movieIds)
.Any())
{
continue;
}
try
{
_downloadService.DownloadReport(remoteMovie);
grabbed.Add(report);
}
catch (Exception e)
{
//TODO: support for store & forward
//We'll need to differentiate between a download client error and an indexer error
_logger.Warn(e, "Couldn't add report to download queue. " + remoteMovie);
}
continue;
}
else
if (report.TemporarilyRejected)
{
var remoteEpisode = report.RemoteEpisode;
_pendingReleaseService.Add(report);
pending.Add(report);
continue;
}
if (remoteEpisode == null || remoteEpisode.Episodes == null)
{
continue;
}
if (pending.SelectMany(r => r.RemoteEpisode.Episodes)
.Select(e => e.Id)
.ToList()
.Intersect(episodeIds)
.Any())
{
continue;
}
var episodeIds = remoteEpisode.Episodes.Select(e => e.Id).ToList();
//Skip if already grabbed
if (grabbed.SelectMany(r => r.RemoteEpisode.Episodes)
.Select(e => e.Id)
.ToList()
.Intersect(episodeIds)
.Any())
{
continue;
}
if (report.TemporarilyRejected)
{
_pendingReleaseService.Add(report);
pending.Add(report);
continue;
}
if (pending.SelectMany(r => r.RemoteEpisode.Episodes)
.Select(e => e.Id)
.ToList()
.Intersect(episodeIds)
.Any())
{
continue;
}
try
{
_downloadService.DownloadReport(remoteEpisode);
grabbed.Add(report);
}
catch (Exception e)
{
//TODO: support for store & forward
//We'll need to differentiate between a download client error and an indexer error
_logger.Warn(e, "Couldn't add report to download queue. " + remoteEpisode);
}
try
{
_downloadService.DownloadReport(remoteEpisode);
grabbed.Add(report);
}
catch (Exception e)
{
//TODO: support for store & forward
//We'll need to differentiate between a download client error and an indexer error
_logger.Warn(e, "Couldn't add report to download queue. " + remoteEpisode);
}
}

View File

@@ -40,109 +40,21 @@ namespace NzbDrone.Core.Download
protected abstract string AddFromMagnetLink(RemoteEpisode remoteEpisode, string hash, string magnetLink);
protected abstract string AddFromTorrentFile(RemoteEpisode remoteEpisode, string hash, string filename, byte[] fileContent);
protected virtual string AddFromMagnetLink(RemoteMovie remoteMovie, string hash, string magnetLink)
{
throw new NotImplementedException();
}
protected virtual string AddFromTorrentFile(RemoteMovie remoteMovie, string hash, string filename, byte[] fileContent)
{
throw new NotImplementedException();
}
public override string Download(RemoteMovie remoteMovie)
public override string Download(RemoteEpisode remoteEpisode)
{
var torrentInfo = remoteMovie.Release as TorrentInfo;
var torrentInfo = remoteEpisode.Release as TorrentInfo;
string magnetUrl = null;
string torrentUrl = null;
if (remoteMovie.Release.DownloadUrl.IsNotNullOrWhiteSpace() && remoteMovie.Release.DownloadUrl.StartsWith("magnet:"))
if (remoteEpisode.Release.DownloadUrl.IsNotNullOrWhiteSpace() && remoteEpisode.Release.DownloadUrl.StartsWith("magnet:"))
{
magnetUrl = remoteMovie.Release.DownloadUrl;
magnetUrl = remoteEpisode.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;
}
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;
torrentUrl = remoteEpisode.Release.DownloadUrl;
}
if (torrentInfo != null && !torrentInfo.MagnetUrl.IsNullOrWhiteSpace())
@@ -156,7 +68,7 @@ namespace NzbDrone.Core.Download
{
try
{
return DownloadFromWebUrl(remoteMovie, torrentUrl);
return DownloadFromWebUrl(remoteEpisode, torrentUrl);
}
catch (Exception ex)
{
@@ -173,11 +85,11 @@ namespace NzbDrone.Core.Download
{
try
{
return DownloadFromMagnetUrl(remoteMovie, magnetUrl);
return DownloadFromMagnetUrl(remoteEpisode, magnetUrl);
}
catch (NotSupportedException ex)
{
throw new ReleaseDownloadException(remoteMovie.Release, "Magnet not supported by download client. ({0})", ex.Message);
throw new ReleaseDownloadException(remoteEpisode.Release, "Magnet not supported by download client. ({0})", ex.Message);
}
}
}
@@ -187,13 +99,13 @@ namespace NzbDrone.Core.Download
{
try
{
return DownloadFromMagnetUrl(remoteMovie, magnetUrl);
return DownloadFromMagnetUrl(remoteEpisode, magnetUrl);
}
catch (NotSupportedException ex)
{
if (torrentUrl.IsNullOrWhiteSpace())
{
throw new ReleaseDownloadException(remoteMovie.Release, "Magnet not supported by download client. ({0})", ex.Message);
throw new ReleaseDownloadException(remoteEpisode.Release, "Magnet not supported by download client. ({0})", ex.Message);
}
_logger.Debug("Magnet not supported by download client, trying torrent. ({0})", ex.Message);
@@ -202,113 +114,13 @@ namespace NzbDrone.Core.Download
if (torrentUrl.IsNotNullOrWhiteSpace())
{
return DownloadFromWebUrl(remoteMovie, torrentUrl);
return DownloadFromWebUrl(remoteEpisode, 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)
{
byte[] torrentFile = null;

View File

@@ -10,7 +10,6 @@ namespace NzbDrone.Core.Download.TrackedDownloads
public TrackedDownloadStage State { get; set; }
public TrackedDownloadStatus Status { get; private set; }
public RemoteEpisode RemoteEpisode { get; set; }
public RemoteMovie RemoteMovie { get; set; }
public TrackedDownloadStatusMessage[] StatusMessages { get; private set; }
public DownloadProtocol Protocol { get; set; }

View File

@@ -62,7 +62,6 @@ namespace NzbDrone.Core.Download.TrackedDownloads
if (parsedEpisodeInfo != null)
{
trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0, 0);
trackedDownload.RemoteMovie = _parsingService.Map(parsedEpisodeInfo, "", null);
}
if (historyItems.Any())
@@ -70,10 +69,10 @@ namespace NzbDrone.Core.Download.TrackedDownloads
var firstHistoryItem = historyItems.OrderByDescending(h => h.Date).First();
trackedDownload.State = GetStateFromHistory(firstHistoryItem.EventType);
if ((parsedEpisodeInfo == null ||
if (parsedEpisodeInfo == null ||
trackedDownload.RemoteEpisode == null ||
trackedDownload.RemoteEpisode.Series == null ||
trackedDownload.RemoteEpisode.Episodes.Empty()) && trackedDownload.RemoteMovie == null)
trackedDownload.RemoteEpisode.Episodes.Empty())
{
// 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
@@ -86,7 +85,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
}
}
if (trackedDownload.RemoteEpisode == null && trackedDownload.RemoteMovie == null)
if (trackedDownload.RemoteEpisode == null)
{
return null;
}

View File

@@ -1,5 +1,4 @@
using System.Net;
using System;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Http;
using NzbDrone.Core.Exceptions;
@@ -32,11 +31,6 @@ namespace NzbDrone.Core.Download
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)
{
var url = remoteEpisode.Release.DownloadUrl;
@@ -73,42 +67,5 @@ namespace NzbDrone.Core.Download
_logger.Info("Adding report [{0}] to the queue.", remoteEpisode.Release.Title);
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);
}
}
}

View File

@@ -1,27 +0,0 @@
using NzbDrone.Common.Exceptions;
namespace NzbDrone.Core.Exceptions
{
public class MovieNotFoundException : NzbDroneException
{
public string ImdbId { get; set; }
public MovieNotFoundException(string imdbid)
: base(string.Format("Movie with imdbid {0} was not found, it may have been removed from IMDb.", imdbid))
{
ImdbId = imdbid;
}
public MovieNotFoundException(string imdbid, string message, params object[] args)
: base(message, args)
{
ImdbId = imdbid;
}
public MovieNotFoundException(string imdbid, string message)
: base(message)
{
ImdbId = imdbid;
}
}
}

View File

@@ -17,11 +17,9 @@ namespace NzbDrone.Core.History
public int EpisodeId { get; set; }
public int SeriesId { get; set; }
public int MovieId { get; set; }
public string SourceTitle { get; set; }
public QualityModel Quality { get; set; }
public DateTime Date { get; set; }
public Movie Movie { get; set; }
public Episode Episode { get; set; }
public Series Series { get; set; }
public HistoryEventType EventType { get; set; }

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using Marr.Data.QGen;
using NzbDrone.Core.Datastore;
@@ -17,7 +16,6 @@ namespace NzbDrone.Core.History
List<History> FindByDownloadId(string downloadId);
List<History> FindDownloadHistory(int idSeriesId, QualityModel quality);
void DeleteForSeries(int seriesId);
History MostRecentForMovie(int movieId);
}
public class HistoryRepository : BasicRepository<History>, IHistoryRepository
@@ -73,20 +71,10 @@ namespace NzbDrone.Core.History
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)
.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);
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);
return base.GetPagedQuery(baseQuery, pagingSpec);
}
public History MostRecentForMovie(int movieId)
{
return Query.Where(h => h.MovieId == movieId)
.OrderByDescending(h => h.Date)
.FirstOrDefault();
}
}
}

View File

@@ -20,7 +20,6 @@ namespace NzbDrone.Core.History
{
QualityModel GetBestQualityInHistory(Profile profile, int episodeId);
PagingSpec<History> Paged(PagingSpec<History> pagingSpec);
History MostRecentForMovie(int movieId);
History MostRecentForEpisode(int episodeId);
History MostRecentForDownloadId(string downloadId);
History Get(int historyId);
@@ -30,7 +29,6 @@ namespace NzbDrone.Core.History
public class HistoryService : IHistoryService,
IHandle<EpisodeGrabbedEvent>,
IHandle<MovieGrabbedEvent>,
IHandle<EpisodeImportedEvent>,
IHandle<DownloadFailedEvent>,
IHandle<EpisodeFileDeletedEvent>,
@@ -55,11 +53,6 @@ namespace NzbDrone.Core.History
return _historyRepository.MostRecentForEpisode(episodeId);
}
public History MostRecentForMovie(int movieId)
{
return _historyRepository.MostRecentForMovie(movieId);
}
public History MostRecentForDownloadId(string downloadId)
{
return _historyRepository.MostRecentForDownloadId(downloadId);
@@ -145,8 +138,7 @@ namespace NzbDrone.Core.History
SourceTitle = message.Episode.Release.Title,
SeriesId = episode.SeriesId,
EpisodeId = episode.Id,
DownloadId = message.DownloadId,
MovieId = 0
DownloadId = message.DownloadId
};
history.Data.Add("Indexer", message.Episode.Release.Indexer);
@@ -180,50 +172,6 @@ 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)
{
if (!message.NewDownload)
@@ -241,18 +189,15 @@ namespace NzbDrone.Core.History
foreach (var episode in message.EpisodeInfo.Episodes)
{
var history = new History
{
EventType = HistoryEventType.DownloadFolderImported,
Date = DateTime.UtcNow,
Quality = message.EpisodeInfo.Quality,
SourceTitle = message.ImportedEpisode.SceneName ?? Path.GetFileNameWithoutExtension(message.EpisodeInfo.Path),
SeriesId = message.ImportedEpisode.SeriesId,
EpisodeId = episode.Id,
DownloadId = downloadId,
MovieId = 0,
};
{
EventType = HistoryEventType.DownloadFolderImported,
Date = DateTime.UtcNow,
Quality = message.EpisodeInfo.Quality,
SourceTitle = message.ImportedEpisode.SceneName ?? Path.GetFileNameWithoutExtension(message.EpisodeInfo.Path),
SeriesId = message.ImportedEpisode.SeriesId,
EpisodeId = episode.Id,
DownloadId = downloadId
};
//Won't have a value since we publish this event before saving to DB.
//history.Data.Add("FileId", message.ImportedEpisode.Id.ToString());
@@ -304,7 +249,6 @@ namespace NzbDrone.Core.History
SourceTitle = message.EpisodeFile.Path,
SeriesId = message.EpisodeFile.SeriesId,
EpisodeId = episode.Id,
MovieId = 0
};
history.Data.Add("Reason", message.Reason.ToString());

View File

@@ -1,11 +0,0 @@
namespace NzbDrone.Core.IndexerSearch.Definitions
{
public class MovieSearchCriteria : SearchCriteriaBase
{
public override string ToString()
{
return string.Format("[{0}]", Movie.Title);
}
}
}

View File

@@ -14,8 +14,6 @@ namespace NzbDrone.Core.IndexerSearch.Definitions
private static readonly Regex BeginningThe = new Regex(@"^the\s", RegexOptions.IgnoreCase | RegexOptions.Compiled);
public Series Series { get; set; }
public Movie Movie { get; set; }
public List<string> SceneTitles { get; set; }
public List<Episode> Episodes { get; set; }
public virtual bool MonitoredEpisodesOnly { get; set; }

View File

@@ -1,11 +0,0 @@
using NzbDrone.Core.Messaging.Commands;
namespace NzbDrone.Core.IndexerSearch
{
public class MoviesSearchCommand : Command
{
public int MovieId { get; set; }
public override bool SendUpdatesToClient => true;
}
}

View File

@@ -1,46 +0,0 @@
using System.Linq;
using NLog;
using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Core.Download;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.IndexerSearch
{
public class MovieSearchService : IExecute<MoviesSearchCommand>
{
private readonly IMovieService _seriesService;
private readonly ISearchForNzb _nzbSearchService;
private readonly IProcessDownloadDecisions _processDownloadDecisions;
private readonly Logger _logger;
public MovieSearchService(IMovieService seriesService,
ISearchForNzb nzbSearchService,
IProcessDownloadDecisions processDownloadDecisions,
Logger logger)
{
_seriesService = seriesService;
_nzbSearchService = nzbSearchService;
_processDownloadDecisions = processDownloadDecisions;
_logger = logger;
}
public void Execute(MoviesSearchCommand message)
{
var series = _seriesService.GetMovie(message.MovieId);
var downloadedCount = 0;
if (!series.Monitored)
{
_logger.Debug("Movie {0} is not monitored, skipping search", series.Title);
}
var decisions = _nzbSearchService.MovieSearch(message.MovieId, false);//_nzbSearchService.SeasonSearch(message.MovieId, season.SeasonNumber, false, message.Trigger == CommandTrigger.Manual);
downloadedCount += _processDownloadDecisions.ProcessDecisions(decisions).Grabbed.Count;
_logger.ProgressInfo("Movie search completed. {0} reports downloaded.", downloadedCount);
}
}
}

View File

@@ -19,8 +19,6 @@ namespace NzbDrone.Core.IndexerSearch
{
List<DownloadDecision> EpisodeSearch(int episodeId, 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);
}
@@ -31,7 +29,6 @@ namespace NzbDrone.Core.IndexerSearch
private readonly ISeriesService _seriesService;
private readonly IEpisodeService _episodeService;
private readonly IMakeDownloadDecision _makeDownloadDecision;
private readonly IMovieService _movieService;
private readonly Logger _logger;
public NzbSearchService(IIndexerFactory indexerFactory,
@@ -39,7 +36,6 @@ namespace NzbDrone.Core.IndexerSearch
ISeriesService seriesService,
IEpisodeService episodeService,
IMakeDownloadDecision makeDownloadDecision,
IMovieService movieService,
Logger logger)
{
_indexerFactory = indexerFactory;
@@ -47,7 +43,6 @@ namespace NzbDrone.Core.IndexerSearch
_seriesService = seriesService;
_episodeService = episodeService;
_makeDownloadDecision = makeDownloadDecision;
_movieService = movieService;
_logger = logger;
}
@@ -58,20 +53,6 @@ namespace NzbDrone.Core.IndexerSearch
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)
{
var series = _seriesService.GetSeries(episode.SeriesId);
@@ -264,23 +245,6 @@ namespace NzbDrone.Core.IndexerSearch
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)
{
var indexers = _indexerFactory.SearchEnabled();

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using NzbDrone.Common.Http;
using NzbDrone.Core.IndexerSearch.Definitions;
@@ -23,11 +22,6 @@ namespace NzbDrone.Core.Indexers.BitMeTv
return new IndexerPageableRequestChain();
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();

View File

@@ -2,7 +2,6 @@
using System.Collections.Generic;
using NzbDrone.Common.Http;
using NzbDrone.Core.IndexerSearch.Definitions;
using System;
namespace NzbDrone.Core.Indexers.BroadcastheNet
{
@@ -190,10 +189,5 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
yield return new IndexerRequest(builder.Build());
}
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
@@ -85,10 +84,5 @@ namespace NzbDrone.Core.Indexers.Fanzub
{
return RemoveCharactersRegex.Replace(title, "");
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
@@ -129,10 +128,5 @@ namespace NzbDrone.Core.Indexers.HDBits
yield return new IndexerRequest(request);
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
}
}

View File

@@ -111,18 +111,6 @@ namespace NzbDrone.Core.Indexers
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)
{
var releases = new List<ReleaseInfo>();

View File

@@ -17,6 +17,5 @@ namespace NzbDrone.Core.Indexers
IList<ReleaseInfo> Fetch(DailyEpisodeSearchCriteria searchCriteria);
IList<ReleaseInfo> Fetch(AnimeEpisodeSearchCriteria searchCriteria);
IList<ReleaseInfo> Fetch(SpecialEpisodeSearchCriteria searchCriteria);
IList<ReleaseInfo> Fetch(MovieSearchCriteria searchCriteria);
}
}

View File

@@ -10,6 +10,5 @@ namespace NzbDrone.Core.Indexers
IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria);
IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria);
IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria);
IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria);
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using NzbDrone.Common.Http;
using NzbDrone.Core.IndexerSearch.Definitions;
@@ -23,11 +22,6 @@ namespace NzbDrone.Core.Indexers.IPTorrents
return new IndexerPageableRequestChain();
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();

View File

@@ -67,7 +67,6 @@ namespace NzbDrone.Core.Indexers
public abstract IList<ReleaseInfo> Fetch(DailyEpisodeSearchCriteria searchCriteria);
public abstract IList<ReleaseInfo> Fetch(AnimeEpisodeSearchCriteria searchCriteria);
public abstract IList<ReleaseInfo> Fetch(SpecialEpisodeSearchCriteria searchCriteria);
public abstract IList<ReleaseInfo> Fetch(MovieSearchCriteria searchCriteria);
protected virtual IList<ReleaseInfo> CleanupReleases(IEnumerable<ReleaseInfo> releases)
{

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Common.Http;
using NzbDrone.Core.IndexerSearch.Definitions;
@@ -148,10 +147,5 @@ namespace NzbDrone.Core.Indexers.KickassTorrents
{
return query.Replace('+', ' ');
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
@@ -274,10 +273,5 @@ namespace NzbDrone.Core.Indexers.Newznab
{
return title.Replace("+", "%20");
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using NzbDrone.Common.Http;
using NzbDrone.Core.IndexerSearch.Definitions;
@@ -103,10 +102,5 @@ namespace NzbDrone.Core.Indexers.Nyaa
{
return query.Replace(' ', '+');
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Text;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
@@ -102,10 +101,5 @@ namespace NzbDrone.Core.Indexers.Omgwtfnzbs
yield return new IndexerRequest(url.ToString(), HttpAccept.Rss);
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.IndexerSearch.Definitions;
@@ -102,7 +101,7 @@ namespace NzbDrone.Core.Indexers.Rarbg
requestBuilder.AddQueryParam("ranked", "0");
}
requestBuilder.AddQueryParam("category", "tv");
requestBuilder.AddQueryParam("category", "18;41");
requestBuilder.AddQueryParam("limit", "100");
requestBuilder.AddQueryParam("token", _tokenProvider.GetToken(Settings));
requestBuilder.AddQueryParam("format", "json_extended");
@@ -110,48 +109,5 @@ namespace NzbDrone.Core.Indexers.Rarbg
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("limit", "100");
requestBuilder.AddQueryParam("token", _tokenProvider.GetToken(Settings));
requestBuilder.AddQueryParam("format", "json_extended");
requestBuilder.AddQueryParam("app_id", "Sonarr");
yield return new IndexerRequest(requestBuilder.Build());
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetMovieRequest(searchCriteria));
return pageableRequests;
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using NzbDrone.Common.Http;
using NzbDrone.Common.Http;
using NzbDrone.Core.IndexerSearch.Definitions;
namespace NzbDrone.Core.Indexers
@@ -23,11 +22,6 @@ namespace NzbDrone.Core.Indexers
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
throw new NotImplementedException();
}
public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.IndexerSearch.Definitions;
@@ -24,11 +23,6 @@ namespace NzbDrone.Core.Indexers.TorrentRss
return new IndexerPageableRequestChain();
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using NzbDrone.Common.Http;
using NzbDrone.Core.IndexerSearch.Definitions;
@@ -23,11 +22,6 @@ namespace NzbDrone.Core.Indexers.Torrentleech
return new IndexerPageableRequestChain();
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();

View File

@@ -7,9 +7,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Newznab;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider;
namespace NzbDrone.Core.Indexers.Torznab
@@ -112,6 +110,5 @@ namespace NzbDrone.Core.Indexers.Torznab
return new ValidationFailure(string.Empty, "Unable to connect to indexer, check the log for more details");
}
}
}
}

View File

@@ -1,11 +1,7 @@
using System;
using System.Collections.Generic;
using NLog;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider;
namespace NzbDrone.Core.Indexers.Wombles

View File

@@ -22,8 +22,6 @@ namespace NzbDrone.Core.MediaCover
public class MediaCoverService :
IHandleAsync<SeriesUpdatedEvent>,
IHandleAsync<MovieUpdatedEvent>,
IHandleAsync<MovieAddedEvent>,
IHandleAsync<SeriesDeletedEvent>,
IMapCoversToLocal
{
@@ -85,8 +83,6 @@ namespace NzbDrone.Core.MediaCover
return Path.Combine(_coverRootFolder, seriesId.ToString());
}
private void EnsureCovers(Series series)
{
foreach (var cover in series.Images)
@@ -114,33 +110,6 @@ namespace NzbDrone.Core.MediaCover
}
}
private void EnsureCovers(Movie movie)
{
foreach (var cover in movie.Images)
{
var fileName = GetCoverPath(movie.Id, cover.CoverType);
var alreadyExists = false;
try
{
alreadyExists = _coverExistsSpecification.AlreadyExists(cover.Url, fileName);
if (!alreadyExists)
{
DownloadCover(movie, cover);
}
}
catch (WebException e)
{
_logger.Warn(string.Format("Couldn't download media cover for {0}. {1}", movie, e.Message));
}
catch (Exception e)
{
_logger.Error(e, "Couldn't download media cover for " + movie);
}
EnsureResizedCovers(movie, cover, !alreadyExists);
}
}
private void DownloadCover(Series series, MediaCover cover)
{
var fileName = GetCoverPath(series.Id, cover.CoverType);
@@ -149,14 +118,6 @@ namespace NzbDrone.Core.MediaCover
_httpClient.DownloadFile(cover.Url, fileName);
}
private void DownloadCover(Movie series, MediaCover cover)
{
var fileName = GetCoverPath(series.Id, cover.CoverType);
_logger.Info("Downloading {0} for {1} {2}", cover.CoverType, series, cover.Url);
_httpClient.DownloadFile(cover.Url, fileName);
}
private void EnsureResizedCovers(Series series, MediaCover cover, bool forceResize)
{
int[] heights;
@@ -202,69 +163,12 @@ namespace NzbDrone.Core.MediaCover
}
}
private void EnsureResizedCovers(Movie series, MediaCover cover, bool forceResize)
{
int[] heights;
switch (cover.CoverType)
{
default:
return;
case MediaCoverTypes.Poster:
case MediaCoverTypes.Headshot:
heights = new[] { 500, 250 };
break;
case MediaCoverTypes.Banner:
heights = new[] { 70, 35 };
break;
case MediaCoverTypes.Fanart:
case MediaCoverTypes.Screenshot:
heights = new[] { 360, 180 };
break;
}
foreach (var height in heights)
{
var mainFileName = GetCoverPath(series.Id, cover.CoverType);
var resizeFileName = GetCoverPath(series.Id, cover.CoverType, height);
if (forceResize || !_diskProvider.FileExists(resizeFileName) || _diskProvider.GetFileSize(resizeFileName) == 0)
{
_logger.Debug("Resizing {0}-{1} for {2}", cover.CoverType, height, series);
try
{
_resizer.Resize(mainFileName, resizeFileName, height);
}
catch
{
_logger.Debug("Couldn't resize media cover {0}-{1} for {2}, using full size image instead.", cover.CoverType, height, series);
}
}
}
}
public void HandleAsync(SeriesUpdatedEvent message)
{
EnsureCovers(message.Series);
_eventAggregator.PublishEvent(new MediaCoversUpdatedEvent(message.Series));
}
public void HandleAsync(MovieUpdatedEvent message)
{
EnsureCovers(message.Movie);
_eventAggregator.PublishEvent(new MediaCoversUpdatedEvent(message.Movie));
}
public void HandleAsync(MovieAddedEvent message)
{
EnsureCovers(message.Movie);
_eventAggregator.PublishEvent(new MediaCoversUpdatedEvent(message.Movie));
}
public void HandleAsync(SeriesDeletedEvent message)
{
var path = GetSeriesCoverPath(message.Series.Id);

View File

@@ -7,16 +7,9 @@ namespace NzbDrone.Core.MediaCover
{
public Series Series { get; set; }
public Movie Movie { get; set; }
public MediaCoversUpdatedEvent(Series series)
{
Series = series;
}
public MediaCoversUpdatedEvent(Movie movie)
{
Movie = movie;
}
}
}

View File

@@ -1,20 +0,0 @@
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;
}
}
}

View File

@@ -22,7 +22,6 @@ namespace NzbDrone.Core.MediaFiles
public interface IDiskScanService
{
void Scan(Series series);
void Scan(Movie movie);
string[] GetVideoFiles(string path, bool allDirectories = true);
string[] GetNonVideoFiles(string path, bool allDirectories = true);
List<string> FilterFiles(Series series, IEnumerable<string> files);
@@ -31,8 +30,6 @@ namespace NzbDrone.Core.MediaFiles
public class DiskScanService :
IDiskScanService,
IHandle<SeriesUpdatedEvent>,
IHandle<MovieUpdatedEvent>,
IExecute<RescanMovieCommand>,
IExecute<RescanSeriesCommand>
{
private readonly IDiskProvider _diskProvider;
@@ -42,7 +39,6 @@ namespace NzbDrone.Core.MediaFiles
private readonly ISeriesService _seriesService;
private readonly IMediaFileTableCleanupService _mediaFileTableCleanupService;
private readonly IEventAggregator _eventAggregator;
private readonly IMovieService _movieService;
private readonly Logger _logger;
public DiskScanService(IDiskProvider diskProvider,
@@ -52,7 +48,6 @@ namespace NzbDrone.Core.MediaFiles
ISeriesService seriesService,
IMediaFileTableCleanupService mediaFileTableCleanupService,
IEventAggregator eventAggregator,
IMovieService movieService,
Logger logger)
{
_diskProvider = diskProvider;
@@ -62,7 +57,6 @@ namespace NzbDrone.Core.MediaFiles
_seriesService = seriesService;
_mediaFileTableCleanupService = mediaFileTableCleanupService;
_eventAggregator = eventAggregator;
_movieService = movieService;
_logger = logger;
}
@@ -127,64 +121,6 @@ namespace NzbDrone.Core.MediaFiles
_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)
{
_logger.Debug("Scanning '{0}' for video files", path);
@@ -220,13 +156,6 @@ namespace NzbDrone.Core.MediaFiles
.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)
{
if (!_configService.SetPermissionsLinux)
@@ -253,28 +182,6 @@ namespace NzbDrone.Core.MediaFiles
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)
{
if (message.SeriesId.HasValue)

View File

@@ -18,8 +18,6 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
public interface IMakeImportDecision
{
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);
}
@@ -55,11 +53,6 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
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)
{
var newFiles = _mediaFileService.FilterExistingFiles(videoFiles.ToList(), series);
@@ -77,75 +70,6 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
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)
{
ImportDecision decision = null;
@@ -258,40 +182,6 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
}) == 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)
{
if (UseFolderQuality(folderInfo, fileQuality, series))

View File

@@ -17,8 +17,8 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
{
if (localEpisode.ParsedEpisodeInfo.FullSeason)
{
//_logger.Debug("Single episode file detected as containing all episodes in the season"); //Not needed for Movies mwhahahahah
//return Decision.Reject("Single episode file contains all episodes in seasons");
_logger.Debug("Single episode file detected as containing all episodes in the season");
return Decision.Reject("Single episode file contains all episodes in seasons");
}
return Decision.Accept();

View File

@@ -1,15 +0,0 @@
using NzbDrone.Common.Messaging;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.MediaFiles.Events
{
public class MovieRenamedEvent : IEvent
{
public Movie Movie { get; private set; }
public MovieRenamedEvent(Movie movie)
{
Movie = movie;
}
}
}

View File

@@ -1,24 +0,0 @@
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
}
}

View File

@@ -1,15 +0,0 @@
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;
}
}
}

View File

@@ -16,11 +16,9 @@ namespace NzbDrone.Core.MediaFiles
void Update(EpisodeFile episodeFile);
void Delete(EpisodeFile episodeFile, DeleteMediaFileReason reason);
List<EpisodeFile> GetFilesBySeries(int seriesId);
List<EpisodeFile> GetFilesByMovie(int movieId);
List<EpisodeFile> GetFilesBySeason(int seriesId, int seasonNumber);
List<EpisodeFile> GetFilesWithoutMediaInfo();
List<string> FilterExistingFiles(List<string> files, Series series);
List<string> FilterExistingFiles(List<string> files, Movie movie);
EpisodeFile Get(int id);
List<EpisodeFile> Get(IEnumerable<int> ids);
@@ -66,11 +64,6 @@ namespace NzbDrone.Core.MediaFiles
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)
{
return _mediaFileRepository.GetFilesBySeason(seriesId, seasonNumber);
@@ -90,15 +83,6 @@ namespace NzbDrone.Core.MediaFiles
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)
{
return _mediaFileRepository.Get(id);

View File

@@ -11,8 +11,6 @@ namespace NzbDrone.Core.MediaFiles
public interface IMediaFileTableCleanupService
{
void Clean(Series series, List<string> filesOnDisk);
void Clean(Movie movie, List<string> filesOnDisk);
}
public class MediaFileTableCleanupService : IMediaFileTableCleanupService
@@ -86,64 +84,5 @@ namespace NzbDrone.Core.MediaFiles
}
}
}
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);
}
}
}
}
}

View File

@@ -1,11 +0,0 @@
using System;
using System.Collections.Generic;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.MetadataSource
{
public interface IProvideMovieInfo
{
Movie GetMovieInfo(string ImdbId);
}
}

View File

@@ -1,10 +0,0 @@
using System.Collections.Generic;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.MetadataSource
{
public interface ISearchForNewMovie
{
List<Movie> SearchForNewMovie(string title);
}
}

View File

@@ -10,11 +10,10 @@ using NzbDrone.Core.Exceptions;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MetadataSource.SkyHook.Resource;
using NzbDrone.Core.Tv;
using Newtonsoft.Json;
namespace NzbDrone.Core.MetadataSource.SkyHook
{
public class SkyHookProxy : IProvideSeriesInfo, ISearchForNewSeries, IProvideMovieInfo, ISearchForNewMovie
public class SkyHookProxy : IProvideSeriesInfo, ISearchForNewSeries
{
private readonly IHttpClient _httpClient;
private readonly Logger _logger;
@@ -58,136 +57,6 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
return new Tuple<Series, List<Episode>>(series, episodes.ToList());
}
public Movie GetMovieInfo(string ImdbId)
{
var imdbRequest = new HttpRequest("http://www.omdbapi.com/?i=" + ImdbId + "&plot=full&r=json");
var httpResponse = _httpClient.Get(imdbRequest);
if (httpResponse.HasHttpError)
{
if (httpResponse.StatusCode == HttpStatusCode.NotFound)
{
throw new MovieNotFoundException(ImdbId);
}
else
{
throw new HttpException(imdbRequest, httpResponse);
}
}
var response = httpResponse.Content;
dynamic json = JsonConvert.DeserializeObject(response);
var movie = new Movie();
movie.Title = json.Title;
movie.TitleSlug = movie.Title.ToLower().Replace(" ", "-");
movie.Overview = json.Plot;
movie.CleanTitle = Parser.Parser.CleanSeriesTitle(movie.Title);
string airDateStr = json.Released;
DateTime airDate = DateTime.Parse(airDateStr);
movie.InCinemas = airDate;
movie.Year = airDate.Year;
movie.ImdbId = ImdbId;
string imdbRating = json.imdbVotes;
if (imdbRating == "N/A")
{
movie.Status = MovieStatusType.Announced;
}
else
{
movie.Status = MovieStatusType.Released;
}
string url = json.Poster;
var imdbPoster = new MediaCover.MediaCover(MediaCoverTypes.Poster, url);
movie.Images.Add(imdbPoster);
string runtime = json.Runtime;
int runtimeNum = 0;
int.TryParse(runtime.Replace("min", "").Trim(), out runtimeNum);
movie.Runtime = runtimeNum;
return movie;
}
public List<Movie> SearchForNewMovie(string title)
{
var lowerTitle = title.ToLower();
if (lowerTitle.StartsWith("imdb:") || lowerTitle.StartsWith("imdbid:"))
{
var slug = lowerTitle.Split(':')[1].Trim();
string imdbid = slug;
if (slug.IsNullOrWhiteSpace() || slug.Any(char.IsWhiteSpace))
{
return new List<Movie>();
}
try
{
return new List<Movie> { GetMovieInfo(imdbid) };
}
catch (SeriesNotFoundException)
{
return new List<Movie>();
}
}
var searchTerm = lowerTitle.Replace("+", "_").Replace(" ", "_");
var firstChar = searchTerm.First();
var imdbRequest = new HttpRequest("https://v2.sg.media-imdb.com/suggests/" + firstChar + "/" + searchTerm + ".json");
var response = _httpClient.Get(imdbRequest);
var imdbCallback = "imdb$" + searchTerm + "(";
var responseCleaned = response.Content.Replace(imdbCallback, "").TrimEnd(")");
dynamic json = JsonConvert.DeserializeObject(responseCleaned);
var imdbMovies = new List<Movie>();
foreach (dynamic entry in json.d)
{
var imdbMovie = new Movie();
imdbMovie.ImdbId = entry.id;
try
{
imdbMovie.SortTitle = entry.l;
imdbMovie.Title = entry.l;
string titleSlug = entry.l;
imdbMovie.TitleSlug = titleSlug.ToLower().Replace(" ", "-");
imdbMovie.Year = entry.y;
imdbMovie.Images = new List<MediaCover.MediaCover>();
try
{
string url = entry.i[0];
var imdbPoster = new MediaCover.MediaCover(MediaCoverTypes.Poster, url);
imdbMovie.Images.Add(imdbPoster);
}
catch (Exception e)
{
_logger.Debug(entry);
continue;
}
imdbMovies.Add(imdbMovie);
}
catch
{
}
}
return imdbMovies;
}
public List<Series> SearchForNewSeries(string title)
{
try
@@ -215,15 +84,11 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
}
}
var httpRequest = _requestBuilder.Create()
.SetSegment("route", "search")
.AddQueryParam("term", title.ToLower().Trim())
.Build();
var httpResponse = _httpClient.Get<List<ShowResource>>(httpRequest);
return httpResponse.Resource.SelectList(MapSeries);

View File

@@ -1,42 +0,0 @@
using System;
using System.Collections.Generic;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.MovieStats
{
public class MovieStatistics : ResultSet
{
public int MovieId { get; set; }
public string NextAiringString { get; set; }
public string PreviousAiringString { get; set; }
public int EpisodeFileCount { get; set; }
public int EpisodeCount { get; set; }
public int TotalEpisodeCount { get; set; }
public long SizeOnDisk { get; set; }
public List<SeasonStatistics> SeasonStatistics { get; set; }
public DateTime? NextAiring
{
get
{
DateTime nextAiring;
if (!DateTime.TryParse(NextAiringString, out nextAiring)) return null;
return nextAiring;
}
}
public DateTime? PreviousAiring
{
get
{
DateTime previousAiring;
if (!DateTime.TryParse(PreviousAiringString, out previousAiring)) return null;
return previousAiring;
}
}
}
}

View File

@@ -1,86 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.MovieStats
{
public interface IMovieStatisticsRepository
{
List<SeasonStatistics> MovieStatistics();
List<SeasonStatistics> MovieStatistics(int movieId);
}
public class MovieStatisticsRepository : IMovieStatisticsRepository
{
private readonly IMainDatabase _database;
public MovieStatisticsRepository(IMainDatabase database)
{
_database = database;
}
public List<SeasonStatistics> MovieStatistics()
{
var mapper = _database.GetDataMapper();
mapper.AddParameter("currentDate", DateTime.UtcNow);
var sb = new StringBuilder();
sb.AppendLine(GetSelectClause());
sb.AppendLine(GetEpisodeFilesJoin());
sb.AppendLine(GetGroupByClause());
var queryText = sb.ToString();
return new List<SeasonStatistics>();
return mapper.Query<SeasonStatistics>(queryText);
}
public List<SeasonStatistics> MovieStatistics(int movieId)
{
var mapper = _database.GetDataMapper();
mapper.AddParameter("currentDate", DateTime.UtcNow);
mapper.AddParameter("movieId", movieId);
var sb = new StringBuilder();
sb.AppendLine(GetSelectClause());
sb.AppendLine(GetEpisodeFilesJoin());
sb.AppendLine("WHERE Episodes.MovieId = @movieId");
sb.AppendLine(GetGroupByClause());
var queryText = sb.ToString();
return new List<SeasonStatistics>();
return mapper.Query<SeasonStatistics>(queryText);
}
private string GetSelectClause()
{
return @"SELECT Episodes.*, SUM(EpisodeFiles.Size) as SizeOnDisk FROM
(SELECT
Episodes.MovieId,
Episodes.SeasonNumber,
SUM(CASE WHEN AirdateUtc <= @currentDate OR EpisodeFileId > 0 THEN 1 ELSE 0 END) AS TotalEpisodeCount,
SUM(CASE WHEN (Monitored = 1 AND AirdateUtc <= @currentDate) OR EpisodeFileId > 0 THEN 1 ELSE 0 END) AS EpisodeCount,
SUM(CASE WHEN EpisodeFileId > 0 THEN 1 ELSE 0 END) AS EpisodeFileCount,
MIN(CASE WHEN AirDateUtc < @currentDate OR EpisodeFileId > 0 OR Monitored = 0 THEN NULL ELSE AirDateUtc END) AS NextAiringString,
MAX(CASE WHEN AirDateUtc >= @currentDate OR EpisodeFileId = 0 AND Monitored = 0 THEN NULL ELSE AirDateUtc END) AS PreviousAiringString
FROM Episodes
GROUP BY Episodes.MovieId, Episodes.SeasonNumber) as Episodes";
}
private string GetGroupByClause()
{
return "GROUP BY Episodes.MovieId, Episodes.SeasonNumber";
}
private string GetEpisodeFilesJoin()
{
return @"LEFT OUTER JOIN EpisodeFiles
ON EpisodeFiles.MovieId = Episodes.MovieId
AND EpisodeFiles.SeasonNumber = Episodes.SeasonNumber";
}
}
}

View File

@@ -1,63 +0,0 @@
using System.Collections.Generic;
using System.Linq;
namespace NzbDrone.Core.MovieStats
{
public interface IMovieStatisticsService
{
List<MovieStatistics> MovieStatistics();
MovieStatistics MovieStatistics(int movieId);
}
public class MovieStatisticsService : IMovieStatisticsService
{
private readonly IMovieStatisticsRepository _movieStatisticsRepository;
public MovieStatisticsService(IMovieStatisticsRepository movieStatisticsRepository)
{
_movieStatisticsRepository = movieStatisticsRepository;
}
public List<MovieStatistics> MovieStatistics()
{
var seasonStatistics = _movieStatisticsRepository.MovieStatistics();
return seasonStatistics.GroupBy(s => s.MovieId).Select(s => MapMovieStatistics(s.ToList())).ToList();
}
public MovieStatistics MovieStatistics(int movieId)
{
var stats = _movieStatisticsRepository.MovieStatistics(movieId);
if (stats == null || stats.Count == 0) return new MovieStatistics();
return MapMovieStatistics(stats);
}
private MovieStatistics MapMovieStatistics(List<SeasonStatistics> seasonStatistics)
{
var movieStatistics = new MovieStatistics
{
SeasonStatistics = seasonStatistics,
MovieId = seasonStatistics.First().MovieId,
EpisodeFileCount = seasonStatistics.Sum(s => s.EpisodeFileCount),
EpisodeCount = seasonStatistics.Sum(s => s.EpisodeCount),
TotalEpisodeCount = seasonStatistics.Sum(s => s.TotalEpisodeCount),
SizeOnDisk = seasonStatistics.Sum(s => s.SizeOnDisk)
};
var nextAiring = seasonStatistics.Where(s => s.NextAiring != null)
.OrderBy(s => s.NextAiring)
.FirstOrDefault();
var previousAiring = seasonStatistics.Where(s => s.PreviousAiring != null)
.OrderBy(s => s.PreviousAiring)
.LastOrDefault();
movieStatistics.NextAiringString = nextAiring != null ? nextAiring.NextAiringString : null;
movieStatistics.PreviousAiringString = previousAiring != null ? previousAiring.PreviousAiringString : null;
return movieStatistics;
}
}
}

View File

@@ -1,41 +0,0 @@
using System;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.MovieStats
{
public class SeasonStatistics : ResultSet
{
public int MovieId { get; set; }
public int SeasonNumber { get; set; }
public string NextAiringString { get; set; }
public string PreviousAiringString { get; set; }
public int EpisodeFileCount { get; set; }
public int EpisodeCount { get; set; }
public int TotalEpisodeCount { get; set; }
public long SizeOnDisk { get; set; }
public DateTime? NextAiring
{
get
{
DateTime nextAiring;
if (!DateTime.TryParse(NextAiringString, out nextAiring)) return null;
return nextAiring;
}
}
public DateTime? PreviousAiring
{
get
{
DateTime previousAiring;
if (!DateTime.TryParse(PreviousAiringString, out previousAiring)) return null;
return previousAiring;
}
}
}
}

View File

@@ -1,7 +1,6 @@
using System.Collections.Generic;
using FluentValidation.Results;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Notifications.Boxcar
{
@@ -15,29 +14,18 @@ namespace NzbDrone.Core.Notifications.Boxcar
}
public override string Link => "https://boxcar.io/client";
public override string Name => "Boxcar";
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Episode Grabbed";
_proxy.SendNotification(title, grabMessage.Message, Settings);
_proxy.SendNotification(EPISODE_GRABBED_TITLE, grabMessage.Message, Settings);
}
public override void OnDownload(DownloadMessage message)
{
const string title = "Episode Downloaded";
_proxy.SendNotification(title, message.Message, Settings);
_proxy.SendNotification(EPISODE_DOWNLOADED_TITLE , message.Message, Settings);
}
public override void OnRename(Series series)
{
}
public override string Name => "Boxcar";
public override bool SupportsOnRename => false;
public override ValidationResult Test()
{
var failures = new List<ValidationFailure>();

View File

@@ -24,6 +24,8 @@ namespace NzbDrone.Core.Notifications.CustomScript
_logger = logger;
}
public override string Name => "Custom Script";
public override string Link => "https://github.com/Sonarr/Sonarr/wiki/Custom-Post-Processing-Scripts";
public override void OnGrab(GrabMessage message)
@@ -95,7 +97,6 @@ namespace NzbDrone.Core.Notifications.CustomScript
ExecuteScript(environmentVariables);
}
public override string Name => "Custom Script";
public override ValidationResult Test()
{

View File

@@ -9,6 +9,9 @@ namespace NzbDrone.Core.Notifications.Email
{
private readonly IEmailService _emailService;
public override string Name => "Email";
public Email(IEmailService emailService)
{
_emailService = emailService;
@@ -18,27 +21,18 @@ namespace NzbDrone.Core.Notifications.Email
public override void OnGrab(GrabMessage grabMessage)
{
const string subject = "Sonarr [TV] - Grabbed";
var body = string.Format("{0} sent to queue.", grabMessage.Message);
var body = $"{grabMessage.Message} sent to queue.";
_emailService.SendEmail(Settings, subject, body);
_emailService.SendEmail(Settings, EPISODE_GRABBED_TITLE_BRANDED, body);
}
public override void OnDownload(DownloadMessage message)
{
const string subject = "Sonarr [TV] - Downloaded";
var body = string.Format("{0} Downloaded and sorted.", message.Message);
var body = $"{message.Message} Downloaded and sorted.";
_emailService.SendEmail(Settings, subject, body);
_emailService.SendEmail(Settings, EPISODE_DOWNLOADED_TITLE_BRANDED, body);
}
public override void OnRename(Series series)
{
}
public override string Name => "Email";
public override bool SupportsOnRename => false;
public override ValidationResult Test()
{

View File

@@ -9,6 +9,9 @@ namespace NzbDrone.Core.Notifications.Growl
{
private readonly IGrowlService _growlService;
public override string Name => "Growl";
public Growl(IGrowlService growlService)
{
_growlService = growlService;
@@ -18,25 +21,14 @@ namespace NzbDrone.Core.Notifications.Growl
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Episode Grabbed";
_growlService.SendNotification(title, grabMessage.Message, "GRAB", Settings.Host, Settings.Port, Settings.Password);
_growlService.SendNotification(EPISODE_GRABBED_TITLE, grabMessage.Message, "GRAB", Settings.Host, Settings.Port, Settings.Password);
}
public override void OnDownload(DownloadMessage message)
{
const string title = "Episode Downloaded";
_growlService.SendNotification(title, message.Message, "DOWNLOAD", Settings.Host, Settings.Port, Settings.Password);
_growlService.SendNotification(EPISODE_GRABBED_TITLE, message.Message, "DOWNLOAD", Settings.Host, Settings.Port, Settings.Password);
}
public override void OnRename(Series series)
{
}
public override string Name => "Growl";
public override bool SupportsOnRename => false;
public override ValidationResult Test()
{

View File

@@ -1,7 +1,6 @@
using System.Collections.Generic;
using FluentValidation.Results;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Notifications.Join
{
@@ -14,30 +13,20 @@ namespace NzbDrone.Core.Notifications.Join
_proxy = proxy;
}
public override string Link => "https://joinjoaomgcd.appspot.com/";
public override string Name => "Join";
public override string Link => "https://joaoapps.com/join/";
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Sonarr - Episode Grabbed";
_proxy.SendNotification(title, grabMessage.Message, Settings);
_proxy.SendNotification(EPISODE_GRABBED_TITLE_BRANDED, Message.Message, Settings);
}
public override void OnDownload(DownloadMessage message)
{
const string title = "Sonarr - Episode Downloaded";
_proxy.SendNotification(title, message.Message, Settings);
_proxy.SendNotification(EPISODE_DOWNLOADED_TITLE_BRANDED, message.Message, Settings);
}
public override void OnRename(Series series)
{
}
public override string Name => "Join";
public override bool SupportsOnRename => false;
public override ValidationResult Test()
{
var failures = new List<ValidationFailure>();

View File

@@ -3,7 +3,7 @@ using FluentValidation.Results;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Notifications.MediaBrowser
namespace NzbDrone.Core.Notifications.Emby
{
public class MediaBrowser : NotificationBase<MediaBrowserSettings>
{
@@ -14,25 +14,23 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
_mediaBrowserService = mediaBrowserService;
}
public override string Link => "http://mediabrowser.tv/";
public override string Link => "https://emby.media/";
public override string Name => "Emby (Media Browser)";
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Sonarr - Grabbed";
if (Settings.Notify)
{
_mediaBrowserService.Notify(Settings, title, grabMessage.Message);
_mediaBrowserService.Notify(Settings, EPISODE_GRABBED_TITLE_BRANDED, grabMessage.Message);
}
}
public override void OnDownload(DownloadMessage message)
{
const string title = "Sonarr - Downloaded";
if (Settings.Notify)
{
_mediaBrowserService.Notify(Settings, title, message.Message);
_mediaBrowserService.Notify(Settings, EPISODE_DOWNLOADED_TITLE_BRANDED, message.Message);
}
if (Settings.UpdateLibrary)
@@ -49,7 +47,6 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
}
}
public override string Name => "Emby (Media Browser)";
public override ValidationResult Test()
{

View File

@@ -2,7 +2,7 @@
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
namespace NzbDrone.Core.Notifications.MediaBrowser
namespace NzbDrone.Core.Notifications.Emby
{
public class MediaBrowserProxy
{

View File

@@ -5,7 +5,7 @@ using NLog;
using NzbDrone.Core.Rest;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Notifications.MediaBrowser
namespace NzbDrone.Core.Notifications.Emby
{
public interface IMediaBrowserService
{

View File

@@ -4,7 +4,7 @@ using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Notifications.MediaBrowser
namespace NzbDrone.Core.Notifications.Emby
{
public class MediaBrowserSettingsValidator : AbstractValidator<MediaBrowserSettings>
{
@@ -40,7 +40,7 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
public bool UpdateLibrary { get; set; }
[JsonIgnore]
public string Address => string.Format("{0}:{1}", Host, Port);
public string Address => $"{Host}:{Port}";
public bool IsValid => !string.IsNullOrWhiteSpace(Host) && Port > 0;

View File

@@ -8,6 +8,12 @@ namespace NzbDrone.Core.Notifications
{
public abstract class NotificationBase<TSettings> : INotification where TSettings : IProviderConfig, new()
{
protected const string EPISODE_GRABBED_TITLE = "Episode Grabbed";
protected const string EPISODE_DOWNLOADED_TITLE = "Episode Downloaded";
protected const string EPISODE_GRABBED_TITLE_BRANDED = "Sonarr - " + EPISODE_GRABBED_TITLE;
protected const string EPISODE_DOWNLOADED_TITLE_BRANDED = "Sonarr - " + EPISODE_DOWNLOADED_TITLE;
public abstract string Name { get; }
public Type ConfigContract => typeof(TSettings);
@@ -21,14 +27,25 @@ namespace NzbDrone.Core.Notifications
public abstract string Link { get; }
public abstract void OnGrab(GrabMessage grabMessage);
public abstract void OnDownload(DownloadMessage message);
public abstract void OnRename(Series series);
public virtual void OnGrab(GrabMessage grabMessage)
{
public virtual bool SupportsOnGrab => true;
public virtual bool SupportsOnDownload => true;
public virtual bool SupportsOnUpgrade => true;
public virtual bool SupportsOnRename => true;
}
public virtual void OnDownload(DownloadMessage message)
{
}
public virtual void OnRename(Series series)
{
}
public bool SupportsOnGrab => HasConcreteImplementation("OnGrab");
public bool SupportsOnRename => HasConcreteImplementation("OnRename");
public bool SupportsOnDownload => HasConcreteImplementation("OnDownload");
public bool SupportsOnUpgrade => SupportsOnDownload;
protected TSettings Settings => (TSettings)Definition.Settings;
@@ -39,5 +56,18 @@ namespace NzbDrone.Core.Notifications
public virtual object RequestAction(string action, IDictionary<string, string> query) { return null; }
private bool HasConcreteImplementation(string methodName)
{
var method = GetType().GetMethod(methodName);
if (method == null)
{
throw new MissingMethodException(GetType().Name, Name);
}
return !method.DeclaringType.IsAbstract;
}
}
}

View File

@@ -1,8 +1,6 @@

using System.Collections.Generic;
using System.Collections.Generic;
using FluentValidation.Results;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Notifications.NotifyMyAndroid
{
@@ -15,30 +13,19 @@ namespace NzbDrone.Core.Notifications.NotifyMyAndroid
_proxy = proxy;
}
public override string Link => "http://www.notifymyandroid.com/";
public override string Link => "https://www.notifymyandroid.com/";
public override string Name => "Notify My Android";
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Episode Grabbed";
_proxy.SendNotification(title, grabMessage.Message, Settings.ApiKey, (NotifyMyAndroidPriority)Settings.Priority);
_proxy.SendNotification(EPISODE_GRABBED_TITLE, grabMessage.Message, Settings.ApiKey, (NotifyMyAndroidPriority)Settings.Priority);
}
public override void OnDownload(DownloadMessage message)
{
const string title = "Episode Downloaded";
_proxy.SendNotification(title, message.Message, Settings.ApiKey, (NotifyMyAndroidPriority)Settings.Priority);
_proxy.SendNotification(EPISODE_DOWNLOADED_TITLE, message.Message, Settings.ApiKey, (NotifyMyAndroidPriority)Settings.Priority);
}
public override void OnRename(Series series)
{
}
public override string Name => "Notify My Android";
public override bool SupportsOnRename => false;
public override ValidationResult Test()
{
var failures = new List<ValidationFailure>();

View File

@@ -9,32 +9,24 @@ namespace NzbDrone.Core.Notifications.Plex
{
private readonly IPlexClientService _plexClientService;
public override string Link => "https://www.plex.tv/";
public override string Name => "Plex Media Center";
public PlexClient(IPlexClientService plexClientService)
{
_plexClientService = plexClientService;
}
public override string Link => "http://www.plexapp.com/";
public override void OnGrab(GrabMessage grabMessage)
{
const string header = "Sonarr [TV] - Grabbed";
_plexClientService.Notify(Settings, header, grabMessage.Message);
_plexClientService.Notify(Settings, EPISODE_GRABBED_TITLE_BRANDED, grabMessage.Message);
}
public override void OnDownload(DownloadMessage message)
{
const string header = "Sonarr [TV] - Downloaded";
_plexClientService.Notify(Settings, header, message.Message);
_plexClientService.Notify(Settings, EPISODE_DOWNLOADED_TITLE_BRANDED, message.Message);
}
public override void OnRename(Series series)
{
}
public override string Name => "Plex Media Center";
public override bool SupportsOnRename => false;
public override ValidationResult Test()
{

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