diff --git a/sopds.properties b/sopds.properties new file mode 100644 index 0000000..0673300 --- /dev/null +++ b/sopds.properties @@ -0,0 +1,8 @@ +#SOPDS Configuration File +#Mon Nov 03 02:18:38 GMT+03:00 2025 +SOPDS_ALPHABET_MENU=true +SOPDS_LANGUAGE=ru +SOPDS_PAGE_SIZE=20 +SOPDS_SCAN_ENABLED=true +SOPDS_SCAN_PATH=books +SOPDS_TITLE=Simple OPDS Catalog diff --git a/src/main/java/ru/mcs/sopds/config/SettingsInitializer.java b/src/main/java/ru/mcs/sopds/config/SettingsInitializer.java new file mode 100644 index 0000000..cd283d4 --- /dev/null +++ b/src/main/java/ru/mcs/sopds/config/SettingsInitializer.java @@ -0,0 +1,30 @@ +package ru.mcs.sopds.config; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; +import ru.mcs.sopds.service.SettingsService; + +@Slf4j +@Component +@RequiredArgsConstructor +public class SettingsInitializer implements ApplicationRunner { + + private final SettingsService settingsService; + + @Override + public void run(ApplicationArguments args) { + log.info("Инициализация настроек SOPDS..."); + settingsService.loadSettings(); + + log.info("Текущие настройки:"); + log.info(" SOPDS_ALPHABET_MENU: {}", settingsService.getAlphabetMenu()); + log.info(" SOPDS_SCAN_ENABLED: {}", settingsService.getScanEnabled()); + log.info(" SOPDS_SCAN_PATH: {}", settingsService.getScanPath()); + log.info(" SOPDS_PAGE_SIZE: {}", settingsService.getPageSize()); + log.info(" SOPDS_TITLE: {}", settingsService.getTitle()); + log.info(" SOPDS_LANGUAGE: {}", settingsService.getLanguage()); + } +} \ No newline at end of file diff --git a/src/main/java/ru/mcs/sopds/controller/SettingsController.java b/src/main/java/ru/mcs/sopds/controller/SettingsController.java index 2a6f1c8..e618148 100644 --- a/src/main/java/ru/mcs/sopds/controller/SettingsController.java +++ b/src/main/java/ru/mcs/sopds/controller/SettingsController.java @@ -22,9 +22,13 @@ model.addAttribute("breadcrumbs", new String[]{"Настройки"}); model.addAttribute("current", "settings"); - // Передаем все настройки в модель - Map settings = settingsService.getAllSettings(); - model.addAttribute("settings", settings); + // Передаем текущие настройки в модель + model.addAttribute("alphabetMenu", settingsService.getAlphabetMenu()); + model.addAttribute("scanEnabled", settingsService.getScanEnabled()); + model.addAttribute("scanPath", settingsService.getScanPath()); + model.addAttribute("pageSize", settingsService.getPageSize()); + model.addAttribute("title", settingsService.getTitle()); + model.addAttribute("language", settingsService.getLanguage()); return "settings"; } @@ -32,31 +36,37 @@ @PostMapping("/save") public String saveSettings(@RequestParam Map params, Model model) { try { - Map settingsToUpdate = new HashMap<>(); - // Обрабатываем чекбоксы (они приходят только если отмечены) boolean alphabetMenu = params.containsKey("SOPDS_ALPHABET_MENU"); boolean scanEnabled = params.containsKey("SOPDS_SCAN_ENABLED"); - settingsToUpdate.put("SOPDS_ALPHABET_MENU", alphabetMenu); - settingsToUpdate.put("SOPDS_SCAN_ENABLED", scanEnabled); + settingsService.setAlphabetMenu(alphabetMenu); + settingsService.setScanEnabled(scanEnabled); // Обрабатываем текстовые поля if (params.containsKey("SOPDS_SCAN_PATH")) { - settingsToUpdate.put("SOPDS_SCAN_PATH", params.get("SOPDS_SCAN_PATH")); + settingsService.setScanPath(params.get("SOPDS_SCAN_PATH")); } if (params.containsKey("SOPDS_PAGE_SIZE")) { try { int pageSize = Integer.parseInt(params.get("SOPDS_PAGE_SIZE")); - settingsToUpdate.put("SOPDS_PAGE_SIZE", pageSize); + settingsService.setPageSize(pageSize); } catch (NumberFormatException e) { // Оставляем предыдущее значение при ошибке } } - // Сохраняем настройки - settingsService.updateSettings(settingsToUpdate); + if (params.containsKey("SOPDS_TITLE")) { + settingsService.setTitle(params.get("SOPDS_TITLE")); + } + + if (params.containsKey("SOPDS_LANGUAGE")) { + settingsService.setLanguage(params.get("SOPDS_LANGUAGE")); + } + + // Сохраняем настройки в файл + settingsService.saveSettings(); model.addAttribute("systemMessage", Map.of( "type", "success", @@ -79,6 +89,20 @@ public String toggleAlphabetMenu() { boolean current = settingsService.getAlphabetMenu(); settingsService.setAlphabetMenu(!current); + settingsService.saveSettings(); return "redirect:/"; } + + @GetMapping("/reload") + public String reloadSettings(Model model) { + settingsService.loadSettings(); + + model.addAttribute("systemMessage", Map.of( + "type", "success", + "title", "Успех", + "text", "Настройки перезагружены из файла!" + )); + + return settingsPage(model); + } } \ No newline at end of file diff --git a/src/main/java/ru/mcs/sopds/service/BookScannerService.java b/src/main/java/ru/mcs/sopds/service/BookScannerService.java index 70debdb..b86d14f 100644 --- a/src/main/java/ru/mcs/sopds/service/BookScannerService.java +++ b/src/main/java/ru/mcs/sopds/service/BookScannerService.java @@ -29,11 +29,11 @@ private final SettingsService settingsService; private String getScanPath() { - return (String) settingsService.getSetting("SOPDS_SCAN_PATH"); + return (String) settingsService.getScanPath(); } private boolean isScannerEnabled() { - return (boolean) settingsService.getSetting("SOPDS_SCAN_ENABLED"); + return (boolean) settingsService.getScanEnabled(); } private final Set SUPPORTED_FORMATS = Set.of("fb2", "epub", "pdf", "mobi", "djvu"); diff --git a/src/main/java/ru/mcs/sopds/service/SettingsService.java b/src/main/java/ru/mcs/sopds/service/SettingsService.java index 35d4616..37a137f 100644 --- a/src/main/java/ru/mcs/sopds/service/SettingsService.java +++ b/src/main/java/ru/mcs/sopds/service/SettingsService.java @@ -1,44 +1,152 @@ package ru.mcs.sopds.service; import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; import org.springframework.stereotype.Service; -import java.util.HashMap; -import java.util.Map; +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Properties; @Slf4j @Service public class SettingsService { - private final Map settings = new HashMap<>(); + private final Properties properties; + private final Path externalConfigPath; public SettingsService() { - // Инициализация настроек по умолчанию - settings.put("SOPDS_ALPHABET_MENU", true); - settings.put("SOPDS_SCAN_ENABLED", true); - settings.put("SOPDS_SCAN_PATH", "books"); - settings.put("SOPDS_PAGE_SIZE", 20); + this.properties = new Properties(); + this.externalConfigPath = Paths.get("sopds.properties"); + loadSettings(); } + public void loadSettings() { + try { + // Сначала пробуем загрузить из внешнего файла (рядом с JAR) + if (Files.exists(externalConfigPath)) { + try (InputStream input = Files.newInputStream(externalConfigPath)) { + properties.load(input); + log.info("Настройки загружены из внешнего файла: {}", externalConfigPath.toAbsolutePath()); + } + } else { + // Если внешнего файла нет, загружаем из ресурсов + Resource resource = new ClassPathResource("sopds.properties"); + try (InputStream input = resource.getInputStream()) { + properties.load(input); + log.info("Настройки загружены из ресурсов"); + } + + // Создаем внешний файл для будущих изменений + saveSettings(); + } + } catch (IOException e) { + log.error("Ошибка при загрузке настроек: {}", e.getMessage()); + setDefaultSettings(); + } + } + + public void saveSettings() { + try (OutputStream output = Files.newOutputStream(externalConfigPath)) { + properties.store(output, "SOPDS Configuration File"); + log.info("Настройки сохранены в файл: {}", externalConfigPath.toAbsolutePath()); + } catch (IOException e) { + log.error("Ошибка при сохранении настроек: {}", e.getMessage()); + } + } + + private void setDefaultSettings() { + properties.setProperty("SOPDS_ALPHABET_MENU", "true"); + properties.setProperty("SOPDS_SCAN_ENABLED", "true"); + properties.setProperty("SOPDS_SCAN_PATH", "books"); + properties.setProperty("SOPDS_PAGE_SIZE", "20"); + properties.setProperty("SOPDS_TITLE", "Simple OPDS Catalog"); + properties.setProperty("SOPDS_LANGUAGE", "ru"); + } + + // Общие методы для работы с настройками + public String getProperty(String key, String defaultValue) { + return properties.getProperty(key, defaultValue); + } + + public void setProperty(String key, String value) { + properties.setProperty(key, value); + } + + public boolean getBooleanProperty(String key, boolean defaultValue) { + String value = properties.getProperty(key); + if (value != null) { + return Boolean.parseBoolean(value); + } + return defaultValue; + } + + public int getIntProperty(String key, int defaultValue) { + String value = properties.getProperty(key); + if (value != null) { + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + log.warn("Некорректное значение для {}: {}", key, value); + } + } + return defaultValue; + } + + // Специфичные геттеры и сеттеры для каждой настройки public boolean getAlphabetMenu() { - return (boolean) settings.getOrDefault("SOPDS_ALPHABET_MENU", true); + return getBooleanProperty("SOPDS_ALPHABET_MENU", true); } - public void setAlphabetMenu(boolean enabled) { - settings.put("SOPDS_ALPHABET_MENU", enabled); - log.info("SOPDS_ALPHABET_MENU установлен в: {}", enabled); + public void setAlphabetMenu(boolean value) { + setProperty("SOPDS_ALPHABET_MENU", String.valueOf(value)); } - public Map getAllSettings() { - return new HashMap<>(settings); + public boolean getScanEnabled() { + return getBooleanProperty("SOPDS_SCAN_ENABLED", true); } - public void updateSettings(Map newSettings) { - settings.putAll(newSettings); - log.info("Настройки обновлены: {}", newSettings); + public void setScanEnabled(boolean value) { + setProperty("SOPDS_SCAN_ENABLED", String.valueOf(value)); } - public Object getSetting(String key) { - return settings.get(key); + public String getScanPath() { + return getProperty("SOPDS_SCAN_PATH", "books"); + } + + public void setScanPath(String value) { + setProperty("SOPDS_SCAN_PATH", value); + } + + public int getPageSize() { + return getIntProperty("SOPDS_PAGE_SIZE", 20); + } + + public void setPageSize(int value) { + setProperty("SOPDS_PAGE_SIZE", String.valueOf(value)); + } + + public String getTitle() { + return getProperty("SOPDS_TITLE", "Simple OPDS Catalog"); + } + + public void setTitle(String value) { + setProperty("SOPDS_TITLE", value); + } + + public String getLanguage() { + return getProperty("SOPDS_LANGUAGE", "ru"); + } + + public void setLanguage(String value) { + setProperty("SOPDS_LANGUAGE", value); + } + + // Метод для получения всех настроек (для отображения) + public Properties getAllProperties() { + return new Properties(properties); } } \ No newline at end of file diff --git a/src/main/resources/sopds.properties b/src/main/resources/sopds.properties new file mode 100644 index 0000000..bed7436 --- /dev/null +++ b/src/main/resources/sopds.properties @@ -0,0 +1,26 @@ +# SOPDS Configuration File +# This file contains all settings for Simple OPDS Catalog + +# ???????? ?????????? ???? ? ??????? ????? ??? ????, ??????? ? ????? +# ?? ?????????: true +SOPDS_ALPHABET_MENU=true + +# ???????? ?????????????? ???????????? ???? ??? ??????? +# ?? ?????????: true +SOPDS_SCAN_ENABLED=true + +# ?????????? ??? ?????? ???? +# ?? ?????????: books +SOPDS_SCAN_PATH=books + +# ?????????? ????????? ?? ????? ???????? +# ?? ?????????: 20 +SOPDS_PAGE_SIZE=20 + +# ????????? ?????????? +# ?? ?????????: Simple OPDS Catalog +SOPDS_TITLE=Simple OPDS Catalog + +# ???? ?????????? +# ?? ?????????: ru +SOPDS_LANGUAGE=ru \ No newline at end of file diff --git a/src/main/resources/templates/settings.html b/src/main/resources/templates/settings.html index 79d3ff3..a8f29c9 100644 --- a/src/main/resources/templates/settings.html +++ b/src/main/resources/templates/settings.html @@ -102,6 +102,14 @@ color: #7f8c8d; margin-top: 5px; } + + .config-info { + background: #f8f9fa; + padding: 15px; + border-radius: 4px; + margin-top: 10px; + font-size: 12px; + } @@ -127,7 +135,7 @@
@@ -135,17 +143,46 @@
- Размер страницы + SOPDS_TITLE +
+ Заголовок приложения +
+
+
+ +
+
+ +
+
+ SOPDS_PAGE_SIZE
Количество элементов на одной странице
+ +
+
+ SOPDS_LANGUAGE +
+ Язык интерфейса +
+
+
+ +
+
@@ -162,7 +199,7 @@
@@ -170,14 +207,14 @@
- Путь для сканирования + SOPDS_SCAN_PATH
Директория для поиска книг
@@ -190,26 +227,32 @@ - + + Перезагрузить + + Отмена - - +
-

Текущие настройки

-
-                        Настройки
-                    
+

Информация о конфигурации

+
+

Файл конфигурации: sopds.properties

+

Расположение: Корневая директория приложения (рядом с JAR файлом)

+

Формат: Properties файл с комментариями

+

Изменения: Вступают в силу после сохранения

+

Резервная копия: Исходный файл в ресурсах используется только при первом запуске

+