diff --git a/src/NzbDrone.Api/Series/MovieResource.cs b/src/NzbDrone.Api/Series/MovieResource.cs index 4733968aa..f9bcf658e 100644 --- a/src/NzbDrone.Api/Series/MovieResource.cs +++ b/src/NzbDrone.Api/Series/MovieResource.cs @@ -85,14 +85,12 @@ namespace NzbDrone.Api.Movie long size = 0; bool downloaded = false; - if(model.MovieFile != null && model.MovieFile.IsLoaded) + if (model.MovieFile != null && model.MovieFile.IsLoaded && model.MovieFile.Value != null) { size = model.MovieFile.Value.Size; downloaded = true; } - //long Size = model.MovieFile != null ? model.MovieFile.Value.Size : 0; - return new MovieResource { Id = model.Id, diff --git a/src/NzbDrone.Core.Test/IndexerTests/BitMeTvTests/BitMeTvFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/BitMeTvTests/BitMeTvFixture.cs deleted file mode 100644 index d49d940a4..000000000 --- a/src/NzbDrone.Core.Test/IndexerTests/BitMeTvTests/BitMeTvFixture.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Moq; -using NUnit.Framework; -using NzbDrone.Common.Http; -using NzbDrone.Core.Indexers; -using NzbDrone.Core.Indexers.BitMeTv; -using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Test.Framework; -using System; -using System.Linq; -using FluentAssertions; - -namespace NzbDrone.Core.Test.IndexerTests.BitMeTvTests -{ - [TestFixture] - public class BitMeTvFixture : CoreTest - { - [SetUp] - public void Setup() - { - Subject.Definition = new IndexerDefinition() - { - Name = "BitMeTV", - Settings = new BitMeTvSettings() { Cookie = "uid=123" } - }; - } - - [Test] - public void should_parse_recent_feed_from_BitMeTv() - { - var recentFeed = ReadAllText(@"Files/Indexers/BitMeTv/BitMeTv.xml"); - - Mocker.GetMock() - .Setup(o => o.Execute(It.Is(v => v.Method == HttpMethod.GET))) - .Returns(r => new HttpResponse(r, new HttpHeader(), recentFeed)); - - var releases = Subject.FetchRecent(); - - releases.Should().HaveCount(5); - releases.First().Should().BeOfType(); - - var torrentInfo = releases.First() as TorrentInfo; - - torrentInfo.Title.Should().Be("Total.Divas.S02E08.HDTV.x264-CRiMSON"); - torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent); - torrentInfo.DownloadUrl.Should().Be("http://www.bitmetv.org/download.php/12/Total.Divas.S02E08.HDTV.x264-CRiMSON.torrent"); - torrentInfo.InfoUrl.Should().BeNullOrEmpty(); - torrentInfo.CommentUrl.Should().BeNullOrEmpty(); - torrentInfo.Indexer.Should().Be(Subject.Definition.Name); - torrentInfo.PublishDate.Should().Be(DateTime.Parse("2014/05/13 17:04:29")); - torrentInfo.Size.Should().Be(395009065); - torrentInfo.InfoHash.Should().Be(null); - torrentInfo.MagnetUrl.Should().Be(null); - torrentInfo.Peers.Should().Be(null); - torrentInfo.Seeders.Should().Be(null); - } - } -} diff --git a/src/NzbDrone.Core.Test/IndexerTests/BroadcastheNetTests/BroadcastheNetFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/BroadcastheNetTests/BroadcastheNetFixture.cs deleted file mode 100644 index a22ba44e3..000000000 --- a/src/NzbDrone.Core.Test/IndexerTests/BroadcastheNetTests/BroadcastheNetFixture.cs +++ /dev/null @@ -1,161 +0,0 @@ -using Moq; -using NUnit.Framework; -using NzbDrone.Common.Http; -using NzbDrone.Core.Indexers; -using NzbDrone.Core.Indexers.BroadcastheNet; -using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Test.Framework; -using NzbDrone.Test.Common; -using System; -using System.Linq; -using FluentAssertions; - -namespace NzbDrone.Core.Test.IndexerTests.BroadcastheNetTests -{ - [TestFixture] - public class BroadcastheNetFixture : CoreTest - { - [SetUp] - public void Setup() - { - Subject.Definition = new IndexerDefinition() - { - Name = "BroadcastheNet", - Settings = new BroadcastheNetSettings() { ApiKey = "abc", BaseUrl = "https://api.btnapps.net/" } - }; - } - - [Test] - public void should_parse_recent_feed_from_BroadcastheNet() - { - var recentFeed = ReadAllText(@"Files/Indexers/BroadcastheNet/RecentFeed.json"); - - Mocker.GetMock() - .Setup(o => o.Execute(It.Is(v => v.Method == HttpMethod.POST))) - .Returns(r => new HttpResponse(r, new HttpHeader(), recentFeed)); - - var releases = Subject.FetchRecent(); - - releases.Should().HaveCount(2); - releases.First().Should().BeOfType(); - - var torrentInfo = releases.First() as TorrentInfo; - - torrentInfo.Guid.Should().Be("BTN-123"); - torrentInfo.Title.Should().Be("Jimmy.Kimmel.2014.09.15.Jane.Fonda.HDTV.x264-aAF"); - torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent); - torrentInfo.DownloadUrl.Should().Be("https://broadcasthe.net/torrents.php?action=download&id=123&authkey=123&torrent_pass=123"); - torrentInfo.InfoUrl.Should().Be("https://broadcasthe.net/torrents.php?id=237457&torrentid=123"); - torrentInfo.CommentUrl.Should().BeNullOrEmpty(); - torrentInfo.Indexer.Should().Be(Subject.Definition.Name); - torrentInfo.PublishDate.Should().Be(DateTime.Parse("2014/09/16 21:15:33")); - torrentInfo.Size.Should().Be(505099926); - torrentInfo.InfoHash.Should().Be("123"); - torrentInfo.TvdbId.Should().Be(71998); - torrentInfo.TvRageId.Should().Be(4055); - torrentInfo.MagnetUrl.Should().BeNullOrEmpty(); - torrentInfo.Peers.Should().Be(40+9); - torrentInfo.Seeders.Should().Be(40); - - torrentInfo.Origin.Should().Be("Scene"); - torrentInfo.Source.Should().Be("HDTV"); - torrentInfo.Container.Should().Be("MP4"); - torrentInfo.Codec.Should().Be("x264"); - torrentInfo.Resolution.Should().Be("SD"); - } - - private void VerifyBackOff() - { - Mocker.GetMock() - .Verify(v => v.RecordFailure(It.IsAny(), It.IsAny()), Times.Once()); - } - - [Test] - public void should_back_off_on_bad_request() - { - Mocker.GetMock() - .Setup(v => v.Execute(It.IsAny())) - .Returns(r => new HttpResponse(r, new HttpHeader(), new byte[0], System.Net.HttpStatusCode.BadRequest)); - - var results = Subject.FetchRecent(); - - results.Should().BeEmpty(); - - VerifyBackOff(); - - ExceptionVerification.ExpectedWarns(1); - } - - [Test] - public void should_back_off_and_report_api_key_invalid() - { - Mocker.GetMock() - .Setup(v => v.Execute(It.IsAny())) - .Returns(r => new HttpResponse(r, new HttpHeader(), new byte[0], System.Net.HttpStatusCode.Unauthorized)); - - var results = Subject.FetchRecent(); - - results.Should().BeEmpty(); - - VerifyBackOff(); - - ExceptionVerification.ExpectedWarns(1); - } - - [Test] - public void should_back_off_on_unknown_method() - { - Mocker.GetMock() - .Setup(v => v.Execute(It.IsAny())) - .Returns(r => new HttpResponse(r, new HttpHeader(), new byte[0], System.Net.HttpStatusCode.NotFound)); - - var results = Subject.FetchRecent(); - - results.Should().BeEmpty(); - - VerifyBackOff(); - - ExceptionVerification.ExpectedWarns(1); - } - - [Test] - public void should_back_off_api_limit_reached() - { - Mocker.GetMock() - .Setup(v => v.Execute(It.IsAny())) - .Returns(r => new HttpResponse(r, new HttpHeader(), new byte[0], System.Net.HttpStatusCode.ServiceUnavailable)); - - var results = Subject.FetchRecent(); - - results.Should().BeEmpty(); - - VerifyBackOff(); - - ExceptionVerification.ExpectedWarns(1); - } - - [Test] - public void should_replace_https_http_as_needed() - { - var recentFeed = ReadAllText(@"Files/Indexers/BroadcastheNet/RecentFeed.json"); - - (Subject.Definition.Settings as BroadcastheNetSettings).BaseUrl = "http://api.btnapps.net/"; - - recentFeed = recentFeed.Replace("http:", "https:"); - - Mocker.GetMock() - .Setup(o => o.Execute(It.Is(v => v.Method == HttpMethod.POST))) - .Returns(r => new HttpResponse(r, new HttpHeader(), recentFeed)); - - var releases = Subject.FetchRecent(); - - releases.Should().HaveCount(2); - releases.First().Should().BeOfType(); - - var torrentInfo = releases.First() as TorrentInfo; - - torrentInfo.DownloadUrl.Should().Be("http://broadcasthe.net/torrents.php?action=download&id=123&authkey=123&torrent_pass=123"); - torrentInfo.InfoUrl.Should().Be("http://broadcasthe.net/torrents.php?id=237457&torrentid=123"); - } - } -} diff --git a/src/NzbDrone.Core.Test/IndexerTests/TorrentleechTests/TorrentleechFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/TorrentleechTests/TorrentleechFixture.cs deleted file mode 100644 index 8ecb58144..000000000 --- a/src/NzbDrone.Core.Test/IndexerTests/TorrentleechTests/TorrentleechFixture.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Moq; -using NUnit.Framework; -using NzbDrone.Common.Http; -using NzbDrone.Core.Indexers; -using NzbDrone.Core.Indexers.Torrentleech; -using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Test.Framework; -using System; -using System.Linq; -using FluentAssertions; - -namespace NzbDrone.Core.Test.IndexerTests.TorrentleechTests -{ - [TestFixture] - public class TorrentleechFixture : CoreTest - { - [SetUp] - public void Setup() - { - Subject.Definition = new IndexerDefinition() - { - Name = "Torrentleech", - Settings = new TorrentleechSettings() - }; - } - - [Test] - public void should_parse_recent_feed_from_Torrentleech() - { - var recentFeed = ReadAllText(@"Files/Indexers/Torrentleech/Torrentleech.xml"); - - Mocker.GetMock() - .Setup(o => o.Execute(It.Is(v => v.Method == HttpMethod.GET))) - .Returns(r => new HttpResponse(r, new HttpHeader(), recentFeed)); - - var releases = Subject.FetchRecent(); - - releases.Should().HaveCount(5); - releases.First().Should().BeOfType(); - - var torrentInfo = releases.First() as TorrentInfo; - - torrentInfo.Title.Should().Be("Classic Car Rescue S02E04 720p HDTV x264-C4TV"); - torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent); - torrentInfo.DownloadUrl.Should().Be("http://www.torrentleech.org/rss/download/513575/1234/Classic.Car.Rescue.S02E04.720p.HDTV.x264-C4TV.torrent"); - torrentInfo.InfoUrl.Should().Be("http://www.torrentleech.org/torrent/513575"); - torrentInfo.CommentUrl.Should().Be("http://www.torrentleech.org/torrent/513575#comments"); - torrentInfo.Indexer.Should().Be(Subject.Definition.Name); - torrentInfo.PublishDate.Should().Be(DateTime.Parse("2014/05/12 19:15:28")); - torrentInfo.Size.Should().Be(0); - torrentInfo.InfoHash.Should().Be(null); - torrentInfo.MagnetUrl.Should().Be(null); - torrentInfo.Peers.Should().Be(7+1); - torrentInfo.Seeders.Should().Be(1); - } - } -} diff --git a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index 77b36ba5e..0140c7a61 100644 --- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -237,8 +237,6 @@ - - @@ -259,7 +257,6 @@ - diff --git a/src/NzbDrone.Core/Datastore/Migration/111_remove_bitmetv.cs b/src/NzbDrone.Core/Datastore/Migration/111_remove_bitmetv.cs new file mode 100644 index 000000000..c31652530 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/111_remove_bitmetv.cs @@ -0,0 +1,14 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(111)] + public class remove_bitmetv : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Delete.FromTable("Indexers").Row(new { Implementation = "BitMeTv" }); + } + } +} diff --git a/src/NzbDrone.Core/Datastore/Migration/112_remove_torrentleech.cs b/src/NzbDrone.Core/Datastore/Migration/112_remove_torrentleech.cs new file mode 100644 index 000000000..efaef09c7 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/112_remove_torrentleech.cs @@ -0,0 +1,14 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(112)] + public class remove_torrentleech : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Delete.FromTable("Indexers").Row(new { Implementation = "Torrentleech" }); + } + } +} diff --git a/src/NzbDrone.Core/Datastore/Migration/113_remove_broadcasthenet.cs b/src/NzbDrone.Core/Datastore/Migration/113_remove_broadcasthenet.cs new file mode 100644 index 000000000..e290283c6 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/113_remove_broadcasthenet.cs @@ -0,0 +1,14 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(113)] + public class remove_broadcasthenet : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Delete.FromTable("Indexers").Row(new { Implementation = "BroadcastheNet" }); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTv.cs b/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTv.cs deleted file mode 100644 index d6bfec2fb..000000000 --- a/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTv.cs +++ /dev/null @@ -1,32 +0,0 @@ -using NzbDrone.Common.Http; -using NzbDrone.Core.Configuration; -using NLog; -using NzbDrone.Core.Parser; - -namespace NzbDrone.Core.Indexers.BitMeTv -{ - public class BitMeTv : HttpIndexerBase - { - public override string Name => "BitMeTV"; - - public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override bool SupportsSearch => false; - public override int PageSize => 0; - - public BitMeTv(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger) - : base(httpClient, indexerStatusService, configService, parsingService, logger) - { - - } - - public override IIndexerRequestGenerator GetRequestGenerator() - { - return new BitMeTvRequestGenerator() { Settings = Settings }; - } - - public override IParseIndexerResponse GetParser() - { - return new TorrentRssParser() { ParseSizeInDescription = true }; - } - } -} \ No newline at end of file diff --git a/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTvSettings.cs b/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTvSettings.cs deleted file mode 100644 index 6e48f46de..000000000 --- a/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTvSettings.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Text.RegularExpressions; -using FluentValidation; -using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; -using NzbDrone.Core.Validation; - -namespace NzbDrone.Core.Indexers.BitMeTv -{ - public class BitMeTvSettingsValidator : AbstractValidator - { - public BitMeTvSettingsValidator() - { - RuleFor(c => c.BaseUrl).ValidRootUrl(); - RuleFor(c => c.UserId).NotEmpty(); - RuleFor(c => c.RssPasskey).NotEmpty(); - - RuleFor(c => c.Cookie).NotEmpty(); - - RuleFor(c => c.Cookie) - .Matches(@"pass=[0-9a-f]{32}", RegexOptions.IgnoreCase) - .WithMessage("Wrong pattern") - .AsWarning(); - } - } - - public class BitMeTvSettings : IProviderConfig - { - private static readonly BitMeTvSettingsValidator Validator = new BitMeTvSettingsValidator(); - - public BitMeTvSettings() - { - BaseUrl = "https://www.bitmetv.org"; - } - - [FieldDefinition(0, Label = "Website URL")] - public string BaseUrl { get; set; } - - [FieldDefinition(1, Label = "UserId")] - public string UserId { get; set; } - - [FieldDefinition(2, Label = "RSS Passkey")] - public string RssPasskey { get; set; } - - [FieldDefinition(3, Label = "Cookie", HelpText = "BitMeTv uses a login cookie needed to access the rss, you'll have to retrieve it via a browser.")] - public string Cookie { get; set; } - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } -} \ No newline at end of file diff --git a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNet.cs b/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNet.cs deleted file mode 100644 index fec611710..000000000 --- a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNet.cs +++ /dev/null @@ -1,45 +0,0 @@ -using NLog; -using NzbDrone.Common.Http; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.Parser; - -namespace NzbDrone.Core.Indexers.BroadcastheNet -{ - public class BroadcastheNet : HttpIndexerBase - { - public override string Name => "BroadcastheNet"; - - public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override bool SupportsRss => true; - public override bool SupportsSearch => true; - public override int PageSize => 100; - - public BroadcastheNet(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger) - : base(httpClient, indexerStatusService, configService, parsingService, logger) - { - - } - - public override IIndexerRequestGenerator GetRequestGenerator() - { - var requestGenerator = new BroadcastheNetRequestGenerator() { Settings = Settings, PageSize = PageSize }; - - var releaseInfo = _indexerStatusService.GetLastRssSyncReleaseInfo(Definition.Id); - if (releaseInfo != null) - { - int torrentID; - if (int.TryParse(releaseInfo.Guid.Replace("BTN-", string.Empty), out torrentID)) - { - requestGenerator.LastRecentTorrentID = torrentID; - } - } - - return requestGenerator; - } - - public override IParseIndexerResponse GetParser() - { - return new BroadcastheNetParser(); - } - } -} diff --git a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetParser.cs b/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetParser.cs deleted file mode 100644 index 9d126da54..000000000 --- a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetParser.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net; -using System.Text.RegularExpressions; -using NzbDrone.Common.Http; -using NzbDrone.Core.Indexers.Exceptions; -using NzbDrone.Core.Parser.Model; - -namespace NzbDrone.Core.Indexers.BroadcastheNet -{ - public class BroadcastheNetParser : IParseIndexerResponse - { - private static readonly Regex RegexProtocol = new Regex("^https?:", RegexOptions.Compiled); - - public IList ParseResponse(IndexerResponse indexerResponse) - { - var results = new List(); - - switch (indexerResponse.HttpResponse.StatusCode) - { - case HttpStatusCode.Unauthorized: - throw new ApiKeyException("API Key invalid or not authorized"); - case HttpStatusCode.NotFound: - throw new IndexerException(indexerResponse, "Indexer API call returned NotFound, the Indexer API may have changed."); - case HttpStatusCode.ServiceUnavailable: - throw new RequestLimitReachedException("Cannot do more than 150 API requests per hour."); - default: - if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) - { - throw new IndexerException(indexerResponse, "Indexer API call returned an unexpected StatusCode [{0}]", indexerResponse.HttpResponse.StatusCode); - } - break; - } - - if (indexerResponse.Content == "Query execution was interrupted") - { - throw new IndexerException(indexerResponse, "Indexer API returned an internal server error"); - } - - - JsonRpcResponse jsonResponse = new HttpResponse>(indexerResponse.HttpResponse).Resource; - - if (jsonResponse.Error != null || jsonResponse.Result == null) - { - throw new IndexerException(indexerResponse, "Indexer API call returned an error [{0}]", jsonResponse.Error); - } - - if (jsonResponse.Result.Results == 0) - { - return results; - } - - var protocol = indexerResponse.HttpRequest.Url.Scheme + ":"; - - foreach (var torrent in jsonResponse.Result.Torrents.Values) - { - var torrentInfo = new TorrentInfo(); - - torrentInfo.Guid = string.Format("BTN-{0}", torrent.TorrentID); - torrentInfo.Title = torrent.ReleaseName; - torrentInfo.Size = torrent.Size; - torrentInfo.DownloadUrl = RegexProtocol.Replace(torrent.DownloadURL, protocol); - torrentInfo.InfoUrl = string.Format("{0}//broadcasthe.net/torrents.php?id={1}&torrentid={2}", protocol, torrent.GroupID, torrent.TorrentID); - //torrentInfo.CommentUrl = - if (torrent.TvdbID.HasValue) - { - torrentInfo.TvdbId = torrent.TvdbID.Value; - } - if (torrent.TvrageID.HasValue) - { - torrentInfo.TvRageId = torrent.TvrageID.Value; - } - torrentInfo.PublishDate = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).ToUniversalTime().AddSeconds(torrent.Time); - //torrentInfo.MagnetUrl = - torrentInfo.InfoHash = torrent.InfoHash; - torrentInfo.Seeders = torrent.Seeders; - torrentInfo.Peers = torrent.Leechers + torrent.Seeders; - - torrentInfo.Origin = torrent.Origin; - torrentInfo.Source = torrent.Source; - torrentInfo.Container = torrent.Container; - torrentInfo.Codec = torrent.Codec; - torrentInfo.Resolution = torrent.Resolution; - - results.Add(torrentInfo); - } - - return results; - } - } -} diff --git a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetRequestGenerator.cs b/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetRequestGenerator.cs deleted file mode 100644 index 579761d89..000000000 --- a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetRequestGenerator.cs +++ /dev/null @@ -1,199 +0,0 @@ -using System.Linq; -using System.Collections.Generic; -using NzbDrone.Common.Http; -using NzbDrone.Core.IndexerSearch.Definitions; -using System; - -namespace NzbDrone.Core.Indexers.BroadcastheNet -{ - public class BroadcastheNetRequestGenerator : IIndexerRequestGenerator - { - public int MaxPages { get; set; } - public int PageSize { get; set; } - public BroadcastheNetSettings Settings { get; set; } - - public int? LastRecentTorrentID { get; set; } - - public BroadcastheNetRequestGenerator() - { - MaxPages = 10; - PageSize = 100; - } - - public virtual IndexerPageableRequestChain GetRecentRequests() - { - var pageableRequests = new IndexerPageableRequestChain(); - - if (LastRecentTorrentID.HasValue) - { - pageableRequests.Add(GetPagedRequests(MaxPages, new BroadcastheNetTorrentQuery() - { - Id = ">=" + (LastRecentTorrentID.Value - 100) - })); - } - - pageableRequests.AddTier(GetPagedRequests(MaxPages, new BroadcastheNetTorrentQuery() - { - Age = "<=86400" - })); - - return pageableRequests; - } - - public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - var parameters = new BroadcastheNetTorrentQuery(); - if (AddSeriesSearchParameters(parameters, searchCriteria)) - { - foreach (var episode in searchCriteria.Episodes) - { - parameters = parameters.Clone(); - - parameters.Category = "Episode"; - parameters.Name = string.Format("S{0:00}%E{1:00}%", episode.SeasonNumber, episode.EpisodeNumber); - - pageableRequests.Add(GetPagedRequests(MaxPages, parameters)); - } - - foreach (var seasonNumber in searchCriteria.Episodes.Select(v => v.SeasonNumber).Distinct()) - { - parameters = parameters.Clone(); - - parameters.Category = "Season"; - parameters.Name = string.Format("Season {0}", seasonNumber); - - pageableRequests.Add(GetPagedRequests(MaxPages, parameters)); - } - } - - return pageableRequests; - } - - public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - var parameters = new BroadcastheNetTorrentQuery(); - if (AddSeriesSearchParameters(parameters, searchCriteria)) - { - foreach (var seasonNumber in searchCriteria.Episodes.Select(v => v.SeasonNumber).Distinct()) - { - parameters.Category = "Season"; - parameters.Name = string.Format("Season {0}", seasonNumber); - - pageableRequests.Add(GetPagedRequests(MaxPages, parameters)); - - parameters = parameters.Clone(); - - parameters.Category = "Episode"; - parameters.Name = string.Format("S{0:00}E%", seasonNumber); - - pageableRequests.Add(GetPagedRequests(MaxPages, parameters)); - } - } - - return pageableRequests; - } - - public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - var parameters = new BroadcastheNetTorrentQuery(); - if (AddSeriesSearchParameters(parameters, searchCriteria)) - { - parameters.Category = "Episode"; - parameters.Name = string.Format("{0:yyyy}.{0:MM}.{0:dd}", searchCriteria.AirDate); - - pageableRequests.Add(GetPagedRequests(MaxPages, parameters)); - - pageableRequests.AddTier(); - - foreach (var episode in searchCriteria.Episodes) - { - parameters = parameters.Clone(); - - parameters.Category = "Episode"; - parameters.Name = string.Format("S{0:00}E{1:00}", episode.SeasonNumber, episode.EpisodeNumber); - - pageableRequests.Add(GetPagedRequests(MaxPages, parameters)); - } - } - - return pageableRequests; - } - - public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - var parameters = new BroadcastheNetTorrentQuery(); - if (AddSeriesSearchParameters(parameters, searchCriteria)) - { - foreach (var episode in searchCriteria.Episodes) - { - parameters = parameters.Clone(); - - parameters.Category = "Episode"; - parameters.Name = string.Format("S{0:00}E{1:00}", episode.SeasonNumber, episode.EpisodeNumber); - - pageableRequests.Add(GetPagedRequests(MaxPages, parameters)); - } - - foreach (var seasonNumber in searchCriteria.Episodes.Select(v => v.SeasonNumber).Distinct()) - { - parameters = parameters.Clone(); - - parameters.Category = "Season"; - parameters.Name = string.Format("Season {0}", seasonNumber); - - pageableRequests.Add(GetPagedRequests(MaxPages, parameters)); - } - } - - return pageableRequests; - } - - public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria) - { - return new IndexerPageableRequestChain(); - } - - private bool AddSeriesSearchParameters(BroadcastheNetTorrentQuery parameters, SearchCriteriaBase searchCriteria) - { - if (searchCriteria.Series.TvdbId != 0) - { - parameters.Tvdb = string.Format("{0}", searchCriteria.Series.TvdbId); - return true; - } - if (searchCriteria.Series.TvRageId != 0) - { - parameters.Tvrage = string.Format("{0}", searchCriteria.Series.TvRageId); - return true; - } - // BTN is very neatly managed, so it's unlikely they map tvrage/tvdb wrongly. - return false; - } - - private IEnumerable GetPagedRequests(int maxPages, BroadcastheNetTorrentQuery parameters) - { - var builder = new JsonRpcRequestBuilder(Settings.BaseUrl) - .Call("getTorrents", Settings.ApiKey, parameters, PageSize, 0); - builder.SuppressHttpError = true; - - for (var page = 0; page < maxPages; page++) - { - builder.JsonParameters[3] = page * PageSize; - - yield return new IndexerRequest(builder.Build()); - } - } - - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) - { - return new IndexerPageableRequestChain(); - } - } -} diff --git a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetSettings.cs b/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetSettings.cs deleted file mode 100644 index ba3d2f969..000000000 --- a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetSettings.cs +++ /dev/null @@ -1,37 +0,0 @@ -using FluentValidation; -using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; -using NzbDrone.Core.Validation; - -namespace NzbDrone.Core.Indexers.BroadcastheNet -{ - public class BroadcastheNetSettingsValidator : AbstractValidator - { - public BroadcastheNetSettingsValidator() - { - RuleFor(c => c.BaseUrl).ValidRootUrl(); - RuleFor(c => c.ApiKey).NotEmpty(); - } - } - - public class BroadcastheNetSettings : IProviderConfig - { - private static readonly BroadcastheNetSettingsValidator Validator = new BroadcastheNetSettingsValidator(); - - public BroadcastheNetSettings() - { - BaseUrl = "http://api.btnapps.net/"; - } - - [FieldDefinition(0, Label = "API URL", Advanced = true, HelpText = "Do not change this unless you know what you're doing. Since your API key will be sent to that host.")] - public string BaseUrl { get; set; } - - [FieldDefinition(1, Label = "API Key")] - public string ApiKey { get; set; } - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } -} \ No newline at end of file diff --git a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetTorrent.cs b/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetTorrent.cs deleted file mode 100644 index fd33c3bac..000000000 --- a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetTorrent.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace NzbDrone.Core.Indexers.BroadcastheNet -{ - public class BroadcastheNetTorrent - { - public string GroupName { get; set; } - public int GroupID { get; set; } - public int TorrentID { get; set; } - public int SeriesID { get; set; } - public string Series { get; set; } - public string SeriesBanner { get; set; } - public string SeriesPoster { get; set; } - public string YoutubeTrailer { get; set; } - public string Category { get; set; } - public int? Snatched { get; set; } - public int? Seeders { get; set; } - public int? Leechers { get; set; } - public string Source { get; set; } - public string Container { get; set; } - public string Codec { get; set; } - public string Resolution { get; set; } - public string Origin { get; set; } - public string ReleaseName { get; set; } - public long Size { get; set; } - public long Time { get; set; } - public int? TvdbID { get; set; } - public int? TvrageID { get; set; } - public string ImdbID { get; set; } - public string InfoHash { get; set; } - public string DownloadURL { get; set; } - } -} diff --git a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetTorrentQuery.cs b/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetTorrentQuery.cs deleted file mode 100644 index 1180f9b63..000000000 --- a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetTorrentQuery.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Newtonsoft.Json; - -namespace NzbDrone.Core.Indexers.BroadcastheNet -{ - public class BroadcastheNetTorrentQuery - { - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string Id { get; set; } - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string Category { get; set; } - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string Name { get; set; } - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string Search { get; set; } - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string Codec { get; set; } - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string Container { get; set; } - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string Source { get; set; } - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string Resolution { get; set; } - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string Origin { get; set; } - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string Hash { get; set; } - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string Tvdb { get; set; } - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string Tvrage { get; set; } - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string Age { get; set; } - - public BroadcastheNetTorrentQuery Clone() - { - return MemberwiseClone() as BroadcastheNetTorrentQuery; - } - } -} diff --git a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetTorrents.cs b/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetTorrents.cs deleted file mode 100644 index f9329e7ea..000000000 --- a/src/NzbDrone.Core/Indexers/BroadcastheNet/BroadcastheNetTorrents.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; - -namespace NzbDrone.Core.Indexers.BroadcastheNet -{ - public class BroadcastheNetTorrents - { - public Dictionary Torrents { get; set; } - public int Results { get; set; } - } -} diff --git a/src/NzbDrone.Core/Indexers/HDBits/HDBitsRequestGenerator.cs b/src/NzbDrone.Core/Indexers/HDBits/HDBitsRequestGenerator.cs index 2b377a9fd..84fef6bb8 100644 --- a/src/NzbDrone.Core/Indexers/HDBits/HDBitsRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/HDBits/HDBitsRequestGenerator.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using NzbDrone.Common.Http; @@ -22,21 +22,7 @@ namespace NzbDrone.Core.Indexers.HDBits public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria) { - var pageableRequests = new IndexerPageableRequestChain(); - - var queryBase = new TorrentQuery(); - if (TryAddSearchParameters(queryBase, searchCriteria)) - { - foreach (var episode in searchCriteria.Episodes) - { - var query = queryBase.Clone(); - - query.TvdbInfo.Season = episode.SeasonNumber; - query.TvdbInfo.Episode = episode.EpisodeNumber; - } - } - - return pageableRequests; + return new IndexerPageableRequestChain(); } public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria) @@ -46,69 +32,28 @@ namespace NzbDrone.Core.Indexers.HDBits public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria) { - var pageableRequests = new IndexerPageableRequestChain(); - - var query = new TorrentQuery(); - if (TryAddSearchParameters(query, searchCriteria)) - { - query.Search = string.Format("{0:yyyy}-{0:MM}-{0:dd}", searchCriteria.AirDate); - - pageableRequests.Add(GetRequest(query)); - } - - return pageableRequests; + return new IndexerPageableRequestChain(); } public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria) { - var pageableRequests = new IndexerPageableRequestChain(); - - var queryBase = new TorrentQuery(); - if (TryAddSearchParameters(queryBase, searchCriteria)) - { - foreach (var seasonNumber in searchCriteria.Episodes.Select(e => e.SeasonNumber).Distinct()) - { - var query = queryBase.Clone(); - - query.TvdbInfo.Season = seasonNumber; - - pageableRequests.Add(GetRequest(query)); - } - } - - return pageableRequests; + return new IndexerPageableRequestChain(); } public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria) { - var pageableRequests = new IndexerPageableRequestChain(); - - var queryBase = new TorrentQuery(); - if (TryAddSearchParameters(queryBase, searchCriteria)) - { - foreach (var episode in searchCriteria.Episodes) - { - var query = queryBase.Clone(); - - query.TvdbInfo.Season = episode.SeasonNumber; - query.TvdbInfo.Episode = episode.EpisodeNumber; - - pageableRequests.Add(GetRequest(query)); - } - } - - return pageableRequests; + return new IndexerPageableRequestChain(); } - private bool TryAddSearchParameters(TorrentQuery query, SearchCriteriaBase searchCriteria) + public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) { - if (searchCriteria.Series.TvdbId != 0) - { - query.TvdbInfo = query.TvdbInfo ?? new TvdbInfo(); - query.TvdbInfo.Id = searchCriteria.Series.TvdbId; - return true; - } - return false; + + var pageableRequests = new IndexerPageableRequestChain(); + var queryBase = new TorrentQuery(); + var query = queryBase.Clone(); + query.ImdbInfo.Id = int.Parse(searchCriteria.Movie.ImdbId.Substring(2)); + pageableRequests.Add(GetRequest(query)); + return pageableRequests; } private IEnumerable GetRequest(TorrentQuery query) @@ -129,10 +74,5 @@ namespace NzbDrone.Core.Indexers.HDBits yield return new IndexerRequest(request); } - - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) - { - return new IndexerPageableRequestChain(); - } } } diff --git a/src/NzbDrone.Core/Indexers/Omgwtfnzbs/OmgwtfnzbsRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Omgwtfnzbs/OmgwtfnzbsRequestGenerator.cs index 983b15a32..a0b81decd 100644 --- a/src/NzbDrone.Core/Indexers/Omgwtfnzbs/OmgwtfnzbsRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Omgwtfnzbs/OmgwtfnzbsRequestGenerator.cs @@ -92,7 +92,7 @@ namespace NzbDrone.Core.Indexers.Omgwtfnzbs private IEnumerable GetPagedRequests(string query) { var url = new StringBuilder(); - url.AppendFormat("{0}?catid=19,20&user={1}&api={2}&eng=1&delay={3}", BaseUrl, Settings.Username, Settings.ApiKey, Settings.Delay); + url.AppendFormat("{0}?catid=15,16,17&user={1}&api={2}&eng=1&delay={3}", BaseUrl, Settings.Username, Settings.ApiKey, Settings.Delay); if (query.IsNotNullOrWhiteSpace()) { @@ -105,7 +105,12 @@ namespace NzbDrone.Core.Indexers.Omgwtfnzbs public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) { - return new IndexerPageableRequestChain(); + var pageableRequests = new IndexerPageableRequestChain(); + + pageableRequests.Add(GetPagedRequests(string.Format("{0}", + searchCriteria.Movie.Title))); + + return pageableRequests; } } } diff --git a/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcorn.cs b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcorn.cs new file mode 100644 index 000000000..301894f57 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcorn.cs @@ -0,0 +1,30 @@ +using NLog; +using NzbDrone.Common.Http; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Parser; + +namespace NzbDrone.Core.Indexers.PassThePopcorn +{ + public class PassThePopcorn : HttpIndexerBase + { + public override string Name => "PassThePopcorn"; + public override DownloadProtocol Protocol => DownloadProtocol.Torrent; + public override bool SupportsRss => true; + public override bool SupportsSearch => true; + public override int PageSize => 50; + + public PassThePopcorn(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger) + : base(httpClient, indexerStatusService, configService, parsingService, logger) + { } + + public override IIndexerRequestGenerator GetRequestGenerator() + { + return new PassThePopcornRequestGenerator() { Settings = Settings }; + } + + public override IParseIndexerResponse GetParser() + { + return new PassThePopcornParser(Settings); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornApi.cs b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornApi.cs new file mode 100644 index 000000000..9d7c93ea8 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornApi.cs @@ -0,0 +1,59 @@ +using System; +using Newtonsoft.Json; +using System.Collections.Generic; + +namespace NzbDrone.Core.Indexers.PassThePopcorn +{ + public class Director + { + public string Name { get; set; } + public string Id { get; set; } + } + + public class Torrent + { + public int Id { get; set; } + public string Quality { get; set; } + public string Source { get; set; } + public string Container { get; set; } + public string Codec { get; set; } + public string Resolution { get; set; } + public bool Scene { get; set; } + public string Size { get; set; } + public DateTime UploadTime { get; set; } + public string RemasterTitle { get; set; } + public string Snatched { get; set; } + public string Seeders { get; set; } + public string Leechers { get; set; } + public string ReleaseName { get; set; } + public bool Checked { get; set; } + public bool GoldenPopcorn { get; set; } + } + + public class Movie + { + public string GroupId { get; set; } + public string Title { get; set; } + public string Year { get; set; } + public string Cover { get; set; } + public List Tags { get; set; } + public List Directors { get; set; } + public string ImdbId { get; set; } + public int TotalLeechers { get; set; } + public int TotalSeeders { get; set; } + public int TotalSnatched { get; set; } + public long MaxSize { get; set; } + public string LastUploadTime { get; set; } + public List Torrents { get; set; } + } + + public class PassThePopcornResponse + { + public string TotalResults { get; set; } + public List Movies { get; set; } + public string Page { get; set; } + public string AuthKey { get; set; } + public string PassKey { get; set; } + } + +} diff --git a/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornInfo.cs b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornInfo.cs new file mode 100644 index 000000000..3fec7eaff --- /dev/null +++ b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornInfo.cs @@ -0,0 +1,15 @@ +using NzbDrone.Core.Parser.Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NzbDrone.Core.Indexers.PassThePopcorn +{ + public class PassThePopcornInfo : TorrentInfo + { + public bool? Golden { get; set; } + public bool? Scene { get; set; } + public bool? Approved { get; set; } + } +} diff --git a/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornParser.cs b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornParser.cs new file mode 100644 index 000000000..ef1ad3909 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornParser.cs @@ -0,0 +1,144 @@ +using System.Collections.Generic; +using System.Net; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NzbDrone.Common.Http; +using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Parser.Model; +using System; +using System.Linq; + +namespace NzbDrone.Core.Indexers.PassThePopcorn +{ + public class PassThePopcornParser : IParseIndexerResponse + { + private readonly PassThePopcornSettings _settings; + + public PassThePopcornParser(PassThePopcornSettings settings) + { + _settings = settings; + } + + public IList ParseResponse(IndexerResponse indexerResponse) + { + var torrentInfos = new List(); + + if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK) + { + throw new IndexerException(indexerResponse, + "Unexpected response status {0} code from API request", + indexerResponse.HttpResponse.StatusCode); + } + + var jsonResponse = JsonConvert.DeserializeObject(indexerResponse.Content); + + var responseData = jsonResponse.Movies; + if (responseData == null) + { + throw new IndexerException(indexerResponse, + "Indexer API call response missing result data"); + } + + foreach (var result in responseData) + { + foreach (var torrent in result.Torrents) + { + var id = torrent.Id; + var title = torrent.ReleaseName; + + if (torrent.GoldenPopcorn) + { + title = $"{title} 🍿"; + } + + if (torrent.Checked) + { + title = $"{title} ✔"; + } + + //if (IsPropertyExist(torrent, "RemasterTitle")) + //{ + // if (torrent.RemasterTitle != null) + // { + // title = $"{title} - {torrent.RemasterTitle}"; + // } + //} + + // Only add approved torrents + if (_settings.Approved && torrent.Checked) + { + torrentInfos.Add(new PassThePopcornInfo() + { + Guid = string.Format("PassThePopcorn-{0}", id), + Title = title, + Size = long.Parse(torrent.Size), + DownloadUrl = GetDownloadUrl(id, jsonResponse.AuthKey, jsonResponse.PassKey), + InfoUrl = GetInfoUrl(result.GroupId, id), + Seeders = int.Parse(torrent.Seeders), + Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders), + PublishDate = torrent.UploadTime.ToUniversalTime(), + Golden = torrent.GoldenPopcorn, + Scene = torrent.Scene, + Approved = torrent.Checked + }); + } + // Add all torrents + else if (!_settings.Approved) + { + torrentInfos.Add(new PassThePopcornInfo() + { + Guid = string.Format("PassThePopcorn-{0}", id), + Title = title, + Size = long.Parse(torrent.Size), + DownloadUrl = GetDownloadUrl(id, jsonResponse.AuthKey, jsonResponse.PassKey), + InfoUrl = GetInfoUrl(result.GroupId, id), + Seeders = int.Parse(torrent.Seeders), + Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders), + PublishDate = torrent.UploadTime.ToUniversalTime(), + Golden = torrent.GoldenPopcorn, + Scene = torrent.Scene, + Approved = torrent.Checked + }); + } + // Don't add any torrents + else if (_settings.Approved && !torrent.Checked) + { + continue; + } + } + } + + // prefer golden + // prefer scene + // require approval + return torrentInfos.OrderBy(o => ((dynamic)o).Golden ? 0 : 1).ThenBy(o => ((dynamic)o).Scene ? 0 : 1).ThenByDescending(o => ((dynamic)o).PublishDate).ToArray(); + } + + private string GetDownloadUrl(int torrentId, string authKey, string passKey) + { + var url = new HttpUri(_settings.BaseUrl) + .CombinePath("/torrents.php") + .AddQueryParam("action", "download") + .AddQueryParam("id", torrentId) + .AddQueryParam("authkey", authKey) + .AddQueryParam("torrent_pass", passKey); + + return url.FullUri; + } + + private string GetInfoUrl(string groupId, int torrentId) + { + var url = new HttpUri(_settings.BaseUrl) + .CombinePath("/torrents.php") + .AddQueryParam("id", groupId) + .AddQueryParam("torrentid", torrentId); + + return url.FullUri; + } + + //public static bool IsPropertyExist(dynamic torrents, string name) + //{ + // return torrents.GetType().GetProperty(name) != null; + //} + } +} diff --git a/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTvRequestGenerator.cs b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornRequestGenerator.cs similarity index 71% rename from src/NzbDrone.Core/Indexers/BitMeTv/BitMeTvRequestGenerator.cs rename to src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornRequestGenerator.cs index 0c631af39..773f18b79 100644 --- a/src/NzbDrone.Core/Indexers/BitMeTv/BitMeTvRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornRequestGenerator.cs @@ -1,56 +1,60 @@ using System; using System.Collections.Generic; +using System.Linq; using NzbDrone.Common.Http; +using NzbDrone.Common.Serializer; using NzbDrone.Core.IndexerSearch.Definitions; -namespace NzbDrone.Core.Indexers.BitMeTv +namespace NzbDrone.Core.Indexers.PassThePopcorn { - public class BitMeTvRequestGenerator : IIndexerRequestGenerator + public class PassThePopcornRequestGenerator : IIndexerRequestGenerator { - public BitMeTvSettings Settings { get; set; } - + public PassThePopcornSettings Settings { get; set; } + public virtual IndexerPageableRequestChain GetRecentRequests() { var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetRssRequests()); + pageableRequests.Add(GetRequest(null)); return pageableRequests; } - public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria) + public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) { - return new IndexerPageableRequestChain(); + var pageableRequests = new IndexerPageableRequestChain(); + pageableRequests.Add(GetRequest(searchCriteria.Movie.ImdbId)); + return pageableRequests; } - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria) { return new IndexerPageableRequestChain(); } - public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria) + public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria) { return new IndexerPageableRequestChain(); } - public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria) + public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria) { return new IndexerPageableRequestChain(); } - public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria) + public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria) { return new IndexerPageableRequestChain(); } - public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria) + public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria) { return new IndexerPageableRequestChain(); } - private IEnumerable GetRssRequests() + private IEnumerable GetRequest(string searchParameters) { - var request = new IndexerRequest(string.Format("{0}/rss.php?uid={1}&passkey={2}", Settings.BaseUrl.Trim().TrimEnd('/'), Settings.UserId, Settings.RssPasskey), HttpAccept.Html); + var request = new IndexerRequest(string.Format("{0}/torrents.php?json=noredirect&searchstr={1}", Settings.BaseUrl.Trim().TrimEnd('/'), searchParameters), HttpAccept.Json); foreach (var cookie in HttpHeader.ParseCookies(Settings.Cookie)) { diff --git a/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornSettings.cs b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornSettings.cs new file mode 100644 index 000000000..88d7e15b2 --- /dev/null +++ b/src/NzbDrone.Core/Indexers/PassThePopcorn/PassThePopcornSettings.cs @@ -0,0 +1,52 @@ +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.ThingiProvider; +using NzbDrone.Core.Validation; +using System.Text.RegularExpressions; + +namespace NzbDrone.Core.Indexers.PassThePopcorn +{ + public class PassThePopcornSettingsValidator : AbstractValidator + { + public PassThePopcornSettingsValidator() + { + RuleFor(c => c.BaseUrl).ValidRootUrl(); + RuleFor(c => c.Cookie).NotEmpty(); + + RuleFor(c => c.Cookie) + .Matches(@"__cfduid=[0-9a-f]{43}", RegexOptions.IgnoreCase) + .WithMessage("Wrong pattern") + .AsWarning(); + } + } + + public class PassThePopcornSettings : IProviderConfig + { + private static readonly PassThePopcornSettingsValidator Validator = new PassThePopcornSettingsValidator(); + + public PassThePopcornSettings() + { + BaseUrl = "https://passthepopcorn.me"; + } + + [FieldDefinition(0, Label = "API URL", Advanced = true, HelpText = "Do not change this unless you know what you're doing. Since your cookie will be sent to that host.")] + public string BaseUrl { get; set; } + + [FieldDefinition(1, Label = "Cookie", HelpText = "PassThePopcorn uses a login cookie needed to access the API, you'll have to retrieve it via a browser.")] + public string Cookie { get; set; } + + [FieldDefinition(2, Type = FieldType.Checkbox, Label = "Prefer Golden", HelpText = "Favors Golden Popcorn-releases over all other releases.")] + public bool Golden { get; set; } + + [FieldDefinition(3, Type = FieldType.Checkbox, Label = "Prefer Scene", HelpText = "Favors scene-releases over non-scene releases.")] + public bool Scene { get; set; } + + [FieldDefinition(4, Type = FieldType.Checkbox, Label = "Require Approved", HelpText = "Require staff-approval for releases to be accepted.")] + public bool Approved { get; set; } + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Torrentleech/Torrentleech.cs b/src/NzbDrone.Core/Indexers/Torrentleech/Torrentleech.cs deleted file mode 100644 index 5c7620a1a..000000000 --- a/src/NzbDrone.Core/Indexers/Torrentleech/Torrentleech.cs +++ /dev/null @@ -1,32 +0,0 @@ -using NzbDrone.Common.Http; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.Parser; -using NLog; - -namespace NzbDrone.Core.Indexers.Torrentleech -{ - public class Torrentleech : HttpIndexerBase - { - public override string Name => "TorrentLeech"; - - public override DownloadProtocol Protocol => DownloadProtocol.Torrent; - public override bool SupportsSearch => false; - public override int PageSize => 0; - - public Torrentleech(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger) - : base(httpClient, indexerStatusService, configService, parsingService, logger) - { - - } - - public override IIndexerRequestGenerator GetRequestGenerator() - { - return new TorrentleechRequestGenerator() { Settings = Settings }; - } - - public override IParseIndexerResponse GetParser() - { - return new TorrentRssParser() { UseGuidInfoUrl = true, ParseSeedersInDescription = true }; - } - } -} diff --git a/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechRequestGenerator.cs deleted file mode 100644 index 51b458c6d..000000000 --- a/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechRequestGenerator.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections.Generic; -using NzbDrone.Common.Http; -using NzbDrone.Core.IndexerSearch.Definitions; - -namespace NzbDrone.Core.Indexers.Torrentleech -{ - public class TorrentleechRequestGenerator : IIndexerRequestGenerator - { - public TorrentleechSettings Settings { get; set; } - - public virtual IndexerPageableRequestChain GetRecentRequests() - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetRssRequests(null)); - - return pageableRequests; - } - - public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria) - { - return new IndexerPageableRequestChain(); - } - - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) - { - return new IndexerPageableRequestChain(); - } - - public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria) - { - return new IndexerPageableRequestChain(); - } - - public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria) - { - return new IndexerPageableRequestChain(); - } - - public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria) - { - return new IndexerPageableRequestChain(); - } - - public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria) - { - return new IndexerPageableRequestChain(); - } - - private IEnumerable GetRssRequests(string searchParameters) - { - yield return new IndexerRequest(string.Format("{0}/{1}{2}", Settings.BaseUrl.Trim().TrimEnd('/'), Settings.ApiKey, searchParameters), HttpAccept.Rss); - } - } -} diff --git a/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechSettings.cs b/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechSettings.cs deleted file mode 100644 index 957bfc3ed..000000000 --- a/src/NzbDrone.Core/Indexers/Torrentleech/TorrentleechSettings.cs +++ /dev/null @@ -1,37 +0,0 @@ -using FluentValidation; -using NzbDrone.Core.Annotations; -using NzbDrone.Core.ThingiProvider; -using NzbDrone.Core.Validation; - -namespace NzbDrone.Core.Indexers.Torrentleech -{ - public class TorrentleechSettingsValidator : AbstractValidator - { - public TorrentleechSettingsValidator() - { - RuleFor(c => c.BaseUrl).ValidRootUrl(); - RuleFor(c => c.ApiKey).NotEmpty(); - } - } - - public class TorrentleechSettings : IProviderConfig - { - private static readonly TorrentleechSettingsValidator Validator = new TorrentleechSettingsValidator(); - - public TorrentleechSettings() - { - BaseUrl = "http://rss.torrentleech.org"; - } - - [FieldDefinition(0, Label = "Website URL")] - public string BaseUrl { get; set; } - - [FieldDefinition(1, Label = "API Key")] - public string ApiKey { get; set; } - - public NzbDroneValidationResult Validate() - { - return new NzbDroneValidationResult(Validator.Validate(this)); - } - } -} \ No newline at end of file diff --git a/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/TMDBResources.cs b/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/TMDBResources.cs index 9c346057a..80e1b42cf 100644 --- a/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/TMDBResources.cs +++ b/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/TMDBResources.cs @@ -6,6 +6,10 @@ using System.Text; namespace NzbDrone.Core.MetadataSource.SkyHook.Resource { + public class FindRoot + { + public MovieResult[] movie_results { get; set; } + } public class MovieSearchRoot { public int page { get; set; } diff --git a/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs b/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs index 14ea51bd7..cdf86f436 100644 --- a/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs +++ b/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs @@ -146,79 +146,29 @@ namespace NzbDrone.Core.MetadataSource.SkyHook public Movie GetMovieInfo(string ImdbId) { - var imdbRequest = new HttpRequest("http://www.omdbapi.com/?i=" + ImdbId + "&plot=full&r=json"); - - var httpResponse = _httpClient.Get(imdbRequest); - - if (httpResponse.HasHttpError) - { - if (httpResponse.StatusCode == HttpStatusCode.NotFound) - { - throw new MovieNotFoundException(ImdbId); - } - else - { - throw new HttpException(imdbRequest, httpResponse); - } - } - - var response = httpResponse.Content; - - dynamic json = JsonConvert.DeserializeObject(response); - - var movie = new Movie(); + var request = _movieBuilder.Create() + .SetSegment("route", "find") + .SetSegment("id", ImdbId) + .SetSegment("secondaryRoute", "") + .AddQueryParam("external_source", "imdb_id") + .Build(); - movie.Title = json.Title; - movie.TitleSlug = movie.Title.ToLower().Replace(" ", "-"); - movie.Overview = json.Plot; - movie.CleanTitle = Parser.Parser.CleanSeriesTitle(movie.Title); - string airDateStr = json.Released; - DateTime airDate = DateTime.Parse(airDateStr); - movie.InCinemas = airDate; - movie.Year = airDate.Year; - movie.ImdbId = ImdbId; - string imdbRating = json.imdbVotes; - if (imdbRating == "N/A") - { - movie.Status = MovieStatusType.Announced; - } - else - { - movie.Status = MovieStatusType.Released; - } - string url = json.Poster; - var imdbPoster = new MediaCover.MediaCover(MediaCoverTypes.Poster, url); - movie.Images.Add(imdbPoster); - string runtime = json.Runtime; - int runtimeNum = 0; - int.TryParse(runtime.Replace("min", "").Trim(), out runtimeNum); - movie.Runtime = runtimeNum; + request.AllowAutoRedirect = true; + request.SuppressHttpError = true; - return movie; - } + var resources = _httpClient.Get(request).Resource; - private string[] SeparateYearFromTitle(string title) - { - var yearPattern = @"((?:19|20)\d{2})"; - var newTitle = title; - var substrings = Regex.Split(title, yearPattern); - var year = ""; - if (substrings.Length > 1) { - newTitle = substrings[0].TrimEnd("("); - year = substrings[1]; - } - - return new[] { newTitle.Trim(), year.Trim() }; + return resources.movie_results.SelectList(MapMovie).FirstOrDefault(); } private string StripTrailingTheFromTitle(string title) { if(title.EndsWith(",the")) { - title = title.Substring(title.Length - 4); + title = title.Substring(0, title.Length - 4); } else if(title.EndsWith(", the")) { - title = title.Substring(title.Length - 5); + title = title.Substring(0, title.Length - 5); } return title; } @@ -226,10 +176,25 @@ namespace NzbDrone.Core.MetadataSource.SkyHook public List SearchForNewMovie(string title) { var lowerTitle = title.ToLower(); - var yearCheck = SeparateYearFromTitle(lowerTitle); // TODO: Make this much less hacky! - lowerTitle = yearCheck[0]; - var yearTerm = yearCheck[1]; + var parserResult = Parser.Parser.ParseMovieTitle(title); + + var yearTerm = ""; + + if (parserResult != null && parserResult.MovieTitle != title) + { + //Parser found something interesting! + lowerTitle = parserResult.MovieTitle.ToLower(); + if (parserResult.Year > 1800) + { + yearTerm = parserResult.Year.ToString(); + } + + if (parserResult.ImdbId.IsNotNullOrWhiteSpace()) + { + return new List { GetMovieInfo(parserResult.ImdbId) }; + } + } lowerTitle = StripTrailingTheFromTitle(lowerTitle); @@ -290,43 +255,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook var movieResults = response.Resource.results; - var imdbMovies = new List(); - - foreach (MovieResult result in movieResults) - { - var imdbMovie = new Movie(); - imdbMovie.TmdbId = result.id; - try - { - imdbMovie.SortTitle = result.title; - imdbMovie.Title = result.title; - string titleSlug = result.title; - imdbMovie.TitleSlug = titleSlug.ToLower().Replace(" ", "-"); - imdbMovie.Year = DateTime.Parse(result.release_date).Year; - imdbMovie.Images = new List(); - imdbMovie.Overview = result.overview; - try - { - string url = result.poster_path; - var imdbPoster = _configService.GetCoverForURL(result.poster_path, MediaCoverTypes.Poster); - imdbMovie.Images.Add(imdbPoster); - } - catch (Exception e) - { - _logger.Debug(result); - continue; - } - - imdbMovies.Add(imdbMovie); - } - catch (Exception e) - { - _logger.Error(e, "Error occured while searching for new movies."); - } - - } - - return imdbMovies; + return movieResults.SelectList(MapMovie); } public List SearchForNewSeries(string title) @@ -380,6 +309,40 @@ namespace NzbDrone.Core.MetadataSource.SkyHook } } + private Movie MapMovie(MovieResult result) + { + var imdbMovie = new Movie(); + imdbMovie.TmdbId = result.id; + try + { + imdbMovie.SortTitle = result.title; + imdbMovie.Title = result.title; + string titleSlug = result.title; + imdbMovie.TitleSlug = titleSlug.ToLower().Replace(" ", "-"); + imdbMovie.Year = DateTime.Parse(result.release_date).Year; + imdbMovie.Images = new List(); + imdbMovie.Overview = result.overview; + try + { + string url = result.poster_path; + var imdbPoster = _configService.GetCoverForURL(result.poster_path, MediaCoverTypes.Poster); + imdbMovie.Images.Add(imdbPoster); + } + catch (Exception e) + { + _logger.Debug(result); + } + + return imdbMovie; + } + catch (Exception e) + { + _logger.Error(e, "Error occured while searching for new movies."); + } + + return null; + } + private static Series MapSeries(ShowResource show) { var series = new Series(); diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index a54696f83..97f67da50 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -183,6 +183,9 @@ + + + @@ -573,16 +576,6 @@ - - - - - - - - - - @@ -593,6 +586,12 @@ + + + + + + @@ -652,9 +651,6 @@ - - - diff --git a/src/NzbDrone.Core/Parser/Model/ParsedMovieInfo.cs b/src/NzbDrone.Core/Parser/Model/ParsedMovieInfo.cs index ba4501f38..87938423f 100644 --- a/src/NzbDrone.Core/Parser/Model/ParsedMovieInfo.cs +++ b/src/NzbDrone.Core/Parser/Model/ParsedMovieInfo.cs @@ -17,6 +17,7 @@ namespace NzbDrone.Core.Parser.Model public string ReleaseHash { get; set; } public string Edition { get; set;} public int Year { get; set; } + public string ImdbId { get; set; } public ParsedMovieInfo() { diff --git a/src/NzbDrone.Core/Parser/Parser.cs b/src/NzbDrone.Core/Parser/Parser.cs index d2a27d215..2120c3add 100644 --- a/src/NzbDrone.Core/Parser/Parser.cs +++ b/src/NzbDrone.Core/Parser/Parser.cs @@ -18,20 +18,20 @@ namespace NzbDrone.Core.Parser private static readonly Regex[] ReportMovieTitleRegex = new[] { //Special, Despecialized, etc. Edition Movies, e.g: Mission.Impossible.3.Special.Edition.2011 - new Regex(@"^(?.+?)?(?:(?:[-_\W](?<![()\[!]))*(?<edition>(\w+\.?edition))\.(?<year>(?<!e|x)\d{4}(?!p|i|\d+|\)|\]|\W\d+)))+(\W+|_|$)(?!\\)", + new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<edition>(\w+\.?edition))\.(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), //Special, Despecialized, etc. Edition Movies, e.g: Mission.Impossible.3.2011.Special.Edition //TODO: Seems to slow down parsing heavily! - new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![()\[!]))*(?<year>(?<!e|x)\d{4}(?!p|i|\d+|\)|\]|\W\d+)))+(\W+|_|$)(?!\\)(?<edition>((\w+\.?){1,3}edition))", + new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)(?<edition>((\w+\.?){1,3}edition))", RegexOptions.IgnoreCase | RegexOptions.Compiled), //Cut Movies, e.g: Mission.Impossible.3.Directors.Cut.2011 - new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![()\[!]))*(?<edition>(\w+\.?cut))\.(?<year>(?<!e|x)\d{4}(?!p|i|\d+|\)|\]|\W\d+)))+(\W+|_|$)(?!\\)", + new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<edition>(\w+\.?cut))\.(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), //Cut Movies, e.g: Mission.Impossible.3.2011.Directors.Cut - new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![()\[!]))*(?<year>(?<!e|x)\d{4}(?!p|i|\d+|\)|\]|\W\d+)))+(\W+|_|$)(?!\\)(?<edition>((\w+\.?){1,3}cut))", + new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)(?<edition>((\w+\.?){1,3}cut))", RegexOptions.IgnoreCase | RegexOptions.Compiled), //Normal movie format, e.g: Mission.Impossible.3.2011 - new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![()\[!]))*(?<year>(?<!e|x)\d{4}(?!p|i|\d+|\)|\]|\W\d+)))+(\W+|_|$)(?!\\)", + new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), //PassThePopcorn Torrent names: Star.Wars[PassThePopcorn] new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![()\[!]))*(?<year>(\[\w *\])))+(\W+|_|$)(?!\\)", @@ -263,7 +263,9 @@ namespace NzbDrone.Core.Parser private static readonly Regex FileExtensionRegex = new Regex(@"\.[a-z0-9]{2,4}$", RegexOptions.IgnoreCase | RegexOptions.Compiled); - private static readonly Regex SimpleTitleRegex = new Regex(@"(?:480[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 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*", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex WebsitePrefixRegex = new Regex(@"^\[\s*[a-z]+(\.[a-z]+)+\s*\][- ]*", @@ -396,6 +398,8 @@ namespace NzbDrone.Core.Parser result.ReleaseGroup = ParseReleaseGroup(title); + result.ImdbId = ParseImdbId(title); + var subGroup = GetSubGroup(match); if (!subGroup.IsNullOrWhiteSpace()) { @@ -433,6 +437,23 @@ namespace NzbDrone.Core.Parser return realResult; } + public static string ParseImdbId(string title) + { + var match = ReportImdbId.Match(title); + if (match.Success) + { + if (match.Groups["imdbid"].Value != null) + { + if (match.Groups["imdbid"].Length == 11) + { + return match.Groups["imdbid"].Value; + } + } + } + + return ""; + } + public static ParsedEpisodeInfo ParseTitle(string title) {