diff --git a/Build.bat b/Build.bat new file mode 100644 index 000000000..8ee0b9dc0 --- /dev/null +++ b/Build.bat @@ -0,0 +1,15 @@ + +rmdir /s /q build +cd src +Msbuild Jackett.sln /t:Clean,Build /p:Configuration=Release +cd .. + +xcopy src\Jackett.Console\bin\Release Build\ /e /y +copy /Y src\Jackett.Service\bin\Release\JackettService.exe build\JackettService.exe +copy /Y src\Jackett.Service\bin\Release\JackettService.exe.config build\JackettService.exe.config +copy /Y src\Jackett.Tray\bin\Release\JackettTray.exe build\JackettTray.exe +copy /Y src\Jackett.Tray\bin\Release\JackettTray.exe.config build\JackettTray.exe.config +cd build +del *.pdb +del *.xml +cd .. diff --git a/Installer.iss b/Installer.iss new file mode 100644 index 000000000..9c6361bc4 --- /dev/null +++ b/Installer.iss @@ -0,0 +1,58 @@ +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +#define MyAppName "Jackett" +#define MyAppVersion "0.5" +#define MyAppPublisher "Jackett Inc." +#define MyAppURL "https://github.com/zone117x/Jackett" +#define MyAppExeName "JackettTray.exe" + +[Setup] +; NOTE: The value of AppId uniquely identifies this application. +; Do not use the same AppId value in installers for other applications. +; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) +AppId={{C2A9FC00-AA48-4F17-9A72-62FBCEE2785B} +AppName={#MyAppName} +AppVersion={#MyAppVersion} +;AppVerName={#MyAppName} {#MyAppVersion} +AppPublisher={#MyAppPublisher} +AppPublisherURL={#MyAppURL} +AppSupportURL={#MyAppURL} +AppUpdatesURL={#MyAppURL} +DefaultDirName={pf}\{#MyAppName} +DefaultGroupName={#MyAppName} +DisableProgramGroupPage=yes +OutputBaseFilename=setup +SetupIconFile=O:\Documents\JackettKayo\src\Jackett.Console\jackett.ico +Compression=lzma +SolidCompression=yes + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Tasks] +Name: "windowsService"; Description: "Install as a Windows Service" +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked + +[Files] +Source: "O:\Documents\JackettKayo\Build\JackettTray.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "O:\Documents\JackettKayo\Build\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Icons] +Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" +Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}" +Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon + +[Run] +Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent + +[Run] +Filename: "{app}\JackettConsole.exe"; Parameters: "/u"; Flags: waituntilterminated; +Filename: "{app}\JackettConsole.exe"; Parameters: "/r"; Flags: waituntilterminated; +Filename: "{app}\JackettConsole.exe"; Parameters: "/i"; Flags: waituntilterminated; Tasks: windowsService + +[UninstallRun] +Filename: "{app}\JackettConsole.exe"; Parameters: "/u"; Flags: waituntilterminated skipifdoesntexist + + diff --git a/src/Jackett.Console/App.config b/src/Jackett.Console/App.config new file mode 100644 index 000000000..da396d090 --- /dev/null +++ b/src/Jackett.Console/App.config @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Jackett.Console/Jackett.Console.csproj b/src/Jackett.Console/Jackett.Console.csproj new file mode 100644 index 000000000..918f669ff --- /dev/null +++ b/src/Jackett.Console/Jackett.Console.csproj @@ -0,0 +1,134 @@ + + + + + Debug + AnyCPU + {4E2A81DA-E235-4A88-AD20-38AABBFBF33C} + Exe + Properties + Jackett.Console + JackettConsole + v4.5.2 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + jackett.ico + + + JackettConsole.Program + + + + False + ..\packages\Autofac.3.5.0\lib\net40\Autofac.dll + + + ..\packages\Autofac.Owin.3.1.0\lib\net45\Autofac.Integration.Owin.dll + + + False + ..\packages\Autofac.WebApi2.3.4.0\lib\net45\Autofac.Integration.WebApi.dll + + + ..\packages\Autofac.WebApi2.Owin.3.2.0\lib\net45\Autofac.Integration.WebApi.Owin.dll + + + ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll + True + + + ..\packages\Microsoft.Owin.FileSystems.3.0.1\lib\net45\Microsoft.Owin.FileSystems.dll + True + + + ..\packages\Microsoft.Owin.Host.HttpListener.2.0.2\lib\net45\Microsoft.Owin.Host.HttpListener.dll + True + + + ..\packages\Microsoft.Owin.Hosting.2.0.2\lib\net45\Microsoft.Owin.Hosting.dll + True + + + ..\packages\Microsoft.Owin.StaticFiles.3.0.1\lib\net45\Microsoft.Owin.StaticFiles.dll + True + + + ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + True + + + False + ..\packages\NLog.4.0.1\lib\net45\NLog.dll + + + ..\packages\Owin.1.0\lib\net40\Owin.dll + True + + + + + ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll + True + + + ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll + True + + + ..\packages\Microsoft.AspNet.WebApi.Owin.5.2.3\lib\net45\System.Web.Http.Owin.dll + True + + + + + + + + + + + + + + + + + + + {e636d5f8-68b4-4903-b4ed-ccfd9c9e899f} + Jackett + + + + + + + + \ No newline at end of file diff --git a/src/Jackett.Console/Program.cs b/src/Jackett.Console/Program.cs new file mode 100644 index 000000000..99a610f7c --- /dev/null +++ b/src/Jackett.Console/Program.cs @@ -0,0 +1,50 @@ +using Jackett; +using Jackett.Indexers; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; + +namespace JackettConsole +{ + public class Program + { + static void Main(string[] args) + { + try + { + if (args.Length > 0) + { + switch (args[0].ToLowerInvariant()) + { + case "/i": + Engine.ServiceConfig.Install(); + return; + case "/r": + Engine.Server.ReserveUrls(); + return; + case "/u": + Engine.Server.ReserveUrls(false); + Engine.ServiceConfig.Uninstall(); + return; + } + } + + Engine.Server.Start(); + Engine.Logger.Info("Running in headless mode."); + Engine.RunTime.Spin(); + Engine.Logger.Info("Server thread exit"); + } + catch(Exception e) + { + Engine.Logger.Error(e, "Top level exception"); + } + } + } +} + diff --git a/src/Jackett.Console/Properties/AssemblyInfo.cs b/src/Jackett.Console/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..0c11610e1 --- /dev/null +++ b/src/Jackett.Console/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Jackett.Console")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Jackett.Console")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4e2a81da-e235-4a88-ad20-38aabbfbf33c")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Jackett/WebContent/favicon.ico b/src/Jackett.Console/jackett.ico similarity index 100% rename from src/Jackett/WebContent/favicon.ico rename to src/Jackett.Console/jackett.ico diff --git a/src/Jackett.Console/packages.config b/src/Jackett.Console/packages.config new file mode 100644 index 000000000..90c9bc1e4 --- /dev/null +++ b/src/Jackett.Console/packages.config @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Jackett.Service/App.config b/src/Jackett.Service/App.config new file mode 100644 index 000000000..e74e545f8 --- /dev/null +++ b/src/Jackett.Service/App.config @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Jackett.Service/Jackett.Service.csproj b/src/Jackett.Service/Jackett.Service.csproj new file mode 100644 index 000000000..b9614e42a --- /dev/null +++ b/src/Jackett.Service/Jackett.Service.csproj @@ -0,0 +1,137 @@ + + + + + Debug + AnyCPU + {BF611F7B-4658-4CB8-AA9E-0736FADAA3BA} + WinExe + Properties + Jackett.Service + JackettService + v4.5.2 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + jackett.ico + + + + False + ..\packages\Autofac.3.5.0\lib\net40\Autofac.dll + + + ..\packages\Autofac.Owin.3.1.0\lib\net45\Autofac.Integration.Owin.dll + + + False + ..\packages\Autofac.WebApi2.3.4.0\lib\net45\Autofac.Integration.WebApi.dll + + + ..\packages\Autofac.WebApi2.Owin.3.2.0\lib\net45\Autofac.Integration.WebApi.Owin.dll + + + False + ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll + + + False + ..\packages\Microsoft.Owin.FileSystems.3.0.1\lib\net45\Microsoft.Owin.FileSystems.dll + + + ..\packages\Microsoft.Owin.Host.HttpListener.3.0.1\lib\net45\Microsoft.Owin.Host.HttpListener.dll + + + False + ..\packages\Microsoft.Owin.Hosting.2.0.2\lib\net45\Microsoft.Owin.Hosting.dll + + + False + ..\packages\Microsoft.Owin.StaticFiles.3.0.1\lib\net45\Microsoft.Owin.StaticFiles.dll + + + False + ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + + + False + ..\packages\NLog.4.0.1\lib\net45\NLog.dll + + + False + ..\packages\Owin.1.0\lib\net40\Owin.dll + + + + + False + ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll + + + False + ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll + + + False + ..\packages\Microsoft.AspNet.WebApi.Owin.5.2.3\lib\net45\System.Web.Http.Owin.dll + + + + + + + + + + + + Component + + + Service.cs + + + + + + + + + + + + + + {e636d5f8-68b4-4903-b4ed-ccfd9c9e899f} + Jackett + + + + + \ No newline at end of file diff --git a/src/Jackett.Service/Program.cs b/src/Jackett.Service/Program.cs new file mode 100644 index 000000000..22c25af4b --- /dev/null +++ b/src/Jackett.Service/Program.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.ServiceProcess; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Service +{ + static class Program + { + /// + /// The main entry point for the application. + /// + static void Main() + { + ServiceBase[] ServicesToRun; + ServicesToRun = new ServiceBase[] + { + new Service() + }; + ServiceBase.Run(ServicesToRun); + } + } +} diff --git a/src/Jackett.Service/Properties/AssemblyInfo.cs b/src/Jackett.Service/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..246a632ba --- /dev/null +++ b/src/Jackett.Service/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Jackett.Service")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Jackett.Service")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("bf611f7b-4658-4cb8-aa9e-0736fadaa3ba")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Jackett.Service/Service.Designer.cs b/src/Jackett.Service/Service.Designer.cs new file mode 100644 index 000000000..0e2f0f42d --- /dev/null +++ b/src/Jackett.Service/Service.Designer.cs @@ -0,0 +1,37 @@ +namespace Jackett.Service +{ + partial class Service + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + this.ServiceName = "Jackett"; + } + + #endregion + } +} diff --git a/src/Jackett.Service/Service.cs b/src/Jackett.Service/Service.cs new file mode 100644 index 000000000..47690ab21 --- /dev/null +++ b/src/Jackett.Service/Service.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Diagnostics; +using System.Linq; +using System.ServiceProcess; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Service +{ + public partial class Service : ServiceBase + { + public Service() + { + InitializeComponent(); + } + + protected override void OnStart(string[] args) + { + Engine.Logger.Info("Service starting"); + Engine.Server.Start(); + Engine.Logger.Info("Service started"); + } + + protected override void OnStop() + { + Engine.Logger.Info("Service stopping"); + Engine.Server.Stop(); + } + } +} diff --git a/src/Jackett/jacket_large.ico b/src/Jackett.Service/jackett.ico similarity index 100% rename from src/Jackett/jacket_large.ico rename to src/Jackett.Service/jackett.ico diff --git a/src/Jackett.Service/packages.config b/src/Jackett.Service/packages.config new file mode 100644 index 000000000..c44eef52e --- /dev/null +++ b/src/Jackett.Service/packages.config @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Jackett.Tray/App.config b/src/Jackett.Tray/App.config new file mode 100644 index 000000000..88fa4027b --- /dev/null +++ b/src/Jackett.Tray/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/Jackett.Tray/Jackett.Tray.csproj b/src/Jackett.Tray/Jackett.Tray.csproj new file mode 100644 index 000000000..0e3f38375 --- /dev/null +++ b/src/Jackett.Tray/Jackett.Tray.csproj @@ -0,0 +1,96 @@ + + + + + Debug + AnyCPU + {FF9025B1-EC14-4AA9-8081-9F69C5E35B63} + WinExe + Properties + Jackett.Tray + JackettTray + v4.5.2 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + jackett.ico + + + + + + + + + + + + + + + + + Form + + + Main.cs + + + + + Main.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + + + + \ No newline at end of file diff --git a/src/Jackett/Main.Designer.cs b/src/Jackett.Tray/Main.Designer.cs similarity index 98% rename from src/Jackett/Main.Designer.cs rename to src/Jackett.Tray/Main.Designer.cs index d881a2821..71457c20d 100644 --- a/src/Jackett/Main.Designer.cs +++ b/src/Jackett.Tray/Main.Designer.cs @@ -1,6 +1,4 @@ -#if !__MonoCS__ - -namespace Jackett +namespace JackettTray { partial class Main { @@ -99,5 +97,4 @@ namespace Jackett private System.Windows.Forms.ToolStripMenuItem toolStripMenuItemShutdown; } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/Jackett/Main.cs b/src/Jackett.Tray/Main.cs similarity index 89% rename from src/Jackett/Main.cs rename to src/Jackett.Tray/Main.cs index 250aff2ce..a1a51b09f 100644 --- a/src/Jackett/Main.cs +++ b/src/Jackett.Tray/Main.cs @@ -13,7 +13,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; -namespace Jackett +namespace JackettTray { public partial class Main : Form { @@ -28,13 +28,13 @@ namespace Jackett toolStripMenuItemWebUI.Click += toolStripMenuItemWebUI_Click; toolStripMenuItemShutdown.Click += toolStripMenuItemShutdown_Click; - if (Program.IsFirstRun) - AutoStart = true; + //if (Server.IsFirstRun) + // AutoStart = true; } void toolStripMenuItemWebUI_Click(object sender, EventArgs e) { - Process.Start("http://127.0.0.1:" + Server.Port); + // Process.Start("http://127.0.0.1:" + Server.Port); } void toolStripMenuItemShutdown_Click(object sender, EventArgs e) @@ -84,12 +84,12 @@ namespace Jackett private void CreateShortcut() { - var appPath = Assembly.GetExecutingAssembly().Location; + /* var appPath = Assembly.GetExecutingAssembly().Location; var shell = new IWshRuntimeLibrary.WshShell(); var shortcut = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(ShortcutPath); shortcut.Description = Assembly.GetExecutingAssembly().GetName().Name; shortcut.TargetPath = appPath; - shortcut.Save(); + shortcut.Save();*/ } } } diff --git a/src/Jackett/Main.resx b/src/Jackett.Tray/Main.resx similarity index 100% rename from src/Jackett/Main.resx rename to src/Jackett.Tray/Main.resx diff --git a/src/Jackett.Tray/Program.cs b/src/Jackett.Tray/Program.cs new file mode 100644 index 000000000..b902536cd --- /dev/null +++ b/src/Jackett.Tray/Program.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace JackettTray +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Main()); + } + } +} diff --git a/src/Jackett.Tray/Properties/AssemblyInfo.cs b/src/Jackett.Tray/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..0f6590c99 --- /dev/null +++ b/src/Jackett.Tray/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Jackett.Tray")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Jackett.Tray")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ff9025b1-ec14-4aa9-8081-9f69c5e35b63")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Jackett.Tray/Properties/Resources.Designer.cs b/src/Jackett.Tray/Properties/Resources.Designer.cs new file mode 100644 index 000000000..b6ce33f0b --- /dev/null +++ b/src/Jackett.Tray/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Jackett.Tray.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Jackett.Tray.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/src/Jackett.Tray/Properties/Resources.resx b/src/Jackett.Tray/Properties/Resources.resx new file mode 100644 index 000000000..af7dbebba --- /dev/null +++ b/src/Jackett.Tray/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Jackett.Tray/Properties/Settings.Designer.cs b/src/Jackett.Tray/Properties/Settings.Designer.cs new file mode 100644 index 000000000..c110e9e5e --- /dev/null +++ b/src/Jackett.Tray/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Jackett.Tray.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/src/Jackett.Tray/Properties/Settings.settings b/src/Jackett.Tray/Properties/Settings.settings new file mode 100644 index 000000000..39645652a --- /dev/null +++ b/src/Jackett.Tray/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/Jackett.Tray/jackett.ico b/src/Jackett.Tray/jackett.ico new file mode 100644 index 000000000..6392acc61 Binary files /dev/null and b/src/Jackett.Tray/jackett.ico differ diff --git a/src/Jackett.sln b/src/Jackett.sln index a7c6e3384..7e7f1ea9b 100644 --- a/src/Jackett.sln +++ b/src/Jackett.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 +# Visual Studio 14 +VisualStudioVersion = 14.0.22823.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jackett", "Jackett\Jackett.csproj", "{E636D5F8-68B4-4903-B4ED-CCFD9C9E899F}" EndProject @@ -13,6 +13,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ..\README.md = ..\README.md EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jackett.Console", "Jackett.Console\Jackett.Console.csproj", "{4E2A81DA-E235-4A88-AD20-38AABBFBF33C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jackett.Service", "Jackett.Service\Jackett.Service.csproj", "{BF611F7B-4658-4CB8-AA9E-0736FADAA3BA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jackett.Tray", "Jackett.Tray\Jackett.Tray.csproj", "{FF9025B1-EC14-4AA9-8081-9F69C5E35B63}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,6 +33,18 @@ Global {74420A79-CC16-442C-8B1E-7C1B913844F0}.Debug|Any CPU.Build.0 = Debug|Any CPU {74420A79-CC16-442C-8B1E-7C1B913844F0}.Release|Any CPU.ActiveCfg = Release|Any CPU {74420A79-CC16-442C-8B1E-7C1B913844F0}.Release|Any CPU.Build.0 = Release|Any CPU + {4E2A81DA-E235-4A88-AD20-38AABBFBF33C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4E2A81DA-E235-4A88-AD20-38AABBFBF33C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4E2A81DA-E235-4A88-AD20-38AABBFBF33C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4E2A81DA-E235-4A88-AD20-38AABBFBF33C}.Release|Any CPU.Build.0 = Release|Any CPU + {BF611F7B-4658-4CB8-AA9E-0736FADAA3BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BF611F7B-4658-4CB8-AA9E-0736FADAA3BA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BF611F7B-4658-4CB8-AA9E-0736FADAA3BA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BF611F7B-4658-4CB8-AA9E-0736FADAA3BA}.Release|Any CPU.Build.0 = Release|Any CPU + {FF9025B1-EC14-4AA9-8081-9F69C5E35B63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF9025B1-EC14-4AA9-8081-9F69C5E35B63}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF9025B1-EC14-4AA9-8081-9F69C5E35B63}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF9025B1-EC14-4AA9-8081-9F69C5E35B63}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Jackett/ApiKey.cs b/src/Jackett/ApiKey.cs deleted file mode 100644 index 86848899a..000000000 --- a/src/Jackett/ApiKey.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett -{ - public class ApiKey - { - - public static string CurrentKey; - - const string chars = "abcdefghijklmnopqrstuvwxyz0123456789"; - - public static string Generate() - { - var randBytes = new byte[32]; - var rngCsp = new RNGCryptoServiceProvider(); - rngCsp.GetBytes(randBytes); - var key = ""; - foreach (var b in randBytes) - { - key += chars[b % chars.Length]; - } - return key; - - } - } -} diff --git a/src/Jackett/App.config b/src/Jackett/App.config index 56ebf3f29..547fa70d5 100644 --- a/src/Jackett/App.config +++ b/src/Jackett/App.config @@ -9,7 +9,27 @@ - + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Jackett/WebContent/animate.css b/src/Jackett/Content/animate.css similarity index 100% rename from src/Jackett/WebContent/animate.css rename to src/Jackett/Content/animate.css diff --git a/src/Jackett/WebContent/binding_dark.png b/src/Jackett/Content/binding_dark.png similarity index 100% rename from src/Jackett/WebContent/binding_dark.png rename to src/Jackett/Content/binding_dark.png diff --git a/src/Jackett/WebContent/bootstrap-notify.js b/src/Jackett/Content/bootstrap-notify.js similarity index 100% rename from src/Jackett/WebContent/bootstrap-notify.js rename to src/Jackett/Content/bootstrap-notify.js diff --git a/src/Jackett/WebContent/bootstrap/bootstrap.min.css b/src/Jackett/Content/bootstrap/bootstrap.min.css similarity index 100% rename from src/Jackett/WebContent/bootstrap/bootstrap.min.css rename to src/Jackett/Content/bootstrap/bootstrap.min.css diff --git a/src/Jackett/WebContent/bootstrap/bootstrap.min.js b/src/Jackett/Content/bootstrap/bootstrap.min.js similarity index 100% rename from src/Jackett/WebContent/bootstrap/bootstrap.min.js rename to src/Jackett/Content/bootstrap/bootstrap.min.js diff --git a/src/Jackett/WebContent/common.js b/src/Jackett/Content/common.js similarity index 100% rename from src/Jackett/WebContent/common.js rename to src/Jackett/Content/common.js diff --git a/src/Jackett/WebContent/congruent_outline.png b/src/Jackett/Content/congruent_outline.png similarity index 100% rename from src/Jackett/WebContent/congruent_outline.png rename to src/Jackett/Content/congruent_outline.png diff --git a/src/Jackett/WebContent/crissXcross.png b/src/Jackett/Content/crissXcross.png similarity index 100% rename from src/Jackett/WebContent/crissXcross.png rename to src/Jackett/Content/crissXcross.png diff --git a/src/Jackett/WebContent/custom.css b/src/Jackett/Content/custom.css similarity index 100% rename from src/Jackett/WebContent/custom.css rename to src/Jackett/Content/custom.css diff --git a/src/Jackett/WebContent/custom.js b/src/Jackett/Content/custom.js similarity index 91% rename from src/Jackett/WebContent/custom.js rename to src/Jackett/Content/custom.js index c79c6fa97..7ecf926b6 100644 --- a/src/Jackett/WebContent/custom.js +++ b/src/Jackett/Content/custom.js @@ -13,14 +13,14 @@ $("#change-jackett-port").click(function () { var jackett_port = $("#jackett-port").val(); var jsonObject = JSON.parse('{"port":"' + jackett_port + '"}'); - var jqxhr = $.post("apply_jackett_config", JSON.stringify(jsonObject), function (data) { + var jqxhr = $.post("admin/apply_jackett_config", JSON.stringify(jsonObject), function (data) { if (data.result == "error") { doNotify("Error: " + data.error, "danger", "glyphicon glyphicon-alert"); return; } else { doNotify("The port has been changed. Jackett will now restart...", "success", "glyphicon glyphicon-ok"); - var jqxhr0 = $.post("jackett_restart", null, function (data_restart) { }); + var jqxhr0 = $.post("admin/jackett_restart", null, function (data_restart) { }); window.setTimeout(function () { url = window.location.href; @@ -35,7 +35,7 @@ $("#change-jackett-port").click(function () { }); function getJackettConfig(callback) { - var jqxhr = $.get("get_jackett_config", function (data) { + var jqxhr = $.get("admin/get_jackett_config", function (data) { callback(data); }).fail(function () { @@ -47,7 +47,7 @@ function reloadIndexers() { $('#indexers').hide(); $('#indexers > .indexer').remove(); $('#unconfigured-indexers').empty(); - var jqxhr = $.get("get_indexers", function (data) { + var jqxhr = $.get("admin/get_indexers", function (data) { $("#api-key-input").val(data.api_key); $("#app-version").html(data.app_version); displayIndexers(data.items); @@ -82,7 +82,7 @@ function prepareDeleteButtons() { var $btn = $(btn); var id = $btn.data("id"); $btn.click(function () { - var jqxhr = $.post("delete_indexer", JSON.stringify({ indexer: id }), function (data) { + var jqxhr = $.post("admin/delete_indexer", JSON.stringify({ indexer: id }), function (data) { if (data.result == "error") { doNotify("Delete error for " + id + "\n" + data.error, "danger", "glyphicon glyphicon-alert"); } @@ -114,7 +114,7 @@ function prepareTestButtons() { var id = $btn.data("id"); $btn.click(function () { doNotify("Test started for " + id, "info", "glyphicon glyphicon-transfer"); - var jqxhr = $.post("test_indexer", JSON.stringify({ indexer: id }), function (data) { + var jqxhr = $.post("admin/test_indexer", JSON.stringify({ indexer: id }), function (data) { if (data.result == "error") { doNotify("Test failed for " + data.name + "\n" + data.error, "danger", "glyphicon glyphicon-alert"); } @@ -130,7 +130,7 @@ function prepareTestButtons() { function displayIndexerSetup(id) { - var jqxhr = $.post("get_config_form", JSON.stringify({ indexer: id }), function (data) { + var jqxhr = $.post("admin/get_config_form", JSON.stringify({ indexer: id }), function (data) { if (data.result == "error") { doNotify("Error: " + data.error, "danger", "glyphicon glyphicon-alert"); return; @@ -200,7 +200,7 @@ function populateSetupForm(indexerId, name, config) { $goButton.prop('disabled', true); $goButton.html($('#templates > .spinner')[0].outerHTML); - var jqxhr = $.post("configure_indexer", JSON.stringify(data), function (data) { + var jqxhr = $.post("admin/configure_indexer", JSON.stringify(data), function (data) { if (data.result == "error") { if (data.config) { populateConfigItems(configForm, data.config); diff --git a/src/Jackett/Content/favicon.ico b/src/Jackett/Content/favicon.ico new file mode 100644 index 000000000..6392acc61 Binary files /dev/null and b/src/Jackett/Content/favicon.ico differ diff --git a/src/Jackett/WebContent/fonts/glyphicons-halflings-regular.woff b/src/Jackett/Content/fonts/glyphicons-halflings-regular.woff similarity index 100% rename from src/Jackett/WebContent/fonts/glyphicons-halflings-regular.woff rename to src/Jackett/Content/fonts/glyphicons-halflings-regular.woff diff --git a/src/Jackett/WebContent/handlebars-v3.0.1.js b/src/Jackett/Content/handlebars-v3.0.1.js similarity index 100% rename from src/Jackett/WebContent/handlebars-v3.0.1.js rename to src/Jackett/Content/handlebars-v3.0.1.js diff --git a/src/Jackett/WebContent/index.html b/src/Jackett/Content/index.html similarity index 100% rename from src/Jackett/WebContent/index.html rename to src/Jackett/Content/index.html diff --git a/src/Jackett/WebContent/jacket_medium.png b/src/Jackett/Content/jacket_medium.png similarity index 100% rename from src/Jackett/WebContent/jacket_medium.png rename to src/Jackett/Content/jacket_medium.png diff --git a/src/Jackett/WebContent/jquery-2.1.3.min.js b/src/Jackett/Content/jquery-2.1.3.min.js similarity index 100% rename from src/Jackett/WebContent/jquery-2.1.3.min.js rename to src/Jackett/Content/jquery-2.1.3.min.js diff --git a/src/Jackett/WebContent/logos/alpharatio.png b/src/Jackett/Content/logos/alpharatio.png similarity index 100% rename from src/Jackett/WebContent/logos/alpharatio.png rename to src/Jackett/Content/logos/alpharatio.png diff --git a/src/Jackett/WebContent/logos/animebytes.png b/src/Jackett/Content/logos/animebytes.png similarity index 100% rename from src/Jackett/WebContent/logos/animebytes.png rename to src/Jackett/Content/logos/animebytes.png diff --git a/src/Jackett/WebContent/logos/beyondhd.png b/src/Jackett/Content/logos/beyondhd.png similarity index 100% rename from src/Jackett/WebContent/logos/beyondhd.png rename to src/Jackett/Content/logos/beyondhd.png diff --git a/src/Jackett/WebContent/logos/bithdtv.png b/src/Jackett/Content/logos/bithdtv.png similarity index 100% rename from src/Jackett/WebContent/logos/bithdtv.png rename to src/Jackett/Content/logos/bithdtv.png diff --git a/src/Jackett/WebContent/logos/bitmetv.png b/src/Jackett/Content/logos/bitmetv.png similarity index 100% rename from src/Jackett/WebContent/logos/bitmetv.png rename to src/Jackett/Content/logos/bitmetv.png diff --git a/src/Jackett/WebContent/logos/frenchtorrentdb.png b/src/Jackett/Content/logos/frenchtorrentdb.png similarity index 100% rename from src/Jackett/WebContent/logos/frenchtorrentdb.png rename to src/Jackett/Content/logos/frenchtorrentdb.png diff --git a/src/Jackett/WebContent/logos/freshon.png b/src/Jackett/Content/logos/freshon.png similarity index 100% rename from src/Jackett/WebContent/logos/freshon.png rename to src/Jackett/Content/logos/freshon.png diff --git a/src/Jackett/WebContent/logos/hdtorrents.png b/src/Jackett/Content/logos/hdtorrents.png similarity index 100% rename from src/Jackett/WebContent/logos/hdtorrents.png rename to src/Jackett/Content/logos/hdtorrents.png diff --git a/src/Jackett/WebContent/logos/iptorrents.png b/src/Jackett/Content/logos/iptorrents.png similarity index 100% rename from src/Jackett/WebContent/logos/iptorrents.png rename to src/Jackett/Content/logos/iptorrents.png diff --git a/src/Jackett/WebContent/logos/morethantv.png b/src/Jackett/Content/logos/morethantv.png similarity index 100% rename from src/Jackett/WebContent/logos/morethantv.png rename to src/Jackett/Content/logos/morethantv.png diff --git a/src/Jackett/WebContent/logos/rarbg.png b/src/Jackett/Content/logos/rarbg.png similarity index 100% rename from src/Jackett/WebContent/logos/rarbg.png rename to src/Jackett/Content/logos/rarbg.png diff --git a/src/Jackett/WebContent/logos/sceneaccess.png b/src/Jackett/Content/logos/sceneaccess.png similarity index 100% rename from src/Jackett/WebContent/logos/sceneaccess.png rename to src/Jackett/Content/logos/sceneaccess.png diff --git a/src/Jackett/WebContent/logos/scenetime.png b/src/Jackett/Content/logos/scenetime.png similarity index 100% rename from src/Jackett/WebContent/logos/scenetime.png rename to src/Jackett/Content/logos/scenetime.png diff --git a/src/Jackett/WebContent/logos/showrss.png b/src/Jackett/Content/logos/showrss.png similarity index 100% rename from src/Jackett/WebContent/logos/showrss.png rename to src/Jackett/Content/logos/showrss.png diff --git a/src/Jackett/WebContent/logos/strike.png b/src/Jackett/Content/logos/strike.png similarity index 100% rename from src/Jackett/WebContent/logos/strike.png rename to src/Jackett/Content/logos/strike.png diff --git a/src/Jackett/WebContent/logos/t411.png b/src/Jackett/Content/logos/t411.png similarity index 100% rename from src/Jackett/WebContent/logos/t411.png rename to src/Jackett/Content/logos/t411.png diff --git a/src/Jackett/WebContent/logos/thepiratebay.png b/src/Jackett/Content/logos/thepiratebay.png similarity index 100% rename from src/Jackett/WebContent/logos/thepiratebay.png rename to src/Jackett/Content/logos/thepiratebay.png diff --git a/src/Jackett/WebContent/logos/torrentday.png b/src/Jackett/Content/logos/torrentday.png similarity index 100% rename from src/Jackett/WebContent/logos/torrentday.png rename to src/Jackett/Content/logos/torrentday.png diff --git a/src/Jackett/WebContent/logos/torrentleech.png b/src/Jackett/Content/logos/torrentleech.png similarity index 100% rename from src/Jackett/WebContent/logos/torrentleech.png rename to src/Jackett/Content/logos/torrentleech.png diff --git a/src/Jackett/WebContent/logos/torrentshack.png b/src/Jackett/Content/logos/torrentshack.png similarity index 100% rename from src/Jackett/WebContent/logos/torrentshack.png rename to src/Jackett/Content/logos/torrentshack.png diff --git a/src/Jackett/WebContent/logos/torrentz.png b/src/Jackett/Content/logos/torrentz.png similarity index 100% rename from src/Jackett/WebContent/logos/torrentz.png rename to src/Jackett/Content/logos/torrentz.png diff --git a/src/Jackett/WebContent/setup_indexer.html b/src/Jackett/Content/setup_indexer.html similarity index 100% rename from src/Jackett/WebContent/setup_indexer.html rename to src/Jackett/Content/setup_indexer.html diff --git a/src/Jackett/Controllers/APIController.cs b/src/Jackett/Controllers/APIController.cs new file mode 100644 index 000000000..d2ac760f9 --- /dev/null +++ b/src/Jackett/Controllers/APIController.cs @@ -0,0 +1,73 @@ +using Jackett.Models; +using Jackett.Services; +using NLog; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Web.Http; + +namespace Jackett.Controllers +{ + public class APIController : ApiController + { + private IIndexerManagerService indexerService; + private Logger logger; + + public APIController(IIndexerManagerService i, Logger l) + { + indexerService = i; + logger = l; + } + + [HttpGet] + public async Task Call(string indexerName) + { + var indexer = indexerService.GetIndexer(indexerName); + var torznabQuery = TorznabQuery.FromHttpQuery(HttpUtility.ParseQueryString(Request.RequestUri.Query)); + + if (torznabQuery.RageIDLookupEnabled && indexer.RequiresRageIDLookupDisabled) + { + throw new ArgumentException("This indexer requires RageID lookup disabled"); + } + + var releases = await indexer.PerformQuery(torznabQuery); + + logger.Debug(string.Format("Found {0} releases from {1}", releases.Length, indexer.DisplayName)); + var severUrl = string.Format("{0}://{1}:{2}/", Request.RequestUri.Scheme, Request.RequestUri.Host, Request.RequestUri.Port); + + var resultPage = new ResultPage(new ChannelInfo + { + Title = indexer.DisplayName, + Description = indexer.DisplayDescription, + Link = indexer.SiteLink, + ImageUrl = new Uri(severUrl + "logos/" + indexer.DisplayName + ".png"), + ImageTitle = indexer.DisplayName, + ImageLink = indexer.SiteLink, + ImageDescription = indexer.DisplayName + }); + + // add Jackett proxy to download links... + foreach (var release in releases) + { + if (release.Link == null || release.Link.Scheme == "magnet") + continue; + var originalLink = release.Link; + var encodedLink = HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes(originalLink.ToString())) + "/download.torrent"; + var proxyLink = string.Format("{0}api/{1}/download/{2}", severUrl, indexer.DisplayName.ToLowerInvariant(), encodedLink); + release.Link = new Uri(proxyLink); + } + + resultPage.Releases.AddRange(releases); + var xml = resultPage.ToXml(new Uri(severUrl)); + // Force the return as XML + return new HttpResponseMessage() + { + Content = new StringContent(xml, Encoding.UTF8, "application/rss+xml") + }; + } + } +} diff --git a/src/Jackett/Controllers/AdminController.cs b/src/Jackett/Controllers/AdminController.cs new file mode 100644 index 000000000..c529fe846 --- /dev/null +++ b/src/Jackett/Controllers/AdminController.cs @@ -0,0 +1,210 @@ +using Autofac; +using Jackett.Models; +using Jackett.Services; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using System.Web.Http; + +namespace Jackett.Controllers +{ + [RoutePrefix("admin")] + public class AdminController : ApiController + { + private IConfigurationService config; + private IIndexerManagerService indexerService; + private IServerService serverService; + + public AdminController(IConfigurationService config, IIndexerManagerService i, IServerService ss) + { + this.config = config; + indexerService = i; + serverService = ss; + } + + private async Task ReadPostDataJson() + { + var content = await Request.Content.ReadAsStringAsync(); + return JObject.Parse(content); + } + + [Route("get_config_form")] + [HttpGet] + public async Task GetConfigForm() + { + var jsonReply = new JObject(); + try + { + var postData = await ReadPostDataJson(); + var indexer = indexerService.GetIndexer((string)postData["indexer"]); + var config = await indexer.GetConfigurationForSetup(); + jsonReply["config"] = config.ToJson(); + jsonReply["name"] = indexer.DisplayName; + jsonReply["result"] = "success"; + } + catch (Exception ex) + { + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + } + return Json(jsonReply); + } + + [Route("configure_indexer")] + [HttpPost] + public async Task Configure() + { + JToken jsonReply = new JObject(); + try + { + var postData = await ReadPostDataJson(); + string indexerString = (string)postData["indexer"]; + var indexer = indexerService.GetIndexer((string)postData["indexer"]); + jsonReply["name"] = indexer.DisplayName; + await indexer.ApplyConfiguration(postData["config"]); + indexerService.TestIndexer((string)postData["indexer"]); + jsonReply["result"] = "success"; + } + catch (Exception ex) + { + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + if (ex is ExceptionWithConfigData) + { + jsonReply["config"] = ((ExceptionWithConfigData)ex).ConfigData.ToJson(); + } + } + return Json(jsonReply); + } + + + + [Route("get_indexers")] + [HttpGet] + public IHttpActionResult Indexers() + { + var jsonReply = new JObject(); + try + { + jsonReply["result"] = "success"; + jsonReply["api_key"] = serverService.Config.APIKey; + jsonReply["app_version"] = config.GetVersion(); + JArray items = new JArray(); + + foreach (var indexer in indexerService.GetAllIndexers()) + { + var item = new JObject(); + item["id"] = indexer.GetType().Name.ToLowerInvariant(); + item["name"] = indexer.DisplayName; + item["description"] = indexer.DisplayDescription; + item["configured"] = indexer.IsConfigured; + item["site_link"] = indexer.SiteLink; + items.Add(item); + } + jsonReply["items"] = items; + } + catch (Exception ex) + { + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + } + return Json(jsonReply); + } + + [Route("test_indexer")] + [HttpPost] + public async Task Test() + { + JToken jsonReply = new JObject(); + try + { + var postData = await ReadPostDataJson(); + string indexerString = (string)postData["indexer"]; + indexerService.TestIndexer(indexerString); + jsonReply["result"] = "success"; + } + catch (Exception ex) + { + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + } + return Json(jsonReply); + } + + [Route("delete_indexer")] + [HttpPost] + public async Task Delete() + { + var jsonReply = new JObject(); + try + { + var postData = await ReadPostDataJson(); + string indexerString = (string)postData["indexer"]; + indexerService.DeleteIndexer(indexerString); + } + catch (Exception ex) + { + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + } + return Json(jsonReply); + } + + [Route("get_jackett_config")] + [HttpGet] + public IHttpActionResult GetConfig() + { + var jsonReply = new JObject(); + try + { + jsonReply["config"] = config.ReadServerSettingsFile(); + jsonReply["result"] = "success"; + } + catch (CustomException ex) + { + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + } + catch (Exception ex) + { + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + } + return Json(jsonReply); + } + + [Route("apply_jackett_config")] + [HttpPost] + public async Task SetConfig() + { + var jsonReply = new JObject(); + try + { + var postData = await ReadPostDataJson(); + // int port = await WebServer.ApplyPortConfiguration(postData); + jsonReply["result"] = "success"; + // jsonReply["port"] = port; + } + catch (Exception ex) + { + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + } + return Json(jsonReply); + } + + + [Route("jackett_restart")] + [HttpPost] + public IHttpActionResult Restart() + { + return null; + } + } +} + diff --git a/src/Jackett/Controllers/DownloadController.cs b/src/Jackett/Controllers/DownloadController.cs new file mode 100644 index 000000000..235abc255 --- /dev/null +++ b/src/Jackett/Controllers/DownloadController.cs @@ -0,0 +1,48 @@ +using Jackett.Services; +using NLog; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Web.Http; + +namespace Jackett.Controllers +{ + public class DownloadController : ApiController + { + private Logger logger; + private IIndexerManagerService indexerService; + + public DownloadController(IIndexerManagerService i, Logger l) + { + logger = l; + indexerService = i; + } + + [HttpGet] + public async Task Download(string indexerName, string path) + { + try + { + var indexer = indexerService.GetIndexer(indexerName); + var remoteFile = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(path)); + var downloadBytes = await indexer.Download(new Uri(remoteFile)); + + var result = new HttpResponseMessage(HttpStatusCode.OK); + result.Content = new ByteArrayContent(downloadBytes); + result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-bittorrent"); + return result; + } + catch (Exception e) + { + logger.Error(e, "Error downloading " + indexerName + " " + path); + return new HttpResponseMessage(HttpStatusCode.NotFound); + } + } + } +} diff --git a/src/Jackett/CookieContainerExtensions.cs b/src/Jackett/CookieContainerExtensions.cs index 447c3be30..070a326fa 100644 --- a/src/Jackett/CookieContainerExtensions.cs +++ b/src/Jackett/CookieContainerExtensions.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json.Linq; +using NLog; using System; using System.Collections.Generic; using System.Linq; @@ -11,8 +12,7 @@ namespace Jackett { public static class CookieContainerExtensions { - - public static void FillFromJson(this CookieContainer cookies, Uri uri, JToken json) + public static void FillFromJson(this CookieContainer cookies, Uri uri, JToken json, Logger logger) { if (json["cookies"] != null) { @@ -43,12 +43,17 @@ namespace Jackett } catch (CookieException ex) { - Program.LoggerInstance.Info("(Non-critical) Problem loading cookie {0}, {1}, {2}", uri, c, ex.Message); + logger.Info("(Non-critical) Problem loading cookie {0}, {1}, {2}", uri, c, ex.Message); } } } } + public static void DumpToJson(this CookieContainer cookies, string uri, JToken json) + { + DumpToJson(cookies, new Uri(uri), json); + } + public static void DumpToJson(this CookieContainer cookies, Uri uri, JToken json) { json["cookie_header"] = cookies.GetCookieHeader(uri); diff --git a/src/Jackett/DataUrl.cs b/src/Jackett/DataUrl.cs index 339858836..3ff22beeb 100644 --- a/src/Jackett/DataUrl.cs +++ b/src/Jackett/DataUrl.cs @@ -10,7 +10,6 @@ namespace Jackett { public class DataUrl { - public static string ReadFileToDataUrl(string file) { string mime = MimeMapping.GetMimeMapping(file); diff --git a/src/Jackett/Engine.cs b/src/Jackett/Engine.cs new file mode 100644 index 000000000..7fffd41a8 --- /dev/null +++ b/src/Jackett/Engine.cs @@ -0,0 +1,111 @@ +using Autofac; +using Jackett.Services; +using NLog; +using NLog.Config; +using NLog.Targets; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett +{ + public class Engine + { + private static IContainer container = null; + + static Engine() + { + var builder = new ContainerBuilder(); + builder.RegisterModule(); + container = builder.Build(); + + // Register the container in itself to allow for late resolves + var secondaryBuilder = new ContainerBuilder(); + secondaryBuilder.RegisterInstance(container).SingleInstance(); + SetupLogging(secondaryBuilder); + secondaryBuilder.Update(container); + + Logger.Info("Starting Jackett " + ConfigService.GetVersion()); + } + + public static IContainer GetContainer() + { + return container; + } + + public static bool IsWindows { + get { + return Environment.OSVersion.Platform == PlatformID.Win32NT; + } + } + + public static IConfigurationService ConfigService + { + get + { + return container.Resolve(); + } + } + + public static IServiceConfigService ServiceConfig + { + get + { + return container.Resolve(); + } + } + + public static IServerService Server + { + get + { + return container.Resolve(); + } + } + + public static IRunTimeService RunTime + { + get + { + return container.Resolve(); + } + } + + public static Logger Logger + { + get + { + return container.Resolve(); + } + } + + private static void SetupLogging(ContainerBuilder builder) + { + var logConfig = new LoggingConfiguration(); + + var logFile = new FileTarget(); + logConfig.AddTarget("file", logFile); + logFile.Layout = "${longdate} ${level} ${message} ${exception:format=ToString}"; + logFile.FileName = Path.Combine(ConfigurationService.GetAppDataFolderStatic(), "log.txt"); + logFile.ArchiveFileName = "log.{#####}.txt"; + logFile.ArchiveAboveSize = 500000; + logFile.MaxArchiveFiles = 1; + logFile.KeepFileOpen = false; + logFile.ArchiveNumbering = ArchiveNumberingMode.DateAndSequence; + var logFileRule = new LoggingRule("*", LogLevel.Debug, logFile); + logConfig.LoggingRules.Add(logFileRule); + + var logConsole = new ConsoleTarget(); + logConfig.AddTarget("console", logConsole); + logConsole.Layout = "${longdate} ${level} ${message} ${exception:format=ToString}"; + var logConsoleRule = new LoggingRule("*", LogLevel.Debug, logConsole); + logConfig.LoggingRules.Add(logConsoleRule); + + LogManager.Configuration = logConfig; + builder.RegisterInstance(LogManager.GetCurrentClassLogger()).SingleInstance(); + } + } +} diff --git a/src/Jackett/ExceptionWithConfigData.cs b/src/Jackett/ExceptionWithConfigData.cs index 60cf8deae..9280d5f14 100644 --- a/src/Jackett/ExceptionWithConfigData.cs +++ b/src/Jackett/ExceptionWithConfigData.cs @@ -1,4 +1,5 @@ -using System; +using Jackett.Models; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/src/Jackett/IndexerManager.cs b/src/Jackett/IndexerManager.cs deleted file mode 100644 index e5f3d8f62..000000000 --- a/src/Jackett/IndexerManager.cs +++ /dev/null @@ -1,107 +0,0 @@ -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Jackett -{ - public class IndexerManager - { - - static string IndexerConfigDirectory = Path.Combine(Program.AppConfigDirectory, "Indexers"); - - public Dictionary Indexers { get; private set; } - - public IndexerManager() - { - Indexers = new Dictionary(); - LoadMissingIndexers(); - } - - void LoadMissingIndexers() - { - var implementedIndexerTypes = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(s => s.GetTypes()) - .Where(p => typeof(IndexerInterface).IsAssignableFrom(p) && !p.IsInterface) - .ToArray(); - - foreach (var t in implementedIndexerTypes) - { - LoadIndexer(t); - } - } - - void LoadIndexer(Type indexerType) - { - var name = indexerType.Name.Trim().ToLower(); - - if (Indexers.ContainsKey(name)) - return; - - IndexerInterface newIndexer = (IndexerInterface)Activator.CreateInstance(indexerType); - newIndexer.OnSaveConfigurationRequested += newIndexer_OnSaveConfigurationRequested; - newIndexer.OnResultParsingError += newIndexer_OnResultParsingError; - - var configFilePath = GetIndexerConfigFilePath(newIndexer); - if (File.Exists(configFilePath)) - { - var jsonString = JObject.Parse(File.ReadAllText(configFilePath)); - newIndexer.LoadFromSavedConfiguration(jsonString); - } - - Indexers.Add(name, newIndexer); - } - - void newIndexer_OnResultParsingError(IndexerInterface indexer, string results, Exception ex) - { - var fileName = string.Format("Error on {0} for {1}.txt", DateTime.Now.ToString("yyyyMMddHHmmss"), indexer.DisplayName); - var spacing = string.Join("", Enumerable.Repeat(Environment.NewLine, 5)); - var fileContents = string.Format("{0}{1}{2}", ex, spacing, results); - File.WriteAllText(Path.Combine(Program.AppConfigDirectory, fileName), fileContents); - } - - string GetIndexerConfigFilePath(IndexerInterface indexer) - { - return Path.Combine(IndexerConfigDirectory, indexer.GetType().Name.ToLower() + ".json"); - } - - void newIndexer_OnSaveConfigurationRequested(IndexerInterface indexer, JToken obj) - { - var configFilePath = GetIndexerConfigFilePath(indexer); - if (!Directory.Exists(IndexerConfigDirectory)) - Directory.CreateDirectory(IndexerConfigDirectory); - File.WriteAllText(configFilePath, obj.ToString()); - } - - public IndexerInterface GetIndexer(string name) - { - IndexerInterface indexer; - if (!Indexers.TryGetValue(name, out indexer)) - throw new Exception(string.Format("No indexer with ID '{0}'", name)); - return indexer; - } - - public void DeleteIndexer(string name) - { - var indexer = GetIndexer(name); - var configPath = GetIndexerConfigFilePath(indexer); - File.Delete(configPath); - Indexers.Remove(name); - LoadMissingIndexers(); - } - - public async Task TestIndexer(IndexerInterface indexer) - { - var browseQuery = new TorznabQuery(); - var results = await indexer.PerformQuery(browseQuery); - Program.LoggerInstance.Debug(string.Format("Found {0} releases from {1}", results.Length, indexer.DisplayName)); - if (results.Length == 0) - throw new Exception("Found no results while trying to browse this tracker"); - - } - - } -} diff --git a/src/Jackett/Indexers/AlphaRatio.cs b/src/Jackett/Indexers/AlphaRatio.cs index 4967c3364..e4883f83d 100644 --- a/src/Jackett/Indexers/AlphaRatio.cs +++ b/src/Jackett/Indexers/AlphaRatio.cs @@ -9,10 +9,13 @@ using System.Text; using System.Threading.Tasks; using System.Web; using System.Net.Http.Headers; +using Jackett.Models; +using Jackett.Utils; +using NLog; namespace Jackett.Indexers { - public class AlphaRatio : IndexerInterface + public class AlphaRatio : IIndexer { public string DisplayName { @@ -32,8 +35,8 @@ namespace Jackett.Indexers public bool RequiresRageIDLookupDisabled { get { return true; } } - public event Action OnSaveConfigurationRequested; - public event Action OnResultParsingError; + public event Action OnSaveConfigurationRequested; + public event Action OnResultParsingError; public bool IsConfigured { get; private set; } @@ -54,9 +57,11 @@ namespace Jackett.Indexers HttpClient client; string cookieHeader; + private Logger logger; - public AlphaRatio() + public AlphaRatio(Logger l) { + logger = l; IsConfigured = false; cookies = new CookieContainer(); handler = new HttpClientHandler @@ -100,7 +105,7 @@ namespace Jackett.Indexers configSaveData = new JObject(); - if (Program.IsWindows) + if (Engine.IsWindows) { // If Windows use .net http var response = await client.SendAsync(message); @@ -144,7 +149,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(SiteLink, jsonConfig); + cookies.FillFromJson(SiteLink, jsonConfig, logger); cookieHeader = cookies.GetCookieHeader(SiteLink); IsConfigured = true; } @@ -167,7 +172,7 @@ namespace Jackett.Indexers var episodeSearchUrl = SearchUrl + HttpUtility.UrlEncode(searchString); string results; - if (Program.IsWindows) + if (Engine.IsWindows) { var request = CreateHttpRequest(new Uri(episodeSearchUrl)); request.Method = HttpMethod.Get; @@ -234,7 +239,7 @@ namespace Jackett.Indexers public async Task Download(Uri link) { - if (Program.IsWindows) + if (Engine.IsWindows) { return await client.GetByteArrayAsync(link); } diff --git a/src/Jackett/Indexers/AnimeBytes.cs b/src/Jackett/Indexers/AnimeBytes.cs index 739b45611..c5360a0f8 100644 --- a/src/Jackett/Indexers/AnimeBytes.cs +++ b/src/Jackett/Indexers/AnimeBytes.cs @@ -1,5 +1,8 @@ using CsQuery; +using Jackett.Models; +using Jackett.Utils; using Newtonsoft.Json.Linq; +using NLog; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -15,7 +18,7 @@ using System.Web; namespace Jackett.Indexers { - public class AnimeBytes : IndexerInterface + public class AnimeBytes : IIndexer { class ConfigurationDataBasicLoginAnimeBytes : ConfigurationDataBasicLogin { @@ -38,8 +41,8 @@ namespace Jackett.Indexers private static List cache = new List(); private static readonly TimeSpan cacheTime = new TimeSpan(0, 9, 0); - public event Action OnResultParsingError; - public event Action OnSaveConfigurationRequested; + public event Action OnResultParsingError; + public event Action OnSaveConfigurationRequested; static string chromeUserAgent = BrowserUtil.ChromeUserAgent; @@ -71,9 +74,11 @@ namespace Jackett.Indexers CookieContainer cookieContainer; HttpClientHandler handler; HttpClient client; + Logger logger; - public AnimeBytes() + public AnimeBytes(Logger l) { + logger = l; IsConfigured = false; cookieContainer = new CookieContainer(); handler = new HttpClientHandler @@ -164,7 +169,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookieContainer.FillFromJson(new Uri(BaseUrl), jsonConfig); + cookieContainer.FillFromJson(new Uri(BaseUrl), jsonConfig, logger); IsConfigured = true; AllowRaws = jsonConfig["raws"].Value(); } diff --git a/src/Jackett/Indexers/BaseIndexer.cs b/src/Jackett/Indexers/BaseIndexer.cs new file mode 100644 index 000000000..1de82fb31 --- /dev/null +++ b/src/Jackett/Indexers/BaseIndexer.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Jackett.Models; +using Newtonsoft.Json.Linq; +using NLog; + +namespace Jackett.Indexers +{ + public abstract class BaseIndexer: IIndexer + { + public string DisplayDescription { get; private set; } + public string DisplayName { get; private set; } + public bool IsConfigured { get; protected set; } + public Uri SiteLink { get; private set; } + public bool RequiresRageIDLookupDisabled { get; private set; } + + public abstract Task ApplyConfiguration(JToken configJson); + public abstract Task Download(Uri link); + public abstract Task GetConfigurationForSetup(); + public abstract void LoadFromSavedConfiguration(JToken jsonConfig); + public abstract Task PerformQuery(TorznabQuery query); + + private Logger logger; + + public BaseIndexer(string name, string description, Uri link, Logger logger) + { + DisplayName = name; + DisplayDescription = description; + SiteLink = link; + this.logger = logger; + } + + protected void LogParseError(string results, Exception ex) + { + var fileName = string.Format("Error on {0} for {1}.txt", DateTime.Now.ToString("yyyyMMddHHmmss"), DisplayName); + var spacing = string.Join("", Enumerable.Repeat(Environment.NewLine, 5)); + var fileContents = string.Format("{0}{1}{2}", ex, spacing, results); + logger.Error(fileName + fileContents); + } + } +} diff --git a/src/Jackett/Indexers/BeyondHD.cs b/src/Jackett/Indexers/BeyondHD.cs index 25293f406..f55a5bdb5 100644 --- a/src/Jackett/Indexers/BeyondHD.cs +++ b/src/Jackett/Indexers/BeyondHD.cs @@ -1,5 +1,8 @@ using CsQuery; +using Jackett.Models; +using Jackett.Utils; using Newtonsoft.Json.Linq; +using NLog; using System; using System.Collections.Generic; using System.Linq; @@ -11,11 +14,11 @@ using System.Web; namespace Jackett.Indexers { - public class BeyondHD : IndexerInterface + public class BeyondHD : IIndexer { - public event Action OnSaveConfigurationRequested; + public event Action OnSaveConfigurationRequested; - public event Action OnResultParsingError; + public event Action OnResultParsingError; public string DisplayName { @@ -43,9 +46,11 @@ namespace Jackett.Indexers CookieContainer cookies; HttpClientHandler handler; HttpClient client; + Logger logger; - public BeyondHD() + public BeyondHD(Logger l) { + logger = l; IsConfigured = false; cookies = new CookieContainer(); handler = new HttpClientHandler @@ -70,7 +75,7 @@ namespace Jackett.Indexers var jsonCookie = new JObject(); jsonCookie["cookie_header"] = config.CookieHeader; - cookies.FillFromJson(new Uri(BaseUrl), jsonCookie); + cookies.FillFromJson(new Uri(BaseUrl), jsonCookie, logger); var responseContent = await client.GetStringAsync(BaseUrl); @@ -94,7 +99,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(new Uri(BaseUrl), jsonConfig); + cookies.FillFromJson(new Uri(BaseUrl), jsonConfig, logger); IsConfigured = true; } diff --git a/src/Jackett/Indexers/BitHdtv.cs b/src/Jackett/Indexers/BitHdtv.cs index 86a8f213c..a7319e23c 100644 --- a/src/Jackett/Indexers/BitHdtv.cs +++ b/src/Jackett/Indexers/BitHdtv.cs @@ -1,5 +1,8 @@ using CsQuery; +using Jackett.Models; +using Jackett.Utils; using Newtonsoft.Json.Linq; +using NLog; using System; using System.Collections.Generic; using System.Globalization; @@ -12,9 +15,9 @@ using System.Web; namespace Jackett.Indexers { - public class BitHdtv : IndexerInterface + public class BitHdtv : IIndexer { - public event Action OnResultParsingError; + public event Action OnResultParsingError; public string DisplayName { @@ -41,9 +44,11 @@ namespace Jackett.Indexers CookieContainer cookies; HttpClientHandler handler; HttpClient client; + Logger loggger; - public BitHdtv() + public BitHdtv(Logger l) { + loggger = l; IsConfigured = false; cookies = new CookieContainer(); handler = new HttpClientHandler @@ -97,13 +102,13 @@ namespace Jackett.Indexers } } - public event Action OnSaveConfigurationRequested; + public event Action OnSaveConfigurationRequested; public bool IsConfigured { get; private set; } public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(new Uri(BaseUrl), jsonConfig); + cookies.FillFromJson(new Uri(BaseUrl), jsonConfig, loggger); IsConfigured = true; } diff --git a/src/Jackett/Indexers/BitMeTV.cs b/src/Jackett/Indexers/BitMeTV.cs index 42d6f2bfc..fc845d2db 100644 --- a/src/Jackett/Indexers/BitMeTV.cs +++ b/src/Jackett/Indexers/BitMeTV.cs @@ -1,5 +1,8 @@ using CsQuery; +using Jackett.Models; +using Jackett.Utils; using Newtonsoft.Json.Linq; +using NLog; using System; using System.Collections.Generic; using System.Globalization; @@ -11,9 +14,9 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Web; -namespace Jackett +namespace Jackett.Indexers { - public class BitMeTV : IndexerInterface + public class BitMeTV : IIndexer { class BmtvConfig : ConfigurationData { @@ -48,12 +51,14 @@ namespace Jackett CookieContainer cookies; HttpClientHandler handler; HttpClient client; + Logger logger; - public event Action OnSaveConfigurationRequested; - public event Action OnResultParsingError; + public event Action OnSaveConfigurationRequested; + public event Action OnResultParsingError; - public BitMeTV() + public BitMeTV(Logger l) { + logger = l; IsConfigured = false; cookies = new CookieContainer(); handler = new HttpClientHandler @@ -124,7 +129,7 @@ namespace Jackett public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(new Uri(BaseUrl), jsonConfig); + cookies.FillFromJson(new Uri(BaseUrl), jsonConfig, logger); IsConfigured = true; } diff --git a/src/Jackett/Indexers/FrenchTorrentDb.cs b/src/Jackett/Indexers/FrenchTorrentDb.cs index 6eae903c6..d03eecceb 100644 --- a/src/Jackett/Indexers/FrenchTorrentDb.cs +++ b/src/Jackett/Indexers/FrenchTorrentDb.cs @@ -1,4 +1,6 @@ using CsQuery; +using Jackett.Models; +using Jackett.Utils; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; @@ -10,11 +12,11 @@ using System.Web; namespace Jackett.Indexers { - class FrenchTorrentDb : IndexerInterface + class FrenchTorrentDb : IIndexer { - public event Action OnSaveConfigurationRequested; + public event Action OnSaveConfigurationRequested; - public event Action OnResultParsingError; + public event Action OnResultParsingError; class ConfigurationDataBasicLoginFrenchTorrentDb : ConfigurationData { diff --git a/src/Jackett/Indexers/Freshon.cs b/src/Jackett/Indexers/Freshon.cs index e2b18cc78..d5080b10e 100644 --- a/src/Jackett/Indexers/Freshon.cs +++ b/src/Jackett/Indexers/Freshon.cs @@ -1,5 +1,9 @@ using CsQuery; +using Jackett.Indexers; +using Jackett.Models; +using Jackett.Utils; using Newtonsoft.Json.Linq; +using NLog; using System; using System.Collections.Generic; using System.Globalization; @@ -14,9 +18,9 @@ using System.Web.UI.WebControls; namespace Jackett { - public class Freshon : IndexerInterface + public class Freshon : IIndexer { - public event Action OnResultParsingError; + public event Action OnResultParsingError; static string BaseUrl = "https://freshon.tv"; static string LoginUrl = BaseUrl + "/login.php"; @@ -39,10 +43,12 @@ namespace Jackett public bool RequiresRageIDLookupDisabled { get { return true; } } - public event Action OnSaveConfigurationRequested; + public event Action OnSaveConfigurationRequested; + private Logger logger; - public Freshon() + public Freshon(Logger l) { + logger = l; IsConfigured = false; cookies = new CookieContainer(); handler = new HttpClientHandler @@ -94,8 +100,8 @@ namespace Jackett var configSaveData = new JObject(); cookies.DumpToJson(SiteLink, configSaveData); - if (OnSaveConfigurationRequested != null) - OnSaveConfigurationRequested(this, configSaveData); + // if (OnSaveConfigurationRequested != null) + // OnSaveConfigurationRequested(this, configSaveData); IsConfigured = true; } @@ -103,7 +109,7 @@ namespace Jackett public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(new Uri(BaseUrl), jsonConfig); + cookies.FillFromJson(new Uri(BaseUrl), jsonConfig, logger); IsConfigured = true; } diff --git a/src/Jackett/Indexers/HDTorrents.cs b/src/Jackett/Indexers/HDTorrents.cs index b14945c7f..9655ec244 100644 --- a/src/Jackett/Indexers/HDTorrents.cs +++ b/src/Jackett/Indexers/HDTorrents.cs @@ -1,5 +1,8 @@ using CsQuery; +using Jackett.Models; +using Jackett.Utils; using Newtonsoft.Json.Linq; +using NLog; using System; using System.Collections.Generic; using System.Globalization; @@ -12,26 +15,27 @@ using System.Web; namespace Jackett.Indexers { - public class HDTorrents : IndexerInterface + public class HDTorrents : IIndexer { - public event Action OnSaveConfigurationRequested; + public event Action OnSaveConfigurationRequested; - public event Action OnResultParsingError; + public event Action OnResultParsingError; const string DefaultUrl = "http://hdts.ru"; // Of the accessible domains the .ru seems the most reliable. https://hdts.ru | https://hd-torrents.org | https://hd-torrents.net | https://hd-torrents.me string BaseUrl = DefaultUrl; static string chromeUserAgent = BrowserUtil.ChromeUserAgent; private string SearchUrl = DefaultUrl + "/torrents.php?search={0}&active=1&options=0&category%5B%5D=59&category%5B%5D=60&category%5B%5D=30&category%5B%5D=38&page={1}"; private static string LoginUrl = DefaultUrl + "/login.php"; - private static string LoginPostUrl = DefaultUrl + "/login.php?returnto=index.php"; private const int MAXPAGES = 3; CookieContainer cookies; HttpClientHandler handler; HttpClient client; + Logger logger; - public HDTorrents() + public HDTorrents(Logger l) { + logger = l; IsConfigured = false; cookies = new CookieContainer(); handler = new HttpClientHandler @@ -124,7 +128,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(SiteLink, jsonConfig); + cookies.FillFromJson(SiteLink, jsonConfig, logger); IsConfigured = true; } diff --git a/src/Jackett/IndexerInterface.cs b/src/Jackett/Indexers/IIndexer.cs similarity index 74% rename from src/Jackett/IndexerInterface.cs rename to src/Jackett/Indexers/IIndexer.cs index abbc9e8f0..ab5e1840a 100644 --- a/src/Jackett/IndexerInterface.cs +++ b/src/Jackett/Indexers/IIndexer.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json.Linq; +using Jackett.Models; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Linq; @@ -6,16 +7,10 @@ using System.Text; using System.Threading.Tasks; using System.Web.UI.WebControls; -namespace Jackett +namespace Jackett.Indexers { - public interface IndexerInterface + public interface IIndexer { - - // Invoked when the indexer configuration has been applied and verified so the cookie needs to be saved - event Action OnSaveConfigurationRequested; - - event Action OnResultParsingError; - string DisplayName { get; } string DisplayDescription { get; } Uri SiteLink { get; } diff --git a/src/Jackett/Indexers/IPTorrents.cs b/src/Jackett/Indexers/IPTorrents.cs index b374366b3..00ff0ca5a 100644 --- a/src/Jackett/Indexers/IPTorrents.cs +++ b/src/Jackett/Indexers/IPTorrents.cs @@ -1,5 +1,8 @@ using CsQuery; +using Jackett.Models; +using Jackett.Utils; using Newtonsoft.Json.Linq; +using NLog; using System; using System.Collections.Generic; using System.Globalization; @@ -12,11 +15,11 @@ using System.Web; namespace Jackett.Indexers { - public class IPTorrents : IndexerInterface + public class IPTorrents : IIndexer { - public event Action OnSaveConfigurationRequested; - public event Action OnResultParsingError; + public event Action OnSaveConfigurationRequested; + public event Action OnResultParsingError; public string DisplayName { get { return "IPTorrents"; } } @@ -38,9 +41,11 @@ namespace Jackett.Indexers CookieContainer cookies; HttpClientHandler handler; HttpClient client; + Logger logger; - public IPTorrents() + public IPTorrents(Logger l) { + logger = l; IsConfigured = false; cookies = new CookieContainer(); handler = new HttpClientHandler @@ -112,7 +117,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(Newtonsoft.Json.Linq.JToken jsonConfig) { - cookies.FillFromJson(new Uri(BaseUrl), jsonConfig); + cookies.FillFromJson(new Uri(BaseUrl), jsonConfig, logger); IsConfigured = true; } diff --git a/src/Jackett/Indexers/Master.cs b/src/Jackett/Indexers/Master.cs new file mode 100644 index 000000000..b563b69cd --- /dev/null +++ b/src/Jackett/Indexers/Master.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Indexers +{ + class Master + { + + + + } +} diff --git a/src/Jackett/Indexers/MoreThanTV.cs b/src/Jackett/Indexers/MoreThanTV.cs index b742192f4..0c158e524 100644 --- a/src/Jackett/Indexers/MoreThanTV.cs +++ b/src/Jackett/Indexers/MoreThanTV.cs @@ -1,5 +1,7 @@ using CsQuery; +using Jackett.Models; using Newtonsoft.Json.Linq; +using NLog; using System; using System.Collections.Generic; using System.IO; @@ -12,7 +14,7 @@ using System.Web; namespace Jackett.Indexers { - public class MoreThanTV : IndexerInterface + public class MoreThanTV : IIndexer { public string DisplayName { @@ -31,8 +33,8 @@ namespace Jackett.Indexers public bool RequiresRageIDLookupDisabled { get { return true; } } - public event Action OnSaveConfigurationRequested; - public event Action OnResultParsingError; + public event Action OnSaveConfigurationRequested; + public event Action OnResultParsingError; public bool IsConfigured { get; private set; } @@ -49,12 +51,14 @@ namespace Jackett.Indexers CookieContainer cookies; HttpClientHandler handler; HttpClient client; + private Logger logger; string cookieHeader; int retries = 3; - public MoreThanTV() + public MoreThanTV(Logger l) { + logger = l; IsConfigured = false; cookies = new CookieContainer(); handler = new HttpClientHandler @@ -90,7 +94,7 @@ namespace Jackett.Indexers var configSaveData = new JObject(); - if (Program.IsWindows) + if (Engine.IsWindows) { // If Windows use .net http var response = await client.PostAsync(LoginUrl, content); @@ -126,7 +130,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(SiteLink, jsonConfig); + cookies.FillFromJson(SiteLink, jsonConfig, logger); cookieHeader = cookies.GetCookieHeader(SiteLink); IsConfigured = true; } @@ -150,7 +154,7 @@ namespace Jackett.Indexers var episodeSearchUrl = SearchUrl + HttpUtility.UrlEncode(searchString); string results; - if (Program.IsWindows) + if (Engine.IsWindows) { results = await client.GetStringAsync(episodeSearchUrl, retries); } @@ -217,7 +221,7 @@ namespace Jackett.Indexers public async Task Download(Uri link) { - if (Program.IsWindows) + if (Engine.IsWindows) { return await client.GetByteArrayAsync(link); } diff --git a/src/Jackett/Indexers/Rarbg.cs b/src/Jackett/Indexers/Rarbg.cs index 45358119d..9495d9475 100644 --- a/src/Jackett/Indexers/Rarbg.cs +++ b/src/Jackett/Indexers/Rarbg.cs @@ -1,4 +1,6 @@ using CsQuery; +using Jackett.Models; +using Jackett.Utils; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; @@ -10,11 +12,11 @@ using System.Threading.Tasks; namespace Jackett.Indexers { - public class Rarbg : IndexerInterface + public class Rarbg : IIndexer { - public event Action OnSaveConfigurationRequested; + public event Action OnSaveConfigurationRequested; - public event Action OnResultParsingError; + public event Action OnResultParsingError; public string DisplayName { diff --git a/src/Jackett/Indexers/SceneAccess.cs b/src/Jackett/Indexers/SceneAccess.cs index 75d29d1f9..b748423a9 100644 --- a/src/Jackett/Indexers/SceneAccess.cs +++ b/src/Jackett/Indexers/SceneAccess.cs @@ -1,5 +1,8 @@ using CsQuery; +using Jackett.Models; +using Jackett.Utils; using Newtonsoft.Json.Linq; +using NLog; using System; using System.Collections.Generic; using System.Globalization; @@ -10,11 +13,11 @@ using System.Threading.Tasks; namespace Jackett.Indexers { - class SceneAccess : IndexerInterface + class SceneAccess : IIndexer { - public event Action OnSaveConfigurationRequested; + public event Action OnSaveConfigurationRequested; - public event Action OnResultParsingError; + public event Action OnResultParsingError; public string DisplayName { @@ -48,9 +51,11 @@ namespace Jackett.Indexers HttpClientHandler handler; HttpClient client; string cookieHeader; + private Logger logger; - public SceneAccess() + public SceneAccess(Logger l) { + logger = l; IsConfigured = false; cookies = new CookieContainer(); handler = new HttpClientHandler @@ -84,7 +89,7 @@ namespace Jackett.Indexers string responseContent; var configSaveData = new JObject(); - if (Program.IsWindows) + if (Engine.IsWindows) { // If Windows use .net http var response = await client.PostAsync(LoginUrl, content); @@ -118,7 +123,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(new Uri(BaseUrl), jsonConfig); + cookies.FillFromJson(new Uri(BaseUrl), jsonConfig, logger); cookieHeader = cookies.GetCookieHeader(SiteLink); IsConfigured = true; } @@ -134,7 +139,7 @@ namespace Jackett.Indexers var searchUrl = string.Format(SearchUrl, searchSection, searchCategory, searchString); string results; - if (Program.IsWindows) + if (Engine.IsWindows) { results = await client.GetStringAsync(searchUrl); } @@ -189,7 +194,7 @@ namespace Jackett.Indexers public async Task Download(Uri link) { - if (Program.IsWindows) + if (Engine.IsWindows) { return await client.GetByteArrayAsync(link); } diff --git a/src/Jackett/Indexers/SceneTime.cs b/src/Jackett/Indexers/SceneTime.cs index c64742cec..1ac3fcddb 100644 --- a/src/Jackett/Indexers/SceneTime.cs +++ b/src/Jackett/Indexers/SceneTime.cs @@ -1,5 +1,8 @@ using CsQuery; +using Jackett.Models; +using Jackett.Utils; using Newtonsoft.Json.Linq; +using NLog; using System; using System.Collections.Generic; using System.Globalization; @@ -12,11 +15,11 @@ using System.Web; namespace Jackett.Indexers { - public class SceneTime : IndexerInterface + public class SceneTime : IIndexer { - public event Action OnSaveConfigurationRequested; + public event Action OnSaveConfigurationRequested; - public event Action OnResultParsingError; + public event Action OnResultParsingError; public string DisplayName { @@ -45,10 +48,12 @@ namespace Jackett.Indexers CookieContainer cookies; HttpClientHandler handler; HttpClient client; + Logger logger; - public SceneTime() + public SceneTime(Logger l) { + logger = l; IsConfigured = false; cookies = new CookieContainer(); handler = new HttpClientHandler @@ -101,7 +106,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(new Uri(BaseUrl), jsonConfig); + cookies.FillFromJson(new Uri(BaseUrl), jsonConfig, logger); IsConfigured = true; } diff --git a/src/Jackett/Indexers/ShowRSS.cs b/src/Jackett/Indexers/ShowRSS.cs index 3f3ef5ca9..30d9b7357 100644 --- a/src/Jackett/Indexers/ShowRSS.cs +++ b/src/Jackett/Indexers/ShowRSS.cs @@ -1,4 +1,6 @@ -using Newtonsoft.Json.Linq; +using Jackett.Models; +using Jackett.Utils; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Globalization; @@ -12,11 +14,11 @@ using System.Xml; namespace Jackett.Indexers { - public class ShowRSS : IndexerInterface + public class ShowRSS : IIndexer { - public event Action OnSaveConfigurationRequested; + public event Action OnSaveConfigurationRequested; - public event Action OnResultParsingError; + public event Action OnResultParsingError; public string DisplayName { diff --git a/src/Jackett/Indexers/Strike.cs b/src/Jackett/Indexers/Strike.cs index b2418548c..594f9c391 100644 --- a/src/Jackett/Indexers/Strike.cs +++ b/src/Jackett/Indexers/Strike.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json.Linq; +using Jackett.Models; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Globalization; @@ -11,11 +12,11 @@ using System.Web; namespace Jackett.Indexers { - public class Strike : IndexerInterface + public class Strike : IIndexer { - public event Action OnSaveConfigurationRequested; - public event Action OnResultParsingError; + public event Action OnSaveConfigurationRequested; + public event Action OnResultParsingError; public string DisplayName { diff --git a/src/Jackett/Indexers/T411.cs b/src/Jackett/Indexers/T411.cs index 085971a09..8371acb93 100644 --- a/src/Jackett/Indexers/T411.cs +++ b/src/Jackett/Indexers/T411.cs @@ -1,4 +1,6 @@ -using Newtonsoft.Json.Linq; +using Jackett.Models; +using Jackett.Utils; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Globalization; @@ -12,12 +14,12 @@ using System.Web; namespace Jackett.Indexers { - public class T411 : IndexerInterface + public class T411 : IIndexer { - public event Action OnSaveConfigurationRequested; + public event Action OnSaveConfigurationRequested; - public event Action OnResultParsingError; + public event Action OnResultParsingError; public string DisplayName { diff --git a/src/Jackett/Indexers/ThePirateBay.cs b/src/Jackett/Indexers/ThePirateBay.cs index 8dd1070c5..c133f55d4 100644 --- a/src/Jackett/Indexers/ThePirateBay.cs +++ b/src/Jackett/Indexers/ThePirateBay.cs @@ -1,4 +1,6 @@ using CsQuery; +using Jackett.Models; +using Jackett.Utils; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; @@ -13,12 +15,12 @@ using System.Web; namespace Jackett.Indexers { - public class ThePirateBay : IndexerInterface + public class ThePirateBay : IIndexer { - public event Action OnSaveConfigurationRequested; + public event Action OnSaveConfigurationRequested; - public event Action OnResultParsingError; + public event Action OnResultParsingError; public string DisplayName { get { return "The Pirate Bay"; } } @@ -101,7 +103,7 @@ namespace Jackett.Indexers string results; - if (Program.IsWindows) + if (Engine.IsWindows) { results = await client.GetStringAsync(episodeSearchUrl); } @@ -175,7 +177,7 @@ namespace Jackett.Indexers } catch (Exception ex) { - OnResultParsingError(this, results, ex); + // OnResultParsingError(this, results, ex); throw ex; } return releases.ToArray(); diff --git a/src/Jackett/Indexers/TorrentDay.cs b/src/Jackett/Indexers/TorrentDay.cs index 5cbec6a05..019ac070b 100644 --- a/src/Jackett/Indexers/TorrentDay.cs +++ b/src/Jackett/Indexers/TorrentDay.cs @@ -1,5 +1,8 @@ using CsQuery; +using Jackett.Models; +using Jackett.Utils; using Newtonsoft.Json.Linq; +using NLog; using System; using System.Collections.Generic; using System.Globalization; @@ -12,11 +15,11 @@ using System.Web; namespace Jackett.Indexers { - public class TorrentDay : IndexerInterface + public class TorrentDay : IIndexer { - public event Action OnSaveConfigurationRequested; + public event Action OnSaveConfigurationRequested; - public event Action OnResultParsingError; + public event Action OnResultParsingError; public string DisplayName { @@ -47,9 +50,11 @@ namespace Jackett.Indexers CookieContainer cookies; HttpClientHandler handler; HttpClient client; + Logger logger; - public TorrentDay() + public TorrentDay(Logger l) { + logger = l; IsConfigured = false; cookies = new CookieContainer(); handler = new HttpClientHandler @@ -120,7 +125,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(new Uri(BaseUrl), jsonConfig); + cookies.FillFromJson(new Uri(BaseUrl), jsonConfig, logger); IsConfigured = true; } diff --git a/src/Jackett/Indexers/TorrentLeech.cs b/src/Jackett/Indexers/TorrentLeech.cs index 15de57ff7..d1ac3218d 100644 --- a/src/Jackett/Indexers/TorrentLeech.cs +++ b/src/Jackett/Indexers/TorrentLeech.cs @@ -1,5 +1,8 @@ using CsQuery; +using Jackett.Models; +using Jackett.Utils; using Newtonsoft.Json.Linq; +using NLog; using System; using System.Collections.Generic; using System.Globalization; @@ -12,11 +15,11 @@ using System.Web; namespace Jackett.Indexers { - public class TorrentLeech : IndexerInterface + public class TorrentLeech : IIndexer { - public event Action OnResultParsingError; + public event Action OnResultParsingError; - public event Action OnSaveConfigurationRequested; + public event Action OnSaveConfigurationRequested; public string DisplayName { @@ -45,9 +48,11 @@ namespace Jackett.Indexers CookieContainer cookies; HttpClientHandler handler; HttpClient client; + Logger logger; - public TorrentLeech() + public TorrentLeech(Logger l) { + logger = l; IsConfigured = false; cookies = new CookieContainer(); handler = new HttpClientHandler @@ -103,7 +108,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(new Uri(BaseUrl), jsonConfig); + cookies.FillFromJson(new Uri(BaseUrl), jsonConfig, logger); IsConfigured = true; } diff --git a/src/Jackett/Indexers/TorrentShack.cs b/src/Jackett/Indexers/TorrentShack.cs index a6141c45d..ec41b0164 100644 --- a/src/Jackett/Indexers/TorrentShack.cs +++ b/src/Jackett/Indexers/TorrentShack.cs @@ -1,5 +1,8 @@ using CsQuery; +using Jackett.Models; +using Jackett.Utils; using Newtonsoft.Json.Linq; +using NLog; using System; using System.Collections.Generic; using System.Globalization; @@ -12,11 +15,11 @@ using System.Web; namespace Jackett.Indexers { - public class TorrentShack : IndexerInterface + public class TorrentShack : IIndexer { - public event Action OnSaveConfigurationRequested; + public event Action OnSaveConfigurationRequested; - public event Action OnResultParsingError; + public event Action OnResultParsingError; public string DisplayName { @@ -43,11 +46,13 @@ namespace Jackett.Indexers CookieContainer cookies; HttpClientHandler handler; HttpClient client; + Logger logger; public bool IsConfigured { get; private set; } - public TorrentShack() + public TorrentShack(Logger l) { + logger = l; IsConfigured = false; cookies = new CookieContainer(); handler = new HttpClientHandler @@ -105,7 +110,7 @@ namespace Jackett.Indexers public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(new Uri(BaseUrl), jsonConfig); + cookies.FillFromJson(new Uri(BaseUrl), jsonConfig, logger); IsConfigured = true; } diff --git a/src/Jackett/Indexers/Torrentz.cs b/src/Jackett/Indexers/Torrentz.cs index de45011c3..b3991179c 100644 --- a/src/Jackett/Indexers/Torrentz.cs +++ b/src/Jackett/Indexers/Torrentz.cs @@ -1,4 +1,6 @@ -using Newtonsoft.Json.Linq; +using Jackett.Models; +using Jackett.Utils; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Globalization; @@ -11,11 +13,11 @@ using System.Xml; namespace Jackett.Indexers { - public class Torrentz : IndexerInterface + public class Torrentz : IIndexer { - public event Action OnSaveConfigurationRequested; + public event Action OnSaveConfigurationRequested; - public event Action OnResultParsingError; + public event Action OnResultParsingError; public string DisplayName { diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj index baeba57d8..ca06f9283 100644 --- a/src/Jackett/Jackett.csproj +++ b/src/Jackett/Jackett.csproj @@ -5,7 +5,7 @@ Debug AnyCPU {E636D5F8-68B4-4903-B4ED-CCFD9C9E899F} - WinExe + Library Properties Jackett Jackett @@ -48,25 +48,79 @@ 4 - jacket_large.ico + + - Jackett.Program + + + + ..\packages\Autofac.3.5.2\lib\net40\Autofac.dll + True + + + ..\packages\Autofac.Owin.3.1.0\lib\net45\Autofac.Integration.Owin.dll + + + False + ..\packages\Autofac.WebApi2.3.4.0\lib\net45\Autofac.Integration.WebApi.dll + + + ..\packages\Autofac.WebApi2.Owin.3.2.0\lib\net45\Autofac.Integration.WebApi.Owin.dll + ..\packages\CsQuery.1.3.4\lib\net40\CsQuery.dll + + ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll + True + + + ..\packages\Microsoft.Owin.FileSystems.3.0.1\lib\net45\Microsoft.Owin.FileSystems.dll + True + + + ..\packages\Microsoft.Owin.Host.HttpListener.2.0.2\lib\net45\Microsoft.Owin.Host.HttpListener.dll + True + + + ..\packages\Microsoft.Owin.Hosting.2.0.2\lib\net45\Microsoft.Owin.Hosting.dll + True + + + ..\packages\Microsoft.Owin.StaticFiles.3.0.1\lib\net45\Microsoft.Owin.StaticFiles.dll + True + ..\packages\NLog.Windows.Forms.2.0.0.0\lib\net35\NLog.Windows.Forms.dll True + + ..\packages\Owin.1.0\lib\net40\Owin.dll + True + + + + ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll + True + + + + ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll + True + + + ..\packages\Microsoft.AspNet.WebApi.Owin.5.2.3\lib\net45\System.Web.Http.Owin.dll + True + @@ -81,20 +135,28 @@ - - - - - - - - + + + + + + + + + + + + + + + + + - - + @@ -102,6 +164,7 @@ + @@ -115,33 +178,29 @@ - - Form - - - Main.cs - - - + + True True Resources.resx - - - - - - + + + + + + + + - + PreserveNewest @@ -149,126 +208,122 @@ - - Main.cs - ResXFileCodeGenerator Resources.Designer.cs - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest diff --git a/src/Jackett/JackettModule.cs b/src/Jackett/JackettModule.cs new file mode 100644 index 000000000..f658d48c8 --- /dev/null +++ b/src/Jackett/JackettModule.cs @@ -0,0 +1,30 @@ +using Autofac; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Autofac.Integration.WebApi; +using Jackett.Indexers; + +namespace Jackett +{ + public class JackettModule: Module + { + protected override void Load(ContainerBuilder builder) + { + // Just register everything! + var thisAssembly = typeof(JackettModule).Assembly; + builder.RegisterAssemblyTypes(thisAssembly).Except().AsImplementedInterfaces().SingleInstance(); + builder.RegisterApiControllers(thisAssembly).InstancePerRequest(); + + // Register indexers + foreach(var indexer in thisAssembly.GetTypes() + .Where(p => typeof(IIndexer).IsAssignableFrom(p) && !p.IsInterface) + .ToArray()) + { + builder.RegisterType(indexer).Named(indexer.Name.ToLowerInvariant()).SingleInstance(); + } + } + } +} diff --git a/src/Jackett/CachedResult.cs b/src/Jackett/Models/CachedResult.cs similarity index 96% rename from src/Jackett/CachedResult.cs rename to src/Jackett/Models/CachedResult.cs index 925d9a139..24feea319 100644 --- a/src/Jackett/CachedResult.cs +++ b/src/Jackett/Models/CachedResult.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Jackett +namespace Jackett.Models { public class CachedResult { diff --git a/src/Jackett/ChannelInfo.cs b/src/Jackett/Models/ChannelInfo.cs similarity index 96% rename from src/Jackett/ChannelInfo.cs rename to src/Jackett/Models/ChannelInfo.cs index a42421e01..e9afa5112 100644 --- a/src/Jackett/ChannelInfo.cs +++ b/src/Jackett/Models/ChannelInfo.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Jackett +namespace Jackett.Models { public class ChannelInfo { diff --git a/src/Jackett/Models/Config/ServerConfig.cs b/src/Jackett/Models/Config/ServerConfig.cs new file mode 100644 index 000000000..932a7143f --- /dev/null +++ b/src/Jackett/Models/Config/ServerConfig.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Models.Config +{ + public class ServerConfig + { + public ServerConfig() + { + Port = 9117; + } + + public int Port { get; set; } + public bool AllowExternal { get; set; } + public string APIKey { get; set; } + + public string GetListenAddress(bool? external = null) + { + + if (external == null) + { + external = AllowExternal; + } + return "http://" + (external.Value ? "*" : "localhost") + ":" + Port + "/"; + } + + public string GenerateApi() + { + var chars = "abcdefghijklmnopqrstuvwxyz0123456789"; + var randBytes = new byte[32]; + var rngCsp = new RNGCryptoServiceProvider(); + rngCsp.GetBytes(randBytes); + var key = ""; + foreach (var b in randBytes) + { + key += chars[b % chars.Length]; + } + return key; + } + } +} diff --git a/src/Jackett/ConfigurationData.cs b/src/Jackett/Models/ConfigurationData.cs similarity index 99% rename from src/Jackett/ConfigurationData.cs rename to src/Jackett/Models/ConfigurationData.cs index 971698b0c..41b6b0055 100644 --- a/src/Jackett/ConfigurationData.cs +++ b/src/Jackett/Models/ConfigurationData.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Jackett +namespace Jackett.Models { public abstract class ConfigurationData { diff --git a/src/Jackett/ConfigurationDataBasicLogin.cs b/src/Jackett/Models/ConfigurationDataBasicLogin.cs similarity index 96% rename from src/Jackett/ConfigurationDataBasicLogin.cs rename to src/Jackett/Models/ConfigurationDataBasicLogin.cs index 19a2ab0ff..66afbffe3 100644 --- a/src/Jackett/ConfigurationDataBasicLogin.cs +++ b/src/Jackett/Models/ConfigurationDataBasicLogin.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Jackett +namespace Jackett.Models { public class ConfigurationDataBasicLogin : ConfigurationData { diff --git a/src/Jackett/ConfigurationDataCookie.cs b/src/Jackett/Models/ConfigurationDataCookie.cs similarity index 98% rename from src/Jackett/ConfigurationDataCookie.cs rename to src/Jackett/Models/ConfigurationDataCookie.cs index c184dfc5a..afa3e46e5 100644 --- a/src/Jackett/ConfigurationDataCookie.cs +++ b/src/Jackett/Models/ConfigurationDataCookie.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Jackett +namespace Jackett.Models { public class ConfigurationDataCookie : ConfigurationData diff --git a/src/Jackett/ConfigurationDataUrl.cs b/src/Jackett/Models/ConfigurationDataUrl.cs similarity index 96% rename from src/Jackett/ConfigurationDataUrl.cs rename to src/Jackett/Models/ConfigurationDataUrl.cs index e302cf2fd..08e80a76a 100644 --- a/src/Jackett/ConfigurationDataUrl.cs +++ b/src/Jackett/Models/ConfigurationDataUrl.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Jackett +namespace Jackett.Models { public class ConfigurationDataUrl : ConfigurationData { diff --git a/src/Jackett/ReleaseInfo.cs b/src/Jackett/Models/ReleaseInfo.cs similarity index 99% rename from src/Jackett/ReleaseInfo.cs rename to src/Jackett/Models/ReleaseInfo.cs index a6845102a..b81d810e7 100644 --- a/src/Jackett/ReleaseInfo.cs +++ b/src/Jackett/Models/ReleaseInfo.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Jackett +namespace Jackett.Models { public class ReleaseInfo: ICloneable diff --git a/src/Jackett/ResultPage.cs b/src/Jackett/Models/ResultPage.cs similarity index 99% rename from src/Jackett/ResultPage.cs rename to src/Jackett/Models/ResultPage.cs index f9d4b9b2e..fe238e225 100644 --- a/src/Jackett/ResultPage.cs +++ b/src/Jackett/Models/ResultPage.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; -namespace Jackett +namespace Jackett.Models { public class ResultPage { diff --git a/src/Jackett/TorznabQuery.cs b/src/Jackett/Models/TorznabQuery.cs similarity index 98% rename from src/Jackett/TorznabQuery.cs rename to src/Jackett/Models/TorznabQuery.cs index ae3e18785..c1e61d632 100644 --- a/src/Jackett/TorznabQuery.cs +++ b/src/Jackett/Models/TorznabQuery.cs @@ -1,4 +1,5 @@ -using System; +using Jackett.Utils; +using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Globalization; @@ -6,7 +7,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Jackett +namespace Jackett.Models { public class TorznabQuery { diff --git a/src/Jackett/Program.cs b/src/Jackett/Program.cs deleted file mode 100644 index 7dcd24db9..000000000 --- a/src/Jackett/Program.cs +++ /dev/null @@ -1,179 +0,0 @@ -using Jackett.Indexers; -using Newtonsoft.Json.Linq; -using NLog; -using NLog.Config; -using NLog.Targets; -using NLog.Windows.Forms; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Forms; - -namespace Jackett -{ - class Program - { - public static string AppConfigDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Jackett"); - - public static Server ServerInstance { get; private set; } - - public static bool IsFirstRun { get; private set; } - - public static Logger LoggerInstance { get; private set; } - - public static ManualResetEvent ExitEvent { get; private set; } - - public static bool IsWindows { get { return Environment.OSVersion.Platform == PlatformID.Win32NT; } } - - - - static void Main(string[] args) - { - ExitEvent = new ManualResetEvent(false); - - MigrateSettingsDirectory(); - - try - { - if (!Directory.Exists(AppConfigDirectory)) - { - IsFirstRun = true; - Directory.CreateDirectory(AppConfigDirectory); - } - Console.WriteLine("App config/log directory: " + AppConfigDirectory); - } - catch (Exception ex) - { - Console.WriteLine("Missing settings directory: " + AppConfigDirectory); - Console.WriteLine("Could not create settings directory. " + ex.Message); - Application.Exit(); - return; - } - - var logConfig = new LoggingConfiguration(); - - var logFile = new FileTarget(); - logConfig.AddTarget("file", logFile); - logFile.Layout = "${longdate} ${level} ${message} \n ${exception:format=ToString}\n"; - logFile.FileName = Path.Combine(AppConfigDirectory, "log.txt"); - logFile.ArchiveFileName = "log.{#####}.txt"; - logFile.ArchiveAboveSize = 500000; - logFile.MaxArchiveFiles = 1; - logFile.KeepFileOpen = false; - logFile.ArchiveNumbering = ArchiveNumberingMode.DateAndSequence; - var logFileRule = new LoggingRule("*", LogLevel.Debug, logFile); - logConfig.LoggingRules.Add(logFileRule); - - if (Program.IsWindows) - { -#if !__MonoCS__ - var logAlert = new MessageBoxTarget(); - logConfig.AddTarget("alert", logAlert); - logAlert.Layout = "${message}"; - logAlert.Caption = "Alert"; - var logAlertRule = new LoggingRule("*", LogLevel.Fatal, logAlert); - logConfig.LoggingRules.Add(logAlertRule); -#endif - } - - var logConsole = new ConsoleTarget(); - logConfig.AddTarget("console", logConsole); - logConsole.Layout = "${longdate} ${level} ${message} ${exception:format=ToString}"; - var logConsoleRule = new LoggingRule("*", LogLevel.Debug, logConsole); - logConfig.LoggingRules.Add(logConsoleRule); - - LogManager.Configuration = logConfig; - LoggerInstance = LogManager.GetCurrentClassLogger(); - - ReadSettingsFile(); - - var serverTask = Task.Run(async () => - { - ServerInstance = new Server(); - await ServerInstance.Start(); - }); - - try - { - if (Program.IsWindows) - { -#if !__MonoCS__ - Application.Run(new Main()); -#endif - } - } - catch (Exception) - { - - } - - Console.WriteLine("Running in headless mode."); - - - - Task.WaitAll(serverTask); - Console.WriteLine("Server thread exit"); - } - - public static void RestartServer() - { - ServerInstance.Stop(); - ServerInstance = null; - var serverTask = Task.Run(async () => - { - ServerInstance = new Server(); - await ServerInstance.Start(); - }); - Task.WaitAll(serverTask); - } - - static void MigrateSettingsDirectory() - { - try - { - string oldDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Jackett"); - if (Directory.Exists(oldDir) && !Directory.Exists(AppConfigDirectory)) - { - Directory.Move(oldDir, AppConfigDirectory); - } - } - catch (Exception ex) - { - Console.WriteLine("ERROR could not migrate settings directory " + ex); - } - } - - static void ReadSettingsFile() - { - var path = Path.Combine(AppConfigDirectory, "config.json"); - if (!File.Exists(path)) - { - JObject f = new JObject(); - f.Add("port", Server.DefaultPort); - f.Add("public", true); - File.WriteAllText(path, f.ToString()); - } - - var configJson = JObject.Parse(File.ReadAllText(path)); - int port = (int)configJson.GetValue("port"); - Server.Port = port; - - Server.ListenPublic = (bool)configJson.GetValue("public"); - - Console.WriteLine("Config file path: " + path); - } - - static public void RestartAsAdmin() - { - var startInfo = new ProcessStartInfo(Application.ExecutablePath.ToString()) { Verb = "runas" }; - Process.Start(startInfo); - Environment.Exit(0); - } - } -} diff --git a/src/Jackett/Server.cs b/src/Jackett/Server.cs deleted file mode 100644 index 598f992c6..000000000 --- a/src/Jackett/Server.cs +++ /dev/null @@ -1,301 +0,0 @@ -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Net; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using System.Web; -using System.Windows.Forms; - -namespace Jackett -{ - public class Server - { - public const int DefaultPort = 9117; - public static int Port = DefaultPort; - public static bool ListenPublic = true; - - HttpListener listener; - IndexerManager indexerManager; - WebApi webApi; - - - public Server() - { - // Allow all SSL.. sucks I know but mono on linux is having problems without it.. - ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true; - - ReadServerSettingsFile(); - LoadApiKey(); - - indexerManager = new IndexerManager(); - webApi = new WebApi(indexerManager); - } - - void LoadApiKey() - { - var apiKeyFile = Path.Combine(Program.AppConfigDirectory, "api_key.txt"); - if (File.Exists(apiKeyFile)) - ApiKey.CurrentKey = File.ReadAllText(apiKeyFile).Trim(); - else - { - ApiKey.CurrentKey = ApiKey.Generate(); - File.WriteAllText(apiKeyFile, ApiKey.CurrentKey); - } - } - - public async Task Start() - { - Program.LoggerInstance.Info("Starting HTTP server on port " + Port + " listening " + (ListenPublic ? "publicly" : "privately")); - - try - { - listener = new HttpListener(); - - if (ListenPublic) - { - listener.Prefixes.Add(string.Format("http://*:{0}/", Port)); - } - else - { - listener.Prefixes.Add(string.Format("http://127.0.0.1:{0}/", Port)); - } - - listener.Start(); - webApi.server = this; - } - catch (HttpListenerException ex) - { - if (ex.ErrorCode == 5) - { - var errorStr = "App must be ran as admin for permission to use port " - + Port + Environment.NewLine + "Restart app with admin privileges?"; - if (Program.IsWindows) - { - var dialogResult = MessageBox.Show(errorStr, "Error", MessageBoxButtons.YesNo); - if (dialogResult == DialogResult.No) - { - Application.Exit(); - return; - } - else - { - Program.RestartAsAdmin(); - } - } - } - else - { - Program.LoggerInstance.FatalException("Failed to start HTTP server. " + ex.Message, ex); - } - } - catch (Exception ex) - { - Program.LoggerInstance.ErrorException("Error starting HTTP server: " + ex.Message, ex); - return; - } - - Program.LoggerInstance.Info("Server started on port " + Port); - Program.LoggerInstance.Info("Accepting only requests from local system: " + (!ListenPublic)); - - while (true) - { - Exception error = null; - try - { - error = null; - var context = await listener.GetContextAsync(); - ProcessHttpRequest(context); - } - catch (ObjectDisposedException ex) - { - Program.LoggerInstance.ErrorException("Critical error, HTTP listener was destroyed", ex); - Process.GetCurrentProcess().Kill(); - } - catch (Exception ex) - { - error = ex; - Program.LoggerInstance.ErrorException("Error processing HTTP request", ex); - } - - if (error != null) - await Task.Delay(TimeSpan.FromSeconds(5)); - } - } - - public void Stop() - { - listener.Stop(); - listener.Abort(); - } - - async void ProcessHttpRequest(HttpListenerContext context) - { - Program.LoggerInstance.Trace("Received request: " + context.Request.Url.ToString()); - Exception exception = null; - try - { - if (await webApi.HandleRequest(context)) - { - - } - else if (context.Request.Url.AbsolutePath.StartsWith("/api/")) - { - await ProcessTorznab(context); - } - else - { - var responseBytes = Encoding.UTF8.GetBytes("Invalid request"); - await context.Response.OutputStream.WriteAsync(responseBytes, 0, responseBytes.Length); - } - } - catch (Exception ex) - { - exception = ex; - Program.LoggerInstance.ErrorException(ex.Message + ex.ToString(), ex); - } - - if (exception != null) - { - try - { - var errorBytes = Encoding.UTF8.GetBytes(exception.Message); - await context.Response.OutputStream.WriteAsync(errorBytes, 0, errorBytes.Length); - } - catch (Exception) - { - } - } - - try - { - context.Response.Close(); - } - catch (Exception) - { - } - - } - - async Task ProcessTorznab(HttpListenerContext context) - { - - var query = HttpUtility.ParseQueryString(context.Request.Url.Query); - var inputStream = context.Request.InputStream; - - var indexerId = context.Request.Url.Segments[2].TrimEnd('/').ToLower(); - var indexer = indexerManager.GetIndexer(indexerId); - - if (context.Request.Url.Segments.Length > 4 && context.Request.Url.Segments[3] == "download/") - { - var downloadSegment = HttpServerUtility.UrlTokenDecode(context.Request.Url.Segments[4].TrimEnd('/')); - var downloadLink = Encoding.UTF8.GetString(downloadSegment); - var downloadBytes = await indexer.Download(new Uri(downloadLink)); - await context.Response.OutputStream.WriteAsync(downloadBytes, 0, downloadBytes.Length); - return; - } - - var torznabQuery = TorznabQuery.FromHttpQuery(query); - - if (torznabQuery.RageIDLookupEnabled && indexer.RequiresRageIDLookupDisabled) - { - throw new ArgumentException("This indexer requires RageID lookup disabled"); - } - - var releases = await indexer.PerformQuery(torznabQuery); - - Program.LoggerInstance.Debug(string.Format("Found {0} releases from {1}", releases.Length, indexer.DisplayName)); - - var severUrl = string.Format("{0}://{1}:{2}/", context.Request.Url.Scheme, context.Request.Url.Host, context.Request.Url.Port); - - var resultPage = new ResultPage(new ChannelInfo - { - Title = indexer.DisplayName, - Description = indexer.DisplayDescription, - Link = indexer.SiteLink, - ImageUrl = new Uri(severUrl + "logos/" + indexerId + ".png"), - ImageTitle = indexer.DisplayName, - ImageLink = indexer.SiteLink, - ImageDescription = indexer.DisplayName - }); - - // add Jackett proxy to download links... - foreach (var release in releases) - { - if (release.Link == null || release.Link.Scheme == "magnet") - continue; - var originalLink = release.Link; - var encodedLink = HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes(originalLink.ToString())) + "/download.torrent"; - var proxyLink = string.Format("{0}api/{1}/download/{2}", severUrl, indexerId, encodedLink); - release.Link = new Uri(proxyLink); - } - - resultPage.Releases.AddRange(releases); - - var xml = resultPage.ToXml(new Uri(severUrl)); - - var responseBytes = Encoding.UTF8.GetBytes(xml); - context.Response.ContentEncoding = Encoding.UTF8; - context.Response.ContentLength64 = responseBytes.LongLength; - context.Response.ContentType = "application/rss+xml"; - await context.Response.OutputStream.WriteAsync(responseBytes, 0, responseBytes.Length); - - } - - - - - public JObject ReadServerSettingsFile() - { - var path = ServerConfigFile; - JObject jsonReply = new JObject(); - if (File.Exists(path)) - { - jsonReply = JObject.Parse(File.ReadAllText(path)); - Port = (int)jsonReply["port"]; - ListenPublic = (bool)jsonReply["public"]; - } - else - { - jsonReply["port"] = Port; - jsonReply["public"] = ListenPublic; - } - return jsonReply; - } - - public Task ApplyPortConfiguration(JToken json) - { - JObject jsonObject = (JObject)json; - JToken jJackettPort = jsonObject.GetValue("port"); - int jackettPort; - if (!ServerUtil.IsPort(jJackettPort.ToString())) - throw new CustomException("The value entered is not a valid port"); - else - jackettPort = int.Parse(jJackettPort.ToString()); - - if (jackettPort == Port) - throw new CustomException("The current port is the same as the one being used now."); - else if (ServerUtil.RestrictedPorts.Contains(jackettPort)) - throw new CustomException("This port is not allowed due to it not being safe."); - SaveSettings(jackettPort); - - return Task.FromResult(jackettPort); - } - - private static string ServerConfigFile = Path.Combine(Program.AppConfigDirectory, "config.json"); - - private void SaveSettings(int jacketPort) - { - JObject json = new JObject(); - json["port"] = jacketPort; - json["public"] = ListenPublic; - File.WriteAllText(ServerConfigFile, json.ToString()); - } - - } -} diff --git a/src/Jackett/Services/ConfigurationService.cs b/src/Jackett/Services/ConfigurationService.cs new file mode 100644 index 000000000..dd6b8a8d8 --- /dev/null +++ b/src/Jackett/Services/ConfigurationService.cs @@ -0,0 +1,187 @@ +using Newtonsoft.Json.Linq; +using NLog; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Jackett.Services +{ + public interface IConfigurationService + { + string GetContentFolder(); + string GetVersion(); + string GetIndexerConfigDir(); + string GetAppDataFolder(); + JObject ReadServerSettingsFile(); + string GetSonarrConfigFile(); + T GetConfig(); + void SaveConfig(T config); + string ApplicationFolder(); + } + + public class ConfigurationService: IConfigurationService + { + private ISerializeService serializeService; + private Logger logger; + + public ConfigurationService(ISerializeService s, Logger l) + { + serializeService = s; + logger = l; + CreateOrMigrateSettings(); + } + + private void CreateOrMigrateSettings() + { + try + { + if (!Directory.Exists(GetAppDataFolder())) + { + Directory.CreateDirectory(GetAppDataFolder()); + } + + logger.Debug("App config/log directory: " + GetAppDataFolder()); + } + catch (Exception ex) + { + throw new Exception("Could not create settings directory. " + ex.Message); + } + + try + { + string oldDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Jackett"); + if (Directory.Exists(oldDir)) + { + foreach (var file in Directory.GetFiles(oldDir, "*", SearchOption.AllDirectories)) + { + var path = file.Replace(oldDir, ""); + var destFolder = GetAppDataFolder()+ path; + if (!Directory.Exists(Path.GetDirectoryName(destFolder))) + { + Directory.CreateDirectory(Path.GetDirectoryName(destFolder)); + } + File.Move(file, destFolder); + } + } + } + catch (Exception ex) + { + logger.Error("ERROR could not migrate settings directory " + ex); + } + } + + public T GetConfig() + { + var type = typeof(T); + var fullPath = Path.Combine(GetAppDataFolder(), type.Name + ".json"); + try + { + if (!File.Exists(fullPath)) + { + logger.Debug("Config file does not exist: " + fullPath); + return default(T); + } + + return serializeService.DeSerialise(File.ReadAllText(fullPath)); + } + catch(Exception e) + { + logger.Error(e, "Error reading config file " + fullPath); + return default(T); + } + } + + public void SaveConfig(T config) + { + var type = typeof(T); + var fullPath = Path.Combine(GetAppDataFolder(), type.Name + ".json"); + try + { + var json = serializeService.Serialise(config); + if (!Directory.Exists(GetAppDataFolder())) + Directory.CreateDirectory(GetAppDataFolder()); + File.WriteAllText(fullPath, json); + } + catch (Exception e) + { + logger.Error(e, "Error reading config file " + fullPath); + } + } + + public string ApplicationFolder() + { + return Path.GetDirectoryName(Application.ExecutablePath); + } + + public string GetContentFolder() + { + // If we are debugging we can use the non copied content. + var dir = Path.Combine(ApplicationFolder(), "Content"); + if (!Directory.Exists(dir)) + { + dir = Path.Combine(ApplicationFolder(), "..\\..\\..\\Jackett\\Content"); + } + + return dir; + } + + public string GetVersion() + { + return Assembly.GetExecutingAssembly().GetName().Version.ToString(); + } + + public string GetAppDataFolder() + { + return GetAppDataFolderStatic(); + } + + /// + /// This is needed for the logger prior to ioc setup. + /// + /// + public static string GetAppDataFolderStatic() + { + return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Jackett"); + } + + public string GetIndexerConfigDir() + { + return Path.Combine(GetAppDataFolder(), "Indexers"); + } + + public string GetConfigFile() + { + return Path.Combine(GetAppDataFolder(), "config.json"); + } + + public string GetSonarrConfigFile() + { + return Path.Combine(GetAppDataFolder(), "sonarr_api.json"); + } + + + public JObject ReadServerSettingsFile() + { + var path = GetConfigFile(); + JObject jsonReply = new JObject(); + if (File.Exists(path)) + { + jsonReply = JObject.Parse(File.ReadAllText(path)); + // Port = (int)jsonReply["port"]; + // ListenPublic = (bool)jsonReply["public"]; + } + else + { + // jsonReply["port"] = Port; + // jsonReply["public"] = ListenPublic; + } + return jsonReply; + } + } +} diff --git a/src/Jackett/Services/IndexerManagerService.cs b/src/Jackett/Services/IndexerManagerService.cs new file mode 100644 index 000000000..718ea39da --- /dev/null +++ b/src/Jackett/Services/IndexerManagerService.cs @@ -0,0 +1,101 @@ +using Autofac; +using Jackett.Indexers; +using Jackett.Models; +using Newtonsoft.Json.Linq; +using NLog; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Services +{ + public interface IIndexerManagerService + { + void TestIndexer(string name); + void DeleteIndexer(string name); + IIndexer GetIndexer(string name); + IEnumerable GetAllIndexers(); + void SaveConfig(IIndexer indexer, JToken obj); + void InitIndexers(); + } + + public class IndexerManagerService : IIndexerManagerService + { + private IContainer container; + private IConfigurationService configService; + private Logger logger; + + public IndexerManagerService(IContainer c, IConfigurationService config, Logger l) + { + container = c; + configService = config; + logger = l; + } + + public void InitIndexers() + { + // Load the existing config for each indexer + foreach (var indexer in GetAllIndexers()) + { + var configFilePath = GetIndexerConfigFilePath(indexer); + if (File.Exists(configFilePath)) + { + var jsonString = JObject.Parse(File.ReadAllText(configFilePath)); + indexer.LoadFromSavedConfiguration(jsonString); + } + } + } + + public IIndexer GetIndexer(string name) + { + var indexer = GetAllIndexers().Where(i => string.Equals(i.DisplayName, name, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); + if (indexer == null) + { + logger.Error("Request for unknown indexer: " + name); + throw new Exception("Unknown indexer: " + name); + } + return indexer; + } + + public IEnumerable GetAllIndexers() + { + + return container.Resolve>().OrderBy(_ => _.DisplayName); + } + + public async void TestIndexer(string name) + { + var indexer = GetIndexer(name); + var browseQuery = new TorznabQuery(); + var results = await indexer.PerformQuery(browseQuery); + logger.Debug(string.Format("Found {0} releases from {1}", results.Length, indexer.DisplayName)); + if (results.Length == 0) + throw new Exception("Found no results while trying to browse this tracker"); + } + + public void DeleteIndexer(string name) + { + var indexer = GetIndexer(name); + var configPath = configService.GetIndexerConfigDir(); + File.Delete(configPath); + //Indexers.Remove(name); + //LoadMissingIndexers(); + } + + private string GetIndexerConfigFilePath(IIndexer indexer) + { + return Path.Combine(configService.GetIndexerConfigDir(), indexer.GetType().Name.ToLower() + ".json"); + } + + public void SaveConfig(IIndexer indexer, JToken obj) + { + var configFilePath = GetIndexerConfigFilePath(indexer); + if (!Directory.Exists(configService.GetIndexerConfigDir())) + Directory.CreateDirectory(configService.GetIndexerConfigDir()); + File.WriteAllText(configFilePath, obj.ToString()); + } + } +} diff --git a/src/Jackett/Services/ProcessService.cs b/src/Jackett/Services/ProcessService.cs new file mode 100644 index 000000000..1ef3bac96 --- /dev/null +++ b/src/Jackett/Services/ProcessService.cs @@ -0,0 +1,64 @@ +using NLog; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Services +{ + public interface IProcessService + { + void StartProcessAndLog(string exe, string args); + } + + public class ProcessService : IProcessService + { + private Logger logger; + + public ProcessService(Logger l) + { + logger = l; + } + + public void StartProcessAndLog(string exe, string args) + { + var startInfo = new ProcessStartInfo() + { + CreateNoWindow = true, + UseShellExecute = false, + FileName = exe, + Arguments = args, + RedirectStandardError = true, + RedirectStandardOutput = true, + RedirectStandardInput = true + }; + + var proc = Process.Start(startInfo); + proc.OutputDataReceived += proc_OutputDataReceived; + proc.ErrorDataReceived += proc_ErrorDataReceived; + proc.BeginErrorReadLine(); + proc.BeginOutputReadLine(); + proc.WaitForExit(); + proc.OutputDataReceived -= proc_OutputDataReceived; + proc.ErrorDataReceived -= proc_ErrorDataReceived; + } + + void proc_ErrorDataReceived(object sender, DataReceivedEventArgs e) + { + if (!string.IsNullOrWhiteSpace(e.Data)) + { + logger.Error(e.Data); + } + } + + void proc_OutputDataReceived(object sender, DataReceivedEventArgs e) + { + if (!string.IsNullOrWhiteSpace(e.Data)) + { + logger.Debug(e.Data); + } + } + } +} diff --git a/src/Jackett/Services/SerializeService.cs b/src/Jackett/Services/SerializeService.cs new file mode 100644 index 000000000..dacbf9ebb --- /dev/null +++ b/src/Jackett/Services/SerializeService.cs @@ -0,0 +1,35 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Services +{ + public interface ISerializeService + { + string Serialise(object obj); + T DeSerialise(string json); + } + + class SerializeService : ISerializeService + { + public string Serialise(object obj) + { + return JsonConvert.SerializeObject(obj,Formatting.Indented); + } + + public T DeSerialise(string json) + { + try + { + return JsonConvert.DeserializeObject(json); + } + catch + { + return default(T); + } + } + } +} diff --git a/src/Jackett/Services/ServerService.cs b/src/Jackett/Services/ServerService.cs new file mode 100644 index 000000000..2ad5724d8 --- /dev/null +++ b/src/Jackett/Services/ServerService.cs @@ -0,0 +1,136 @@ +using Autofac; +using Jackett.Models.Config; +using Jackett.Services; +using Microsoft.Owin.Hosting; +using Newtonsoft.Json.Linq; +using NLog; +using NLog.Config; +using NLog.Targets; +using NLog.Windows.Forms; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Services +{ + public interface IServerService + { + void Start(); + void Stop(); + void ReserveUrls(bool doInstall = true); + ServerConfig Config { get; } + } + + public class ServerService : IServerService + { + private ServerConfig config; + + private IDisposable _server = null; + + private IIndexerManagerService indexerService; + private IProcessService processService; + private ISerializeService serializeService; + private IConfigurationService configService; + private Logger logger; + + public ServerService(IIndexerManagerService i, IProcessService p, ISerializeService s, IConfigurationService c, Logger l) + { + indexerService = i; + processService = p; + serializeService = s; + configService = c; + logger = l; + + LoadConfig(); + } + + public ServerConfig Config + { + get { return config; } + } + + private void LoadConfig() + { + // Load config + config = configService.GetConfig(); + if (config == null) + { + config = new ServerConfig(); + } + + if (string.IsNullOrWhiteSpace(config.APIKey)) + { + // Check for legacy key config + var apiKeyFile = Path.Combine(configService.GetAppDataFolder(), "api_key.txt"); + if (File.Exists(apiKeyFile)) + { + config.APIKey = File.ReadAllText(apiKeyFile); + } + + // Check for legacy settings + + var path = Path.Combine(configService.GetAppDataFolder(), "config.json"); ; + var jsonReply = new JObject(); + if (File.Exists(path)) + { + jsonReply = JObject.Parse(File.ReadAllText(path)); + config.Port = (int)jsonReply["port"]; + config.AllowExternal = (bool)jsonReply["public"]; + } + + if (string.IsNullOrWhiteSpace(config.APIKey)) + { + config.APIKey = config.GenerateApi(); + } + + configService.SaveConfig(config); + } + } + + public void Start() + { + // Allow all SSL.. sucks I know but mono on linux is having problems without it.. + ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true; + + // Load indexers + indexerService.InitIndexers(); + + // Start the server + logger.Debug("Starting web server at " + config.GetListenAddress()); + _server = WebApp.Start(url: config.GetListenAddress()); + logger.Debug("Web server started"); + } + + public void ReserveUrls(bool doInstall = true) + { + logger.Debug("Unreserving Urls"); + RunNetSh(string.Format("http delete urlacl {0}", config.GetListenAddress(false))); + RunNetSh(string.Format("http delete urlacl {0}", config.GetListenAddress(true))); + if (doInstall) + { + logger.Debug("Reserving Urls"); + RunNetSh(string.Format("http add urlacl {0} sddl=D:(A;;GX;;;S-1-1-0)", config.GetListenAddress())); + logger.Debug("Urls reserved"); + } + } + + private void RunNetSh(string args) + { + processService.StartProcessAndLog("netsh.exe", args); + } + + public void Stop() + { + if (_server != null) + { + _server.Dispose(); + } + } + } +} diff --git a/src/Jackett/Services/ServiceConfigService.cs b/src/Jackett/Services/ServiceConfigService.cs new file mode 100644 index 000000000..12886e931 --- /dev/null +++ b/src/Jackett/Services/ServiceConfigService.cs @@ -0,0 +1,114 @@ +using NLog; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Configuration.Install; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.ServiceProcess; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett.Services +{ + public interface IServiceConfigService + { + void Install(); + void Uninstall(); + } + + class ServiceConfigService : IServiceConfigService + { + private const string NAME = "Jackett"; + private const string DESCRIPTION = "Additional indexers for Sonarr"; + private const string SERVICEEXE = "JackettService.exe"; + + private IConfigurationService configService; + private Logger logger; + + public ServiceConfigService(IConfigurationService c, Logger l) + { + configService = c; + logger = l; + } + + public bool Exists() + { + return GetService(NAME) != null; + } + + public ServiceController GetService(string serviceName) + { + return ServiceController.GetServices().FirstOrDefault(c => String.Equals(c.ServiceName, serviceName, StringComparison.InvariantCultureIgnoreCase)); + } + + public void Install() + { + if (Exists()) + { + + } + else + { + var installer = new ServiceProcessInstaller + { + Account = ServiceAccount.NetworkService + }; + + var serviceInstaller = new ServiceInstaller(); + + var exePath = Path.Combine(configService.ApplicationFolder(), SERVICEEXE); + if (!File.Exists(exePath) && Debugger.IsAttached) + { + exePath = Path.Combine(configService.ApplicationFolder(), "..\\..\\..\\Jackett.Service\\bin\\Debug", SERVICEEXE); + } + + string[] cmdline = { @"/assemblypath=" + exePath}; + + var context = new InstallContext("jackettservice_install.log", cmdline); + serviceInstaller.Context = context; + serviceInstaller.DisplayName = NAME; + serviceInstaller.ServiceName = NAME; + serviceInstaller.Description = DESCRIPTION; + serviceInstaller.StartType = ServiceStartMode.Automatic; + serviceInstaller.Parent = installer; + + serviceInstaller.Install(new ListDictionary()); + } + } + + public void Uninstall() + { + Stop(); + + var serviceInstaller = new ServiceInstaller(); + + var context = new InstallContext("jackettservice_uninstall.log", null); + serviceInstaller.Context = context; + serviceInstaller.ServiceName = NAME; + serviceInstaller.Uninstall(null); + + logger.Info("The service was uninstalled."); + + } + + public void Stop() + { + var service = GetService(NAME); + if (service.Status != ServiceControllerStatus.Stopped) + { + service.Stop(); + service.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(60)); + + service.Refresh(); + if (service.Status == ServiceControllerStatus.Stopped) + logger.Info("Service stopped."); + else + logger.Error("Failed to stop the service"); + } + else + logger.Warn("The service was already stopped"); + } + } +} diff --git a/src/Jackett/Services/SpinService.cs b/src/Jackett/Services/SpinService.cs new file mode 100644 index 000000000..8d8e5d0b0 --- /dev/null +++ b/src/Jackett/Services/SpinService.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Jackett.Services +{ + public interface IRunTimeService + { + void Spin(); + } + + class RunTimeService : IRunTimeService + { + private bool isRunning = true; + + public void Spin() + { + while (isRunning) + { + Thread.Sleep(2000); + } + } + } +} diff --git a/src/Jackett/Startup.cs b/src/Jackett/Startup.cs new file mode 100644 index 000000000..43b456328 --- /dev/null +++ b/src/Jackett/Startup.cs @@ -0,0 +1,57 @@ +using Owin; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Web.Http; +using Autofac.Integration.WebApi; +using Microsoft.Owin; +using Jackett; +using Microsoft.Owin.StaticFiles; +using Microsoft.Owin.FileSystems; +using Autofac; +using Jackett.Services; + +[assembly: OwinStartup(typeof(Startup))] +namespace Jackett +{ + public class Startup + { + public void Configuration(IAppBuilder appBuilder) + { + // Configure Web API for self-host. + var config = new HttpConfiguration(); + config.DependencyResolver = new AutofacWebApiDependencyResolver(Engine.GetContainer()); + config.MapHttpAttributeRoutes(); + + config.Routes.MapHttpRoute( + name: "Admin", + routeTemplate: "admin/{action}", + defaults: new { controller = "Admin" } + ); + + config.Routes.MapHttpRoute( + name: "api", + routeTemplate: "api/{indexerName}", + defaults: new { controller = "API", action = "Call" } + ); + + config.Routes.MapHttpRoute( + name: "download", + routeTemplate: "api/{indexerName}/download/{path}/download.torrent", + defaults: new { controller = "Download", action = "Download" } + ); + + appBuilder.UseFileServer(new FileServerOptions + { + RequestPath = new PathString(string.Empty), + FileSystem = new PhysicalFileSystem(Engine.ConfigService.GetContentFolder()), + EnableDirectoryBrowsing = true, + }); + + appBuilder.UseWebApi(config); + } + } +} diff --git a/src/Jackett/BrowserUtil.cs b/src/Jackett/Utils/BrowserUtil.cs similarity index 94% rename from src/Jackett/BrowserUtil.cs rename to src/Jackett/Utils/BrowserUtil.cs index 82154b176..669b1e346 100644 --- a/src/Jackett/BrowserUtil.cs +++ b/src/Jackett/Utils/BrowserUtil.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Jackett +namespace Jackett.Utils { public static class BrowserUtil { diff --git a/src/Jackett/ParseUtil.cs b/src/Jackett/Utils/ParseUtil.cs similarity index 98% rename from src/Jackett/ParseUtil.cs rename to src/Jackett/Utils/ParseUtil.cs index 9b62c0027..c96e2be7a 100644 --- a/src/Jackett/ParseUtil.cs +++ b/src/Jackett/Utils/ParseUtil.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Jackett +namespace Jackett.Utils { public static class ParseUtil { diff --git a/src/Jackett/ServerUtil.cs b/src/Jackett/Utils/ServerUtil.cs similarity index 99% rename from src/Jackett/ServerUtil.cs rename to src/Jackett/Utils/ServerUtil.cs index 8f3e6c02f..a65f1f2f7 100644 --- a/src/Jackett/ServerUtil.cs +++ b/src/Jackett/Utils/ServerUtil.cs @@ -5,7 +5,7 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; -namespace Jackett +namespace Jackett.Utils { public static class ServerUtil { diff --git a/src/Jackett/WebApi.cs b/src/Jackett/WebApi.cs deleted file mode 100644 index 2f56a5d58..000000000 --- a/src/Jackett/WebApi.cs +++ /dev/null @@ -1,325 +0,0 @@ -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Reflection; -using System.Security.Cryptography; -using System.Text; -using System.Threading.Tasks; -using System.Web; - -namespace Jackett -{ - public class WebApi - { - static string WebContentFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WebContent"); - static string[] StaticFiles = Directory.EnumerateFiles(WebContentFolder, "*", SearchOption.AllDirectories).ToArray(); - public Server server; - - public enum WebApiMethod - { - GetConfigForm, - ConfigureIndexer, - GetIndexers, - TestIndexer, - DeleteIndexer, - GetSonarrConfig, - ApplySonarrConfig, - GetJackettConfig, - ApplyJackettConfig, - JackettRestart, - } - - static Dictionary WebApiMethods = new Dictionary { - { "get_config_form", WebApiMethod.GetConfigForm }, - { "configure_indexer", WebApiMethod.ConfigureIndexer }, - { "get_indexers", WebApiMethod.GetIndexers }, - { "test_indexer", WebApiMethod.TestIndexer }, - { "delete_indexer", WebApiMethod.DeleteIndexer }, - { "get_sonarr_config", WebApiMethod.GetSonarrConfig }, - { "apply_sonarr_config", WebApiMethod.ApplySonarrConfig }, - { "get_jackett_config",WebApiMethod.GetJackettConfig}, - { "apply_jackett_config",WebApiMethod.ApplyJackettConfig}, - { "jackett_restart", WebApiMethod.JackettRestart }, - }; - - IndexerManager indexerManager; - - public WebApi(IndexerManager indexerManager) - { - this.indexerManager = indexerManager; - } - - public async Task HandleRequest(HttpListenerContext context) - { - string path = context.Request.Url.AbsolutePath.TrimStart('/'); - if (path == "") - path = "index.html"; - - var sysPath = Path.Combine(WebContentFolder, path.Replace("/", Path.DirectorySeparatorChar.ToString())); - if (Array.IndexOf(StaticFiles, sysPath) > -1) - { - await ServeStaticFile(context, path); - return true; - } - - WebApi.WebApiMethod apiMethod; - if (WebApi.WebApiMethods.TryGetValue(path, out apiMethod)) - { - await ProcessWebApiRequest(context, apiMethod); - return true; - } - - return false; - } - - async Task ServeStaticFile(HttpListenerContext context, string file) - { - var contentFile = File.ReadAllBytes(Path.Combine(WebContentFolder, file)); - context.Response.ContentType = MimeMapping.GetMimeMapping(file); - context.Response.StatusCode = (int)HttpStatusCode.OK; - try - { - await context.Response.OutputStream.WriteAsync(contentFile, 0, contentFile.Length); - } - catch (HttpListenerException) - { - } - } - - async Task ReadPostDataJson(Stream stream) - { - string postData = await new StreamReader(stream).ReadToEndAsync(); - return JObject.Parse(postData); - } - - delegate Task HandlerTask(HttpListenerContext context); - - async Task ProcessWebApiRequest(HttpListenerContext context, WebApiMethod method) - { - context.Response.ContentType = "text/json"; - context.Response.StatusCode = (int)HttpStatusCode.OK; - - HandlerTask handlerTask; - - switch (method) - { - case WebApiMethod.GetConfigForm: - handlerTask = HandleConfigForm; - break; - case WebApiMethod.ConfigureIndexer: - handlerTask = HandleConfigureIndexer; - break; - case WebApiMethod.GetIndexers: - handlerTask = HandleGetIndexers; - break; - case WebApiMethod.TestIndexer: - handlerTask = HandleTestIndexer; - break; - case WebApiMethod.DeleteIndexer: - handlerTask = HandleDeleteIndexer; - break; - case WebApiMethod.ApplyJackettConfig: - handlerTask = HandleApplyJackettConfig; - break; - case WebApiMethod.GetJackettConfig: - handlerTask = HandleJackettConfig; - break; - case WebApiMethod.JackettRestart: - handlerTask = HandleJackettRestart; - break; - default: - handlerTask = HandleInvalidApiMethod; - break; - } - JToken jsonReply = await handlerTask(context); - await ReplyWithJson(context, jsonReply, method.ToString()); - } - - async Task ReplyWithJson(HttpListenerContext context, JToken json, string apiCall) - { - try - { - byte[] jsonBytes = Encoding.UTF8.GetBytes(json.ToString()); - await context.Response.OutputStream.WriteAsync(jsonBytes, 0, jsonBytes.Length); - } - catch (Exception ex) - { - Console.WriteLine("Error writing json to stream for API call " + apiCall + Environment.NewLine + ex.ToString()); - } - } - - Task HandleInvalidApiMethod(HttpListenerContext context) - { - JToken jsonReply = new JObject(); - jsonReply["result"] = "error"; - jsonReply["error"] = "Invalid API method"; - return Task.FromResult(jsonReply); - } - - async Task HandleConfigForm(HttpListenerContext context) - { - JToken jsonReply = new JObject(); - try - { - var postData = await ReadPostDataJson(context.Request.InputStream); - string indexerString = (string)postData["indexer"]; - var indexer = indexerManager.GetIndexer(indexerString); - var config = await indexer.GetConfigurationForSetup(); - jsonReply["config"] = config.ToJson(); - jsonReply["name"] = indexer.DisplayName; - jsonReply["result"] = "success"; - } - catch (Exception ex) - { - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } - return jsonReply; - } - - async Task HandleConfigureIndexer(HttpListenerContext context) - { - JToken jsonReply = new JObject(); - try - { - var postData = await ReadPostDataJson(context.Request.InputStream); - string indexerString = (string)postData["indexer"]; - var indexer = indexerManager.GetIndexer(indexerString); - jsonReply["name"] = indexer.DisplayName; - await indexer.ApplyConfiguration(postData["config"]); - await indexerManager.TestIndexer(indexer); - jsonReply["result"] = "success"; - } - catch (Exception ex) - { - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - if (ex is ExceptionWithConfigData) - { - jsonReply["config"] = ((ExceptionWithConfigData)ex).ConfigData.ToJson(); - } - } - return jsonReply; - } - - Task HandleGetIndexers(HttpListenerContext context) - { - JToken jsonReply = new JObject(); - try - { - jsonReply["result"] = "success"; - jsonReply["api_key"] = ApiKey.CurrentKey; - jsonReply["app_version"] = Assembly.GetExecutingAssembly().GetName().Version.ToString(); - JArray items = new JArray(); - foreach (var i in indexerManager.Indexers.OrderBy(_ => _.Key)) - { - var indexer = i.Value; - var item = new JObject(); - item["id"] = i.Key; - item["name"] = indexer.DisplayName; - item["description"] = indexer.DisplayDescription; - item["configured"] = indexer.IsConfigured; - item["site_link"] = indexer.SiteLink; - items.Add(item); - } - jsonReply["items"] = items; - } - catch (Exception ex) - { - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } - return Task.FromResult(jsonReply); - } - - async Task HandleTestIndexer(HttpListenerContext context) - { - JToken jsonReply = new JObject(); - try - { - var postData = await ReadPostDataJson(context.Request.InputStream); - string indexerString = (string)postData["indexer"]; - var indexer = indexerManager.GetIndexer(indexerString); - jsonReply["name"] = indexer.DisplayName; - await indexerManager.TestIndexer(indexer); - jsonReply["result"] = "success"; - } - catch (Exception ex) - { - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } - return jsonReply; - } - - async Task HandleDeleteIndexer(HttpListenerContext context) - { - JToken jsonReply = new JObject(); - try - { - var postData = await ReadPostDataJson(context.Request.InputStream); - string indexerString = (string)postData["indexer"]; - indexerManager.DeleteIndexer(indexerString); - } - catch (Exception ex) - { - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } - return jsonReply; - } - - - //Jacket port functions - Task HandleJackettConfig(HttpListenerContext context) - { - JObject jsonReply = new JObject(); - try - { - jsonReply["config"] = server.ReadServerSettingsFile(); - jsonReply["result"] = "success"; - } - catch (CustomException ex) - { - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } - catch (Exception ex) - { - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } - return Task.FromResult(jsonReply); - } - - async Task HandleApplyJackettConfig(HttpListenerContext context) - { - JToken jsonReply = new JObject(); - - try - { - var postData = await ReadPostDataJson(context.Request.InputStream); - int port = await server.ApplyPortConfiguration(postData); - jsonReply["result"] = "success"; - jsonReply["port"] = port; - } - catch (Exception ex) - { - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } - return jsonReply; - } - - async Task HandleJackettRestart(HttpListenerContext context) - { - Program.RestartServer(); - return null; - } - - - } -} diff --git a/src/Jackett/packages.config b/src/Jackett/packages.config index efab650c9..a4f77e87c 100644 --- a/src/Jackett/packages.config +++ b/src/Jackett/packages.config @@ -1,7 +1,22 @@  - - - - + + + + + + + + + + + + + + + + + + + \ No newline at end of file