Add endpoint for thumbnails (WIP)
This commit is contained in:
parent
3dbc1b54d6
commit
f3e321d8c7
@ -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());
|
||||||
|
@ -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());
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user