Add endpoint for thumbnails (WIP)

This commit is contained in:
MrLetsplay 2025-02-11 23:05:29 +01:00
parent 3dbc1b54d6
commit f3e321d8c7
Signed by: mr
SSH Key Fingerprint: SHA256:92jBH80vpXyaZHjaIl47pjRq+Yt7XGTArqQg1V7hSqg
3 changed files with 96 additions and 4 deletions

View File

@ -8,6 +8,7 @@ import java.util.concurrent.TimeUnit;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import me.mrletsplay.simplehttpserver.http.cors.CorsConfiguration;
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;
import me.mrletsplay.videobase.rest.LibraryAPI; import me.mrletsplay.videobase.rest.LibraryAPI;
@ -35,6 +36,7 @@ public class VideoBase {
.poolSize(20) .poolSize(20)
.ioWorkers(3) .ioWorkers(3)
// .logger(NOPLogger.NOP_LOGGER) // .logger(NOPLogger.NOP_LOGGER)
.defaultCorsConfiguration(CorsConfiguration.createAllowAll())
.create()); .create());
new LibraryAPI().register(server.getDocumentProvider()); new LibraryAPI().register(server.getDocumentProvider());

View File

@ -1,7 +1,12 @@
package me.mrletsplay.videobase.rest; package me.mrletsplay.videobase.rest;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List; import java.util.List;
import javax.imageio.ImageIO;
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.simplehttpserver.http.HttpRequestMethod; import me.mrletsplay.simplehttpserver.http.HttpRequestMethod;
@ -13,11 +18,13 @@ 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.util.MimeType;
import me.mrletsplay.simplehttpserver.http.validation.result.ValidationResult; 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; import me.mrletsplay.videobase.library.VideoMetadata;
import me.mrletsplay.videobase.util.ThumbnailCreator;
public class LibraryAPI implements EndpointCollection { public class LibraryAPI implements EndpointCollection {
@ -71,10 +78,6 @@ public class LibraryAPI implements EndpointCollection {
videosObj.put(group, videosArr); videosObj.put(group, videosArr);
} }
if(!"none".equals("groupBy")) {
}
libraryObj.put("videos", videosObj); libraryObj.put("videos", videosObj);
ctx.respond(HttpStatusCodes.OK_200, new JsonResponse(libraryObj)); ctx.respond(HttpStatusCodes.OK_200, new JsonResponse(libraryObj));
@ -127,6 +130,30 @@ public class LibraryAPI implements EndpointCollection {
ctx.respond(HttpStatusCodes.OK_200, new JsonResponse(video.getMetadata().getRaw())); ctx.respond(HttpStatusCodes.OK_200, new JsonResponse(video.getMetadata().getRaw()));
} }
@Endpoint(method = HttpRequestMethod.GET, path = "/video/{video}/thumbnail", pathPattern = true)
public void getThumbnail(HttpRequestContext ctx, @RequestParameter("video") String videoId) {
Video video = VideoBase.getLibrary().findVideoById(videoId);
if(video == null) {
ctx.respond(HttpStatusCodes.NOT_FOUND_404, new TextResponse("Not found"));
return;
}
BufferedImage thumbnail = ThumbnailCreator.createThumbnail(video.getPath());
if(thumbnail == null) {
ctx.respond(HttpStatusCodes.NOT_FOUND_404, new TextResponse("No thumbnail found"));
return;
}
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
try {
ImageIO.write(thumbnail, "PNG", bOut);
} catch (IOException e) {
ctx.respond(HttpStatusCodes.INTERNAL_SERVER_ERROR_500, new TextResponse("Failed to create thumbnail"));
}
ctx.getServerHeader().setContent(MimeType.PNG, bOut.toByteArray());
}
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());

View File

@ -0,0 +1,63 @@
package me.mrletsplay.videobase.util;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
import javax.imageio.ImageIO;
import me.mrletsplay.videobase.VideoBase;
public class ThumbnailCreator {
public static BufferedImage createThumbnail(Path videoPath) {
ProcessBuilder ffmpegBuilder = new ProcessBuilder("ffmpeg",
"-i", videoPath.toAbsolutePath().toString(),
"-vf", "thumbnail",
"-vf", "scale=960:540:force_original_aspect_ratio=decrease,pad=960:540:-1:-1:color=black",
"-frames:v", "1",
"-f", "image2pipe",
"-vcodec", "png",
"-"
);
try {
Process ffmpeg = ffmpegBuilder.start();
long start = System.currentTimeMillis();
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int len;
while(System.currentTimeMillis() - start < 1000
&& (len = ffmpeg.getInputStream().read(buf)) > 0) {
bOut.write(buf, 0, len);
}
ffmpeg.waitFor(10, TimeUnit.SECONDS);
if(ffmpeg.isAlive()) {
VideoBase.LOGGER.warn("ffmpeg didn't exit after 10 seconds, destroying");
ffmpeg.destroy();
if(!ffmpeg.waitFor(10, TimeUnit.SECONDS)) {
VideoBase.LOGGER.warn("ffmpeg didn't exit 10 seconds after destroying, destroying forcibly");
ffmpeg.destroyForcibly();
}
return null;
}
return ImageIO.read(new ByteArrayInputStream(bOut.toByteArray()));
} catch (InterruptedException | IOException e) {
e.printStackTrace();
return null;
}
}
}