-
-
Notifications
You must be signed in to change notification settings - Fork 963
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(cherry picked from commit 6d88a98282d1441f903d567470a9f1ce6ba0b52f)
- Loading branch information
1 parent
f14482c
commit 588c8fb
Showing
7 changed files
with
339 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
using NLog; | ||
using NzbDrone.Common.Http; | ||
using NzbDrone.Core.Configuration; | ||
using NzbDrone.Core.Parser; | ||
|
||
namespace NzbDrone.Core.ImportLists.Rss.Plex | ||
{ | ||
public class PlexRssImport : RssImportBase<PlexRssImportSettings> | ||
{ | ||
public override string Name => "Plex Watchlist RSS"; | ||
public override ImportListType ListType => ImportListType.Plex; | ||
|
||
public PlexRssImport(IHttpClient httpClient, | ||
IImportListStatusService importListStatusService, | ||
IConfigService configService, | ||
IParsingService parsingService, | ||
Logger logger) | ||
: base(httpClient, importListStatusService, configService, parsingService, logger) | ||
{ | ||
} | ||
|
||
public override IParseImportListResponse GetParser() | ||
{ | ||
return new PlexRssImportParser(_logger); | ||
} | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
src/NzbDrone.Core/ImportLists/Rss/Plex/PlexRssImportParser.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
using System.Xml.Linq; | ||
using NLog; | ||
using NzbDrone.Common.Extensions; | ||
using NzbDrone.Core.ImportLists.ImportListMovies; | ||
using NzbDrone.Core.Indexers; | ||
using NzbDrone.Core.Indexers.Exceptions; | ||
|
||
namespace NzbDrone.Core.ImportLists.Rss.Plex | ||
{ | ||
public class PlexRssImportParser : RssImportBaseParser | ||
{ | ||
public PlexRssImportParser(Logger logger) | ||
: base(logger) | ||
{ | ||
} | ||
|
||
protected override ImportListMovie ProcessItem(XElement item) | ||
{ | ||
var category = item.TryGetValue("category"); | ||
|
||
if (category != "movie") | ||
{ | ||
return null; | ||
} | ||
|
||
var info = new ImportListMovie | ||
{ | ||
Title = item.TryGetValue("title", "Unknown") | ||
}; | ||
|
||
var guid = item.TryGetValue("guid", string.Empty); | ||
|
||
if (guid.IsNotNullOrWhiteSpace() && guid.StartsWith("imdb://")) | ||
{ | ||
info.ImdbId = Parser.Parser.ParseImdbId(guid.Replace("imdb://", "")); | ||
} | ||
|
||
if (info.ImdbId.IsNullOrWhiteSpace()) | ||
{ | ||
throw new UnsupportedFeedException("Each item in the RSS feed must have a guid element with a IMDB ID"); | ||
} | ||
|
||
return info; | ||
} | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
src/NzbDrone.Core/ImportLists/Rss/Plex/PlexRssImportSettings.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
using FluentValidation; | ||
using NzbDrone.Core.Annotations; | ||
using NzbDrone.Core.Validation; | ||
|
||
namespace NzbDrone.Core.ImportLists.Rss.Plex | ||
{ | ||
public class PlexRssImportSettingsValidator : AbstractValidator<PlexRssImportSettings> | ||
{ | ||
public PlexRssImportSettingsValidator() | ||
{ | ||
RuleFor(c => c.Url).NotEmpty(); | ||
} | ||
} | ||
|
||
public class PlexRssImportSettings : RssImportBaseSettings | ||
{ | ||
private PlexRssImportSettingsValidator Validator => new (); | ||
|
||
[FieldDefinition(0, Label = "Url", Type = FieldType.Textbox, HelpLink = "https://app.plex.tv/desktop/#!/settings/watchlist")] | ||
public override string Url { get; set; } | ||
|
||
public override NzbDroneValidationResult Validate() | ||
{ | ||
return new NzbDroneValidationResult(Validator.Validate(this)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
using NLog; | ||
using NzbDrone.Common.Http; | ||
using NzbDrone.Core.Configuration; | ||
using NzbDrone.Core.Parser; | ||
|
||
namespace NzbDrone.Core.ImportLists.Rss | ||
{ | ||
public abstract class RssImportBase<TSettings> : HttpImportListBase<TSettings> | ||
where TSettings : RssImportBaseSettings, new() | ||
{ | ||
public override bool Enabled => true; | ||
public override bool EnableAuto => false; | ||
|
||
public RssImportBase(IHttpClient httpClient, | ||
IImportListStatusService importListStatusService, | ||
IConfigService configService, | ||
IParsingService parsingService, | ||
Logger logger) | ||
: base(httpClient, importListStatusService, configService, parsingService, logger) | ||
{ | ||
} | ||
|
||
public override ImportListFetchResult Fetch() | ||
{ | ||
var generator = GetRequestGenerator(); | ||
|
||
return FetchMovies(generator.GetMovies()); | ||
} | ||
|
||
public override IParseImportListResponse GetParser() | ||
{ | ||
return new RssImportBaseParser(_logger); | ||
} | ||
|
||
public override IImportListRequestGenerator GetRequestGenerator() | ||
{ | ||
return new RssImportRequestGenerator | ||
{ | ||
Settings = Settings | ||
}; | ||
} | ||
} | ||
} |
142 changes: 142 additions & 0 deletions
142
src/NzbDrone.Core/ImportLists/Rss/RssImportBaseParser.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Net; | ||
using System.Xml; | ||
using System.Xml.Linq; | ||
using NLog; | ||
using NzbDrone.Common.Extensions; | ||
using NzbDrone.Core.ImportLists.Exceptions; | ||
using NzbDrone.Core.ImportLists.ImportListMovies; | ||
using NzbDrone.Core.Indexers; | ||
using NzbDrone.Core.Indexers.Exceptions; | ||
|
||
namespace NzbDrone.Core.ImportLists.Rss | ||
{ | ||
public class RssImportBaseParser : IParseImportListResponse | ||
{ | ||
private readonly Logger _logger; | ||
|
||
public RssImportBaseParser(Logger logger) | ||
{ | ||
_logger = logger; | ||
} | ||
|
||
public virtual IList<ImportListMovie> ParseResponse(ImportListResponse importResponse) | ||
{ | ||
var movies = new List<ImportListMovie>(); | ||
|
||
if (!PreProcess(importResponse)) | ||
{ | ||
return movies; | ||
} | ||
|
||
var document = LoadXmlDocument(importResponse); | ||
var items = GetItems(document).ToList(); | ||
|
||
foreach (var item in items) | ||
{ | ||
try | ||
{ | ||
var itemInfo = ProcessItem(item); | ||
|
||
movies.AddIfNotNull(itemInfo); | ||
} | ||
catch (UnsupportedFeedException itemEx) | ||
{ | ||
itemEx.WithData("FeedUrl", importResponse.Request.Url); | ||
itemEx.WithData("ItemTitle", item.Title()); | ||
throw; | ||
} | ||
catch (Exception itemEx) | ||
{ | ||
itemEx.WithData("FeedUrl", importResponse.Request.Url); | ||
itemEx.WithData("ItemTitle", item.Title()); | ||
_logger.Error(itemEx, "An error occurred while processing feed item from {0}", importResponse.Request.Url); | ||
} | ||
} | ||
|
||
return movies; | ||
} | ||
|
||
protected virtual bool PreProcess(ImportListResponse importListResponse) | ||
{ | ||
if (importListResponse.HttpResponse.StatusCode != HttpStatusCode.OK) | ||
{ | ||
throw new ImportListException(importListResponse, "Request resulted in an unexpected StatusCode [{0}]", importListResponse.HttpResponse.StatusCode); | ||
} | ||
|
||
if (importListResponse.HttpResponse.Headers.ContentType != null && importListResponse.HttpResponse.Headers.ContentType.Contains("text/xml") && | ||
importListResponse.HttpRequest.Headers.Accept != null && !importListResponse.HttpRequest.Headers.Accept.Contains("text/xml")) | ||
{ | ||
throw new ImportListException(importListResponse, "Request responded with html content. Site is likely blocked or unavailable."); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
protected virtual XDocument LoadXmlDocument(ImportListResponse importListResponse) | ||
{ | ||
try | ||
{ | ||
var content = XmlCleaner.ReplaceEntities(importListResponse.Content); | ||
content = XmlCleaner.ReplaceUnicode(content); | ||
|
||
using var xmlTextReader = XmlReader.Create(new StringReader(content), new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore, IgnoreComments = true }); | ||
|
||
return XDocument.Load(xmlTextReader); | ||
} | ||
catch (XmlException ex) | ||
{ | ||
var contentSample = importListResponse.Content.Substring(0, Math.Min(importListResponse.Content.Length, 512)); | ||
_logger.Debug("Truncated response content (originally {0} characters): {1}", importListResponse.Content.Length, contentSample); | ||
|
||
ex.WithData(importListResponse.HttpResponse); | ||
|
||
throw; | ||
} | ||
} | ||
|
||
protected IEnumerable<XElement> GetItems(XDocument document) | ||
{ | ||
var root = document.Root; | ||
|
||
if (root == null) | ||
{ | ||
return Enumerable.Empty<XElement>(); | ||
} | ||
|
||
var channel = root.Element("channel"); | ||
|
||
if (channel == null) | ||
{ | ||
return Enumerable.Empty<XElement>(); | ||
} | ||
|
||
return channel.Elements("item"); | ||
} | ||
|
||
protected virtual ImportListMovie ProcessItem(XElement item) | ||
{ | ||
var info = new ImportListMovie | ||
{ | ||
Title = item.TryGetValue("title", "Unknown") | ||
}; | ||
|
||
var guid = item.TryGetValue("guid"); | ||
|
||
if (guid != null && int.TryParse(guid, out var tmdbId)) | ||
{ | ||
info.TmdbId = tmdbId; | ||
} | ||
|
||
if (info.TmdbId == 0) | ||
{ | ||
throw new UnsupportedFeedException("Each item in the RSS feed must have a guid element with a TMDB ID"); | ||
} | ||
|
||
return info; | ||
} | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
src/NzbDrone.Core/ImportLists/Rss/RssImportBaseSettings.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
using FluentValidation; | ||
using NzbDrone.Core.Annotations; | ||
using NzbDrone.Core.ThingiProvider; | ||
using NzbDrone.Core.Validation; | ||
|
||
namespace NzbDrone.Core.ImportLists.Rss | ||
{ | ||
public class RssImportSettingsValidator : AbstractValidator<RssImportBaseSettings> | ||
{ | ||
public RssImportSettingsValidator() | ||
{ | ||
RuleFor(c => c.Url).NotEmpty(); | ||
} | ||
} | ||
|
||
public class RssImportBaseSettings : IProviderConfig | ||
{ | ||
private RssImportSettingsValidator Validator => new (); | ||
|
||
[FieldDefinition(0, Label = "Url", Type = FieldType.Textbox)] | ||
public virtual string Url { get; set; } | ||
|
||
public virtual NzbDroneValidationResult Validate() | ||
{ | ||
return new NzbDroneValidationResult(Validator.Validate(this)); | ||
} | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
src/NzbDrone.Core/ImportLists/Rss/RssImportRequestGenerator.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using System.Collections.Generic; | ||
using NzbDrone.Common.Http; | ||
|
||
namespace NzbDrone.Core.ImportLists.Rss | ||
{ | ||
public class RssImportRequestGenerator : IImportListRequestGenerator | ||
{ | ||
public RssImportBaseSettings Settings { get; set; } | ||
|
||
public virtual ImportListPageableRequestChain GetMovies() | ||
{ | ||
var pageableRequests = new ImportListPageableRequestChain(); | ||
|
||
pageableRequests.Add(GetMoviesRequest()); | ||
|
||
return pageableRequests; | ||
} | ||
|
||
private IEnumerable<ImportListRequest> GetMoviesRequest() | ||
{ | ||
var request = new ImportListRequest(Settings.Url, HttpAccept.Rss); | ||
|
||
yield return request; | ||
} | ||
} | ||
} |