Add endpoint to update metadata

This commit is contained in:
MrLetsplay 2025-02-10 22:56:55 +01:00
parent d826999380
commit ae1d9e2bc1
Signed by: mr
SSH Key Fingerprint: SHA256:92jBH80vpXyaZHjaIl47pjRq+Yt7XGTArqQg1V7hSqg
5 changed files with 76 additions and 9 deletions

View File

@ -4,7 +4,9 @@ import java.nio.file.Path;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import me.mrletsplay.simplehttpserver.http.server.HttpServer;
import me.mrletsplay.videobase.library.Library;
@ -13,7 +15,7 @@ import me.mrletsplay.videobase.util.Hash;
public class VideoBase {
public static final Logger LOGGER = Logger.getLogger(VideoBase.class.getName());
public static final Logger LOGGER = LoggerFactory.getLogger(VideoBase.class.getName());
private static ScheduledExecutorService executor;
private static Library library;
@ -32,6 +34,7 @@ public class VideoBase {
.port(6969)
.poolSize(20)
.ioWorkers(3)
// .logger(NOPLogger.NOP_LOGGER)
.create());
new LibraryAPI().register(server.getDocumentProvider());

View File

@ -8,7 +8,6 @@ import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.logging.Level;
import java.util.stream.Collectors;
import me.mrletsplay.mrcore.json.JSONObject;
@ -76,6 +75,19 @@ public class Library {
.collect(Collectors.toList());
}
public void updateMetadata(Video video, VideoMetadata metadata) {
VideoMetadata oldMetadata = video.getMetadata();
video.setMetadata(VideoMetadata.inherit(oldMetadata, metadata));
// TODO: save metadata
}
public boolean updateMetadata(String videoId, VideoMetadata metadata) {
Video video = findVideoById(videoId);
if(video == null) return false;
updateMetadata(video, metadata);
return true;
}
public static Library load(Path path) {
List<Video> videos = new ArrayList<>();
load(path, path, videos, VideoMetadata.DEFAULT_METADATA);
@ -95,7 +107,7 @@ public class Library {
libraryMeta = JSONConverter.decodeObject(obj, LibraryMetadata.class);
defaultMetadata = VideoMetadata.inherit(defaultMetadata, libraryMeta.getDefault());
}catch(IOException | JSONParseException | ClassCastException e) {
VideoBase.LOGGER.log(Level.WARNING, "Failed to parse metadata at " + path, e);
VideoBase.LOGGER.warn("Failed to parse metadata at " + path, e);
}
}
@ -132,7 +144,7 @@ public class Library {
JSONObject obj = new JSONObject(Files.readString(videoMetaPath));
videoMeta = VideoMetadata.inherit(videoMeta, JSONConverter.decodeObject(obj, VideoMetadata.class));
}catch(IOException | JSONParseException | ClassCastException e) {
VideoBase.LOGGER.log(Level.WARNING, "Failed to parse metadata at " + path, e);
VideoBase.LOGGER.warn("Failed to parse metadata at " + path, e);
}
}else if(libraryMeta != null && libraryMeta.getOverrides().containsKey(fileName)) {
videoMeta = VideoMetadata.inherit(videoMeta, libraryMeta.getOverrides().get(fileName));
@ -142,7 +154,7 @@ public class Library {
videos.add(new Video(subPath, id, videoMeta == null ? VideoMetadata.DEFAULT_METADATA : videoMeta));
}
}catch(IOException e) {
VideoBase.LOGGER.log(Level.WARNING, "Failed to load folder at " + path, e);
VideoBase.LOGGER.warn("Failed to load folder at " + path, e);
}
}

View File

@ -22,6 +22,10 @@ public class Video {
return id;
}
public void setMetadata(VideoMetadata metadata) {
this.metadata = metadata;
}
public VideoMetadata getMetadata() {
return metadata;
}

View File

@ -4,8 +4,10 @@ import java.util.Map;
import java.util.Objects;
import me.mrletsplay.mrcore.json.JSONObject;
import me.mrletsplay.mrcore.json.JSONType;
import me.mrletsplay.mrcore.json.converter.JSONConstructor;
import me.mrletsplay.mrcore.json.converter.JSONConvertible;
import me.mrletsplay.simplehttpserver.http.validation.JsonObjectValidator;
public class VideoMetadata implements JSONConvertible {
@ -30,6 +32,12 @@ public class VideoMetadata implements JSONConvertible {
FIELD_INDEX, DEFAULT_INDEX
)));
public static final JsonObjectValidator VALIDATOR = new JsonObjectValidator()
.optional(FIELD_SERIES, JSONType.STRING)
.optional(FIELD_TITLE, JSONType.STRING)
.optional(FIELD_AUTHOR, JSONType.STRING)
.optional(FIELD_INDEX, JSONType.INTEGER);
private JSONObject metadata;
@JSONConstructor
@ -56,6 +64,10 @@ public class VideoMetadata implements JSONConvertible {
return metadata.optInt(FIELD_INDEX).orElse(null);
}
public JSONObject getRaw() {
return new JSONObject(metadata);
}
@Override
public void preDeserialize(JSONObject object) {
this.metadata = object;
@ -79,7 +91,16 @@ public class VideoMetadata implements JSONConvertible {
JSONObject meta = new JSONObject(parent == null ? null : parent.metadata);
for(String key : child.metadata.keys()) {
meta.set(key, child.metadata.get(key));
Object value = child.metadata.get(key);
if(value == null) { // Setting to null resets to default value if available, otherwise removes attribute
value = DEFAULT_METADATA.metadata.opt(key).orElse(null);
if(value == null) {
meta.remove(key);
continue;
}
}
meta.set(key, value);
}
return new VideoMetadata(meta);

View File

@ -4,18 +4,20 @@ import java.util.List;
import me.mrletsplay.mrcore.json.JSONArray;
import me.mrletsplay.mrcore.json.JSONObject;
import me.mrletsplay.mrcore.json.converter.SerializationOption;
import me.mrletsplay.simplehttpserver.http.HttpRequestMethod;
import me.mrletsplay.simplehttpserver.http.HttpStatusCodes;
import me.mrletsplay.simplehttpserver.http.endpoint.Endpoint;
import me.mrletsplay.simplehttpserver.http.endpoint.EndpointCollection;
import me.mrletsplay.simplehttpserver.http.endpoint.RequestParameter;
import me.mrletsplay.simplehttpserver.http.header.DefaultClientContentTypes;
import me.mrletsplay.simplehttpserver.http.request.HttpRequestContext;
import me.mrletsplay.simplehttpserver.http.response.JsonResponse;
import me.mrletsplay.simplehttpserver.http.response.TextResponse;
import me.mrletsplay.simplehttpserver.http.validation.result.ValidationResult;
import me.mrletsplay.videobase.VideoBase;
import me.mrletsplay.videobase.library.Library;
import me.mrletsplay.videobase.library.Video;
import me.mrletsplay.videobase.library.VideoMetadata;
public class LibraryAPI implements EndpointCollection {
@ -89,10 +91,35 @@ public class LibraryAPI implements EndpointCollection {
ctx.respond(HttpStatusCodes.OK_200, new JsonResponse(videoToJSON(video)));
}
@Endpoint(method = HttpRequestMethod.PUT, path = "/video/{video}/metadata", pathPattern = true)
public void updateVideoMetadata(HttpRequestContext ctx, @RequestParameter("video") String videoId) {
Library library = VideoBase.getLibrary();
Video video = VideoBase.getLibrary().findVideoById(videoId);
if(video == null) {
ctx.respond(HttpStatusCodes.NOT_FOUND_404, new TextResponse("Not found"));
return;
}
JSONObject metadata = ctx.expectContent(DefaultClientContentTypes.JSON_OBJECT);
if(metadata == null) {
ctx.respond(HttpStatusCodes.BAD_REQUEST_400, ValidationResult.error("_", "Invalid content").asJsonResponse());
return;
}
ValidationResult result = VideoMetadata.VALIDATOR.validate(metadata);
if(!result.isOk()) {
ctx.respond(HttpStatusCodes.BAD_REQUEST_400, result.asJsonResponse());
return;
}
library.updateMetadata(video, new VideoMetadata(metadata));
ctx.respond(HttpStatusCodes.OK_200, new JsonResponse(video.getMetadata().getRaw()));
}
private JSONObject videoToJSON(Video video) {
JSONObject v = new JSONObject();
v.put("id", video.getId());
v.put("metadata", video.getMetadata().toJSON(SerializationOption.DONT_INCLUDE_CLASS));
v.put("metadata", video.getMetadata().getRaw());
return v;
}