feat(metadata): consider locked, but empty or null metadata valid (#1729)

Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
This commit is contained in:
Balázs Szücs
2025-12-02 18:13:55 +01:00
committed by GitHub
parent d40a650df7
commit ff2654db1b
2 changed files with 138 additions and 27 deletions

View File

@@ -41,39 +41,41 @@ public class MetadataMatchService {
float score = 0f;
if (isPresent(metadata.getTitle())) score += weights.getTitle();
if (isPresent(metadata.getSubtitle())) score += weights.getSubtitle();
if (isPresent(metadata.getDescription())) score += weights.getDescription();
if (hasContent(metadata.getAuthors())) score += weights.getAuthors();
if (isPresent(metadata.getPublisher())) score += weights.getPublisher();
if (metadata.getPublishedDate() != null) score += weights.getPublishedDate();
if (isPresent(metadata.getSeriesName())) score += weights.getSeriesName();
if (metadata.getSeriesNumber() != null && metadata.getSeriesNumber() > 0) score += weights.getSeriesNumber();
if (metadata.getSeriesTotal() != null && metadata.getSeriesTotal() > 0) score += weights.getSeriesTotal();
if (isPresent(metadata.getIsbn13())) score += weights.getIsbn13();
if (isPresent(metadata.getIsbn10())) score += weights.getIsbn10();
if (isPresent(metadata.getLanguage())) score += weights.getLanguage();
if (metadata.getPageCount() != null && metadata.getPageCount() > 0) score += weights.getPageCount();
if (hasContent(metadata.getCategories())) score += weights.getCategories();
if (isPositive(metadata.getAmazonRating())) score += weights.getAmazonRating();
if (isPositive(metadata.getAmazonReviewCount())) score += weights.getAmazonReviewCount();
if (isPositive(metadata.getGoodreadsRating())) score += weights.getGoodreadsRating();
if (isPositive(metadata.getGoodreadsReviewCount())) score += weights.getGoodreadsReviewCount();
if (isPositive(metadata.getHardcoverRating())) score += weights.getHardcoverRating();
if (isPositive(metadata.getHardcoverReviewCount())) score += weights.getHardcoverReviewCount();
if (isPresent(metadata.getTitle(), metadata.getTitleLocked())) score += weights.getTitle();
if (isPresent(metadata.getSubtitle(), metadata.getSubtitleLocked())) score += weights.getSubtitle();
if (isPresent(metadata.getDescription(), metadata.getDescriptionLocked())) score += weights.getDescription();
if (hasContent(metadata.getAuthors(), metadata.getAuthorsLocked())) score += weights.getAuthors();
if (isPresent(metadata.getPublisher(), metadata.getPublisherLocked())) score += weights.getPublisher();
if (metadata.getPublishedDate() != null || Boolean.TRUE.equals(metadata.getPublishedDateLocked())) score += weights.getPublishedDate();
if (isPresent(metadata.getSeriesName(), metadata.getSeriesNameLocked())) score += weights.getSeriesName();
if ((metadata.getSeriesNumber() != null && metadata.getSeriesNumber() > 0) || Boolean.TRUE.equals(metadata.getSeriesNumberLocked())) score += weights.getSeriesNumber();
if ((metadata.getSeriesTotal() != null && metadata.getSeriesTotal() > 0) || Boolean.TRUE.equals(metadata.getSeriesTotalLocked())) score += weights.getSeriesTotal();
if (isPresent(metadata.getIsbn13(), metadata.getIsbn13Locked())) score += weights.getIsbn13();
if (isPresent(metadata.getIsbn10(), metadata.getIsbn10Locked())) score += weights.getIsbn10();
if (isPresent(metadata.getLanguage(), metadata.getLanguageLocked())) score += weights.getLanguage();
if ((metadata.getPageCount() != null && metadata.getPageCount() > 0) || Boolean.TRUE.equals(metadata.getPageCountLocked())) score += weights.getPageCount();
if (hasContent(metadata.getCategories(), metadata.getCategoriesLocked())) score += weights.getCategories();
if (isPositive(metadata.getAmazonRating(), metadata.getAmazonRatingLocked())) score += weights.getAmazonRating();
if (isPositive(metadata.getAmazonReviewCount(), metadata.getAmazonReviewCountLocked())) score += weights.getAmazonReviewCount();
if (isPositive(metadata.getGoodreadsRating(), metadata.getGoodreadsRatingLocked())) score += weights.getGoodreadsRating();
if (isPositive(metadata.getGoodreadsReviewCount(), metadata.getGoodreadsReviewCountLocked())) score += weights.getGoodreadsReviewCount();
if (isPositive(metadata.getHardcoverRating(), metadata.getHardcoverRatingLocked())) score += weights.getHardcoverRating();
if (isPositive(metadata.getHardcoverReviewCount(), metadata.getHardcoverReviewCountLocked())) score += weights.getHardcoverReviewCount();
return (score / totalWeight) * 100f;
}
private boolean isPresent(String value) {
return value != null && !value.isBlank();
private boolean isPresent(String value, Boolean locked) {
return (value != null && !value.isBlank()) || Boolean.TRUE.equals(locked);
}
private boolean hasContent(Iterable<?> iterable) {
return iterable != null && iterable.iterator().hasNext();
private boolean hasContent(Iterable<?> iterable, Boolean locked) {
return (iterable != null && iterable.iterator().hasNext()) || Boolean.TRUE.equals(locked);
}
private boolean isPositive(Number number) {
return number != null && number.doubleValue() > 0;
private boolean isPositive(Number number, Boolean locked) {
return (number != null && number.doubleValue() > 0) || Boolean.TRUE.equals(locked);
}
}
}

View File

@@ -0,0 +1,109 @@
package com.adityachandel.booklore.service.metadata;
import com.adityachandel.booklore.model.dto.settings.AppSettings;
import com.adityachandel.booklore.model.dto.settings.MetadataMatchWeights;
import com.adityachandel.booklore.model.entity.BookEntity;
import com.adityachandel.booklore.model.entity.BookMetadataEntity;
import com.adityachandel.booklore.service.appsettings.AppSettingService;
import com.adityachandel.booklore.service.book.BookQueryService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class MetadataMatchServiceTest {
@Mock
private AppSettingService appSettingsService;
@Mock
private BookQueryService bookQueryService;
@InjectMocks
private MetadataMatchService metadataMatchService;
private MetadataMatchWeights weights;
@BeforeEach
void setUp() {
weights = MetadataMatchWeights.builder()
.title(10)
.subtitle(5)
.description(5)
.authors(10)
.build(); // other fields default to 0
AppSettings appSettings = AppSettings.builder()
.metadataMatchWeights(weights)
.build();
when(appSettingsService.getAppSettings()).thenReturn(appSettings);
}
@Test
void calculateMatchScore_shouldScoreOnlyPresentFields() {
BookMetadataEntity metadata = BookMetadataEntity.builder()
.title("Some Title")
.build();
BookEntity book = BookEntity.builder()
.metadata(metadata)
.build();
Float score = metadataMatchService.calculateMatchScore(book);
assertEquals(10f / 30f * 100f, score, 0.01f);
}
@Test
void calculateMatchScore_shouldScoreLockedEmptySubtitle() {
BookMetadataEntity metadata = BookMetadataEntity.builder()
.title("Some Title")
.subtitleLocked(true) // Empty but locked
.build();
BookEntity book = BookEntity.builder()
.metadata(metadata)
.build();
Float score = metadataMatchService.calculateMatchScore(book);
assertEquals(50.0f, score, 0.01f);
}
@Test
void calculateMatchScore_shouldScoreLockedNullSeriesNumber() {
weights = MetadataMatchWeights.builder()
.title(10)
.seriesNumber(5)
.build();
// Total 15
AppSettings appSettings = AppSettings.builder()
.metadataMatchWeights(weights)
.build();
when(appSettingsService.getAppSettings()).thenReturn(appSettings);
BookMetadataEntity metadata = BookMetadataEntity.builder()
.title("Some Title")
.seriesNumberLocked(true) // Null but locked
.build();
BookEntity book = BookEntity.builder()
.metadata(metadata)
.build();
Float score = metadataMatchService.calculateMatchScore(book);
assertEquals(100.0f, score, 0.01f);
}
}