1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-04-23 22:25:14 -04:00

Added couchpotato, and added a test

This commit is contained in:
Devin Buhl
2017-01-21 19:15:06 -05:00
parent b4d1c0e053
commit ddf10ed137
12 changed files with 736 additions and 209 deletions
@@ -3,91 +3,88 @@ using System.Xml.Serialization;
namespace NzbDrone.Core.NetImport.CouchPotato
{
class CouchPotatoAPI
public class CouchPotatoResponse
{
public class CouchPotatoResponse
{
public Movie[] movies { get; set; }
public int total { get; set; }
public bool empty { get; set; }
public bool success { get; set; }
}
public Movie[] movies { get; set; }
public int total { get; set; }
public bool empty { get; set; }
public bool success { get; set; }
}
public class Movie
{
public string status { get; set; }
public Info info { get; set; }
public string _t { get; set; }
public List<Release> releases { get; set; }
public string title { get; set; }
public string _rev { get; set; }
public string profile_id { get; set; }
public string _id { get; set; }
public object category_id { get; set; }
public string type { get; set; }
}
public class Movie
{
public string status { get; set; }
public Info info { get; set; }
public string _t { get; set; }
public List<Release> releases { get; set; }
public string title { get; set; }
public string _rev { get; set; }
public string profile_id { get; set; }
public string _id { get; set; }
public object category_id { get; set; }
public string type { get; set; }
}
public class Info
{
public string[] genres { get; set; }
public int tmdb_id { get; set; }
public string plot { get; set; }
public string tagline { get; set; }
public int year { get; set; }
public string original_title { get; set; }
public bool via_imdb { get; set; }
public string[] directors { get; set; }
public string[] titles { get; set; }
public string imdb { get; set; }
public string mpaa { get; set; }
public bool via_tmdb { get; set; }
public string[] actors { get; set; }
public string[] writers { get; set; }
public int runtime { get; set; }
public string type { get; set; }
public string released { get; set; }
}
public class Info
{
public string[] genres { get; set; }
public int tmdb_id { get; set; }
public string plot { get; set; }
public string tagline { get; set; }
public int year { get; set; }
public string original_title { get; set; }
public bool via_imdb { get; set; }
public string[] directors { get; set; }
public string[] titles { get; set; }
public string imdb { get; set; }
public string mpaa { get; set; }
public bool via_tmdb { get; set; }
public string[] actors { get; set; }
public string[] writers { get; set; }
public int runtime { get; set; }
public string type { get; set; }
public string released { get; set; }
}
public class ReleaseInfo
{
public int size { get; set; }
public int seeders { get; set; }
public string protocol { get; set; }
public string description { get; set; }
public string url { get; set; }
public int age { get; set; }
public string id { get; set; }
public int leechers { get; set; }
public int score { get; set; }
public string provider { get; set; }
public int seed_time { get; set; }
public string provider_extra { get; set; }
public string detail_url { get; set; }
public string type { get; set; }
public double seed_ratio { get; set; }
public string name { get; set; }
}
public class ReleaseInfo
{
public int size { get; set; }
public int seeders { get; set; }
public string protocol { get; set; }
public string description { get; set; }
public string url { get; set; }
public int age { get; set; }
public string id { get; set; }
public int leechers { get; set; }
public int score { get; set; }
public string provider { get; set; }
public int seed_time { get; set; }
public string provider_extra { get; set; }
public string detail_url { get; set; }
public string type { get; set; }
public double seed_ratio { get; set; }
public string name { get; set; }
}
public class DownloadInfo
{
public bool status_support { get; set; }
public string id { get; set; }
public string downloader { get; set; }
}
public class DownloadInfo
{
public bool status_support { get; set; }
public string id { get; set; }
public string downloader { get; set; }
}
public class Release
{
public string status { get; set; }
public ReleaseInfo info { get; set; }
public DownloadInfo download_info { get; set; }
public string _id { get; set; }
public string media_id { get; set; }
public string _rev { get; set; }
public string _t { get; set; }
public bool is_3d { get; set; }
public int last_edit { get; set; }
public string identifier { get; set; }
public string quality { get; set; }
}
public class Release
{
public string status { get; set; }
public ReleaseInfo info { get; set; }
public DownloadInfo download_info { get; set; }
public string _id { get; set; }
public string media_id { get; set; }
public string _rev { get; set; }
public string _t { get; set; }
public bool is_3d { get; set; }
public int last_edit { get; set; }
public string identifier { get; set; }
public string quality { get; set; }
}
}
@@ -0,0 +1,106 @@
using Newtonsoft.Json;
using NzbDrone.Core.NetImport.Exceptions;
using NzbDrone.Core.Tv;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Linq;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.NetImport.CouchPotato
{
public class CouchPotatoParser : IParseNetImportResponse
{
private readonly CouchPotatoSettings _settings;
private NetImportResponse _importResponse;
private readonly Logger _logger;
private static readonly Regex ReplaceEntities = new Regex("&[a-z]+;", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public CouchPotatoParser(CouchPotatoSettings settings)
{
_settings = settings;
}
public IList<Tv.Movie> ParseResponse(NetImportResponse importResponse)
{
_importResponse = importResponse;
var movies = new List<Tv.Movie>();
if (!PreProcess(_importResponse))
{
return movies;
}
var jsonResponse = JsonConvert.DeserializeObject<CouchPotatoResponse>(_importResponse.Content);
// no movies were return
if (jsonResponse.total == 0)
{
return movies;
}
var responseData = jsonResponse.movies;
foreach (var item in responseData)
{
// if there are no releases at all the movie wasn't found on CP, so return movies
if (!item.releases.Any() && item.type == "movie")
{
movies.AddIfNotNull(new Tv.Movie()
{
Title = item.title,
ImdbId = item.info.imdb,
TmdbId = item.info.tmdb_id
});
}
else
{
// snatched,missing,available,downloaded
// done,seeding
bool isCompleted = item.releases.Any(rel => (rel.status == "done" || rel.status == "seeding"));
if (!isCompleted)
{
movies.AddIfNotNull(new Tv.Movie()
{
Title = item.title,
ImdbId = item.info.imdb,
TmdbId = item.info.tmdb_id
});
}
}
}
return movies;
}
protected virtual bool PreProcess(NetImportResponse indexerResponse)
{
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
{
throw new NetImportException(indexerResponse, "Indexer API call resulted in an unexpected StatusCode [{0}]", indexerResponse.HttpResponse.StatusCode);
}
if (indexerResponse.HttpResponse.Headers.ContentType != null && indexerResponse.HttpResponse.Headers.ContentType.Contains("text/json") &&
indexerResponse.HttpRequest.Headers.Accept != null && !indexerResponse.HttpRequest.Headers.Accept.Contains("text/json"))
{
throw new NetImportException(indexerResponse, "Indexer responded with html content. Site is likely blocked or unavailable.");
}
return true;
}
}
}
@@ -0,0 +1,28 @@
using NzbDrone.Common.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Core.NetImport.CouchPotato
{
public class CouchPotatoRequestGenerator : INetImportRequestGenerator
{
public CouchPotatoSettings Settings { get; set; }
public virtual NetImportPageableRequestChain GetMovies()
{
var pageableRequests = new NetImportPageableRequestChain();
pageableRequests.Add(GetMovies(null));
return pageableRequests;
}
private IEnumerable<NetImportRequest> GetMovies(string searchParameters)
{
var request = new NetImportRequest($"{Settings.Link.Trim()}:{Settings.Port}/api/{Settings.ApiKey}/movie.list/?status=active", HttpAccept.Json);
yield return request;
}
}
}
@@ -0,0 +1,26 @@
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Profiles;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.NetImport.CouchPotato
{
public class CouchPotatoSettings : NetImportBaseSettings
{
public CouchPotatoSettings()
{
Link = "http://localhost";
}
[FieldDefinition(0, Label = "CouchPotato URL", HelpText = "Link to your CoouchPootato.")]
public new string Link { get; set; }
[FieldDefinition(1, Label = "CouchPotato Port", HelpText = "Port your CoouchPootato uses.")]
public string Port { get; set; }
[FieldDefinition(2, Label = "CouchPotato API Key", HelpText = "CoouchPootato API Key.")]
public string ApiKey { get; set; }
}
}
@@ -1,40 +0,0 @@
using System.Collections.Generic;
using System.Xml.Serialization;
namespace NzbDrone.Core.NetImport.RSSImport
{
class IMDbWatchListAPI
{
[XmlRoot(ElementName = "item")]
public class Movie
{
[XmlElement(ElementName = "pubDate")]
public string PublishDate { get; set; }
[XmlElement(ElementName = "title")]
public string Title { get; set; }
[XmlElement(ElementName = "link")]
public string Link { get; set; }
[XmlElement(ElementName = "guid")]
public string Guid { get; set; }
[XmlElement(ElementName = "description")]
public string Description { get; set; }
}
[XmlRoot(ElementName = "channel")]
public class Channel
{
[XmlElement(ElementName = "title")]
public string Title { get; set; }
[XmlElement(ElementName = "link")]
public string Link { get; set; }
[XmlElement(ElementName = "description")]
public string Description { get; set; }
[XmlElement(ElementName = "pubDate")]
public string PublishDate { get; set; }
[XmlElement(ElementName = "lastBuildDate")]
public string LastBuildDate { get; set; }
[XmlElement(ElementName = "item")]
public List<Movie> Movie { get; set; }
}
}
}
@@ -1,79 +0,0 @@
using System;
using System.Linq;
using System.Net;
using System.Xml.Linq;
using FluentValidation.Results;
using NLog;
using NzbDrone.Core.Exceptions;
using RestSharp;
using NzbDrone.Core.Rest;
namespace NzbDrone.Core.NetImport.RSSImport
{
public interface IIMDbWatchListProxy
{
void ImportMovies(string url);
ValidationFailure Test(RSSImportSettings settings);
}
public class IMDbWatchListProxy : IIMDbWatchListProxy
{
private readonly Logger _logger;
private const string URL = "http://rss.imdb.com";
public IMDbWatchListProxy(Logger logger)
{
_logger = logger;
}
public void ImportMovies(string id)
{
var client = RestClientFactory.BuildClient(URL);
var request = new RestRequest("/list/{id}", Method.GET);
request.RequestFormat = DataFormat.Xml;
request.AddParameter("id", id, ParameterType.UrlSegment);
var response = client.ExecuteAndValidate(request);
ValidateResponse(response);
}
private void Verify(string id)
{
var client = RestClientFactory.BuildClient(URL);
var request = new RestRequest("/list/{id}", Method.GET);
request.RequestFormat = DataFormat.Xml;
request.AddParameter("id", id, ParameterType.UrlSegment);
var response = client.ExecuteAndValidate(request);
ValidateResponse(response);
}
private void ValidateResponse(IRestResponse response)
{
var xDoc = XDocument.Parse(response.Content);
var nma = xDoc.Descendants("nma").Single();
var error = nma.Descendants("error").SingleOrDefault();
if (error != null)
{
((HttpStatusCode)Convert.ToInt32(error.Attribute("code").Value)).VerifyStatusCode(error.Value);
}
}
public ValidationFailure Test(RSSImportSettings settings)
{
try
{
Verify(settings.Link);
ImportMovies(settings.Link);
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to import movies: " + ex.Message);
return new ValidationFailure("IMDbWatchListId", "Unable to import movies");
}
return null;
}
}
}
@@ -20,10 +20,10 @@ namespace NzbDrone.Core.NetImport.RSSImport
return pageableRequests;
}
public NetImportPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
return new NetImportPageableRequestChain();
}
//public NetImportPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
//{
// return new NetImportPageableRequestChain();
//}
private IEnumerable<NetImportRequest> GetMovies(string searchParameters)
{
@@ -14,7 +14,6 @@ namespace NzbDrone.Core.NetImport.RSSImport
public RSSImportSettings()
{
Link = "http://rss.yoursite.com";
ProfileId = 1;
}
[FieldDefinition(0, Label = "RSS Link", HelpText = "Link to the rss feed of movies.")]