1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-03-24 17:25:22 -04:00

Compare commits

...

36 Commits

Author SHA1 Message Date
Devin Buhl
0d1150d4d2 Wait 5 seconds before getting the next 35 movies from TMDb using X-RateLimit-Remaining (#647)
* Wait 5 seconds before getting the next 35 movies from TMDb using X-RateLimit-Remaining

* Update SkyHookProxy.cs
2017-02-07 16:55:57 -05:00
Devin Buhl
1f68b46575 Correct the Kickass migration (#649) 2017-02-07 16:36:35 -05:00
Devin Buhl
32c5c4d741 Update notif list warning when importing from a list (#648) 2017-02-07 16:29:12 -05:00
Devin Buhl
0cb15121e5 Fix movies not showing up in Queue when downloading (#640) 2017-02-07 03:03:15 -05:00
Devin Buhl
808033a01c Fixed Movie link in history tab (#637) 2017-02-06 20:57:53 -05:00
Devin Buhl
736e0d2e70 Clean up download clients to use radarr as label, fix hoduken, and blackhole. (#635)
* change default label to radarr for rtorrent

* change utorrent default label to radarr

* change hadoken to use radarr label

* change blackhole default to radarr, update hoduken

* Episodes don't work, but it needs to be here

* Fix blackhole xD
2017-02-06 19:51:30 -05:00
Devin Buhl
96741570c5 Use Movie Name-TmdbId for slug, update toUrlSlug (#629) 2017-02-06 17:01:02 -05:00
Devin Buhl
8feb3fee98 Removed Wombles and Kickass, updated torrentpotato and torznab (#625)
* Remove Wombles and kickass

* Clean up TorrentPotato Request Gen

* Opps, we need to use SupportedMovieSearchParameters xD

* Consistancy

* Clean up Newznab Request Gen, add year to search if cannot use IMDB

* Added SpecialCharRegex to remove \ / : &
2017-02-06 16:34:11 -05:00
Abzie
07e3e44a68 Various ui text fixes (#620)
* Fix notification text on rename

* Fixed profile tooltip for minimum sizes

* Updated link to now point to Radarr's FAQ

* Revert "Updated link to now point to Radarr's FAQ"

This reverts commit 726e0cc870.

Revert 726e0cc

* Fixed: Updated link to now point to Radarr's FAQ
2017-02-06 13:58:24 -05:00
vertigo235
d67d405024 Delay Profile: Fix for when preferred words is null. (#618) 2017-02-06 14:07:17 +01:00
Devin Buhl
520836f475 Merge pull request #598 from vertigo235/delay-profile-patch
Delay Profile: Upgradable Check Fix
2017-02-05 15:58:49 -05:00
vertigo235
6d6bf1044b preferredcount -> preferredCount 2017-02-05 15:45:09 -05:00
vertigo235
195866f3aa Delay Profile: Require preferred word to skip delay. 2017-02-05 14:09:22 -05:00
schumi2004
10f0be0708 fix ical ics file (#603) 2017-02-05 20:04:38 +01:00
Leonardo Galli
721773ef68 Fixed issue where quality weight was mapped wrongly. Fixes #597 2017-02-05 20:00:41 +01:00
vertigo235
0d647ffb9a Delay Profile: Delay for at least 1 preferred word 2017-02-04 02:26:11 -05:00
vertigo235
b6235e99c8 Delay Profile: Upgradable Check Fix
Only do the upgradable file check if there are exisitng files.
2017-02-04 01:07:26 -05:00
Devin Buhl
1d0a6af7d7 Merge pull request #587 from Radarr/patch/preferred-tags-info
Added 'Case Insensitive.' to preferred tags info to help-inline
2017-02-03 02:30:19 -05:00
Devin Buhl
efd7af165c Added 'Case Insensitive.' to preferred tags info to help-inline 2017-02-03 01:11:01 -05:00
Leonardo Galli
3f4ee6d841 Runtime error fix. 2017-02-02 18:18:02 +01:00
Leonardo Galli
55c437d980 Fix runtime issues.
Fixes #275 and #577
2017-02-02 17:35:00 +01:00
Leonardo Galli
ecfe103c50 Fix glaringly obvious mistake that caused RSS Sync to fail.
Fixes #580
2017-02-02 17:29:49 +01:00
Devin Buhl
a282ad7809 Merge pull request #573 from Radarr/patch/more-trakt-options
Added more options to trakt, popular movies, upcoming, anticipated etc..
2017-02-01 19:06:05 -05:00
Devin Buhl
64176b8d26 Added more options to trakt, popular movies, upcoming, anticipated etc.. 2017-02-01 18:49:40 -05:00
Devin Buhl
278fb298b6 Merge pull request #571 from Radarr/patch/settings-branch-warning
Add warning for docker users when switching branch
2017-02-01 17:45:32 -05:00
Devin Buhl
1d1b88cf05 Add warning for docker users when switching branch 2017-02-01 17:33:37 -05:00
Chris Allen
0c50aa7872 Add plain "ES" audioProfile. (#569) 2017-02-01 23:13:48 +01:00
Leonardo Galli
0bfa01f072 Fix delay specification when delay is not set to zero
Fixes #410
2017-02-01 18:58:06 +01:00
Chris Allen
3e9594f069 Use shorter format Profile string. (#561) 2017-02-01 11:22:28 +01:00
Chris Allen
a07138680b Use movieFile instead of episodeFile. (#560) 2017-02-01 10:44:41 +01:00
Chris Allen
5f6f2f2859 Add expanded DTS audio codecs to FileNameBuilder and fix up Atmos TrueHD audioCodec string. (#559)
* Add DTS-ES, DTS-HD HRA, DTS-HD MA, DTS-X to audioCodec.

* Cleanup "Atmos / TrueHD" audioCodec string.
2017-02-01 10:22:33 +01:00
Tim Turner
e185ba0191 Don't display mapped movies in import list
When importing existing movies, don't list those which already exist in the collection.
2017-01-31 15:11:33 -05:00
Tim Turner
3ab0b17379 Fix Delete modal when adding movie 2017-01-31 10:32:12 -05:00
Leonardo Galli
942d97931e Delete files now works. Fixes #127 2017-01-31 14:34:35 +01:00
Leonardo Galli
40809f1d91 First pass regarding delete. 2017-01-31 13:45:20 +01:00
Leonardo Galli
f6a37186aa Fix error for movies with less than 4 characters. Fixes #507 2017-01-31 13:12:32 +01:00
57 changed files with 461 additions and 965 deletions

View File

@@ -25,9 +25,9 @@ namespace NzbDrone.Api.Indexers
release.ReleaseWeight = initialWeight;
if (decision.RemoteEpisode.Series != null)
if (decision.RemoteMovie.Movie != null)
{
release.QualityWeight = decision.RemoteEpisode.Series
release.QualityWeight = decision.RemoteMovie.Movie
.Profile.Value
.Items.FindIndex(v => v.Quality == release.Quality.Quality) * 100;
}

View File

@@ -38,8 +38,8 @@ namespace NzbDrone.Api.RootFolders
Id = resource.Id,
Path = resource.Path,
//FreeSpace
//UnmappedFolders
FreeSpace = resource.FreeSpace,
UnmappedFolders = resource.UnmappedFolders
};
}

View File

@@ -5,7 +5,6 @@ using NUnit.Framework;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.Newznab;
using NzbDrone.Core.Indexers.Omgwtfnzbs;
using NzbDrone.Core.Indexers.Wombles;
using NzbDrone.Core.Lifecycle;
using NzbDrone.Core.Test.Framework;
@@ -22,7 +21,6 @@ namespace NzbDrone.Core.Test.IndexerTests
_indexers.Add(Mocker.Resolve<Newznab>());
_indexers.Add(Mocker.Resolve<Omgwtfnzbs>());
_indexers.Add(Mocker.Resolve<Wombles>());
Mocker.SetConstant<IEnumerable<IIndexer>>(_indexers);
}

View File

@@ -4,9 +4,7 @@ using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.KickassTorrents;
using NzbDrone.Core.Indexers.Nyaa;
using NzbDrone.Core.Indexers.Wombles;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
@@ -40,58 +38,6 @@ namespace NzbDrone.Core.Test.IndexerTests.IntegrationTests
};
}
[Test]
public void wombles_fetch_recent()
{
var indexer = Mocker.Resolve<Wombles>();
indexer.Definition = new IndexerDefinition
{
Name = "MyIndexer",
Settings = NullConfig.Instance
};
var result = indexer.FetchRecent();
ValidateResult(result);
}
[Test]
[ManualTest]
[Explicit]
public void kickass_fetch_recent()
{
var indexer = Mocker.Resolve<KickassTorrents>();
indexer.Definition = new IndexerDefinition
{
Name = "MyIndexer",
Settings = new KickassTorrentsSettings()
};
var result = indexer.FetchRecent();
ValidateTorrentResult(result, hasSize: true);
}
[Test]
[ManualTest]
[Explicit]
public void kickass_search_single()
{
var indexer = Mocker.Resolve<KickassTorrents>();
indexer.Definition = new IndexerDefinition
{
Name = "MyIndexer",
Settings = new KickassTorrentsSettings()
};
var result = indexer.Fetch(_singleSearchCriteria);
ValidateTorrentResult(result, hasSize: true, hasMagnet: true);
}
[Test]
public void nyaa_fetch_recent()
{

View File

@@ -1,173 +0,0 @@
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.KickassTorrents;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
using System;
using System.Linq;
using FluentAssertions;
using System.Text.RegularExpressions;
namespace NzbDrone.Core.Test.IndexerTests.KickassTorrentsTests
{
[TestFixture]
public class KickassTorrentsFixture : CoreTest<KickassTorrents>
{
[SetUp]
public void Setup()
{
Subject.Definition = new IndexerDefinition()
{
Name = "Kickass Torrents",
Settings = new KickassTorrentsSettings() { VerifiedOnly = false }
};
}
[Test]
public void should_parse_recent_feed_from_KickassTorrents()
{
var recentFeed = ReadAllText(@"Files/Indexers/KickassTorrents/KickassTorrents.xml");
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
var releases = Subject.FetchRecent();
releases.Should().HaveCount(5);
releases.First().Should().BeOfType<TorrentInfo>();
var torrentInfo = (TorrentInfo) releases.First();
torrentInfo.Title.Should().Be("Doctor Stranger.E03.140512.HDTV.H264.720p-iPOP.avi [CTRG]");
torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
torrentInfo.DownloadUrl.Should().Be("http://torcache.net/torrent/208C4F7866612CC88BFEBC7C496FA72C2368D1C0.torrent?title=%5Bkickass.to%5Ddoctor.stranger.e03.140512.hdtv.h264.720p.ipop.avi.ctrg");
torrentInfo.InfoUrl.Should().Be("http://kickass.to/doctor-stranger-e03-140512-hdtv-h264-720p-ipop-avi-ctrg-t9100648.html");
torrentInfo.CommentUrl.Should().BeNullOrEmpty();
torrentInfo.Indexer.Should().Be(Subject.Definition.Name);
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2014/05/12 16:16:49"));
torrentInfo.Size.Should().Be(1205364736);
torrentInfo.InfoHash.Should().Be("208C4F7866612CC88BFEBC7C496FA72C2368D1C0");
torrentInfo.MagnetUrl.Should().Be("magnet:?xt=urn:btih:208C4F7866612CC88BFEBC7C496FA72C2368D1C0&dn=doctor+stranger+e03+140512+hdtv+h264+720p+ipop+avi+ctrg&tr=udp%3A%2F%2Fopen.demonii.com%3A1337%2Fannounce");
}
[Test]
public void should_return_empty_list_on_404()
{
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new byte[0], System.Net.HttpStatusCode.NotFound));
var releases = Subject.FetchRecent();
releases.Should().HaveCount(0);
ExceptionVerification.IgnoreWarns();
}
[Test]
public void should_not_return_unverified_releases_if_not_configured()
{
((KickassTorrentsSettings) Subject.Definition.Settings).VerifiedOnly = true;
var recentFeed = ReadAllText(@"Files/Indexers/KickassTorrents/KickassTorrents.xml");
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
var releases = Subject.FetchRecent();
releases.Should().HaveCount(4);
}
[Test]
public void should_set_seeders_to_null()
{
// Atm, Kickass supplies 0 as seeders and leechers on the rss feed (but not the site), so set it to null if there aren't any peers.
var recentFeed = ReadAllText(@"Files/Indexers/KickassTorrents/KickassTorrents.xml");
recentFeed = recentFeed.Replace("<pubDate>Mon, 12 May 2014 16:16:49 +0000</pubDate>", string.Format("<pubDate>{0:R}</pubDate>", DateTime.UtcNow));
recentFeed = Regex.Replace(recentFeed, @"(seeds|peers)\>\d*", "$1>0");
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
var releases = Subject.FetchRecent();
releases.Should().HaveCount(5);
releases.First().Should().BeOfType<TorrentInfo>();
var torrentInfo = (TorrentInfo)releases.First();
torrentInfo.Peers.Should().NotHaveValue();
torrentInfo.Seeders.Should().NotHaveValue();
}
[Test]
public void should_not_set_seeders_to_null_if_has_peers()
{
// Atm, Kickass supplies 0 as seeders and leechers on the rss feed (but not the site), so set it to null if there aren't any peers.
var recentFeed = ReadAllText(@"Files/Indexers/KickassTorrents/KickassTorrents.xml");
recentFeed = recentFeed.Replace("<pubDate>Mon, 12 May 2014 16:16:49 +0000</pubDate>", string.Format("<pubDate>{0:R}</pubDate>", DateTime.UtcNow));
recentFeed = Regex.Replace(recentFeed, @"(seeds)\>\d*", "$1>0");
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
var releases = Subject.FetchRecent();
releases.Should().HaveCount(5);
releases.First().Should().BeOfType<TorrentInfo>();
var torrentInfo = (TorrentInfo)releases.First();
torrentInfo.Peers.Should().Be(311);
torrentInfo.Seeders.Should().Be(0);
}
[Test]
public void should_not_set_seeders_to_null_if_older_than_12_hours()
{
// Atm, Kickass supplies 0 as seeders and leechers on the rss feed (but not the site), so set it to null if there aren't any peers.
var recentFeed = ReadAllText(@"Files/Indexers/KickassTorrents/KickassTorrents.xml");
recentFeed = Regex.Replace(recentFeed, @"(seeds|peers)\>\d*", "$1>0");
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
var releases = Subject.FetchRecent();
releases.Should().HaveCount(5);
releases.First().Should().BeOfType<TorrentInfo>();
var torrentInfo = (TorrentInfo)releases.First();
torrentInfo.Peers.Should().Be(0);
torrentInfo.Seeders.Should().Be(0);
}
[Test]
public void should_handle_xml_with_html_accents()
{
var recentFeed = ReadAllText(@"Files/Indexers/KickassTorrents/KickassTorrents_accents.xml");
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
var releases = Subject.FetchRecent();
releases.Should().HaveCount(5);
}
}
}

View File

@@ -1,59 +0,0 @@
using System;
using System.Linq;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.Wombles;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.ThingiProvider;
namespace NzbDrone.Core.Test.IndexerTests.WomblesTests
{
[TestFixture]
public class TorrentRssIndexerFixture : CoreTest<Wombles>
{
[SetUp]
public void Setup()
{
Subject.Definition = new IndexerDefinition()
{
Name = "Wombles",
Settings = new NullConfig(),
};
}
private void GivenRecentFeedResponse(string rssXmlFile)
{
var recentFeed = ReadAllText(@"Files/Indexers/" + rssXmlFile);
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.IsAny<HttpRequest>()))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
}
[Test]
public void should_parse_recent_feed_from_wombles()
{
GivenRecentFeedResponse("Wombles/wombles.xml");
var releases = Subject.FetchRecent();
releases.Should().HaveCount(5);
var releaseInfo = releases.First();
releaseInfo.Title.Should().Be("One.Child.S01E01.720p.HDTV.x264-TLA");
releaseInfo.DownloadProtocol.Should().Be(DownloadProtocol.Usenet);
releaseInfo.DownloadUrl.Should().Be("http://indexer.local/nzb/bb4/One.Child.S01E01.720p.HDTV.x264-TLA.nzb");
releaseInfo.InfoUrl.Should().BeNullOrEmpty();
releaseInfo.CommentUrl.Should().BeNullOrEmpty();
releaseInfo.Indexer.Should().Be(Subject.Definition.Name);
releaseInfo.PublishDate.Should().Be(DateTime.Parse("2016-02-17 23:03:52 +0000").ToUniversalTime());
releaseInfo.Size.Should().Be(956*1024*1024);
}
}
}

View File

@@ -257,11 +257,9 @@
<Compile Include="IndexerTests\TestIndexer.cs" />
<Compile Include="IndexerTests\TestIndexerSettings.cs" />
<Compile Include="IndexerTests\IPTorrentsTests\IPTorrentsFixture.cs" />
<Compile Include="IndexerTests\KickassTorrentsTests\KickassTorrentsFixture.cs" />
<Compile Include="IndexerTests\NyaaTests\NyaaFixture.cs" />
<Compile Include="IndexerTests\TorrentRssIndexerTests\TorrentRssIndexerFixture.cs" />
<Compile Include="IndexerTests\TorrentRssIndexerTests\TestTorrentRssIndexer.cs" />
<Compile Include="IndexerTests\WomblesTests\WomblesFixture.cs" />
<Compile Include="IndexerTests\XElementExtensionsFixture.cs" />
<Compile Include="InstrumentationTests\DatabaseTargetFixture.cs" />
<Compile Include="JobTests\JobRepositoryFixture.cs" />

View File

@@ -0,0 +1,14 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(127)]
public class remove_wombles : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Delete.FromTable("Indexers").Row(new { Implementation = "Wombles" });
}
}
}

View File

@@ -0,0 +1,14 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(128)]
public class remove_kickass : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Delete.FromTable("Indexers").Row(new { Implementation = "Kickass Torrents" });
}
}
}

View File

@@ -0,0 +1,14 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(129)]
public class remove_kickass_again : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Delete.FromTable("Indexers").Row(new { Implementation = "KickassTorrents" });
}
}
}

View File

@@ -36,7 +36,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
return Decision.Accept();
}
public Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase searchCriteria)
public virtual Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase searchCriteria)
{
if (subject.Movie.MovieFile.Value != null)
{

View File

@@ -39,7 +39,22 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
var profile = subject.Movie.Profile.Value;
var delayProfile = _delayProfileService.BestForTags(subject.Movie.Tags);
var delay = delayProfile.GetProtocolDelay(subject.Release.DownloadProtocol);
var isPreferredProtocol = subject.Release.DownloadProtocol == delayProfile.PreferredProtocol;
var isPreferredProtocol = subject.Release.DownloadProtocol == delayProfile.PreferredProtocol;
// Preferred word count
var title = subject.Release.Title;
var preferredWords = subject.Movie.Profile.Value.PreferredTags;
var preferredCount = 0;
if (preferredWords == null)
{
preferredCount = 1;
_logger.Debug("Preferred words is null, setting preffered count to 1.");
}
else
{
preferredCount = preferredWords.AsEnumerable().Count(w => title.ToLower().Contains(w.ToLower()));
}
if (delay == 0)
{
@@ -49,7 +64,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
var comparer = new QualityModelComparer(profile);
if (isPreferredProtocol)
if (isPreferredProtocol && (subject.Movie.MovieFileId != 0) && (preferredCount > 0 || preferredWords == null))
{
var upgradable = _qualityUpgradableSpecification.IsUpgradable(profile, subject.Movie.MovieFile.Value.Quality, subject.ParsedMovieInfo.Quality);
@@ -59,7 +74,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
if (revisionUpgrade)
{
_logger.Debug("New quality is a better revision for existing quality, skipping delay");
_logger.Debug("New quality is a better revision for existing quality and preferred word count is {0}, skipping delay", preferredCount);
return Decision.Accept();
}
}
@@ -68,11 +83,11 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
// If quality meets or exceeds the best allowed quality in the profile accept it immediately
var bestQualityInProfile = new QualityModel(profile.LastAllowedQuality());
var isBestInProfile = comparer.Compare(subject.ParsedEpisodeInfo.Quality, bestQualityInProfile) >= 0;
var isBestInProfile = comparer.Compare(subject.ParsedMovieInfo.Quality, bestQualityInProfile) >= 0;
if (isBestInProfile && isPreferredProtocol)
if (isBestInProfile && isPreferredProtocol && (preferredCount > 0 || preferredWords == null))
{
_logger.Debug("Quality is highest in profile for preferred protocol, will not delay");
_logger.Debug("Quality is highest in profile for preferred protocol and preferred word count is {0}, will not delay.", preferredCount);
return Decision.Accept();
}
@@ -82,13 +97,13 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
if (oldest != null && oldest.Release.AgeMinutes > delay)
{
return Decision.Accept();
}
}*/
if (subject.Release.AgeMinutes < delay)
{
_logger.Debug("Waiting for better quality release, There is a {0} minute delay on {1}", delay, subject.Release.DownloadProtocol);
return Decision.Reject("Waiting for better quality release");
}*/ //TODO: Update for movies!
} //TODO: Update for movies!
return Decision.Accept();
}

View File

@@ -39,6 +39,17 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
}
protected override string AddFromMagnetLink(RemoteEpisode remoteEpisode, string hash, string magnetLink)
{
throw new NotImplementedException("Episodes are not working with Radarr");
}
protected override string AddFromTorrentFile(RemoteEpisode remoteEpisode, string hash, string filename, byte[] fileContent)
{
throw new NotImplementedException("Episodes are not working with Radarr");
}
protected override string AddFromMagnetLink(RemoteMovie remoteEpisode, string hash, string magnetLink)
{
if (!Settings.SaveMagnetFiles)
{
@@ -62,7 +73,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
return null;
}
protected override string AddFromTorrentFile(RemoteEpisode remoteEpisode, string hash, string filename, byte[] fileContent)
protected override string AddFromTorrentFile(RemoteMovie remoteEpisode, string hash, string filename, byte[] fileContent)
{
var title = remoteEpisode.Release.Title;
@@ -93,7 +104,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
{
DownloadClient = Definition.Name,
DownloadId = Definition.Name + "_" + item.DownloadId,
Category = "sonarr",
Category = "radarr",
Title = item.Title,
TotalSize = item.TotalSize,

View File

@@ -34,20 +34,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
protected override string AddFromNzbFile(RemoteEpisode remoteEpisode, string filename, byte[] fileContents)
{
var title = remoteEpisode.Release.Title;
title = FileNameBuilder.CleanFileName(title);
var filepath = Path.Combine(Settings.NzbFolder, title + ".nzb");
using (var stream = _diskProvider.OpenWriteStream(filepath))
{
stream.Write(fileContents, 0, fileContents.Length);
}
_logger.Debug("NZB Download succeeded, saved to: {0}", filepath);
return null;
throw new NotImplementedException("Episodes are not working with Radarr");
}
protected override string AddFromNzbFile(RemoteMovie remoteMovie, string filename, byte[] fileContents)

View File

@@ -150,13 +150,23 @@ namespace NzbDrone.Core.Download.Clients.Hadouken
}
protected override string AddFromMagnetLink(RemoteEpisode remoteEpisode, string hash, string magnetLink)
{
throw new NotImplementedException("Episodes are not working with Radarr");
}
protected override string AddFromTorrentFile(RemoteEpisode remoteEpisode, string hash, string filename, byte[] fileContent)
{
throw new NotImplementedException("Episodes are not working with Radarr");
}
protected override string AddFromMagnetLink(RemoteMovie remoteEpisode, string hash, string magnetLink)
{
_proxy.AddTorrentUri(Settings, magnetLink);
return hash.ToUpper();
}
protected override string AddFromTorrentFile(RemoteEpisode remoteEpisode, string hash, string filename, byte[] fileContent)
protected override string AddFromTorrentFile(RemoteMovie remoteEpisode, string hash, string filename, byte[] fileContent)
{
return _proxy.AddTorrentFile(Settings, fileContent).ToUpper();
}

View File

@@ -28,7 +28,7 @@ namespace NzbDrone.Core.Download.Clients.Hadouken
{
Host = "localhost";
Port = 7070;
Category = "sonarr-tv";
Category = "radarr";
}
[FieldDefinition(0, Label = "Host", Type = FieldType.Textbox)]

View File

@@ -26,7 +26,7 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
Host = "localhost";
Port = 8080;
UrlBase = "RPC2";
MovieCategory = "movies-radarr";
MovieCategory = "radarr";
}
[FieldDefinition(0, Label = "Host", Type = FieldType.Textbox)]

View File

@@ -23,7 +23,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
{
Host = "localhost";
Port = 9091;
TvCategory = "tv-sonarr";
TvCategory = "radarr";
}
[FieldDefinition(0, Label = "Host", Type = FieldType.Textbox)]

View File

@@ -56,7 +56,6 @@ namespace NzbDrone.Core.Download.TrackedDownloads
try
{
var parsedEpisodeInfo = Parser.Parser.ParseTitle(trackedDownload.DownloadItem.Title);
var parsedMovieInfo = Parser.Parser.ParseMovieTitle(trackedDownload.DownloadItem.Title);
var historyItems = _historyService.FindByDownloadId(downloadItem.DownloadId);
@@ -65,33 +64,25 @@ namespace NzbDrone.Core.Download.TrackedDownloads
trackedDownload.RemoteMovie = _parsingService.Map(parsedMovieInfo, "", null);
}
if (parsedEpisodeInfo != null)
{
trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0, 0);
}
if (historyItems.Any())
{
var firstHistoryItem = historyItems.OrderByDescending(h => h.Date).First();
trackedDownload.State = GetStateFromHistory(firstHistoryItem.EventType);
if ((parsedEpisodeInfo == null ||
trackedDownload.RemoteEpisode == null ||
trackedDownload.RemoteEpisode.Series == null ||
trackedDownload.RemoteEpisode.Episodes.Empty()) && trackedDownload.RemoteMovie == null)
if (parsedMovieInfo == null ||
trackedDownload.RemoteMovie == null ||
trackedDownload.RemoteMovie.Movie == null)
{
// Try parsing the original source title and if that fails, try parsing it as a special
// TODO: Pass the TVDB ID and TVRage IDs in as well so we have a better chance for finding the item
parsedEpisodeInfo = Parser.Parser.ParseTitle(firstHistoryItem.SourceTitle) ?? _parsingService.ParseSpecialEpisodeTitle(firstHistoryItem.SourceTitle, 0, 0);
parsedMovieInfo = Parser.Parser.ParseMovieTitle(firstHistoryItem.SourceTitle);
if (parsedEpisodeInfo != null)
if (parsedMovieInfo != null)
{
trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, firstHistoryItem.SeriesId, historyItems.Where(v => v.EventType == HistoryEventType.Grabbed).Select(h => h.EpisodeId).Distinct());
trackedDownload.RemoteMovie = _parsingService.Map(parsedMovieInfo, "", null);
}
}
}
if (trackedDownload.RemoteEpisode == null && trackedDownload.RemoteMovie == null)
if (trackedDownload.RemoteMovie == null)
{
return null;
}

View File

@@ -1,31 +0,0 @@
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Indexers.KickassTorrents
{
public class KickassTorrents : HttpIndexerBase<KickassTorrentsSettings>
{
public override string Name => "Kickass Torrents";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override int PageSize => 25;
public KickassTorrents(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(httpClient, indexerStatusService, configService, parsingService, logger)
{
}
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new KickassTorrentsRequestGenerator() { Settings = Settings, PageSize = PageSize };
}
public override IParseIndexerResponse GetParser()
{
return new KickassTorrentsRssParser() { Settings = Settings };
}
}
}

View File

@@ -1,157 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Common.Http;
using NzbDrone.Core.IndexerSearch.Definitions;
namespace NzbDrone.Core.Indexers.KickassTorrents
{
public class KickassTorrentsRequestGenerator : IIndexerRequestGenerator
{
public KickassTorrentsSettings Settings { get; set; }
public int MaxPages { get; set; }
public int PageSize { get; set; }
public KickassTorrentsRequestGenerator()
{
MaxPages = 30;
PageSize = 25;
}
public virtual IndexerPageableRequestChain GetRecentRequests()
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(MaxPages, "tv"));
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
foreach (var queryTitle in searchCriteria.QueryTitles)
{
pageableRequests.Add(GetPagedRequests(MaxPages, "usearch",
PrepareQuery(queryTitle),
"category:tv",
string.Format("season:{0}", searchCriteria.SeasonNumber),
string.Format("episode:{0}", searchCriteria.EpisodeNumber)));
pageableRequests.Add(GetPagedRequests(MaxPages, "usearch",
PrepareQuery(queryTitle),
string.Format("S{0:00}E{1:00}", searchCriteria.SeasonNumber, searchCriteria.EpisodeNumber),
"category:tv"));
}
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
foreach (var queryTitle in searchCriteria.QueryTitles)
{
pageableRequests.Add(GetPagedRequests(MaxPages, "usearch",
PrepareQuery(queryTitle),
"category:tv",
string.Format("season:{0}", searchCriteria.SeasonNumber)));
pageableRequests.Add(GetPagedRequests(MaxPages, "usearch",
PrepareQuery(queryTitle),
"category:tv",
string.Format("S{0:00}", searchCriteria.SeasonNumber)));
pageableRequests.Add(GetPagedRequests(MaxPages, "usearch",
PrepareQuery(queryTitle),
"category:tv",
string.Format("Season {0}", searchCriteria.SeasonNumber)));
}
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
foreach (var queryTitle in searchCriteria.QueryTitles)
{
pageableRequests.Add(GetPagedRequests(MaxPages, "usearch",
PrepareQuery(queryTitle),
string.Format("{0:yyyy-MM-dd}", searchCriteria.AirDate),
"category:tv"));
}
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
foreach (var queryTitle in searchCriteria.EpisodeQueryTitles)
{
pageableRequests.Add(GetPagedRequests(MaxPages, "usearch",
PrepareQuery(queryTitle),
"category:tv"));
}
return pageableRequests;
}
private IEnumerable<IndexerRequest> GetPagedRequests(int maxPages, string rssType, params string[] searchParameters)
{
string searchUrl = null;
if (searchParameters.Any())
{
// Prevent adding a '/' if no search parameters are specified
if (Settings.VerifiedOnly)
{
searchUrl = string.Format("/{0} verified:1", string.Join(" ", searchParameters));
}
else
{
searchUrl = string.Format("/{0}", string.Join(" ", searchParameters)).Trim();
}
}
if (PageSize == 0)
{
var request = new IndexerRequest(string.Format("{0}/{1}{2}/?rss=1&field=time_add&sorder=desc", Settings.BaseUrl.TrimEnd('/'), rssType, searchUrl), HttpAccept.Rss);
request.HttpRequest.SuppressHttpError = true;
yield return request;
}
else
{
for (var page = 0; page < maxPages; page++)
{
var request = new IndexerRequest(string.Format("{0}/{1}{2}/{3}/?rss=1&field=time_add&sorder=desc", Settings.BaseUrl.TrimEnd('/'), rssType, searchUrl, page + 1), HttpAccept.Rss);
request.HttpRequest.SuppressHttpError = true;
yield return request;
}
}
}
private string PrepareQuery(string query)
{
return query.Replace('+', ' ');
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
}
}

View File

@@ -1,44 +0,0 @@
using System;
using System.Linq;
using System.Xml.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Indexers.KickassTorrents
{
public class KickassTorrentsRssParser : EzrssTorrentRssParser
{
public KickassTorrentsSettings Settings { get; set; }
protected override bool PreProcess(IndexerResponse indexerResponse)
{
if (indexerResponse.HttpResponse.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return false;
}
return base.PreProcess(indexerResponse);
}
protected override ReleaseInfo PostProcess(XElement item, ReleaseInfo releaseInfo)
{
var verified = item.FindDecendants("verified").SingleOrDefault();
if (Settings != null && Settings.VerifiedOnly && (string)verified == "0")
{
return null;
}
// Atm, Kickass supplies 0 as seeders and leechers on the rss feed for recent releases, so set it to null if there aren't any peers.
// But only for releases younger than 12h (the real number seems to be close to 14h, but it depends on a number of factors).
var torrentInfo = releaseInfo as TorrentInfo;
if (torrentInfo.Peers.HasValue && torrentInfo.Peers.Value == 0 && torrentInfo.PublishDate > DateTime.UtcNow.AddHours(-12))
{
torrentInfo.Seeders = null;
torrentInfo.Peers = null;
}
return base.PostProcess(item, releaseInfo);
}
}
}

View File

@@ -1,37 +0,0 @@
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.KickassTorrents
{
public class KickassTorrentsSettingsValidator : AbstractValidator<KickassTorrentsSettings>
{
public KickassTorrentsSettingsValidator()
{
RuleFor(c => c.BaseUrl).ValidRootUrl();
}
}
public class KickassTorrentsSettings : IProviderConfig
{
private static readonly KickassTorrentsSettingsValidator Validator = new KickassTorrentsSettingsValidator();
public KickassTorrentsSettings()
{
BaseUrl = "";
VerifiedOnly = true;
}
[FieldDefinition(0, Label = "Website URL", HelpText = "Please verify that the url you enter is a trustworthy site.")]
public string BaseUrl { get; set; }
[FieldDefinition(1, Label = "Verified Only", Type = FieldType.Checkbox, HelpText = "By setting this to No you will likely get more junk and unconfirmed releases, so use it with caution.")]
public bool VerifiedOnly { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
}

View File

@@ -22,69 +22,6 @@ namespace NzbDrone.Core.Indexers.Newznab
PageSize = 100;
}
private bool SupportsSearch
{
get
{
var capabilities = _capabilitiesProvider.GetCapabilities(Settings);
return capabilities.SupportedSearchParameters != null &&
capabilities.SupportedSearchParameters.Contains("q");
}
}
private bool SupportsTvSearch
{
get
{
var capabilities = _capabilitiesProvider.GetCapabilities(Settings);
return capabilities.SupportedTvSearchParameters != null &&
capabilities.SupportedTvSearchParameters.Contains("q") &&
capabilities.SupportedTvSearchParameters.Contains("season") &&
capabilities.SupportedTvSearchParameters.Contains("ep");
}
}
private bool SupportsTvdbSearch
{
get
{
var capabilities = _capabilitiesProvider.GetCapabilities(Settings);
return capabilities.SupportedTvSearchParameters != null &&
capabilities.SupportedTvSearchParameters.Contains("tvdbid") &&
capabilities.SupportedTvSearchParameters.Contains("season") &&
capabilities.SupportedTvSearchParameters.Contains("ep");
}
}
private bool SupportsTvRageSearch
{
get
{
var capabilities = _capabilitiesProvider.GetCapabilities(Settings);
return capabilities.SupportedTvSearchParameters != null &&
capabilities.SupportedTvSearchParameters.Contains("rid") &&
capabilities.SupportedTvSearchParameters.Contains("season") &&
capabilities.SupportedTvSearchParameters.Contains("ep");
}
}
private bool SupportsTvMazeSearch
{
get
{
var capabilities = _capabilitiesProvider.GetCapabilities(Settings);
return capabilities.SupportedTvSearchParameters != null &&
capabilities.SupportedTvSearchParameters.Contains("tvmazeid") &&
capabilities.SupportedTvSearchParameters.Contains("season") &&
capabilities.SupportedTvSearchParameters.Contains("ep");
}
}
private bool SupportsMovieSearch
{
get
@@ -96,16 +33,6 @@ namespace NzbDrone.Core.Indexers.Newznab
}
}
private bool SupportsAggregatedIdSearch
{
get
{
var capabilities = _capabilitiesProvider.GetCapabilities(Settings);
return capabilities.SupportsAggregateIdSearch;
}
}
public virtual IndexerPageableRequestChain GetRecentRequests()
{
var pageableRequests = new IndexerPageableRequestChain();
@@ -126,14 +53,11 @@ namespace NzbDrone.Core.Indexers.Newznab
if (SupportsMovieSearch)
{
pageableRequests.Add(GetPagedRequests(MaxPages, Settings.Categories, "movie",
string.Format("&imdbid={0}", searchCriteria.Movie.ImdbId.Substring(2)))); //strip off the "tt" - VERY HACKY
pageableRequests.Add(GetPagedRequests(MaxPages, Settings.Categories, "movie", $"&imdbid={searchCriteria.Movie.ImdbId.Substring(2)}"));
}
else
{
//Let's try anyways with q parameter, worst case nothing found.
pageableRequests.Add(GetPagedRequests(MaxPages, Settings.Categories, "search",
string.Format("&q={0}", Parser.Parser.NormalizeTitle(searchCriteria.Movie.Title))));
pageableRequests.Add(GetPagedRequests(MaxPages, Settings.Categories, "search", $"&q={Parser.Parser.NormalizeTitle(searchCriteria.Movie.Title)}%20{searchCriteria.Movie.Year}"));
}
return pageableRequests;
@@ -141,134 +65,27 @@ namespace NzbDrone.Core.Indexers.Newznab
public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
AddTvIdPageableRequests(pageableRequests, MaxPages, Settings.Categories, searchCriteria,
string.Format("&season={0}&ep={1}",
searchCriteria.SeasonNumber,
searchCriteria.EpisodeNumber));
return pageableRequests;
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
AddTvIdPageableRequests(pageableRequests, MaxPages, Settings.Categories, searchCriteria,
string.Format("&season={0}",
searchCriteria.SeasonNumber));
return pageableRequests;
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
AddTvIdPageableRequests(pageableRequests, MaxPages, Settings.Categories, searchCriteria,
string.Format("&season={0:yyyy}&ep={0:MM}/{0:dd}",
searchCriteria.AirDate));
return pageableRequests;
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
if (SupportsSearch)
{
foreach (var queryTitle in searchCriteria.QueryTitles)
{
pageableRequests.Add(GetPagedRequests(MaxPages, Settings.AnimeCategories, "search",
string.Format("&q={0}+{1:00}",
NewsnabifyTitle(queryTitle),
searchCriteria.AbsoluteEpisodeNumber)));
}
}
return pageableRequests;
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
if (SupportsSearch)
{
foreach (var queryTitle in searchCriteria.EpisodeQueryTitles)
{
var query = queryTitle.Replace('+', ' ');
query = System.Web.HttpUtility.UrlEncode(query);
pageableRequests.Add(GetPagedRequests(MaxPages, Settings.Categories.Concat(Settings.AnimeCategories), "search",
string.Format("&q={0}",
query)));
}
}
return pageableRequests;
}
private void AddTvIdPageableRequests(IndexerPageableRequestChain chain, int maxPages, IEnumerable<int> categories, SearchCriteriaBase searchCriteria, string parameters)
{
var includeTvdbSearch = SupportsTvdbSearch && searchCriteria.Series.TvdbId > 0;
var includeTvRageSearch = SupportsTvRageSearch && searchCriteria.Series.TvRageId > 0;
var includeTvMazeSearch = SupportsTvMazeSearch && searchCriteria.Series.TvMazeId > 0;
if (SupportsAggregatedIdSearch && (includeTvdbSearch || includeTvRageSearch || includeTvMazeSearch))
{
var ids = "";
if (includeTvdbSearch)
{
ids += "&tvdbid=" + searchCriteria.Series.TvdbId;
}
if (includeTvRageSearch)
{
ids += "&rid=" + searchCriteria.Series.TvRageId;
}
if (includeTvMazeSearch)
{
ids += "&tvmazeid=" + searchCriteria.Series.TvMazeId;
}
chain.Add(GetPagedRequests(maxPages, categories, "tvsearch", ids + parameters));
}
else
{
if (includeTvdbSearch)
{
chain.Add(GetPagedRequests(maxPages, categories, "tvsearch",
string.Format("&tvdbid={0}{1}", searchCriteria.Series.TvdbId, parameters)));
}
else if (includeTvRageSearch)
{
chain.Add(GetPagedRequests(maxPages, categories, "tvsearch",
string.Format("&rid={0}{1}", searchCriteria.Series.TvRageId, parameters)));
}
else if (includeTvMazeSearch)
{
chain.Add(GetPagedRequests(maxPages, categories, "tvsearch",
string.Format("&tvmazeid={0}{1}", searchCriteria.Series.TvMazeId, parameters)));
}
}
if (SupportsTvSearch)
{
chain.AddTier();
foreach (var queryTitle in searchCriteria.QueryTitles)
{
chain.Add(GetPagedRequests(MaxPages, Settings.Categories, "tvsearch",
string.Format("&q={0}{1}",
NewsnabifyTitle(queryTitle),
parameters)));
}
}
return new IndexerPageableRequestChain();
}
private IEnumerable<IndexerRequest> GetPagedRequests(int maxPages, IEnumerable<int> categories, string searchType, string parameters)

View File

@@ -23,9 +23,9 @@ namespace NzbDrone.Core.Indexers
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
public virtual IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
throw new NotImplementedException();
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria)

View File

@@ -27,29 +27,17 @@ namespace NzbDrone.Core.Indexers.TorrentPotato
public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests("search", searchCriteria.Series.TvdbId, "S{0:00}E{1:00}", searchCriteria.SeasonNumber, searchCriteria.EpisodeNumber));
return pageableRequests;
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests("search", searchCriteria.Series.TvdbId, "S{0:00}", searchCriteria.SeasonNumber));
return pageableRequests;
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests("search", searchCriteria.Series.TvdbId, "\"{0:yyyy MM dd}\"", searchCriteria.AirDate));
return pageableRequests;
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
@@ -59,17 +47,7 @@ namespace NzbDrone.Core.Indexers.TorrentPotato
public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
foreach (var queryTitle in searchCriteria.EpisodeQueryTitles)
{
var query = queryTitle.Replace('+', ' ');
query = System.Web.HttpUtility.UrlEncode(query);
pageableRequests.Add(GetPagedRequests("search", searchCriteria.Series.TvdbId, query));
}
return pageableRequests;
return new IndexerPageableRequestChain();
}
private IEnumerable<IndexerRequest> GetPagedRequests(string mode, int? tvdbId, string query, params object[] args)
@@ -114,7 +92,7 @@ namespace NzbDrone.Core.Indexers.TorrentPotato
}
else
{
requestBuilder.AddQueryParam("search", searchCriteria.Movie.Title);
requestBuilder.AddQueryParam("search", $"{searchCriteria.Movie.Title} {searchCriteria.Movie.Year}");
}
yield return new IndexerRequest(requestBuilder.Build());
@@ -122,15 +100,9 @@ namespace NzbDrone.Core.Indexers.TorrentPotato
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetMovieRequest(searchCriteria));
return pageableRequests;
}
}
}

View File

@@ -96,8 +96,8 @@ namespace NzbDrone.Core.Indexers.Torznab
return null;
}
if (capabilities.SupportedTvSearchParameters != null &&
new[] { "q", "imdbid" }.Any(v => capabilities.SupportedTvSearchParameters.Contains(v)))
if (capabilities.SupportedMovieSearchParameters != null &&
new[] { "q", "imdbid" }.Any(v => capabilities.SupportedMovieSearchParameters.Contains(v)))
{
return null;
}

View File

@@ -1,36 +0,0 @@
using System;
using System.Collections.Generic;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider;
namespace NzbDrone.Core.Indexers.Wombles
{
public class Wombles : HttpIndexerBase<NullConfig>
{
public override string Name => "Womble's";
public override DownloadProtocol Protocol => DownloadProtocol.Usenet;
public override bool SupportsSearch => false;
public override IParseIndexerResponse GetParser()
{
return new WomblesRssParser();
}
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new RssIndexerRequestGenerator("http://newshost.co.za/rss/?sec=Movies&fr=false");
}
public Wombles(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(httpClient, indexerStatusService, configService, parsingService, logger)
{
}
}
}

View File

@@ -1,20 +0,0 @@
using System;
using System.Xml.Linq;
namespace NzbDrone.Core.Indexers.Wombles
{
public class WomblesRssParser : RssParser
{
public WomblesRssParser()
{
ParseSizeInDescription = true;
}
protected override DateTime GetPublishDate(XElement item)
{
var dateString = item.TryGetValue("pubDate") + " +0000";
return XElementExtensions.ParseDate(dateString);
}
}
}

View File

@@ -153,7 +153,12 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
private int GetMinimumAllowedRuntime(Movie movie)
{
return 360; //6 minutes
if (movie.Runtime < 1)
{
return 5 * 60;
}
return movie.Runtime / 5 * 60;
}
private int GetMinimumAllowedRuntime(Series series)

View File

@@ -33,7 +33,8 @@ namespace NzbDrone.Core.MediaFiles
//List<MovieFile> Get(IEnumerable<int> ids);
}
public class MediaFileService : IMediaFileService, IHandleAsync<SeriesDeletedEvent>
public class MediaFileService : IMediaFileService, IHandleAsync<SeriesDeletedEvent>,
IHandleAsync<MovieDeletedEvent>
{
private readonly IEventAggregator _eventAggregator;
private readonly IMediaFileRepository _mediaFileRepository;
@@ -155,5 +156,14 @@ namespace NzbDrone.Core.MediaFiles
{
return _movieFileRepository.Get(id);
}
}
public void HandleAsync(MovieDeletedEvent message)
{
if (message.DeleteFiles == true)
{
var files = GetFilesByMovie(message.Movie.Id);
_movieFileRepository.DeleteMany(files);
}
}
}
}

View File

@@ -122,13 +122,13 @@ namespace NzbDrone.Core.MediaFiles
public void Execute(RenameMovieCommand message)
{
_logger.Debug("Renaming all files for selected movie");
_logger.Debug("Renaming movie files for selected movie");
var moviesToRename = _movieService.GetMovies(message.MovieIds);
foreach(var movie in moviesToRename)
{
var movieFiles = _mediaFileService.GetFilesByMovie(movie.Id);
_logger.ProgressInfo("Renaming all files in movie: {0}", movie.Title);
_logger.ProgressInfo("Renaming movie files for {0}", movie.Title);
RenameFiles(movieFiles, movie);
_logger.ProgressInfo("All movie files renamed for {0}", movie.Title);
}

View File

@@ -14,6 +14,7 @@ using NzbDrone.Core.Tv;
using Newtonsoft.Json;
using System.Text.RegularExpressions;
using System.Text;
using System.Threading;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Profiles;
@@ -86,8 +87,18 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
request.SuppressHttpError = true;
var response = _httpClient.Get<MovieResourceRoot>(request);
var resource = response.Resource;
// The dude abides, so should us, Lets be nice to TMDb
// var allowed = int.Parse(response.Headers.GetValues("X-RateLimit-Limit").First()); // get allowed
// var reset = long.Parse(response.Headers.GetValues("X-RateLimit-Reset").First()); // get time when it resets
var remaining = int.Parse(response.Headers.GetValues("X-RateLimit-Remaining").First());
if (remaining <= 5)
{
_logger.Trace("Waiting 5 seconds to get information for the next 35 movies");
Thread.Sleep(5000);
}
var resource = response.Resource;
if (resource.status_message != null)
{
if (resource.status_code == 34)
@@ -133,7 +144,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
movie.Year = movie.InCinemas.Value.Year;
}
movie.TitleSlug += "-" + movie.Year.ToString();
movie.TitleSlug += "-" + movie.TmdbId.ToString();
movie.Images.Add(_configService.GetCoverForURL(resource.poster_path, MediaCoverTypes.Poster));//TODO: Update to load image specs from tmdb page!
movie.Images.Add(_configService.GetCoverForURL(resource.backdrop_path, MediaCoverTypes.Banner));
@@ -391,7 +402,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
imdbMovie.Year = DateTime.Parse(result.release_date).Year;
}
imdbMovie.TitleSlug += "-" + imdbMovie.Year;
imdbMovie.TitleSlug += "-" + imdbMovie.TmdbId;
imdbMovie.Images = new List<MediaCover.MediaCover>();
imdbMovie.Overview = result.overview;
@@ -577,7 +588,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
value = value.ToLowerInvariant();
//Remove all accents
var bytes = Encoding.GetEncoding("Cyrillic").GetBytes(value);
var bytes = Encoding.GetEncoding("ISO-8859-8").GetBytes(value);
value = Encoding.ASCII.GetString(bytes);
//Replace spaces

View File

@@ -21,9 +21,18 @@ namespace NzbDrone.Core.NetImport.Trakt
public class TraktResponse
{
public int rank { get; set; }
public int? rank { get; set; }
public string listed_at { get; set; }
public string type { get; set; }
public int? watchers { get; set; }
public long? revenue { get; set; }
public long? watcher_count { get; set; }
public long? play_count { get; set; }
public long? collected_count { get; set; }
public Movie movie { get; set; }
}
}

View File

@@ -1,9 +1,32 @@
namespace NzbDrone.Core.NetImport.Trakt
using System.Runtime.Serialization;
namespace NzbDrone.Core.NetImport.Trakt
{
public enum TraktListType
{
WatchList = 0,
Watched = 1,
CustomList = 2
[EnumMember(Value = "User Watch List")]
UserWatchList = 0,
[EnumMember(Value = "User Watched List")]
UserWatchedList = 1,
[EnumMember(Value = "User Custom List")]
UserCustomList = 2,
[EnumMember(Value = "Trending Movies")]
TrendingMovies = 3,
[EnumMember(Value = "Popular Movies")]
PopularMovies = 4,
[EnumMember(Value = "Top Anticipated Movies")]
AnticipatedMovies = 5,
[EnumMember(Value = "Top Box Office Movies")]
BoxOfficeMovies = 6,
[EnumMember(Value = "Top Watched Movies By Week")]
TopWatchedByWeek = 7,
[EnumMember(Value = "Top Watched Movies By Month")]
TopWatchedByMonth = 8,
[EnumMember(Value = "Top Watched Movies By Year")]
TopWatchedByYear = 9,
[EnumMember(Value = "Top Watched Movies Of All Time")]
TopWatchedByAllTime = 10
}
}

View File

@@ -42,26 +42,45 @@ namespace NzbDrone.Core.NetImport.Trakt
return movies;
}
var jsonResponse = JsonConvert.DeserializeObject<List<TraktResponse>>(_importResponse.Content);
// no movies were return
if (jsonResponse == null)
if (_settings.ListType == (int) TraktListType.PopularMovies)
{
return movies;
}
var jsonResponse = JsonConvert.DeserializeObject<List<Movie>>(_importResponse.Content);
foreach (var movie in jsonResponse)
{
movies.AddIfNotNull(new Tv.Movie()
foreach (var movie in jsonResponse)
{
Title = movie.movie.title,
ImdbId = movie.movie.ids.imdb,
TmdbId = movie.movie.ids.tmdb,
Year = (movie.movie.year ?? 0)
});
movies.AddIfNotNull(new Tv.Movie()
{
Title = movie.title,
ImdbId = movie.ids.imdb,
TmdbId = movie.ids.tmdb,
Year = (movie.year ?? 0)
});
}
}
else
{
var jsonResponse = JsonConvert.DeserializeObject<List<TraktResponse>>(_importResponse.Content);
// no movies were return
if (jsonResponse == null)
{
return movies;
}
foreach (var movie in jsonResponse)
{
movies.AddIfNotNull(new Tv.Movie()
{
Title = movie.movie.title,
ImdbId = movie.movie.ids.imdb,
TmdbId = movie.movie.ids.tmdb,
Year = (movie.movie.year ?? 0)
});
}
}
return movies;
}
protected virtual bool PreProcess(NetImportResponse indexerResponse)

View File

@@ -21,18 +21,42 @@ namespace NzbDrone.Core.NetImport.Trakt
private IEnumerable<NetImportRequest> GetMovies(string searchParameters)
{
var link = $"{Settings.Link.Trim()}{Settings.Username.Trim()}";
var link = Settings.Link.Trim();
switch (Settings.ListType)
{
case (int)TraktListType.CustomList:
link = link + $"/lists/{Settings.Listname.Trim()}/items/movies";
case (int)TraktListType.UserCustomList:
link = link + $"/users/{Settings.Username.Trim()}/lists/{Settings.Listname.Trim()}/items/movies";
break;
case (int)TraktListType.WatchList:
link = link + "/watchlist/movies";
case (int)TraktListType.UserWatchList:
link = link + $"/users/{Settings.Username.Trim()}/watchlist/movies";
break;
case (int)TraktListType.Watched:
link = link + "/watched/movies";
case (int)TraktListType.UserWatchedList:
link = link + $"/users/{Settings.Username.Trim()}/watched/movies";
break;
case (int)TraktListType.TrendingMovies:
link = link + "/movies/trending";
break;
case (int)TraktListType.PopularMovies:
link = link + "/movies/popular";
break;
case (int)TraktListType.AnticipatedMovies:
link = link + "/movies/anticipated";
break;
case (int)TraktListType.BoxOfficeMovies:
link = link + "/movies/boxoffice";
break;
case (int)TraktListType.TopWatchedByWeek:
link = link + "/movies/watched/weekly";
break;
case (int)TraktListType.TopWatchedByMonth:
link = link + "/movies/watched/monthly";
break;
case (int)TraktListType.TopWatchedByYear:
link = link + "/movies/watched/yearly";
break;
case (int)TraktListType.TopWatchedByAllTime:
link = link + "/movies/watched/all";
break;
}

View File

@@ -1,7 +1,5 @@
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Profiles;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.NetImport.Trakt
@@ -20,7 +18,7 @@ namespace NzbDrone.Core.NetImport.Trakt
{
public TraktSettings()
{
Link = "https://api.trakt.tv/users/";
Link = "https://api.trakt.tv";
Username = "";
Listname = "";
}
@@ -31,7 +29,7 @@ namespace NzbDrone.Core.NetImport.Trakt
[FieldDefinition(1, Label = "Trakt List Type", Type = FieldType.Select, SelectOptions = typeof(TraktListType), HelpText = "Trakt list type, custom or watchlist")]
public int ListType { get; set; }
[FieldDefinition(2, Label = "Trakt Username", HelpText = "Trakt Username the list belongs to.")]
[FieldDefinition(2, Label = "Trakt Username", HelpText = "Required for User List")]
public string Username { get; set; }
[FieldDefinition(3, Label = "Trakt List Name", HelpText = "Required for Custom List")]
@@ -39,4 +37,6 @@ namespace NzbDrone.Core.NetImport.Trakt
}
}

View File

@@ -99,6 +99,7 @@
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Web" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Windows.Forms" />
@@ -123,6 +124,7 @@
<Compile Include="Authentication\UserRepository.cs" />
<Compile Include="Authentication\UserService.cs" />
<Compile Include="Datastore\Migration\123_create_netimport_table.cs" />
<Compile Include="Datastore\Migration\128_remove_kickass.cs" />
<Compile Include="NetImport\Trakt\TraktAPI.cs" />
<Compile Include="NetImport\Trakt\TraktImport.cs" />
<Compile Include="NetImport\Trakt\TraktListType.cs" />
@@ -666,10 +668,6 @@
<Compile Include="Indexers\IPTorrents\IPTorrentsRequestGenerator.cs" />
<Compile Include="Indexers\IPTorrents\IPTorrents.cs" />
<Compile Include="Indexers\IPTorrents\IPTorrentsSettings.cs" />
<Compile Include="Indexers\KickassTorrents\KickassTorrents.cs" />
<Compile Include="Indexers\KickassTorrents\KickassTorrentsRssParser.cs" />
<Compile Include="Indexers\KickassTorrents\KickassTorrentsSettings.cs" />
<Compile Include="Indexers\KickassTorrents\KickassTorrentsRequestGenerator.cs" />
<Compile Include="Indexers\Newznab\Newznab.cs" />
<Compile Include="Indexers\Newznab\NewznabCapabilities.cs" />
<Compile Include="Indexers\Newznab\NewznabCapabilitiesProvider.cs" />
@@ -713,8 +711,6 @@
<Compile Include="Indexers\Torznab\TorznabException.cs" />
<Compile Include="Indexers\Torznab\TorznabRssParser.cs" />
<Compile Include="Indexers\Torznab\TorznabSettings.cs" />
<Compile Include="Indexers\Wombles\Wombles.cs" />
<Compile Include="Indexers\Wombles\WomblesRssParser.cs" />
<Compile Include="Indexers\XElementExtensions.cs" />
<Compile Include="IndexerSearch\Definitions\AnimeEpisodeSearchCriteria.cs" />
<Compile Include="IndexerSearch\Definitions\DailyEpisodeSearchCriteria.cs" />

View File

@@ -323,6 +323,12 @@ namespace NzbDrone.Core.Organizer
public static string TitleThe(string title)
{
string[] prefixes = { "The ", "An ", "A " };
if (title.Length < 5)
{
return title;
}
foreach (string prefix in prefixes)
{
int prefix_length = prefix.Length;
@@ -724,6 +730,10 @@ namespace NzbDrone.Core.Organizer
case "E-AC-3":
audioCodec = "EAC3";
break;
case "Atmos / TrueHD":
audioCodec = "Atmos TrueHD";
break;
case "MPEG Audio":
if (movieFile.MediaInfo.AudioProfile == "Layer 3")
@@ -737,7 +747,26 @@ namespace NzbDrone.Core.Organizer
break;
case "DTS":
audioCodec = movieFile.MediaInfo.AudioFormat;
if (movieFile.MediaInfo.AudioProfile == "ES" || movieFile.MediaInfo.AudioProfile == "ES Discrete" || movieFile.MediaInfo.AudioProfile == "ES Matrix")
{
audioCodec = "DTS-ES";
}
else if (movieFile.MediaInfo.AudioProfile == "MA")
{
audioCodec = "DTS-HD MA";
}
else if (movieFile.MediaInfo.AudioProfile == "HRA")
{
audioCodec = "DTS-HD HRA";
}
else if (movieFile.MediaInfo.AudioProfile == "X")
{
audioCodec = "DTS-X";
}
else
{
audioCodec = movieFile.MediaInfo.AudioFormat;
}
break;
default:

View File

@@ -296,6 +296,7 @@ namespace NzbDrone.Core.Parser
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex WordDelimiterRegex = new Regex(@"(\s|\.|,|_|-|=|\|)+", RegexOptions.Compiled);
private static readonly Regex SpecialCharRegex = new Regex(@"(\&|\:|\\|\/)+", RegexOptions.Compiled);
private static readonly Regex PunctuationRegex = new Regex(@"[^\w\s]", RegexOptions.Compiled);
private static readonly Regex CommonWordRegex = new Regex(@"\b(a|an|the|and|or|of)\b\s?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex SpecialEpisodeWordRegex = new Regex(@"\b(part|special|edition|christmas)\b\s?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
@@ -621,6 +622,7 @@ namespace NzbDrone.Core.Parser
title = PunctuationRegex.Replace(title, string.Empty);
title = CommonWordRegex.Replace(title, string.Empty);
title = DuplicateSpacesRegex.Replace(title, " ");
title = SpecialCharRegex.Replace(title, string.Empty);
return title.Trim().ToLower();
}

View File

@@ -399,11 +399,16 @@ namespace NzbDrone.Core.Parser
if (parsedEpisodeInfo.Year > 1900)
{
movie = _movieService.FindByTitle(parsedEpisodeInfo.MovieTitle, parsedEpisodeInfo.Year);
//Todo: same as above!
}
else
{
movie = _movieService.FindByTitle(parsedEpisodeInfo.MovieTitle); //Todo: same as above!
movie = _movieService.FindByTitle(parsedEpisodeInfo.MovieTitle);
}
if (movie == null)
{
movie = _movieService.FindByTitle(parsedEpisodeInfo.MovieTitle);
}
return movie;
}
@@ -412,7 +417,6 @@ namespace NzbDrone.Core.Parser
if (movie == null && imdbId.IsNotNullOrWhiteSpace())
{
//TODO: If series is found by TvdbId, we should report it as a scene naming exception, since it will fail to import
movie = _movieService.FindByImdbId(imdbId);
}

View File

@@ -25,6 +25,7 @@ namespace NzbDrone.Core.RootFolders
private readonly IRootFolderRepository _rootFolderRepository;
private readonly IDiskProvider _diskProvider;
private readonly ISeriesRepository _seriesRepository;
private readonly IMovieRepository _movieRepository;
private readonly IConfigService _configService;
private readonly Logger _logger;
@@ -44,12 +45,14 @@ namespace NzbDrone.Core.RootFolders
public RootFolderService(IRootFolderRepository rootFolderRepository,
IDiskProvider diskProvider,
ISeriesRepository seriesRepository,
IMovieRepository movieRepository,
IConfigService configService,
Logger logger)
{
_rootFolderRepository = rootFolderRepository;
_diskProvider = diskProvider;
_seriesRepository = seriesRepository;
_movieRepository = movieRepository;
_configService = configService;
_logger = logger;
}
@@ -128,6 +131,41 @@ namespace NzbDrone.Core.RootFolders
_rootFolderRepository.Delete(id);
}
//private List<UnmappedFolder> GetUnmappedFolders(string path)
//{
// _logger.Debug("Generating list of unmapped folders");
// if (string.IsNullOrEmpty(path))
// throw new ArgumentException("Invalid path provided", "path");
// var results = new List<UnmappedFolder>();
// var series = _seriesRepository.All().ToList();
// if (!_diskProvider.FolderExists(path))
// {
// _logger.Debug("Path supplied does not exist: {0}", path);
// return results;
// }
// var seriesFolders = _diskProvider.GetDirectories(path).ToList();
// var unmappedFolders = seriesFolders.Except(series.Select(s => s.Path), PathEqualityComparer.Instance).ToList();
// foreach (string unmappedFolder in unmappedFolders)
// {
// var di = new DirectoryInfo(unmappedFolder.Normalize());
// if (!di.Attributes.HasFlag(FileAttributes.System) && !di.Attributes.HasFlag(FileAttributes.Hidden))
// {
// results.Add(new UnmappedFolder { Name = di.Name, Path = di.FullName });
// }
// }
// var setToRemove = SpecialFolders;
// results.RemoveAll(x => setToRemove.Contains(new DirectoryInfo(x.Path.ToLowerInvariant()).Name));
// _logger.Debug("{0} unmapped folders detected.", results.Count);
// return results;
//}
private List<UnmappedFolder> GetUnmappedFolders(string path)
{
_logger.Debug("Generating list of unmapped folders");
@@ -135,7 +173,7 @@ namespace NzbDrone.Core.RootFolders
throw new ArgumentException("Invalid path provided", "path");
var results = new List<UnmappedFolder>();
var series = _seriesRepository.All().ToList();
var movies = _movieRepository.All().ToList();
if (!_diskProvider.FolderExists(path))
{
@@ -143,8 +181,8 @@ namespace NzbDrone.Core.RootFolders
return results;
}
var seriesFolders = _diskProvider.GetDirectories(path).ToList();
var unmappedFolders = seriesFolders.Except(series.Select(s => s.Path), PathEqualityComparer.Instance).ToList();
var movieFolders = _diskProvider.GetDirectories(path).ToList();
var unmappedFolders = movieFolders.Except(movies.Select(s => s.Path), PathEqualityComparer.Instance).ToList();
foreach (string unmappedFolder in unmappedFolders)
{

View File

@@ -55,7 +55,7 @@ module.exports = Marionette.Layout.extend({
_folderSelected : function(options) {
vent.trigger(vent.Commands.CloseModalCommand);
this.ui.$existing.show();
//this.ui.$existing.show();
this.workspace.show(new ExistingMoviesCollectionView({ model : options.model }));
},
@@ -70,7 +70,7 @@ module.exports = Marionette.Layout.extend({
},
_addFromList : function() {
this.ui.$existing.hide();
//this.ui.$existing.hide();
this.workspace.show(new AddFromListView());
}
});

View File

@@ -187,13 +187,13 @@ module.exports = Marionette.Layout.extend({
_importSelected : function() {
var selected = this.importGrid.getSelectedModels();
console.log(selected);
// console.log(selected);
var promise = MoviesCollection.importFromList(selected);
this.ui.importSelected.spinForPromise(promise);
this.ui.importSelected.addClass('disabled');
Messenger.show({
message : "Importing {0} movies. This can take multiple minutes depending on how many movies should be imported. Don't close this browser window until it is finished!".format(selected.length),
message : "Importing {0} movies. Don't close this browser window until it has finished".format(selected.length),
hideOnNavigate : false,
hideAfter : 30,
type : "error"

View File

@@ -2,6 +2,6 @@
<h3>
Sorry. We couldn't find any movies matching '{{term}}'
</h3>
<a href="https://github.com/NzbDrone/NzbDrone/wiki/FAQ#wiki-why-cant-i-add-a-new-show-to-nzbdrone-its-on-thetvdb">[UPDATE LINK] Why can't I find my movie?</a>
<a href="https://github.com/Radarr/Radarr/wiki/FAQ#why-cant-i-add-a-new-movie-to-radarr-its-on-tmdb">Why can't I find my movie?</a>
</div>

View File

@@ -29,7 +29,7 @@ module.exports = Marionette.Layout.extend({
},
_updateUrl : function() {
var icalUrl = window.location.host + StatusModel.get('urlBase') + '/feed/calendar/NzbDrone.ics?';
var icalUrl = window.location.host + StatusModel.get('urlBase') + '/feed/calendar/Radarr.ics?';
if (this.ui.includeUnmonitored.prop('checked')) {
icalUrl += 'unmonitored=true&';
@@ -51,4 +51,4 @@ module.exports = Marionette.Layout.extend({
this.ui.icalUrl.attr('value', icalHttpUrl);
this.ui.icalWebCal.attr('href', icalWebCalUrl);
}
});
});

View File

@@ -6,7 +6,7 @@ module.exports = TemplatedCell.extend({
render : function() {
this.$el.html('<a href="movies/' + this.model.get("movie").get("titleSlug") +'">' + this.model.get("movie").get("title") + '</a>'); //Hack, but somehow handlebar helper does not work.
this.$el.html('<a href="/movies/' + this.model.get("movie").get("titleSlug") +'">' + this.model.get("movie").get("title") + '</a>'); //Hack, but somehow handlebar helper does not work.
return this;
}
});

View File

@@ -0,0 +1,50 @@
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3>Delete {{title}}</h3>
</div>
<div class="modal-body delete-series-modal">
<div class="row">
<div class="col-sm-3 hidden-xs">
{{poster}}
</div>
<div class="col-sm-9">
<div class="form-horizontal">
<h3 class="path">{{path}}</h3>
<div class="form-group">
<label class="col-sm-4 control-label">Delete all files</label>
<div class="col-sm-8">
<div class="input-group">
<label class="checkbox toggle well">
<input type="checkbox" class="x-delete-files"/>
<p>
<span>Yes</span>
<span>No</span>
</p>
<div class="btn slide-button btn-danger"/>
</label>
<span class="help-inline-checkbox">
<i class="icon-sonarr-form-info" title="Do you want to delete all files from disk?"/>
<i class="icon-sonarr-form-warning" title="This option is irreversible, use with extreme caution"/>
</span>
</div>
</div>
</div>
<div class="col-md-offset-1 col-md-5 delete-files-info x-delete-files-info">
{{#if hasFile}}1{{else}}0{{/if}} movie file(s) will be deleted
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<span class="indicator x-indicator"><i class="icon-sonarr-spinner fa-spin"></i></span>
<button class="btn" data-dismiss="modal">Cancel</button>
<button class="btn btn-danger x-confirm-delete">Delete</button>
</div>
</div>

View File

@@ -0,0 +1,41 @@
var vent = require('vent');
var Marionette = require('marionette');
module.exports = Marionette.ItemView.extend({
template : 'Movies/Delete/DeleteMovieTemplate',
events : {
'click .x-confirm-delete' : 'removeSeries',
'change .x-delete-files' : 'changeDeletedFiles'
},
ui : {
deleteFiles : '.x-delete-files',
deleteFilesInfo : '.x-delete-files-info',
indicator : '.x-indicator'
},
removeSeries : function() {
var self = this;
var deleteFiles = this.ui.deleteFiles.prop('checked');
this.ui.indicator.show();
this.model.destroy({
data : { 'deleteFiles' : deleteFiles },
wait : true
}).done(function() {
vent.trigger(vent.Events.SeriesDeleted, { series : self.model });
vent.trigger(vent.Commands.CloseModalCommand);
});
},
changeDeletedFiles : function() {
var deleteFiles = this.ui.deleteFiles.prop('checked');
if (deleteFiles) {
this.ui.deleteFilesInfo.show();
} else {
this.ui.deleteFilesInfo.hide();
}
}
});

View File

@@ -17,7 +17,7 @@ var view = Marionette.ItemView.extend({
},
events : {
'click .x-remove' : '_removeSeries'
'click .x-remove' : '_removeMovie'
},
initialize : function() {
@@ -42,8 +42,8 @@ var view = Marionette.ItemView.extend({
vent.trigger(vent.Commands.CloseModalCommand);
},
_removeSeries : function() {
vent.trigger(vent.Commands.DeleteSeriesCommand, { series : this.model });
_removeMovie : function() {
vent.trigger(vent.Commands.DeleteMovieCommand, { movie : this.model });
}
});

View File

@@ -322,7 +322,11 @@
<div class="form-group">
<label class="col-sm-3 control-label">Branch</label>
<div class="col-sm-4">
<div class="col-sm-1 col-sm-push-2 help-inline">
<i class="icon-sonarr-form-warning" title="If using Docker, do not use 'develop' or 'nightly' branches"/>
</div>
<div class="col-sm-2 col-sm-pull-1">
<input type="text" placeholder="master" name="branch" class="form-control"/>
</div>
</div>

View File

@@ -31,7 +31,7 @@
<label class="col-sm-3 control-label">Preferred Tags</label>
<div class="col-sm-1 col-sm-push-5 help-inline">
<i class="icon-sonarr-form-info" title="When the release contains these tags it will be preferred." />
<i class="icon-sonarr-form-info" title="When the release contains these tags it will be preferred. Case Insensitive." />
</div>
<div class="col-sm-5 col-sm-pull-1">

View File

@@ -10,11 +10,11 @@
<div class="pull-left">
<span class="label label-warning x-min-thirty"
name="thirtyMinuteMinSize"
title="Minimum size for a 90 minute episode">
title="Minimum size for a 90 minute movie">
</span>
<span class="label label-info x-min-sixty"
name="sixtyMinuteMinSize"
title="Minimum size for a 140 minute episode">
title="Minimum size for a 140 minute movie">
</span>
</div>
<div class="pull-right">

View File

@@ -3,7 +3,7 @@ var AppLayout = require('../../AppLayout');
var Marionette = require('marionette');
var EditSeriesView = require('../../Series/Edit/EditSeriesView');
var EditMovieView = require('../../Movies/Edit/EditMovieView');
var DeleteSeriesView = require('../../Series/Delete/DeleteSeriesView');
var DeleteMovieView = require('../../Movies/Delete/DeleteMovieView');
var EpisodeDetailsLayout = require('../../Episode/EpisodeDetailsLayout');
var HistoryDetailsLayout = require('../../Activity/History/Details/HistoryDetailsLayout');
var LogDetailsView = require('../../System/Logs/Table/Details/LogDetailsView');
@@ -22,7 +22,7 @@ module.exports = Marionette.AppRouter.extend({
vent.on(vent.Commands.EditSeriesCommand, this._editSeries, this);
vent.on(vent.Commands.EditMovieCommand, this._editMovie, this);
vent.on(vent.Commands.EditFileCommand, this._editFile, this);
vent.on(vent.Commands.DeleteSeriesCommand, this._deleteSeries, this);
vent.on(vent.Commands.DeleteMovieCommand, this._deleteMovie, this);
vent.on(vent.Commands.ShowEpisodeDetails, this._showEpisode, this);
vent.on(vent.Commands.ShowMovieDetails, this._showMovie, this);
vent.on(vent.Commands.ShowHistoryDetails, this._showHistory, this);
@@ -64,8 +64,8 @@ module.exports = Marionette.AppRouter.extend({
AppLayout.modalRegion.show(view);
},
_deleteSeries : function(options) {
var view = new DeleteSeriesView({ model : options.series });
_deleteMovie : function(options) {
var view = new DeleteMovieView({ model : options.movie });
AppLayout.modalRegion.show(view);
},

View File

@@ -47,7 +47,7 @@
<meta name="msapplication-config" content="/Content/Images/favicon/browserconfig.xml">
<meta name="theme-color" content="#272727">
<link rel="alternate" type="text/calendar" title="iCalendar feed for Radarr" href="/feed/calendar/NzbDrone.ics"/>
<link rel="alternate" type="text/calendar" title="iCalendar feed for Radarr" href="/feed/calendar/Radarr.ics"/>
</head>
<body>
<div class="container">

View File

@@ -13,8 +13,9 @@ vent.Events = {
vent.Commands = {
EditSeriesCommand : 'EditSeriesCommand',
EditMovieCommand : 'EditMovieCommand',
EditFileCommand : "EditFileCommand",
EditFileCommand : "EditFileCommand",
DeleteSeriesCommand : 'DeleteSeriesCommand',
DeleteMovieCommand : 'DeleteMovieCommand',
OpenModalCommand : 'OpenModalCommand',
CloseModalCommand : 'CloseModalCommand',
OpenModal2Command : 'OpenModal2Command',