Compare commits

..

No commits in common. "1791fd909d6cc3493207f4bb582792c6e877e878" and "ae52c1cd492fd3aaa5f577406fc788e54debac70" have entirely different histories.

11 changed files with 17 additions and 248 deletions

View file

@ -1,31 +0,0 @@
package ru.redrise.marinesco;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import ru.redrise.marinesco.data.InpEntryRepository;
import ru.redrise.marinesco.library.InpEntry;
@Controller
@RequestMapping("/book")
public class BookController {
InpEntryRepository inpEntryRepository;
public BookController(InpEntryRepository inpEntryRepository){
this.inpEntryRepository = inpEntryRepository;
}
@GetMapping("/{bookId}")
public String getPage(@PathVariable("bookId") Long bookId, Model model) {
InpEntry book = inpEntryRepository.findById(bookId).orElse(null);
if (book == null){
model.addAttribute("Error", "Not found");
return "book";
}
model.addAttribute("book", book);
return "book";
}
}

View file

@ -1,89 +0,0 @@
package ru.redrise.marinesco;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import ru.redrise.marinesco.settings.ApplicationSettings;
@Slf4j
@Controller
@RequestMapping("/download")
public class DownloadController {
private String filesLocation;
public DownloadController(ApplicationSettings applicationSettings) {
this.filesLocation = applicationSettings.getFilesLocation();
}
@GetMapping(value = "/")
public void getMethodName(@RequestParam String container,
@RequestParam String file,
HttpServletResponse response) throws Exception {
final FileSystemResource libraryLocation = new FileSystemResource(filesLocation + File.separator + container);
try (ZipInputStream zipInputStream = new ZipInputStream(libraryLocation.getInputStream())) {
ZipEntry zipEntry = zipInputStream.getNextEntry();
while (zipEntry != null) {
if (zipEntry.getName().contains(file)) {
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, ContentDisposition.attachment()
.filename(file+".fb2", StandardCharsets.UTF_8) //TODO: fix
.build()
.toString());
ServletOutputStream outStream = response.getOutputStream();
sendFile(zipEntry.getSize(), zipInputStream, outStream);
outStream.flush();
outStream.close();
return;
}
zipEntry = zipInputStream.getNextEntry();
}
}
throw new Exception("file not found " +
filesLocation + File.separator + container + "" + file);
}
private void sendFile(long fileSize,
ZipInputStream zipInputStream,
ServletOutputStream outStream) throws Exception {
int blockSize = 0x200;
if (fileSize < 0x200)
blockSize = (int) fileSize;
byte[] block = new byte[blockSize];
long i = 0;
while (true) {
int actuallyRead = zipInputStream.read(block);
outStream.write(block, 0, actuallyRead);
i += actuallyRead;
if ((i + blockSize) > fileSize) {
blockSize = (int) (fileSize - i);
if (blockSize == 0)
break;
block = new byte[blockSize];
}
}
}
}

View file

@ -2,20 +2,12 @@ package ru.redrise.marinesco;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller @Controller
@RequestMapping("/")
public class RootController { public class RootController {
@GetMapping @GetMapping("/")
public String getPage(@ModelAttribute("search") String text) { public String home(){
// TODO: SEARCH PAGE + CONTROLLER
log.info(text);
return "root"; return "root";
} }
} }

View file

@ -1,21 +0,0 @@
package ru.redrise.marinesco.library;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import ru.redrise.marinesco.data.AuthorRepository;
@Component
public class AthorByIdConverter implements Converter<Long, Author>{
private AuthorRepository authorRepository;
public AthorByIdConverter(AuthorRepository authorRepository){
this.authorRepository = authorRepository;
}
@Override
public Author convert(Long id) {
return authorRepository.findById(id).orElse(null);
}
}

View file

@ -1,21 +0,0 @@
package ru.redrise.marinesco.library;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import ru.redrise.marinesco.data.GenreRepository;
@Component
public class GenreByIdConverter implements Converter<String, Genre>{
private GenreRepository genreRepository;
public GenreByIdConverter(GenreRepository genreRepository){
this.genreRepository = genreRepository;
}
@Override
public Genre convert(String id) {
return genreRepository.findById(id).orElse(null);
}
}

View file

@ -17,29 +17,27 @@ import ru.redrise.marinesco.data.AuthorRepository;
import ru.redrise.marinesco.data.GenreRepository; import ru.redrise.marinesco.data.GenreRepository;
import ru.redrise.marinesco.data.InpEntryRepository; import ru.redrise.marinesco.data.InpEntryRepository;
import ru.redrise.marinesco.data.LibraryMetadataRepository; import ru.redrise.marinesco.data.LibraryMetadataRepository;
import ru.redrise.marinesco.settings.ApplicationSettings;
@Slf4j @Slf4j
@Component @Component
@ConfigurationProperties(prefix = "marinesco.library")
public class InpxScanner implements Runnable { public class InpxScanner implements Runnable {
private static volatile Thread parser; private static volatile Thread parser;
private static volatile String lastRunErrors; private static volatile String lastRunErrors;
private String filesLocation = "";
private LibraryMetadata libraryMetadata; private LibraryMetadata libraryMetadata;
private LibraryMetadataRepository libraryMetadataRepository; private LibraryMetadataRepository libraryMetadataRepository;
private AuthorRepository authorRepository; private AuthorRepository authorRepository;
private GenreRepository genreRepository; private GenreRepository genreRepository;
private InpEntryRepository inpEntryRepository; private InpEntryRepository inpEntryRepository;
private String filesLocation; public InpxScanner(AuthorRepository authorRepository,
public InpxScanner(ApplicationSettings applicationSettings,
AuthorRepository authorRepository,
GenreRepository genreRepository, GenreRepository genreRepository,
InpEntryRepository inpEntryRepository, InpEntryRepository inpEntryRepository,
LibraryMetadataRepository libraryMetadataRepository) { LibraryMetadataRepository libraryMetadataRepository) {
this.filesLocation = applicationSettings.getFilesLocation();
this.authorRepository = authorRepository; this.authorRepository = authorRepository;
this.genreRepository = genreRepository; this.genreRepository = genreRepository;
this.inpEntryRepository = inpEntryRepository; this.inpEntryRepository = inpEntryRepository;
@ -49,7 +47,7 @@ public class InpxScanner implements Runnable {
/* /*
* @return true if executed, false if already running * @return true if executed, false if already running
*/ */
public boolean reScan() { public boolean reScan(){
if (parser == null || !parser.isAlive()) { if (parser == null || !parser.isAlive()) {
parser = new Thread(this); parser = new Thread(this);
parser.start(); parser.start();
@ -135,9 +133,6 @@ public class InpxScanner implements Runnable {
} }
private void parseInp(File inpxFile) throws Exception { private void parseInp(File inpxFile) throws Exception {
log.warn("REMOVE TEMPORARY SOLUTION - BREAKER");
log.warn("REMOVE TEMPORARY SOLUTION - BREAKER");
log.warn("REMOVE TEMPORARY SOLUTION - BREAKER");
boolean breaker = false; boolean breaker = false;
try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(inpxFile))) { try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(inpxFile))) {
@ -192,6 +187,14 @@ public class InpxScanner implements Runnable {
return i + 1 < content.length && (content[i + 1] == '\r'); return i + 1 < content.length && (content[i + 1] == '\r');
} }
public String getFilesLocation() {
return filesLocation;
}
public void setFilesLocation(String location) {
filesLocation = location;
}
public static String getLastRunErrors() { public static String getLastRunErrors() {
return lastRunErrors; return lastRunErrors;
} }

View file

@ -1,15 +1,11 @@
package ru.redrise.marinesco.settings; package ru.redrise.marinesco.settings;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
@ConfigurationProperties(prefix = "marinesco.library")
public class ApplicationSettings { public class ApplicationSettings {
private static final String ALLOW_REGISTRATION = "allow_registration"; private static final String ALLOW_REGISTRATION = "allow_registration";
private String filesLocation = "";
private KeyValueRepository keyValueRepository; private KeyValueRepository keyValueRepository;
private boolean registrationAllowed; private boolean registrationAllowed;
@ -38,13 +34,4 @@ public class ApplicationSettings {
public synchronized boolean isRegistrationAllowed() { public synchronized boolean isRegistrationAllowed() {
return registrationAllowed; return registrationAllowed;
} }
public String getFilesLocation() {
return filesLocation;
}
public void setFilesLocation(String location) {
filesLocation = location;
}
} }

View file

@ -8,10 +8,6 @@
src: url('/styles/Arimo-VariableFont_wght.ttf'); src: url('/styles/Arimo-VariableFont_wght.ttf');
} }
html{
line-height: 1.5;
}
body { body {
font-family: Arimo; font-family: Arimo;
background-color: #212121; background-color: #212121;

View file

@ -1,40 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Marinesco</title>
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="alternate icon" href="/favicon.png" type="image/png">
<link rel="stylesheet" th:href="@{/styles/styles.css}" />
</head>
<body>
<div class="page">
<div th:replace="~{fragments/header :: 'header'}"></div>
<div class="container base">
<span class="validationError" th:if="${Error} != null" th:text="${Error}"></span>
<div th:if="${book} != null">
<br /><span th:text="${'Title: ' + book.title}"></span>
<br /><span>Authors: </span>
<div th:each="author : ${book.authors}">
<span th:text="${' * ' + author.authorName}"></span>
</div>
<br /><span>Genres: </span>
<div th:each="genre : ${book.genres}">
<span th:text="${' * ' + genre.genreId + ' — ' + genre.humanReadableDescription}"></span>
</div>
<br /><span th:if="${book.series} != null" th:text="${'Series: ' + book.series}"></span>
<br /><span th:if="${book.serNo} != null" th:text="${'Series # : ' + book.serNo}"></span>
<br /><span th:text="${'Format: ' + book.fileExtension}"></span>
<br /><span th:if="${book.addedDate} != null" th:text="${'Added : ' + book.addedDate}"></span>
<br /><span th:text="${'Size: ' + book.fileSize + ' bytes'}"></span>
<p>
<a th:href="${'/download/?container=' + book.container + '&file=' + book.fsFileName}" th:text="Download"></a>
</p>
</div>
</div>
</div>
<div th:replace="~{fragments/footer :: 'footer'}"></div>
</body>
</html>

View file

@ -9,7 +9,7 @@
<div class="container"> <div class="container">
<footer class="inner_footer"> <footer class="inner_footer">
<a class="entry" href="https://redrise.ru"> <a class="entry" href="https://redrise.ru">
<div class="copy_link">&copy; 2023-2024 Dmitry Isaenko</div> <div class="copy_link">&copy; 2023 Dmitry Isaenko</div>
</a> </a>
</footer> </footer>
</div> </div>

View file

@ -16,14 +16,7 @@
<br /><a href="/profile">/profile</a> <br /><a href="/profile">/profile</a>
<br /><a href="/manage_users">/manage_users</a> <br /><a href="/manage_users">/manage_users</a>
<br /><a href="/settings">/settings</a> <br /><a href="/settings">/settings</a>
<br /><a href="/book/59992766">/book/59992766</a>
<br /><a href="/h2">H2</a> <br /><a href="/h2">H2</a>
<br />
<br />
<form action='' method='get'>
<input type='text' name='search'>
<button class="sign" type='submit'>Search</button>
</form>
</div> </div>
</div> </div>
<div th:replace="~{fragments/footer :: 'footer'}"></div> <div th:replace="~{fragments/footer :: 'footer'}"></div>