Update quarkus to version 3.30.2
* Also adds a bunch of old things I don't remember writing
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,5 +1,5 @@
|
||||
executable:
|
||||
./mvnw package -Pnative -Dquarkus.native.additional-build-args="--initialize-at-run-time=sun.java2d.Disposer" $(EXECUTABLE_ARGS)
|
||||
./mvnw package -Pnative -Dquarkus.native.file-encoding=UTF-8 -Dquarkus.native.additional-build-args="--initialize-at-run-time=sun.java2d.Disposer" $(EXECUTABLE_ARGS)
|
||||
|
||||
image:
|
||||
docker build -t rhiobet/lalafin$(IMAGE_TAG) . -f src/main/docker/Dockerfile.native
|
||||
|
||||
@@ -18,7 +18,9 @@ stdenv.mkDerivation rec {
|
||||
'';
|
||||
|
||||
postFixup = ''
|
||||
wrapProgram $out/bin/lalafin --prefix PATH : ${pkgs.imagemagick}/bin
|
||||
wrapProgram $out/bin/lalafin \
|
||||
--prefix PATH : ${pkgs.imagemagick}/bin \
|
||||
--prefix LD_LIBRARY_PATH : ${pkgs.stdenv.cc.cc.lib}/lib
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
|
||||
23
pom.xml
23
pom.xml
@@ -6,17 +6,17 @@
|
||||
<artifactId>lalafin</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<properties>
|
||||
<compiler-plugin.version>3.8.1</compiler-plugin.version>
|
||||
<compiler-plugin.version>3.12.1</compiler-plugin.version>
|
||||
<maven.compiler.parameters>true</maven.compiler.parameters>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<quarkus-plugin.version>3.4.1</quarkus-plugin.version>
|
||||
<quarkus-plugin.version>3.30.2</quarkus-plugin.version>
|
||||
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
|
||||
<quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
|
||||
<quarkus.platform.version>3.4.1</quarkus.platform.version>
|
||||
<surefire-plugin.version>2.22.1</surefire-plugin.version>
|
||||
<quarkus.platform.version>3.30.2</quarkus.platform.version>
|
||||
<surefire-plugin.version>3.2.3</surefire-plugin.version>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
@@ -32,19 +32,19 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-resteasy-reactive</artifactId>
|
||||
<artifactId>quarkus-rest</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-resteasy-reactive-qute</artifactId>
|
||||
<artifactId>quarkus-rest-qute</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
|
||||
<artifactId>quarkus-rest-jackson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-resteasy-reactive-jaxb</artifactId>
|
||||
<artifactId>quarkus-rest-jaxb</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
@@ -107,7 +107,8 @@
|
||||
<profile>
|
||||
<id>native</id>
|
||||
<properties>
|
||||
<quarkus.package.type>native</quarkus.package.type>
|
||||
<quarkus.native.enabled>true</quarkus.native.enabled>
|
||||
<quarkus.package.jar.enabled>false</quarkus.package.jar.enabled>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package sh.rhiobet.lalafin.api;
|
||||
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.GET;
|
||||
@@ -50,11 +52,24 @@ public class FilePublicAPI {
|
||||
String decodedFile = URLDecoder.decode(token.file, StandardCharsets.UTF_8);
|
||||
if (request.remoteAddress().host().toString().equals(token.ip)
|
||||
&& System.currentTimeMillis() < token.timestamp + 172800000) {
|
||||
FileInfoBase fileInfoBase = fileInfoService.getInfo(decodedFile.split("/"), null);
|
||||
if (fileInfoBase instanceof FileInfo) {
|
||||
return fileServeService.serveFile((FileInfo) fileInfoBase, range);
|
||||
String[] decodedFileSplitted = decodedFile.split("/");
|
||||
FileInfoBase fileInfoBase;
|
||||
if (decodedFileSplitted[decodedFileSplitted.length - 2].endsWith(".zip")) {
|
||||
fileInfoBase = fileInfoService.getInfo(
|
||||
Arrays.copyOf(decodedFileSplitted, decodedFileSplitted.length - 1), null);
|
||||
if (fileInfoBase instanceof FileInfo) {
|
||||
return fileServeService.serveArchiveContent((FileInfo) fileInfoBase,
|
||||
decodedFileSplitted[decodedFileSplitted.length - 1]);
|
||||
} else {
|
||||
return Response.status(Response.Status.NOT_FOUND).build();
|
||||
}
|
||||
} else {
|
||||
return Response.status(Response.Status.NOT_FOUND).build();
|
||||
fileInfoBase = fileInfoService.getInfo(decodedFileSplitted, null);
|
||||
if (fileInfoBase instanceof FileInfo) {
|
||||
return fileServeService.serveFile((FileInfo) fileInfoBase, range);
|
||||
} else {
|
||||
return Response.status(Response.Status.NOT_FOUND).build();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Response.status(Response.Status.FORBIDDEN).build();
|
||||
|
||||
30
src/main/java/sh/rhiobet/lalafin/api/model/ArchiveInfo.java
Normal file
30
src/main/java/sh/rhiobet/lalafin/api/model/ArchiveInfo.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package sh.rhiobet.lalafin.api.model;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
|
||||
@RegisterForReflection
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class ArchiveInfo extends FileInfo {
|
||||
|
||||
public List<FileInfoBase> content;
|
||||
|
||||
public ArchiveInfo(String filename, String thumbnailUrl, String directUrl, String viewUrl,
|
||||
String publicApiUrl) {
|
||||
super(filename, thumbnailUrl, directUrl, publicApiUrl);
|
||||
this.content = new ArrayList<>();
|
||||
this.viewUrl = viewUrl;
|
||||
this.type = "archive";
|
||||
}
|
||||
|
||||
public ArchiveInfo(String filename, String thumbnailUrl, String directUrl, String viewUrl) {
|
||||
this(filename, thumbnailUrl, directUrl, viewUrl, "");
|
||||
}
|
||||
|
||||
public ArchiveInfo(String filename, String directUrl) {
|
||||
this(filename, "", directUrl, "");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -84,10 +84,14 @@ public class JellyfinThumbnailGenerator implements ThumbnailGenerator {
|
||||
try {
|
||||
Optional<Path> imgPath;
|
||||
|
||||
Path posterPath = folderPath.resolve("poster.jpg");
|
||||
if (Files.exists(posterPath)) {
|
||||
// Check for series poster
|
||||
imgPath = Optional.of(posterPath);
|
||||
Path posterPathJpg = folderPath.resolve("poster.jpg");
|
||||
Path posterPathPng = folderPath.resolve("poster.png");
|
||||
if (Files.exists(posterPathJpg)) {
|
||||
// Check for series poster (jpg)
|
||||
imgPath = Optional.of(posterPathJpg);
|
||||
} else if (Files.exists(posterPathPng)) {
|
||||
// Check for series poster (png)
|
||||
imgPath = Optional.of(posterPathPng);
|
||||
} else if (folderPath.getFileName().toString().startsWith("Season ")
|
||||
|| (folderPath.getFileName().toString().equals("Specials"))) {
|
||||
// Season folder
|
||||
@@ -95,10 +99,22 @@ public class JellyfinThumbnailGenerator implements ThumbnailGenerator {
|
||||
if (folderName.startsWith("Season ")) {
|
||||
String seasonNumber =
|
||||
String.format("%02d", Integer.parseInt(folderName.substring(7)));
|
||||
imgPath = Optional
|
||||
.of(folderPath.resolveSibling("season" + seasonNumber + "-poster.jpg"));
|
||||
Path seasonPathJpg =
|
||||
folderPath.resolveSibling("season" + seasonNumber + "-poster.jpg");
|
||||
if (Files.exists(seasonPathJpg)) {
|
||||
imgPath = Optional.of(seasonPathJpg);
|
||||
} else {
|
||||
imgPath = Optional.of(folderPath
|
||||
.resolveSibling("season" + seasonNumber + "-poster.png"));
|
||||
}
|
||||
} else {
|
||||
imgPath = Optional.of(folderPath.resolveSibling("season-specials-poster.jpg"));
|
||||
Path specialsPathJpg = folderPath.resolveSibling("season-specials-poster.jpg");
|
||||
if (Files.exists(specialsPathJpg)) {
|
||||
imgPath = Optional.of(specialsPathJpg);
|
||||
} else {
|
||||
imgPath = Optional
|
||||
.of(folderPath.resolveSibling("season-specials-poster.png"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
imgPath = Optional.empty();
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipFile;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.core.PathSegment;
|
||||
@@ -16,6 +17,7 @@ import sh.rhiobet.lalafin.LalafinConfiguration;
|
||||
import sh.rhiobet.lalafin.api.advent.AdventAccessService;
|
||||
import sh.rhiobet.lalafin.api.configuration.FileApiConfiguration;
|
||||
import sh.rhiobet.lalafin.api.internal.redis.FileTokenProvider;
|
||||
import sh.rhiobet.lalafin.api.model.ArchiveInfo;
|
||||
import sh.rhiobet.lalafin.api.model.FileInfo;
|
||||
import sh.rhiobet.lalafin.api.model.FileInfoBase;
|
||||
import sh.rhiobet.lalafin.api.model.FolderInfo;
|
||||
@@ -110,7 +112,7 @@ public class FileInfoService {
|
||||
}
|
||||
StringBuilder playlistContent = new StringBuilder();
|
||||
try {
|
||||
Stream<Path> stream = Files.list(path);
|
||||
Stream<Path> stream = Files.list(path).sorted();
|
||||
stream.forEach(p -> {
|
||||
String fileName = p.getFileName().toString();
|
||||
String fileUri = URLEncoder.encode(fileName, StandardCharsets.UTF_8)
|
||||
@@ -213,22 +215,50 @@ public class FileInfoService {
|
||||
return folderInfo;
|
||||
} else {
|
||||
String requestedFilenameUri = URLEncoder
|
||||
.encode(requestedFilename, StandardCharsets.UTF_8).replace("+", "%20");
|
||||
FileInfo fileInfo = new FileInfo(requestedFilename, "/file" + requestedUri);
|
||||
if (!requestedThumbUrl.isEmpty()) {
|
||||
fileInfo.thumbnailUrl = requestedThumbUrl;
|
||||
}
|
||||
if (fileTokenProvider != null) {
|
||||
fileInfo.publicApiUrl =
|
||||
"/api/public/file/token/" + fileTokenProvider.getFileToken(requestedUri)
|
||||
+ "/" + requestedFilenameUri;
|
||||
}
|
||||
.encode(requestedFilename, StandardCharsets.UTF_8).replace("+", "%20");
|
||||
if (requestedFilename.endsWith(".zip")) {
|
||||
fileInfo.viewUrl = "/view" + requestedUri + "/1";
|
||||
} else if (requestedFilename.endsWith(".epub")) {
|
||||
fileInfo.viewUrl = "/view" + requestedUri + "/0";
|
||||
ArchiveInfo archiveInfo = new ArchiveInfo(requestedFilename, "/file" + requestedUri);
|
||||
if (!requestedThumbUrl.isEmpty()) {
|
||||
archiveInfo.thumbnailUrl = requestedThumbUrl;
|
||||
}
|
||||
archiveInfo.viewUrl = "/view" + requestedUri + "/1";
|
||||
|
||||
Path zipPath = Paths.get(fileApiConfiguration.directory() + "/file/" + requestedPath);
|
||||
try {
|
||||
ZipFile zipFile = new ZipFile(zipPath.toFile());
|
||||
zipFile.stream().filter(e -> !e.isDirectory()).forEach(e -> {
|
||||
String zipEntryName = e.getName();
|
||||
String zipEntryNameUri =
|
||||
URLEncoder.encode(zipEntryName, StandardCharsets.UTF_8).replace("+", "%20");
|
||||
String zipEntryUri = requestedUri + "/" + zipEntryNameUri;
|
||||
FileInfo zipEntryInfo = new FileInfo(zipEntryName, "/file" + zipEntryUri);
|
||||
if (fileTokenProvider != null) {
|
||||
zipEntryInfo.publicApiUrl = "/api/public/file/token/"
|
||||
+ fileTokenProvider.getFileToken(zipEntryUri) + "/" + zipEntryNameUri;
|
||||
}
|
||||
archiveInfo.content.add(zipEntryInfo);
|
||||
});
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return archiveInfo;
|
||||
} else {
|
||||
FileInfo fileInfo = new FileInfo(requestedFilename, "/file" + requestedUri);
|
||||
if (!requestedThumbUrl.isEmpty()) {
|
||||
fileInfo.thumbnailUrl = requestedThumbUrl;
|
||||
}
|
||||
if (fileTokenProvider != null) {
|
||||
fileInfo.publicApiUrl = "/api/public/file/token/"
|
||||
+ fileTokenProvider.getFileToken(requestedUri) + "/" + requestedFilenameUri;
|
||||
}
|
||||
if (requestedFilename.endsWith(".zip")) {
|
||||
fileInfo.viewUrl = "/view" + requestedUri + "/1";
|
||||
} else if (requestedFilename.endsWith(".epub")) {
|
||||
fileInfo.viewUrl = "/view" + requestedUri + "/0";
|
||||
}
|
||||
return fileInfo;
|
||||
}
|
||||
return fileInfo;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -8,6 +8,8 @@ import java.nio.channels.FileChannel;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
@@ -100,6 +102,31 @@ public class FileServeService {
|
||||
}
|
||||
}
|
||||
|
||||
public Response serveArchiveContent(FileInfo fileInfo, String name) {
|
||||
try {
|
||||
Path path = Paths.get(fileApiConfiguration.directory(),
|
||||
URLDecoder.decode(fileInfo.directUrl, StandardCharsets.UTF_8));
|
||||
ZipFile zipFile = new ZipFile(path.toFile());
|
||||
ZipEntry zipEntry = zipFile.getEntry(name);
|
||||
|
||||
if (zipEntry == null) {
|
||||
throw new IOException();
|
||||
}
|
||||
|
||||
ResponseBuilder response;
|
||||
long fileSize = zipEntry.getSize();
|
||||
|
||||
response = Response.ok(zipFile.getInputStream(zipEntry));
|
||||
response.header("Content-Length", Long.toString(fileSize));
|
||||
|
||||
response.header("Accept-Ranges", "bytes");
|
||||
response.header("Content-Disposition", "inline; filename=\"" + name + "\"");
|
||||
response.header("Content-Type", FileHelper.getMimeType(name));
|
||||
return response.build();
|
||||
} catch (IOException e) {
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FileServeInputStream extends InputStream {
|
||||
@@ -188,4 +215,4 @@ class FileServeInputStream extends InputStream {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,24 +5,72 @@
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<link rel="stylesheet" href="/style/sakura.css" />
|
||||
<title>{info.filename}</title>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<table style="table-layout: fixed;">
|
||||
<tr>
|
||||
<td style="text-align: left; padding-top: 0; padding-bottom: 0;"><a href="{info.directUrl}/..">back</a></td>
|
||||
<td style="text-align: center; padding-top: 0; padding-bottom: 0;">{currpage}/{totpage}</td>
|
||||
<td style="text-align: right; padding-top: 0; padding-bottom: 0;">{#if currpage > 1}<a href="{prevuri}"><</a> {/if}{#if currpage < totpage}<a href="{nexturi}">></a>{/if}</td>
|
||||
<td id="viewer-page-counter" style="text-align: center; padding-top: 0; padding-bottom: 0;">{currpage}/{totpage}</td>
|
||||
<td style="text-align: right; padding-top: 0; padding-bottom: 0;"><a id="viewer-page-navigation-left" {#if currpage > 1}href="{prevuri}"{/if}><</a> <a id="viewer-page-navigation-right" {#if currpage < totpage}href="{nexturi}"{/if}>></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr />
|
||||
{#if currpage < totpage}<a href="{nexturi}">{/if}
|
||||
{#if currpage < totpage}<a id="viewer-page-link" href="{nexturi}">{/if}
|
||||
{#if image??}
|
||||
<img style="position: absolute; left: 50%; transform: translate(-50%, 0);" src="{image}" />
|
||||
<img id="viewer-page-image" style="position: absolute; left: 50%; transform: translate(-50%, 0);" src="{image}" />
|
||||
{#else if video??}
|
||||
<video src="{video}" controls style="width: 100%"></video>
|
||||
{/if}
|
||||
{#if currpage < totpage}</a>{/if}
|
||||
<hr />
|
||||
{#if image??}
|
||||
<script>
|
||||
var pages = [];
|
||||
var preloadedPages = [];
|
||||
$.getJSON('/api/private{info.directUrl}', function(data) {
|
||||
for (const c of data.content) {
|
||||
pages.push(c.publicApiUrl);
|
||||
}
|
||||
for (const page of pages) {
|
||||
preloadedPages.push(new Promise(resolve => {
|
||||
const img = new Image();
|
||||
img.src = page;
|
||||
resolve(img);
|
||||
}));
|
||||
}
|
||||
displayPage({currpage});
|
||||
});
|
||||
function displayPage(pageNumber) {
|
||||
var imgtag = document.getElementById("viewer-page-image");
|
||||
var atag = document.getElementById("viewer-page-link");
|
||||
atag.setAttribute("href", "#");
|
||||
|
||||
var leftatag = document.getElementById("viewer-page-navigation-left");
|
||||
leftatag.setAttribute('href', '#');
|
||||
if (pageNumber > 1) {
|
||||
leftatag.setAttribute('onClick', 'displayPage(' + (pageNumber-1) + ')');
|
||||
}
|
||||
|
||||
var rightatag = document.getElementById("viewer-page-navigation-right");
|
||||
if (pageNumber < pages.length) {
|
||||
rightatag.setAttribute('href', '#');
|
||||
rightatag.setAttribute('onClick', 'displayPage(' + (pageNumber+1) + ')');
|
||||
atag.setAttribute('onClick', 'displayPage(' + (pageNumber+1) + ')');
|
||||
}
|
||||
if (typeof preloadedPages !== "undefined" && preloadedPages.length > 0) {
|
||||
preloadedPages[pageNumber-1].then(img => {
|
||||
img.setAttribute('id', imgtag.id)
|
||||
img.setAttribute('style', imgtag.style.cssText);
|
||||
atag.innerHTML = '';
|
||||
atag.appendChild(img);
|
||||
});
|
||||
}
|
||||
var middlespantag = document.getElementById("viewer-page-counter");
|
||||
middlespantag.innerHTML = pageNumber + "/" + pages.length;
|
||||
}
|
||||
</script>
|
||||
{/if}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user