1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-03-20 16:44:37 -04:00

Compare commits

...

61 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
Tim Turner
2bb21fedab Update height of posters to accomodate additional labels 2017-01-18 17:24:32 -05:00
vertigo235
91c820f98b Fix pushover priority values. 2017-01-18 23:16:57 +01:00
Leonardo Galli
7d3118aece Hopefully fix issue when importing
existing scene named movies
2017-01-18 23:02:05 +01:00
Tim Turner
4f4ad77ad1 Add download status to poster view
Fixes #319
2017-01-18 16:54:17 -05:00
Leonardo Galli
42f205a731 Update SkyHookProxy.cs 2017-01-18 22:50:12 +01:00
Devin Buhl
cbb2b778a6 Merge pull request #336 from Radarr/patch/add-imdb-to-naming
Add IMDb ID to file naming
2017-01-18 15:11:16 -05:00
Devin Buhl
b3e03a648d Add IMDb ID to file naming 2017-01-18 14:53:29 -05:00
Devin Buhl
acf45a79e8 Merge pull request #333 from baltoaca/develop
basic implementation of the wanted tab
2017-01-18 14:36:48 -05:00
Devin Buhl
b5d8ac852e Merge pull request #335 from Radarr/patch/task-updates
Turn off scene mapping task #329, update TaskManager to use 'DownloadedMovieScanCommand
2017-01-18 14:36:29 -05:00
Vlad Ilies
4aec0e8fc6 fixed build 2017-01-18 21:09:00 +02:00
Devin Buhl
ecea417fd8 Revert DownloadedMovieScanCommand to DownloadedEpisodesScanCommand
Not sure if it will break anything so putting it back.
2017-01-18 14:07:51 -05:00
Devin Buhl
6a41f6a435 Turn off scene mapping task #329, update TaskManager to use 'DownloadedMovieScanCommand' 2017-01-18 14:02:04 -05:00
Vlad Ilies
da2d075aa8 basic implementation of the wanted tab (#31)
* top buttons don't yet work

* new missing module for movies

*  find missing movies method to movie service

* new movie status cell with text

* adapted UI missing collection and layout
2017-01-18 20:53:17 +02:00
Devin Buhl
10dc3993df Merge pull request #332 from Radarr/revert-318-sonarr/sqlite-updates
Revert "Sonarr/sqlite updates"
2017-01-18 13:33:46 -05:00
Devin Buhl
7e5020db9a Merge pull request #331 from vertigo235/nzbgetaddpaused
Nzbgetaddpaused
2017-01-18 13:20:12 -05:00
Devin Buhl
c48fe9de12 Revert "Sonarr/sqlite updates" 2017-01-18 13:17:35 -05:00
vertigo235
421e827a95 Update Test Files for AddPaused to NZBGET 2017-01-18 13:08:59 -05:00
vertigo235
34d8045cf4 Add "Add Paused" option for NZBGET downloader
Adds option to pause nzbs uppon sending to NZBGET downloader.
2017-01-18 12:42:33 -05:00
Devin Buhl
c6de163748 Merge pull request #318 from Radarr/sonarr/sqlite-updates
Sonarr/sqlite updates
2017-01-17 18:59:11 -05:00
Keivan Beigi
d9e2b22e74 Upgraded System.Data.SQLite to 1.0.104.0 2017-01-17 18:45:23 -05:00
Keivan Beigi
65c0137964 Revert "Upgraded System.Data.SQLite to 1.0.104.0"
This reverts commit a6f3ac219d61964f1b923cfd89382f94c4c74243.
2017-01-17 18:44:37 -05:00
Keivan
ae19424ce7 New: Upgraded SQLite binares for macOS
Upgraded from 3.8.1 to 3.9.1
2017-01-17 18:41:11 -05:00
Keivan Beigi
7527ec52b7 New: Upgraded SQLite binaries for Windows (3.16.0) 2017-01-17 18:41:05 -05:00
Leonardo Galli
640fcf3eaf Remove series references 2017-01-17 23:57:04 +01:00
Leonardo Galli
3ce8232777 Hopefully fix download ordering. 2017-01-17 23:30:11 +01:00
Devin Buhl
864b441d8e Merge pull request #316 from Radarr/patch/skyhook-cleanup
Maybe this will solve the error Object reference not set to an instance of an object
2017-01-17 17:20:49 -05:00
Devin Buhl
bc2ff149b4 Maybe this will solve the error
Couldn't refresh info for [tt2032572][USS Indianapolis: Men of Courage]: Object reference not set to an instance of an object
2017-01-17 17:05:19 -05:00
Devin Buhl
dea305e921 Fix Issue when adding some movies. 2017-01-17 22:25:49 +01:00
Leonardo Galli
e2eab31548 Hopefully fix RSSSync 2017-01-17 21:22:51 +01:00
Devin Buhl
fe62e18f0d Merge pull request #308 from Radarr/patch/jackett
Fix publish date for jackett #239
2017-01-17 13:56:47 -05:00
Devin Buhl
f1fa1553cf Merge pull request #307 from aenima99x/aenima99x-issue91
Fix: Issue #91 - "Search All Missing" wording
2017-01-17 13:48:30 -05:00
Devin Buhl
b576ae813d Fix publish date #239 2017-01-17 13:47:11 -05:00
Aenima99x
99123be936 Fix: Issue #91 - "Search All Missing" wording 2017-01-17 09:00:56 -08:00
Leonardo Galli
dd0a033b0f Add Support for changing file date to either cinema or physical release.
Fixes #124
2017-01-17 15:02:48 +01:00
Leonardo Galli
c64597c9f1 Fix for movies with . in title when importing them. Fixes #268 2017-01-17 14:47:23 +01:00
Leonardo Galli
6d2f81e3ed Remove - as replacement for : 2017-01-17 14:28:30 +01:00
Leonardo Galli
4263808360 Fix only one movie showing. Fix more button not showing up. 2017-01-17 13:21:40 +01:00
Leonardo Galli
c5ca2babf7 Updated website and donation links 2017-01-17 13:07:02 +01:00
Leonardo Galli
08db74d6e6 Fix Audiochannels just being added together. 2017-01-17 13:03:20 +01:00
Leonardo Galli
b309a9b01f Change Scheduled Refresh Series to Refresh Movie. Fixes #301 2017-01-17 12:55:32 +01:00
Tim Turner
2730745607 Clean up rename preview & organize
Fixes #125, #129,

BE SURE TO RUN "Update Library" before renaming/organizing.
2017-01-16 18:43:32 -05:00
Tim Turner
ae0df2aef0 Disambiguate Movie from Episode Renaming
Fixes #84
2017-01-16 17:12:27 -05:00
65 changed files with 1030 additions and 671 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.
When possible include a log!

View File

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

View File

@@ -12,7 +12,7 @@ namespace NzbDrone.Api.Movies
private readonly IRenameMovieFileService _renameMovieFileService;
public RenameMovieModule(IRenameMovieFileService renameMovieFileService)
: base("rename")
: base("renameMovie")
{
_renameMovieFileService = renameMovieFileService;

View File

@@ -260,6 +260,7 @@
<Compile Include="Wanted\CutoffModule.cs" />
<Compile Include="Wanted\LegacyMissingModule.cs" />
<Compile Include="Wanted\MissingModule.cs" />
<Compile Include="Wanted\MovieMissingModule.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
@@ -294,4 +295,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>

View File

@@ -201,6 +201,8 @@ namespace NzbDrone.Api.Movie
//var mappings = null;//_sceneMappingService.FindByTvdbId(resource.TvdbId);
//if (mappings == null) return;
//Not necessary anymore
//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)
{
//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)
{
BroadcastResourceChange(ModelAction.Updated, message.Series.Id);
//BroadcastResourceChange(ModelAction.Updated, message.Series.Id);
}
}
}

View File

@@ -12,7 +12,7 @@ namespace NzbDrone.Api.Wanted
ISeriesService seriesService,
IQualityUpgradableSpecification qualityUpgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster)
: base(episodeService, seriesService, qualityUpgradableSpecification, signalRBroadcaster, "wanted/missing")
: base(episodeService, seriesService, qualityUpgradableSpecification, signalRBroadcaster, "wanted/missing_episodes")
{
GetResourcePaged = GetMissingEpisodes;
}

View File

@@ -0,0 +1,77 @@
using NzbDrone.Api.Movie;
using NzbDrone.Api.Movies;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Datastore;
using NzbDrone.SignalR;
using NzbDrone.Core.Download;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events;
using System;
using NzbDrone.Core.Datastore.Events;
namespace NzbDrone.Api.Wanted
{
class MovieMissingModule : NzbDroneRestModuleWithSignalR<MovieResource, Core.Tv.Movie>,
IHandle<MovieGrabbedEvent>,
IHandle<MovieDownloadedEvent>
{
protected readonly IMovieService _movieService;
public MovieMissingModule(IMovieService movieService,
IQualityUpgradableSpecification qualityUpgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster)
: base(signalRBroadcaster, "wanted/missing")
{
_movieService = movieService;
GetResourcePaged = GetMissingMovies;
}
private PagingResource<MovieResource> GetMissingMovies(PagingResource<MovieResource> pagingResource)
{
var pagingSpec = pagingResource.MapToPagingSpec<MovieResource, Core.Tv.Movie>("physicalRelease", SortDirection.Descending);
if (pagingResource.FilterKey == "monitored" && pagingResource.FilterValue == "false")
{
pagingSpec.FilterExpression = v => v.Monitored == false;
}
else
{
pagingSpec.FilterExpression = v => v.Monitored == true;
}
var resource = ApplyToPage(_movieService.MoviesWithoutFiles, pagingSpec, v => MapToResource(v, false));
return resource;
}
private MovieResource GetMovie(int id)
{
var movie = _movieService.GetMovie(id);
var resource = MapToResource(movie, true);
return resource;
}
private MovieResource MapToResource(Core.Tv.Movie movie, bool includeMovieFile)
{
var resource = movie.ToResource();
return resource;
}
public void Handle(MovieGrabbedEvent message)
{
var resource = message.Movie.Movie.ToResource();
//add a grabbed field in MovieResource?
//resource.Grabbed = true;
BroadcastResourceChange(ModelAction.Updated, resource);
}
public void Handle(MovieDownloadedEvent message)
{
BroadcastResourceChange(ModelAction.Updated, message.Movie.Movie.Id);
}
}
}

View File

@@ -92,14 +92,14 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
protected void GivenFailedDownload()
{
Mocker.GetMock<INzbgetProxy>()
.Setup(s => s.DownloadNzb(It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<NzbgetSettings>()))
.Setup(s => s.DownloadNzb(It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<bool>(), It.IsAny<NzbgetSettings>()))
.Returns((string)null);
}
protected void GivenSuccessfulDownload()
{
Mocker.GetMock<INzbgetProxy>()
.Setup(s => s.DownloadNzb(It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<NzbgetSettings>()))
.Setup(s => s.DownloadNzb(It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<bool>(), It.IsAny<NzbgetSettings>()))
.Returns(Guid.NewGuid().ToString().Replace("-", ""));
}

View File

@@ -47,5 +47,17 @@ namespace NzbDrone.Core.Test.ParserTests
{
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 Series Series { get; set; }
public int MovieId { get; set; }
public Movie Movie { get; set; }
public List<int> EpisodeIds { get; set; }
public string SourceTitle { 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> BlacklistedByTorrentInfoHash(int seriesId, string torrentInfoHash);
List<Blacklist> BlacklistedBySeries(int seriesId);
List<Blacklist> BlacklistedByMovie(int seriesId);
}
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));
}
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));
}
@@ -37,9 +37,14 @@ namespace NzbDrone.Core.Blacklisting
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)
{
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);
}

View File

@@ -21,7 +21,7 @@ namespace NzbDrone.Core.Blacklisting
IExecute<ClearBlacklistCommand>,
IHandle<DownloadFailedEvent>,
IHandleAsync<SeriesDeletedEvent>
IHandleAsync<MovieDeletedEvent>
{
private readonly IBlacklistRepository _blacklistRepository;
@@ -128,8 +128,9 @@ namespace NzbDrone.Core.Blacklisting
{
var blacklist = new Blacklist
{
SeriesId = message.SeriesId,
SeriesId = 0,
EpisodeIds = message.EpisodeIds,
MovieId = message.MovieId,
SourceTitle = message.SourceTitle,
Quality = message.Quality,
Date = DateTime.UtcNow,
@@ -144,9 +145,9 @@ namespace NzbDrone.Core.Blacklisting
_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);
}

View File

@@ -0,0 +1,67 @@
using System.Data;
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
using System.Text;
using System.Text.RegularExpressions;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(121)]
public class update_filedate_config : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Execute.WithConnection(SetTitleSlug);
}
private void SetTitleSlug(IDbConnection conn, IDbTransaction tran)
{
using (IDbCommand getSeriesCmd = conn.CreateCommand())
{
getSeriesCmd.Transaction = tran;
getSeriesCmd.CommandText = @"SELECT Id, Value FROM Config WHERE Key = 'filedate'";
using (IDataReader seriesReader = getSeriesCmd.ExecuteReader())
{
while (seriesReader.Read())
{
var id = seriesReader.GetInt32(0);
var value = seriesReader.GetString(1);
using (IDbCommand updateCmd = conn.CreateCommand())
{
updateCmd.Transaction = tran;
updateCmd.CommandText = "UPDATE Config SET Value = 'Release' WHERE Id = ?";
updateCmd.AddParameter(id);
updateCmd.ExecuteNonQuery();
}
}
}
}
}
public static string ToUrlSlug(string value)
{
//First to lower case
value = value.ToLowerInvariant();
//Remove all accents
var bytes = Encoding.GetEncoding("Cyrillic").GetBytes(value);
value = Encoding.ASCII.GetString(bytes);
//Replace spaces
value = Regex.Replace(value, @"\s", "-", RegexOptions.Compiled);
//Remove invalid chars
value = Regex.Replace(value, @"[^a-z0-9\s-_]", "", RegexOptions.Compiled);
//Trim dashes from end
value = value.Trim('-', '_');
//Replace double occurences of - or _
value = Regex.Replace(value, @"([-_]){2,}", "$1", RegexOptions.Compiled);
return value;
}
}
}

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

@@ -68,6 +68,17 @@ namespace NzbDrone.Core.DecisionEngine
private int CompareProtocol(DownloadDecision x, DownloadDecision y)
{
if (x.IsForMovie)
{
return CompareBy(x.RemoteMovie, y.RemoteMovie, remoteEpisode =>
{
var delayProfile = _delayProfileService.BestForTags(remoteEpisode.Movie.Tags);
var downloadProtocol = remoteEpisode.Release.DownloadProtocol;
return downloadProtocol == delayProfile.PreferredProtocol;
});
}
var result = CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode =>
{
var delayProfile = _delayProfileService.BestForTags(remoteEpisode.Series.Tags);
@@ -75,15 +86,7 @@ namespace NzbDrone.Core.DecisionEngine
return downloadProtocol == delayProfile.PreferredProtocol;
});
if (x.IsForMovie)
{
result = CompareBy(x.RemoteMovie, y.RemoteMovie, remoteEpisode =>
{
var delayProfile = _delayProfileService.BestForTags(remoteEpisode.Movie.Tags);
var downloadProtocol = remoteEpisode.Release.DownloadProtocol;
return downloadProtocol == delayProfile.PreferredProtocol;
});
}
return result;
}
@@ -125,8 +128,8 @@ namespace NzbDrone.Core.DecisionEngine
private int CompareAgeIfUsenet(DownloadDecision x, DownloadDecision y)
{
if (x.RemoteEpisode.Release.DownloadProtocol != DownloadProtocol.Usenet ||
y.RemoteEpisode.Release.DownloadProtocol != DownloadProtocol.Usenet)
if (x.RemoteMovie.Release.DownloadProtocol != DownloadProtocol.Usenet ||
y.RemoteMovie.Release.DownloadProtocol != DownloadProtocol.Usenet)
{
return 0;
}

View File

@@ -32,7 +32,7 @@ namespace NzbDrone.Core.DecisionEngine
public List<DownloadDecision> GetRssDecision(List<ReleaseInfo> reports)
{
return GetDecisions(reports).ToList();
return GetMovieDecisions(reports).ToList();
}
public List<DownloadDecision> GetSearchDecision(List<ReleaseInfo> reports, SearchCriteriaBase searchCriteriaBase)

View File

@@ -34,11 +34,11 @@ namespace NzbDrone.Core.DecisionEngine
public List<DownloadDecision> PrioritizeDecisionsForMovies(List<DownloadDecision> decisions)
{
return decisions.Where(c => c.RemoteMovie.Movie != null)
/*.GroupBy(c => c.RemoteMovie.Movie.Id, (movieId, downloadDecisions) =>
.GroupBy(c => c.RemoteMovie.Movie.Id, (movieId, downloadDecisions) =>
{
return downloadDecisions.OrderByDescending(decision => decision, new DownloadDecisionComparer(_delayProfileService));
})
.SelectMany(c => c)*/
.SelectMany(c => c)
.Union(decisions.Where(c => c.RemoteMovie.Movie == null))
.ToList();
}

View File

@@ -33,7 +33,11 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
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();
}

View File

@@ -32,9 +32,12 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
protected override string AddFromNzbFile(RemoteEpisode remoteEpisode, string filename, byte[] fileContents)
{
var category = Settings.TvCategory;
var priority = remoteEpisode.IsRecentEpisode() ? Settings.RecentTvPriority : Settings.OlderTvPriority;
var response = _proxy.DownloadNzb(fileContents, filename, category, priority, Settings);
var addpaused = Settings.AddPaused;
var response = _proxy.DownloadNzb(fileContents, filename, category, priority, addpaused, Settings);
if (response == null)
{
@@ -47,9 +50,12 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
protected override string AddFromNzbFile(RemoteMovie remoteMovie, string filename, byte[] fileContents)
{
var category = Settings.TvCategory; // TODO: Update this to MovieCategory?
var priority = Settings.RecentTvPriority;
var response = _proxy.DownloadNzb(fileContents, filename, category, priority, Settings);
var addpaused = Settings.AddPaused;
var response = _proxy.DownloadNzb(fileContents, filename, category, priority, addpaused, Settings);
if(response == null)
{

View File

@@ -11,7 +11,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
{
public interface INzbgetProxy
{
string DownloadNzb(byte[] nzbData, string title, string category, int priority, NzbgetSettings settings);
string DownloadNzb(byte[] nzbData, string title, string category, int priority, bool addpaused, NzbgetSettings settings);
NzbgetGlobalStatus GetGlobalStatus(NzbgetSettings settings);
List<NzbgetQueueItem> GetQueue(NzbgetSettings settings);
List<NzbgetHistoryItem> GetHistory(NzbgetSettings settings);
@@ -45,12 +45,12 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
return version >= minimumVersion;
}
public string DownloadNzb(byte[] nzbData, string title, string category, int priority, NzbgetSettings settings)
public string DownloadNzb(byte[] nzbData, string title, string category, int priority, bool addpaused, NzbgetSettings settings)
{
if (HasVersion(16, settings))
{
var droneId = Guid.NewGuid().ToString().Replace("-", "");
var response = ProcessRequest<int>(settings, "append", title, nzbData, category, priority, false, false, string.Empty, 0, "all", new string[] { "drone", droneId });
var response = ProcessRequest<int>(settings, "append", title, nzbData, category, priority, false, addpaused, string.Empty, 0, "all", new string[] { "drone", droneId });
if (response <= 0)
{
return null;

View File

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

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Net;
using System.Text.RegularExpressions;
using NzbDrone.Common.Http;
@@ -36,7 +37,7 @@ namespace NzbDrone.Core.Indexers.TorrentPotato
torrentInfo.Size = (long)torrent.size*1000*1000;
torrentInfo.DownloadUrl = torrent.download_url;
torrentInfo.InfoUrl = torrent.details_url;
torrentInfo.PublishDate = torrent.publishdate.ToUniversalTime();
torrentInfo.PublishDate = torrent.publish_date.ToUniversalTime();
torrentInfo.Seeders = torrent.seeders;
torrentInfo.Peers = torrent.leechers + torrent.seeders;
torrentInfo.Freeleech = torrent.freeleech;

View File

@@ -21,7 +21,7 @@ namespace NzbDrone.Core.Indexers.TorrentPotato
public int size { get; set; }
public int leechers { get; set; }
public int seeders { get; set; }
public DateTime publishdate { get; set; }
public DateTime publish_date { get; set; }
}
}

View File

@@ -39,7 +39,13 @@ namespace NzbDrone.Core.Indexers.Torznab
protected override ReleaseInfo ProcessItem(XElement item, ReleaseInfo releaseInfo)
{
var torrentInfo = base.ProcessItem(item, releaseInfo) as TorrentInfo;
torrentInfo.ImdbId = int.Parse(GetImdbId(item).Substring(2));
if (GetImdbId(item) != null)
{
if (torrentInfo != null)
{
torrentInfo.ImdbId = int.Parse(GetImdbId(item).Substring(2));
}
}
return torrentInfo;
}

View File

@@ -64,9 +64,9 @@ namespace NzbDrone.Core.Jobs
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 = 3*60, TypeName = typeof(UpdateSceneMappingCommand).FullName},
// new ScheduledTask{ Interval = 3*60, TypeName = typeof(UpdateSceneMappingCommand).FullName},
new ScheduledTask{ Interval = 6*60, TypeName = typeof(CheckHealthCommand).FullName},
new ScheduledTask{ Interval = 12*60, TypeName = typeof(RefreshSeriesCommand).FullName},
new ScheduledTask{ Interval = 24*60, TypeName = typeof(RefreshMovieCommand).FullName},
new ScheduledTask{ Interval = 24*60, TypeName = typeof(HousekeepingCommand).FullName},
new ScheduledTask{ Interval = 7*24*60, TypeName = typeof(BackupCommand).FullName},
@@ -80,6 +80,7 @@ namespace NzbDrone.Core.Jobs
{
Interval = _configService.DownloadedEpisodesScanInterval,
TypeName = typeof(DownloadedEpisodesScanCommand).FullName
//TypeName = typeof(DownloadedMovieScanCommand).FullName
},
};

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)
{
@@ -130,7 +130,25 @@ namespace NzbDrone.Core.MediaCover
}
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)
{

View File

@@ -68,22 +68,22 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
{
//check if already imported
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"));
continue;
}
var episodeFile = new MovieFile();
episodeFile.DateAdded = DateTime.UtcNow;
episodeFile.MovieId = localMovie.Movie.Id;
episodeFile.Path = localMovie.Path.CleanFilePath();
episodeFile.Size = _diskProvider.GetFileSize(localMovie.Path);
episodeFile.Quality = localMovie.Quality;
episodeFile.MediaInfo = localMovie.MediaInfo;
episodeFile.Movie = localMovie.Movie;
episodeFile.ReleaseGroup = localMovie.ParsedMovieInfo.ReleaseGroup;
episodeFile.Edition = localMovie.ParsedMovieInfo.Edition;
var movieFile = new MovieFile();
movieFile.DateAdded = DateTime.UtcNow;
movieFile.MovieId = localMovie.Movie.Id;
movieFile.Path = localMovie.Path.CleanFilePath();
movieFile.Size = _diskProvider.GetFileSize(localMovie.Path);
movieFile.Quality = localMovie.Quality;
movieFile.MediaInfo = localMovie.MediaInfo;
movieFile.Movie = localMovie.Movie;
movieFile.ReleaseGroup = localMovie.ParsedMovieInfo.ReleaseGroup;
movieFile.Edition = localMovie.ParsedMovieInfo.Edition;
bool copyOnly;
switch (importMode)
@@ -102,17 +102,17 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
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;
}
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));
if (newDownload)
@@ -122,22 +122,22 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
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
{
_eventAggregator.PublishEvent(new MovieImportedEvent(localMovie, episodeFile, newDownload));
_eventAggregator.PublishEvent(new MovieImportedEvent(localMovie, movieFile, newDownload));
}
if (newDownload)
{
_eventAggregator.PublishEvent(new MovieDownloadedEvent(localMovie, episodeFile, oldFiles));
_eventAggregator.PublishEvent(new MovieDownloadedEvent(localMovie, movieFile, oldFiles));
}
}
catch (Exception e)
{
_logger.Warn(e, "Couldn't import episode " + localMovie);
importResults.Add(new ImportResult(importDecision, "Failed to import episode"));
_logger.Warn(e, "Couldn't import movie " + localMovie);
importResults.Add(new ImportResult(importDecision, "Failed to import movie"));
}
}

View File

@@ -3,7 +3,7 @@
public enum FileDateType
{
None = 0,
LocalAirDate = 1,
UtcAirDate = 2
Cinemas = 1,
Release = 2
}
}

View File

@@ -111,11 +111,11 @@ namespace NzbDrone.Core.MediaFiles
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)

View File

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

@@ -48,7 +48,11 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
return AudioChannelPositionsText.ContainsIgnoreCase("LFE") ? AudioChannels - 1 + 0.1m : AudioChannels;
}
return AudioChannelPositions.Split('/').Sum(s => decimal.Parse(s, CultureInfo.InvariantCulture));
decimal channels = 0;
decimal.TryParse(AudioChannelPositions.Split('/').First(), out channels);
return channels;
}
}
}

View File

@@ -49,7 +49,7 @@ namespace NzbDrone.Core.MediaFiles
switch (_configService.FileDate)
{
case FileDateType.LocalAirDate:
case FileDateType.Release:
{
var airDate = episodes.First().AirDate;
var airTime = series.AirTime;
@@ -62,7 +62,7 @@ namespace NzbDrone.Core.MediaFiles
return ChangeFileDateToLocalAirDate(episodeFilePath, airDate, airTime);
}
case FileDateType.UtcAirDate:
case FileDateType.Cinemas:
{
var airDateUtc = episodes.First().AirDateUtc;

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -20,7 +20,7 @@ namespace NzbDrone.Core.MediaFiles
}
public class UpdateMovieFileService : IUpdateMovieFileService,
IHandle<SeriesScannedEvent>
IHandle<MovieScannedEvent>
{
private readonly IDiskProvider _diskProvider;
private readonly IConfigService _configService;
@@ -47,17 +47,67 @@ namespace NzbDrone.Core.MediaFiles
{
var movieFilePath = Path.Combine(movie.Path, movieFile.RelativePath);
switch (_configService.FileDate)
{
case FileDateType.Release:
{
var airDate = movie.PhysicalRelease;
if (airDate == null)
{
return false;
}
return ChangeFileDate(movieFilePath, airDate.Value);
}
case FileDateType.Cinemas:
{
var airDate = movie.InCinemas;
if (airDate == null)
{
return false;
}
return ChangeFileDate(movieFilePath, airDate.Value);
}
}
return false;
}
public void Handle(SeriesScannedEvent message)
private bool ChangeFileDate(string filePath, DateTime date)
{
DateTime oldDateTime = _diskProvider.FileGetLastWrite(filePath);
if (!DateTime.Equals(date, oldDateTime))
{
try
{
_diskProvider.FileSetLastWriteTime(filePath, date);
_logger.Debug("Date of file [{0}] changed from '{1}' to '{2}'", filePath, oldDateTime, date);
return true;
}
catch (Exception ex)
{
_logger.Warn(ex, "Unable to set date of file [" + filePath + "]");
}
}
return false;
}
public void Handle(MovieScannedEvent message)
{
if (_configService.FileDate == FileDateType.None)
{
return;
}
/* var movies = _movieService.MoviesWithFiles(message.Series.Id);
var movies = _movieService.MoviesWithFiles(message.Movie.Id);
var movieFiles = new List<MovieFile>();
var updated = new List<MovieFile>();
@@ -69,7 +119,7 @@ namespace NzbDrone.Core.MediaFiles
movieFiles.Add(movieFile);
if (ChangeFileDate(movieFile, message.Series, moviesInFile))
if (ChangeFileDate(movieFile, message.Movie))
{
updated.Add(movieFile);
}
@@ -77,13 +127,13 @@ namespace NzbDrone.Core.MediaFiles
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
{
_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)

View File

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

View File

@@ -89,9 +89,9 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
movie.TmdbId = TmdbId;
movie.ImdbId = resource.imdb_id;
movie.Title = resource.title;
movie.TitleSlug = ToUrlSlug(movie.Title);
movie.CleanTitle = Parser.Parser.CleanSeriesTitle(movie.Title);
movie.SortTitle = Parser.Parser.NormalizeTitle(movie.Title);
movie.TitleSlug = ToUrlSlug(resource.title);
movie.CleanTitle = Parser.Parser.CleanSeriesTitle(resource.title);
movie.SortTitle = Parser.Parser.NormalizeTitle(resource.title);
movie.Overview = resource.overview;
movie.Website = resource.homepage;
if (resource.release_date.IsNotNullOrWhiteSpace())
@@ -152,19 +152,25 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
if (resource.videos != null)
{
foreach(Video video in resource.videos.results)
foreach (Video video in resource.videos.results)
{
if(video.type == "Trailer" && video.site == "YouTube")
if (video.type == "Trailer" && video.site == "YouTube")
{
movie.YouTubeTrailerId = video.key;
break;
if (video.key != null)
{
movie.YouTubeTrailerId = video.key;
break;
}
}
}
}
if (resource.production_companies != null && resource.production_companies.Count() > 0)
if (resource.production_companies != null)
{
movie.Studio = resource.production_companies[0].name;
if (resource.production_companies.Any())
{
movie.Studio = resource.production_companies[0].name;
}
}
return movie;
@@ -203,6 +209,8 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
{
var lowerTitle = title.ToLower();
lowerTitle = lowerTitle.Replace(".", "");
var parserResult = Parser.Parser.ParseMovieTitle(title, true);
var yearTerm = "";
@@ -210,7 +218,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
if (parserResult != null && parserResult.MovieTitle != title)
{
//Parser found something interesting!
lowerTitle = parserResult.MovieTitle.ToLower();
lowerTitle = parserResult.MovieTitle.ToLower().Replace(".", " "); //TODO Update so not every period gets replaced (e.g. R.I.P.D.)
if (parserResult.Year > 1800)
{
yearTerm = parserResult.Year.ToString();
@@ -343,25 +351,19 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
{
imdbMovie.SortTitle = Parser.Parser.NormalizeTitle(result.title);
imdbMovie.Title = result.title;
string titleSlug = ToUrlSlug(result.title);
imdbMovie.TitleSlug = titleSlug.ToLower().Replace(" ", "-");
imdbMovie.TitleSlug = ToUrlSlug(result.title);
if (result.release_date.IsNotNullOrWhiteSpace())
{
imdbMovie.Year = DateTime.Parse(result.release_date).Year;
}
//var slugResult = _movieService.FindByTitleSlug(imdbMovie.TitleSlug);
//if (slugResult != null)
//{
// _logger.Debug("Movie with this title slug already exists. Adding year...");
//}
imdbMovie.TitleSlug += "-" + imdbMovie.Year.ToString();
imdbMovie.TitleSlug += "-" + imdbMovie.Year;
imdbMovie.Images = new List<MediaCover.MediaCover>();
imdbMovie.Overview = result.overview;
try
{
string url = result.poster_path;
var imdbPoster = _configService.GetCoverForURL(result.poster_path, MediaCoverTypes.Poster);
imdbMovie.Images.Add(imdbPoster);
}

View File

@@ -2,7 +2,7 @@
{
public enum PushoverPriority
{
Silent = -1,
Silent = -2,
Quiet = -1,
Normal = 0,
High = 1,

View File

@@ -183,6 +183,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\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" />
<Compile Include="Datastore\Migration\119_add_youtube_trailer_id_table .cs" />
<Compile Include="Datastore\Migration\118_update_movie_slug.cs" />

View File

@@ -58,7 +58,7 @@ namespace NzbDrone.Core.Organizer
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)\})",
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);
@@ -161,6 +161,7 @@ namespace NzbDrone.Core.Organizer
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);
@@ -301,6 +302,7 @@ namespace NzbDrone.Core.Organizer
AddMovieTokens(tokenHandlers, movie);
AddReleaseDateTokens(tokenHandlers, movie.Year);
AddImdbIdTokens(tokenHandlers, movie.ImdbId);
return CleanFolderName(ReplaceTokens(namingConfig.MovieFolderFormat, tokenHandlers, namingConfig));
}
@@ -314,11 +316,27 @@ 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)
{
string result = name;
string[] badCharacters = { "\\", "/", "<", ">", "?", "*", ":", "|", "\"" };
string[] goodCharacters = { "+", "+", "", "", "!", "-", "-", "", "" };
string[] goodCharacters = { "+", "+", "", "", "!", "-", "", "", "" };
for (int i = 0; i < badCharacters.Length; i++)
{
@@ -470,6 +488,7 @@ namespace NzbDrone.Core.Organizer
{
tokenHandlers["{Movie Title}"] = m => 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)
@@ -477,6 +496,11 @@ namespace NzbDrone.Core.Organizer
tokenHandlers["{Release Year}"] = m => string.Format("{0}", releaseYear.ToString()); //Do I need m.CustomFormat?
}
private void AddImdbIdTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, string imdbId)
{
tokenHandlers["{IMDb Id}"] = m => $"{imdbId}";
}
private void AddSeasonTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, int seasonNumber)
{
tokenHandlers["{Season}"] = m => seasonNumber.ToString(m.CustomFormat);
@@ -508,6 +532,7 @@ namespace NzbDrone.Core.Organizer
{
tokenHandlers["{Original Title}"] = m => GetOriginalTitle(episodeFile);
tokenHandlers["{Original Filename}"] = m => GetOriginalFileName(episodeFile);
//tokenHandlers["{IMDb Id}"] = m =>
tokenHandlers["{Release Group}"] = m => episodeFile.ReleaseGroup ?? m.DefaultValue("Sonarr");
}

View File

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

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 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);
private static readonly Regex WebsitePrefixRegex = new Regex(@"^\[\s*[a-z]+(\.[a-z]+)+\s*\][- ]*",

View File

@@ -3,7 +3,9 @@ using System.Linq;
using System.Collections.Generic;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Datastore.Extensions;
using Marr.Data.QGen;
using NzbDrone.Core.MediaFiles;
namespace NzbDrone.Core.Tv
{
@@ -15,6 +17,8 @@ namespace NzbDrone.Core.Tv
Movie FindByImdbId(string imdbid);
Movie FindByTitleSlug(string slug);
List<Movie> MoviesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored);
List<Movie> MoviesWithFiles(int movieId);
PagingSpec<Movie> MoviesWithoutFiles(PagingSpec<Movie> pagingSpec);
List<Movie> GetMoviesByFileId(int fileId);
void SetFileId(int fileId, int movieId);
}
@@ -132,5 +136,30 @@ namespace NzbDrone.Core.Tv
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)
{
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.Status == MovieStatusType.Released)
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection())
.Skip(pagingSpec.PagingOffset())
.Take(pagingSpec.PageSize);
}
}
}

View File

@@ -12,6 +12,7 @@ using NzbDrone.Core.Parser;
using NzbDrone.Core.Tv.Events;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Tv
{
@@ -27,12 +28,14 @@ namespace NzbDrone.Core.Tv
Movie FindByTitleSlug(string slug);
Movie GetMovieByFileId(int fileId);
List<Movie> GetMoviesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored);
PagingSpec<Movie> MoviesWithoutFiles(PagingSpec<Movie> pagingSpec);
void DeleteMovie(int movieId, bool deleteFiles);
List<Movie> GetAllMovies();
Movie UpdateMovie(Movie movie);
List<Movie> UpdateMovie(List<Movie> movie);
bool MoviePathExists(string folder);
void RemoveAddOptions(Movie movie);
List<Movie> MoviesWithFiles(int movieId);
}
public class MovieService : IMovieService, IHandle<MovieFileAddedEvent>,
@@ -232,5 +235,17 @@ namespace NzbDrone.Core.Tv
return episodes;
}
public List<Movie> MoviesWithFiles(int movieId)
{
return _movieRepository.MoviesWithFiles(movieId);
}
public PagingSpec<Movie> MoviesWithoutFiles(PagingSpec<Movie> pagingSpec)
{
var movieResult = _movieRepository.MoviesWithoutFiles(pagingSpec);
return movieResult;
}
}
}

View File

@@ -9,178 +9,178 @@ var ErrorView = require('./ErrorView');
var LoadingView = require('../Shared/LoadingView');
module.exports = Marionette.Layout.extend({
template : 'AddMovies/AddMoviesViewTemplate',
template : 'AddMovies/AddMoviesViewTemplate',
regions : {
searchResult : '#search-result'
},
regions : {
searchResult : '#search-result'
},
ui : {
moviesSearch : '.x-movies-search',
searchBar : '.x-search-bar',
loadMore : '.x-load-more'
},
ui : {
moviesSearch : '.x-movies-search',
searchBar : '.x-search-bar',
loadMore : '.x-load-more'
},
events : {
'click .x-load-more' : '_onLoadMore'
},
events : {
'click .x-load-more' : '_onLoadMore'
},
initialize : function(options) {
console.log(options);
this.isExisting = options.isExisting;
this.collection = new AddMoviesCollection();
initialize : function(options) {
console.log(options);
if (this.isExisting) {
this.collection.unmappedFolderModel = this.model;
}
this.isExisting = options.isExisting;
this.collection = new AddMoviesCollection();
if (this.isExisting) {
this.className = 'existing-movies';
} else {
this.className = 'new-movies';
}
if (this.isExisting) {
this.collection.unmappedFolderModel = this.model;
}
this.listenTo(vent, vent.Events.MoviesAdded, this._onMoviesAdded);
this.listenTo(this.collection, 'sync', this._showResults);
if (this.isExisting) {
this.className = 'existing-movies';
} else {
this.className = 'new-movies';
}
this.resultCollectionView = new SearchResultCollectionView({
collection : this.collection,
isExisting : this.isExisting
});
this.listenTo(vent, vent.Events.MoviesAdded, this._onMoviesAdded);
this.listenTo(this.collection, 'sync', this._showResults);
this.throttledSearch = _.debounce(this.search, 1000, { trailing : true }).bind(this);
},
this.resultCollectionView = new SearchResultCollectionView({
collection : this.collection,
isExisting : this.isExisting
});
onRender : function() {
var self = this;
this.throttledSearch = _.debounce(this.search, 1000, { trailing : true }).bind(this);
},
this.$el.addClass(this.className);
onRender : function() {
var self = this;
this.ui.moviesSearch.keyup(function(e) {
this.$el.addClass(this.className);
if (_.contains([
9,
16,
17,
18,
19,
20,
33,
34,
35,
36,
37,
38,
39,
40,
91,
92,
93
], e.keyCode)) {
return;
}
this.ui.moviesSearch.keyup(function(e) {
self._abortExistingSearch();
self.throttledSearch({
term : self.ui.moviesSearch.val()
});
});
if (_.contains([
9,
16,
17,
18,
19,
20,
33,
34,
35,
36,
37,
38,
39,
40,
91,
92,
93
], e.keyCode)) {
return;
}
this._clearResults();
self._abortExistingSearch();
self.throttledSearch({
term : self.ui.moviesSearch.val()
});
});
if (this.isExisting) {
this.ui.searchBar.hide();
}
},
this._clearResults();
onShow : function() {
this.ui.moviesSearch.focus();
},
if (this.isExisting) {
this.ui.searchBar.hide();
}
},
search : function(options) {
var self = this;
onShow : function() {
this.ui.moviesSearch.focus();
},
this.collection.reset();
search : function(options) {
var self = this;
if (!options.term || options.term === this.collection.term) {
return Marionette.$.Deferred().resolve();
}
this.collection.reset();
this.searchResult.show(new LoadingView());
this.collection.term = options.term;
this.currentSearchPromise = this.collection.fetch({
data : { term : options.term }
});
if (!options.term || options.term === this.collection.term) {
return Marionette.$.Deferred().resolve();
}
this.currentSearchPromise.fail(function() {
self._showError();
});
this.searchResult.show(new LoadingView());
this.collection.term = options.term;
this.currentSearchPromise = this.collection.fetch({
data : { term : options.term }
});
return this.currentSearchPromise;
},
this.currentSearchPromise.fail(function() {
self._showError();
});
_onMoviesAdded : function(options) {
if (this.isExisting && options.movie.get('path') === this.model.get('folder').path) {
this.close();
}
return this.currentSearchPromise;
},
else if (!this.isExisting) {
this.resultCollectionView.setExisting(options.movie.get('tmdbId'));
/*this.collection.term = '';
this.collection.reset();
this._clearResults();
this.ui.moviesSearch.val('');
this.ui.moviesSearch.focus();*/ //TODO: Maybe add option wheter to clear search result.
}
},
_onMoviesAdded : function(options) {
if (this.isExisting && options.movie.get('path') === this.model.get('folder').path) {
this.close();
}
_onLoadMore : function() {
var showingAll = this.resultCollectionView.showMore();
this.ui.searchBar.show();
else if (!this.isExisting) {
this.resultCollectionView.setExisting(options.movie.get('tmdbId'));
/*this.collection.term = '';
this.collection.reset();
this._clearResults();
this.ui.moviesSearch.val('');
this.ui.moviesSearch.focus();*/ //TODO: Maybe add option wheter to clear search result.
}
},
if (showingAll) {
this.ui.loadMore.hide();
}
},
_onLoadMore : function() {
var showingAll = this.resultCollectionView.showMore();
this.ui.searchBar.show();
_clearResults : function() {
if (showingAll) {
this.ui.loadMore.hide();
}
},
if (!this.isExisting) {
this.searchResult.show(new EmptyView());
} else {
this.searchResult.close();
}
},
_clearResults : function() {
_showResults : function() {
if (!this.isClosed) {
if (this.collection.length === 0) {
this.ui.searchBar.show();
this.searchResult.show(new NotFoundView({ term : this.collection.term }));
} else {
this.searchResult.show(this.resultCollectionView);
if (!this.showingAll && this.isExisting) {
this.ui.loadMore.show();
}
}
}
},
if (!this.isExisting) {
this.searchResult.show(new EmptyView());
} else {
this.searchResult.close();
}
},
_abortExistingSearch : function() {
if (this.currentSearchPromise && this.currentSearchPromise.readyState > 0 && this.currentSearchPromise.readyState < 4) {
console.log('aborting previous pending search request.');
this.currentSearchPromise.abort();
} else {
this._clearResults();
}
},
_showResults : function() {
if (!this.isClosed) {
if (this.collection.length === 0) {
this.ui.searchBar.show();
this.searchResult.show(new NotFoundView({ term : this.collection.term }));
} else {
this.searchResult.show(this.resultCollectionView);
if (!this.showingAll) {
this.ui.loadMore.show();
}
}
}
},
_showError : function() {
if (!this.isClosed) {
this.ui.searchBar.show();
this.searchResult.show(new ErrorView({ term : this.collection.term }));
this.collection.term = '';
}
}
_abortExistingSearch : function() {
if (this.currentSearchPromise && this.currentSearchPromise.readyState > 0 && this.currentSearchPromise.readyState < 4) {
console.log('aborting previous pending search request.');
this.currentSearchPromise.abort();
} else {
this._clearResults();
}
},
_showError : function() {
if (!this.isClosed) {
this.ui.searchBar.show();
this.searchResult.show(new ErrorView({ term : this.collection.term }));
this.collection.term = '';
}
}
});

View File

@@ -4,59 +4,62 @@ var MoviesCollection = require('../Movies/MoviesCollection');
var vent = require('vent');
module.exports = Marionette.CollectionView.extend({
itemView : SearchResultView,
itemView : SearchResultView,
initialize : function(options) {
this.showExisting = true;
this.isExisting = options.isExisting;
this.showing = 1;
vent.on(vent.Commands.ShowExistingCommand, this._onExistingToggle.bind(this));
},
initialize : function(options) {
this.showExisting = true;
this.isExisting = options.isExisting;
this.showing = 5;
if (this.isExisting) {
this.showing = 1;
}
vent.on(vent.Commands.ShowExistingCommand, this._onExistingToggle.bind(this));
},
_onExistingToggle : function(data) {
this.showExisting = data.showExisting;
_onExistingToggle : function(data) {
this.showExisting = data.showExisting;
this.render();
},
this.render();
},
showAll : function() {
this.showingAll = true;
this.render();
},
showAll : function() {
this.showingAll = true;
this.render();
},
showMore : function() {
this.showing += 5;
this.render();
showMore : function() {
this.showing += 5;
this.render();
return this.showing >= this.collection.length;
},
return this.showing >= this.collection.length;
},
setExisting : function(tmdbid) {
var movies = this.collection.where({ tmdbId : tmdbid });
console.warn(movies);
//debugger;
if (movies.length > 0) {
this.children.findByModel(movies[0])._configureTemplateHelpers();
//this.children.findByModel(movies[0])._configureTemplateHelpers();
this.children.findByModel(movies[0]).render();
//this.templateHelpers.existing = existingMovies[0].toJSON();
}
},
setExisting : function(tmdbid) {
var movies = this.collection.where({ tmdbId : tmdbid });
console.warn(movies);
//debugger;
if (movies.length > 0) {
this.children.findByModel(movies[0])._configureTemplateHelpers();
//this.children.findByModel(movies[0])._configureTemplateHelpers();
this.children.findByModel(movies[0]).render();
//this.templateHelpers.existing = existingMovies[0].toJSON();
}
},
appendHtml : function(collectionView, itemView, index) {
var tmdbId = itemView.model.get('tmdbId');
var existingMovies = MoviesCollection.where({ tmdbId: tmdbId });
if(existingMovies.length > 0) {
if(this.showExisting) {
if (index < this.showing || index === 0) {
collectionView.$el.append(itemView.el);
}
}
} else {
if (index < this.showing || index === 0) {
collectionView.$el.append(itemView.el);
}
}
}
appendHtml : function(collectionView, itemView, index) {
var tmdbId = itemView.model.get('tmdbId');
var existingMovies = MoviesCollection.where({ tmdbId: tmdbId });
if(existingMovies.length > 0) {
if(this.showExisting) {
if (index < this.showing || index === 0) {
collectionView.$el.append(itemView.el);
}
}
} else {
if (index < this.showing || index === 0) {
collectionView.$el.append(itemView.el);
}
}
}
});

View File

@@ -0,0 +1,42 @@
var NzbDroneCell = require('./NzbDroneCell');
//used in Wanted tab
module.exports = NzbDroneCell.extend({
className : 'movie-status-text-cell',
render : function() {
this.$el.empty();
var monitored = this.model.get('monitored');
var status = this.model.get('status');
var inCinemas = this.model.get("inCinemas");
var date = new Date(inCinemas);
var timeSince = new Date().getTime() - date.getTime();
var numOfMonths = timeSince / 1000 / 60 / 60 / 24 / 30;
if (status === 'released') {
this.$el.html('<div class="released-banner"><i class="icon-sonarr-movie-released grid-icon" title=""></i>&nbsp;Released</div>');
this._setStatusWeight(3);
}
if (numOfMonths > 3) {
this.$el.html('<div class="released-banner"><i class="icon-sonarr-movie-released grid-icon" title=""></i>&nbsp;Released</div>');//TODO: Update for PreDB.me
this._setStatusWeight(2);
}
if (numOfMonths < 3) {
this.$el.html('<div class="cinemas-banner"><i class="icon-sonarr-movie-cinemas grid-icon" title=""></i>&nbsp;In Cinemas</div>');
this._setStatusWeight(2);
}
if (status === "announced") {
this.$el.html('<div class="announced-banner"><i class="icon-sonarr-movie-announced grid-icon" title=""></i>&nbsp;Announced</div>');
this._setStatusWeight(1);
}
return this;
},
_setStatusWeight : function(weight) {
this.model.set('statusWeight', weight, { silent : true });
}
});

View File

@@ -55,6 +55,10 @@
width : 150px;
}
.movie-status-text-cell {
width : 150px;
}
.history-event-type-cell {
width : 10px;
}

View File

@@ -109,7 +109,7 @@ module.exports = Marionette.Layout.extend({
element : this.ui.rename,
command : {
name : 'renameMovieFiles',
movieId : this.model.id,
movieId : this.model.id,
seasonNumber : -1
}
});

View File

@@ -11,9 +11,9 @@
Are you sure you want to update all files in the {{numberOfMovies}} selected movies?
{{debug}}
<ul class="selected-series">
{{#each movie}}
{{#each movies}}
<li>{{title}}</li>
{{/each}}
</ul>

View File

@@ -18,7 +18,7 @@
<div class="center">
<div class="labels">
<span class="label label-{{DownloadedStatusColor}}" title="{{DownloadedQuality}}">{{DownloadedStatus}}</span>
{{#if website}}
<a href="{{homepage}}" class="label label-info">Homepage</a>
{{/if}}

View File

@@ -126,7 +126,7 @@
.card;
.clickable;
margin-bottom : 20px;
height : 344px;
height : 363px;
.center {
display : block;
@@ -166,7 +166,7 @@
}
@media (max-width: @screen-xs-max) {
height : 268px;
height : 283px;
margin : 5px;
padding : 6px 5px;

View File

@@ -1,44 +1,44 @@
<!-- Static navbar -->
<div class="navbar navbar-nzbdrone" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle navbar-inverse" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-sonarr-navbar-collapsed fa-lg"></span>
</button>
<a class="navbar-brand" href="{{UrlBase}}/">
<!--<img src="{{UrlBase}}/Content/Images/logo.png?v=2" alt="Radarr">-->
<img src="{{UrlBase}}/Content/Images/logos/128.png" class="visible-lg"/>
<img src="{{UrlBase}}/Content/Images/logos/64.png" class="visible-md visible-sm"/>
<span class="visible-xs">
<img src="{{UrlBase}}/Content/Images/logos/32.png"/>
<span class="logo-text">Radarr</span>
</span>
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle navbar-inverse" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-sonarr-navbar-collapsed fa-lg"></span>
</button>
<a class="navbar-brand" href="{{UrlBase}}/">
<!--<img src="{{UrlBase}}/Content/Images/logo.png?v=2" alt="Radarr">-->
<img src="{{UrlBase}}/Content/Images/logos/128.png" class="visible-lg"/>
<img src="{{UrlBase}}/Content/Images/logos/64.png" class="visible-md visible-sm"/>
<span class="visible-xs">
<img src="{{UrlBase}}/Content/Images/logos/32.png"/>
<span class="logo-text">Radarr</span>
</span>
</a>
</div>
<div class="navbar-collapse collapse x-navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="{{UrlBase}}/" class="x-series-nav"><i class="icon-sonarr-navbar-icon icon-sonarr-navbar-series"></i> Movies</a></li>
<li><a href="{{UrlBase}}/calendar" class="x-calendar-nav"><i class="icon-sonarr-navbar-icon icon-sonarr-navbar-calendar"></i> Calendar</a></li>
<li><a href="{{UrlBase}}/activity" class="x-activity-nav"><i class="icon-sonarr-navbar-icon icon-sonarr-navbar-activity"></i> Activity<span id="x-queue-count" class="navbar-info"></span></a></li>
<li><a href="{{UrlBase}}/wanted" class="x-wanted-nav"><i class="icon-sonarr-navbar-icon icon-sonarr-navbar-wanted"></i> Wanted</a></li>
<li><a href="{{UrlBase}}/settings" class="x-settings-nav"><i class="icon-sonarr-navbar-icon icon-sonarr-navbar-settings"></i> Settings</a></li>
<li><a href="{{UrlBase}}/system" class="x-system-nav"><i class="icon-sonarr-navbar-icon icon-sonarr-navbar-system"></i> System<span id="x-health" class="navbar-info"></span></a></li>
<li><a href="https://sonarr.tv/donate" target="_blank"><i class="icon-sonarr-navbar-icon icon-sonarr-navbar-donate"></i> Donate</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="active screen-size"></li>
</ul>
</div><!--/.nav-collapse -->
</div><!--/.container-fluid -->
</a>
</div>
<div class="navbar-collapse collapse x-navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="{{UrlBase}}/" class="x-series-nav"><i class="icon-sonarr-navbar-icon icon-sonarr-navbar-series"></i> Movies</a></li>
<li><a href="{{UrlBase}}/calendar" class="x-calendar-nav"><i class="icon-sonarr-navbar-icon icon-sonarr-navbar-calendar"></i> Calendar</a></li>
<li><a href="{{UrlBase}}/activity" class="x-activity-nav"><i class="icon-sonarr-navbar-icon icon-sonarr-navbar-activity"></i> Activity<span id="x-queue-count" class="navbar-info"></span></a></li>
<li><a href="{{UrlBase}}/wanted" class="x-wanted-nav"><i class="icon-sonarr-navbar-icon icon-sonarr-navbar-wanted"></i> Wanted</a></li>
<li><a href="{{UrlBase}}/settings" class="x-settings-nav"><i class="icon-sonarr-navbar-icon icon-sonarr-navbar-settings"></i> Settings</a></li>
<li><a href="{{UrlBase}}/system" class="x-system-nav"><i class="icon-sonarr-navbar-icon icon-sonarr-navbar-system"></i> System<span id="x-health" class="navbar-info"></span></a></li>
<li><a href="https://radarr.video/donate.html" target="_blank"><i class="icon-sonarr-navbar-icon icon-sonarr-navbar-donate"></i> Donate</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="active screen-size"></li>
</ul>
</div><!--/.nav-collapse -->
</div><!--/.container-fluid -->
<div class="col-md-12 search">
<div class="col-md-6 col-md-offset-3">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-search"></i></span>
<input type="text" class="col-md-6 form-control x-series-search" placeholder="Search the movies in your library">
</div>
</div>
</div>
<div class="col-md-12 search">
<div class="col-md-6 col-md-offset-3">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-search"></i></span>
<input type="text" class="col-md-6 form-control x-series-search" placeholder="Search the movies in your library">
</div>
</div>
</div>
</div>

View File

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

View File

@@ -1,43 +1,8 @@
// var Backbone = require('backbone');
// var RenamePreviewModel = require('./RenamePreviewModel');
// module.exports = Backbone.Collection.extend({
// url : window.NzbDrone.ApiRoot + '/rename',
// model : RenamePreviewModel,
// originalFetch : Backbone.Collection.prototype.fetch,
// initialize : function(options) {
// if (!options.seriesId) {
// throw 'seriesId is required';
// }
// this.seriesId = options.seriesId;
// this.seasonNumber = options.seasonNumber;
// },
// fetch : function(options) {
// if (!this.seriesId) {
// throw 'seriesId is required';
// }
// options = options || {};
// options.data = {};
// options.data.seriesId = this.seriesId;
// if (this.seasonNumber !== undefined) {
// options.data.seasonNumber = this.seasonNumber;
// }
// return this.originalFetch.call(this, options);
// }
// });
var Backbone = require('backbone');
var RenamePreviewModel = require('./RenamePreviewModel');
module.exports = Backbone.Collection.extend({
url : window.NzbDrone.ApiRoot + '/rename',
url : window.NzbDrone.ApiRoot + '/renameMovie',
model : RenamePreviewModel,
originalFetch : Backbone.Collection.prototype.fetch,

View File

@@ -6,10 +6,10 @@ module.exports = Marionette.ItemView.extend({
template : 'Rename/RenamePreviewFormatViewTemplate',
templateHelpers : function() {
var type = this.model.get('seriesType');
//var type = this.model.get('seriesType');
return {
rename : this.naming.get('renameEpisodes'),
format : this.naming.get(type + 'EpisodeFormat')
format : this.naming.get('standardMovieFormat')
};
},

View File

@@ -1,98 +1,98 @@
<fieldset>
<legend>File Management</legend>
<legend>File Management</legend>
<div class="form-group">
<label class="col-sm-3 control-label">Ignore Deleted Movies</label>
<div class="form-group">
<label class="col-sm-3 control-label">Ignore Deleted Movies</label>
<div class="col-sm-9">
<div class="input-group">
<label class="checkbox toggle well">
<input type="checkbox" name="autoUnmonitorPreviouslyDownloadedEpisodes"/>
<p>
<span>Yes</span>
<span>No</span>
</p>
<div class="col-sm-9">
<div class="input-group">
<label class="checkbox toggle well">
<input type="checkbox" name="autoUnmonitorPreviouslyDownloadedEpisodes"/>
<p>
<span>Yes</span>
<span>No</span>
</p>
<div class="btn btn-primary slide-button"/>
</label>
<div class="btn btn-primary slide-button"/>
</label>
<span class="help-inline-checkbox">
<i class="icon-sonarr-form-info" title="Movies deleted from disk are automatically unmonitored in Radarr"/>
</span>
</div>
</div>
</div>
<span class="help-inline-checkbox">
<i class="icon-sonarr-form-info" title="Movies deleted from disk are automatically unmonitored in Radarr"/>
</span>
</div>
</div>
</div>
<div class="form-group advanced-setting">
<label class="col-sm-3 control-label">Download Propers</label>
<div class="form-group advanced-setting">
<label class="col-sm-3 control-label">Download Propers</label>
<div class="col-sm-9">
<div class="input-group">
<label class="checkbox toggle well">
<input type="checkbox" name="autoDownloadPropers"/>
<p>
<span>Yes</span>
<span>No</span>
</p>
<div class="col-sm-9">
<div class="input-group">
<label class="checkbox toggle well">
<input type="checkbox" name="autoDownloadPropers"/>
<p>
<span>Yes</span>
<span>No</span>
</p>
<div class="btn btn-primary slide-button"/>
</label>
<div class="btn btn-primary slide-button"/>
</label>
<span class="help-inline-checkbox">
<i class="icon-sonarr-form-info" title="Should Radarr automatically upgrade to propers when available?"/>
</span>
</div>
</div>
</div>
<span class="help-inline-checkbox">
<i class="icon-sonarr-form-info" title="Should Radarr automatically upgrade to propers when available?"/>
</span>
</div>
</div>
</div>
<div class="form-group advanced-setting">
<label class="col-sm-3 control-label">Analyse video files</label>
<div class="form-group advanced-setting">
<label class="col-sm-3 control-label">Analyse video files</label>
<div class="col-sm-9">
<div class="input-group">
<label class="checkbox toggle well">
<input type="checkbox" name="enableMediaInfo"/>
<p>
<span>Yes</span>
<span>No</span>
</p>
<div class="col-sm-9">
<div class="input-group">
<label class="checkbox toggle well">
<input type="checkbox" name="enableMediaInfo"/>
<p>
<span>Yes</span>
<span>No</span>
</p>
<div class="btn btn-primary slide-button"/>
</label>
<div class="btn btn-primary slide-button"/>
</label>
<span class="help-inline-checkbox">
<i class="icon-sonarr-form-info" title="Extract video information such as resolution, runtime and codec information from files. This requires Radarr to read parts of the file which may cause high disk or network activity during scans."/>
</span>
</div>
</div>
</div>
<span class="help-inline-checkbox">
<i class="icon-sonarr-form-info" title="Extract video information such as resolution, runtime and codec information from files. This requires Radarr to read parts of the file which may cause high disk or network activity during scans."/>
</span>
</div>
</div>
</div>
<div class="form-group advanced-setting">
<label class="col-sm-3 control-label">Change File Date</label>
<div class="form-group advanced-setting">
<label class="col-sm-3 control-label">Change File Date</label>
<div class="col-sm-1 col-sm-push-2 help-inline">
<i class="icon-sonarr-form-info" title="Change file date on import/rescan"/>
</div>
<div class="col-sm-2 col-sm-pull-1">
<select class="form-control" name="fileDate">
<option value="none">None</option>
<option value="localAirDate">Local Air Date</option>
<option value="utcAirDate">UTC Air Date</option>
</select>
</div>
</div>
<div class="col-sm-1 col-sm-push-2 help-inline">
<i class="icon-sonarr-form-info" title="Change file date on import/rescan"/>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Recycling Bin</label>
<div class="col-sm-2 col-sm-pull-1">
<select class="form-control" name="fileDate">
<option value="none">None</option>
<option value="cinemas">In Cinemas Date</option>
<option value="release">Physical Release Date</option>
</select>
</div>
</div>
<div class="col-sm-1 col-sm-push-8 help-inline">
<i class="icon-sonarr-form-info" title="Episode files will go here when deleted instead of being permanently deleted"/>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Recycling Bin</label>
<div class="col-sm-8 col-sm-pull-1">
<input type="text" name="recycleBin" class="form-control x-path"/>
</div>
<div class="col-sm-1 col-sm-push-8 help-inline">
<i class="icon-sonarr-form-info" title="Episode files will go here when deleted instead of being permanently deleted"/>
</div>
</div>
<div class="col-sm-8 col-sm-pull-1">
<input type="text" name="recycleBin" class="form-control x-path"/>
</div>
</div>
</fieldset>

View File

@@ -72,6 +72,7 @@
{{> MediaInfoNamingPartial}}
{{> ReleaseGroupNamingPartial}}
{{> OriginalTitleNamingPartial}}
{{> ImdbIdNamingPartial}}
{{> SeparatorNamingPartial}}
</ul>
</div>
@@ -161,6 +162,7 @@
<ul class="dropdown-menu">
{{> MovieTitleNamingPartial}}
{{> ReleaseYearNamingPartial}}
{{> ImdbIdNamingPartial}}
</ul>
</div>
</div>

View File

@@ -0,0 +1 @@
<li><a href="#" data-token="IMDb Id">IMDb Id</a></li>

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 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>

View File

@@ -1,16 +1,16 @@
<fieldset>
<legend>Quality Definitions</legend>
<div class="col-md-11">
<div id="quality-definition-list">
<div class="quality-header x-header hidden-xs">
<div class="row">
<span class="col-md-2 col-sm-3">Quality</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>
</div>
</div>
<div class="rows x-rows">
</div>
</div>
</div>
<legend>Quality Definitions</legend>
<div class="col-md-11">
<div id="quality-definition-list">
<div class="quality-header x-header hidden-xs">
<div class="row">
<span class="col-md-2 col-sm-3">Quality</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-warning" title="Limits are automatically adjusted for the movie runtime." /></span>
</div>
</div>
<div class="rows x-rows">
</div>
</div>
</div>
</fieldset>

View File

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

View File

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

View File

@@ -1,32 +1,32 @@
<fieldset>
<legend>More Info</legend>
<legend>More Info</legend>
<dl class="dl-horizontal info">
<dt>Discord</dt>
<dd><a href="https://discord.gg/AD3UP37">Radarr on Discord</a>
<dl class="dl-horizontal info">
<dt>Discord</dt>
<dd><a href="https://discord.gg/AD3UP37">Radarr on Discord</a>
<dt>Reddit</dt>
<dd><a href="https://www.reddit.com/r/radarr/">Radarr Subreddit</a>
{{!--<dt>Home page</dt>
<dd><a href="https://radarr.tdb/">radarr.tdb</a></dd>
<dt>Reddit</dt>
<dd><a href="https://www.reddit.com/r/radarr/">Radarr Subreddit</a>
<dt>Home page</dt>
<dd><a href="https://radarr.video/">radarr.video</a></dd>
<dt>Wiki</dt>
<dd><a href="https://wiki.radarr.tdb/">wiki.radarr.tdb</a></dd>
{{!--<dt>Wiki</dt>
<dd><a href="https://wiki.radarr.tdb/">wiki.radarr.tdb</a></dd>
<dt>Forums</dt>
<dd><a href="https://forums.sonarr.tv/">forums.sonarr.tv</a></dd>
<dt>Forums</dt>
<dd><a href="https://forums.sonarr.tv/">forums.sonarr.tv</a></dd>
<dt>Twitter</dt>
<dd><a href="https://twitter.com/sonarrtv">@sonarrtv</a></dd>
<dt>Twitter</dt>
<dd><a href="https://twitter.com/sonarrtv">@sonarrtv</a></dd>
<dt>IRC</dt>
<dd><a href="irc://irc.freenode.net/#sonarr">#sonarr on Freenode</a> or (<a href="http://webchat.freenode.net/?channels=#sonarr">webchat</a>)</dd>--}}
<dt>IRC</dt>
<dd><a href="irc://irc.freenode.net/#sonarr">#sonarr on Freenode</a> or (<a href="http://webchat.freenode.net/?channels=#sonarr">webchat</a>)</dd>--}}
<dt>Source</dt>
<dd><a href="https://github.com/Radarr/Radarr">Radarr on Github</a></dd>
<dt>Source</dt>
<dd><a href="https://github.com/Radarr/Radarr">Radarr on Github</a></dd>
<dt>Feature Requests</dt>
<!--<dd><a href="https://forums.sonarr.tv/">forums.sonarr.tv</a></dd>-->
<dd><a href="https://github.com/Radarr/Radarr/issues">Github Issues</a></dd>
</dl>
<dt>Feature Requests</dt>
<!--<dd><a href="https://forums.sonarr.tv/">forums.sonarr.tv</a></dd>-->
<dd><a href="https://github.com/Radarr/Radarr/issues">Github Issues</a></dd>
</dl>
</fieldset>

View File

@@ -1,5 +1,5 @@
var _ = require('underscore');
var EpisodeModel = require('../../Series/EpisodeModel');
var MovieModel = require('../../Movies/MovieModel');
var PagableCollection = require('backbone.pageable');
var AsFilteredCollection = require('../../Mixins/AsFilteredCollection');
var AsSortedCollection = require('../../Mixins/AsSortedCollection');
@@ -7,13 +7,13 @@ var AsPersistedStateCollection = require('../../Mixins/AsPersistedStateCollectio
var Collection = PagableCollection.extend({
url : window.NzbDrone.ApiRoot + '/wanted/missing',
model : EpisodeModel,
model : MovieModel,
tableName : 'wanted.missing',
state : {
pageSize : 15,
sortKey : 'airDateUtc',
order : 1
sortKey : 'inCinemas',
order : -1
},
queryParams : {
@@ -39,10 +39,6 @@ var Collection = PagableCollection.extend({
]
},
sortMappings : {
'series' : { sortKey : 'series.sortTitle' }
},
parseState : function(resp) {
return { totalRecords : resp.totalRecords };
},
@@ -58,4 +54,4 @@ var Collection = PagableCollection.extend({
Collection = AsFilteredCollection.call(Collection);
Collection = AsSortedCollection.call(Collection);
module.exports = AsPersistedStateCollection.call(Collection);
module.exports = AsPersistedStateCollection.call(Collection);

View File

@@ -5,11 +5,9 @@ var Marionette = require('marionette');
var Backgrid = require('backgrid');
var MissingCollection = require('./MissingCollection');
var SelectAllCell = require('../../Cells/SelectAllCell');
var SeriesTitleCell = require('../../Cells/SeriesTitleCell');
var EpisodeNumberCell = require('../../Cells/EpisodeNumberCell');
var EpisodeTitleCell = require('../../Cells/EpisodeTitleCell');
var MovieTitleCell = require('../../Cells/MovieTitleCell');
var RelativeDateCell = require('../../Cells/RelativeDateCell');
var EpisodeStatusCell = require('../../Cells/EpisodeStatusCell');
var MovieStatusWithTextCell = require('../../Cells/MovieStatusWithTextCell');
var GridPager = require('../../Shared/Grid/Pager');
var ToolbarLayout = require('../../Shared/Toolbar/ToolbarLayout');
var LoadingView = require('../../Shared/LoadingView');
@@ -39,35 +37,29 @@ module.exports = Marionette.Layout.extend({
headerCell : 'select-all',
sortable : false
},
{
name : 'series',
label : 'Series Title',
cell : SeriesTitleCell,
sortValue : 'series.sortTitle'
},
{
name : 'this',
label : 'Episode',
cell : EpisodeNumberCell,
label : 'Movie Title',
cell : MovieTitleCell,
sortable : false
},
{
name : 'this',
label : 'Episode Title',
cell : EpisodeTitleCell,
sortable : false
name : 'inCinemas',
label : 'In Cinemas',
cell : RelativeDateCell
},
{
name : 'airDateUtc',
label : 'Air Date',
name : 'physicalRelease',
label : 'PhysicalRelease',
cell : RelativeDateCell
},
{
name : 'status',
label : 'Status',
cell : EpisodeStatusCell,
cell : MovieStatusWithTextCell,
sortable : false
}
},
],
initialize : function() {
@@ -206,8 +198,8 @@ module.exports = Marionette.Layout.extend({
});
},
_searchMissing : function() {
if (window.confirm('Are you sure you want to search for {0} missing episodes? '.format(this.collection.state.totalRecords) +
'One API request to each indexer will be used for each episode. ' + 'This cannot be stopped once started.')) {
if (window.confirm('Are you sure you want to search for {0} missing movies? '.format(this.collection.state.totalRecords) +
'One API request to each indexer will be used for each movie. ' + 'This cannot be stopped once started.')) {
CommandController.Execute('missingEpisodeSearch', { name : 'missingEpisodeSearch' });
}
},
@@ -237,4 +229,4 @@ module.exports = Marionette.Layout.extend({
_manualImport : function () {
vent.trigger(vent.Commands.ShowManualImport);
}
});
});