132 lines
4.9 KiB
C#
132 lines
4.9 KiB
C#
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; }
|
|
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;
|
|
private readonly ILibraryManager _libraryManager;
|
|
|
|
public LispPlaygroundController(
|
|
ILogger<LispPlaygroundController> logger,
|
|
ILibraryManager libraryManager
|
|
) {
|
|
_logger = logger;
|
|
_libraryManager = libraryManager;
|
|
}
|
|
|
|
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;
|
|
};
|
|
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;
|
|
}
|
|
|
|
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 input;
|
|
using (StreamReader reader = new StreamReader(Request.Body)) {
|
|
input = await reader.ReadToEndAsync();
|
|
}
|
|
var dto = new DeserializerBuilder().Build().Deserialize<ProgramInputDto>(input);
|
|
StringBuilder output = new StringBuilder();
|
|
var e = SetupExecutor(output, extractItemIds(dto.InputLinks));
|
|
var r = e.eval(dto.Program).ToString();
|
|
return Ok(new ProgramOutputDto() {
|
|
FinalExpression = r,
|
|
Output = output.ToString(),
|
|
});
|
|
} catch (Exception ex) {
|
|
return Ok(new ProgramOutputDto() {
|
|
Traceback = ex.ToString(),
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|