mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-20 05:23:31 -07:00
New: Command line arguments for Custom Scripts are no longer supported
This commit is contained in:
parent
b8b8f064c7
commit
b9d240924f
15 changed files with 170 additions and 126 deletions
|
@ -15,10 +15,11 @@ namespace Lidarr.Http.ClientSchema
|
|||
public bool Advanced { get; set; }
|
||||
public List<SelectOption> SelectOptions { get; set; }
|
||||
public string Section { get; set; }
|
||||
public string Hidden { get; set; }
|
||||
|
||||
public Field Clone()
|
||||
{
|
||||
return (Field) MemberwiseClone();
|
||||
return (Field)MemberwiseClone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,14 +20,14 @@ namespace Lidarr.Http.ClientSchema
|
|||
|
||||
var mappings = GetFieldMappings(model.GetType());
|
||||
|
||||
var result = new List<Field>(mappings.Length);
|
||||
var result = new List<Field>(mappings.Length);
|
||||
|
||||
foreach (var mapping in mappings)
|
||||
{
|
||||
var field = mapping.Field.Clone();
|
||||
field.Value = mapping.GetterFunc(model);
|
||||
|
||||
result.Add(field);
|
||||
result.Add(field);
|
||||
}
|
||||
|
||||
return result.OrderBy(r => r.Order).ToList();
|
||||
|
@ -45,7 +45,7 @@ namespace Lidarr.Http.ClientSchema
|
|||
{
|
||||
var field = fields.Find(f => f.Name == mapping.Field.Name);
|
||||
|
||||
mapping.SetterFunc(target, field.Value);
|
||||
mapping.SetterFunc(target, field.Value);
|
||||
}
|
||||
|
||||
return target;
|
||||
|
@ -54,9 +54,10 @@ namespace Lidarr.Http.ClientSchema
|
|||
|
||||
public static T ReadFromSchema<T>(List<Field> fields)
|
||||
{
|
||||
return (T) ReadFromSchema(fields, typeof(T));
|
||||
return (T)ReadFromSchema(fields, typeof(T));
|
||||
}
|
||||
|
||||
|
||||
// Ideally this function should begin a System.Linq.Expression expression tree since it's faster.
|
||||
// But it's probably not needed till performance issues pop up.
|
||||
public static FieldMapping[] GetFieldMappings(Type type)
|
||||
|
@ -74,11 +75,12 @@ namespace Lidarr.Http.ClientSchema
|
|||
result[i].Field.Order = i;
|
||||
}
|
||||
|
||||
_mappings[type] = result;
|
||||
_mappings[type] = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static FieldMapping[] GetFieldMapping(Type type, string prefix, Func<object, object> targetSelector)
|
||||
{
|
||||
var result = new List<FieldMapping>();
|
||||
|
@ -97,7 +99,7 @@ namespace Lidarr.Http.ClientSchema
|
|||
HelpLink = fieldAttribute.HelpLink,
|
||||
Order = fieldAttribute.Order,
|
||||
Advanced = fieldAttribute.Advanced,
|
||||
Type = fieldAttribute.Type.ToString().ToLowerInvariant(),
|
||||
Type = fieldAttribute.Type.ToString().FirstCharToLower(),
|
||||
Section = fieldAttribute.Section
|
||||
};
|
||||
|
||||
|
@ -106,9 +108,14 @@ namespace Lidarr.Http.ClientSchema
|
|||
field.SelectOptions = GetSelectOptions(fieldAttribute.SelectOptions);
|
||||
}
|
||||
|
||||
if (fieldAttribute.Hidden != HiddenType.Visible)
|
||||
{
|
||||
field.Hidden = fieldAttribute.Hidden.ToString().FirstCharToLower();
|
||||
}
|
||||
|
||||
var valueConverter = GetValueConverter(propertyInfo.PropertyType);
|
||||
|
||||
result.Add(new FieldMapping
|
||||
result.Add(new FieldMapping
|
||||
{
|
||||
Field = field,
|
||||
PropertyType = propertyInfo.PropertyType,
|
||||
|
@ -138,8 +145,10 @@ namespace Lidarr.Http.ClientSchema
|
|||
{
|
||||
var options = from Enum e in Enum.GetValues(selectOptions)
|
||||
select new SelectOption { Value = Convert.ToInt32(e), Name = e.ToString() };
|
||||
|
||||
return options.OrderBy(o => o.Value).ToList();
|
||||
}
|
||||
|
||||
private static Func<object, object> GetValueConverter(Type propertyType)
|
||||
{
|
||||
if (propertyType == typeof(int))
|
||||
|
@ -178,13 +187,11 @@ namespace Lidarr.Http.ClientSchema
|
|||
{
|
||||
if (fieldValue.GetType() == typeof(JArray))
|
||||
{
|
||||
return ((JArray) fieldValue).Select(s => s.Value<int>());
|
||||
return ((JArray)fieldValue).Select(s => s.Value<int>());
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return fieldValue.ToString().Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(s => Convert.ToInt32(s));
|
||||
return fieldValue.ToString().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => Convert.ToInt32(s));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -195,11 +202,11 @@ namespace Lidarr.Http.ClientSchema
|
|||
{
|
||||
if (fieldValue.GetType() == typeof(JArray))
|
||||
{
|
||||
return ((JArray) fieldValue).Select(s => s.Value<string>());
|
||||
return ((JArray)fieldValue).Select(s => s.Value<string>());
|
||||
}
|
||||
else
|
||||
{
|
||||
return fieldValue.ToString().Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);
|
||||
return fieldValue.ToString().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
31
src/NzbDrone.Common/Disk/SystemFolders.cs
Normal file
31
src/NzbDrone.Common/Disk/SystemFolders.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
|
||||
namespace NzbDrone.Common.Disk
|
||||
{
|
||||
public static class SystemFolders
|
||||
{
|
||||
public static List<string> GetSystemFolders()
|
||||
{
|
||||
if (OsInfo.IsWindows)
|
||||
{
|
||||
return new List<string> { Environment.GetFolderPath(Environment.SpecialFolder.Windows) };
|
||||
}
|
||||
|
||||
if (OsInfo.IsOsx)
|
||||
{
|
||||
return new List<string> { "/System" };
|
||||
}
|
||||
|
||||
return new List<string>
|
||||
{
|
||||
"/bin",
|
||||
"/boot",
|
||||
"/lib",
|
||||
"/sbin",
|
||||
"/proc"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -79,6 +79,7 @@
|
|||
<Compile Include="Disk\RelativeFileSystemModel.cs" />
|
||||
<Compile Include="Disk\FileSystemModel.cs" />
|
||||
<Compile Include="Disk\FileSystemResult.cs" />
|
||||
<Compile Include="Disk\SystemFolders.cs" />
|
||||
<Compile Include="EnvironmentInfo\IOsVersionAdapter.cs" />
|
||||
<Compile Include="EnvironmentInfo\IPlatformInfo.cs" />
|
||||
<Compile Include="EnvironmentInfo\OsVersionModel.cs" />
|
||||
|
@ -259,6 +260,7 @@
|
|||
<PackageReference Include="System.IO.Abstractions">
|
||||
<Version>4.0.11</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
|
@ -268,4 +270,4 @@
|
|||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -108,11 +108,7 @@ namespace NzbDrone.Common.Processes
|
|||
|
||||
public Process Start(string path, string args = null, StringDictionary environmentVariables = null, Action<string> onOutputDataReceived = null, Action<string> onErrorDataReceived = null)
|
||||
{
|
||||
if (PlatformInfo.IsMono && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
args = GetMonoArgs(path, args);
|
||||
path = "mono";
|
||||
}
|
||||
(path, args) = GetPathAndArgs(path, args);
|
||||
|
||||
var logger = LogManager.GetLogger(new FileInfo(path).Name);
|
||||
|
||||
|
@ -192,11 +188,7 @@ namespace NzbDrone.Common.Processes
|
|||
|
||||
public Process SpawnNewProcess(string path, string args = null, StringDictionary environmentVariables = null, bool noWindow = false)
|
||||
{
|
||||
if (PlatformInfo.IsMono && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
args = GetMonoArgs(path, args);
|
||||
path = "mono";
|
||||
}
|
||||
(path, args) = GetPathAndArgs(path, args);
|
||||
|
||||
_logger.Debug("Starting {0} {1}", path, args);
|
||||
|
||||
|
@ -361,9 +353,19 @@ namespace NzbDrone.Common.Processes
|
|||
return processes;
|
||||
}
|
||||
|
||||
private string GetMonoArgs(string path, string args)
|
||||
private (string Path, string Args) GetPathAndArgs(string path, string args)
|
||||
{
|
||||
return string.Format("--debug {0} {1}", path, args);
|
||||
if (PlatformInfo.IsMono && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return ("mono", $"--debug {path} {args}");
|
||||
}
|
||||
|
||||
if (OsInfo.IsWindows && path.EndsWith(".bat", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return ("cmd.exe", $"/c {path} {args}");
|
||||
}
|
||||
|
||||
return (path, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace NzbDrone.Core.Annotations
|
|||
public bool Advanced { get; set; }
|
||||
public Type SelectOptions { get; set; }
|
||||
public string Section { get; set; }
|
||||
public HiddenType Hidden { get; set; }
|
||||
}
|
||||
|
||||
public enum FieldType
|
||||
|
@ -30,7 +31,6 @@ namespace NzbDrone.Core.Annotations
|
|||
Select,
|
||||
Path,
|
||||
FilePath,
|
||||
Hidden,
|
||||
Tag,
|
||||
Action,
|
||||
Url,
|
||||
|
@ -38,4 +38,11 @@ namespace NzbDrone.Core.Annotations
|
|||
OAuth,
|
||||
Device
|
||||
}
|
||||
|
||||
public enum HiddenType
|
||||
{
|
||||
Visible,
|
||||
Hidden,
|
||||
HiddenIfNotSet
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
|
@ -5,6 +6,7 @@ using System.Linq;
|
|||
using FluentValidation.Results;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Processes;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.Music;
|
||||
|
@ -160,6 +162,35 @@ namespace NzbDrone.Core.Notifications.CustomScript
|
|||
failures.Add(new NzbDroneValidationFailure("Path", "File does not exist"));
|
||||
}
|
||||
|
||||
foreach (var systemFolder in SystemFolders.GetSystemFolders())
|
||||
{
|
||||
if (systemFolder.IsParentPath(Settings.Path))
|
||||
{
|
||||
failures.Add(new NzbDroneValidationFailure("Path", $"Must not be a descendant of '{systemFolder}'"));
|
||||
}
|
||||
}
|
||||
|
||||
if (failures.Empty())
|
||||
{
|
||||
try
|
||||
{
|
||||
var environmentVariables = new StringDictionary();
|
||||
environmentVariables.Add("Sonarr_EventType", "Test");
|
||||
|
||||
var processOutput = ExecuteScript(environmentVariables);
|
||||
|
||||
if (processOutput.ExitCode != 0)
|
||||
{
|
||||
failures.Add(new NzbDroneValidationFailure(string.Empty, $"Script exited with code: {processOutput.ExitCode}"));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex);
|
||||
failures.Add(new NzbDroneValidationFailure(string.Empty, ex.Message));
|
||||
}
|
||||
}
|
||||
|
||||
return new ValidationResult(failures);
|
||||
}
|
||||
|
||||
|
@ -172,5 +203,10 @@ namespace NzbDrone.Core.Notifications.CustomScript
|
|||
_logger.Debug("Executed external script: {0} - Status: {1}", Settings.Path, process.ExitCode);
|
||||
_logger.Debug($"Script Output: {System.Environment.NewLine}{string.Join(System.Environment.NewLine, process.Lines)}");
|
||||
}
|
||||
|
||||
private bool ValidatePathParent(string possibleParent, string path)
|
||||
{
|
||||
return possibleParent.IsParentPath(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace NzbDrone.Core.Notifications.CustomScript
|
|||
public CustomScriptSettingsValidator()
|
||||
{
|
||||
RuleFor(c => c.Path).IsValidPath();
|
||||
RuleFor(c => c.Arguments).Empty().WithMessage("Arguments are no longer supported for custom scripts");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,7 +22,7 @@ namespace NzbDrone.Core.Notifications.CustomScript
|
|||
[FieldDefinition(0, Label = "Path", Type = FieldType.FilePath)]
|
||||
public string Path { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Arguments", HelpText = "Arguments to pass to the script")]
|
||||
[FieldDefinition(1, Label = "Arguments", HelpText = "Arguments to pass to the script", Hidden = HiddenType.HiddenIfNotSet)]
|
||||
public string Arguments { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
|
|
|
@ -13,22 +13,22 @@ namespace NzbDrone.Core.Notifications.Plex.HomeTheater
|
|||
|
||||
//These need to be kept in the same order as XBMC Settings, but we don't want them displayed
|
||||
|
||||
[FieldDefinition(2, Label = "Username", Type = FieldType.Hidden)]
|
||||
[FieldDefinition(2, Label = "Username", Hidden = HiddenType.Hidden)]
|
||||
public new string Username { get; set; }
|
||||
|
||||
[FieldDefinition(3, Label = "Password", Type = FieldType.Hidden)]
|
||||
[FieldDefinition(3, Label = "Password", Hidden = HiddenType.Hidden)]
|
||||
public new string Password { get; set; }
|
||||
|
||||
[FieldDefinition(5, Label = "GUI Notification", Type = FieldType.Hidden)]
|
||||
[FieldDefinition(5, Label = "GUI Notification", Type = FieldType.Checkbox, Hidden = HiddenType.Hidden)]
|
||||
public new bool Notify { get; set; }
|
||||
|
||||
[FieldDefinition(6, Label = "Update Library", HelpText = "Update Library on Download & Rename?", Type = FieldType.Hidden)]
|
||||
[FieldDefinition(6, Label = "Update Library", HelpText = "Update Library on Download & Rename?", Type = FieldType.Checkbox, Hidden = HiddenType.Hidden)]
|
||||
public new bool UpdateLibrary { get; set; }
|
||||
|
||||
[FieldDefinition(7, Label = "Clean Library", HelpText = "Clean Library after update?", Type = FieldType.Hidden)]
|
||||
[FieldDefinition(7, Label = "Clean Library", HelpText = "Clean Library after update?", Type = FieldType.Checkbox, Hidden = HiddenType.Hidden)]
|
||||
public new bool CleanLibrary { get; set; }
|
||||
|
||||
[FieldDefinition(8, Label = "Always Update", HelpText = "Update Library even when a video is playing?", Type = FieldType.Hidden)]
|
||||
[FieldDefinition(8, Label = "Always Update", HelpText = "Update Library even when a video is playing?", Type = FieldType.Checkbox, Hidden = HiddenType.Hidden)]
|
||||
public new bool AlwaysUpdate { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,15 +70,15 @@ namespace NzbDrone.Core.Notifications.PushBullet
|
|||
var devices = _proxy.GetDevices(Settings);
|
||||
|
||||
return new
|
||||
{
|
||||
devices = devices.Where(d => d.Nickname.IsNotNullOrWhiteSpace())
|
||||
.OrderBy(d => d.Nickname, StringComparer.InvariantCultureIgnoreCase)
|
||||
.Select(d => new
|
||||
{
|
||||
id = d.Id,
|
||||
name = d.Nickname
|
||||
})
|
||||
};
|
||||
{
|
||||
options = devices.Where(d => d.Nickname.IsNotNullOrWhiteSpace())
|
||||
.OrderBy(d => d.Nickname, StringComparer.InvariantCultureIgnoreCase)
|
||||
.Select(d => new
|
||||
{
|
||||
id = d.Id,
|
||||
name = d.Nickname
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
return new { };
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using FluentValidation.Validators;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
||||
namespace NzbDrone.Core.Validation.Paths
|
||||
|
@ -16,33 +15,13 @@ namespace NzbDrone.Core.Validation.Paths
|
|||
{
|
||||
var folder = context.PropertyValue.ToString();
|
||||
|
||||
if (OsInfo.IsWindows)
|
||||
foreach (var systemFolder in SystemFolders.GetSystemFolders())
|
||||
{
|
||||
var windowsFolder = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
|
||||
context.MessageFormatter.AppendArgument("systemFolder", windowsFolder);
|
||||
|
||||
if (windowsFolder.PathEquals(folder))
|
||||
{
|
||||
context.MessageFormatter.AppendArgument("relationship", "set to");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (windowsFolder.IsParentPath(folder))
|
||||
{
|
||||
context.MessageFormatter.AppendArgument("relationship", "child of");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (OsInfo.IsOsx)
|
||||
{
|
||||
var systemFolder = "/System";
|
||||
context.MessageFormatter.AppendArgument("systemFolder", systemFolder);
|
||||
|
||||
if (systemFolder.PathEquals(folder))
|
||||
{
|
||||
context.MessageFormatter.AppendArgument("relationship", "child of");
|
||||
context.MessageFormatter.AppendArgument("relationship", "set to");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -54,36 +33,6 @@ namespace NzbDrone.Core.Validation.Paths
|
|||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var folders = new[]
|
||||
{
|
||||
"/bin",
|
||||
"/boot",
|
||||
"/lib",
|
||||
"/sbin",
|
||||
"/proc"
|
||||
};
|
||||
|
||||
foreach (var f in folders)
|
||||
{
|
||||
context.MessageFormatter.AppendArgument("systemFolder", f);
|
||||
|
||||
if (f.PathEquals(folder))
|
||||
{
|
||||
context.MessageFormatter.AppendArgument("relationship", "child of");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (f.IsParentPath(folder))
|
||||
{
|
||||
context.MessageFormatter.AppendArgument("relationship", "child of");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue