Compare commits

...

2 commits

3 changed files with 71 additions and 1 deletions

View file

@ -112,6 +112,9 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp {
} }
public class Builtins : Dictionary<string, Function> { public class Builtins : Dictionary<string, Function> {
private static Dictionary<string, Assembly> AssemblyMapping = new Dictionary<string, Assembly>();
public Builtins() : base() { public Builtins() : base() {
this["atom"] = _atom; this["atom"] = _atom;
this["eq"] = _eq; this["eq"] = _eq;
@ -147,6 +150,7 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp {
this["haskeys"] = _haskeys; this["haskeys"] = _haskeys;
this["getitems"] = _getitems; this["getitems"] = _getitems;
this["invoke"] = _invoke; this["invoke"] = _invoke;
this["invoke-generic"] = _invoke_generic;
} }
private static T _agg<T>(Func<T, T, T> op, IEnumerable<Expression> args) where T : Expression { private static T _agg<T>(Func<T, T, T> op, IEnumerable<Expression> args) where T : Expression {
T agg = (T) args.First(); T agg = (T) args.First();
@ -250,11 +254,68 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp {
IList<Expression> r = new List<Expression>(); IList<Expression> r = new List<Expression>();
MethodInfo? mi = o.Value().GetType().GetMethod(s.Value(), l_types); MethodInfo? mi = o.Value().GetType().GetMethod(s.Value(), l_types);
if (mi == null) { if (mi == null) {
throw new ApplicationException($"{o.Value()} has not method {s.Value()}"); throw new ApplicationException($"{o.Value()} has no method {s.Value()}");
} }
return Object.FromBase(mi.Invoke(o.Value(), l_)); return Object.FromBase(mi.Invoke(o.Value(), l_));
} }
private static Type? GetType(string name) {
return Type.GetType(
name,
(name) => { return AppDomain.CurrentDomain.GetAssemblies().Where(z => z.FullName == name.FullName).FirstOrDefault(); },
null,
true
);
}
private static Expression _invoke_generic(IEnumerable<Expression> args) {
Object o = new Object(((IInner) args.First()).Inner());
String s = (String) args.Skip(1).First();
IEnumerable<Expression> l;
if (args.Skip(2).First() is Boolean lb && lb == Boolean.FALSE) {
l = new List<Expression>();
} else if (args.Skip(2).First() is Cons lc) {
l = lc.ToList();
} else {
throw new ApplicationException($"Expected a list of arguments, got {args.Skip(2).First()}");
}
IEnumerable<Type> types;
if (args.Skip(3).First() is Boolean lb_ && lb_ == Boolean.FALSE) {
types = new List<Type>();
} else if (args.Skip(3).First() is Cons lc) {
types = lc.ToList().Select(x => GetType(((String) x).Value())).ToList();
} else {
throw new ApplicationException($"Expected a list of arguments, got {args.Skip(3).First()}");
}
object[]? l_ = l.Select<Expression, object>(x => {
switch (x) {
case Integer s:
return s.Value();
case Boolean b:
return b.Value();
case String s:
return s.Value();
case Object o:
return o.Value();
case Cons c:
return c.ToList().ToList();
}
throw new ApplicationException($"Unhandled value {x} (type {x.GetType()})");
}).ToArray();
Type[] l_types = l_.Select( x => {
return x.GetType();
}).ToArray();
IList<Expression> r = new List<Expression>();
MethodInfo? mi = o.Value().GetType().GetMethod(s.Value(), l_types);
if (mi == null) {
throw new ApplicationException($"{o.Value()} has no method {s.Value()}");
}
mi = mi.MakeGenericMethod(types.ToArray());
return Object.FromBase(mi.Invoke(o.Value(), l_));
}
} }
public class BuiltinsLater : Dictionary<string, FunctionLater> { public class BuiltinsLater : Dictionary<string, FunctionLater> {

View file

@ -143,6 +143,10 @@ namespace Jellyfin.Plugin.SmartPlaylist.ScheduledTasks {
public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken) { public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken) {
_logger.LogInformation("Started regenerate Smart Playlists"); _logger.LogInformation("Started regenerate Smart Playlists");
_logger.LogDebug("Loaded Assemblies:");
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) {
_logger.LogDebug("- {0}", asm);
}
foreach (SmartPlaylistDto dto in await _store.GetAllSmartPlaylistsAsync()) { foreach (SmartPlaylistDto dto in await _store.GetAllSmartPlaylistsAsync()) {
var changedDto = false; var changedDto = false;
if (dto.Playlists.Length == 0) { if (dto.Playlists.Length == 0) {

View file

@ -17,6 +17,9 @@ namespace Tests
public int I() { public int I() {
return _i; return _i;
} }
public string G<E>() {
return typeof(E).FullName;
}
} }
public class Test { public class Test {
@ -202,6 +205,8 @@ namespace Tests
Assert.Equal("(5 nil)", string.Format("{0}", r)); Assert.Equal("(5 nil)", string.Format("{0}", r));
r = e.eval("""(invoke o "I" nil)"""); r = e.eval("""(invoke o "I" nil)""");
Assert.Equal("5", string.Format("{0}", r)); Assert.Equal("5", string.Format("{0}", r));
r = e.eval("""(invoke-generic o "G" nil ((lambda (. args) args) "System.String"))""");
Assert.Equal("\"System.String\"", string.Format("{0}", r));
} }
[Fact] [Fact]