Compare commits

...

2 commits

3 changed files with 30 additions and 17 deletions

View file

@ -21,26 +21,26 @@ namespace Jellyfin.Plugin.SmartPlaylist {
(define genre-list (define genre-list
(lambda nil (lambda nil
(let (let
(_g (getitems item "Genres")) (_g (getitems *item* "Genres"))
(if (null _g) (if (null _g)
nil nil
(car _g))))) (car _g)))))
(define is-favorite (define is-favorite
(lambda nil (lambda nil
(invoke item "IsFavoriteOrLiked" (list user)))) (invoke *item* "IsFavoriteOrLiked" (list *user*))))
(define is-type (define is-type
(lambda (x) (lambda (x)
(and (and
(haskeys item "GetClientTypeName") (haskeys *item* "GetClientTypeName")
(invoke (invoke item "GetClientTypeName" nil) "Equals" (list x))))) (invoke (invoke *item* "GetClientTypeName" nil) "Equals" (list x)))))
(define name-contains (define name-contains
(lambda (x) (lambda (x)
(invoke (lower (car (getitems item "Name"))) "Contains" (list (lower x))))) (invoke (lower (car (getitems *item* "Name"))) "Contains" (list (lower x)))))
(define is-favourite is-favorite) (define is-favourite is-favorite)
(define all-genres (lambda (want have) (all (lambda (x) (is-genre x have)) want))) (define all-genres (lambda (want have) (all (lambda (x) (is-genre x have)) want)))
(define any-genres (lambda (want have) (any (lambda (x) (is-genre x have)) want))) (define any-genres (lambda (want have) (any (lambda (x) (is-genre x have)) want)))
(define get-name (lambda (x) (car (getitems x "Name")))) (define get-name (lambda (x) (car (getitems x "Name"))))
(define find-parent (lambda (typename) (invoke-generic item "FindParent" nil (list typename)))) (define find-parent (lambda (typename) (invoke-generic *item* "FindParent" nil (list typename))))
(define find-artist (lambda nil (find-parent "MediaBrowser.Controller.Entities.Audio.MusicArtist, MediaBrowser.Controller")))) (define find-artist (lambda nil (find-parent "MediaBrowser.Controller.Entities.Audio.MusicArtist, MediaBrowser.Controller"))))
"""; """;
store = new Store(new SmartPlaylistFileSystem(Plugin.Instance.ServerApplicationPaths)); store = new Store(new SmartPlaylistFileSystem(Plugin.Instance.ServerApplicationPaths));

View file

@ -94,11 +94,9 @@ namespace Jellyfin.Plugin.SmartPlaylist.ScheduledTasks {
return playlistGuid; return playlistGuid;
} }
private IEnumerable<Guid> FilterPlaylistItems(IEnumerable<BaseItem> items, User user, SmartPlaylistDto smartPlaylist) { private Executor SetupExecutor() {
List<BaseItem> results = new List<BaseItem>(); var env = new DefaultEnvironment();
Expression expression = new Parser(StringTokenStream.generate(smartPlaylist.Program)).parse(); // parse here, so that we don't repeat the work for each item var executor = new Executor(env);
Executor executor = new Executor(new DefaultEnvironment());
executor.builtins["logd"] = (x) => { executor.builtins["logd"] = (x) => {
_logger.LogDebug(((Lisp.String)x.First()).Value(), x.Skip(1).ToArray()); _logger.LogDebug(((Lisp.String)x.First()).Value(), x.Skip(1).ToArray());
return Lisp_Boolean.TRUE; return Lisp_Boolean.TRUE;
@ -115,15 +113,22 @@ namespace Jellyfin.Plugin.SmartPlaylist.ScheduledTasks {
_logger.LogError(((Lisp.String)x.First()).Value(), x.Skip(1).ToArray()); _logger.LogError(((Lisp.String)x.First()).Value(), x.Skip(1).ToArray());
return Lisp_Boolean.TRUE; return Lisp_Boolean.TRUE;
}; };
executor.environment.Set("user", Lisp_Object.FromBase(user));
if (Plugin.Instance is not null) { if (Plugin.Instance is not null) {
executor.eval(Plugin.Instance.Configuration.InitialProgram); executor.eval(Plugin.Instance.Configuration.InitialProgram);
} else { } else {
throw new ApplicationException("Plugin Instance is not yet initialized"); throw new ApplicationException("Plugin Instance is not yet initialized");
} }
return executor;
}
private IEnumerable<Guid> FilterPlaylistItems(IEnumerable<BaseItem> items, User user, SmartPlaylistDto smartPlaylist) {
List<BaseItem> results = new List<BaseItem>();
Expression expression = new Parser(StringTokenStream.generate(smartPlaylist.Program)).parse(); // parse here, so that we don't repeat the work for each item
Executor executor = SetupExecutor();
executor.environment.Set("*user*", Lisp_Object.FromBase(user));
foreach (var i in items) { foreach (var i in items) {
executor.environment.Set("item", Lisp_Object.FromBase(i)); executor.environment.Set("*item*", Lisp_Object.FromBase(i));
var r = executor.eval(expression); var r = executor.eval(expression);
_logger.LogTrace("Item {0} evaluated to {1}", i, r.ToString()); _logger.LogTrace("Item {0} evaluated to {1}", i, r.ToString());
if ((r is not Lisp_Boolean r_bool) || (r_bool.Value())) { if ((r is not Lisp_Boolean r_bool) || (r_bool.Value())) {
@ -131,9 +136,9 @@ namespace Jellyfin.Plugin.SmartPlaylist.ScheduledTasks {
results.Add(i); results.Add(i);
} }
} }
executor = new Executor(new DefaultEnvironment()); executor = SetupExecutor();
executor.environment.Set("user", Lisp_Object.FromBase(user)); executor.environment.Set("*user*", Lisp_Object.FromBase(user));
executor.environment.Set("items", Lisp_Object.FromBase(results)); executor.environment.Set("*items*", Lisp_Object.FromBase(results));
results = new List<BaseItem>(); results = new List<BaseItem>();
var sort_result = executor.eval(smartPlaylist.SortProgram); var sort_result = executor.eval(smartPlaylist.SortProgram);
if (sort_result is Cons sorted_items) { if (sort_result is Cons sorted_items) {

View file

@ -1,5 +1,6 @@
using Lisp_Boolean = Jellyfin.Plugin.SmartPlaylist.Lisp.Boolean; using Lisp_Boolean = Jellyfin.Plugin.SmartPlaylist.Lisp.Boolean;
using Lisp_Object = Jellyfin.Plugin.SmartPlaylist.Lisp.Object; using Lisp_Object = Jellyfin.Plugin.SmartPlaylist.Lisp.Object;
using Lisp_Integer = Jellyfin.Plugin.SmartPlaylist.Lisp.Integer;
using Jellyfin.Plugin.SmartPlaylist.Lisp; using Jellyfin.Plugin.SmartPlaylist.Lisp;
using Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler; using Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler;
@ -230,6 +231,13 @@ namespace Tests
Assert.Equal("\"System.String\"", string.Format("{0}", r)); Assert.Equal("\"System.String\"", string.Format("{0}", r));
} }
[Fact]
public static void GlobalVariableTest() {
Executor e = new Executor();
e.environment.Set("*o*", new Lisp_Integer(5));
Assert.Equal("10", e.eval("(* *o* 2)").ToString());
}
[Fact] [Fact]
public static void DefaultEnvironmentTest() { public static void DefaultEnvironmentTest() {
Executor e = new Executor(new DefaultEnvironment()); Executor e = new Executor(new DefaultEnvironment());