Merge Develop into Net-Import
BIN
Logo/1024.png
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 48 KiB |
BIN
Logo/128.png
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 5.1 KiB |
BIN
Logo/16.png
Before Width: | Height: | Size: 811 B After Width: | Height: | Size: 701 B |
BIN
Logo/256.png
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 11 KiB |
BIN
Logo/32.png
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
Logo/400.png
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 17 KiB |
BIN
Logo/48.png
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 2 KiB |
BIN
Logo/512.png
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 22 KiB |
BIN
Logo/64.png
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 2.6 KiB |
BIN
Logo/800.png
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 37 KiB |
597
Logo/Radarr.svg
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 31 KiB |
|
@ -61,6 +61,8 @@ To connect to the UI, fire up your browser and open <http://localhost:7878> or <
|
|||
* Importing movies from various online sources, such as IMDb Watchlists (A complete list can be found [here](https://github.com/Radarr/Radarr/issues/114))
|
||||
* Full integration with Kodi, Plex (notification, library update, metadata)
|
||||
|
||||
##Feature Requests
|
||||
[](http://feathub.com/Radarr/Radarr)
|
||||
|
||||
## Configuring Development Environment
|
||||
|
||||
|
|
|
@ -64,6 +64,8 @@ namespace NzbDrone.Api.Authentication
|
|||
new DefaultHmacProvider(new PassphraseKeyGenerator(_configService.HmacPassphrase, Encoding.ASCII.GetBytes(_configService.HmacSalt)))
|
||||
);
|
||||
|
||||
FormsAuthentication.FormsAuthenticationCookieName = "_ncfaradarr"; //For those people that both have sonarr and radarr.
|
||||
|
||||
FormsAuthentication.Enable(pipelines, new FormsAuthenticationConfiguration
|
||||
{
|
||||
RedirectUrl = _configFileProvider.UrlBase + "/login",
|
||||
|
|
|
@ -35,21 +35,21 @@ namespace NzbDrone.Api.EpisodeFiles
|
|||
_seriesService = seriesService;
|
||||
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
||||
_logger = logger;
|
||||
/*GetResourceById = GetEpisodeFile;
|
||||
GetResourceAll = GetEpisodeFiles;
|
||||
GetResourceById = GetMovieFile;
|
||||
/*GetResourceAll = GetEpisodeFiles;
|
||||
UpdateResource = SetQuality;*/
|
||||
UpdateResource = SetQuality;
|
||||
DeleteResource = DeleteEpisodeFile;
|
||||
}
|
||||
|
||||
/*private EpisodeFileResource GetEpisodeFile(int id)
|
||||
private MovieFileResource GetMovieFile(int id)
|
||||
{
|
||||
var episodeFile = _mediaFileService.Get(id);
|
||||
var series = _seriesService.GetSeries(episodeFile.SeriesId);
|
||||
var episodeFile = _mediaFileService.GetMovie(id);
|
||||
|
||||
return episodeFile.ToResource(series, _qualityUpgradableSpecification);
|
||||
return episodeFile.ToResource();
|
||||
}
|
||||
|
||||
private List<EpisodeFileResource> GetEpisodeFiles()
|
||||
/*private List<EpisodeFileResource> GetEpisodeFiles()
|
||||
{
|
||||
if (!Request.Query.SeriesId.HasValue)
|
||||
{
|
||||
|
@ -62,13 +62,13 @@ namespace NzbDrone.Api.EpisodeFiles
|
|||
|
||||
return _mediaFileService.GetFilesBySeries(seriesId).ConvertAll(f => f.ToResource(series, _qualityUpgradableSpecification));
|
||||
}
|
||||
|
||||
private void SetQuality(EpisodeFileResource episodeFileResource)
|
||||
*/
|
||||
private void SetQuality(MovieFileResource episodeFileResource)
|
||||
{
|
||||
var episodeFile = _mediaFileService.Get(episodeFileResource.Id);
|
||||
var episodeFile = _mediaFileService.GetMovie(episodeFileResource.Id);
|
||||
episodeFile.Quality = episodeFileResource.Quality;
|
||||
_mediaFileService.Update(episodeFile);
|
||||
}*/
|
||||
}
|
||||
|
||||
private void DeleteEpisodeFile(int id)
|
||||
{
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace NzbDrone.Api.Profiles
|
|||
{
|
||||
public string Name { get; set; }
|
||||
public Quality Cutoff { get; set; }
|
||||
public string PreferredTags { get; set; }
|
||||
public List<ProfileQualityItemResource> Items { get; set; }
|
||||
public Language Language { get; set; }
|
||||
}
|
||||
|
@ -33,6 +34,7 @@ namespace NzbDrone.Api.Profiles
|
|||
|
||||
Name = model.Name,
|
||||
Cutoff = model.Cutoff,
|
||||
PreferredTags = model.PreferredTags != null ? string.Join(",", model.PreferredTags) : "",
|
||||
Items = model.Items.ConvertAll(ToResource),
|
||||
Language = model.Language
|
||||
};
|
||||
|
@ -59,6 +61,7 @@ namespace NzbDrone.Api.Profiles
|
|||
|
||||
Name = resource.Name,
|
||||
Cutoff = (Quality)resource.Cutoff.Id,
|
||||
PreferredTags = resource.PreferredTags.Split(',').ToList(),
|
||||
Items = resource.Items.ConvertAll(ToModel),
|
||||
Language = resource.Language
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace NzbDrone.Api.Validation
|
|||
public class RssSyncIntervalValidator : PropertyValidator
|
||||
{
|
||||
public RssSyncIntervalValidator()
|
||||
: base("Must be between 10 and 120 or 0 to disable")
|
||||
: base("Must be between 10 and 720 or 0 to disable")
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ namespace NzbDrone.Api.Validation
|
|||
return true;
|
||||
}
|
||||
|
||||
if (value >= 10 && value <= 120)
|
||||
if (value >= 10 && value <= 720)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 81 KiB |
|
@ -32,7 +32,7 @@ namespace NzbDrone.Core.Test.Configuration
|
|||
[Test]
|
||||
public void Get_value_should_return_default_when_no_value()
|
||||
{
|
||||
Subject.RssSyncInterval.Should().Be(15);
|
||||
Subject.RssSyncInterval.Should().Be(60);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -47,7 +47,7 @@ namespace NzbDrone.Core.Test.Configuration
|
|||
public void get_value_with_out_persist_should_not_store_default_value()
|
||||
{
|
||||
var interval = Subject.RssSyncInterval;
|
||||
interval.Should().Be(15);
|
||||
interval.Should().Be(60);
|
||||
Mocker.GetMock<IConfigRepository>().Verify(c => c.Insert(It.IsAny<Config>()), Times.Never());
|
||||
}
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ namespace NzbDrone.Core.Configuration
|
|||
|
||||
public int RssSyncInterval
|
||||
{
|
||||
get { return GetValueInt("RssSyncInterval", 15); }
|
||||
get { return GetValueInt("RssSyncInterval", 60); }
|
||||
|
||||
set { SetValue("RssSyncInterval", value); }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
using System.Data;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(124)]
|
||||
public class add_preferred_tags_to_profile : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Alter.Table("Profiles").AddColumn("PreferredTags").AsString().Nullable();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
31
src/NzbDrone.Core/Datastore/Migration/125_fix_imdb_unique.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
using System.Data;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(125)]
|
||||
public class fix_imdb_unique : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Execute.WithConnection(DeleteUniqueIndex);
|
||||
}
|
||||
|
||||
private void DeleteUniqueIndex(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
using (IDbCommand getSeriesCmd = conn.CreateCommand())
|
||||
{
|
||||
getSeriesCmd.Transaction = tran;
|
||||
getSeriesCmd.CommandText = @"DROP INDEX 'IX_Movies_ImdbId'";
|
||||
|
||||
getSeriesCmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ namespace NzbDrone.Core.DecisionEngine
|
|||
var comparers = new List<CompareDelegate>
|
||||
{
|
||||
CompareQuality,
|
||||
ComparePreferredWords,
|
||||
CompareProtocol,
|
||||
ComparePeersIfTorrent,
|
||||
CompareAgeIfUsenet,
|
||||
|
@ -65,6 +66,26 @@ namespace NzbDrone.Core.DecisionEngine
|
|||
CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.ParsedEpisodeInfo.Quality.Revision.Version));
|
||||
}
|
||||
|
||||
private int ComparePreferredWords(DownloadDecision x, DownloadDecision y)
|
||||
{
|
||||
return CompareBy(x.RemoteMovie, y.RemoteMovie, remoteMovie =>
|
||||
{
|
||||
var title = remoteMovie.Release.Title;
|
||||
remoteMovie.Movie.Profile.LazyLoad();
|
||||
var preferredWords = remoteMovie.Movie.Profile.Value.PreferredTags;
|
||||
|
||||
if (preferredWords == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var num = preferredWords.AsEnumerable().Count(w => title.ToLower().Contains(w.ToLower()));
|
||||
|
||||
return num;
|
||||
|
||||
});
|
||||
; }
|
||||
|
||||
private int CompareProtocol(DownloadDecision x, DownloadDecision y)
|
||||
{
|
||||
|
||||
|
|
|
@ -19,7 +19,21 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
|||
|
||||
public Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
if (searchCriteria != null)
|
||||
{
|
||||
if (searchCriteria.UserInvokedSearch)
|
||||
{
|
||||
_logger.Debug("Skipping monitored check during search");
|
||||
return Decision.Accept();
|
||||
}
|
||||
}
|
||||
|
||||
if (!subject.Movie.Monitored)
|
||||
{
|
||||
return Decision.Reject("Movie is not monitored");
|
||||
}
|
||||
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace NzbDrone.Core.Download
|
|||
public ProcessedDecisions ProcessDecisions(List<DownloadDecision> decisions)
|
||||
{
|
||||
//var qualifiedReports = GetQualifiedReports(decisions);
|
||||
var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(decisions);
|
||||
var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisionsForMovies(decisions);
|
||||
var grabbed = new List<DownloadDecision>();
|
||||
var pending = new List<DownloadDecision>();
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ using NzbDrone.Core.IndexerSearch;
|
|||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Tv;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.Download
|
||||
{
|
||||
|
@ -38,7 +39,7 @@ namespace NzbDrone.Core.Download
|
|||
{
|
||||
_logger.Debug("Failed download contains a movie, searching again.");
|
||||
|
||||
_commandQueueManager.Push(new MoviesSearchCommand { MovieId = message.MovieId });
|
||||
_commandQueueManager.Push(new MoviesSearchCommand { MovieIds = new List<int> { message.MovieId } });
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -102,13 +102,13 @@ namespace NzbDrone.Core.Extras
|
|||
|
||||
public void Handle(MediaCoversUpdatedEvent message)
|
||||
{
|
||||
var series = message.Series;
|
||||
var episodeFiles = GetEpisodeFiles(series.Id);
|
||||
//var series = message.Series;
|
||||
//var episodeFiles = GetEpisodeFiles(series.Id);
|
||||
|
||||
foreach (var extraFileManager in _extraFileManagers)
|
||||
{
|
||||
extraFileManager.CreateAfterSeriesScan(series, episodeFiles);
|
||||
}
|
||||
//foreach (var extraFileManager in _extraFileManagers)
|
||||
//{
|
||||
// extraFileManager.CreateAfterSeriesScan(series, episodeFiles);
|
||||
//}
|
||||
}
|
||||
|
||||
//TODO: Implementing this will fix a lot of our warning exceptions
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
using NzbDrone.Core.Messaging.Commands;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.IndexerSearch
|
||||
{
|
||||
public class MissingMoviesSearchCommand : Command
|
||||
{
|
||||
public override bool SendUpdatesToClient => true;
|
||||
}
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
using NzbDrone.Core.Messaging.Commands;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.IndexerSearch
|
||||
{
|
||||
public class MoviesSearchCommand : Command
|
||||
{
|
||||
public int MovieId { get; set; }
|
||||
public List<int> MovieIds { get; set; }
|
||||
|
||||
public override bool SendUpdatesToClient => true;
|
||||
}
|
||||
|
|
|
@ -4,22 +4,23 @@ using NzbDrone.Common.Instrumentation.Extensions;
|
|||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Datastore;
|
||||
|
||||
namespace NzbDrone.Core.IndexerSearch
|
||||
{
|
||||
public class MovieSearchService : IExecute<MoviesSearchCommand>
|
||||
public class MovieSearchService : IExecute<MoviesSearchCommand>, IExecute<MissingMoviesSearchCommand>
|
||||
{
|
||||
private readonly IMovieService _seriesService;
|
||||
private readonly IMovieService _movieService;
|
||||
private readonly ISearchForNzb _nzbSearchService;
|
||||
private readonly IProcessDownloadDecisions _processDownloadDecisions;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public MovieSearchService(IMovieService seriesService,
|
||||
public MovieSearchService(IMovieService movieService,
|
||||
ISearchForNzb nzbSearchService,
|
||||
IProcessDownloadDecisions processDownloadDecisions,
|
||||
Logger logger)
|
||||
{
|
||||
_seriesService = seriesService;
|
||||
_movieService = movieService;
|
||||
_nzbSearchService = nzbSearchService;
|
||||
_processDownloadDecisions = processDownloadDecisions;
|
||||
_logger = logger;
|
||||
|
@ -27,20 +28,35 @@ namespace NzbDrone.Core.IndexerSearch
|
|||
|
||||
public void Execute(MoviesSearchCommand message)
|
||||
{
|
||||
var series = _seriesService.GetMovie(message.MovieId);
|
||||
|
||||
var downloadedCount = 0;
|
||||
|
||||
foreach (var movieId in message.MovieIds)
|
||||
{
|
||||
var series = _movieService.GetMovie(movieId);
|
||||
|
||||
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);
|
||||
var decisions = _nzbSearchService.MovieSearch(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);
|
||||
}
|
||||
|
||||
public void Execute(MissingMoviesSearchCommand message)
|
||||
{
|
||||
var movies = _movieService.MoviesWithoutFiles(new PagingSpec<Movie>
|
||||
{
|
||||
Page = 1,
|
||||
PageSize = 100000,
|
||||
SortDirection = SortDirection.Ascending,
|
||||
SortKey = "Id",
|
||||
FilterExpression =
|
||||
v =>
|
||||
v.Monitored == true
|
||||
}).Records.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,13 +54,19 @@ namespace NzbDrone.Core.Indexers.AwesomeHD
|
|||
|
||||
private IEnumerable<IndexerRequest> GetRequest(string searchParameters)
|
||||
{
|
||||
var onlyInternal = "";
|
||||
if (Settings.Internal)
|
||||
{
|
||||
onlyInternal = "&internal=true";
|
||||
}
|
||||
|
||||
if (searchParameters != null)
|
||||
{
|
||||
yield return new IndexerRequest(string.Format("{0}/searchapi.php?action=imdbsearch&passkey={1}&imdb={2}", Settings.BaseUrl.Trim().TrimEnd('/'), Settings.Passkey.Trim(), searchParameters), HttpAccept.Rss);
|
||||
yield return new IndexerRequest($"{Settings.BaseUrl.Trim().TrimEnd('/')}/searchapi.php?action=imdbsearch&passkey={Settings.Passkey.Trim()}&imdb={searchParameters}", HttpAccept.Rss);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new IndexerRequest(string.Format("{0}/searchapi.php?action=latestmovies&passkey={1}", Settings.BaseUrl.Trim().TrimEnd('/'), Settings.Passkey.Trim()), HttpAccept.Rss);
|
||||
yield return new IndexerRequest($"{Settings.BaseUrl.Trim().TrimEnd('/')}/searchapi.php?action=latestmovies&passkey={Settings.Passkey.Trim()}{onlyInternal}", HttpAccept.Rss);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@ namespace NzbDrone.Core.Indexers.AwesomeHD
|
|||
[FieldDefinition(1, Label = "Passkey")]
|
||||
public string Passkey { get; set; }
|
||||
|
||||
[FieldDefinition(2, Type = FieldType.Checkbox, Label = "Require Internal", HelpText = "Will only include internal releases for RSS Sync.")]
|
||||
public bool Internal { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
|
|
|
@ -31,12 +31,14 @@ namespace NzbDrone.Core.Jobs
|
|||
{
|
||||
private readonly IScheduledTaskRepository _scheduledTaskRepository;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly IConfigFileProvider _configFileProvider;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public TaskManager(IScheduledTaskRepository scheduledTaskRepository, IConfigService configService, Logger logger)
|
||||
public TaskManager(IScheduledTaskRepository scheduledTaskRepository, IConfigService configService, IConfigFileProvider configFileProvider, Logger logger)
|
||||
{
|
||||
_scheduledTaskRepository = scheduledTaskRepository;
|
||||
_configService = configService;
|
||||
_configFileProvider = configFileProvider;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
@ -60,11 +62,19 @@ namespace NzbDrone.Core.Jobs
|
|||
|
||||
public void Handle(ApplicationStartedEvent message)
|
||||
{
|
||||
float updateInterval = 6 * 60;
|
||||
|
||||
if (_configFileProvider.Branch == "nightly")
|
||||
{
|
||||
updateInterval = 30;
|
||||
}
|
||||
|
||||
var defaultTasks = new[]
|
||||
{
|
||||
new ScheduledTask{ Interval = 0.25f, TypeName = typeof(CheckForFinishedDownloadCommand).FullName},
|
||||
new ScheduledTask{ Interval = 5, TypeName = typeof(MessagingCleanupCommand).FullName},
|
||||
new ScheduledTask{ Interval = 6*60, TypeName = typeof(ApplicationUpdateCommand).FullName},
|
||||
new ScheduledTask{ Interval = updateInterval, TypeName = typeof(ApplicationUpdateCommand).FullName},
|
||||
// new ScheduledTask{ Interval = 3*60, TypeName = typeof(UpdateSceneMappingCommand).FullName},
|
||||
new ScheduledTask{ Interval = 12*60, TypeName = typeof(NetImportSyncCommand).FullName},
|
||||
new ScheduledTask{ Interval = 6*60, TypeName = typeof(CheckHealthCommand).FullName},
|
||||
new ScheduledTask{ Interval = 24*60, TypeName = typeof(RefreshMovieCommand).FullName},
|
||||
|
|
|
@ -46,11 +46,18 @@ namespace NzbDrone.Core.MediaCover
|
|||
{
|
||||
try
|
||||
{
|
||||
GdiPlusInterop.CheckGdiPlus();
|
||||
|
||||
using (var bmp = new Bitmap(filename))
|
||||
{
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (DllNotFoundException ex)
|
||||
{
|
||||
_logger.Error(ex, "Could not find libgdiplus. Cannot test if image is corrupt.");
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Debug(ex, "Corrupted image found at: {0}. Redownloading...", filename);
|
||||
|
|
|
@ -128,7 +128,48 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||
var current = localMovie.Quality;
|
||||
var qualityName = current.Quality.Name.ToLower();
|
||||
QualityModel updated = null;
|
||||
if (width > 1400)
|
||||
if (width > 2000)
|
||||
{
|
||||
if (qualityName.Contains("bluray"))
|
||||
{
|
||||
updated = new QualityModel(Quality.Bluray2160p);
|
||||
}
|
||||
|
||||
else if (qualityName.Contains("webdl"))
|
||||
{
|
||||
updated = new QualityModel(Quality.WEBDL2160p);
|
||||
}
|
||||
|
||||
else if (qualityName.Contains("hdtv"))
|
||||
{
|
||||
updated = new QualityModel(Quality.HDTV2160p);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
var def = _qualitiesService.Get(Quality.HDTV2160p);
|
||||
if (localMovie.Size > def.MinSize && def.MaxSize > localMovie.Size)
|
||||
{
|
||||
updated = new QualityModel(Quality.HDTV2160p);
|
||||
}
|
||||
def = _qualitiesService.Get(Quality.WEBDL2160p);
|
||||
if (localMovie.Size > def.MinSize && def.MaxSize > localMovie.Size)
|
||||
{
|
||||
updated = new QualityModel(Quality.WEBDL2160p);
|
||||
}
|
||||
def = _qualitiesService.Get(Quality.Bluray2160p);
|
||||
if (localMovie.Size > def.MinSize && def.MaxSize > localMovie.Size)
|
||||
{
|
||||
updated = new QualityModel(Quality.Bluray2160p);
|
||||
}
|
||||
if (updated == null)
|
||||
{
|
||||
updated = new QualityModel(Quality.Bluray2160p);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (width > 1400)
|
||||
{
|
||||
if (qualityName.Contains("bluray"))
|
||||
{
|
||||
|
@ -147,7 +188,6 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||
|
||||
else
|
||||
{
|
||||
|
||||
var def = _qualitiesService.Get(Quality.HDTV1080p);
|
||||
if (localMovie.Size > def.MinSize && def.MaxSize > localMovie.Size)
|
||||
{
|
||||
|
|
|
@ -49,14 +49,12 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
|||
return AudioChannelPositionsText.ContainsIgnoreCase("LFE") ? AudioChannels - 1 + 0.1m : AudioChannels;
|
||||
}
|
||||
|
||||
return
|
||||
AudioChannelPositions.Replace(" / ", "$")
|
||||
.Split('$')
|
||||
.First()
|
||||
.Split('/')
|
||||
.Sum(s => decimal.Parse(s, CultureInfo.InvariantCulture));
|
||||
|
||||
|
||||
return
|
||||
AudioChannelPositions.Replace("Object Based /", "").Replace(" / ", "$")
|
||||
.Split('$')
|
||||
.First()
|
||||
.Split('/')
|
||||
.Sum(s => decimal.Parse(s, CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
}
|
||||
else
|
||||
{
|
||||
_logger.Warn("The existing movie file was not lazy loaded.");
|
||||
//_logger.Warn("The existing movie file was not lazy loaded.");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Profiles;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.MetadataSource
|
||||
|
@ -7,6 +8,6 @@ namespace NzbDrone.Core.MetadataSource
|
|||
public interface IProvideMovieInfo
|
||||
{
|
||||
Movie GetMovieInfo(string ImdbId);
|
||||
Movie GetMovieInfo(int TmdbId);
|
||||
Movie GetMovieInfo(int TmdbId, Profile profile);
|
||||
}
|
||||
}
|
|
@ -14,6 +14,8 @@ using NzbDrone.Core.Tv;
|
|||
using Newtonsoft.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Text;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Profiles;
|
||||
|
||||
namespace NzbDrone.Core.MetadataSource.SkyHook
|
||||
{
|
||||
|
@ -67,21 +69,23 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
|||
return new Tuple<Series, List<Episode>>(series, episodes.ToList());
|
||||
}
|
||||
|
||||
public Movie GetMovieInfo(int TmdbId)
|
||||
public Movie GetMovieInfo(int TmdbId, Profile profile = null)
|
||||
{
|
||||
var langCode = profile != null ? IsoLanguages.Get(profile.Language).TwoLetterCode : "us";
|
||||
|
||||
var request = _movieBuilder.Create()
|
||||
.SetSegment("route", "movie")
|
||||
.SetSegment("id", TmdbId.ToString())
|
||||
.SetSegment("secondaryRoute", "")
|
||||
.AddQueryParam("append_to_response", "alternative_titles,release_dates,videos")
|
||||
.AddQueryParam("country", "US")
|
||||
.AddQueryParam("language", langCode.ToUpper())
|
||||
// .AddQueryParam("country", "US")
|
||||
.Build();
|
||||
|
||||
request.AllowAutoRedirect = true;
|
||||
request.SuppressHttpError = true;
|
||||
|
||||
var response = _httpClient.Get<MovieResourceRoot>(request);
|
||||
|
||||
var resource = response.Resource;
|
||||
|
||||
if (resource.status_message != null)
|
||||
|
@ -98,6 +102,18 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
|||
|
||||
var movie = new Movie();
|
||||
|
||||
foreach (var alternativeTitle in resource.alternative_titles.titles)
|
||||
{
|
||||
if (alternativeTitle.iso_3166_1.ToLower() == langCode)
|
||||
{
|
||||
movie.AlternativeTitles.Add(alternativeTitle.title);
|
||||
}
|
||||
else if (alternativeTitle.iso_3166_1.ToLower() == "us")
|
||||
{
|
||||
movie.AlternativeTitles.Add(alternativeTitle.title);
|
||||
}
|
||||
}
|
||||
|
||||
movie.TmdbId = TmdbId;
|
||||
movie.ImdbId = resource.imdb_id;
|
||||
movie.Title = resource.title;
|
||||
|
@ -118,10 +134,10 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
|||
movie.Images.Add(_configService.GetCoverForURL(resource.backdrop_path, MediaCoverTypes.Banner));
|
||||
movie.Runtime = resource.runtime;
|
||||
|
||||
foreach(Title title in resource.alternative_titles.titles)
|
||||
{
|
||||
movie.AlternativeTitles.Add(title.title);
|
||||
}
|
||||
//foreach(Title title in resource.alternative_titles.titles)
|
||||
//{
|
||||
// movie.AlternativeTitles.Add(title.title);
|
||||
//}
|
||||
|
||||
foreach(ReleaseDates releaseDates in resource.release_dates.results)
|
||||
{
|
||||
|
@ -161,7 +177,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
|||
{
|
||||
movie.Status = MovieStatusType.Announced;
|
||||
}
|
||||
|
||||
|
||||
if (resource.videos != null)
|
||||
{
|
||||
foreach (Video video in resource.videos.results)
|
||||
|
|
|
@ -18,18 +18,22 @@ namespace NzbDrone.Core.Notifications.Boxcar
|
|||
|
||||
public override void OnGrab(GrabMessage grabMessage)
|
||||
{
|
||||
const string title = "Episode Grabbed";
|
||||
const string title = "Movie Grabbed";
|
||||
|
||||
_proxy.SendNotification(title, grabMessage.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnDownload(DownloadMessage message)
|
||||
{
|
||||
const string title = "Episode Downloaded";
|
||||
const string title = "Movie Downloaded";
|
||||
|
||||
_proxy.SendNotification(title, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
@ -24,75 +25,66 @@ namespace NzbDrone.Core.Notifications.CustomScript
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public override string Link => "https://github.com/Sonarr/Sonarr/wiki/Custom-Post-Processing-Scripts";
|
||||
public override string Link => "https://github.com/Radarr/Radarr/wiki/Custom-Post-Processing-Scripts";
|
||||
|
||||
public override void OnGrab(GrabMessage message)
|
||||
{
|
||||
var series = message.Series;
|
||||
var remoteEpisode = message.Episode;
|
||||
var releaseGroup = remoteEpisode.ParsedEpisodeInfo.ReleaseGroup;
|
||||
var movie = message.Movie;
|
||||
var remoteMovie = message.RemoteMovie;
|
||||
var releaseGroup = remoteMovie.ParsedMovieInfo.ReleaseGroup;
|
||||
var environmentVariables = new StringDictionary();
|
||||
|
||||
environmentVariables.Add("Sonarr_EventType", "Grab");
|
||||
environmentVariables.Add("Sonarr_Series_Id", series.Id.ToString());
|
||||
environmentVariables.Add("Sonarr_Series_Title", series.Title);
|
||||
environmentVariables.Add("Sonarr_Series_TvdbId", series.TvdbId.ToString());
|
||||
environmentVariables.Add("Sonarr_Series_Type", series.SeriesType.ToString());
|
||||
environmentVariables.Add("Sonarr_Release_EpisodeCount", remoteEpisode.Episodes.Count.ToString());
|
||||
environmentVariables.Add("Sonarr_Release_SeasonNumber", remoteEpisode.ParsedEpisodeInfo.SeasonNumber.ToString());
|
||||
environmentVariables.Add("Sonarr_Release_EpisodeNumbers", string.Join(",", remoteEpisode.Episodes.Select(e => e.EpisodeNumber)));
|
||||
environmentVariables.Add("Sonarr_Release_Title", remoteEpisode.Release.Title);
|
||||
environmentVariables.Add("Sonarr_Release_Indexer", remoteEpisode.Release.Indexer);
|
||||
environmentVariables.Add("Sonarr_Release_Size", remoteEpisode.Release.Size.ToString());
|
||||
environmentVariables.Add("Sonarr_Release_ReleaseGroup", releaseGroup);
|
||||
environmentVariables.Add("Radarr_EventType", "Grab");
|
||||
environmentVariables.Add("Radarr_Movie_Id", movie.Id.ToString());
|
||||
environmentVariables.Add("Radarr_Movie_Title", movie.Title);
|
||||
environmentVariables.Add("Radarr_Movie_ImdbId", movie.ImdbId.ToString());
|
||||
environmentVariables.Add("Radarr_Release_Title", remoteMovie.Release.Title);
|
||||
environmentVariables.Add("Radarr_Release_Indexer", remoteMovie.Release.Indexer);
|
||||
environmentVariables.Add("Radarr_Release_Size", remoteMovie.Release.Size.ToString());
|
||||
environmentVariables.Add("Radarr_Release_ReleaseGroup", releaseGroup);
|
||||
|
||||
ExecuteScript(environmentVariables);
|
||||
}
|
||||
|
||||
public override void OnDownload(DownloadMessage message)
|
||||
{
|
||||
var series = message.Series;
|
||||
var episodeFile = message.EpisodeFile;
|
||||
var movie = message.Movie;
|
||||
var movieFile = message.MovieFile;
|
||||
var sourcePath = message.SourcePath;
|
||||
var environmentVariables = new StringDictionary();
|
||||
|
||||
environmentVariables.Add("Sonarr_EventType", "Download");
|
||||
environmentVariables.Add("Sonarr_Series_Id", series.Id.ToString());
|
||||
environmentVariables.Add("Sonarr_Series_Title", series.Title);
|
||||
environmentVariables.Add("Sonarr_Series_Path", series.Path);
|
||||
environmentVariables.Add("Sonarr_Series_TvdbId", series.TvdbId.ToString());
|
||||
environmentVariables.Add("Sonarr_Series_Type", series.SeriesType.ToString());
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_Id", episodeFile.Id.ToString());
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeCount", episodeFile.Episodes.Value.Count.ToString());
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_RelativePath", episodeFile.RelativePath);
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_Path", Path.Combine(series.Path, episodeFile.RelativePath));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_SeasonNumber", episodeFile.SeasonNumber.ToString());
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeNumbers", string.Join(",", episodeFile.Episodes.Value.Select(e => e.EpisodeNumber)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeAirDates", string.Join(",", episodeFile.Episodes.Value.Select(e => e.AirDate)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeAirDatesUtc", string.Join(",", episodeFile.Episodes.Value.Select(e => e.AirDateUtc)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeTitles", string.Join("|", episodeFile.Episodes.Value.Select(e => e.Title)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_Quality", episodeFile.Quality.Quality.Name);
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_QualityVersion", episodeFile.Quality.Revision.Version.ToString());
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_ReleaseGroup", episodeFile.ReleaseGroup ?? string.Empty);
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_SceneName", episodeFile.SceneName ?? string.Empty);
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_SourcePath", sourcePath);
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_SourceFolder", Path.GetDirectoryName(sourcePath));
|
||||
environmentVariables.Add("Radarr_EventType", "Download");
|
||||
environmentVariables.Add("Radarr_Movie_Id", movie.Id.ToString());
|
||||
environmentVariables.Add("Radarr_Movie_Title", movie.Title);
|
||||
environmentVariables.Add("Radarr_Movie_Path", movie.Path);
|
||||
environmentVariables.Add("Radarr_Movie_ImdbId", movie.ImdbId.ToString());
|
||||
environmentVariables.Add("Radarr_MovieFile_Id", movieFile.Id.ToString());
|
||||
environmentVariables.Add("Radarr_MovieFile_RelativePath", movieFile.RelativePath);
|
||||
environmentVariables.Add("Radarr_MovieFile_Path", Path.Combine(movie.Path, movieFile.RelativePath));
|
||||
environmentVariables.Add("Radarr_MovieFile_Quality", movieFile.Quality.Quality.Name);
|
||||
environmentVariables.Add("Radarr_MovieFile_QualityVersion", movieFile.Quality.Revision.Version.ToString());
|
||||
environmentVariables.Add("Radarr_MovieFile_ReleaseGroup", movieFile.ReleaseGroup ?? string.Empty);
|
||||
environmentVariables.Add("Radarr_MovieFile_SceneName", movieFile.SceneName ?? string.Empty);
|
||||
environmentVariables.Add("Radarr_MovieFile_SourcePath", sourcePath);
|
||||
environmentVariables.Add("Radarr_MovieFile_SourceFolder", Path.GetDirectoryName(sourcePath));
|
||||
|
||||
ExecuteScript(environmentVariables);
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
var environmentVariables = new StringDictionary();
|
||||
|
||||
environmentVariables.Add("Radarr_EventType", "Rename");
|
||||
environmentVariables.Add("Radarr_Movie_Id", movie.Id.ToString());
|
||||
environmentVariables.Add("Radarr_Movie_Title", movie.Title);
|
||||
environmentVariables.Add("Radarr_Movie_Path", movie.Path);
|
||||
environmentVariables.Add("Radarr_Movie_TvdbId", movie.ImdbId.ToString());
|
||||
ExecuteScript(environmentVariables);
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
{
|
||||
var environmentVariables = new StringDictionary();
|
||||
|
||||
environmentVariables.Add("Sonarr_EventType", "Rename");
|
||||
environmentVariables.Add("Sonarr_Series_Id", series.Id.ToString());
|
||||
environmentVariables.Add("Sonarr_Series_Title", series.Title);
|
||||
environmentVariables.Add("Sonarr_Series_Path", series.Path);
|
||||
environmentVariables.Add("Sonarr_Series_TvdbId", series.TvdbId.ToString());
|
||||
environmentVariables.Add("Sonarr_Series_Type", series.SeriesType.ToString());
|
||||
|
||||
ExecuteScript(environmentVariables);
|
||||
}
|
||||
|
||||
public override string Name => "Custom Script";
|
||||
|
|
|
@ -8,8 +8,11 @@ namespace NzbDrone.Core.Notifications
|
|||
{
|
||||
public string Message { get; set; }
|
||||
public Series Series { get; set; }
|
||||
public Movie Movie { get; set; }
|
||||
public EpisodeFile EpisodeFile { get; set; }
|
||||
public List<EpisodeFile> OldFiles { get; set; }
|
||||
public MovieFile MovieFile { get; set; }
|
||||
public List<MovieFile> OldMovieFiles { get; set; }
|
||||
public string SourcePath { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace NzbDrone.Core.Notifications.Email
|
|||
|
||||
public override void OnGrab(GrabMessage grabMessage)
|
||||
{
|
||||
const string subject = "Radarr [TV] - Grabbed";
|
||||
const string subject = "Radarr [Movie] - Grabbed";
|
||||
var body = string.Format("{0} sent to queue.", grabMessage.Message);
|
||||
|
||||
_emailService.SendEmail(Settings, subject, body);
|
||||
|
@ -26,12 +26,16 @@ namespace NzbDrone.Core.Notifications.Email
|
|||
|
||||
public override void OnDownload(DownloadMessage message)
|
||||
{
|
||||
const string subject = "Radarr [TV] - Downloaded";
|
||||
const string subject = "Radarr [Movie] - Downloaded";
|
||||
var body = string.Format("{0} Downloaded and sorted.", message.Message);
|
||||
|
||||
_emailService.SendEmail(Settings, subject, body);
|
||||
}
|
||||
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ namespace NzbDrone.Core.Notifications
|
|||
{
|
||||
public string Message { get; set; }
|
||||
public Series Series { get; set; }
|
||||
public Movie Movie { get; set; }
|
||||
public RemoteMovie RemoteMovie { get; set; }
|
||||
public RemoteEpisode Episode { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
|
||||
|
|
|
@ -18,18 +18,22 @@ namespace NzbDrone.Core.Notifications.Growl
|
|||
|
||||
public override void OnGrab(GrabMessage grabMessage)
|
||||
{
|
||||
const string title = "Episode Grabbed";
|
||||
const string title = "Movie Grabbed";
|
||||
|
||||
_growlService.SendNotification(title, grabMessage.Message, "GRAB", Settings.Host, Settings.Port, Settings.Password);
|
||||
}
|
||||
|
||||
public override void OnDownload(DownloadMessage message)
|
||||
{
|
||||
const string title = "Episode Downloaded";
|
||||
const string title = "Movie Downloaded";
|
||||
|
||||
_growlService.SendNotification(title, message.Message, "DOWNLOAD", Settings.Host, Settings.Port, Settings.Password);
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace NzbDrone.Core.Notifications
|
|||
void OnGrab(GrabMessage grabMessage);
|
||||
void OnDownload(DownloadMessage message);
|
||||
void OnRename(Series series);
|
||||
void OnMovieRename(Movie movie);
|
||||
bool SupportsOnGrab { get; }
|
||||
bool SupportsOnDownload { get; }
|
||||
bool SupportsOnUpgrade { get; }
|
||||
|
|
|
@ -18,18 +18,22 @@ namespace NzbDrone.Core.Notifications.Join
|
|||
|
||||
public override void OnGrab(GrabMessage grabMessage)
|
||||
{
|
||||
const string title = "Radarr - Episode Grabbed";
|
||||
const string title = "Radarr - Movie Grabbed";
|
||||
|
||||
_proxy.SendNotification(title, grabMessage.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnDownload(DownloadMessage message)
|
||||
{
|
||||
const string title = "Radarr - Episode Downloaded";
|
||||
const string title = "Radarr - Movie Downloaded";
|
||||
|
||||
_proxy.SendNotification(title, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ namespace NzbDrone.Core.Notifications.Join
|
|||
request.AddParameter("apikey", settings.ApiKey);
|
||||
request.AddParameter("title", title);
|
||||
request.AddParameter("text", message);
|
||||
request.AddParameter("icon", "https://cdn.rawgit.com/Sonarr/Sonarr/develop/Logo/256.png"); // Use the Sonarr logo.
|
||||
request.AddParameter("icon", "https://cdn.rawgit.com/Radarr/Radarr/develop/Logo/256.png"); // Use the Radarr logo.
|
||||
|
||||
var response = client.ExecuteAndValidate(request);
|
||||
var res = Json.Deserialize<JoinResponseModel>(response.Content);
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
|
|||
|
||||
public override void OnGrab(GrabMessage grabMessage)
|
||||
{
|
||||
const string title = "Radarr - Grabbed";
|
||||
const string title = "Radarr - Movie Grabbed";
|
||||
|
||||
if (Settings.Notify)
|
||||
{
|
||||
|
@ -28,7 +28,7 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
|
|||
|
||||
public override void OnDownload(DownloadMessage message)
|
||||
{
|
||||
const string title = "Radarr - Downloaded";
|
||||
const string title = "Radarr - Movie Downloaded";
|
||||
|
||||
if (Settings.Notify)
|
||||
{
|
||||
|
@ -37,7 +37,15 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
|
|||
|
||||
if (Settings.UpdateLibrary)
|
||||
{
|
||||
_mediaBrowserService.Update(Settings, message.Series);
|
||||
_mediaBrowserService.UpdateMovies(Settings, message.Movie);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
if (Settings.UpdateLibrary)
|
||||
{
|
||||
_mediaBrowserService.UpdateMovies(Settings, movie);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,16 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
|
|||
ProcessRequest(request, settings);
|
||||
}
|
||||
|
||||
|
||||
public void UpdateMovies(MediaBrowserSettings settings, string imdbid)
|
||||
{
|
||||
var path = string.Format("/Library/Movies/Updated?ImdbId={0}", imdbid);
|
||||
var request = BuildRequest(path, settings);
|
||||
request.Headers.Add("Content-Length", "0");
|
||||
|
||||
ProcessRequest(request, settings);
|
||||
}
|
||||
|
||||
private string ProcessRequest(HttpRequest request, MediaBrowserSettings settings)
|
||||
{
|
||||
request.Headers.Add("X-MediaBrowser-Token", settings.ApiKey);
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
|
|||
{
|
||||
void Notify(MediaBrowserSettings settings, string title, string message);
|
||||
void Update(MediaBrowserSettings settings, Series series);
|
||||
void UpdateMovies(MediaBrowserSettings settings, Movie movie);
|
||||
ValidationFailure Test(MediaBrowserSettings settings);
|
||||
}
|
||||
|
||||
|
@ -35,6 +36,13 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
|
|||
_proxy.Update(settings, series.TvdbId);
|
||||
}
|
||||
|
||||
|
||||
public void UpdateMovies(MediaBrowserSettings settings, Movie movie)
|
||||
{
|
||||
_proxy.UpdateMovies(settings, movie.ImdbId);
|
||||
}
|
||||
|
||||
|
||||
public ValidationFailure Test(MediaBrowserSettings settings)
|
||||
{
|
||||
try
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace NzbDrone.Core.Notifications
|
|||
public abstract void OnGrab(GrabMessage grabMessage);
|
||||
public abstract void OnDownload(DownloadMessage message);
|
||||
public abstract void OnRename(Series series);
|
||||
public abstract void OnMovieRename(Movie movie);
|
||||
|
||||
public virtual bool SupportsOnGrab => true;
|
||||
public virtual bool SupportsOnDownload => true;
|
||||
|
|
|
@ -15,7 +15,11 @@ namespace NzbDrone.Core.Notifications
|
|||
public class NotificationService
|
||||
: IHandle<EpisodeGrabbedEvent>,
|
||||
IHandle<EpisodeDownloadedEvent>,
|
||||
IHandle<SeriesRenamedEvent>
|
||||
IHandle<SeriesRenamedEvent>,
|
||||
IHandle<MovieRenamedEvent>,
|
||||
IHandle<MovieGrabbedEvent>,
|
||||
IHandle<MovieDownloadedEvent>
|
||||
|
||||
{
|
||||
private readonly INotificationFactory _notificationFactory;
|
||||
private readonly Logger _logger;
|
||||
|
@ -67,6 +71,42 @@ namespace NzbDrone.Core.Notifications
|
|||
qualityString);
|
||||
}
|
||||
|
||||
private string GetMessage(Movie movie, QualityModel quality)
|
||||
{
|
||||
var qualityString = quality.Quality.ToString();
|
||||
|
||||
if (quality.Revision.Version > 1)
|
||||
{
|
||||
qualityString += " Proper";
|
||||
}
|
||||
|
||||
return string.Format("{0} ({1}) [{2}]",
|
||||
movie.Title,
|
||||
movie.Year,
|
||||
qualityString);
|
||||
}
|
||||
|
||||
private bool ShouldHandleMovie(ProviderDefinition definition, Movie movie)
|
||||
{
|
||||
var notificationDefinition = (NotificationDefinition)definition;
|
||||
|
||||
if (notificationDefinition.Tags.Empty())
|
||||
{
|
||||
_logger.Debug("No tags set for this notification.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (notificationDefinition.Tags.Intersect(movie.Tags).Any())
|
||||
{
|
||||
_logger.Debug("Notification and series have one or more matching tags.");
|
||||
return true;
|
||||
}
|
||||
|
||||
//TODO: this message could be more clear
|
||||
_logger.Debug("{0} does not have any tags that match {1}'s tags", notificationDefinition.Name, movie.Title);
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool ShouldHandleSeries(ProviderDefinition definition, Series series)
|
||||
{
|
||||
var notificationDefinition = (NotificationDefinition) definition;
|
||||
|
@ -112,6 +152,33 @@ namespace NzbDrone.Core.Notifications
|
|||
}
|
||||
}
|
||||
|
||||
public void Handle(MovieGrabbedEvent message)
|
||||
{
|
||||
var grabMessage = new GrabMessage
|
||||
{
|
||||
Message = GetMessage(message.Movie.Movie, message.Movie.ParsedMovieInfo.Quality),
|
||||
Series = null,
|
||||
Quality = message.Movie.ParsedMovieInfo.Quality,
|
||||
Episode = null,
|
||||
Movie = message.Movie.Movie,
|
||||
RemoteMovie = message.Movie
|
||||
};
|
||||
|
||||
foreach (var notification in _notificationFactory.OnGrabEnabled())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!ShouldHandleMovie(notification.Definition, message.Movie.Movie)) continue;
|
||||
notification.OnGrab(grabMessage);
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex, "Unable to send OnGrab notification to: " + notification.Definition.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(EpisodeDownloadedEvent message)
|
||||
{
|
||||
var downloadMessage = new DownloadMessage();
|
||||
|
@ -141,6 +208,38 @@ namespace NzbDrone.Core.Notifications
|
|||
}
|
||||
}
|
||||
|
||||
public void Handle(MovieDownloadedEvent message)
|
||||
{
|
||||
var downloadMessage = new DownloadMessage();
|
||||
downloadMessage.Message = GetMessage(message.Movie.Movie, message.Movie.Quality);
|
||||
downloadMessage.Series = null;
|
||||
downloadMessage.EpisodeFile = null;
|
||||
downloadMessage.MovieFile = message.MovieFile;
|
||||
downloadMessage.Movie = message.Movie.Movie;
|
||||
downloadMessage.OldFiles = null;
|
||||
downloadMessage.OldMovieFiles = message.OldFiles;
|
||||
downloadMessage.SourcePath = message.Movie.Path;
|
||||
|
||||
foreach (var notification in _notificationFactory.OnDownloadEnabled())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ShouldHandleMovie(notification.Definition, message.Movie.Movie))
|
||||
{
|
||||
if (downloadMessage.OldMovieFiles.Empty() || ((NotificationDefinition)notification.Definition).OnUpgrade)
|
||||
{
|
||||
notification.OnDownload(downloadMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warn(ex, "Unable to send OnDownload notification to: " + notification.Definition.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(SeriesRenamedEvent message)
|
||||
{
|
||||
foreach (var notification in _notificationFactory.OnRenameEnabled())
|
||||
|
@ -159,5 +258,24 @@ namespace NzbDrone.Core.Notifications
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(MovieRenamedEvent message)
|
||||
{
|
||||
foreach (var notification in _notificationFactory.OnRenameEnabled())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ShouldHandleMovie(notification.Definition, message.Movie))
|
||||
{
|
||||
notification.OnMovieRename(message.Movie);
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warn(ex, "Unable to send OnRename notification to: " + notification.Definition.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,18 +19,22 @@ namespace NzbDrone.Core.Notifications.NotifyMyAndroid
|
|||
|
||||
public override void OnGrab(GrabMessage grabMessage)
|
||||
{
|
||||
const string title = "Episode Grabbed";
|
||||
const string title = "Movie Grabbed";
|
||||
|
||||
_proxy.SendNotification(title, grabMessage.Message, Settings.ApiKey, (NotifyMyAndroidPriority)Settings.Priority);
|
||||
}
|
||||
|
||||
public override void OnDownload(DownloadMessage message)
|
||||
{
|
||||
const string title = "Episode Downloaded";
|
||||
const string title = "Movie Downloaded";
|
||||
|
||||
_proxy.SendNotification(title, message.Message, Settings.ApiKey, (NotifyMyAndroidPriority)Settings.Priority);
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -28,6 +28,10 @@ namespace NzbDrone.Core.Notifications.Plex
|
|||
_plexClientService.Notify(Settings, header, message.Message);
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -35,6 +35,10 @@ namespace NzbDrone.Core.Notifications.Plex
|
|||
Notify(Settings, header, message.Message);
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
{
|
||||
|
||||
|
|
|
@ -22,19 +22,24 @@ namespace NzbDrone.Core.Notifications.Plex
|
|||
|
||||
public override void OnDownload(DownloadMessage message)
|
||||
{
|
||||
UpdateIfEnabled(message.Series);
|
||||
UpdateIfEnabled(message.Movie);
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
UpdateIfEnabled(movie);
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
{
|
||||
UpdateIfEnabled(series);
|
||||
//UpdateIfEnabled(movie);
|
||||
}
|
||||
|
||||
private void UpdateIfEnabled(Series series)
|
||||
private void UpdateIfEnabled(Movie movie)
|
||||
{
|
||||
if (Settings.UpdateLibrary)
|
||||
{
|
||||
_plexServerService.UpdateLibrary(series, Settings);
|
||||
_plexServerService.UpdateMovieSections(movie, Settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace NzbDrone.Core.Notifications.Plex
|
|||
public interface IPlexServerProxy
|
||||
{
|
||||
List<PlexSection> GetTvSections(PlexServerSettings settings);
|
||||
List<PlexSection> GetMovieSections(PlexServerSettings settings);
|
||||
void Update(int sectionId, PlexServerSettings settings);
|
||||
void UpdateSeries(int metadataId, PlexServerSettings settings);
|
||||
string Version(PlexServerSettings settings);
|
||||
|
@ -66,6 +67,37 @@ namespace NzbDrone.Core.Notifications.Plex
|
|||
.ToList();
|
||||
}
|
||||
|
||||
public List<PlexSection> GetMovieSections(PlexServerSettings settings)
|
||||
{
|
||||
var request = GetPlexServerRequest("library/sections", Method.GET, settings);
|
||||
var client = GetPlexServerClient(settings);
|
||||
var response = client.Execute(request);
|
||||
|
||||
_logger.Trace("Sections response: {0}", response.Content);
|
||||
CheckForError(response, settings);
|
||||
|
||||
if (response.Content.Contains("_children"))
|
||||
{
|
||||
return Json.Deserialize<PlexMediaContainerLegacy>(response.Content)
|
||||
.Sections
|
||||
.Where(d => d.Type == "movie")
|
||||
.Select(s => new PlexSection
|
||||
{
|
||||
Id = s.Id,
|
||||
Language = s.Language,
|
||||
Locations = s.Locations,
|
||||
Type = s.Type
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
|
||||
return Json.Deserialize<PlexResponse<PlexSectionsContainer>>(response.Content)
|
||||
.MediaContainer
|
||||
.Sections
|
||||
.Where(d => d.Type == "movie")
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public void Update(int sectionId, PlexServerSettings settings)
|
||||
{
|
||||
var resource = string.Format("library/sections/{0}/refresh", sectionId);
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace NzbDrone.Core.Notifications.Plex
|
|||
public interface IPlexServerService
|
||||
{
|
||||
void UpdateLibrary(Series series, PlexServerSettings settings);
|
||||
void UpdateMovieSections(Movie movie, PlexServerSettings settings);
|
||||
ValidationFailure Test(PlexServerSettings settings);
|
||||
}
|
||||
|
||||
|
@ -62,11 +63,43 @@ namespace NzbDrone.Core.Notifications.Plex
|
|||
}
|
||||
}
|
||||
|
||||
public void UpdateMovieSections(Movie movie, PlexServerSettings settings)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.Debug("Sending Update Request to Plex Server");
|
||||
|
||||
var version = _versionCache.Get(settings.Host, () => GetVersion(settings), TimeSpan.FromHours(2));
|
||||
ValidateVersion(version);
|
||||
|
||||
var sections = GetSections(settings);
|
||||
var partialUpdates = _partialUpdateCache.Get(settings.Host, () => PartialUpdatesAllowed(settings, version), TimeSpan.FromHours(2));
|
||||
|
||||
// TODO: Investiate partial updates later, for now just update all movie sections...
|
||||
|
||||
//if (partialUpdates)
|
||||
//{
|
||||
// UpdatePartialSection(series, sections, settings);
|
||||
//}
|
||||
|
||||
//else
|
||||
//{
|
||||
sections.ForEach(s => UpdateSection(s.Id, settings));
|
||||
//}
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warn(ex, "Failed to Update Plex host: " + settings.Host);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private List<PlexSection> GetSections(PlexServerSettings settings)
|
||||
{
|
||||
_logger.Debug("Getting sections from Plex host: {0}", settings.Host);
|
||||
|
||||
return _plexServerProxy.GetTvSections(settings).ToList();
|
||||
return _plexServerProxy.GetMovieSections(settings).ToList();
|
||||
}
|
||||
|
||||
private bool PartialUpdatesAllowed(PlexServerSettings settings, Version version)
|
||||
|
|
|
@ -19,18 +19,22 @@ namespace NzbDrone.Core.Notifications.Prowl
|
|||
|
||||
public override void OnGrab(GrabMessage grabMessage)
|
||||
{
|
||||
const string title = "Episode Grabbed";
|
||||
const string title = "Movie Grabbed";
|
||||
|
||||
_prowlService.SendNotification(title, grabMessage.Message, Settings.ApiKey, (NotificationPriority)Settings.Priority);
|
||||
}
|
||||
|
||||
public override void OnDownload(DownloadMessage message)
|
||||
{
|
||||
const string title = "Episode Downloaded";
|
||||
const string title = "Movie Downloaded";
|
||||
|
||||
_prowlService.SendNotification(title, message.Message, Settings.ApiKey, (NotificationPriority)Settings.Priority);
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -18,18 +18,22 @@ namespace NzbDrone.Core.Notifications.PushBullet
|
|||
|
||||
public override void OnGrab(GrabMessage grabMessage)
|
||||
{
|
||||
const string title = "Radarr - Episode Grabbed";
|
||||
const string title = "Radarr - Movie Grabbed";
|
||||
|
||||
_proxy.SendNotification(title, grabMessage.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnDownload(DownloadMessage message)
|
||||
{
|
||||
const string title = "Radarr - Episode Downloaded";
|
||||
const string title = "Radarr - Movie Downloaded";
|
||||
|
||||
_proxy.SendNotification(title, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -18,18 +18,22 @@ namespace NzbDrone.Core.Notifications.Pushalot
|
|||
|
||||
public override void OnGrab(GrabMessage grabMessage)
|
||||
{
|
||||
const string title = "Episode Grabbed";
|
||||
const string title = "Movie Grabbed";
|
||||
|
||||
_proxy.SendNotification(title, grabMessage.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnDownload(DownloadMessage message)
|
||||
{
|
||||
const string title = "Episode Downloaded";
|
||||
const string title = "Movie Downloaded";
|
||||
|
||||
_proxy.SendNotification(title, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -18,18 +18,22 @@ namespace NzbDrone.Core.Notifications.Pushover
|
|||
|
||||
public override void OnGrab(GrabMessage grabMessage)
|
||||
{
|
||||
const string title = "Episode Grabbed";
|
||||
const string title = "Movie Grabbed";
|
||||
|
||||
_proxy.SendNotification(title, grabMessage.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnDownload(DownloadMessage message)
|
||||
{
|
||||
const string title = "Episode Downloaded";
|
||||
const string title = "Movie Downloaded";
|
||||
|
||||
_proxy.SendNotification(title, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace NzbDrone.Core.Notifications.Slack
|
|||
new Attachment
|
||||
{
|
||||
Fallback = message.Message,
|
||||
Title = message.Series.Title,
|
||||
Title = message.Movie.Title,
|
||||
Text = message.Message,
|
||||
Color = "warning"
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ namespace NzbDrone.Core.Notifications.Slack
|
|||
new Attachment
|
||||
{
|
||||
Fallback = message.Message,
|
||||
Title = message.Series.Title,
|
||||
Title = message.Movie.Title,
|
||||
Text = message.Message,
|
||||
Color = "good"
|
||||
}
|
||||
|
@ -69,6 +69,25 @@ namespace NzbDrone.Core.Notifications.Slack
|
|||
NotifySlack(payload);
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
var payload = new SlackPayload
|
||||
{
|
||||
IconEmoji = Settings.Icon,
|
||||
Username = Settings.Username,
|
||||
Text = "Renamed",
|
||||
Attachments = new List<Attachment>
|
||||
{
|
||||
new Attachment
|
||||
{
|
||||
Title = movie.Title,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
NotifySlack(payload);
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
{
|
||||
var payload = new SlackPayload
|
||||
|
|
|
@ -27,21 +27,29 @@ namespace NzbDrone.Core.Notifications.Synology
|
|||
{
|
||||
if (Settings.UpdateLibrary)
|
||||
{
|
||||
foreach (var oldFile in message.OldFiles)
|
||||
foreach (var oldFile in message.OldMovieFiles)
|
||||
{
|
||||
var fullPath = Path.Combine(message.Series.Path, oldFile.RelativePath);
|
||||
var fullPath = Path.Combine(message.Movie.Path, oldFile.RelativePath);
|
||||
|
||||
_indexerProxy.DeleteFile(fullPath);
|
||||
}
|
||||
|
||||
{
|
||||
var fullPath = Path.Combine(message.Series.Path, message.EpisodeFile.RelativePath);
|
||||
var fullPath = Path.Combine(message.Movie.Path, message.MovieFile.RelativePath);
|
||||
|
||||
_indexerProxy.AddFile(fullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
if (Settings.UpdateLibrary)
|
||||
{
|
||||
_indexerProxy.UpdateFolder(movie.Path);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
{
|
||||
if (Settings.UpdateLibrary)
|
||||
|
|
|
@ -18,18 +18,22 @@ namespace NzbDrone.Core.Notifications.Telegram
|
|||
|
||||
public override void OnGrab(GrabMessage grabMessage)
|
||||
{
|
||||
const string title = "Episode Grabbed";
|
||||
const string title = "Movie Grabbed";
|
||||
|
||||
_proxy.SendNotification(title, grabMessage.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnDownload(DownloadMessage message)
|
||||
{
|
||||
const string title = "Episode Downloaded";
|
||||
const string title = "Movie Downloaded";
|
||||
|
||||
_proxy.SendNotification(title, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -29,6 +29,10 @@ namespace NzbDrone.Core.Notifications.Twitter
|
|||
_twitterService.SendNotification($"Imported: {message.Message}", Settings);
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -27,6 +27,10 @@ namespace NzbDrone.Core.Notifications.Webhook
|
|||
_service.OnDownload(message.Series, message.EpisodeFile, Settings);
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
{
|
||||
_service.OnRename(series, Settings);
|
||||
|
|
|
@ -51,6 +51,24 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||
UpdateLibrary(settings, series);
|
||||
}
|
||||
|
||||
public void UpdateMovie(XbmcSettings settings, Movie movie)
|
||||
{
|
||||
if (!settings.AlwaysUpdate)
|
||||
{
|
||||
_logger.Debug("Determining if there are any active players on XBMC host: {0}", settings.Address);
|
||||
var activePlayers = GetActivePlayers(settings);
|
||||
|
||||
if (activePlayers.Any(a => a.Type.Equals("video")))
|
||||
{
|
||||
_logger.Debug("Video is currently playing, skipping library update");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateMovieLibrary(settings, movie);
|
||||
}
|
||||
|
||||
|
||||
public void Clean(XbmcSettings settings)
|
||||
{
|
||||
const string cleanVideoLibrary = "CleanLibrary(video)";
|
||||
|
@ -167,6 +185,37 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||
}
|
||||
}
|
||||
|
||||
private void UpdateMovieLibrary(XbmcSettings settings, Movie movie)
|
||||
{
|
||||
try
|
||||
{
|
||||
//_logger.Debug("Sending Update DB Request to XBMC Host: {0}", settings.Address);
|
||||
//var xbmcSeriesPath = GetSeriesPath(settings, series);
|
||||
|
||||
////If the path is found update it, else update the whole library
|
||||
//if (!string.IsNullOrEmpty(xbmcSeriesPath))
|
||||
//{
|
||||
// _logger.Debug("Updating series [{0}] on XBMC host: {1}", series, settings.Address);
|
||||
// var command = BuildExecBuiltInCommand(string.Format("UpdateLibrary(video,{0})", xbmcSeriesPath));
|
||||
// SendCommand(settings, command);
|
||||
//}
|
||||
|
||||
//else
|
||||
//{
|
||||
//Update the entire library
|
||||
_logger.Debug("Series [{0}] doesn't exist on XBMC host: {1}, Updating Entire Library", movie, settings.Address);
|
||||
var command = BuildExecBuiltInCommand("UpdateLibrary(video)");
|
||||
SendCommand(settings, command);
|
||||
//}
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Debug(ex, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private string SendCommand(XbmcSettings settings, string command)
|
||||
{
|
||||
var url = string.Format("http://{0}/xbmcCmds/xbmcHttp?command={1}", settings.Address, command);
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||
{
|
||||
void Notify(XbmcSettings settings, string title, string message);
|
||||
void Update(XbmcSettings settings, Series series);
|
||||
void UpdateMovie(XbmcSettings settings, Movie movie);
|
||||
void Clean(XbmcSettings settings);
|
||||
bool CanHandle(XbmcVersion version);
|
||||
}
|
||||
|
|
|
@ -44,7 +44,25 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||
|
||||
UpdateLibrary(settings, series);
|
||||
}
|
||||
|
||||
|
||||
public void UpdateMovie(XbmcSettings settings, Movie movie)
|
||||
{
|
||||
if (!settings.AlwaysUpdate)
|
||||
{
|
||||
_logger.Debug("Determining if there are any active players on XBMC host: {0}", settings.Address);
|
||||
var activePlayers = _proxy.GetActivePlayers(settings);
|
||||
|
||||
if (activePlayers.Any(a => a.Type.Equals("video")))
|
||||
{
|
||||
_logger.Debug("Video is currently playing, skipping library update");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateMovieLibrary(settings, movie);
|
||||
}
|
||||
|
||||
|
||||
public void Clean(XbmcSettings settings)
|
||||
{
|
||||
_proxy.CleanLibrary(settings);
|
||||
|
@ -108,5 +126,23 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||
_logger.Debug(ex, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateMovieLibrary(XbmcSettings settings, Movie movie)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = _proxy.UpdateLibrary(settings, null);
|
||||
|
||||
if (!response.Equals("OK", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
_logger.Debug("Failed to update library for: {0}", settings.Address);
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Debug(ex, ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,12 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||
const string header = "Radarr - Downloaded";
|
||||
|
||||
Notify(Settings, header, message.Message);
|
||||
UpdateAndClean(message.Series, message.OldFiles.Any());
|
||||
UpdateAndCleanMovie(message.Movie, message.OldMovieFiles.Any());
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
UpdateAndCleanMovie(movie);
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
|
@ -88,5 +93,26 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||
_logger.Debug(ex, logMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateAndCleanMovie(Movie movie, bool clean = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Settings.UpdateLibrary)
|
||||
{
|
||||
_xbmcService.UpdateMovie(Settings, movie);
|
||||
}
|
||||
|
||||
if (clean && Settings.CleanLibrary)
|
||||
{
|
||||
_xbmcService.Clean(Settings);
|
||||
}
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
var logMessage = string.Format("Unable to connect to XBMC Host: {0}:{1}", Settings.Host, Settings.Port);
|
||||
_logger.Debug(ex, logMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||
{
|
||||
void Notify(XbmcSettings settings, string title, string message);
|
||||
void Update(XbmcSettings settings, Series series);
|
||||
void UpdateMovie(XbmcSettings settings, Movie movie);
|
||||
void Clean(XbmcSettings settings);
|
||||
ValidationFailure Test(XbmcSettings settings, string message);
|
||||
}
|
||||
|
@ -51,6 +52,12 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||
provider.Update(settings, series);
|
||||
}
|
||||
|
||||
public void UpdateMovie(XbmcSettings settings, Movie movie)
|
||||
{
|
||||
var provider = GetApiProvider(settings);
|
||||
provider.UpdateMovie(settings, movie);
|
||||
}
|
||||
|
||||
public void Clean(XbmcSettings settings)
|
||||
{
|
||||
var provider = GetApiProvider(settings);
|
||||
|
|
|
@ -218,6 +218,8 @@
|
|||
<Compile Include="Datastore\Migration\002_remove_tvrage_imdb_unique_constraint.cs" />
|
||||
<Compile Include="Datastore\Migration\003_remove_clean_title_from_scene_mapping.cs" />
|
||||
<Compile Include="Datastore\Migration\004_updated_history.cs" />
|
||||
<Compile Include="Datastore\Migration\125_fix_imdb_unique.cs" />
|
||||
<Compile Include="Datastore\Migration\124_add_preferred_tags_to_profile.cs" />
|
||||
<Compile Include="Datastore\Migration\122_add_movieid_to_blacklist.cs" />
|
||||
<Compile Include="Datastore\Migration\121_update_filedate_config.cs" />
|
||||
<Compile Include="Datastore\Migration\120_add_studio_to_table.cs" />
|
||||
|
@ -618,6 +620,7 @@
|
|||
<Compile Include="Http\HttpProxySettingsProvider.cs" />
|
||||
<Compile Include="Http\TorcacheHttpInterceptor.cs" />
|
||||
<Compile Include="IndexerSearch\Definitions\MovieSearchCriteria.cs" />
|
||||
<Compile Include="IndexerSearch\MissingMoviesSearchCommand.cs" />
|
||||
<Compile Include="IndexerSearch\MoviesSearchCommand.cs" />
|
||||
<Compile Include="IndexerSearch\MoviesSearchService.cs" />
|
||||
<Compile Include="Indexers\AwesomeHD\AwesomeHDRssParser.cs" />
|
||||
|
|
|
@ -1,3 +1,337 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Common.EnsureThat;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Organizer
|
||||
{
|
||||
public interface IBuildFileNames
|
||||
{
|
||||
string BuildFileName(List<Episode> episodes, Series series, EpisodeFile episodeFile, NamingConfig namingConfig = null);
|
||||
string BuildFileName(Movie movie, MovieFile movieFile, NamingConfig namingConfig = null);
|
||||
string BuildFilePath(Movie movie, string fileName, string extension);
|
||||
string BuildFilePath(Series series, int seasonNumber, string fileName, string extension);
|
||||
string BuildSeasonPath(Series series, int seasonNumber);
|
||||
BasicNamingConfig GetBasicNamingConfig(NamingConfig nameSpec);
|
||||
string GetSeriesFolder(Series series, NamingConfig namingConfig = null);
|
||||
string GetSeasonFolder(Series series, int seasonNumber, NamingConfig namingConfig = null);
|
||||
string GetMovieFolder(Movie movie, NamingConfig namingConfig = null);
|
||||
}
|
||||
|
||||
public class FileNameBuilder : IBuildFileNames
|
||||
{
|
||||
private readonly INamingConfigService _namingConfigService;
|
||||
private readonly IQualityDefinitionService _qualityDefinitionService;
|
||||
private readonly ICached<EpisodeFormat[]> _episodeFormatCache;
|
||||
private readonly ICached<AbsoluteEpisodeFormat[]> _absoluteEpisodeFormatCache;
|
||||
private readonly Logger _logger;
|
||||
|
||||
private static readonly Regex TitleRegex = new Regex(@"\{(?<prefix>[- ._\[(]*)(?<token>(?:[a-z0-9]+)(?:(?<separator>[- ._]+)(?:[a-z0-9]+))?)(?::(?<customFormat>[a-z0-9]+))?(?<suffix>[- ._)\]]*)\}",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly Regex EpisodeRegex = new Regex(@"(?<episode>\{episode(?:\:0+)?})",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly Regex SeasonRegex = new Regex(@"(?<season>\{season(?:\:0+)?})",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly Regex AbsoluteEpisodeRegex = new Regex(@"(?<absolute>\{absolute(?:\:0+)?})",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public static readonly Regex SeasonEpisodePatternRegex = new Regex(@"(?<separator>(?<=})[- ._]+?)?(?<seasonEpisode>s?{season(?:\:0+)?}(?<episodeSeparator>[- ._]?[ex])(?<episode>{episode(?:\:0+)?}))(?<separator>[- ._]+?(?={))?",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public static readonly Regex AbsoluteEpisodePatternRegex = new Regex(@"(?<separator>(?<=})[- ._]+?)?(?<absolute>{absolute(?:\:0+)?})(?<separator>[- ._]+?(?={))?",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public static readonly Regex AirDateRegex = new Regex(@"\{Air(\s|\W|_)Date\}", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public static readonly Regex SeriesTitleRegex = new Regex(@"(?<token>\{(?:Series)(?<separator>[- ._])(Clean)?Title\})",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public static readonly Regex MovieTitleRegex = new Regex(@"(?<token>\{((?:(Movie|Original))(?<separator>[- ._])(Clean)?Title(The)?)\})",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly Regex FileNameCleanupRegex = new Regex(@"([- ._])(\1)+", RegexOptions.Compiled);
|
||||
private static readonly Regex TrimSeparatorsRegex = new Regex(@"[- ._]$", RegexOptions.Compiled);
|
||||
|
||||
private static readonly Regex ScenifyRemoveChars = new Regex(@"(?<=\s)(,|<|>|\/|\\|;|:|'|""|\||`|~|!|\?|@|$|%|^|\*|-|_|=){1}(?=\s)|('|:|\?|,)(?=(?:(?:s|m)\s)|\s|$)|(\(|\)|\[|\]|\{|\})", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex ScenifyReplaceChars = new Regex(@"[\/]", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
//TODO: Support Written numbers (One, Two, etc) and Roman Numerals (I, II, III etc)
|
||||
private static readonly Regex MultiPartCleanupRegex = new Regex(@"(?:\(\d+\)|(Part|Pt\.?)\s?\d+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly char[] EpisodeTitleTrimCharacters = new[] { ' ', '.', '?' };
|
||||
|
||||
public FileNameBuilder(INamingConfigService namingConfigService,
|
||||
IQualityDefinitionService qualityDefinitionService,
|
||||
ICacheManager cacheManager,
|
||||
Logger logger)
|
||||
{
|
||||
_namingConfigService = namingConfigService;
|
||||
_qualityDefinitionService = qualityDefinitionService;
|
||||
//_movieFormatCache = cacheManager.GetCache<MovieFormat>(GetType(), "movieFormat");
|
||||
_episodeFormatCache = cacheManager.GetCache<EpisodeFormat[]>(GetType(), "episodeFormat");
|
||||
_absoluteEpisodeFormatCache = cacheManager.GetCache<AbsoluteEpisodeFormat[]>(GetType(), "absoluteEpisodeFormat");
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public string BuildFileName(List<Episode> episodes, Series series, EpisodeFile episodeFile, NamingConfig namingConfig = null)
|
||||
{
|
||||
if (namingConfig == null)
|
||||
{
|
||||
namingConfig = _namingConfigService.GetConfig();
|
||||
}
|
||||
|
||||
if (!namingConfig.RenameEpisodes)
|
||||
{
|
||||
return GetOriginalTitle(episodeFile);
|
||||
}
|
||||
|
||||
if (namingConfig.StandardEpisodeFormat.IsNullOrWhiteSpace() && series.SeriesType == SeriesTypes.Standard)
|
||||
{
|
||||
throw new NamingFormatException("Standard episode format cannot be empty");
|
||||
}
|
||||
|
||||
if (namingConfig.DailyEpisodeFormat.IsNullOrWhiteSpace() && series.SeriesType == SeriesTypes.Daily)
|
||||
{
|
||||
throw new NamingFormatException("Daily episode format cannot be empty");
|
||||
}
|
||||
|
||||
if (namingConfig.AnimeEpisodeFormat.IsNullOrWhiteSpace() && series.SeriesType == SeriesTypes.Anime)
|
||||
{
|
||||
throw new NamingFormatException("Anime episode format cannot be empty");
|
||||
}
|
||||
|
||||
var pattern = namingConfig.StandardEpisodeFormat;
|
||||
var tokenHandlers = new Dictionary<string, Func<TokenMatch, string>>(FileNameBuilderTokenEqualityComparer.Instance);
|
||||
|
||||
episodes = episodes.OrderBy(e => e.SeasonNumber).ThenBy(e => e.EpisodeNumber).ToList();
|
||||
|
||||
if (series.SeriesType == SeriesTypes.Daily)
|
||||
{
|
||||
pattern = namingConfig.DailyEpisodeFormat;
|
||||
}
|
||||
|
||||
if (series.SeriesType == SeriesTypes.Anime && episodes.All(e => e.AbsoluteEpisodeNumber.HasValue))
|
||||
{
|
||||
pattern = namingConfig.AnimeEpisodeFormat;
|
||||
}
|
||||
|
||||
pattern = AddSeasonEpisodeNumberingTokens(pattern, tokenHandlers, episodes, namingConfig);
|
||||
pattern = AddAbsoluteNumberingTokens(pattern, tokenHandlers, series, episodes, namingConfig);
|
||||
|
||||
AddSeriesTokens(tokenHandlers, series);
|
||||
AddEpisodeTokens(tokenHandlers, episodes);
|
||||
AddEpisodeFileTokens(tokenHandlers, episodeFile);
|
||||
AddQualityTokens(tokenHandlers, series, episodeFile);
|
||||
AddMediaInfoTokens(tokenHandlers, episodeFile);
|
||||
|
||||
var fileName = ReplaceTokens(pattern, tokenHandlers, namingConfig).Trim();
|
||||
fileName = FileNameCleanupRegex.Replace(fileName, match => match.Captures[0].Value[0].ToString());
|
||||
fileName = TrimSeparatorsRegex.Replace(fileName, string.Empty);
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public string BuildFileName(Movie movie, MovieFile movieFile, NamingConfig namingConfig = null)
|
||||
{
|
||||
if (namingConfig == null)
|
||||
{
|
||||
namingConfig = _namingConfigService.GetConfig();
|
||||
}
|
||||
|
||||
if (!namingConfig.RenameEpisodes)
|
||||
{
|
||||
return GetOriginalTitle(movieFile);
|
||||
}
|
||||
|
||||
//TODO: Update namingConfig for Movies!
|
||||
var pattern = namingConfig.StandardMovieFormat;
|
||||
var tokenHandlers = new Dictionary<string, Func<TokenMatch, string>>(FileNameBuilderTokenEqualityComparer.Instance);
|
||||
|
||||
AddMovieTokens(tokenHandlers, movie);
|
||||
AddReleaseDateTokens(tokenHandlers, movie.Year); //In case we want to separate the year
|
||||
AddImdbIdTokens(tokenHandlers, movie.ImdbId);
|
||||
AddQualityTokens(tokenHandlers, movie, movieFile);
|
||||
AddMediaInfoTokens(tokenHandlers, movieFile);
|
||||
AddMovieFileTokens(tokenHandlers, movieFile);
|
||||
|
||||
var fileName = ReplaceTokens(pattern, tokenHandlers, namingConfig).Trim();
|
||||
fileName = FileNameCleanupRegex.Replace(fileName, match => match.Captures[0].Value[0].ToString());
|
||||
fileName = TrimSeparatorsRegex.Replace(fileName, string.Empty);
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public string BuildFilePath(Series series, int seasonNumber, string fileName, string extension)
|
||||
{
|
||||
Ensure.That(extension, () => extension).IsNotNullOrWhiteSpace();
|
||||
|
||||
var path = BuildSeasonPath(series, seasonNumber);
|
||||
|
||||
return Path.Combine(path, fileName + extension);
|
||||
}
|
||||
|
||||
public string BuildFilePath(Movie movie, string fileName, string extension)
|
||||
{
|
||||
Ensure.That(extension, () => extension).IsNotNullOrWhiteSpace();
|
||||
|
||||
var path = movie.Path;
|
||||
|
||||
return Path.Combine(path, fileName + extension);
|
||||
}
|
||||
|
||||
public string BuildSeasonPath(Series series, int seasonNumber)
|
||||
{
|
||||
var path = series.Path;
|
||||
|
||||
if (series.SeasonFolder)
|
||||
{
|
||||
if (seasonNumber == 0)
|
||||
{
|
||||
path = Path.Combine(path, "Specials");
|
||||
}
|
||||
else
|
||||
{
|
||||
var seasonFolder = GetSeasonFolder(series, seasonNumber);
|
||||
|
||||
seasonFolder = CleanFileName(seasonFolder);
|
||||
|
||||
path = Path.Combine(path, seasonFolder);
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
public BasicNamingConfig GetBasicNamingConfig(NamingConfig nameSpec)
|
||||
{
|
||||
return new BasicNamingConfig(); //For now let's be lazy
|
||||
|
||||
var episodeFormat = GetEpisodeFormat(nameSpec.StandardEpisodeFormat).LastOrDefault();
|
||||
|
||||
if (episodeFormat == null)
|
||||
{
|
||||
return new BasicNamingConfig();
|
||||
}
|
||||
|
||||
var basicNamingConfig = new BasicNamingConfig
|
||||
{
|
||||
Separator = episodeFormat.Separator,
|
||||
NumberStyle = episodeFormat.SeasonEpisodePattern
|
||||
};
|
||||
|
||||
var titleTokens = TitleRegex.Matches(nameSpec.StandardEpisodeFormat);
|
||||
|
||||
foreach (Match match in titleTokens)
|
||||
{
|
||||
var separator = match.Groups["separator"].Value;
|
||||
var token = match.Groups["token"].Value;
|
||||
|
||||
if (!separator.Equals(" "))
|
||||
{
|
||||
basicNamingConfig.ReplaceSpaces = true;
|
||||
}
|
||||
|
||||
if (token.StartsWith("{Series", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
basicNamingConfig.IncludeSeriesTitle = true;
|
||||
}
|
||||
|
||||
if (token.StartsWith("{Episode", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
basicNamingConfig.IncludeEpisodeTitle = true;
|
||||
}
|
||||
|
||||
if (token.StartsWith("{Quality", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
basicNamingConfig.IncludeQuality = true;
|
||||
}
|
||||
}
|
||||
|
||||
return basicNamingConfig;
|
||||
}
|
||||
|
||||
public string GetSeriesFolder(Series series, NamingConfig namingConfig = null)
|
||||
{
|
||||
if (namingConfig == null)
|
||||
{
|
||||
namingConfig = _namingConfigService.GetConfig();
|
||||
}
|
||||
|
||||
var tokenHandlers = new Dictionary<string, Func<TokenMatch, string>>(FileNameBuilderTokenEqualityComparer.Instance);
|
||||
|
||||
AddSeriesTokens(tokenHandlers, series);
|
||||
|
||||
return CleanFolderName(ReplaceTokens(namingConfig.SeriesFolderFormat, tokenHandlers, namingConfig));
|
||||
}
|
||||
|
||||
public string GetSeasonFolder(Series series, int seasonNumber, NamingConfig namingConfig = null)
|
||||
{
|
||||
if (namingConfig == null)
|
||||
{
|
||||
namingConfig = _namingConfigService.GetConfig();
|
||||
}
|
||||
|
||||
var tokenHandlers = new Dictionary<string, Func<TokenMatch, string>>(FileNameBuilderTokenEqualityComparer.Instance);
|
||||
|
||||
AddSeriesTokens(tokenHandlers, series);
|
||||
AddSeasonTokens(tokenHandlers, seasonNumber);
|
||||
|
||||
return CleanFolderName(ReplaceTokens(namingConfig.SeasonFolderFormat, tokenHandlers, namingConfig));
|
||||
}
|
||||
|
||||
public string GetMovieFolder(Movie movie, NamingConfig namingConfig = null)
|
||||
{
|
||||
if(namingConfig == null)
|
||||
{
|
||||
namingConfig = _namingConfigService.GetConfig();
|
||||
}
|
||||
|
||||
var tokenHandlers = new Dictionary<string, Func<TokenMatch, string>>(FileNameBuilderTokenEqualityComparer.Instance);
|
||||
|
||||
AddMovieTokens(tokenHandlers, movie);
|
||||
AddReleaseDateTokens(tokenHandlers, movie.Year);
|
||||
AddImdbIdTokens(tokenHandlers, movie.ImdbId);
|
||||
|
||||
return CleanFolderName(ReplaceTokens(namingConfig.MovieFolderFormat, tokenHandlers, namingConfig));
|
||||
}
|
||||
|
||||
public static string CleanTitle(string title)
|
||||
{
|
||||
title = title.Replace("&", "and");
|
||||
title = ScenifyReplaceChars.Replace(title, " ");
|
||||
title = ScenifyRemoveChars.Replace(title, string.Empty);
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
public static string TitleThe(string title)
|
||||
{
|
||||
string[] prefixes = { "The ", "An ", "A " };
|
||||
foreach (string prefix in prefixes)
|
||||
{
|
||||
int prefix_length = prefix.Length;
|
||||
if (prefix.ToLower() == title.Substring(0, prefix_length).ToLower())
|
||||
{
|
||||
title = title.Substring(prefix_length) + ", " + prefix.Trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return title.Trim();
|
||||
}
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
@ -41,6 +375,9 @@ namespace NzbDrone.Core.Organizer
|
|||
private static readonly Regex EpisodeRegex = new Regex(@"(?<episode>\{episode(?:\:0+)?})",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly Regex TagsRegex = new Regex(@"(?<tags>\{tags(?:\:0+)?})",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly Regex SeasonRegex = new Regex(@"(?<season>\{season(?:\:0+)?})",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
|
@ -165,6 +502,7 @@ namespace NzbDrone.Core.Organizer
|
|||
AddQualityTokens(tokenHandlers, movie, movieFile);
|
||||
AddMediaInfoTokens(tokenHandlers, movieFile);
|
||||
AddMovieFileTokens(tokenHandlers, movieFile);
|
||||
AddTagsTokens(tokenHandlers, movieFile);
|
||||
|
||||
var fileName = ReplaceTokens(pattern, tokenHandlers, namingConfig).Trim();
|
||||
fileName = FileNameCleanupRegex.Replace(fileName, match => match.Captures[0].Value[0].ToString());
|
||||
|
@ -316,20 +654,6 @@ namespace NzbDrone.Core.Organizer
|
|||
return title;
|
||||
}
|
||||
|
||||
public static string TitleThe(string title)
|
||||
{
|
||||
string[] prefixes = { "The ", "An ", "A " };
|
||||
foreach (string prefix in prefixes)
|
||||
{
|
||||
int prefix_length = prefix.Length;
|
||||
if (prefix.ToLower() == title.Substring(0, prefix_length).ToLower())
|
||||
{
|
||||
title = title.Substring(prefix_length) + ", " + prefix.Trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return title.Trim();
|
||||
}
|
||||
|
||||
public static string CleanFileName(string name, bool replace = true)
|
||||
|
@ -491,6 +815,14 @@ namespace NzbDrone.Core.Organizer
|
|||
tokenHandlers["{Movie Title The}"] = m => TitleThe(movie.Title);
|
||||
}
|
||||
|
||||
private void AddTagsTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, MovieFile movieFile)
|
||||
{
|
||||
if (movieFile.Edition.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
tokenHandlers["{Edition Tags}"] = m => CultureInfo.CurrentCulture.TextInfo.ToTitleCase(movieFile.Edition.ToLower());
|
||||
}
|
||||
}
|
||||
|
||||
private void AddReleaseDateTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, int releaseYear)
|
||||
{
|
||||
tokenHandlers["{Release Year}"] = m => string.Format("{0}", releaseYear.ToString()); //Do I need m.CustomFormat?
|
||||
|
@ -1064,4 +1396,4 @@ namespace NzbDrone.Core.Organizer
|
|||
Range = 4,
|
||||
PrefixedRange = 5
|
||||
}
|
||||
}
|
||||
}
|
|
@ -125,7 +125,8 @@ namespace NzbDrone.Core.Organizer
|
|||
RelativePath = "Movie.Title.2010.1080p.BluRay.DTS.x264-EVOLVE.mkv",
|
||||
SceneName = "Movie.Title.2010.1080p.BluRay.DTS.x264-EVOLVE",
|
||||
ReleaseGroup = "RlsGrp",
|
||||
MediaInfo = mediaInfo
|
||||
MediaInfo = mediaInfo,
|
||||
Edition = "Ultimate extended edition",
|
||||
};
|
||||
|
||||
_singleEpisodeFile = new EpisodeFile
|
||||
|
|
|
@ -12,5 +12,6 @@
|
|||
ThreeLetterCode = threeLetterCode;
|
||||
Language = language;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,20 +18,20 @@ namespace NzbDrone.Core.Parser
|
|||
private static readonly Regex[] ReportMovieTitleRegex = new[]
|
||||
{
|
||||
//Special, Despecialized, etc. Edition Movies, e.g: Mission.Impossible.3.Special.Edition.2011
|
||||
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<edition>(\.?((Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Final|Extended|Rogue|Special|Despecialized).(Cut|Edition|Version)|Extended|Uncensored|Remastered|Unrated|Uncut|IMAX)))\.(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)",
|
||||
new Regex(@"^(?<title>(?![(\[]).+?)?(?:(?:[-_\W](?<![)\[!]))*(?<edition>(\.?((Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Final|Extended|Rogue|Special|Despecialized).(Cut|Edition|Version)|Extended|Uncensored|Remastered|Unrated|Uncut|IMAX)))\.(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)",
|
||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||
//Special, Despecialized, etc. Edition Movies, e.g: Mission.Impossible.3.2011.Special.Edition //TODO: Seems to slow down parsing heavily!
|
||||
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)(?<edition>((Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Final|Extended|Rogue|Special|Despecialized).(Cut|Edition|Version)|Extended|Uncensored|Remastered|Unrated|Uncut|IMAX))",
|
||||
new Regex(@"^(?<title>(?![(\[]).+?)?(?:(?:[-_\W](?<![)\[!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)(?<edition>((Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Final|Extended|Rogue|Special|Despecialized).(Cut|Edition|Version)|Extended|Uncensored|Remastered|Unrated|Uncut|IMAX))",
|
||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||
|
||||
//Normal movie format, e.g: Mission.Impossible.3.2011
|
||||
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)",
|
||||
new Regex(@"^(?<title>(?![(\[]).+?)?(?:(?:[-_\W](?<![)\[!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)",
|
||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||
//PassThePopcorn Torrent names: Star.Wars[PassThePopcorn]
|
||||
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![()\[!]))*(?<year>(\[\w *\])))+(\W+|_|$)(?!\\)",
|
||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||
//That did not work? Maybe some tool uses [] for years. Who would do that?
|
||||
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\W\d+)))+(\W+|_|$)(?!\\)",
|
||||
new Regex(@"^(?<title>(?![(\[]).+?)?(?:(?:[-_\W](?<![)!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\W\d+)))+(\W+|_|$)(?!\\)",
|
||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||
};
|
||||
|
||||
|
@ -696,6 +696,12 @@ namespace NzbDrone.Core.Parser
|
|||
|
||||
private static ParsedMovieInfo ParseMovieMatchCollection(MatchCollection matchCollection)
|
||||
{
|
||||
if (!matchCollection[0].Groups["title"].Success)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
var seriesName = matchCollection[0].Groups["title"].Value.Replace('.', ' ').Replace('_', ' ');
|
||||
seriesName = RequestInfoRegex.Replace(seriesName, "").Trim(' ');
|
||||
|
||||
|
|
|
@ -396,9 +396,15 @@ namespace NzbDrone.Core.Parser
|
|||
|
||||
if (searchCriteria == null)
|
||||
{
|
||||
|
||||
movie = _movieService.FindByTitle(parsedEpisodeInfo.MovieTitle); //Todo: same as above!
|
||||
|
||||
if (parsedEpisodeInfo.Year > 1900)
|
||||
{
|
||||
movie = _movieService.FindByTitle(parsedEpisodeInfo.MovieTitle, parsedEpisodeInfo.Year);
|
||||
//Todo: same as above!
|
||||
}
|
||||
else
|
||||
{
|
||||
movie = _movieService.FindByTitle(parsedEpisodeInfo.MovieTitle); //Todo: same as above!
|
||||
}
|
||||
return movie;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace NzbDrone.Core.Profiles
|
|||
public string Name { get; set; }
|
||||
public Quality Cutoff { get; set; }
|
||||
public List<ProfileQualityItem> Items { get; set; }
|
||||
public List<string> PreferredTags { get; set; }
|
||||
public Language Language { get; set; }
|
||||
|
||||
public Quality LastAllowedQuality()
|
||||
|
|
|
@ -3,6 +3,7 @@ using NzbDrone.Core.IndexerSearch;
|
|||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
|
@ -37,7 +38,7 @@ namespace NzbDrone.Core.Tv
|
|||
|
||||
if (movie.AddOptions.SearchForMovie)
|
||||
{
|
||||
_commandQueueManager.Push(new MoviesSearchCommand { MovieId = movie.Id});
|
||||
_commandQueueManager.Push(new MoviesSearchCommand { MovieIds = new List<int> { movie.Id } });
|
||||
}
|
||||
|
||||
movie.AddOptions = null;
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace NzbDrone.Core.Tv
|
|||
|
||||
try
|
||||
{
|
||||
movieInfo = _movieInfo.GetMovieInfo(movie.TmdbId);
|
||||
movieInfo = _movieInfo.GetMovieInfo(movie.TmdbId, movie.Profile);
|
||||
}
|
||||
catch (MovieNotFoundException)
|
||||
{
|
||||
|
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 81 KiB |
BIN
src/Radarr.ico
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 81 KiB |
|
@ -1,7 +1,7 @@
|
|||
var Marionette = require('marionette');
|
||||
var Backgrid = require('backgrid');
|
||||
var QueueCollection = require('./QueueCollection');
|
||||
var SeriesTitleCell = require('../../Cells/MovieTitleCell');
|
||||
var MovieTitleCell = require('../../Cells/MovieTitleCell');
|
||||
var EpisodeNumberCell = require('../../Cells/EpisodeNumberCell');
|
||||
var EpisodeTitleCell = require('../../Cells/EpisodeTitleCell');
|
||||
var QualityCell = require('../../Cells/QualityCell');
|
||||
|
@ -30,7 +30,7 @@ module.exports = Marionette.Layout.extend({
|
|||
{
|
||||
name : 'movie',
|
||||
label : 'Movie',
|
||||
cell : SeriesTitleCell
|
||||
cell : MovieTitleCell
|
||||
},
|
||||
/*{
|
||||
name : 'episode',
|
||||
|
|
|
@ -6,9 +6,7 @@ module.exports = TemplatedCell.extend({
|
|||
|
||||
|
||||
render : function() {
|
||||
this.$el.html(this.model.get("movie").get("title")); //Hack, but somehow handlebar helper does not work.
|
||||
debugger;
|
||||
this.$el.html('<a href="movies/' + this.model.get("movie").get("titleSlug") +'">' + this.model.get("movie").get("title") + '</a>'); //Hack, but somehow handlebar helper does not work.
|
||||
return this;
|
||||
|
||||
}
|
||||
});
|
||||
|
|
|
@ -2,23 +2,26 @@ var $ = require('jquery');
|
|||
var vent = require('./vent');
|
||||
|
||||
module.exports = {
|
||||
ConfigNamespace : 'Radarr.',
|
||||
|
||||
Events : {
|
||||
ConfigUpdatedEvent : 'ConfigUpdatedEvent'
|
||||
},
|
||||
|
||||
Keys : {
|
||||
DefaultProfileId : 'DefaultProfileId',
|
||||
DefaultRootFolderId : 'DefaultRootFolderId',
|
||||
UseSeasonFolder : 'UseSeasonFolder',
|
||||
DefaultSeriesType : 'DefaultSeriesType',
|
||||
MonitorEpisodes : 'MonitorEpisodes',
|
||||
AdvancedSettings : 'advancedSettings'
|
||||
DefaultProfileId : 'RadarrDefaultProfileId',
|
||||
DefaultRootFolderId : 'RadarrDefaultRootFolderId',
|
||||
UseSeasonFolder : 'RadarrUseSeasonFolder',
|
||||
DefaultSeriesType : 'RadarrDefaultSeriesType',
|
||||
MonitorEpisodes : 'RadarrMonitorEpisodes',
|
||||
AdvancedSettings : 'RadarradvancedSettings'
|
||||
},
|
||||
|
||||
getValueJson : function (key, defaultValue) {
|
||||
var storeKey = this.ConfigNamespace + key;
|
||||
defaultValue = defaultValue || {};
|
||||
|
||||
var storeValue = window.localStorage.getItem(key);
|
||||
var storeValue = window.localStorage.getItem(storeKey);
|
||||
|
||||
if (!storeValue) {
|
||||
return defaultValue;
|
||||
|
@ -34,7 +37,8 @@ module.exports = {
|
|||
},
|
||||
|
||||
getValue : function(key, defaultValue) {
|
||||
var storeValue = window.localStorage.getItem(key);
|
||||
var storeKey = this.ConfigNamespace + key;
|
||||
var storeValue = window.localStorage.getItem(storeKey);
|
||||
|
||||
if (!storeValue) {
|
||||
return defaultValue;
|
||||
|
@ -48,22 +52,22 @@ module.exports = {
|
|||
},
|
||||
|
||||
setValue : function(key, value) {
|
||||
|
||||
console.log('Config: [{0}] => [{1}]'.format(key, value));
|
||||
var storeKey = this.ConfigNamespace + key;
|
||||
console.log('Config: [{0}] => [{1}]'.format(storeKey, value));
|
||||
|
||||
if (this.getValue(key) === value.toString()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
window.localStorage.setItem(key, value);
|
||||
window.localStorage.setItem(storeKey, value);
|
||||
vent.trigger(this.Events.ConfigUpdatedEvent, {
|
||||
key : key,
|
||||
value : value
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Unable to save config: [{0}] => [{1}]'.format(key, value));
|
||||
console.error('Unable to save config: [{0}] => [{1}]'.format(storeKey, value));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 15 KiB |
BIN
src/UI/Content/Images/favicon/android-chrome-144x144.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
src/UI/Content/Images/favicon/android-chrome-192x192.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
src/UI/Content/Images/favicon/android-chrome-256x256.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
src/UI/Content/Images/favicon/android-chrome-36x36.png
Normal file
After Width: | Height: | Size: 862 B |
BIN
src/UI/Content/Images/favicon/android-chrome-384x384.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
src/UI/Content/Images/favicon/android-chrome-48x48.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
src/UI/Content/Images/favicon/android-chrome-512x512.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
src/UI/Content/Images/favicon/android-chrome-72x72.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src/UI/Content/Images/favicon/android-chrome-96x96.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2 KiB |