feat: allow specifying items as inputs for the lisp playground.
Refs: #6
This commit is contained in:
parent
b35df95d86
commit
a00b01c577
3 changed files with 56 additions and 14 deletions
|
@ -1,15 +1,26 @@
|
|||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using MediaBrowser.Common.Api;
|
||||
using MediaBrowser.Controller.Library;
|
||||
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
using Jellyfin.Plugin.SmartPlaylist.Lisp;
|
||||
|
||||
namespace Jellyfin.Plugin.SmartPlaylist.Api {
|
||||
|
||||
[Serializable]
|
||||
public class ProgramInputDto {
|
||||
public string InputLinks { get; set; }
|
||||
public string Program { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ProgramOutputDto {
|
||||
public string Output { get; set; }
|
||||
|
@ -23,16 +34,21 @@ namespace Jellyfin.Plugin.SmartPlaylist.Api {
|
|||
[Produces(MediaTypeNames.Application.Json)]
|
||||
public class LispPlaygroundController : ControllerBase {
|
||||
private readonly ILogger _logger;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
public LispPlaygroundController(
|
||||
ILogger<LispPlaygroundController> logger
|
||||
ILogger<LispPlaygroundController> logger,
|
||||
ILibraryManager libraryManager
|
||||
) {
|
||||
_logger = logger;
|
||||
_libraryManager = libraryManager;
|
||||
}
|
||||
|
||||
private Executor SetupExecutor(StringBuilder sb) {
|
||||
private Executor SetupExecutor(StringBuilder sb, IList<string> inputs) {
|
||||
var env = new DefaultEnvironment();
|
||||
var executor = new Executor(env);
|
||||
|
||||
env["*items*"] = Lisp.Cons.FromList(inputs.Select(x => _libraryManager.GetItemById(x)).Select(x => Lisp.Object.FromBase(x)).ToList());
|
||||
executor.builtins["logd"] = (x) => {
|
||||
_logger.LogDebug(((Lisp.String)x.First()).Value(), x.Skip(1).ToArray());
|
||||
return Lisp.Boolean.TRUE;
|
||||
|
@ -76,17 +92,32 @@ namespace Jellyfin.Plugin.SmartPlaylist.Api {
|
|||
return executor;
|
||||
}
|
||||
|
||||
private List<string> extractItemIds(string s) {
|
||||
List<string> r = new List<string>();
|
||||
foreach (string line in s.Split("\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)) {
|
||||
var uri = new Uri(line);
|
||||
uri = new Uri("http://some-domain.tld" + uri.Fragment.Substring(1));
|
||||
var id = HttpUtility.ParseQueryString(uri.Query).Get("id");
|
||||
if (id == null) {
|
||||
continue;
|
||||
}
|
||||
r.Add(id);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<ProgramOutputDto>> SetPlaylist() {
|
||||
try {
|
||||
string program;
|
||||
string input;
|
||||
using (StreamReader reader = new StreamReader(Request.Body)) {
|
||||
program = await reader.ReadToEndAsync();
|
||||
input = await reader.ReadToEndAsync();
|
||||
}
|
||||
var dto = new DeserializerBuilder().Build().Deserialize<ProgramInputDto>(input);
|
||||
StringBuilder output = new StringBuilder();
|
||||
var e = SetupExecutor(output);
|
||||
var r = e.eval(program).ToString();
|
||||
var e = SetupExecutor(output, extractItemIds(dto.InputLinks));
|
||||
var r = e.eval(dto.Program).ToString();
|
||||
return Ok(new ProgramOutputDto() {
|
||||
FinalExpression = r,
|
||||
Output = output.ToString(),
|
||||
|
|
|
@ -9,20 +9,27 @@
|
|||
<div data-role="content">
|
||||
<div class="content-primary">
|
||||
<form id="LispPlaygroundConfigForm">
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="LispPlaygroundInputLinks">Input Items</label>
|
||||
<div class="fieldDescription">
|
||||
Items which should be given to the filter program, one link per line.
|
||||
The program will get this list in the variable <code>*items*</code>.
|
||||
<textarea id="LispPlaygroundInputLinks" class="emby-input smartplayground-monospace" name="InputLinks" rows="16" cols="120"></textarea>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="LispPlaygroundEditProgram">Program</label>
|
||||
<div class="fieldDescription">A program which should return <code>t</code> or <code>nil</code> to include or exclude the provided <code>item</code>.</div>
|
||||
<textarea id="LispPlaygroundEditProgram" class="emby-input smartcollection-monospace" name="Program" rows="16" cols="120"></textarea>
|
||||
<textarea id="LispPlaygroundEditProgram" class="emby-input smartplayground-monospace" name="Program" rows="16" cols="120"></textarea>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="LispPlaygroundOutput">Output</label>
|
||||
<div class="fieldDescription">The output of the program.</div>
|
||||
<textarea id="LispPlaygroundOutput" class="emby-input smartcollection-monospace" name="Output" rows="16" cols="120"></textarea>
|
||||
<textarea id="LispPlaygroundOutput" class="emby-input smartplayground-monospace" name="Output" rows="16" cols="120"></textarea>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="LispPlaygroundReturn">Final expression</label>
|
||||
<div class="fieldDescription">The final expression the program has been reduced to.</div>
|
||||
<textarea id="LispPlaygroundReturn" class="emby-input smartcollection-monospace" name="Output" rows="1" cols="120"></textarea>
|
||||
<textarea id="LispPlaygroundReturn" class="emby-input smartplayground-monospace" name="Output" rows="1" cols="120"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<button is="emby-button" type="submit" class="raised button-submit block emby-button">
|
||||
|
@ -33,7 +40,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.smartcollection-monospace {
|
||||
.smartplayground-monospace {
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -6,14 +6,17 @@ function fillForm(o) {
|
|||
return_.value = (o.hasOwnProperty("FinalExpression")) ? o.FinalExpression : '';
|
||||
}
|
||||
|
||||
ApiClient.runLispProgram = function (program) {
|
||||
ApiClient.runLispProgram = function (inputLinks, program) {
|
||||
const url = ApiClient.getUrl('LispPlayground');
|
||||
return this.ajax({
|
||||
type: 'POST',
|
||||
url: url,
|
||||
dataType: 'json',
|
||||
contentType: 'text/plain; charset=UTF-8',
|
||||
data: program,
|
||||
contentType: 'application/json; charset=UTF-8',
|
||||
data: JSON.stringify({
|
||||
InputLinks: inputLinks,
|
||||
Program: program,
|
||||
}),
|
||||
});
|
||||
}
|
||||
function initial_load() {
|
||||
|
@ -37,8 +40,9 @@ export default function (view, params) {
|
|||
.addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
Dashboard.showLoadingMsg();
|
||||
const editInputLinks = document.querySelector('#LispPlaygroundInputLinks');
|
||||
const editProgram = document.querySelector('#LispPlaygroundEditProgram');
|
||||
ApiClient.runLispProgram(editProgram.value).then(function (r) {
|
||||
ApiClient.runLispProgram(editInputLinks.value, editProgram.value).then(function (r) {
|
||||
fillForm(r);
|
||||
Dashboard.hideLoadingMsg();
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue