1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-04-18 21:35:51 -04:00

Compare commits

...

19 Commits

Author SHA1 Message Date
Leonardo Galli
3d67f6237e Should fix 4K releases not getting parsed. 2017-01-21 00:39:44 +01:00
Krystian Charubin
a691ffa7b7 adds 'Movie Title, The' filename option (#359)
* adds 'Movie Title, The' filename option
* updates the FileNameBuilder.MovieTitleRegex to include new format
2017-01-20 17:42:14 -05:00
Leonardo Galli
aa9537c201 Fix issue when movie file is null. 2017-01-20 20:30:36 +01:00
Leonardo Galli
a3d9fb1c20 Should fix upgrading of existing movie files. 2017-01-20 18:26:18 +01:00
Leonardo Galli
62a1e70c86 Add tests for 4K quality. 2017-01-20 18:21:31 +01:00
Leonardo Galli
93d0d21846 Hopefully a fix for corrupt media covers. 2017-01-20 18:06:58 +01:00
Leonardo Galli
b1c5a3ac14 Fixed blacklist being ignored by download decision maker. 2017-01-20 17:48:47 +01:00
vertigo235
55a525ba2f Add helptext to nzbget "add paused" settings. (#363)
Requires nzbget 16 or greater.
2017-01-20 09:14:15 -05:00
Devin Buhl
a53768463b Merge pull request #358 from Radarr/patch/add-year-to-search
add year to search
2017-01-19 20:07:33 -05:00
Tim Turner
24cbd6bcef Fix issue with reimporting on movie fresh (#357)
Fixes #314. Still have multiple movieFiles issue to clean up.
2017-01-19 19:58:57 -05:00
Devin Buhl
3ab3e66853 Add year to quick search results 2017-01-19 19:56:26 -05:00
Leonardo Galli
40ca469339 Update MovieModule 2017-01-20 00:00:12 +01:00
Tim Turner
2cbd2f719f Merge branch 'develop' of https://github.com/Radarr/Radarr into develop 2017-01-19 16:45:39 -05:00
Tim Turner
53cbfa803b Fix MediaCoversUpdatedEvent broadcast
Cleans exception when updating media covers expects a series Id.
2017-01-19 16:45:29 -05:00
Leonardo Galli
c0b0310bbd Update ISSUE_TEMPLATE.md 2017-01-19 22:10:59 +01:00
Devin Buhl
30e50062a8 Merge pull request #352 from baltoaca/develop
bug fix for 15 movie wanted tab limit
2017-01-19 13:17:40 -05:00
Vlad Ilies
85fd8f2c65 bug fix for 15 movie wanted tab (#348) 2017-01-19 20:08:15 +02:00
Leonardo Galli
f72b042d5d Blacklisting works now. 2017-01-19 17:43:23 +01:00
Leonardo Galli
2d3a3a0677 Update sizing information in settings tab. 2017-01-19 17:40:25 +01:00
28 changed files with 311 additions and 214 deletions

View File

@@ -1,6 +1,8 @@
Please use the search bar and make sure you are not submitting an already submitted issue.
Provide a description of the feature request or bug, the more details the better. Provide a description of the feature request or bug, the more details the better.
When possible include a log! When possible include a log!

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using NzbDrone.Api.Movie;
using NzbDrone.Api.REST; using NzbDrone.Api.REST;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Api.Series; using NzbDrone.Api.Series;
@@ -11,13 +12,14 @@ namespace NzbDrone.Api.Blacklist
{ {
public int SeriesId { get; set; } public int SeriesId { get; set; }
public List<int> EpisodeIds { get; set; } public List<int> EpisodeIds { get; set; }
public int MovieId { get; set; }
public string SourceTitle { get; set; } public string SourceTitle { get; set; }
public QualityModel Quality { get; set; } public QualityModel Quality { get; set; }
public DateTime Date { get; set; } public DateTime Date { get; set; }
public DownloadProtocol Protocol { get; set; } public DownloadProtocol Protocol { get; set; }
public string Indexer { get; set; } public string Indexer { get; set; }
public string Message { get; set; } public string Message { get; set; }
public MovieResource Movie { get; set; }
public SeriesResource Series { get; set; } public SeriesResource Series { get; set; }
} }
@@ -30,7 +32,7 @@ namespace NzbDrone.Api.Blacklist
return new BlacklistResource return new BlacklistResource
{ {
Id = model.Id, Id = model.Id,
MovieId = model.MovieId,
SeriesId = model.SeriesId, SeriesId = model.SeriesId,
EpisodeIds = model.EpisodeIds, EpisodeIds = model.EpisodeIds,
SourceTitle = model.SourceTitle, SourceTitle = model.SourceTitle,
@@ -39,7 +41,7 @@ namespace NzbDrone.Api.Blacklist
Protocol = model.Protocol, Protocol = model.Protocol,
Indexer = model.Indexer, Indexer = model.Indexer,
Message = model.Message, Message = model.Message,
Movie = model.Movie.ToResource(),
Series = model.Series.ToResource() Series = model.Series.ToResource()
}; };
} }

View File

@@ -201,6 +201,8 @@ namespace NzbDrone.Api.Movie
//var mappings = null;//_sceneMappingService.FindByTvdbId(resource.TvdbId); //var mappings = null;//_sceneMappingService.FindByTvdbId(resource.TvdbId);
//if (mappings == null) return; //if (mappings == null) return;
//Not necessary anymore
//resource.AlternateTitles = mappings.Select(v => new AlternateTitleResource { Title = v.Title, SeasonNumber = v.SeasonNumber, SceneSeasonNumber = v.SceneSeasonNumber }).ToList(); //resource.AlternateTitles = mappings.Select(v => new AlternateTitleResource { Title = v.Title, SeasonNumber = v.SeasonNumber, SceneSeasonNumber = v.SceneSeasonNumber }).ToList();
} }
@@ -239,7 +241,7 @@ namespace NzbDrone.Api.Movie
public void Handle(MediaCoversUpdatedEvent message) public void Handle(MediaCoversUpdatedEvent message)
{ {
//BroadcastResourceChange(ModelAction.Updated, message.Movie.Id); BroadcastResourceChange(ModelAction.Updated, message.Movie.Id);
} }
} }
} }

View File

@@ -236,7 +236,7 @@ namespace NzbDrone.Api.Series
public void Handle(MediaCoversUpdatedEvent message) public void Handle(MediaCoversUpdatedEvent message)
{ {
BroadcastResourceChange(ModelAction.Updated, message.Series.Id); //BroadcastResourceChange(ModelAction.Updated, message.Series.Id);
} }
} }
} }

View File

@@ -47,5 +47,17 @@ namespace NzbDrone.Core.Test.ParserTests
{ {
QualityParser.ParseQuality(title).Revision.Version.Should().Be(version); QualityParser.ParseQuality(title).Revision.Version.Should().Be(version);
} }
[TestCase("Deadpool 2016 2160p 4K UltraHD BluRay DTS-HD MA 7 1 x264-Whatevs", 19)]
[TestCase("Deadpool 2016 2160p 4K UltraHD DTS-HD MA 7 1 x264-Whatevs", 16)]
[TestCase("Deadpool 2016 4K 2160p UltraHD BluRay AAC2 0 HEVC x265", 19)]
[TestCase("The Revenant 2015 2160p UHD BluRay DTS x264-Whatevs", 19)]
[TestCase("The Revenant 2015 2160p UHD BluRay FLAC 7 1 x264-Whatevs", 19)]
[TestCase("The Martian 2015 2160p Ultra HD BluRay DTS-HD MA 7 1 x264-Whatevs", 19)]
[TestCase("Into the Inferno 2016 2160p Netflix WEBRip DD5 1 x264-Whatevs", 18)]
public void should_parse_ultrahd_from_title(string title, int version)
{
QualityParser.ParseQuality(title).Quality.Id.Should().Be(version);
}
} }
} }

View File

@@ -11,6 +11,8 @@ namespace NzbDrone.Core.Blacklisting
{ {
public int SeriesId { get; set; } public int SeriesId { get; set; }
public Series Series { get; set; } public Series Series { get; set; }
public int MovieId { get; set; }
public Movie Movie { get; set; }
public List<int> EpisodeIds { get; set; } public List<int> EpisodeIds { get; set; }
public string SourceTitle { get; set; } public string SourceTitle { get; set; }
public QualityModel Quality { get; set; } public QualityModel Quality { get; set; }

View File

@@ -10,7 +10,7 @@ namespace NzbDrone.Core.Blacklisting
{ {
List<Blacklist> BlacklistedByTitle(int seriesId, string sourceTitle); List<Blacklist> BlacklistedByTitle(int seriesId, string sourceTitle);
List<Blacklist> BlacklistedByTorrentInfoHash(int seriesId, string torrentInfoHash); List<Blacklist> BlacklistedByTorrentInfoHash(int seriesId, string torrentInfoHash);
List<Blacklist> BlacklistedBySeries(int seriesId); List<Blacklist> BlacklistedByMovie(int seriesId);
} }
public class BlacklistRepository : BasicRepository<Blacklist>, IBlacklistRepository public class BlacklistRepository : BasicRepository<Blacklist>, IBlacklistRepository
@@ -20,15 +20,15 @@ namespace NzbDrone.Core.Blacklisting
{ {
} }
public List<Blacklist> BlacklistedByTitle(int seriesId, string sourceTitle) public List<Blacklist> BlacklistedByTitle(int movieId, string sourceTitle)
{ {
return Query.Where(e => e.SeriesId == seriesId) return Query.Where(e => e.MovieId == movieId)
.AndWhere(e => e.SourceTitle.Contains(sourceTitle)); .AndWhere(e => e.SourceTitle.Contains(sourceTitle));
} }
public List<Blacklist> BlacklistedByTorrentInfoHash(int seriesId, string torrentInfoHash) public List<Blacklist> BlacklistedByTorrentInfoHash(int movieId, string torrentInfoHash)
{ {
return Query.Where(e => e.SeriesId == seriesId) return Query.Where(e => e.MovieId == movieId)
.AndWhere(e => e.TorrentInfoHash.Contains(torrentInfoHash)); .AndWhere(e => e.TorrentInfoHash.Contains(torrentInfoHash));
} }
@@ -37,9 +37,14 @@ namespace NzbDrone.Core.Blacklisting
return Query.Where(b => b.SeriesId == seriesId); return Query.Where(b => b.SeriesId == seriesId);
} }
public List<Blacklist> BlacklistedByMovie(int movieId)
{
return Query.Where(b => b.MovieId == movieId);
}
protected override SortBuilder<Blacklist> GetPagedQuery(QueryBuilder<Blacklist> query, PagingSpec<Blacklist> pagingSpec) protected override SortBuilder<Blacklist> GetPagedQuery(QueryBuilder<Blacklist> query, PagingSpec<Blacklist> pagingSpec)
{ {
var baseQuery = query.Join<Blacklist, Series>(JoinType.Inner, h => h.Series, (h, s) => h.SeriesId == s.Id); var baseQuery = query.Join<Blacklist, Movie>(JoinType.Inner, h => h.Movie, (h, s) => h.MovieId == s.Id);
return base.GetPagedQuery(baseQuery, pagingSpec); return base.GetPagedQuery(baseQuery, pagingSpec);
} }

View File

@@ -21,7 +21,7 @@ namespace NzbDrone.Core.Blacklisting
IExecute<ClearBlacklistCommand>, IExecute<ClearBlacklistCommand>,
IHandle<DownloadFailedEvent>, IHandle<DownloadFailedEvent>,
IHandleAsync<SeriesDeletedEvent> IHandleAsync<MovieDeletedEvent>
{ {
private readonly IBlacklistRepository _blacklistRepository; private readonly IBlacklistRepository _blacklistRepository;
@@ -128,8 +128,9 @@ namespace NzbDrone.Core.Blacklisting
{ {
var blacklist = new Blacklist var blacklist = new Blacklist
{ {
SeriesId = message.SeriesId, SeriesId = 0,
EpisodeIds = message.EpisodeIds, EpisodeIds = message.EpisodeIds,
MovieId = message.MovieId,
SourceTitle = message.SourceTitle, SourceTitle = message.SourceTitle,
Quality = message.Quality, Quality = message.Quality,
Date = DateTime.UtcNow, Date = DateTime.UtcNow,
@@ -144,9 +145,9 @@ namespace NzbDrone.Core.Blacklisting
_blacklistRepository.Insert(blacklist); _blacklistRepository.Insert(blacklist);
} }
public void HandleAsync(SeriesDeletedEvent message) public void HandleAsync(MovieDeletedEvent message)
{ {
var blacklisted = _blacklistRepository.BlacklistedBySeries(message.Series.Id); var blacklisted = _blacklistRepository.BlacklistedByMovie(message.Movie.Id);
_blacklistRepository.DeleteMany(blacklisted); _blacklistRepository.DeleteMany(blacklisted);
} }

View File

@@ -0,0 +1,22 @@
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(122)]
public class add_movieid_to_blacklist : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("Blacklist").AddColumn("MovieId").AsInt32().Nullable().WithDefaultValue(0);
Alter.Table("Blacklist").AlterColumn("SeriesId").AsInt32().Nullable();
Alter.Table("Blacklist").AlterColumn("EpisodeIds").AsString().Nullable();
}
}
}

View File

@@ -33,7 +33,11 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
public Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase searchCriteria) public Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase searchCriteria)
{ {
throw new NotImplementedException(); if (_blacklistService.Blacklisted(subject.Movie.Id, subject.Release))
{
_logger.Debug("{0} is blacklisted, rejecting.", subject.Release.Title);
return Decision.Reject("Release is blacklisted");
}
return Decision.Accept(); return Decision.Accept();
} }

View File

@@ -57,7 +57,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
[FieldDefinition(7, Label = "Use SSL", Type = FieldType.Checkbox)] [FieldDefinition(7, Label = "Use SSL", Type = FieldType.Checkbox)]
public bool UseSsl { get; set; } public bool UseSsl { get; set; }
[FieldDefinition(8, Label = "Add Paused", Type = FieldType.Checkbox)] [FieldDefinition(8, Label = "Add Paused", Type = FieldType.Checkbox, HelpText = "This option requires at least NzbGet version 16.0")]
public bool AddPaused { get; set; } public bool AddPaused { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

View File

@@ -114,7 +114,7 @@ namespace NzbDrone.Core.MediaCover
} }
} }
private void EnsureCovers(Movie movie) private void EnsureCovers(Movie movie, int retried = 0)
{ {
foreach (var cover in movie.Images) foreach (var cover in movie.Images)
{ {
@@ -130,7 +130,25 @@ namespace NzbDrone.Core.MediaCover
} }
catch (WebException e) catch (WebException e)
{ {
_logger.Warn(string.Format("Couldn't download media cover for {0}. {1}", movie, e.Message)); if (e.Status == WebExceptionStatus.ProtocolError)
{
_logger.Warn(e, "Server returned different code than 200. The poster is probably not available yet.");
return;
}
_logger.Warn(e, string.Format("Couldn't download media cover for {0}. {1}", movie, e.Message));
if (retried < 3)
{
retried = +1;
_logger.Warn("Retrying for the {0}. time in ten seconds.", retried);
System.Threading.Thread.Sleep(10*1000);
EnsureCovers(movie, retried);
}
else
{
_logger.Warn(e, "Couldn't download media cover even after retrying five times :(.");
}
} }
catch (Exception e) catch (Exception e)
{ {

View File

@@ -68,22 +68,22 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
{ {
//check if already imported //check if already imported
if (importResults.Select(r => r.ImportDecision.LocalMovie.Movie) if (importResults.Select(r => r.ImportDecision.LocalMovie.Movie)
.Select(e => e.Id).Contains(localMovie.Movie.Id)) .Select(m => m.Id).Contains(localMovie.Movie.Id))
{ {
importResults.Add(new ImportResult(importDecision, "Movie has already been imported")); importResults.Add(new ImportResult(importDecision, "Movie has already been imported"));
continue; continue;
} }
var episodeFile = new MovieFile(); var movieFile = new MovieFile();
episodeFile.DateAdded = DateTime.UtcNow; movieFile.DateAdded = DateTime.UtcNow;
episodeFile.MovieId = localMovie.Movie.Id; movieFile.MovieId = localMovie.Movie.Id;
episodeFile.Path = localMovie.Path.CleanFilePath(); movieFile.Path = localMovie.Path.CleanFilePath();
episodeFile.Size = _diskProvider.GetFileSize(localMovie.Path); movieFile.Size = _diskProvider.GetFileSize(localMovie.Path);
episodeFile.Quality = localMovie.Quality; movieFile.Quality = localMovie.Quality;
episodeFile.MediaInfo = localMovie.MediaInfo; movieFile.MediaInfo = localMovie.MediaInfo;
episodeFile.Movie = localMovie.Movie; movieFile.Movie = localMovie.Movie;
episodeFile.ReleaseGroup = localMovie.ParsedMovieInfo.ReleaseGroup; movieFile.ReleaseGroup = localMovie.ParsedMovieInfo.ReleaseGroup;
episodeFile.Edition = localMovie.ParsedMovieInfo.Edition; movieFile.Edition = localMovie.ParsedMovieInfo.Edition;
bool copyOnly; bool copyOnly;
switch (importMode) switch (importMode)
@@ -102,17 +102,17 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
if (newDownload) if (newDownload)
{ {
episodeFile.SceneName = GetSceneName(downloadClientItem, localMovie); movieFile.SceneName = GetSceneName(downloadClientItem, localMovie);
var moveResult = _episodeFileUpgrader.UpgradeMovieFile(episodeFile, localMovie, copyOnly); var moveResult = _episodeFileUpgrader.UpgradeMovieFile(movieFile, localMovie, copyOnly); //TODO: Check if this works
oldFiles = moveResult.OldFiles; oldFiles = moveResult.OldFiles;
} }
else else
{ {
episodeFile.RelativePath = localMovie.Movie.Path.GetRelativePath(episodeFile.Path); movieFile.RelativePath = localMovie.Movie.Path.GetRelativePath(movieFile.Path);
} }
_mediaFileService.Add(episodeFile); _mediaFileService.Add(movieFile);
importResults.Add(new ImportResult(importDecision)); importResults.Add(new ImportResult(importDecision));
if (newDownload) if (newDownload)
@@ -122,22 +122,22 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
if (downloadClientItem != null) if (downloadClientItem != null)
{ {
_eventAggregator.PublishEvent(new MovieImportedEvent(localMovie, episodeFile, newDownload, downloadClientItem.DownloadClient, downloadClientItem.DownloadId, downloadClientItem.IsReadOnly)); _eventAggregator.PublishEvent(new MovieImportedEvent(localMovie, movieFile, newDownload, downloadClientItem.DownloadClient, downloadClientItem.DownloadId, downloadClientItem.IsReadOnly));
} }
else else
{ {
_eventAggregator.PublishEvent(new MovieImportedEvent(localMovie, episodeFile, newDownload)); _eventAggregator.PublishEvent(new MovieImportedEvent(localMovie, movieFile, newDownload));
} }
if (newDownload) if (newDownload)
{ {
_eventAggregator.PublishEvent(new MovieDownloadedEvent(localMovie, episodeFile, oldFiles)); _eventAggregator.PublishEvent(new MovieDownloadedEvent(localMovie, movieFile, oldFiles));
} }
} }
catch (Exception e) catch (Exception e)
{ {
_logger.Warn(e, "Couldn't import episode " + localMovie); _logger.Warn(e, "Couldn't import movie " + localMovie);
importResults.Add(new ImportResult(importDecision, "Failed to import episode")); importResults.Add(new ImportResult(importDecision, "Failed to import movie"));
} }
} }

View File

@@ -111,11 +111,11 @@ namespace NzbDrone.Core.MediaFiles
public List<string> FilterExistingFiles(List<string> files, Movie movie) public List<string> FilterExistingFiles(List<string> files, Movie movie)
{ {
var seriesFiles = GetFilesBySeries(movie.Id).Select(f => Path.Combine(movie.Path, f.RelativePath)).ToList(); var movieFiles = GetFilesByMovie(movie.Id).Select(f => Path.Combine(movie.Path, f.RelativePath)).ToList();
if (!seriesFiles.Any()) return files; if (!movieFiles.Any()) return files;
return files.Except(seriesFiles, PathEqualityComparer.Instance).ToList(); return files.Except(movieFiles, PathEqualityComparer.Instance).ToList();
} }
public EpisodeFile Get(int id) public EpisodeFile Get(int id)

View File

@@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using NLog; using NLog;
@@ -18,14 +18,17 @@ namespace NzbDrone.Core.MediaFiles
public class MediaFileTableCleanupService : IMediaFileTableCleanupService public class MediaFileTableCleanupService : IMediaFileTableCleanupService
{ {
private readonly IMediaFileService _mediaFileService; private readonly IMediaFileService _mediaFileService;
private readonly IMovieService _movieService;
private readonly IEpisodeService _episodeService; private readonly IEpisodeService _episodeService;
private readonly Logger _logger; private readonly Logger _logger;
public MediaFileTableCleanupService(IMediaFileService mediaFileService, public MediaFileTableCleanupService(IMediaFileService mediaFileService,
IMovieService movieService,
IEpisodeService episodeService, IEpisodeService episodeService,
Logger logger) Logger logger)
{ {
_mediaFileService = mediaFileService; _mediaFileService = mediaFileService;
_movieService = movieService;
_episodeService = episodeService; _episodeService = episodeService;
_logger = logger; _logger = logger;
} }
@@ -89,61 +92,39 @@ namespace NzbDrone.Core.MediaFiles
public void Clean(Movie movie, List<string> filesOnDisk) public void Clean(Movie movie, List<string> filesOnDisk)
{ {
var movieFiles = _mediaFileService.GetFilesByMovie(movie.Id);
//TODO: Update implementation for movies.
var seriesFiles = _mediaFileService.GetFilesBySeries(movie.Id);
var episodes = _episodeService.GetEpisodeBySeries(movie.Id);
var filesOnDiskKeys = new HashSet<string>(filesOnDisk, PathEqualityComparer.Instance); var filesOnDiskKeys = new HashSet<string>(filesOnDisk, PathEqualityComparer.Instance);
foreach (var seriesFile in seriesFiles) foreach(var movieFile in movieFiles)
{ {
var episodeFile = seriesFile; var movieFilePath = Path.Combine(movie.Path, movieFile.RelativePath);
var episodeFilePath = Path.Combine(movie.Path, episodeFile.RelativePath);
try try
{ {
if (!filesOnDiskKeys.Contains(episodeFilePath)) if (!filesOnDiskKeys.Contains(movieFilePath))
{ {
_logger.Debug("File [{0}] no longer exists on disk, removing from db", episodeFilePath); _logger.Debug("File [{0}] no longer exists on disk, removing from db", movieFilePath);
_mediaFileService.Delete(seriesFile, DeleteMediaFileReason.MissingFromDisk); _mediaFileService.Delete(movieFile, DeleteMediaFileReason.MissingFromDisk);
continue; continue;
} }
if (episodes.None(e => e.EpisodeFileId == episodeFile.Id)) //var localMovie = _parsingService.GetLocalMovie(movieFile.Path, movie);
{
_logger.Debug("File [{0}] is not assigned to any episodes, removing from db", episodeFilePath);
_mediaFileService.Delete(episodeFile, DeleteMediaFileReason.NoLinkedEpisodes);
continue;
}
// var localEpsiode = _parsingService.GetLocalEpisode(episodeFile.Path, series); //if (localMovie == null)
// //{
// if (localEpsiode == null || episodes.Count != localEpsiode.Episodes.Count) // _logger.Debug("File [{0}] parsed episodes has changed, removing from db", localMovie.Path);
// { // _mediaFileService.Delete(localMovie);
// _logger.Debug("File [{0}] parsed episodes has changed, removing from db", episodeFile.Path); // continue;
// _mediaFileService.Delete(episodeFile); //}
// continue;
// }
} }
catch (Exception ex) catch (Exception ex)
{ {
var errorMessage = string.Format("Unable to cleanup EpisodeFile in DB: {0}", episodeFile.Id); var errorMessage = string.Format("Unable to cleanup MovieFile in DB: {0}", movieFile.Id);
_logger.Error(ex, errorMessage); _logger.Error(ex, errorMessage);
} }
} }
foreach (var e in episodes)
{
var episode = e;
if (episode.EpisodeFileId > 0 && seriesFiles.None(f => f.Id == episode.EpisodeFileId))
{
episode.EpisodeFileId = 0;
_episodeService.UpdateEpisode(episode);
}
}
} }
} }
} }

View File

@@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@@ -107,7 +107,7 @@ namespace NzbDrone.Core.MediaFiles
return; return;
} }
/* var movies = _movieService.MoviesWithFiles(message.Series.Id); var movies = _movieService.MoviesWithFiles(message.Movie.Id);
var movieFiles = new List<MovieFile>(); var movieFiles = new List<MovieFile>();
var updated = new List<MovieFile>(); var updated = new List<MovieFile>();
@@ -119,7 +119,7 @@ namespace NzbDrone.Core.MediaFiles
movieFiles.Add(movieFile); movieFiles.Add(movieFile);
if (ChangeFileDate(movieFile, message.Series, moviesInFile)) if (ChangeFileDate(movieFile, message.Movie))
{ {
updated.Add(movieFile); updated.Add(movieFile);
} }
@@ -127,13 +127,13 @@ namespace NzbDrone.Core.MediaFiles
if (updated.Any()) if (updated.Any())
{ {
_logger.ProgressDebug("Changed file date for {0} files of {1} in {2}", updated.Count, movieFiles.Count, message.Series.Title); _logger.ProgressDebug("Changed file date for {0} files of {1} in {2}", updated.Count, movieFiles.Count, message.Movie.Title);
} }
else else
{ {
_logger.ProgressDebug("No file dates changed for {0}", message.Series.Title); _logger.ProgressDebug("No file dates changed for {0}", message.Movie.Title);
}*/ }
} }
private bool ChangeFileDateToLocalAirDate(string filePath, string fileDate, string fileTime) private bool ChangeFileDateToLocalAirDate(string filePath, string fileDate, string fileTime)

View File

@@ -38,10 +38,13 @@ namespace NzbDrone.Core.MediaFiles
public MovieFileMoveResult UpgradeMovieFile(MovieFile episodeFile, LocalMovie localEpisode, bool copyOnly = false) public MovieFileMoveResult UpgradeMovieFile(MovieFile episodeFile, LocalMovie localEpisode, bool copyOnly = false)
{ {
_logger.Trace("Upgrading existing episode file.");
var moveFileResult = new MovieFileMoveResult(); var moveFileResult = new MovieFileMoveResult();
localEpisode.Movie.MovieFile.LazyLoad();
var existingFile = localEpisode.Movie.MovieFile; var existingFile = localEpisode.Movie.MovieFile;
existingFile.LazyLoad();
if (existingFile.IsLoaded) if (existingFile.IsLoaded && existingFile.Value != null)
{ {
var file = existingFile.Value; var file = existingFile.Value;
var episodeFilePath = Path.Combine(localEpisode.Movie.Path, file.RelativePath); var episodeFilePath = Path.Combine(localEpisode.Movie.Path, file.RelativePath);
@@ -55,6 +58,10 @@ namespace NzbDrone.Core.MediaFiles
moveFileResult.OldFiles.Add(file); moveFileResult.OldFiles.Add(file);
_mediaFileService.Delete(file, DeleteMediaFileReason.Upgrade); _mediaFileService.Delete(file, DeleteMediaFileReason.Upgrade);
} }
else
{
_logger.Warn("The existing movie file was not lazy loaded.");
}

View File

@@ -183,6 +183,7 @@
<Compile Include="Datastore\Migration\002_remove_tvrage_imdb_unique_constraint.cs" /> <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\003_remove_clean_title_from_scene_mapping.cs" />
<Compile Include="Datastore\Migration\004_updated_history.cs" /> <Compile Include="Datastore\Migration\004_updated_history.cs" />
<Compile Include="Datastore\Migration\122_add_movieid_to_blacklist.cs" />
<Compile Include="Datastore\Migration\121_update_filedate_config.cs" /> <Compile Include="Datastore\Migration\121_update_filedate_config.cs" />
<Compile Include="Datastore\Migration\120_add_studio_to_table.cs" /> <Compile Include="Datastore\Migration\120_add_studio_to_table.cs" />
<Compile Include="Datastore\Migration\119_add_youtube_trailer_id_table .cs" /> <Compile Include="Datastore\Migration\119_add_youtube_trailer_id_table .cs" />

View File

@@ -58,7 +58,7 @@ namespace NzbDrone.Core.Organizer
public static readonly Regex SeriesTitleRegex = new Regex(@"(?<token>\{(?:Series)(?<separator>[- ._])(Clean)?Title\})", public static readonly Regex SeriesTitleRegex = new Regex(@"(?<token>\{(?:Series)(?<separator>[- ._])(Clean)?Title\})",
RegexOptions.Compiled | RegexOptions.IgnoreCase); RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static readonly Regex MovieTitleRegex = new Regex(@"(?<token>\{((?:(Movie|Original))(?<separator>[- ._])(Clean)?Title)\})", public static readonly Regex MovieTitleRegex = new Regex(@"(?<token>\{((?:(Movie|Original))(?<separator>[- ._])(Clean)?Title(The)?)\})",
RegexOptions.Compiled | RegexOptions.IgnoreCase); RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex FileNameCleanupRegex = new Regex(@"([- ._])(\1)+", RegexOptions.Compiled); private static readonly Regex FileNameCleanupRegex = new Regex(@"([- ._])(\1)+", RegexOptions.Compiled);
@@ -316,6 +316,22 @@ namespace NzbDrone.Core.Organizer
return title; 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) public static string CleanFileName(string name, bool replace = true)
{ {
string result = name; string result = name;
@@ -472,6 +488,7 @@ namespace NzbDrone.Core.Organizer
{ {
tokenHandlers["{Movie Title}"] = m => movie.Title; tokenHandlers["{Movie Title}"] = m => movie.Title;
tokenHandlers["{Movie CleanTitle}"] = m => CleanTitle(movie.Title); tokenHandlers["{Movie CleanTitle}"] = m => CleanTitle(movie.Title);
tokenHandlers["{Movie Title The}"] = m => TitleThe(movie.Title);
} }
private void AddReleaseDateTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, int releaseYear) private void AddReleaseDateTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, int releaseYear)

View File

@@ -46,7 +46,7 @@ namespace NzbDrone.Core.Organizer
_movie = new Movie _movie = new Movie
{ {
Title = "Movie Title", Title = "The Movie Title",
Year = 2010, Year = 2010,
ImdbId = "tt0066921" ImdbId = "tt0066921"
}; };

View File

@@ -268,7 +268,7 @@ namespace NzbDrone.Core.Parser
private static readonly Regex ReportImdbId = new Regex(@"(?<imdbid>tt\d{9})", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex ReportImdbId = new Regex(@"(?<imdbid>tt\d{9})", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex SimpleTitleRegex = new Regex(@"(?:480[ip]|576[ip]|720[ip]|1080[ip]|[xh][\W_]?26[45]|DD\W?5\W1|[<>?*:|]|848x480|1280x720|1920x1080|(8|10)b(it)?)\s*", private static readonly Regex SimpleTitleRegex = new Regex(@"(?:480[ip]|576[ip]|720[ip]|1080[ip]|2160[ip]|[xh][\W_]?26[45]|DD\W?5\W1|[<>?*:|]|848x480|1280x720|1920x1080|(8|10)b(it)?)\s*",
RegexOptions.IgnoreCase | RegexOptions.Compiled); RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex WebsitePrefixRegex = new Regex(@"^\[\s*[a-z]+(\.[a-z]+)+\s*\][- ]*", private static readonly Regex WebsitePrefixRegex = new Regex(@"^\[\s*[a-z]+(\.[a-z]+)+\s*\][- ]*",

View File

@@ -4,6 +4,8 @@ using System.Collections.Generic;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Datastore.Extensions; using NzbDrone.Core.Datastore.Extensions;
using Marr.Data.QGen;
using NzbDrone.Core.MediaFiles;
namespace NzbDrone.Core.Tv namespace NzbDrone.Core.Tv
{ {
@@ -15,6 +17,7 @@ namespace NzbDrone.Core.Tv
Movie FindByImdbId(string imdbid); Movie FindByImdbId(string imdbid);
Movie FindByTitleSlug(string slug); Movie FindByTitleSlug(string slug);
List<Movie> MoviesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored); List<Movie> MoviesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored);
List<Movie> MoviesWithFiles(int movieId);
PagingSpec<Movie> MoviesWithoutFiles(PagingSpec<Movie> pagingSpec); PagingSpec<Movie> MoviesWithoutFiles(PagingSpec<Movie> pagingSpec);
List<Movie> GetMoviesByFileId(int fileId); List<Movie> GetMoviesByFileId(int fileId);
void SetFileId(int fileId, int movieId); void SetFileId(int fileId, int movieId);
@@ -134,20 +137,29 @@ namespace NzbDrone.Core.Tv
return query.ToList(); return query.ToList();
} }
public List<Movie> MoviesWithFiles(int movieId)
{
return Query.Join<Movie, MovieFile>(JoinType.Inner, m => m.MovieFile, (m, mf) => m.MovieFileId == mf.Id)
.Where(m => m.Id == movieId);
}
public PagingSpec<Movie> MoviesWithoutFiles(PagingSpec<Movie> pagingSpec) public PagingSpec<Movie> MoviesWithoutFiles(PagingSpec<Movie> pagingSpec)
{ {
var query = Query.Where(pagingSpec.FilterExpression) pagingSpec.TotalRecords = GetMoviesWithoutFilesQuery(pagingSpec).GetRowCount();
pagingSpec.Records = GetMoviesWithoutFilesQuery(pagingSpec).ToList();
return pagingSpec;
}
public SortBuilder<Movie> GetMoviesWithoutFilesQuery(PagingSpec<Movie> pagingSpec)
{
return Query.Where(pagingSpec.FilterExpression)
.AndWhere(m => m.MovieFileId == 0) .AndWhere(m => m.MovieFileId == 0)
.AndWhere(m => m.Status == MovieStatusType.Released) .AndWhere(m => m.Status == MovieStatusType.Released)
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection()) .OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection())
.Skip(pagingSpec.PagingOffset()) .Skip(pagingSpec.PagingOffset())
.Take(pagingSpec.PageSize); .Take(pagingSpec.PageSize);
pagingSpec.Records = query.ToList();
pagingSpec.TotalRecords = pagingSpec.Records.Count;
return pagingSpec;
} }
} }
} }

View File

@@ -35,6 +35,7 @@ namespace NzbDrone.Core.Tv
List<Movie> UpdateMovie(List<Movie> movie); List<Movie> UpdateMovie(List<Movie> movie);
bool MoviePathExists(string folder); bool MoviePathExists(string folder);
void RemoveAddOptions(Movie movie); void RemoveAddOptions(Movie movie);
List<Movie> MoviesWithFiles(int movieId);
} }
public class MovieService : IMovieService, IHandle<MovieFileAddedEvent>, public class MovieService : IMovieService, IHandle<MovieFileAddedEvent>,
@@ -235,6 +236,11 @@ namespace NzbDrone.Core.Tv
return episodes; return episodes;
} }
public List<Movie> MoviesWithFiles(int movieId)
{
return _movieRepository.MoviesWithFiles(movieId);
}
public PagingSpec<Movie> MoviesWithoutFiles(PagingSpec<Movie> pagingSpec) public PagingSpec<Movie> MoviesWithoutFiles(PagingSpec<Movie> pagingSpec)
{ {
var movieResult = _movieRepository.MoviesWithoutFiles(pagingSpec); var movieResult = _movieRepository.MoviesWithoutFiles(pagingSpec);

View File

@@ -25,7 +25,9 @@ $.fn.bindSearch = function() {
minLength : 1 minLength : 1
}, { }, {
name : 'series', name : 'series',
displayKey : 'title', displayKey : function(series) {
return series.title + ' (' + series.year + ')';
},
source : substringMatcher() source : substringMatcher()
}); });

View File

@@ -4,6 +4,7 @@
<li><a href="#" data-token="Movie Title">Movie Title</a></li> <li><a href="#" data-token="Movie Title">Movie Title</a></li>
<li><a href="#" data-token="Movie.Title">Movie.Title</a></li> <li><a href="#" data-token="Movie.Title">Movie.Title</a></li>
<li><a href="#" data-token="Movie_Title">Movie_Title</a></li> <li><a href="#" data-token="Movie_Title">Movie_Title</a></li>
<li><a href="#" data-token="Movie TitleThe">Movie Title, The</a></li>
<li><a href="#" data-token="Movie CleanTitle">Movie CleanTitle</a></li> <li><a href="#" data-token="Movie CleanTitle">Movie CleanTitle</a></li>
<li><a href="#" data-token="Movie.CleanTitle">Movie.CleanTitle</a></li> <li><a href="#" data-token="Movie.CleanTitle">Movie.CleanTitle</a></li>
<li><a href="#" data-token="Movie_CleanTitle">Movie_CleanTitle</a></li> <li><a href="#" data-token="Movie_CleanTitle">Movie_CleanTitle</a></li>

View File

@@ -1,16 +1,16 @@
<fieldset> <fieldset>
<legend>Quality Definitions</legend> <legend>Quality Definitions</legend>
<div class="col-md-11"> <div class="col-md-11">
<div id="quality-definition-list"> <div id="quality-definition-list">
<div class="quality-header x-header hidden-xs"> <div class="quality-header x-header hidden-xs">
<div class="row"> <div class="row">
<span class="col-md-2 col-sm-3">Quality</span> <span class="col-md-2 col-sm-3">Quality</span>
<span class="col-md-2 col-sm-3">Title</span> <span class="col-md-2 col-sm-3">Title</span>
<span class="col-md-4 col-sm-6">Size Limit <i class="icon-sonarr-info" title="Limits are automatically adjusted for the series runtime and number of episodes in the file." /></span> <span class="col-md-4 col-sm-6">Size Limit <i class="icon-sonarr-warning" title="Limits are automatically adjusted for the movie runtime." /></span>
</div> </div>
</div> </div>
<div class="rows x-rows"> <div class="rows x-rows">
</div> </div>
</div> </div>
</div> </div>
</fieldset> </fieldset>

View File

@@ -4,92 +4,92 @@ require('jquery-ui');
var FormatHelpers = require('../../../Shared/FormatHelpers'); var FormatHelpers = require('../../../Shared/FormatHelpers');
var view = Marionette.ItemView.extend({ var view = Marionette.ItemView.extend({
template : 'Settings/Quality/Definition/QualityDefinitionItemViewTemplate', template : 'Settings/Quality/Definition/QualityDefinitionItemViewTemplate',
className : 'row', className : 'row',
slider : {
min : 0,
max : 200,
step : 0.1
},
ui : { slider : {
sizeSlider : '.x-slider', min : 0,
thirtyMinuteMinSize : '.x-min-thirty', max : 200,
sixtyMinuteMinSize : '.x-min-sixty', step : 0.1
thirtyMinuteMaxSize : '.x-max-thirty', },
sixtyMinuteMaxSize : '.x-max-sixty'
},
events : { ui : {
'slide .x-slider' : '_updateSize' sizeSlider : '.x-slider',
}, thirtyMinuteMinSize : '.x-min-thirty',
sixtyMinuteMinSize : '.x-min-sixty',
thirtyMinuteMaxSize : '.x-max-thirty',
sixtyMinuteMaxSize : '.x-max-sixty'
},
initialize : function(options) { events : {
this.profileCollection = options.profiles; 'slide .x-slider' : '_updateSize'
}, },
onRender : function() { initialize : function(options) {
if (this.model.get('quality').id === 0) { this.profileCollection = options.profiles;
this.$el.addClass('row advanced-setting'); },
}
this.ui.sizeSlider.slider({ onRender : function() {
range : true, if (this.model.get('quality').id === 0) {
min : this.slider.min, this.$el.addClass('row advanced-setting');
max : this.slider.max, }
step : this.slider.step,
values : [
this.model.get('minSize') || this.slider.min,
this.model.get('maxSize') || this.slider.max
]
});
this._changeSize(); this.ui.sizeSlider.slider({
}, range : true,
min : this.slider.min,
max : this.slider.max,
step : this.slider.step,
values : [
this.model.get('minSize') || this.slider.min,
this.model.get('maxSize') || this.slider.max
]
});
_updateSize : function(event, ui) { this._changeSize();
var minSize = ui.values[0]; },
var maxSize = ui.values[1];
if (maxSize === this.slider.max) {
maxSize = null;
}
this.model.set('minSize', minSize);
this.model.set('maxSize', maxSize);
this._changeSize(); _updateSize : function(event, ui) {
}, var minSize = ui.values[0];
var maxSize = ui.values[1];
_changeSize : function() { if (maxSize === this.slider.max) {
var minSize = this.model.get('minSize') || this.slider.min; maxSize = null;
var maxSize = this.model.get('maxSize') || null; }
{
var minBytes = minSize * 1024 * 1024;
var minThirty = FormatHelpers.bytes(minBytes * 30, 2);
var minSixty = FormatHelpers.bytes(minBytes * 60, 2);
this.ui.thirtyMinuteMinSize.html(minThirty); this.model.set('minSize', minSize);
this.ui.sixtyMinuteMinSize.html(minSixty); this.model.set('maxSize', maxSize);
}
{ this._changeSize();
if (maxSize === 0 || maxSize === null) { },
this.ui.thirtyMinuteMaxSize.html('Unlimited');
this.ui.sixtyMinuteMaxSize.html('Unlimited');
} else {
var maxBytes = maxSize * 1024 * 1024;
var maxThirty = FormatHelpers.bytes(maxBytes * 30, 2);
var maxSixty = FormatHelpers.bytes(maxBytes * 60, 2);
this.ui.thirtyMinuteMaxSize.html(maxThirty); _changeSize : function() {
this.ui.sixtyMinuteMaxSize.html(maxSixty); var minSize = this.model.get('minSize') || this.slider.min;
} var maxSize = this.model.get('maxSize') || null;
} {
} var minBytes = minSize * 1024 * 1024;
var minThirty = FormatHelpers.bytes(minBytes * 90, 2);
var minSixty = FormatHelpers.bytes(minBytes * 140, 2);
this.ui.thirtyMinuteMinSize.html(minThirty);
this.ui.sixtyMinuteMinSize.html(minSixty);
}
{
if (maxSize === 0 || maxSize === null) {
this.ui.thirtyMinuteMaxSize.html('Unlimited');
this.ui.sixtyMinuteMaxSize.html('Unlimited');
} else {
var maxBytes = maxSize * 1024 * 1024;
var maxThirty = FormatHelpers.bytes(maxBytes * 90, 2);
var maxSixty = FormatHelpers.bytes(maxBytes * 140, 2);
this.ui.thirtyMinuteMaxSize.html(maxThirty);
this.ui.sixtyMinuteMaxSize.html(maxSixty);
}
}
}
}); });
view = AsModelBoundView.call(view); view = AsModelBoundView.call(view);
module.exports = view; module.exports = view;

View File

@@ -1,31 +1,31 @@
<span class="col-md-2 col-sm-3"> <span class="col-md-2 col-sm-3">
{{quality.name}} {{quality.name}}
</span> </span>
<span class="col-md-2 col-sm-3"> <span class="col-md-2 col-sm-3">
<input type="text" class="form-control" name="title"> <input type="text" class="form-control" name="title">
</span> </span>
<span class="col-md-4 col-sm-6"> <span class="col-md-4 col-sm-6">
<div class="x-slider"></div> <div class="x-slider"></div>
<div class="size-label-wrapper"> <div class="size-label-wrapper">
<div class="pull-left"> <div class="pull-left">
<span class="label label-warning x-min-thirty" <span class="label label-warning x-min-thirty"
name="thirtyMinuteMinSize" name="thirtyMinuteMinSize"
title="Minimum size for a 30 minute episode"> title="Minimum size for a 90 minute episode">
</span> </span>
<span class="label label-info x-min-sixty" <span class="label label-info x-min-sixty"
name="sixtyMinuteMinSize" name="sixtyMinuteMinSize"
title="Minimum size for a 60 minute episode"> title="Minimum size for a 140 minute episode">
</span> </span>
</div> </div>
<div class="pull-right"> <div class="pull-right">
<span class="label label-warning x-max-thirty" <span class="label label-warning x-max-thirty"
name="thirtyMinuteMaxSize" name="thirtyMinuteMaxSize"
title="Maximum size for a 30 minute episode"> title="Maximum size for a 90 minute movie">
</span> </span>
<span class="label label-info x-max-sixty" <span class="label label-info x-max-sixty"
name="sixtyMinuteMaxSize" name="sixtyMinuteMaxSize"
title="Maximum size for a 60 minute episode"> title="Maximum size for a 140 minute movie">
</span> </span>
</div> </div>
</div> </div>
</span> </span>