Feature/omdb api integration (#1509)

* Line endings...

* Refactoring how MetaIndexers handle fallbacks

Originally this modification was part of a much larger refactoring,
however for the sake of reviewability I split it into smaller chunks.
Sadly it is still quite large.
I wanted to split it even more, however after a certain point there was
really no value in creating smaller chunks. The biggest part of this
modification would be still huge.

So all in all, there're 3 aspects of this modification
- It modifies BaseIndexer so that it now implements IIndexer (will be
very useful later on)
- Resolving most of the warnings currently in Jackett (the only ones
remaining are related to Autofac, however if I could I would just burn
Autofac altogether rather than fix the warnings. Will open discussion on
this.)
- Biggest part: refactoring how MetaIndexers handle fallbacks and how
they provide the final result set

MetaIndexers now accept any kind of fallback and filtering mechanism
that implements the necessary interface, so that in the future IMDB
fallback and filtering won't be the only one. I know there are not a lot
of unit tests around Jackett at the moment, however this renders the
class much more unittestable as well.

* Integrate OMDB API for the fallback option

* Safeguarding when no API key is specified

* Autofac started complaining... I don't understand...

* How did that not make the previous commit?
This commit is contained in:
chibidev 2017-06-29 07:53:25 +02:00 committed by kaso17
parent 345602926e
commit 75e7ce81c2
7 changed files with 1208 additions and 1218 deletions

File diff suppressed because it is too large Load Diff

View File

@ -140,6 +140,10 @@
<span class="input-header">Enhanced logging: </span>
<input id="jackett-logging" class="form-control input-right" type="checkbox" />
</div>
<div class="input-area">
<span class="input-header">OMDB API key: </span>
<input id="jackett-omdbkey" class="form-control input-right" type="text" value="" placeholder="">
</div>
<hr />
<div id="footer">
Jackett Version <span id="app-version"></span>

View File

@ -332,7 +332,7 @@ namespace Jackett.Controllers
cfg["password"] = string.IsNullOrEmpty(serverService.Config.AdminPassword) ? string.Empty : serverService.Config.AdminPassword.Substring(0, 10);
cfg["logging"] = Startup.TracingEnabled;
cfg["basepathoverride"] = serverService.Config.BasePathOverride;
cfg["omdbkey"] = serverService.Config.OmdbApiKey;
jsonReply["config"] = cfg;
jsonReply["app_version"] = config.GetVersion();
@ -364,10 +364,12 @@ namespace Jackett.Controllers
bool preRelease = (bool)postData["prerelease"];
bool logging = (bool)postData["logging"];
string basePathOverride = (string)postData["basepathoverride"];
string omdbApiKey = (string)postData["omdbkey"];
Engine.Server.Config.UpdateDisabled = updateDisabled;
Engine.Server.Config.UpdatePrerelease = preRelease;
Engine.Server.Config.BasePathOverride = basePathOverride;
Engine.Server.Config.OmdbApiKey = omdbApiKey;
Startup.BasePath = Engine.Server.BasePath();
Engine.Server.SaveConfig();

View File

@ -18,76 +18,67 @@ namespace Jackett
{
public class JackettModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
protected override void Load (ContainerBuilder builder)
{
// Just register everything!
var thisAssembly = typeof(JackettModule).Assembly;
builder.RegisterAssemblyTypes(thisAssembly)
.Except<IIndexer>()
.Except<IImdbResolver>()
.Except<IFallbackStrategyProvider>()
.Except<ImdbFallbackStrategyProvider>()
.Except<IFallbackStrategy>()
.Except<ImdbFallbackStrategy>()
.Except<IResultFilterProvider>()
.Except<ImdbTitleResultFilterProvider>()
.Except<IResultFilter>()
.Except<ImdbTitleResultFilterProvider>()
.Except<BaseMetaIndexer>()
.Except<AggregateIndexer>()
.AsImplementedInterfaces().SingleInstance();
builder.RegisterApiControllers(thisAssembly).InstancePerRequest();
builder.RegisterType<HttpWebClient>();
var thisAssembly = typeof (JackettModule).Assembly;
builder.RegisterAssemblyTypes (thisAssembly)
.Except<IIndexer> ()
.Except<IImdbResolver> ()
.Except<OmdbResolver> ()
.Except<IFallbackStrategyProvider> ()
.Except<ImdbFallbackStrategyProvider> ()
.Except<IFallbackStrategy> ()
.Except<ImdbFallbackStrategy> ()
.Except<IResultFilterProvider> ()
.Except<ImdbTitleResultFilterProvider> ()
.Except<IResultFilter> ()
.Except<ImdbTitleResultFilterProvider> ()
.Except<BaseMetaIndexer> ()
.Except<AggregateIndexer> ()
.AsImplementedInterfaces ().SingleInstance ();
builder.RegisterApiControllers (thisAssembly).InstancePerRequest ();
builder.RegisterType<HttpWebClient> ();
// Register the best web client for the platform or the override
switch (Startup.ClientOverride)
{
case "httpclient":
builder.RegisterType<HttpWebClient>().As<IWebClient>();
break;
case "httpclient2":
builder.RegisterType<HttpWebClient2>().As<IWebClient>();
break;
case "safecurl":
builder.RegisterType<UnixSafeCurlWebClient>().As<IWebClient>();
break;
case "libcurl":
builder.RegisterType<UnixLibCurlWebClient>().As<IWebClient>();
break;
case "automatic":
default:
if (System.Environment.OSVersion.Platform == PlatformID.Unix)
{
var usehttpclient = false;
try {
Type monotype = Type.GetType("Mono.Runtime");
if (monotype != null)
{
MethodInfo displayName = monotype.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static);
if (displayName != null)
{
var monoVersion = displayName.Invoke(null, null).ToString();
var monoVersionO = new Version(monoVersion.Split(' ')[0]);
if ((monoVersionO.Major >= 4 && monoVersionO.Minor >= 8) || monoVersionO.Major >= 5)
{
// check if btls is supported
var monoSecurity = Assembly.Load("Mono.Security");
Type monoTlsProviderFactory = monoSecurity.GetType("Mono.Security.Interface.MonoTlsProviderFactory");
if (monoTlsProviderFactory != null)
{
MethodInfo isProviderSupported = monoTlsProviderFactory.GetMethod("IsProviderSupported");
if(isProviderSupported != null)
{
var btlsSupported = (bool)isProviderSupported.Invoke(null, new string[] { "btls" });
if (btlsSupported)
{
// initialize btls
MethodInfo initialize = monoTlsProviderFactory.GetMethod("Initialize", new[] { typeof(string) });
if (initialize != null)
{
initialize.Invoke(null, new string[] { "btls" });
usehttpclient = true;
}
switch (Startup.ClientOverride) {
case "httpclient":
builder.RegisterType<HttpWebClient> ().As<IWebClient> ();
break;
case "httpclient2":
builder.RegisterType<HttpWebClient2> ().As<IWebClient> ();
break;
case "safecurl":
builder.RegisterType<UnixSafeCurlWebClient> ().As<IWebClient> ();
break;
case "libcurl":
builder.RegisterType<UnixLibCurlWebClient> ().As<IWebClient> ();
break;
case "automatic":
default:
if (System.Environment.OSVersion.Platform == PlatformID.Unix) {
var usehttpclient = false;
try {
Type monotype = Type.GetType ("Mono.Runtime");
if (monotype != null) {
MethodInfo displayName = monotype.GetMethod ("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static);
if (displayName != null) {
var monoVersion = displayName.Invoke (null, null).ToString ();
var monoVersionO = new Version (monoVersion.Split (' ') [0]);
if ((monoVersionO.Major >= 4 && monoVersionO.Minor >= 8) || monoVersionO.Major >= 5) {
// check if btls is supported
var monoSecurity = Assembly.Load ("Mono.Security");
Type monoTlsProviderFactory = monoSecurity.GetType ("Mono.Security.Interface.MonoTlsProviderFactory");
if (monoTlsProviderFactory != null) {
MethodInfo isProviderSupported = monoTlsProviderFactory.GetMethod ("IsProviderSupported");
if (isProviderSupported != null) {
var btlsSupported = (bool)isProviderSupported.Invoke (null, new string [] { "btls" });
if (btlsSupported) {
// initialize btls
MethodInfo initialize = monoTlsProviderFactory.GetMethod ("Initialize", new [] { typeof (string) });
if (initialize != null) {
initialize.Invoke (null, new string [] { "btls" });
usehttpclient = true;
}
}
}
@ -95,56 +86,45 @@ namespace Jackett
}
}
}
catch (Exception e)
{
Console.Out.WriteLine("Error while deciding which HttpWebClient to use: " + e);
}
} catch (Exception e) {
Console.Out.WriteLine ("Error while deciding which HttpWebClient to use: " + e);
}
if (usehttpclient)
builder.RegisterType<HttpWebClient>().As<IWebClient>();
else
builder.RegisterType<UnixLibCurlWebClient>().As<IWebClient>();
}
if (usehttpclient)
builder.RegisterType<HttpWebClient> ().As<IWebClient> ();
else
{
builder.RegisterType<HttpWebClient>().As<IWebClient>();
}
break;
builder.RegisterType<UnixLibCurlWebClient> ().As<IWebClient> ();
} else {
builder.RegisterType<HttpWebClient> ().As<IWebClient> ();
}
break;
}
// Register indexers
var indexerTypes = thisAssembly.GetTypes().Where(p => typeof (IIndexer).IsAssignableFrom (p) && !p.IsInterface && !p.IsInNamespace("Jackett.Indexers.Meta"));
foreach (var indexer in indexerTypes)
{
builder.RegisterType(indexer).Named<IIndexer>(BaseIndexer.GetIndexerID(indexer));
var indexerTypes = thisAssembly.GetTypes ().Where (p => typeof (IIndexer).IsAssignableFrom (p) && !p.IsInterface && !p.IsInNamespace ("Jackett.Indexers.Meta"));
foreach (var indexer in indexerTypes) {
builder.RegisterType (indexer).Named<IIndexer> (BaseIndexer.GetIndexerID (indexer));
}
Mapper.CreateMap<WebClientByteResult, WebClientStringResult>().ForMember(x => x.Content, opt => opt.Ignore()).AfterMap((be, str) =>
{
str.Content = Encoding.UTF8.GetString(be.Content);
Mapper.CreateMap<WebClientByteResult, WebClientStringResult> ().ForMember (x => x.Content, opt => opt.Ignore ()).AfterMap ((be, str) => {
str.Content = Encoding.UTF8.GetString (be.Content);
});
Mapper.CreateMap<WebClientStringResult, WebClientByteResult>().ForMember(x => x.Content, opt => opt.Ignore()).AfterMap((str, be) =>
{
if (!string.IsNullOrEmpty(str.Content))
{
be.Content = Encoding.UTF8.GetBytes(str.Content);
Mapper.CreateMap<WebClientStringResult, WebClientByteResult> ().ForMember (x => x.Content, opt => opt.Ignore ()).AfterMap ((str, be) => {
if (!string.IsNullOrEmpty (str.Content)) {
be.Content = Encoding.UTF8.GetBytes (str.Content);
}
});
Mapper.CreateMap<WebClientStringResult, WebClientStringResult>();
Mapper.CreateMap<WebClientByteResult, WebClientByteResult>();
Mapper.CreateMap<ReleaseInfo, ReleaseInfo>();
Mapper.CreateMap<WebClientStringResult, WebClientStringResult> ();
Mapper.CreateMap<WebClientByteResult, WebClientByteResult> ();
Mapper.CreateMap<ReleaseInfo, ReleaseInfo> ();
Mapper.CreateMap<ReleaseInfo, TrackerCacheResult>().AfterMap((r, t) =>
{
if (r.Category != null)
{
var CategoryDesc = string.Join(", ", r.Category.Select(x => TorznabCatType.GetCatDesc(x)).Where(x => !string.IsNullOrEmpty(x)));
Mapper.CreateMap<ReleaseInfo, TrackerCacheResult> ().AfterMap ((r, t) => {
if (r.Category != null) {
var CategoryDesc = string.Join (", ", r.Category.Select (x => TorznabCatType.GetCatDesc (x)).Where (x => !string.IsNullOrEmpty (x)));
t.CategoryDesc = CategoryDesc;
}
else
{
} else {
t.CategoryDesc = "";
}
});

View File

@ -24,6 +24,7 @@ namespace Jackett.Models.Config
public bool UpdateDisabled { get; set; }
public bool UpdatePrerelease { get; set; }
public string BasePathOverride { get; set; }
public string OmdbApiKey { get; set; }
public string[] GetListenAddresses(bool? external = null)
{

View File

@ -4,6 +4,8 @@ using System.Threading.Tasks;
using System.Web;
using CsQuery;
using Jackett.Utils.Clients;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Jackett.Services
{
@ -12,36 +14,34 @@ namespace Jackett.Services
Task<IEnumerable<string>> GetAllTitles(string imdbId);
}
public class ImdbResolver : IImdbResolver
public struct Movie
{
public ImdbResolver(IWebClient webClient)
public string Title;
}
public class OmdbResolver : IImdbResolver
{
public OmdbResolver(IWebClient webClient, string omdbApiKey)
{
WebClient = webClient;
apiKey = omdbApiKey;
}
public async Task<IEnumerable<string>> GetAllTitles(string imdbId)
{
if (apiKey == null)
return new string[] { };
if (!imdbId.StartsWith("tt", StringComparison.Ordinal))
imdbId = "tt" + imdbId;
var request = new WebRequest("http://www.imdb.com/title/" + imdbId + "/releaseinfo");
var request = new WebRequest("http://omdbapi.com/?apikey=" + apiKey + "&i=" + imdbId);
var result = await WebClient.GetString(request);
var movie = JsonConvert.DeserializeObject<Movie>(result.Content);
CQ dom = result.Content;
var mainTitle = dom["h3[itemprop=name]"].Find("a")[0].InnerHTML.Replace("\"", "");
var akas = dom["table#akas"].Find("tbody").Find("tr");
var titleList = new List<string>();
titleList.Add(mainTitle);
foreach (var row in akas) {
string title = row.FirstElementChild.InnerHTML;
if (title == "(original title)" || title == "")
titleList.Add(HttpUtility.HtmlDecode(row.FirstElementChild.NextElementSibling.InnerHTML));
}
return titleList;
return new string[] { movie.Title };
}
private IWebClient WebClient;
private string apiKey;
}
}

View File

@ -131,7 +131,7 @@ namespace Jackett.Services
public void InitAggregateIndexer()
{
var imdbResolver = new ImdbResolver(container.Resolve<IWebClient>());
var imdbResolver = new OmdbResolver(container.Resolve<IWebClient>(), container.Resolve<IServerService>().Config.OmdbApiKey);
var imdbFallbackStrategyProvider = new ImdbFallbackStrategyProvider(imdbResolver);
var imdbTitleResultFilterProvider = new ImdbTitleResultFilterProvider(imdbResolver);