jellyfin-smart-playlist/Jellyfin.Plugin.SmartPlaylist/Api/LispPlaygroundController.cs

101 lines
3.7 KiB
C#

using System.Net.Mime;
using System.Text;
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 Jellyfin.Plugin.SmartPlaylist.Lisp;
namespace Jellyfin.Plugin.SmartPlaylist.Api {
[Serializable]
public class ProgramOutputDto {
public string Output { get; set; }
public string FinalExpression { get; set; }
public string Traceback { get; set; }
}
[ApiController]
[Authorize(Policy = Policies.RequiresElevation)]
[Route("LispPlayground")]
[Produces(MediaTypeNames.Application.Json)]
public class LispPlaygroundController : ControllerBase {
private readonly ILogger _logger;
public LispPlaygroundController(
ILogger<LispPlaygroundController> logger
) {
_logger = logger;
}
private Executor SetupExecutor(StringBuilder sb) {
var env = new DefaultEnvironment();
var executor = new Executor(env);
executor.builtins["logd"] = (x) => {
_logger.LogDebug(((Lisp.String)x.First()).Value(), x.Skip(1).ToArray());
return Lisp.Boolean.TRUE;
};
executor.builtins["logi"] = (x) => {
_logger.LogInformation(((Lisp.String)x.First()).Value(), x.Skip(1).ToArray());
return Lisp.Boolean.TRUE;
};
executor.builtins["logw"] = (x) => {
_logger.LogWarning(((Lisp.String)x.First()).Value(), x.Skip(1).ToArray());
return Lisp.Boolean.TRUE;
};
executor.builtins["loge"] = (x) => {
_logger.LogError(((Lisp.String)x.First()).Value(), x.Skip(1).ToArray());
return Lisp.Boolean.TRUE;
};
executor.builtins["print"] = (x) => {
sb.Append(string.Join(" ", x.Select((i) => {
if (i is Lisp.String i_s) {
return i_s.Value();
}
return i.ToString();
})));
return Lisp.Boolean.TRUE;
};
executor.builtins["print"] = (x) => {
sb.Append(string.Join(" ", x.Select((i) => {
if (i is Lisp.String i_s) {
return i_s.Value();
}
return i.ToString();
})));
sb.Append("\n");
return Lisp.Boolean.TRUE;
};
if (Plugin.Instance is not null) {
executor.eval(Plugin.Instance.Configuration.InitialProgram);
} else {
throw new ApplicationException("Plugin Instance is not yet initialized");
}
return executor;
}
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<ProgramOutputDto>> SetPlaylist() {
try {
string program;
using (StreamReader reader = new StreamReader(Request.Body)) {
program = await reader.ReadToEndAsync();
}
StringBuilder output = new StringBuilder();
var e = SetupExecutor(output);
var r = e.eval(program).ToString();
return Ok(new ProgramOutputDto() {
FinalExpression = r,
Output = output.ToString(),
});
} catch (Exception ex) {
return Ok(new ProgramOutputDto() {
Traceback = ex.ToString(),
});
}
}
}
}