Merge branch 'master' into dotnetcore

This commit is contained in:
flightlevel 2018-06-27 22:12:53 +10:00
commit bc965b1a0c
12 changed files with 164 additions and 30 deletions

View File

@ -17,7 +17,7 @@ Developer note: The software implements the [Torznab](https://github.com/Sonarr/
#### Supported Systems #### Supported Systems
* Windows using .NET 4.6.1 or above [Download here](https://www.microsoft.com/net/framework/versions/net461). * Windows using .NET 4.6.1 or above [Download here](https://www.microsoft.com/net/framework/versions/net461).
* Linux and macOS using Mono 5.8 or above. [Download here](http://www.mono-project.com/download/). Earlier versions of mono may work, but some trackers may fail to negotiate SSL correctly, and others may cause Jackett to crash when used. * Linux and macOS using Mono 5.8 or above. [Download here](http://www.mono-project.com/download/).
### Supported Public Trackers ### Supported Public Trackers
* 1337x * 1337x
@ -403,6 +403,7 @@ All contributions are welcome just send a pull request. Jackett's framework all
## Building from source ## Building from source
### Windows ### Windows
* Install the .NET Core [SDK](https://www.microsoft.com/net/download/windows)
* Open the Jackett solution in Visual Studio 2017 (version 15.7 or above) * Open the Jackett solution in Visual Studio 2017 (version 15.7 or above)
* Right click on the Jackett solution and click 'Rebuild Solution' to restore nuget packages * Right click on the Jackett solution and click 'Rebuild Solution' to restore nuget packages
* Select Jackett.Console as startup project * Select Jackett.Console as startup project

View File

@ -13,6 +13,7 @@ using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using static Jackett.Common.Models.IndexerConfig.ConfigurationData;
namespace Jackett.Common.Indexers namespace Jackett.Common.Indexers
{ {
@ -194,17 +195,31 @@ namespace Jackett.Common.Indexers
LoadValuesFromJson(jsonConfig, false); LoadValuesFromJson(jsonConfig, false);
object passwordPropertyValue = null; StringItem passwordPropertyValue = null;
string passwordValue = ""; string passwordValue = "";
try try
{ {
passwordPropertyValue = configData.GetType().GetProperty("Password").GetValue(configData, null); // try dynamic items first (e.g. all cardigann indexers)
passwordValue = passwordPropertyValue.GetType().GetProperty("Value").GetValue(passwordPropertyValue, null).ToString(); passwordPropertyValue = (StringItem)configData.GetDynamicByName("password");
if (passwordPropertyValue == null) // if there's no dynamic password try the static property
{
passwordPropertyValue = (StringItem)configData.GetType().GetProperty("Password").GetValue(configData, null);
// protection is based on the item.Name value (property name might be different, example: Abnormal), so check the Name again
if (!string.Equals(passwordPropertyValue.Name, "password", StringComparison.InvariantCultureIgnoreCase))
{
logger.Debug($"Skipping non default password property (unencrpyted password) for [{ID}] while attempting migration");
return false;
}
}
passwordValue = passwordPropertyValue.Value;
} }
catch (Exception) catch (Exception)
{ {
logger.Debug($"Unable to source password for [{ID}] while attempting migration, likely a public tracker"); logger.Debug($"Unable to source password for [{ID}] while attempting migration, likely a tracker without a password setting");
return false; return false;
} }
@ -230,7 +245,7 @@ namespace Jackett.Common.Indexers
string unprotectedPassword = protectionService.LegacyUnProtect(passwordValue); string unprotectedPassword = protectionService.LegacyUnProtect(passwordValue);
//Password successfully unprotected using Windows/Mono DPAPI //Password successfully unprotected using Windows/Mono DPAPI
passwordPropertyValue.GetType().GetProperty("Value").SetValue(passwordPropertyValue, unprotectedPassword); passwordPropertyValue.Value = unprotectedPassword;
SaveConfig(); SaveConfig();
IsConfigured = true; IsConfigured = true;

View File

@ -180,7 +180,7 @@ namespace Jackett.Common.Indexers
} }
var response = await RequestStringWithCookiesAndRetry(urlSearch); var response = await RequestStringWithCookiesAndRetry(urlSearch);
if (response.Status == System.Net.HttpStatusCode.Forbidden) if (response.Status == System.Net.HttpStatusCode.Forbidden || CookieHeader.Contains("pass=deleted"))
{ {
// re-login // re-login
await ApplyConfiguration(null); await ApplyConfiguration(null);

View File

@ -116,7 +116,7 @@ namespace Jackett.Common.Models.IndexerConfig
case ItemType.HiddenData: case ItemType.HiddenData:
case ItemType.DisplayInfo: case ItemType.DisplayInfo:
var value = ((StringItem)item).Value; var value = ((StringItem)item).Value;
if (string.Equals(item.Name, "password", StringComparison.InvariantCultureIgnoreCase)) if (string.Equals(item.Name, "password", StringComparison.InvariantCultureIgnoreCase)) // if we chagne this logic we've to change the MigratedFromDPAPI() logic too, #2114 is realted
{ {
if (string.IsNullOrEmpty(value)) if (string.IsNullOrEmpty(value))
value = string.Empty; value = string.Empty;
@ -190,6 +190,11 @@ namespace Jackett.Common.Models.IndexerConfig
} }
} }
public Item GetDynamicByName(string Name)
{
return dynamics.Values.Where(i => string.Equals(i.Name, Name, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
}
public class Item public class Item
{ {
public ItemType ItemType { get; set; } public ItemType ItemType { get; set; }

View File

@ -7,7 +7,7 @@ namespace Jackett.Common.Services
public class TrayLockService : ITrayLockService public class TrayLockService : ITrayLockService
{ {
private readonly string EVENT_HANDLE_NAME = "JACKETT.TRAY"; private readonly string EVENT_HANDLE_NAME = @"Global\JACKETT.TRAY";
private EventWaitHandle GetEventHandle() private EventWaitHandle GetEventHandle()
{ {

View File

@ -268,17 +268,29 @@ namespace Jackett.Common.Services
return tempDir; return tempDir;
} }
private void StartUpdate(string updaterExePath, string installLocation, bool isWindows, bool NoRestart, bool trayWasRunning) private void StartUpdate(string updaterExePath, string installLocation, bool isWindows, bool NoRestart, bool trayIsRunning)
{ {
string appType = "Console";
//DI once off Owin
IProcessService processService = new ProcessService(logger);
IServiceConfigService windowsService = new WindowsServiceConfigService(processService, logger);
if (isWindows && windowsService.ServiceExists() && windowsService.ServiceRunning())
{
appType = "WindowsService";
}
var exe = Path.GetFileName(ExePath()); var exe = Path.GetFileName(ExePath());
var args = string.Join(" ", Environment.GetCommandLineArgs().Skip(1).Select(a => a.Contains(" ") ? "\"" +a + "\"" : a )).Replace("\"", "\\\""); var args = string.Join(" ", Environment.GetCommandLineArgs().Skip(1).Select(a => a.Contains(" ") ? "\"" +a + "\"" : a )).Replace("\"", "\\\"");
var startInfo = new ProcessStartInfo(); var startInfo = new ProcessStartInfo();
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
// Note: add a leading space to the --Args argument to avoid parsing as arguments // Note: add a leading space to the --Args argument to avoid parsing as arguments
if (isWindows) if (isWindows)
{ {
startInfo.Arguments = $"--Path \"{installLocation}\" --Type \"{exe}\" --Args \" {args}\""; startInfo.Arguments = $"--Path \"{installLocation}\" --Type \"{appType}\" --Args \" {args}\"";
startInfo.FileName = Path.Combine(updaterExePath); startInfo.FileName = Path.Combine(updaterExePath);
} }
else else
@ -287,13 +299,12 @@ namespace Jackett.Common.Services
args = exe + " " + args; args = exe + " " + args;
exe = "mono"; exe = "mono";
startInfo.Arguments = $"{Path.Combine(updaterExePath)} --Path \"{installLocation}\" --Type \"{exe}\" --Args \" {args}\""; startInfo.Arguments = $"{Path.Combine(updaterExePath)} --Path \"{installLocation}\" --Type \"{appType}\" --Args \" {args}\"";
startInfo.FileName = "mono"; startInfo.FileName = "mono";
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
} }
try { try
{
var pid = Process.GetCurrentProcess().Id; var pid = Process.GetCurrentProcess().Id;
startInfo.Arguments += $" --KillPids \"{pid}\""; startInfo.Arguments += $" --KillPids \"{pid}\"";
} }
@ -308,18 +319,25 @@ namespace Jackett.Common.Services
startInfo.Arguments += " --NoRestart"; startInfo.Arguments += " --NoRestart";
} }
if (trayWasRunning) if (trayIsRunning && appType == "Console")
{ {
startInfo.Arguments += " --StartTray"; startInfo.Arguments += " --StartTray";
} }
if (isWindows)
{
lockService.Signal();
logger.Info("Signal sent to lock service");
Thread.Sleep(2000);
}
logger.Info($"Starting updater: {startInfo.FileName} {startInfo.Arguments}"); logger.Info($"Starting updater: {startInfo.FileName} {startInfo.Arguments}");
var procInfo = Process.Start(startInfo); var procInfo = Process.Start(startInfo);
logger.Info($"Updater started process id: {procInfo.Id}"); logger.Info($"Updater started process id: {procInfo.Id}");
if (NoRestart == false)
if (!NoRestart)
{ {
logger.Info("Exiting Jackett.."); logger.Info("Exiting Jackett..");
lockService.Signal();
//TODO: Remove once off Owin //TODO: Remove once off Owin
if (EnvironmentUtil.IsRunningLegacyOwin) if (EnvironmentUtil.IsRunningLegacyOwin)
{ {

View File

@ -77,10 +77,12 @@ namespace Jackett.Service
private void ProcessExited(object sender, EventArgs e) private void ProcessExited(object sender, EventArgs e)
{ {
logger.Info("Console process exited");
if (!serviceStopInitiated) if (!serviceStopInitiated)
{ {
logger.Info("Service stop not responsible for process exit"); logger.Info("Service stop not responsible for process exit");
OnStop(); Stop();
} }
} }
@ -89,7 +91,7 @@ namespace Jackett.Service
if (consoleProcess != null && !consoleProcess.HasExited) if (consoleProcess != null && !consoleProcess.HasExited)
{ {
consoleProcess.StandardInput.Close(); consoleProcess.StandardInput.Close();
System.Threading.Thread.Sleep(1000); consoleProcess.WaitForExit(2000);
if (consoleProcess != null && !consoleProcess.HasExited) if (consoleProcess != null && !consoleProcess.HasExited)
{ {
consoleProcess.Kill(); consoleProcess.Kill();

View File

@ -66,6 +66,7 @@
</Compile> </Compile>
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TrayConsoleOptions.cs" />
<EmbeddedResource Include="Main.resx"> <EmbeddedResource Include="Main.resx">
<DependentUpon>Main.cs</DependentUpon> <DependentUpon>Main.cs</DependentUpon>
</EmbeddedResource> </EmbeddedResource>
@ -109,6 +110,11 @@
<EmbedInteropTypes>True</EmbedInteropTypes> <EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference> </COMReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="CommandLineParser">
<Version>2.2.1</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- 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. Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -25,7 +25,7 @@ namespace Jackett.Tray
private Logger logger; private Logger logger;
private bool closeApplicationInitiated; private bool closeApplicationInitiated;
public Main() public Main(string updatedVersion)
{ {
Hide(); Hide();
InitializeComponent(); InitializeComponent();
@ -65,12 +65,45 @@ namespace Jackett.Tray
StartConsoleApplication(); StartConsoleApplication();
} }
updatedVersion = updatedVersion.Equals("yes", StringComparison.OrdinalIgnoreCase) ? EnvironmentUtil.JackettVersion : updatedVersion;
if (!string.IsNullOrWhiteSpace(updatedVersion))
{
notifyIcon1.BalloonTipTitle = "Jackett";
notifyIcon1.BalloonTipText = $"Jackett has updated to version {updatedVersion}";
notifyIcon1.BalloonTipIcon = ToolTipIcon.Info;
notifyIcon1.ShowBalloonTip(10000);
logger.Info($"Display balloon tip, updated to {updatedVersion}");
}
Task.Factory.StartNew(WaitForEvent); Task.Factory.StartNew(WaitForEvent);
} }
private void WaitForEvent() private void WaitForEvent()
{ {
trayLockService.WaitForSignal(); trayLockService.WaitForSignal();
logger.Info("Received signal from tray lock service");
if (windowsService.ServiceExists() && windowsService.ServiceRunning())
{
//We won't be able to start the tray app up again from the updater, as when running via a windows service there is no interaction with the desktop
//Fire off a console process that will start the tray 20 seconds later
string trayExePath = Assembly.GetEntryAssembly().Location;
var startInfo = new ProcessStartInfo()
{
Arguments = $"/c timeout 20 > NUL & \"{trayExePath}\" --UpdatedVersion yes",
FileName = "cmd.exe",
UseShellExecute = true,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
};
logger.Info("Starting 20 second delay tray launch as Jackett is running as a Windows service: " + startInfo.FileName + " " + startInfo.Arguments);
Process.Start(startInfo);
}
CloseTrayApplication(); CloseTrayApplication();
} }

View File

@ -1,4 +1,5 @@
using System; using CommandLine;
using System;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
@ -11,7 +12,7 @@ namespace Jackett.Tray
/// The main entry point for the application. /// The main entry point for the application.
/// </summary> /// </summary>
[STAThread] [STAThread]
static void Main() static void Main(string[] args)
{ {
var JacketTrayProcess = Process.GetCurrentProcess(); var JacketTrayProcess = Process.GetCurrentProcess();
var runningProcesses = Process.GetProcesses(); var runningProcesses = Process.GetProcesses();
@ -24,9 +25,28 @@ namespace Jackett.Tray
} }
else else
{ {
string newVersion = "";
var commandLineParser = new Parser(settings => settings.CaseSensitive = false);
try
{
var optionsResult = commandLineParser.ParseArguments<TrayConsoleOptions>(args);
optionsResult.WithParsed(options =>
{
if (!string.IsNullOrWhiteSpace(options.UpdatedVersion))
{
newVersion = options.UpdatedVersion;
}
});
}
catch (Exception e)
{
newVersion = "";
}
Application.EnableVisualStyles(); Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false); Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Main()); Application.Run(new Main(newVersion));
} }
} }
} }

View File

@ -0,0 +1,10 @@
using CommandLine;
namespace Jackett.Tray
{
public class TrayConsoleOptions
{
[Option("UpdatedVersion", HelpText = "Indicates the new version that Jackett just updated to so that user understands why they are getting a prompt to start Windows service")]
public string UpdatedVersion { get; set; }
}
}

View File

@ -38,6 +38,14 @@ namespace Jackett.Updater
logger.Info("Jackett Updater v" + GetCurrentVersion()); logger.Info("Jackett Updater v" + GetCurrentVersion());
logger.Info("Options \"" + string.Join("\" \"", args) + "\""); logger.Info("Options \"" + string.Join("\" \"", args) + "\"");
bool isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT;
if (isWindows)
{
//The updater starts before Jackett closes
logger.Info("Pausing for 3 seconds to give Jackett & tray time to shutdown");
System.Threading.Thread.Sleep(3000);
}
processService = new ProcessService(logger); processService = new ProcessService(logger);
windowsService = new WindowsServiceConfigService(processService, logger); windowsService = new WindowsServiceConfigService(processService, logger);
@ -248,15 +256,16 @@ namespace Jackett.Updater
if (options.NoRestart == false) if (options.NoRestart == false)
{ {
if (trayRunning || options.StartTray) if (isWindows && (trayRunning || options.StartTray) && !string.Equals(options.Type, "WindowsService", StringComparison.OrdinalIgnoreCase))
{ {
var startInfo = new ProcessStartInfo() var startInfo = new ProcessStartInfo()
{ {
Arguments = options.Args, Arguments = $"--UpdatedVersion \" {EnvironmentUtil.JackettVersion}\"",
FileName = Path.Combine(options.Path, "JackettTray.exe"), FileName = Path.Combine(options.Path, "JackettTray.exe"),
UseShellExecute = true UseShellExecute = true
}; };
logger.Info("Starting Tray: " + startInfo.FileName + " " + startInfo.Arguments);
Process.Start(startInfo); Process.Start(startInfo);
if (!windowsService.ServiceExists()) if (!windowsService.ServiceExists())
@ -266,12 +275,27 @@ namespace Jackett.Updater
} }
} }
if (string.Equals(options.Type, "JackettService.exe", StringComparison.InvariantCultureIgnoreCase)) if (string.Equals(options.Type, "WindowsService", StringComparison.OrdinalIgnoreCase))
{ {
if (windowsService.ServiceExists()) logger.Info("Starting Windows service");
if (ServerUtil.IsUserAdministrator())
{ {
windowsService.Start(); windowsService.Start();
} }
else
{
try
{
var consolePath = Path.Combine(options.Path, "JackettConsole.exe");
processService.StartProcessAndLog(consolePath, "--Start", true);
}
catch
{
logger.Error("Failed to get admin rights to start the service.");
}
}
} }
else else
{ {