Create few classes, few repos
This commit is contained in:
parent
9b41f9c3c0
commit
280dcd0fb0
11 changed files with 348 additions and 61 deletions
139
src/main/java/ru/redrise/marinesco/RainbowDump.java
Normal file
139
src/main/java/ru/redrise/marinesco/RainbowDump.java
Normal file
|
@ -0,0 +1,139 @@
|
|||
package ru.redrise.marinesco;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/* ANSI_BLACK = "\u001B[30m";
|
||||
ANSI_YELLOW = "\u001B[33m";
|
||||
ANSI_PURPLE = "\u001B[35m";
|
||||
ANSI_CYAN = "\u001B[36m";
|
||||
ANSI_WHITE = "\u001B[37m"; */
|
||||
/**
|
||||
* Debug tool like hexdump <3
|
||||
*/
|
||||
@Slf4j
|
||||
public class RainbowDump {
|
||||
|
||||
private static final String ANSI_RESET = "\u001B[0m";
|
||||
private static final String ANSI_RED = "\u001B[31m";
|
||||
private static final String ANSI_GREEN = "\u001B[32m";
|
||||
private static final String ANSI_BLUE = "\u001B[34m";
|
||||
|
||||
private static StringBuilder stringBuilder;
|
||||
|
||||
public static void hexDumpUTF8(byte[] byteArray) {
|
||||
stringBuilder = new StringBuilder(" -- RainbowDump --\n");
|
||||
if (byteArray == null || byteArray.length == 0)
|
||||
return;
|
||||
|
||||
int k = 0;
|
||||
boolean lastCharCyrillic = false;
|
||||
stringBuilder.append(String.format("%s%08x %s", ANSI_BLUE, 0, ANSI_RESET));
|
||||
for (int i = 0; i < byteArray.length; i++) {
|
||||
if (k == 8)
|
||||
stringBuilder.append(" ");
|
||||
if (k == 16) {
|
||||
stringBuilder.append(ANSI_GREEN + "| " + ANSI_RESET);
|
||||
lastCharCyrillic = printChars(byteArray, i, lastCharCyrillic);
|
||||
stringBuilder.append("\n")
|
||||
.append(String.format("%s%08x %s", ANSI_BLUE, i, ANSI_RESET));
|
||||
k = 0;
|
||||
}
|
||||
stringBuilder.append(String.format("%02x ", byteArray[i]));
|
||||
k++;
|
||||
}
|
||||
int paddingSize = 16 - (byteArray.length % 16);
|
||||
if (paddingSize != 16) {
|
||||
for (int i = 0; i < paddingSize; i++) {
|
||||
stringBuilder.append(" ");
|
||||
}
|
||||
if (paddingSize > 7) {
|
||||
stringBuilder.append(" ");
|
||||
}
|
||||
}
|
||||
stringBuilder.append(ANSI_GREEN + "| " + ANSI_RESET);
|
||||
printChars(byteArray, byteArray.length);
|
||||
stringBuilder.append("\n")
|
||||
.append(ANSI_RESET)
|
||||
.append(new String(byteArray, StandardCharsets.UTF_8))
|
||||
.append("\n");
|
||||
|
||||
log.info(stringBuilder.toString());
|
||||
}
|
||||
|
||||
private static void printChars(byte[] byteArray, int pointer){
|
||||
printChars(byteArray, pointer, false);
|
||||
}
|
||||
private static boolean printChars(byte[] byteArray, int pointer, boolean skipFirstByte){
|
||||
int j;
|
||||
if (pointer < 16)
|
||||
j = 0;
|
||||
else
|
||||
j = pointer-16;
|
||||
|
||||
int utf8val = 0;
|
||||
if (skipFirstByte){
|
||||
++j;
|
||||
stringBuilder.append(" ");
|
||||
}
|
||||
|
||||
for (; j < pointer; j++){
|
||||
utf8val = 0;
|
||||
|
||||
if (byteArray.length > (j+1))
|
||||
utf8val = ((byteArray[j] & 0xff) << 8) | (byteArray[j+1] & 0xff);
|
||||
|
||||
if ((byteArray[j] > 21) && (byteArray[j] < 126)) // man ascii
|
||||
stringBuilder.append((char) byteArray[j]);
|
||||
else if (byteArray[j] == 0x0a)
|
||||
stringBuilder.append("↲"); //""
|
||||
else if (byteArray[j] == 0x0d)
|
||||
stringBuilder.append("←"); // "␍"
|
||||
else if (utf8val >= 0xd080 && utf8val <= 0xd3bf){
|
||||
byte[] arr = new byte[0x2];
|
||||
System.arraycopy(byteArray, j, arr, 0, 2);
|
||||
stringBuilder.append(new String(arr, StandardCharsets.UTF_8)+" ");
|
||||
++j;
|
||||
}
|
||||
else
|
||||
stringBuilder.append(".");
|
||||
}
|
||||
|
||||
return (utf8val >= 0xd080 && utf8val <= 0xd3bf && j > pointer);
|
||||
}
|
||||
|
||||
public static void hexDumpUTF8Legacy(byte[] byteArray) {
|
||||
StringBuilder stringBuilderLegacy = new StringBuilder("HexDumpUTF8Legacy");
|
||||
stringBuilderLegacy.append(ANSI_BLUE);
|
||||
|
||||
if (byteArray == null || byteArray.length == 0)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < byteArray.length; i++)
|
||||
stringBuilderLegacy.append(String.format("%02d-", i % 100));
|
||||
stringBuilderLegacy.append(">" + ANSI_RED).append(byteArray.length).append(ANSI_RESET).append("\n");
|
||||
for (byte b : byteArray)
|
||||
stringBuilderLegacy.append(String.format("%02x ", b));
|
||||
stringBuilderLegacy.append("\n")
|
||||
.append(new String(byteArray, StandardCharsets.UTF_8))
|
||||
.append("\n");
|
||||
log.info(stringBuilderLegacy.toString());
|
||||
}
|
||||
/*
|
||||
public static void binDumpInt(int value) {
|
||||
log.info(Converter.intToBinaryString(value));
|
||||
}
|
||||
*/
|
||||
public static void binDumpLong(long value) {
|
||||
log.info(String.format("%64s", Long.toBinaryString(value)).replace(' ', '0') + " | " + value);
|
||||
}
|
||||
|
||||
public static String formatDecHexString(long value) {
|
||||
return String.format("%-20d 0x%x", value, value);
|
||||
}
|
||||
|
||||
public static String formatDecHexString(int value) {
|
||||
return String.format("%-20d 0x%x", value, value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package ru.redrise.marinesco.data;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import ru.redrise.marinesco.library.Author;
|
||||
|
||||
|
||||
@Repository
|
||||
public interface AuthorRepository extends CrudRepository<Author, Long>{
|
||||
}
|
11
src/main/java/ru/redrise/marinesco/data/GenreRepository.java
Normal file
11
src/main/java/ru/redrise/marinesco/data/GenreRepository.java
Normal file
|
@ -0,0 +1,11 @@
|
|||
package ru.redrise.marinesco.data;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import ru.redrise.marinesco.library.Genre;
|
||||
|
||||
|
||||
@Repository
|
||||
public interface GenreRepository extends CrudRepository<Genre, String>{
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package ru.redrise.marinesco.data;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import ru.redrise.marinesco.library.InpEntry;
|
||||
|
||||
@Repository
|
||||
public interface InpEntryRepository extends CrudRepository<InpEntry, Long>{
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package ru.redrise.marinesco.data;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import ru.redrise.marinesco.library.LibraryMetadata;
|
||||
|
||||
@Repository
|
||||
public interface LibraryMetadataRepository extends CrudRepository<LibraryMetadata, Long>{
|
||||
|
||||
}
|
30
src/main/java/ru/redrise/marinesco/library/Author.java
Normal file
30
src/main/java/ru/redrise/marinesco/library/Author.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
package ru.redrise.marinesco.library;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE, force = true)
|
||||
@AllArgsConstructor
|
||||
public class Author {
|
||||
// private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@Column(unique=true)
|
||||
private String authorName;
|
||||
|
||||
public Author(String name){
|
||||
this.authorName = name;
|
||||
}
|
||||
}
|
17
src/main/java/ru/redrise/marinesco/library/Genre.java
Normal file
17
src/main/java/ru/redrise/marinesco/library/Genre.java
Normal file
|
@ -0,0 +1,17 @@
|
|||
package ru.redrise.marinesco.library;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
public class Genre {
|
||||
@Id
|
||||
private String genreId;
|
||||
private String humanReadableDescription;
|
||||
|
||||
public Genre(String genreId){
|
||||
this.genreId = genreId;
|
||||
}
|
||||
}
|
|
@ -3,31 +3,49 @@ package ru.redrise.marinesco.library;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToMany;
|
||||
import jakarta.persistence.Transient;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import ru.redrise.marinesco.RainbowDump;
|
||||
|
||||
@Slf4j
|
||||
@Entity
|
||||
@Data
|
||||
public class InpEntry {
|
||||
private List<String> authors = new ArrayList<>(); // Surname,name,by-father
|
||||
private List<String> generes = new ArrayList<>();
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@ManyToMany
|
||||
private List<Author> authors; // Surname,name,by-father
|
||||
@ManyToMany
|
||||
private List<Genre> genres;
|
||||
private String title;
|
||||
private String series;
|
||||
private String serNo;
|
||||
private String fsFileName;
|
||||
private String fileSize; // extracted
|
||||
private String fsFileName; // inside zip
|
||||
private String fileSize; // extracted, in bytes
|
||||
private String libId; // same to filename
|
||||
private String deleted; // is deleted flag
|
||||
private String fileExtension; // - concatenate to fsFileName
|
||||
private LocalDate addedDate;
|
||||
|
||||
private String container;
|
||||
|
||||
@Transient
|
||||
private int position;
|
||||
|
||||
public InpEntry(byte[] line) throws Exception{
|
||||
public InpEntry(byte[] line, String container) throws Exception{
|
||||
// AUTHOR;GENRE;TITLE;SERIES;SERNO;FILE;SIZE;LIBID;DEL;EXT;DATE;
|
||||
this.container = container;
|
||||
this.authors = new ArrayList<>();
|
||||
this.genres = new ArrayList<>();
|
||||
parseAuthors(line);
|
||||
parseGenere(line);
|
||||
this.title = parseNextString(line);
|
||||
|
@ -40,10 +58,11 @@ public class InpEntry {
|
|||
this.fileExtension = parseNextString(line);
|
||||
this.addedDate = LocalDate.parse(parseNextString(line));
|
||||
|
||||
for (String author : authors)
|
||||
log.info(author);
|
||||
for (String gen : generes)
|
||||
log.info(gen);
|
||||
/*
|
||||
for (Author author : authors)
|
||||
log.info(author.getAuthorName());
|
||||
for (Genre gen : genres)
|
||||
log.info(gen.getGenreId());
|
||||
|
||||
log.info(title);
|
||||
log.info(series);
|
||||
|
@ -56,10 +75,11 @@ public class InpEntry {
|
|||
log.info(addedDate.toString());
|
||||
|
||||
log.info("-----------------");
|
||||
//*/
|
||||
}
|
||||
private void parseAuthors(byte[] line) throws Exception{
|
||||
for (int i = 0; i < line.length; i++){
|
||||
if (line[i] == ':' && i+1 < line.length && line[i+1] == 0x04){
|
||||
if (line[i] == 0x04){
|
||||
splitAuthors(new String(line, 0, i, StandardCharsets.UTF_8));
|
||||
position = i+1;
|
||||
return;
|
||||
|
@ -69,23 +89,27 @@ public class InpEntry {
|
|||
throw new Exception("Invalid 'inp' file format (parse Authors)");
|
||||
}
|
||||
private void splitAuthors(String allAuthors){
|
||||
authors = Arrays.asList(allAuthors.split(":"));
|
||||
for (String author : allAuthors.split(":")){
|
||||
authors.add(new Author(author));
|
||||
}
|
||||
}
|
||||
|
||||
private void parseGenere(byte[] line) throws Exception{
|
||||
for (int i = position; i < line.length; i++){
|
||||
if (line[i] == ':'){
|
||||
if (line[i] == ':' && i+1 < line.length && line[i+1] == 0x04){
|
||||
generes.add(new String(line, position, i-position, StandardCharsets.UTF_8));
|
||||
position = i+2;
|
||||
return;
|
||||
}
|
||||
generes.add(new String(line, position, i-position, StandardCharsets.UTF_8));
|
||||
if (line[i] == 0x04){
|
||||
splitGenres(new String(line, 0, i, StandardCharsets.UTF_8));
|
||||
position = i+1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
RainbowDump.hexDumpUTF8(line);
|
||||
throw new Exception("Invalid 'inp' file format (parse Genere)");
|
||||
}
|
||||
private void splitGenres(String allGenres){
|
||||
for (String genre : allGenres.split(":")){
|
||||
genres.add(new Genre(genre));
|
||||
}
|
||||
}
|
||||
|
||||
private String parseNextString(byte[] line) throws Exception{
|
||||
for (int i = position; i < line.length; i++){
|
||||
|
@ -95,7 +119,7 @@ public class InpEntry {
|
|||
return resultingString;
|
||||
}
|
||||
}
|
||||
|
||||
RainbowDump.hexDumpUTF8(line);
|
||||
throw new Exception("Invalid 'inp' file format (parse Title)");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,13 @@
|
|||
package ru.redrise.marinesco.library;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
//@Entity
|
||||
@Data
|
||||
public class InpFile {
|
||||
public class InpFileScanner {
|
||||
private String name;
|
||||
|
||||
private final String name;
|
||||
private final List<InpEntry> inpEntries;
|
||||
|
||||
public InpFile(byte[] content, String name) throws Exception{
|
||||
public InpFileScanner(byte[] content, String name) throws Exception{
|
||||
this.name = name.substring(0, name.lastIndexOf('.'));
|
||||
this.inpEntries = new ArrayList<>();
|
||||
log.info("FILE RELATED "+this.name);
|
||||
parseContent(content);
|
||||
}
|
||||
|
@ -27,7 +18,7 @@ public class InpFile {
|
|||
if (content[i] == '\n'){
|
||||
byte[] line = new byte[i-lastIndex];
|
||||
System.arraycopy(content, lastIndex, line, 0, i-lastIndex-1);
|
||||
inpEntries.add(new InpEntry(line));
|
||||
new InpEntry(line, name);
|
||||
//RainbowDump.hexDumpUTF8(line);
|
||||
|
||||
if (isNextCarriageReturn(i, content)){
|
|
@ -13,6 +13,10 @@ import org.springframework.core.io.FileSystemResource;
|
|||
import org.springframework.stereotype.Component;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import ru.redrise.marinesco.data.AuthorRepository;
|
||||
import ru.redrise.marinesco.data.GenreRepository;
|
||||
import ru.redrise.marinesco.data.InpEntryRepository;
|
||||
import ru.redrise.marinesco.data.LibraryMetadataRepository;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
|
@ -21,13 +25,23 @@ public class InpxScanner {
|
|||
|
||||
private String filesLocation = "";
|
||||
|
||||
private FileSystemResource libraryLocation;
|
||||
private LibraryMetadataRepository libraryMetadataRepository;
|
||||
private AuthorRepository authorRepository;
|
||||
private GenreRepository genreRepository;
|
||||
private InpEntryRepository inpEntryRepository;
|
||||
|
||||
private LibraryMetadata collectionFileMeta;
|
||||
private LibraryMetadata versionFileMeta;
|
||||
public InpxScanner(AuthorRepository authorRepository,
|
||||
GenreRepository genreRepository,
|
||||
InpEntryRepository inpEntryRepository,
|
||||
LibraryMetadataRepository libraryMetadataRepository) {
|
||||
this.authorRepository = authorRepository;
|
||||
this.genreRepository = genreRepository;
|
||||
this.libraryMetadataRepository = libraryMetadataRepository;
|
||||
}
|
||||
|
||||
public void reScan() throws Exception {
|
||||
libraryLocation = new FileSystemResource(filesLocation);
|
||||
LibraryMetadata libraryMetadata = new LibraryMetadata();
|
||||
final FileSystemResource libraryLocation = new FileSystemResource(filesLocation);
|
||||
|
||||
File inpxFile = Stream.of(libraryLocation.getFile().listFiles())
|
||||
.filter(file -> file.getName().endsWith(".inpx"))
|
||||
|
@ -35,44 +49,38 @@ public class InpxScanner {
|
|||
.get();
|
||||
|
||||
log.info("INPX file found as " + inpxFile.getName());
|
||||
|
||||
|
||||
boolean breaker = false;
|
||||
|
||||
try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(inpxFile))) {
|
||||
ZipEntry zipEntry = zipInputStream.getNextEntry();
|
||||
while (zipEntry != null) {
|
||||
//log.info("Now parsing: " + zipEntry.getName());
|
||||
if (zipEntry.isDirectory()) {
|
||||
zipEntry = zipInputStream.getNextEntry();
|
||||
continue;
|
||||
}
|
||||
/* Lines:
|
||||
* 1 - Collection Display Name
|
||||
* 2 - Collection file name
|
||||
* 3 - num: 0 - fb2, 1 - non-FB2
|
||||
* 4 - description
|
||||
*/
|
||||
if (zipEntry.getName().toLowerCase().equals("collection.info"))
|
||||
setMetadata("collection.info", zipInputStream);
|
||||
|
||||
// version.info contains only 1 string
|
||||
if (zipEntry.getName().toLowerCase().equals("version.info"))
|
||||
setMetadata("version.info", zipInputStream);
|
||||
if (zipEntry.getName().toLowerCase().contains("collection.info"))
|
||||
libraryMetadata.setCollectionInfo(readPlainText(zipInputStream));
|
||||
|
||||
if (zipEntry.getName().toLowerCase().endsWith(".inp")){
|
||||
if (breaker)
|
||||
break;
|
||||
breaker = true;
|
||||
if (zipEntry.getName().toLowerCase().contains("version.info"))
|
||||
libraryMetadata.setVersionInfo(readPlainText(zipInputStream));
|
||||
|
||||
if (zipEntry.getName().toLowerCase().endsWith(".inp")) {
|
||||
/*
|
||||
if (breaker) {
|
||||
zipEntry = zipInputStream.getNextEntry();
|
||||
continue;
|
||||
}
|
||||
breaker = true;// */
|
||||
parseInp(zipInputStream, zipEntry.getSize(), zipEntry.getName());
|
||||
}
|
||||
|
||||
zipEntry = zipInputStream.getNextEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setMetadata(String filename, ZipInputStream zipInputStream) throws Exception {
|
||||
collectionFileMeta = new LibraryMetadata(filename, readPlainText(zipInputStream));
|
||||
libraryMetadataRepository.save(libraryMetadata);
|
||||
}
|
||||
|
||||
private String readPlainText(ZipInputStream zipInputStream) throws Exception {
|
||||
|
@ -105,7 +113,9 @@ public class InpxScanner {
|
|||
block = new byte[blockSize];
|
||||
}
|
||||
}
|
||||
new InpFile(inpByteBuffer.array(), fileName);
|
||||
// TODO : FIX!
|
||||
//inpFileRepository.save(new InpFile(inpByteBuffer.array(), fileName));
|
||||
new InpFileScanner(inpByteBuffer.array(), fileName);
|
||||
}
|
||||
|
||||
public String getFilesLocation() {
|
||||
|
|
|
@ -1,15 +1,48 @@
|
|||
package ru.redrise.marinesco.library;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/*
|
||||
* collection.info lines:
|
||||
* 1 - Collection Display Name
|
||||
* 2 - Collection file name
|
||||
* 3 - num: 0 - fb2, 1 - non-FB2
|
||||
* 4 - description
|
||||
// version.info contains only 1 string
|
||||
*/
|
||||
@Entity
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class LibraryMetadata {
|
||||
@Id
|
||||
private String filename;
|
||||
private String content;
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private String libraryName;
|
||||
private String libraryFileName; // makes no sense, fuck it either way
|
||||
private Integer libraryType; // used to be good idea but still nobody bother to fill it right so ignore this shit
|
||||
private String description;
|
||||
|
||||
private String version;
|
||||
|
||||
public void setVersionInfo(String content) throws Exception {
|
||||
this.version = content.trim();
|
||||
}
|
||||
|
||||
public void setCollectionInfo(String content) throws Exception {
|
||||
String[] lines = content.split("\n");
|
||||
if (lines.length < 4)
|
||||
throw new Exception("Invalid 'collection.info' file. It contains only "+lines.length+" lines!");
|
||||
libraryName = lines[0].trim();
|
||||
libraryFileName = lines[1].trim();
|
||||
libraryType = Integer.parseInt(lines[2].trim());
|
||||
description = lines[3].trim();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue