Auto update #8

This commit is contained in:
WhatFox 2015-11-09 21:59:16 +00:00
parent 35580224c7
commit a9e14cc4af
21 changed files with 610 additions and 18 deletions

1
.gitignore vendored
View File

@ -196,3 +196,4 @@ FakesAssemblies/
*.opt
/Build.mono
/Build.windows
/Output

View File

@ -11,6 +11,8 @@ copy /Y src\Jackett.Service\bin\Release\JackettService.exe build.windows\Jackett
copy /Y src\Jackett.Service\bin\Release\JackettService.exe.config build.windows\JackettService.exe.config
copy /Y src\Jackett.Tray\bin\Release\JackettTray.exe build.windows\JackettTray.exe
copy /Y src\Jackett.Tray\bin\Release\JackettTray.exe.config build.windows\JackettTray.exe.config
copy /Y src\Jackett.Updater\bin\Release\JackettUpdater.exe build.windows\JackettUpdater.exe
copy /Y src\Jackett.Updater\bin\Release\JackettUpdater.exe.config build.windows\JackettUpdater.exe.config
copy /Y LICENSE build.windows\LICENSE
copy /Y README.md build.windows\README.md
@ -25,6 +27,8 @@ copy /Y src\Jackett.Service\bin\Release\JackettService.exe build.mono\JackettSer
copy /Y src\Jackett.Service\bin\Release\JackettService.exe.config build.mono\JackettService.exe.config
copy /Y src\Jackett.Tray\bin\Release\JackettTray.exe build.mono\JackettTray.exe
copy /Y src\Jackett.Tray\bin\Release\JackettTray.exe.config build.mono\JackettTray.exe.config
copy /Y src\Jackett.Updater\bin\Release\JackettUpdater.exe build.mono\JackettUpdater.exe
copy /Y src\Jackett.Updater\bin\Release\JackettUpdater.exe.config build.mono\JackettUpdater.exe.config
copy /Y LICENSE build.mono\LICENSE
copy /Y README.md build.mono\README.md
copy /Y Upstart.config build.mono\Upstart.config

View File

@ -24,9 +24,10 @@ DefaultGroupName={#MyAppName}
DisableProgramGroupPage=yes
OutputBaseFilename=setup
SetupIconFile=src\Jackett.Console\jackett.ico
UninstallDisplayIcon={app}\JackettConsole.exe
UninstallDisplayIcon={userappdata}\Jackett\JackettConsole.exe
Compression=lzma
SolidCompression=yes
DisableDirPage=yes
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
@ -36,26 +37,27 @@ Name: "windowsService"; Description: "Install as a Windows Service"
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Files]
Source: "build.windows\JackettTray.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "build.windows\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "build.windows\JackettTray.exe"; DestDir: "{userappdata}\Jackett"; Flags: ignoreversion
Source: "build.windows\JackettUpdater.exe"; DestDir: "{userappdata}\Jackett"; Flags: ignoreversion
Source: "build.windows\*"; DestDir: "{userappdata}\Jackett"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{group}\{#MyAppName}"; Filename: "{userappdata}\Jackett\{#MyAppExeName}"
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
Name: "{commondesktop}\{#MyAppName}"; Filename: "{userappdata}\Jackett\{#MyAppExeName}"; Tasks: desktopicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
Filename: "{userappdata}\Jackett\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
[Run]
Filename: "{app}\JackettConsole.exe"; Parameters: "--Uninstall"; Flags: waituntilterminated;
Filename: "{app}\JackettConsole.exe"; Parameters: "--ReserveUrls"; Flags: waituntilterminated;
Filename: "{app}\JackettConsole.exe"; Parameters: "--MigrateSettings"; Flags: waituntilterminated;
Filename: "{app}\JackettConsole.exe"; Parameters: "--Install"; Flags: waituntilterminated; Tasks: windowsService
Filename: "{app}\JackettConsole.exe"; Parameters: "--Start"; Flags: waituntilterminated; Tasks: windowsService
Filename: "{userappdata}\Jackett\JackettConsole.exe"; Parameters: "--Uninstall"; Flags: waituntilterminated;
Filename: "{userappdata}\Jackett\JackettConsole.exe"; Parameters: "--ReserveUrls"; Flags: waituntilterminated;
Filename: "{userappdata}\Jackett\JackettConsole.exe"; Parameters: "--MigrateSettings"; Flags: waituntilterminated;
Filename: "{userappdata}\Jackett\JackettConsole.exe"; Parameters: "--Install"; Flags: waituntilterminated; Tasks: windowsService
Filename: "{userappdata}\Jackett\JackettConsole.exe"; Parameters: "--Start"; Flags: waituntilterminated; Tasks: windowsService
[UninstallRun]
Filename: "{app}\JackettConsole.exe"; Parameters: "--Uninstall"; Flags: waituntilterminated skipifdoesntexist
Filename: "{userappdata}\Jackett\JackettConsole.exe"; Parameters: "--Uninstall"; Flags: waituntilterminated skipifdoesntexist

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Http.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A61E311A-6F8B-4497-B5E4-2EA8994C7BD8}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Jackett.Updater</RootNamespace>
<AssemblyName>JackettUpdater</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>jackett.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="CommandLine, Version=1.9.71.2, Culture=neutral, PublicKeyToken=de6f01bd326f8c32, processorArchitecture=MSIL">
<HintPath>..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.2.0\lib\net45\NLog.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UpdaterConsoleOptions.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Jackett\Jackett.csproj">
<Project>{e636d5f8-68b4-4903-b4ed-ccfd9c9e899f}</Project>
<Name>Jackett</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="jackett.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,143 @@
using CommandLine;
using Jackett.Services;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Jackett.Updater
{
class Program
{
static void Main(string[] args)
{
new Program().Run(args);
}
private void Run(string[] args)
{
Console.WriteLine("Jackett Updater v" + GetCurrentVersion());
Console.WriteLine("Waiting for Jackett to close..");
Thread.Sleep(2000);
try {
var options = new UpdaterConsoleOptions();
if (Parser.Default.ParseArguments(args, options))
{
ProcessUpdate(options);
}
else
{
Console.WriteLine("Failed to process update arguments!: " + string.Join(" ", args));
Console.ReadKey();
}
}
catch (Exception e)
{
Console.WriteLine("Exception applying update: " + e.Message);
Console.ReadKey();
}
}
private string GetCurrentVersion()
{
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
return fvi.FileVersion;
}
private void ProcessUpdate(UpdaterConsoleOptions options)
{
var updateLocation = GetUpdateLocation();
if(!(updateLocation.EndsWith("\\") || updateLocation.EndsWith("/")))
{
updateLocation += Path.DirectorySeparatorChar;
}
var isWindows = System.Environment.OSVersion.Platform != PlatformID.Unix;
var trayRunning = false;
var trayProcesses = Process.GetProcessesByName("JackettTray.exe");
if (isWindows)
{
if (trayProcesses.Count() > 0)
{
foreach (var proc in trayProcesses)
{
try
{
Console.WriteLine("Killing tray process " + proc.Id);
proc.Kill();
trayRunning = true;
}
catch { }
}
}
}
var files = Directory.GetFiles(updateLocation, "*.*", SearchOption.AllDirectories);
foreach(var file in files)
{
var fileName = Path.GetFileName(file).ToLowerInvariant();
if (fileName.EndsWith(".zip") ||
fileName.EndsWith(".tar") ||
fileName.EndsWith(".gz"))
{
continue;
}
Console.WriteLine("Copying " + fileName);
var dest = Path.Combine(options.Path, file.Substring(updateLocation.Length));
File.Copy(file, dest, true);
}
if (trayRunning)
{
var startInfo = new ProcessStartInfo()
{
Arguments = options.Args,
FileName = Path.Combine(options.Path, "JackettTray.exe"),
UseShellExecute = true
};
Process.Start(startInfo);
}
if(string.Equals(options.Type, "JackettService.exe", StringComparison.InvariantCultureIgnoreCase))
{
var serviceHelper = new ServiceConfigService(null, null);
if (serviceHelper.ServiceExists())
{
serviceHelper.Start();
}
} else
{
var startInfo = new ProcessStartInfo()
{
Arguments = options.Args,
FileName = Path.Combine(options.Path, "JackettConsole.exe"),
UseShellExecute = true
};
if (!isWindows)
{
startInfo.Arguments = startInfo.FileName + " " + startInfo.Arguments;
startInfo.FileName = "mono";
}
Process.Start(startInfo);
}
}
private string GetUpdateLocation()
{
var location = new Uri(Assembly.GetEntryAssembly().GetName().CodeBase);
return new FileInfo(location.AbsolutePath).DirectoryName;
}
}
}

View File

@ -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.Updater")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Jackett.Updater")]
[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("a61e311a-6f8b-4497-b5e4-2ea8994c7bd8")]
// 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("0.0.0.0")]
[assembly: AssemblyFileVersion("0.0.0.0")]

View File

@ -0,0 +1,21 @@
using CommandLine;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Jackett.Updater
{
public class UpdaterConsoleOptions
{
[Option('p', "Path", HelpText = "Install location")]
public string Path { get; set; }
[Option('t', "Type", HelpText = "Install type")]
public string Type { get; set; }
[Option('a', "Args", HelpText = "Launch arguments")]
public string Args { get; set; }
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="CommandLineParser" version="1.9.71" targetFramework="net45" />
<package id="NLog" version="4.2.0" targetFramework="net45" />
</packages>

View File

@ -27,6 +27,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jackett.Distribution", "Jac
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Website", "Website\Website.csproj", "{6B6AB1B0-5ABD-4696-A3D2-70E991174625}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jackett.Updater", "Jackett.Updater\Jackett.Updater.csproj", "{A61E311A-6F8B-4497-B5E4-2EA8994C7BD8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -65,6 +67,10 @@ Global
{6B6AB1B0-5ABD-4696-A3D2-70E991174625}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6B6AB1B0-5ABD-4696-A3D2-70E991174625}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6B6AB1B0-5ABD-4696-A3D2-70E991174625}.Release|Any CPU.Build.0 = Release|Any CPU
{A61E311A-6F8B-4497-B5E4-2EA8994C7BD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A61E311A-6F8B-4497-B5E4-2EA8994C7BD8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A61E311A-6F8B-4497-B5E4-2EA8994C7BD8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A61E311A-6F8B-4497-B5E4-2EA8994C7BD8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -220,7 +220,7 @@ hr {
text-align: center;
}
#jackett-allowext {
#jackett-allowext, #jackett-allowupdate {
width: 25px;
}

View File

@ -24,6 +24,7 @@ function loadJackettSettings() {
$("#jackett-port").val(data.config.port);
$("#jackett-savedir").val(data.config.blackholedir);
$("#jackett-allowext").attr('checked', data.config.external);
$("#jackett-allowupdate").attr('checked', data.config.updatedisabled);
var password = data.config.password;
$("#jackett-adminpwd").val(password);
if (password != null && password != '') {
@ -544,9 +545,11 @@ function bindUIButtons() {
$("#change-jackett-port").click(function () {
var jackett_port = $("#jackett-port").val();
var jackett_external = $("#jackett-allowext").is(':checked');
var jackett_update = $("#jackett-allowupdate").is(':checked');
var jsonObject = {
port: jackett_port,
external: jackett_external,
updatedisabled: jackett_update,
blackholedir: $("#jackett-savedir").val()
};
var jqxhr = $.post("/admin/set_config", JSON.stringify(jsonObject), function (data) {
@ -570,6 +573,19 @@ function bindUIButtons() {
});
});
$("#trigger-updater").click(function () {
var jqxhr = $.get("/admin/trigger_update", function (data) {
if (data.result == "error") {
doNotify("Error: " + data.error, "danger", "glyphicon glyphicon-alert");
return;
} else {
doNotify("Updater triggered see log for details..", "success", "glyphicon glyphicon-ok");
}
}).fail(function () {
doNotify("Request to Jackett server failed", "danger", "glyphicon glyphicon-alert");
});
});
$("#change-jackett-password").click(function () {
var password = $("#jackett-adminpwd").val();
var jsonObject = { password: password };

View File

@ -61,7 +61,7 @@
<hr />
<h3>Jackett Configuration</h3>
<div class="input-area">
<span class="input-header">Admin Password: </span>
<span class="input-header">Admin password: </span>
<input id="jackett-adminpwd" class="form-control input-right" type="password" value="" placeholder="Blank to disable" />
<button id="change-jackett-password" class="btn btn-primary btn-sm">
<i class="fa fa-user-secret"></i> Set Password <span class="glyphicon glyphicon-ok-wrench" aria-hidden="true"></span>
@ -88,6 +88,13 @@
<span class="input-header">External access: </span>
<input id="jackett-allowext" class="form-control input-right" type="checkbox" />
</div>
<div class="input-area">
<span class="input-header">Disable auto update: </span>
<input id="jackett-allowupdate" class="form-control input-right" type="checkbox" />
<button id="trigger-updater" class="btn btn-warning btn-sm">
<i class="fa fa-wrench"></i> Check for updates <span class="glyphicon glyphicon-ok-wrench" aria-hidden="true"></span>
</button>
</div>
<hr />
<div id="footer">
Jackett Version <span id="app-version"></span>

View File

@ -39,8 +39,9 @@ namespace Jackett.Controllers
private ICacheService cacheService;
private Logger logger;
private ILogCacheService logCache;
private IUpdateService updater;
public AdminController(IConfigurationService config, IIndexerManagerService i, IServerService ss, ISecuityService s, IProcessService p, ICacheService c, Logger l, ILogCacheService lc)
public AdminController(IConfigurationService config, IIndexerManagerService i, IServerService ss, ISecuityService s, IProcessService p, ICacheService c, Logger l, ILogCacheService lc, IUpdateService u)
{
this.config = config;
indexerService = i;
@ -50,6 +51,7 @@ namespace Jackett.Controllers
cacheService = c;
logger = l;
logCache = lc;
updater = u;
}
private async Task<JToken> ReadPostDataJson()
@ -291,6 +293,15 @@ namespace Jackett.Controllers
return Json(jsonReply);
}
[Route("trigger_update")]
[HttpGet]
public IHttpActionResult TriggerUpdates()
{
var jsonReply = new JObject();
updater.CheckForUpdatesNow();
return Json(jsonReply);
}
[Route("get_jackett_config")]
[HttpGet]
public IHttpActionResult GetConfig()
@ -303,6 +314,7 @@ namespace Jackett.Controllers
cfg["external"] = serverService.Config.AllowExternal;
cfg["api_key"] = serverService.Config.APIKey;
cfg["blackholedir"] = serverService.Config.BlackholeDir;
cfg["updatedisabled"] = serverService.Config.UpdateDisabled;
cfg["password"] = string.IsNullOrEmpty(serverService.Config.AdminPassword) ? string.Empty : serverService.Config.AdminPassword.Substring(0, 10);
jsonReply["config"] = cfg;
@ -331,8 +343,9 @@ namespace Jackett.Controllers
int port = (int)postData["port"];
bool external = (bool)postData["external"];
string saveDir = (string)postData["blackholedir"];
bool updateDisabled = (bool)postData["updatedisabled"];
if (port != Engine.Server.Config.Port || external != Engine.Server.Config.AllowExternal)
if (port != Engine.Server.Config.Port || external != Engine.Server.Config.AllowExternal || Engine.Server.Config.UpdateDisabled != updateDisabled)
{
if (ServerUtil.RestrictedPorts.Contains(port))
{
@ -344,6 +357,7 @@ namespace Jackett.Controllers
// Save port to the config so it can be picked up by the if needed when running as admin below.
Engine.Server.Config.AllowExternal = external;
Engine.Server.Config.Port = port;
Engine.Server.Config.UpdateDisabled = updateDisabled;
Engine.Server.SaveConfig();
// On Windows change the url reservations

View File

@ -82,6 +82,10 @@
<HintPath>..\packages\CsQuery.1.3.4\lib\net40\CsQuery.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.AspNet.Identity.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll</HintPath>
<Private>True</Private>
@ -126,6 +130,10 @@
<HintPath>..\packages\NLog.Windows.Forms.4.0\lib\net35\NLog.Windows.Forms.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Octokit, Version=0.16.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Octokit.0.16.0\lib\net45\Octokit.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL">
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
<Private>True</Private>
@ -262,6 +270,7 @@
<Compile Include="Services\CacheService.cs" />
<Compile Include="Services\LogCacheService.cs" />
<Compile Include="Services\ProtectionService.cs" />
<Compile Include="Services\UpdateService.cs" />
<Compile Include="Utils\Clients\BaseWebResult.cs" />
<Compile Include="Utils\Clients\UnixLibCurlWebClient.cs" />
<Compile Include="Utils\Clients\WebByteResult.cs" />

View File

@ -21,6 +21,9 @@ namespace Jackett.Models.Config
public string AdminPassword { get; set; }
public string InstanceId { get; set; }
public string BlackholeDir { get; set; }
public string GitHubUsername { get; set; }
public string GitHubPassword { get; set; }
public bool UpdateDisabled { get; set; }
public string[] GetListenAddresses(bool? external = null)
{

View File

@ -47,8 +47,9 @@ namespace Jackett.Services
private IConfigurationService configService;
private Logger logger;
private IWebClient client;
private IUpdateService updater;
public ServerService(IIndexerManagerService i, IProcessService p, ISerializeService s, IConfigurationService c, Logger l, IWebClient w)
public ServerService(IIndexerManagerService i, IProcessService p, ISerializeService s, IConfigurationService c, Logger l, IWebClient w, IUpdateService u)
{
indexerService = i;
processService = p;
@ -56,6 +57,7 @@ namespace Jackett.Services
configService = c;
logger = l;
client = w;
updater = u;
LoadConfig();
}
@ -139,6 +141,7 @@ namespace Jackett.Services
config.GetListenAddresses().ToList().ForEach(u => startOptions.Urls.Add(u));
_server = WebApp.Start<Startup>(startOptions);
logger.Debug("Web server started");
updater.StartUpdateChecker();
}
public void ReserveUrls(bool doInstall = true)

View File

@ -22,7 +22,7 @@ namespace Jackett.Services
void Stop();
}
class ServiceConfigService : IServiceConfigService
public class ServiceConfigService : IServiceConfigService
{
private const string NAME = "Jackett";
private const string DESCRIPTION = "Additional indexers for Sonarr";

View File

@ -0,0 +1,207 @@
using ICSharpCode.SharpZipLib.GZip;
using ICSharpCode.SharpZipLib.Tar;
using ICSharpCode.SharpZipLib.Zip;
using Jackett.Models.Config;
using Jackett.Utils.Clients;
using NLog;
using Octokit;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Jackett.Services
{
public interface IUpdateService
{
void StartUpdateChecker();
void CheckForUpdatesNow();
}
public class UpdateService: IUpdateService
{
Logger logger;
IWebClient client;
IConfigurationService configService;
ManualResetEvent locker = new ManualResetEvent(false);
public UpdateService(Logger l, IWebClient c, IConfigurationService cfg)
{
logger = l;
client = c;
configService = cfg;
}
private string ExePath()
{
var location = new Uri(Assembly.GetEntryAssembly().GetName().CodeBase);
return new FileInfo(location.AbsolutePath).FullName;
}
public void StartUpdateChecker()
{
Task.Factory.StartNew(UpdateWorkerThread);
}
public void CheckForUpdatesNow()
{
locker.Set();
}
private async void UpdateWorkerThread()
{
while (true)
{
locker.WaitOne((int)new TimeSpan(24, 0, 0).TotalMilliseconds);
locker.Reset();
await CheckForUpdates();
}
}
private async Task CheckForUpdates()
{
var config = configService.GetConfig<ServerConfig>();
if (config.UpdateDisabled)
{
logger.Info($"Skipping update check as it is disabled.");
return;
}
var isWindows = System.Environment.OSVersion.Platform != PlatformID.Unix;
if (Debugger.IsAttached)
{
logger.Info($"Skipping checking for new releases as the debugger is attached.");
return;
}
try
{
var github = new GitHubClient(new ProductHeaderValue("Jackett"));
if(config!=null && !string.IsNullOrWhiteSpace(config.GitHubUsername))
{
github.Credentials = new Credentials(config.GitHubUsername, config.GitHubPassword);
}
var releases = await github.Release.GetAll("Jackett", "Jackett");
if (releases.Count > 0)
{
var latestRelease = releases.OrderByDescending(o => o.CreatedAt).First();
var currentVersion = $"v{GetCurrentVersion()}";
if (latestRelease.Name != currentVersion && currentVersion != "v0.0.0.0")
{
logger.Info($"New release found. Current: {currentVersion} New: {latestRelease.Name}");
try
{
var tempDir = await DownloadRelease(latestRelease.Name, isWindows);
// Copy updater
var installDir = Path.GetDirectoryName(ExePath());
var updaterPath = Path.Combine(tempDir, "Jackett", "JackettUpdater.exe");
StartUpdate(updaterPath, installDir, isWindows);
}
catch (Exception e)
{
logger.Error(e, "Error performing update.");
}
}
else
{
logger.Info($"Checked for a updated release but none was found.");
}
}
}
catch (Exception e)
{
logger.Error(e, "Error checking for updates.");
}
}
private string GetCurrentVersion()
{
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
return fvi.FileVersion;
}
private async Task<string> DownloadRelease(string version, bool isWindows)
{
var downloadUrl = $"https://github.com/Jackett/Jackett/releases/download/{version}/";
if (isWindows)
{
downloadUrl += "Jackett.Binaries.Windows.zip";
}
else
{
downloadUrl += "Jackett.Binaries.Mono.tar.gz";
}
var data = await client.GetBytes(new WebRequest() { Url = downloadUrl, EmulateBrowser = true, Type = RequestType.GET });
while (data.IsRedirect)
{
data = await client.GetBytes(new WebRequest() { Url = data.RedirectingTo, EmulateBrowser = true, Type = RequestType.GET });
}
var tempDir = Path.Combine(Path.GetTempPath(), "JackettUpdate-" + version + "-" + DateTime.Now.Ticks);
if (Directory.Exists(tempDir))
{
Directory.Delete(tempDir, true);
}
Directory.CreateDirectory(tempDir);
if (isWindows)
{
var zipPath = Path.Combine(tempDir, "Update.zip");
File.WriteAllBytes(zipPath, data.Content);
var fastZip = new FastZip();
fastZip.ExtractZip(zipPath, tempDir, null);
}
else
{
var gzPath = Path.Combine(tempDir, "Update.tar.gz");
File.WriteAllBytes(gzPath, data.Content);
Stream inStream = File.OpenRead(gzPath);
Stream gzipStream = new GZipInputStream(inStream);
TarArchive tarArchive = TarArchive.CreateInputTarArchive(gzipStream);
tarArchive.ExtractContents(tempDir);
tarArchive.Close();
gzipStream.Close();
inStream.Close();
}
return tempDir;
}
private void StartUpdate(string updaterExePath, string installLocation, bool isWindows)
{
var exe = Path.GetFileName(ExePath()).ToLowerInvariant();
var args = string.Join(" ", Environment.GetCommandLineArgs().Skip(1));
if (!isWindows)
{
// Wrap mono
args = exe + " " + args;
exe = "mono";
}
var startInfo = new ProcessStartInfo()
{
Arguments = $"--Path \"{installLocation}\" --Type \"{exe}\" --Args \"{args}\"",
FileName = Path.Combine(updaterExePath)
};
var procInfo = Process.Start(startInfo);
logger.Info($"Updater started process id: {procInfo.Id}");
Environment.Exit(0);
}
}
}

View File

@ -26,5 +26,7 @@
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
<package id="NLog" version="4.2.0" targetFramework="net45" />
<package id="NLog.Windows.Forms" version="4.0" targetFramework="net45" />
<package id="Octokit" version="0.16.0" targetFramework="net45" />
<package id="Owin" version="1.0" targetFramework="net45" />
<package id="SharpZipLib" version="0.86.0" targetFramework="net45" />
</packages>