feat: add SortProgram.

Works similar to Program, but receives the list of matched items
and should return the same list but sorted.
This can actually also be used for further filtering.
This commit is contained in:
redxef 2024-11-19 17:33:33 +01:00
parent 0844cebd88
commit f479c93c5c
Signed by: redxef
GPG key ID: 7DAC3AA211CBD921
2 changed files with 31 additions and 6 deletions

View file

@ -95,25 +95,42 @@ namespace Jellyfin.Plugin.SmartPlaylist.ScheduledTasks {
} }
private IEnumerable<Guid> FilterPlaylistItems(IEnumerable<BaseItem> items, User user, SmartPlaylistDto smartPlaylist) { private IEnumerable<Guid> FilterPlaylistItems(IEnumerable<BaseItem> items, User user, SmartPlaylistDto smartPlaylist) {
List<Guid> results = new List<Guid>(); List<BaseItem> results = new List<BaseItem>();
Expression expression = new Parser(StringTokenStream.generate(smartPlaylist.Program)).parse(); Expression expression = new Parser(StringTokenStream.generate(smartPlaylist.Program)).parse(); // parse here, so that we don't repeat the work for each item
Executor executor = new Executor(new DefaultEnvironment()); Executor executor = new Executor(new DefaultEnvironment());
executor.environment.Set("user", new Lisp_Object(user)); 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");
} }
foreach (var i in items) { foreach (var i in items) {
executor.environment.Set("item", new Lisp_Object(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())) {
_logger.LogDebug("Added '{0}' to Smart Playlist {1}", i, smartPlaylist.Name); _logger.LogDebug("Added '{0}' to Smart Playlist {1}", i, smartPlaylist.Name);
results.Add(i.Id); results.Add(i);
} }
} }
return results; executor = new Executor(new DefaultEnvironment());
executor.environment.Set("user", Lisp_Object.FromBase(user));
executor.environment.Set("items", Lisp_Object.FromBase(results));
results = new List<BaseItem>();
var sort_result = executor.eval(smartPlaylist.SortProgram);
if (sort_result is Cons sorted_items) {
foreach (var i in sorted_items.ToList()) {
if (i is Lisp_Object iObject && iObject.Value() is BaseItem iBaseItem) {
results.Add(iBaseItem);
continue;
}
throw new ApplicationException($"Returned sorted list does contain unexpected items, got {i}");
}
} else if (sort_result == Lisp_Boolean.FALSE) {
} else {
throw new ApplicationException($"Did not return a list of items, returned {sort_result}");
}
return results.Select(x => x.Id);
} }
private IEnumerable<BaseItem> GetAllUserMedia(User user) { private IEnumerable<BaseItem> GetAllUserMedia(User user) {

View file

@ -42,10 +42,12 @@ namespace Jellyfin.Plugin.SmartPlaylist {
[Serializable] [Serializable]
public class SmartPlaylistDto : ISerializable { public class SmartPlaylistDto : ISerializable {
private static string DEFAULT_PROGRAM = "(begin (invoke item \"IsFavoriteOrLiked\" (list user)))"; private static string DEFAULT_PROGRAM = "(begin (invoke item \"IsFavoriteOrLiked\" (list user)))";
private static string DEFAULT_SORT_PROGRAM = "(begin items)";
public SmartPlaylistId Id { get; set; } public SmartPlaylistId Id { get; set; }
public SmartPlaylistLinkDto[] Playlists { get; set; } public SmartPlaylistLinkDto[] Playlists { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Program { get; set; } public string Program { get; set; }
public string SortProgram { get; set; }
public string? Filename { get; set; } public string? Filename { get; set; }
public bool Enabled { get; set; } public bool Enabled { get; set; }
@ -54,6 +56,7 @@ namespace Jellyfin.Plugin.SmartPlaylist {
Playlists = []; Playlists = [];
Name = Id.ToString(); Name = Id.ToString();
Program = DEFAULT_PROGRAM; Program = DEFAULT_PROGRAM;
SortProgram = DEFAULT_SORT_PROGRAM;
Filename = null; Filename = null;
Enabled = true; Enabled = true;
} }
@ -79,6 +82,11 @@ namespace Jellyfin.Plugin.SmartPlaylist {
} else { } else {
Program = DEFAULT_PROGRAM; Program = DEFAULT_PROGRAM;
} }
if (info.GetValue("SortProgram", typeof(string)) is string _SortProgram) {
SortProgram = _SortProgram;
} else {
SortProgram = DEFAULT_SORT_PROGRAM;
}
if (info.GetValue("Filename", typeof(string)) is string _Filename) { if (info.GetValue("Filename", typeof(string)) is string _Filename) {
Filename = _Filename; Filename = _Filename;
} else { } else {