Skip to content

Commit eb1ee1d

Browse files
authored
Merge pull request #2895 from booklore-app/develop
Merge develop into master for release
2 parents 3e854d2 + 24767fa commit eb1ee1d

File tree

90 files changed

+8893
-4179
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+8893
-4179
lines changed

Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ LABEL org.opencontainers.image.title="BookLore" \
5656

5757
ENV JAVA_TOOL_OPTIONS="-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+UseStringDeduplication -XX:+UseContainerSupport -XX:+UseCompactObjectHeaders -XX:MaxRAMPercentage=75.0"
5858

59-
RUN apk update && apk add --no-cache su-exec
59+
RUN apk update && apk add --no-cache su-exec && \
60+
mkdir -p /bookdrop
6061

6162
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
6263
RUN chmod +x /usr/local/bin/entrypoint.sh

booklore-api/src/main/java/org/booklore/model/dto/settings/MetadataMatchWeights.java

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package org.booklore.model.dto.settings;
22

33

4+
import com.fasterxml.jackson.annotation.JsonSetter;
5+
import com.fasterxml.jackson.annotation.Nulls;
46
import lombok.AllArgsConstructor;
57
import lombok.Builder;
68
import lombok.Data;
@@ -11,30 +13,54 @@
1113
@NoArgsConstructor
1214
@AllArgsConstructor
1315
public class MetadataMatchWeights {
14-
private int title;
15-
private int subtitle;
16-
private int description;
17-
private int authors;
18-
private int publisher;
19-
private int publishedDate;
20-
private int seriesName;
21-
private int seriesNumber;
22-
private int seriesTotal;
23-
private int isbn13;
24-
private int isbn10;
25-
private int language;
26-
private int pageCount;
27-
private int categories;
28-
private int amazonRating;
29-
private int amazonReviewCount;
30-
private int goodreadsRating;
31-
private int goodreadsReviewCount;
32-
private int hardcoverRating;
33-
private int hardcoverReviewCount;
34-
private int doubanRating;
35-
private int doubanReviewCount;
36-
private int ranobedbRating;
37-
private int coverImage;
16+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
17+
private int title = 10;
18+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
19+
private int subtitle = 1;
20+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
21+
private int description = 10;
22+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
23+
private int authors = 10;
24+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
25+
private int publisher = 5;
26+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
27+
private int publishedDate = 3;
28+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
29+
private int seriesName = 2;
30+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
31+
private int seriesNumber = 2;
32+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
33+
private int seriesTotal = 1;
34+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
35+
private int isbn13 = 3;
36+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
37+
private int isbn10 = 5;
38+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
39+
private int language = 2;
40+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
41+
private int pageCount = 1;
42+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
43+
private int categories = 10;
44+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
45+
private int amazonRating = 3;
46+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
47+
private int amazonReviewCount = 2;
48+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
49+
private int goodreadsRating = 4;
50+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
51+
private int goodreadsReviewCount = 2;
52+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
53+
private int hardcoverRating = 2;
54+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
55+
private int hardcoverReviewCount = 1;
56+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
57+
private int doubanRating = 3;
58+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
59+
private int doubanReviewCount = 2;
60+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
61+
private int ranobedbRating = 2;
62+
@Builder.Default @JsonSetter(nulls = Nulls.SKIP)
63+
private int coverImage = 5;
3864

3965
public int totalWeight() {
4066
return title + subtitle + description + authors + publisher + publishedDate +

booklore-api/src/main/java/org/booklore/service/bookdrop/BookdropMonitoringService.java

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public class BookdropMonitoringService {
3030
private volatile boolean running;
3131
private WatchKey watchKey;
3232
private volatile boolean paused;
33+
private volatile boolean disabled;
3334

3435
public BookdropMonitoringService(
3536
AppProperties appProperties,
@@ -42,29 +43,36 @@ public BookdropMonitoringService(
4243
}
4344

4445
@PostConstruct
45-
public void start() throws IOException {
46+
public void start() {
4647
bookdrop = Path.of(appProperties.getBookdropFolder());
4748
if (Files.notExists(bookdrop)) {
4849
try {
4950
Files.createDirectories(bookdrop);
5051
log.info("Created missing bookdrop folder: {}", bookdrop);
5152
} catch (IOException e) {
52-
log.error("Failed to create bookdrop folder: {}", bookdrop, e);
53-
throw e;
53+
log.warn("Bookdrop folder is not available at '{}'. Bookdrop monitoring is disabled. " +
54+
"Mount a volume at this path to enable it.", bookdrop);
55+
this.disabled = true;
56+
return;
5457
}
5558
}
5659

57-
log.info("Starting bookdrop folder monitor: {}", bookdrop);
58-
this.watchService = FileSystems.getDefault().newWatchService();
59-
this.watchKey = bookdrop.register(watchService,
60-
StandardWatchEventKinds.ENTRY_CREATE,
61-
StandardWatchEventKinds.ENTRY_DELETE);
62-
this.running = true;
63-
this.paused = false;
64-
this.watchThread = new Thread(this::processEvents, "BookdropFolderWatcher");
65-
this.watchThread.setDaemon(true);
66-
this.watchThread.start();
67-
scanExistingBookdropFiles();
60+
try {
61+
log.info("Starting bookdrop folder monitor: {}", bookdrop);
62+
this.watchService = FileSystems.getDefault().newWatchService();
63+
this.watchKey = bookdrop.register(watchService,
64+
StandardWatchEventKinds.ENTRY_CREATE,
65+
StandardWatchEventKinds.ENTRY_DELETE);
66+
this.running = true;
67+
this.paused = false;
68+
this.watchThread = new Thread(this::processEvents, "BookdropFolderWatcher");
69+
this.watchThread.setDaemon(true);
70+
this.watchThread.start();
71+
scanExistingBookdropFiles();
72+
} catch (IOException e) {
73+
log.warn("Failed to start bookdrop folder monitor. Bookdrop monitoring is disabled.", e);
74+
this.disabled = true;
75+
}
6876
}
6977

7078
@PreDestroy
@@ -84,6 +92,7 @@ public void stop() {
8492
}
8593

8694
public synchronized void pauseMonitoring() {
95+
if (disabled) return;
8796
if (!paused) {
8897
if (watchKey != null) {
8998
watchKey.cancel();
@@ -97,6 +106,7 @@ public synchronized void pauseMonitoring() {
97106
}
98107

99108
public synchronized void resumeMonitoring() {
109+
if (disabled) return;
100110
if (paused) {
101111
try {
102112
watchKey = bookdrop.register(watchService,
@@ -190,6 +200,10 @@ private void processEvents() {
190200
}
191201

192202
public void rescanBookdropFolder() {
203+
if (disabled) {
204+
log.warn("Bookdrop monitoring is disabled. Skipping rescan.");
205+
return;
206+
}
193207
log.info("Rescan of Bookdrop folder triggered.");
194208
scanExistingBookdropFiles();
195209
}

booklore-api/src/main/java/org/booklore/util/kobo/KoboUrlBuilder.java

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,21 @@
11
package org.booklore.util.kobo;
22

3-
import org.booklore.util.RequestUtils;
4-
import jakarta.servlet.http.HttpServletRequest;
53
import lombok.RequiredArgsConstructor;
64
import lombok.extern.slf4j.Slf4j;
7-
import org.springframework.beans.factory.annotation.Value;
85
import org.springframework.stereotype.Component;
96
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
107
import org.springframework.web.util.UriComponentsBuilder;
118

12-
import java.util.regex.Pattern;
13-
149
@Component
1510
@Slf4j
1611
@RequiredArgsConstructor
1712
public class KoboUrlBuilder {
1813

19-
private static final Pattern IP_ADDRESS_PATTERN = Pattern.compile("\\d+\\.\\d+\\.\\d+\\.\\d+");
20-
@Value("${server.port}")
21-
private int serverPort;
22-
2314
public UriComponentsBuilder baseBuilder() {
24-
HttpServletRequest request = RequestUtils.getCurrentRequest();
25-
2615
UriComponentsBuilder builder = ServletUriComponentsBuilder
2716
.fromCurrentContextPath()
2817
.replacePath("")
29-
.replaceQuery(null)
30-
.port(-1);
31-
32-
String host = builder.build().getHost();
33-
34-
if (host == null) host = "";
35-
36-
String xfPort = request.getHeader("X-Forwarded-Port");
37-
try {
38-
int port = Integer.parseInt(xfPort);
39-
40-
if (IP_ADDRESS_PATTERN.matcher(host).matches() || "localhost".equals(host)) {
41-
builder.port(port);
42-
}
43-
log.info("Applied X-Forwarded-Port: {}", port);
44-
} catch (NumberFormatException e) {
45-
builder.port(serverPort);
46-
log.debug("Invalid X-Forwarded-Port header: {}", xfPort);
47-
}
18+
.replaceQuery(null);
4819

4920
log.debug("Final base URL: {}", builder.build().toUriString());
5021
return builder;

booklore-api/src/test/java/org/booklore/service/metadata/MetadataMatchServiceTest.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ class MetadataMatchServiceTest {
3333

3434
@BeforeEach
3535
void setUp() {
36-
weights = MetadataMatchWeights.builder()
36+
weights = zeroWeights()
3737
.title(10)
3838
.subtitle(5)
3939
.description(5)
4040
.authors(10)
41-
.build(); // other fields default to 0
41+
.build();
4242

4343
AppSettings appSettings = AppSettings.builder()
4444
.metadataMatchWeights(weights)
@@ -80,7 +80,7 @@ void calculateMatchScore_shouldScoreLockedEmptySubtitle() {
8080

8181
@Test
8282
void calculateMatchScore_shouldScoreLockedNullSeriesNumber() {
83-
weights = MetadataMatchWeights.builder()
83+
weights = zeroWeights()
8484
.title(10)
8585
.seriesNumber(5)
8686
.build();
@@ -106,4 +106,14 @@ void calculateMatchScore_shouldScoreLockedNullSeriesNumber() {
106106

107107
assertEquals(100.0f, score, 0.01f);
108108
}
109+
110+
private MetadataMatchWeights.MetadataMatchWeightsBuilder zeroWeights() {
111+
return MetadataMatchWeights.builder()
112+
.title(0).subtitle(0).description(0).authors(0).publisher(0)
113+
.publishedDate(0).seriesName(0).seriesNumber(0).seriesTotal(0)
114+
.isbn13(0).isbn10(0).language(0).pageCount(0).categories(0)
115+
.amazonRating(0).amazonReviewCount(0).goodreadsRating(0)
116+
.goodreadsReviewCount(0).hardcoverRating(0).hardcoverReviewCount(0)
117+
.doubanRating(0).doubanReviewCount(0).ranobedbRating(0).coverImage(0);
118+
}
109119
}

0 commit comments

Comments
 (0)