-
-
Notifications
You must be signed in to change notification settings - Fork 124
refactor(api): use NightCompress library for reading CBX
#113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
balazs-szucs
merged 38 commits into
grimmory-tools:develop
from
imnotjames:refactor/29/nightcompress
Mar 31, 2026
Merged
Changes from all commits
Commits
Show all changes
38 commits
Select commit
Hold shift + click to select a range
1bc8d4c
build: drop unrar from dockerfile
imnotjames 08f6fe0
build: add libarchive to dockerfile
imnotjames 73e5ad4
ci: add libarchive for tests
imnotjames 581c967
build: try adding to the gradle build
imnotjames 850fe4d
refactor: use nightcompress for reading CBX
imnotjames 7a0c57a
test: disable tests using nightcompress when unavailable
imnotjames 4ed3e6c
ci: drop showing java information
imnotjames 44882c0
build: add libarchive to dev compose
imnotjames 6381818
build: fix libarchive link in alpine
imnotjames 21d2fe7
build: use expected order for allowing java to use native libs
imnotjames f9c82b7
fix: ensure we initialize NightCompress before using it
imnotjames 700a79f
fix: properly find input stream
imnotjames 2160950
fix: return amount of data copied
imnotjames b12e087
test: add helper to turn off tests in ArchiveService
imnotjames 81e36a1
test: rewrite CbxMetadataExtractorTest to mock archiveService
imnotjames d7a899e
refactor: expose `Path` to make `CbxMetadataExtractor` easier to test
imnotjames b8a2a8a
test: drop now useless test
imnotjames f54c5f2
test: add archiveservice to rar5 integration
imnotjames 69a198a
test: mock out archiveservice in cbxreader test
imnotjames 141a122
test: use real archiveservice in cbxconverstionintegration
imnotjames f947545
file: the cbxconversionservicetest also seems to be integration
imnotjames 9533626
test: remove unused imports from cbxmetadataextractortest
imnotjames cc6ff7d
test: cbxcomicinfocompliance is also an integration
imnotjames 15908e1
test: cbxmetadatawriter is also integration
imnotjames 51d946a
chore: drop unused properties
imnotjames 6d84558
test: make cbxmetadataextractortest do something for covers
imnotjames 8343bd1
fix: invert check
imnotjames 5864b9b
chore: better comment
imnotjames 055f745
test: fix more cbxmetadataextractor tests that never worked
imnotjames 206b6f6
test: we only ever raise ioexception
imnotjames df91323
fix: handle `null` comicinfo when parsing
imnotjames bfc30b3
test: properly test for no files comicinfo
imnotjames 56e4893
build: manual link of dev docker compose
imnotjames 81f87d6
test: if you use any matchers, all must be
imnotjames 273829f
build: drop unrar from dev compose
imnotjames 54b51c9
test: if you use any matchers, all must be
imnotjames 12c3179
test: always get a fresh stream
imnotjames ef588df
test: drop more toFile
imnotjames File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
124 changes: 124 additions & 0 deletions
124
booklore-api/src/main/java/org/booklore/service/ArchiveService.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| package org.booklore.service; | ||
|
|
||
| import com.github.gotson.nightcompress.Archive; | ||
| import com.github.gotson.nightcompress.ArchiveEntry; | ||
| import com.github.gotson.nightcompress.LibArchiveException; | ||
| import jakarta.annotation.PostConstruct; | ||
| import lombok.Getter; | ||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.springframework.stereotype.Service; | ||
|
|
||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.IOException; | ||
| import java.io.InputStream; | ||
| import java.io.OutputStream; | ||
| import java.nio.file.Files; | ||
| import java.nio.file.Path; | ||
| import java.util.List; | ||
| import java.util.stream.Stream; | ||
|
|
||
| @Slf4j | ||
| @Service | ||
| public class ArchiveService { | ||
| @PostConstruct | ||
| public void checkArchiveAvailable() { | ||
| try { | ||
| // We want to check the version early because it allows for | ||
| // NightCompress to preload the libarchive library in a safe | ||
| // thread. Loading native libraries is not a thread safe operation. | ||
| if (!Archive.isAvailable()) { | ||
| log.warn("LibArchive is not available"); | ||
| } | ||
| } catch (Throwable e) { | ||
| log.error("LibArchive could not be loaded", e); | ||
| } | ||
| } | ||
|
|
||
| public static boolean isAvailable() { | ||
| return Archive.isAvailable(); | ||
| } | ||
|
|
||
| public static class Entry { | ||
| private Entry() {} | ||
|
|
||
| @Getter | ||
| private String name; | ||
|
|
||
| @Getter | ||
| private long size; | ||
| } | ||
|
|
||
| private Entry getEntryFromArchiveEntry(ArchiveEntry archiveEntry) { | ||
| Entry entry = new Entry(); | ||
|
|
||
| entry.name = archiveEntry.getName(); | ||
| entry.size = archiveEntry.getSize(); | ||
|
|
||
| return entry; | ||
| } | ||
|
|
||
| public List<Entry> getEntries(Path path) throws IOException { | ||
| return streamEntries(path).toList(); | ||
| } | ||
|
|
||
| public Stream<Entry> streamEntries(Path path) throws IOException { | ||
| try { | ||
| return Archive.getEntries(path) | ||
| .stream() | ||
| .map(this::getEntryFromArchiveEntry); | ||
| } catch (LibArchiveException e) { | ||
| throw new IOException("Failed to read archive", e); | ||
| } | ||
| } | ||
|
|
||
| public List<String> getEntryNames(Path path) throws IOException { | ||
| return streamEntryNames(path).toList(); | ||
| } | ||
|
|
||
| public Stream<String> streamEntryNames(Path path) throws IOException { | ||
| try { | ||
| return Archive.getEntries(path) | ||
| .stream() | ||
| .map(ArchiveEntry::getName); | ||
| } catch (LibArchiveException e) { | ||
| throw new IOException("Failed to read archive", e); | ||
| } | ||
| } | ||
|
|
||
| public long transferEntryTo(Path path, String entryName, OutputStream outputStream) throws IOException { | ||
| // We cannot directly use the NightCompress `InputStream` as it is limited | ||
| // in its implementation and will cause fatal errors. Instead, we can use | ||
| // the `transferTo` on an output stream to copy data around. | ||
| try (InputStream inputStream = Archive.getInputStream(path, entryName)) { | ||
| if (inputStream != null) { | ||
| return inputStream.transferTo(outputStream); | ||
| } | ||
| } catch (Exception e) { | ||
| throw new IOException("Failed to extract from archive: " + e.getMessage(), e); | ||
| } | ||
|
|
||
| throw new IOException("Entry not found in archive"); | ||
| } | ||
|
|
||
| public byte[] getEntryBytes(Path path, String entryName) throws IOException { | ||
| try ( | ||
| ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); | ||
| ) { | ||
| transferEntryTo(path, entryName, outputStream); | ||
|
|
||
| return outputStream.toByteArray(); | ||
| } | ||
| } | ||
|
|
||
| public long extractEntryToPath(Path path, String entryName, Path outputPath) throws IOException { | ||
| try (InputStream inputStream = Archive.getInputStream(path, entryName)) { | ||
| if (inputStream != null) { | ||
| return Files.copy(inputStream, outputPath); | ||
| } | ||
| } catch (Exception e) { | ||
| throw new IOException("Failed to extract from archive: " + e.getMessage(), e); | ||
| } | ||
|
|
||
| throw new IOException("Entry not found in archive"); | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.