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.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; 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.simplehttpserver.http.server.HttpServer;
import me.mrletsplay.videobase.library.Library; import me.mrletsplay.videobase.library.Library;
@ -13,7 +15,7 @@ import me.mrletsplay.videobase.util.Hash;
public class VideoBase { 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 ScheduledExecutorService executor;
private static Library library; private static Library library;
@ -32,6 +34,7 @@ public class VideoBase {
.port(6969) .port(6969)
.poolSize(20) .poolSize(20)
.ioWorkers(3) .ioWorkers(3)
// .logger(NOPLogger.NOP_LOGGER)
.create()); .create());
new LibraryAPI().register(server.getDocumentProvider()); new LibraryAPI().register(server.getDocumentProvider());

View File

@ -8,7 +8,6 @@ import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import me.mrletsplay.mrcore.json.JSONObject; import me.mrletsplay.mrcore.json.JSONObject;
@ -76,6 +75,19 @@ public class Library {
.collect(Collectors.toList()); .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) { public static Library load(Path path) {
List<Video> videos = new ArrayList<>(); List<Video> videos = new ArrayList<>();
load(path, path, videos, VideoMetadata.DEFAULT_METADATA); load(path, path, videos, VideoMetadata.DEFAULT_METADATA);
@ -95,7 +107,7 @@ public class Library {
libraryMeta = JSONConverter.decodeObject(obj, LibraryMetadata.class); libraryMeta = JSONConverter.decodeObject(obj, LibraryMetadata.class);
defaultMetadata = VideoMetadata.inherit(defaultMetadata, libraryMeta.getDefault()); defaultMetadata = VideoMetadata.inherit(defaultMetadata, libraryMeta.getDefault());
}catch(IOException | JSONParseException | ClassCastException e) { }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)); JSONObject obj = new JSONObject(Files.readString(videoMetaPath));
videoMeta = VideoMetadata.inherit(videoMeta, JSONConverter.decodeObject(obj, VideoMetadata.class)); videoMeta = VideoMetadata.inherit(videoMeta, JSONConverter.decodeObject(obj, VideoMetadata.class));
}catch(IOException | JSONParseException | ClassCastException e) { }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)) { }else if(libraryMeta != null && libraryMeta.getOverrides().containsKey(fileName)) {
videoMeta = VideoMetadata.inherit(videoMeta, libraryMeta.getOverrides().get(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)); videos.add(new Video(subPath, id, videoMeta == null ? VideoMetadata.DEFAULT_METADATA : videoMeta));
} }
}catch(IOException e) { }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; return id;
} }
public void setMetadata(VideoMetadata metadata) {
this.metadata = metadata;
}
public VideoMetadata getMetadata() { public VideoMetadata getMetadata() {
return metadata; return metadata;
} }

View File

@ -4,8 +4,10 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import me.mrletsplay.mrcore.json.JSONObject; 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.JSONConstructor;
import me.mrletsplay.mrcore.json.converter.JSONConvertible; import me.mrletsplay.mrcore.json.converter.JSONConvertible;
import me.mrletsplay.simplehttpserver.http.validation.JsonObjectValidator;
public class VideoMetadata implements JSONConvertible { public class VideoMetadata implements JSONConvertible {
@ -30,6 +32,12 @@ public class VideoMetadata implements JSONConvertible {
FIELD_INDEX, DEFAULT_INDEX 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; private JSONObject metadata;
@JSONConstructor @JSONConstructor
@ -56,6 +64,10 @@ public class VideoMetadata implements JSONConvertible {
return metadata.optInt(FIELD_INDEX).orElse(null); return metadata.optInt(FIELD_INDEX).orElse(null);
} }
public JSONObject getRaw() {
return new JSONObject(metadata);
}
@Override @Override
public void preDeserialize(JSONObject object) { public void preDeserialize(JSONObject object) {
this.metadata = object; this.metadata = object;
@ -79,7 +91,16 @@ public class VideoMetadata implements JSONConvertible {
JSONObject meta = new JSONObject(parent == null ? null : parent.metadata); JSONObject meta = new JSONObject(parent == null ? null : parent.metadata);
for(String key : child.metadata.keys()) { 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); 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.JSONArray;
import me.mrletsplay.mrcore.json.JSONObject; import me.mrletsplay.mrcore.json.JSONObject;
import me.mrletsplay.mrcore.json.converter.SerializationOption;
import me.mrletsplay.simplehttpserver.http.HttpRequestMethod; import me.mrletsplay.simplehttpserver.http.HttpRequestMethod;
import me.mrletsplay.simplehttpserver.http.HttpStatusCodes; import me.mrletsplay.simplehttpserver.http.HttpStatusCodes;
import me.mrletsplay.simplehttpserver.http.endpoint.Endpoint; import me.mrletsplay.simplehttpserver.http.endpoint.Endpoint;
import me.mrletsplay.simplehttpserver.http.endpoint.EndpointCollection; import me.mrletsplay.simplehttpserver.http.endpoint.EndpointCollection;
import me.mrletsplay.simplehttpserver.http.endpoint.RequestParameter; 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.request.HttpRequestContext;
import me.mrletsplay.simplehttpserver.http.response.JsonResponse; import me.mrletsplay.simplehttpserver.http.response.JsonResponse;
import me.mrletsplay.simplehttpserver.http.response.TextResponse; import me.mrletsplay.simplehttpserver.http.response.TextResponse;
import me.mrletsplay.simplehttpserver.http.validation.result.ValidationResult;
import me.mrletsplay.videobase.VideoBase; import me.mrletsplay.videobase.VideoBase;
import me.mrletsplay.videobase.library.Library; import me.mrletsplay.videobase.library.Library;
import me.mrletsplay.videobase.library.Video; import me.mrletsplay.videobase.library.Video;
import me.mrletsplay.videobase.library.VideoMetadata;
public class LibraryAPI implements EndpointCollection { public class LibraryAPI implements EndpointCollection {
@ -89,10 +91,35 @@ public class LibraryAPI implements EndpointCollection {
ctx.respond(HttpStatusCodes.OK_200, new JsonResponse(videoToJSON(video))); 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) { private JSONObject videoToJSON(Video video) {
JSONObject v = new JSONObject(); JSONObject v = new JSONObject();
v.put("id", video.getId()); v.put("id", video.getId());
v.put("metadata", video.getMetadata().toJSON(SerializationOption.DONT_INCLUDE_CLASS)); v.put("metadata", video.getMetadata().getRaw());
return v; return v;
} }