diff --git a/pom.xml b/pom.xml index 0e4beca5..a1021f6f 100644 --- a/pom.xml +++ b/pom.xml @@ -134,15 +134,27 @@ 1.4 - - + + org.jetbrains.xodus + xodus-environment + 1.3.232 + + + org.jetbrains.xodus + xodus-entity-store + 1.3.232 + + + org.jetbrains.xodus + xodus-vfs + 1.3.232 + + org.testng diff --git a/src/main/java/uk/yermak/audiobookconverter/AppProperties.java b/src/main/java/uk/yermak/audiobookconverter/AppProperties.java deleted file mode 100644 index 726c780e..00000000 --- a/src/main/java/uk/yermak/audiobookconverter/AppProperties.java +++ /dev/null @@ -1,63 +0,0 @@ -package uk.yermak.audiobookconverter; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.lang.invoke.MethodHandles; -import java.util.Enumeration; -import java.util.Properties; - -public class AppProperties { - final static Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - public static final File APP_DIR = new File(System.getProperty("APP_HOME")); - public static final File PROP_FILE = new File(APP_DIR, Version.getVersionString() + ".properties"); - private static final Properties applicationProps = new Properties(); - - static { - loadAppProperties(); - } - - static synchronized Properties loadAppProperties() { - if (PROP_FILE.exists()) { - try (FileInputStream in = new FileInputStream(PROP_FILE)) { - applicationProps.load(in); - } catch (IOException e) { - logger.error("Error during loading properties", e); - } - } - return applicationProps; - } - - public static String getProperty(String key) { - return applicationProps.getProperty(key); - } - - public static Properties getProperties(String group) { - Properties properties = new Properties(); - Enumeration keys = applicationProps.keys(); - while (keys.hasMoreElements()) { - String propName = (String) keys.nextElement(); - if (propName.startsWith(group + ".")) { - String nameWithoutGroup = propName.substring(group.length() + 1); - properties.setProperty(nameWithoutGroup, applicationProps.getProperty(propName)); - } - } - return properties; - } - - public static synchronized void setProperty(String key, String value) { - applicationProps.put(key, value); - File appDir = APP_DIR; - if (appDir.exists() || appDir.mkdir()) { - try (FileOutputStream out = new FileOutputStream(PROP_FILE)) { - applicationProps.store(out, ""); - } catch (Exception e) { - logger.error("Error during saving properties", e); - } - } - } -} diff --git a/src/main/java/uk/yermak/audiobookconverter/AppSetting.java b/src/main/java/uk/yermak/audiobookconverter/AppSetting.java new file mode 100644 index 00000000..f9d5e5f3 --- /dev/null +++ b/src/main/java/uk/yermak/audiobookconverter/AppSetting.java @@ -0,0 +1,163 @@ +package uk.yermak.audiobookconverter; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import jetbrains.exodus.ByteIterable; +import jetbrains.exodus.bindings.StringBinding; +import jetbrains.exodus.entitystore.Entity; +import jetbrains.exodus.entitystore.EntityIterable; +import jetbrains.exodus.entitystore.PersistentEntityStore; +import jetbrains.exodus.entitystore.PersistentEntityStores; +import jetbrains.exodus.env.*; +import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.lang.invoke.MethodHandles; +import java.util.*; +import java.util.stream.StreamSupport; + +public class AppSetting { + final static Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + public static final File APP_DIR = new File(System.getProperty("APP_HOME")); + public static final String PRESET_ENTITY = "Preset"; + public static final String PRESET_NAME = "name"; + public static final String PRESET_FORMAT = "format"; + public static final String PRESET_BITRATE = "bitrate"; + public static final String PRESET_FREQUENCY = "frequency"; + public static final String PRESET_CHANNELS = "channels"; + public static final String PRESET_CUTOFF = "cutoff"; + public static final String PRESET_CBR = "cbr"; + public static final String PRESET_QUALITY = "quality"; + public static final String GENRE_ENTITY = "Genre"; + public static final String GENRE_TITLE = "title"; + public static final String GENRE_CREATED = "created"; + public static final String SETTINGS = "Settings"; + + + public static String getProperty(String key) { + String result; + try (jetbrains.exodus.env.Environment env = Environments.newInstance(APP_DIR.getPath())) { + result = env.computeInReadonlyTransaction(txn -> { + final Store store = env.openStore(SETTINGS, StoreConfig.WITHOUT_DUPLICATES, txn); + ByteIterable entry = store.get(txn, StringBinding.stringToEntry(key)); + if (entry!=null) { + return StringBinding.entryToString(entry); + } else { + return null; + } + }); + } + return result; + } + + public static synchronized void setProperty(String key, String value) { + try (jetbrains.exodus.env.Environment env = Environments.newInstance(APP_DIR.getPath())) { + env.executeInTransaction(txn -> { + final Store store = env.openStore(SETTINGS, StoreConfig.WITHOUT_DUPLICATES, txn); + store.put(txn, StringBinding.stringToEntry(key), StringBinding.stringToEntry(value)); + }); + } + } + + public static void saveGenres(String genre) { + if (StringUtils.isNotEmpty(genre) & loadGenres().stream().noneMatch(s -> s.equals(genre))) { + try (PersistentEntityStore entityStore = PersistentEntityStores.newInstance(APP_DIR.getPath())) { + entityStore.executeInTransaction(txn -> { + final Entity genreEntity = txn.newEntity(GENRE_ENTITY); + genreEntity.setProperty(GENRE_TITLE, genre); + genreEntity.setProperty(GENRE_CREATED, System.currentTimeMillis()); + }); + } + } + } + + public static ObservableList loadGenres() { + ObservableList genres; + try (PersistentEntityStore entityStore = PersistentEntityStores.newInstance(APP_DIR.getPath())) { + genres = entityStore.computeInReadonlyTransaction(txn -> { + ObservableList list = FXCollections.observableArrayList(); + StreamSupport.stream(txn.sort(GENRE_ENTITY, GENRE_TITLE, true).spliterator(), false).forEach(g -> list.add((String) g.getProperty(GENRE_TITLE))); + return list; + }); + } + return genres; + } + + public static void removeGenre(String genre) { + try (PersistentEntityStore entityStore = PersistentEntityStores.newInstance(APP_DIR.getPath())) { + entityStore.executeInTransaction(txn -> { + EntityIterable entities = txn.find(GENRE_ENTITY, GENRE_TITLE, genre); + for (Entity entity : entities) { + entity.delete(); + } + }); + } + } + + public static List loadPresets() { + List presets; + try (PersistentEntityStore entityStore = PersistentEntityStores.newInstance(APP_DIR.getPath())) { + presets = entityStore.computeInReadonlyTransaction(txn -> { + List list = new ArrayList<>(); + EntityIterable all = txn.getAll(PRESET_ENTITY); + for (Entity entity : all) { + Preset preset = bindPreset(entity); + list.add(preset); + } + return list; + }); + } + return presets; + } + + @NotNull + private static Preset bindPreset(Entity entity) { + String name = (String) entity.getProperty(PRESET_NAME); + String format = (String) entity.getProperty(PRESET_FORMAT); + Integer bitrate = (Integer) entity.getProperty(PRESET_BITRATE); + Integer frequency = (Integer) entity.getProperty(PRESET_FREQUENCY); + Integer channels = (Integer) entity.getProperty(PRESET_CHANNELS); + Integer cutoff = (Integer) entity.getProperty(PRESET_CUTOFF); + Boolean cbr = (Boolean) entity.getProperty(PRESET_CBR); + Integer quality = (Integer) entity.getProperty(PRESET_QUALITY); + Preset preset = new Preset(name, new OutputParameters(Format.instance(format), bitrate, frequency, channels, cutoff, cbr, quality)); + return preset; + } + + public static void savePreset(Preset preset) { + try (PersistentEntityStore entityStore = PersistentEntityStores.newInstance(APP_DIR.getPath())) { + entityStore.executeInTransaction(txn -> { + Entity entity; + EntityIterable entities = txn.find(PRESET_ENTITY, PRESET_NAME, preset.getName()); + if (entities.isEmpty()) { + entity = txn.newEntity(PRESET_ENTITY); + } else { + entity = entities.getFirst(); + } + entity.setProperty(PRESET_NAME, preset.getName()); + entity.setProperty(PRESET_FORMAT, preset.getFormat().format); + entity.setProperty(PRESET_BITRATE, preset.getBitRate()); + entity.setProperty(PRESET_FREQUENCY, preset.getFrequency()); + entity.setProperty(PRESET_CHANNELS, preset.getChannels()); + entity.setProperty(PRESET_CUTOFF, preset.getCutoff()); + entity.setProperty(PRESET_CBR, preset.isCbr()); + entity.setProperty(PRESET_QUALITY, preset.getVbrQuality()); + }); + } + } + + public static Preset loadPreset(String presetName) { + Preset preset; + try (PersistentEntityStore entityStore = PersistentEntityStores.newInstance(APP_DIR.getPath())) { + preset = entityStore.computeInReadonlyTransaction(txn -> { + EntityIterable entities = txn.find(PRESET_ENTITY, PRESET_NAME, presetName); + if (entities.isEmpty()) return null; + return bindPreset(entities.getFirst()); + }); + } + return preset; + } +} diff --git a/src/main/java/uk/yermak/audiobookconverter/AudiobookConverter.java b/src/main/java/uk/yermak/audiobookconverter/AudiobookConverter.java index e406d2aa..ed87fc99 100644 --- a/src/main/java/uk/yermak/audiobookconverter/AudiobookConverter.java +++ b/src/main/java/uk/yermak/audiobookconverter/AudiobookConverter.java @@ -4,7 +4,6 @@ import com.apple.eio.FileManager; import javafx.application.Application; -import javafx.application.Platform; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; @@ -16,7 +15,6 @@ import org.controlsfx.control.Notifications; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import uk.yermak.audiobookconverter.Version; import uk.yermak.audiobookconverter.fx.ConversionContext; import uk.yermak.audiobookconverter.fx.JfxEnv; @@ -138,13 +136,13 @@ static class VersionChecker implements Runnable { @Override public void run() { try { - String platform = Environment.current.loadAppProperties().getProperty("platform"); + String platform = Platform.current.loadAppProperties().getProperty("platform"); if (platform == null) platform = "version"; if ("steam".equals(platform)) return; String version = readStringFromURL("https://raw.githubusercontent.com/yermak/AudioBookConverter/version/" + platform + ".txt"); if (!Version.getVersionString().equals(StringUtils.trim(version))) { logger.info("New version found: {}", version); - Platform.runLater(() -> { + javafx.application.Platform.runLater(() -> { Alert alert = new Alert(Alert.AlertType.CONFIRMATION); alert.setTitle("New Version Available!"); String path = FileManager.getPathToApplicationBundle(); diff --git a/src/main/java/uk/yermak/audiobookconverter/DurationVerifier.java b/src/main/java/uk/yermak/audiobookconverter/DurationVerifier.java index f088a186..3904d419 100644 --- a/src/main/java/uk/yermak/audiobookconverter/DurationVerifier.java +++ b/src/main/java/uk/yermak/audiobookconverter/DurationVerifier.java @@ -45,7 +45,7 @@ static long parseDuration(String info) { public static void mp4v2UpdateDuration(MediaInfo mediaInfo, String outputFileName) throws IOException { Process process = null; try { - ProcessBuilder infoProcessBuilder = new ProcessBuilder(Environment.MP4INFO, outputFileName); + ProcessBuilder infoProcessBuilder = new ProcessBuilder(Platform.MP4INFO, outputFileName); process = infoProcessBuilder.start(); ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamCopier.copy(process.getInputStream(), out); @@ -67,7 +67,7 @@ public static void mp4v2UpdateDuration(MediaInfo mediaInfo, String outputFileNam public static void ffMpegUpdateDuration(MediaInfo mediaInfo, String outputFileName) throws IOException { final Set AUDIO_CODECS = ImmutableSet.of("mp3", "aac", "wmav2", "flac", "alac", "vorbis", "opus"); - FFprobe ffprobe = new FFprobe(Environment.FFPROBE); + FFprobe ffprobe = new FFprobe(Platform.FFPROBE); FFmpegProbeResult probe = ffprobe.probe(outputFileName); List streams = probe.getStreams(); for (FFmpegStream stream : streams) { diff --git a/src/main/java/uk/yermak/audiobookconverter/FFMediaLoader.java b/src/main/java/uk/yermak/audiobookconverter/FFMediaLoader.java index fc5023cf..b64f3d1f 100644 --- a/src/main/java/uk/yermak/audiobookconverter/FFMediaLoader.java +++ b/src/main/java/uk/yermak/audiobookconverter/FFMediaLoader.java @@ -42,7 +42,7 @@ public FFMediaLoader(List files, ConversionGroup conversionGroup) { public List loadMediaInfo() { logger.info("Loading media info"); try { - FFprobe ffprobe = new FFprobe(Environment.FFPROBE); + FFprobe ffprobe = new FFprobe(Platform.FFPROBE); List media = new ArrayList<>(); for (String fileName : fileNames) { Future futureLoad = mediaExecutor.submit(new MediaInfoCallable(ffprobe, fileName, conversionGroup)); diff --git a/src/main/java/uk/yermak/audiobookconverter/FFMpegOptimizer.java b/src/main/java/uk/yermak/audiobookconverter/FFMpegOptimizer.java index c3991eae..4895f272 100644 --- a/src/main/java/uk/yermak/audiobookconverter/FFMpegOptimizer.java +++ b/src/main/java/uk/yermak/audiobookconverter/FFMpegOptimizer.java @@ -59,7 +59,7 @@ private void optimize() throws InterruptedException { try { String[] optimize = { - Environment.FFMPEG, + Platform.FFMPEG, "-i", tempFile, "-map", "0:v", "-map", "0:a", diff --git a/src/main/java/uk/yermak/audiobookconverter/FFmpegArtWorkExtractor.java b/src/main/java/uk/yermak/audiobookconverter/FFmpegArtWorkExtractor.java index 999ebf06..f5afd99e 100644 --- a/src/main/java/uk/yermak/audiobookconverter/FFmpegArtWorkExtractor.java +++ b/src/main/java/uk/yermak/audiobookconverter/FFmpegArtWorkExtractor.java @@ -1,7 +1,5 @@ package uk.yermak.audiobookconverter; -import javafx.application.Platform; - import java.io.ByteArrayOutputStream; import java.io.File; import java.util.concurrent.Callable; @@ -28,7 +26,7 @@ public ArtWork call() throws Exception { if (conversionGroup.isOver() || conversionGroup.isStarted() || conversionGroup.isDetached()) throw new InterruptedException("ArtWork loading was interrupted"); String poster = Utils.getTmp(mediaInfo.getUID(), stream, format); - ProcessBuilder pictureProcessBuilder = new ProcessBuilder(Environment.FFMPEG, + ProcessBuilder pictureProcessBuilder = new ProcessBuilder(Platform.FFMPEG, "-i", mediaInfo.getFileName(), "-map", "0:" + stream, "-y", @@ -50,7 +48,7 @@ public ArtWork call() throws Exception { FFMediaLoader.logger.error("ArtWork Error: {}", err); ArtWorkBean artWorkBean = new ArtWorkBean(poster); - Platform.runLater(() -> { + javafx.application.Platform.runLater(() -> { if (!conversionGroup.isOver() && !conversionGroup.isStarted() && !conversionGroup.isDetached()) { AudiobookConverter.getContext().addPosterIfMissingWithDelay(artWorkBean); } diff --git a/src/main/java/uk/yermak/audiobookconverter/Format.java b/src/main/java/uk/yermak/audiobookconverter/Format.java index ae531cfc..9be82637 100644 --- a/src/main/java/uk/yermak/audiobookconverter/Format.java +++ b/src/main/java/uk/yermak/audiobookconverter/Format.java @@ -32,7 +32,7 @@ public boolean ffmpegCompatible() { @Override public List getReencodingOptions(MediaInfo mediaInfo, String progressUri, String outputFileName, OutputParameters outputParameters) { List options = new ArrayList<>(); - options.add(Environment.FFMPEG); + options.add(Platform.FFMPEG); if (mediaInfo.getOffset() != -1) { options.add("-ss"); options.add(toFFMpegTime(mediaInfo.getOffset())); @@ -103,7 +103,7 @@ public Integer defaultVbrQuality() { @Override public List getConcatOptions(String fileListFileName, MetadataBuilder metadataBuilder, String progressUri, String outputFileName) { List options = new ArrayList<>(); - options.add(Environment.FFMPEG); + options.add(Platform.FFMPEG); options.add("-protocol_whitelist"); options.add("file,pipe,concat"); options.add("-f"); @@ -178,7 +178,7 @@ public Boolean defaultCBR() { @Override public List getConcatOptions(String fileListFileName, MetadataBuilder metadataBuilder, String progressUri, String outputFileName) { List options = new ArrayList<>(); - options.add(Environment.FFMPEG); + options.add(Platform.FFMPEG); options.add("-protocol_whitelist"); options.add("file,pipe,concat"); options.add("-f"); @@ -207,7 +207,7 @@ public List getConcatOptions(String fileListFileName, MetadataBuilder me @Override public List getReencodingOptions(MediaInfo mediaInfo, String progressUri, String outputFileName, OutputParameters outputParameters) { List options = new ArrayList<>(); - options.add(Environment.FFMPEG); + options.add(Platform.FFMPEG); if (mediaInfo.getOffset() != -1) { options.add("-ss"); options.add(toFFMpegTime(mediaInfo.getOffset())); @@ -329,7 +329,7 @@ public static Format instance(String extension) { public List getReencodingOptions(MediaInfo mediaInfo, String progressUri, String outputFileName, OutputParameters outputParameters) { List options = new ArrayList<>(); - options.add(Environment.FFMPEG); + options.add(Platform.FFMPEG); if (mediaInfo.getOffset() != -1) { options.add("-ss"); options.add(toFFMpegTime(mediaInfo.getOffset())); @@ -374,7 +374,7 @@ public List getReencodingOptions(MediaInfo mediaInfo, String progressUri public List getTranscodingOptions(MediaInfo mediaInfo, String progressUri, String outputFileName) { List options = new ArrayList<>(); - options.add(Environment.FFMPEG); + options.add(Platform.FFMPEG); if (mediaInfo.getOffset() != -1) { options.add("-ss"); options.add(toFFMpegTime(mediaInfo.getOffset())); @@ -401,7 +401,7 @@ public List getTranscodingOptions(MediaInfo mediaInfo, String progressUr } public List getConcatOptions(String fileListFileName, MetadataBuilder metadataBuilder, String progressUri, String outputFileName) { - String[] strings = {Environment.FFMPEG, + String[] strings = {Platform.FFMPEG, "-protocol_whitelist", "file,pipe,concat", "-vn", "-f", "concat", diff --git a/src/main/java/uk/yermak/audiobookconverter/GenresManager.java b/src/main/java/uk/yermak/audiobookconverter/GenresManager.java deleted file mode 100644 index 61df5b4f..00000000 --- a/src/main/java/uk/yermak/audiobookconverter/GenresManager.java +++ /dev/null @@ -1,37 +0,0 @@ -package uk.yermak.audiobookconverter; - -import com.google.gson.Gson; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import org.apache.commons.lang3.StringUtils; - -import java.util.ArrayList; -import java.util.stream.Collectors; - -public class GenresManager { - - private final ObservableList genres = FXCollections.observableArrayList(); - - public void saveGenres(AudioBookInfo bookInfo) { - if (bookInfo != null) { - if (StringUtils.isNotEmpty(bookInfo.genre().get()) & genres.stream().noneMatch(s -> s.equals(bookInfo.genre().get()))) { - genres.add(bookInfo.genre().get()); - } - Gson gson = new Gson(); - String genresString = gson.toJson(new ArrayList<>(genres)); - AppProperties.setProperty("genres", genresString); - } - } - - public ObservableList loadGenres() { - genres.clear(); - String genresProperty = AppProperties.getProperty("genres"); - if (genresProperty != null) { - Gson gson = new Gson(); - ArrayList list = gson.fromJson(genresProperty, ArrayList.class); - this.genres.addAll(list.stream().sorted().collect(Collectors.toList())); - } - return genres; - } - -} diff --git a/src/main/java/uk/yermak/audiobookconverter/Mp4v2ArtBuilder.java b/src/main/java/uk/yermak/audiobookconverter/Mp4v2ArtBuilder.java index d2877679..d634803e 100644 --- a/src/main/java/uk/yermak/audiobookconverter/Mp4v2ArtBuilder.java +++ b/src/main/java/uk/yermak/audiobookconverter/Mp4v2ArtBuilder.java @@ -36,7 +36,7 @@ public void coverArt(String outputFileName) throws IOException, InterruptedExcep public void updateSinglePoster(ArtWork poster, int index, String outputFileName) { Process process = null; try { - ProcessBuilder artProcessBuilder = new ProcessBuilder(Environment.MP4ART, + ProcessBuilder artProcessBuilder = new ProcessBuilder(Platform.MP4ART, "--art-index", String.valueOf(index), "--add", poster.getFileName(), outputFileName); diff --git a/src/main/java/uk/yermak/audiobookconverter/Environment.java b/src/main/java/uk/yermak/audiobookconverter/Platform.java similarity index 98% rename from src/main/java/uk/yermak/audiobookconverter/Environment.java rename to src/main/java/uk/yermak/audiobookconverter/Platform.java index 186ba50c..1a2a5f14 100644 --- a/src/main/java/uk/yermak/audiobookconverter/Environment.java +++ b/src/main/java/uk/yermak/audiobookconverter/Platform.java @@ -10,7 +10,7 @@ import java.lang.invoke.MethodHandles; import java.util.Properties; -public enum Environment { +public enum Platform { DEV { }, @@ -35,7 +35,7 @@ protected File getConfigFilePath() { WINDOWS { }; - static Environment current; + static Platform current; private static Properties properties = new Properties(); static { diff --git a/src/main/java/uk/yermak/audiobookconverter/Preset.java b/src/main/java/uk/yermak/audiobookconverter/Preset.java index b5c0c8e5..3ebf24ab 100644 --- a/src/main/java/uk/yermak/audiobookconverter/Preset.java +++ b/src/main/java/uk/yermak/audiobookconverter/Preset.java @@ -1,7 +1,5 @@ package uk.yermak.audiobookconverter; -import com.google.gson.Gson; - import java.util.*; public class Preset extends OutputParameters { @@ -16,37 +14,32 @@ public String toString() { } - static Map defaultValues = Map.of( - "ipod nano", new Preset("ipod nano", new OutputParameters(Format.M4B, 64, 44100, 1, 10000, false, 2)), - "ipod classic", new Preset("ipod classic", new OutputParameters(Format.M4B, 96, 44100, 2, 12000, true, 3)), - "iphone", new Preset("iphone", new OutputParameters(Format.M4B, 128, 44100, 2, 12000, true, 4)), - "android 5+", new Preset("android 5+", new OutputParameters(Format.OGG, 64, 44100, 2, 12000, false, 3)), - "android old", new Preset("android old", new OutputParameters(Format.M4B, 96, 44100, 2, 10000, true, 3)), - "legacy", new Preset("legacy", new OutputParameters(Format.MP3, 128, 44100, 2, 12000, true, 3)) + static List defaultValues = List.of( + new Preset("ipod nano", new OutputParameters(Format.M4B, 64, 44100, 1, 10000, false, 2)), + new Preset("ipod classic", new OutputParameters(Format.M4B, 96, 44100, 2, 12000, true, 3)), + new Preset("iphone", new OutputParameters(Format.M4B, 128, 44100, 2, 12000, true, 4)), + new Preset("android 5+", new OutputParameters(Format.OGG, 64, 44100, 2, 12000, false, 3)), + new Preset("android old", new OutputParameters(Format.M4B, 96, 44100, 2, 10000, true, 3)), + new Preset("legacy", new OutputParameters(Format.MP3, 128, 44100, 2, 12000, true, 3)) ); public static final Preset DEFAULT_OUTPUT_PARAMETERS = new Preset(Preset.DEFAULT); public static List loadPresets() { - List list = new ArrayList<>(); - Properties savedPresets = AppProperties.getProperties("preset"); - savedPresets.keySet().forEach(p -> list.add(new Preset((String) p))); - Set presetNames = defaultValues.keySet(); - for (String presetName : presetNames) { - if (!savedPresets.containsKey(presetName)) { - Gson gson = new Gson(); - String gsonString = gson.toJson(defaultValues.get(presetName)); - AppProperties.setProperty("preset." + presetName, gsonString); - list.add(new Preset(presetName)); - } + List presets = AppSetting.loadPresets(); + ArrayList toStore = new ArrayList<>(defaultValues); + toStore.removeAll(presets); + for (Preset preset : toStore) { + AppSetting.savePreset(preset); } - return list; + return AppSetting.loadPresets(); + } // private final OutputParameters save; - private Preset(String name, OutputParameters preset) { + Preset(String name, OutputParameters preset) { this.name = name; this.bitRate = preset.getBitRate(); this.frequency = preset.getFrequency(); @@ -55,7 +48,7 @@ private Preset(String name, OutputParameters preset) { this.cbr = preset.isCbr(); this.cutoff = preset.getCutoff(); this.format = preset.getFormat(); - saveProperty(); +// savePreset(); } @@ -68,66 +61,60 @@ public static Preset copy(String presetName, Preset copy) { } public static Preset instance(String presetName) { - String property = AppProperties.getProperty("preset." + presetName); - if (property != null) { - Gson gson = new Gson(); - Preset preset = gson.fromJson(property, Preset.class); - preset.initSpeed(); - return preset; - } - return new Preset(presetName, Objects.requireNonNullElseGet(defaultValues.get(presetName), OutputParameters::new)); + Preset preset = AppSetting.loadPreset(presetName); + if (preset != null) return preset; + + return new Preset(presetName, new OutputParameters()); } - private void saveProperty() { - Gson gson = new Gson(); - String gsonString = gson.toJson(this); - AppProperties.setProperty("preset." + name, gsonString); + private void savePreset() { + AppSetting.savePreset(this); } @Override public void setupFormat(Format format) { super.setupFormat(format); - saveProperty(); + savePreset(); } @Override public void setBitRate(Integer bitRate) { super.setBitRate(bitRate); - saveProperty(); + savePreset(); } @Override public void setFrequency(Integer frequency) { super.setFrequency(frequency); - saveProperty(); + savePreset(); } @Override public void setChannels(Integer channels) { super.setChannels(channels); - saveProperty(); + savePreset(); } @Override public void setVbrQuality(Integer vbrQuality) { super.setVbrQuality(vbrQuality); - saveProperty(); + savePreset(); } @Override public void setCbr(Boolean cbr) { super.setCbr(cbr); - saveProperty(); + savePreset(); } @Override public void updateAuto(List media) { - if (!defaultValues.containsKey(name)) { + if (!defaultValues.contains(this)) { super.updateAuto(media); - saveProperty(); + savePreset(); } else { //Ignoring auto-update and save for all other preset } @@ -136,10 +123,23 @@ public void updateAuto(List media) { @Override public void setCutoff(Integer cutoff) { super.setCutoff(cutoff); - saveProperty(); + savePreset(); } public String getName() { return name; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Preset preset = (Preset) o; + return Objects.equals(name, preset.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } } diff --git a/src/main/java/uk/yermak/audiobookconverter/Utils.java b/src/main/java/uk/yermak/audiobookconverter/Utils.java index 7cf08c9a..00e00e07 100644 --- a/src/main/java/uk/yermak/audiobookconverter/Utils.java +++ b/src/main/java/uk/yermak/audiobookconverter/Utils.java @@ -45,7 +45,7 @@ public static void closeSilently(Process process) { } public static String renderChapter(Chapter chapter, Map> context) { - String chapterFormat = AppProperties.getProperty("chapter_format"); + String chapterFormat = AppSetting.getProperty("chapter_format"); if (chapterFormat == null) { chapterFormat = ". " + ". " + @@ -54,7 +54,7 @@ public static String renderChapter(Chapter chapter, Map " + " " + " - "; - AppProperties.setProperty("chapter_format", chapterFormat); + AppSetting.setProperty("chapter_format", chapterFormat); } STGroup g = new STGroupString(""); g.registerRenderer(Number.class, new NumberRenderer()); @@ -73,10 +73,10 @@ public static String renderChapter(Chapter chapter, Map] - <if(NARRATOR)> (<NARRATOR>)<endif>"; - AppProperties.setProperty("filename_format", filenameFormat); + AppSetting.setProperty("filename_format", filenameFormat); } STGroup g = new STGroupString(""); @@ -146,7 +146,7 @@ public static String tempCopy(String fileName) { } public static String renderPart(Part part, Map<String, Function<Part, Object>> context) { - String partFormat = AppProperties.getProperty("part_format"); + String partFormat = AppSetting.getProperty("part_format"); if (partFormat == null) { partFormat = "<if(WRITER)><WRITER> <endif>" + "<if(SERIES)>- [<SERIES><if(BOOK_NUMBER)> -<BOOK_NUMBER><endif>] - <endif>" + @@ -154,7 +154,7 @@ public static String renderPart(Part part, Map<String, Function<Part, Object>> c "<if(NARRATOR)> (<NARRATOR>)<endif>" + "<if(YEAR)>-<YEAR><endif>" + "<if(PART)>, Part <PART; format=\"%,03d\"><endif>"; - AppProperties.setProperty("part_format", partFormat); + AppSetting.setProperty("part_format", partFormat); } STGroup g = new STGroupString(""); diff --git a/src/main/java/uk/yermak/audiobookconverter/fx/ArtWorkController.java b/src/main/java/uk/yermak/audiobookconverter/fx/ArtWorkController.java index fa6afde7..b4f5b4d0 100644 --- a/src/main/java/uk/yermak/audiobookconverter/fx/ArtWorkController.java +++ b/src/main/java/uk/yermak/audiobookconverter/fx/ArtWorkController.java @@ -44,8 +44,8 @@ private void initialize() { @FXML private void addImage(ActionEvent actionEvent) { FileChooser fileChooser = new FileChooser(); - String sourceFolder = AppProperties.getProperty("source.folder"); - fileChooser.setInitialDirectory(Environment.getInitialDirecotory(sourceFolder)); + String sourceFolder = AppSetting.getProperty("source.folder"); + fileChooser.setInitialDirectory(Platform.getInitialDirecotory(sourceFolder)); fileChooser.setTitle("Select JPG or PNG file"); fileChooser.getExtensionFilters().addAll( new FileChooser.ExtensionFilter("jpg", "*.jpg", "*.jpeg", "*.jfif"), diff --git a/src/main/java/uk/yermak/audiobookconverter/fx/BookInfoController.java b/src/main/java/uk/yermak/audiobookconverter/fx/BookInfoController.java index d808fd77..4020d271 100644 --- a/src/main/java/uk/yermak/audiobookconverter/fx/BookInfoController.java +++ b/src/main/java/uk/yermak/audiobookconverter/fx/BookInfoController.java @@ -11,6 +11,7 @@ import javafx.scene.control.MenuItem; import javafx.scene.control.TextField; import org.apache.commons.lang3.StringUtils; +import uk.yermak.audiobookconverter.AppSetting; import uk.yermak.audiobookconverter.AudioBookInfo; import uk.yermak.audiobookconverter.AudiobookConverter; import uk.yermak.audiobookconverter.MediaInfo; @@ -44,11 +45,15 @@ public class BookInfoController { private void initialize() { MenuItem menuItem = new MenuItem("Remove"); - genre.setItems(AudiobookConverter.getContext().loadGenres()); + + genre.setItems(AppSetting.loadGenres()); menuItem.setOnAction(event -> { - genre.getItems().remove(genre.getSelectionModel().getSelectedIndex()); - AudiobookConverter.getContext().saveGenres(); + String remove = genre.getItems().get(genre.getSelectionModel().getSelectedIndex()); + AppSetting.removeGenre(remove); + genre.setItems(AppSetting.loadGenres()); }); + AudiobookConverter.getContext().addContextDetachListener(observable -> genre.setItems(AppSetting.loadGenres())); + ContextMenu contextMenu = new ContextMenu(menuItem); genre.setOnContextMenuRequested(event -> { diff --git a/src/main/java/uk/yermak/audiobookconverter/fx/ConversionContext.java b/src/main/java/uk/yermak/audiobookconverter/fx/ConversionContext.java index 0e581b26..aa5d8992 100644 --- a/src/main/java/uk/yermak/audiobookconverter/fx/ConversionContext.java +++ b/src/main/java/uk/yermak/audiobookconverter/fx/ConversionContext.java @@ -27,7 +27,8 @@ public class ConversionContext { private boolean paused; private final ObservableList<MediaInfo> selectedMedia = FXCollections.observableArrayList(); - private final GenresManager genresManager = new GenresManager(); + private final ObservableList<String> genres = FXCollections.observableArrayList(); + private final SimpleObjectProperty<AudioBookInfo> bookInfo = new SimpleObjectProperty<>(AudioBookInfo.instance()); private final SimpleObjectProperty<Book> book = new SimpleObjectProperty<>(); @@ -45,15 +46,6 @@ public ConversionContext() { // resetForNewConversion(); } - - public void saveGenres() { - genresManager.saveGenres(conversionGroupHolder.get().getBookInfo()); - } - - public ObservableList<String> loadGenres() { - return genresManager.loadGenres(); - } - public void stopConversions() { conversionQueue.forEach(ConversionJob::stop); } @@ -92,7 +84,7 @@ public ObservableList<MediaInfo> getMedia() { public ConversionGroup detach() { mediaLoader.detach(); - saveGenres(); + ConversionGroup conversionGroup = conversionGroupHolder.get(); conversionGroup.setMedia(new ArrayList<>(media)); @@ -101,6 +93,7 @@ public ConversionGroup detach() { conversionGroup.setBookInfo(bookInfo.get()); conversionGroup.setOutputParameters(new OutputParameters(outputParameters.get())); conversionGroup.setDetached(true); + AppSetting.saveGenres(bookInfo.get().genre().get()); ConversionGroup newConversionGroup = new ConversionGroup(); conversionGroupHolder.set(newConversionGroup); diff --git a/src/main/java/uk/yermak/audiobookconverter/fx/DialogHelper.java b/src/main/java/uk/yermak/audiobookconverter/fx/DialogHelper.java index f43fb4b6..80c56328 100644 --- a/src/main/java/uk/yermak/audiobookconverter/fx/DialogHelper.java +++ b/src/main/java/uk/yermak/audiobookconverter/fx/DialogHelper.java @@ -32,8 +32,8 @@ static String selectOutputFile(AudioBookInfo audioBookInfo) { JfxEnv env = AudiobookConverter.getEnv(); final FileChooser fileChooser = new FileChooser(); - String outputFolder = AppProperties.getProperty("output.folder"); - fileChooser.setInitialDirectory(Environment.getInitialDirecotory(outputFolder)); + String outputFolder = AppSetting.getProperty("output.folder"); + fileChooser.setInitialDirectory(Platform.getInitialDirecotory(outputFolder)); fileChooser.setInitialFileName(Utils.getOuputFilenameSuggestion(audioBookInfo)); fileChooser.setTitle("Save AudioBook"); fileChooser.getExtensionFilters().addAll( @@ -42,15 +42,15 @@ static String selectOutputFile(AudioBookInfo audioBookInfo) { File file = fileChooser.showSaveDialog(env.getWindow()); if (file == null) return null; File parentFolder = file.getParentFile(); - AppProperties.setProperty("output.folder", parentFolder.getAbsolutePath()); + AppSetting.setProperty("output.folder", parentFolder.getAbsolutePath()); return file.getPath(); } public static List<String> selectFilesDialog() { Window window = AudiobookConverter.getEnv().getWindow(); final FileChooser fileChooser = new FileChooser(); - String sourceFolder = AppProperties.getProperty("source.folder"); - fileChooser.setInitialDirectory(Environment.getInitialDirecotory(sourceFolder)); + String sourceFolder = AppSetting.getProperty("source.folder"); + fileChooser.setInitialDirectory(Platform.getInitialDirecotory(sourceFolder)); StringJoiner filetypes = new StringJoiner("/"); Arrays.stream(FILE_EXTENSIONS).map(String::toUpperCase).forEach(filetypes::add); @@ -65,7 +65,7 @@ public static List<String> selectFilesDialog() { if (!files.isEmpty()) { File firstFile = files.get(0); File parentFile = firstFile.getParentFile(); - AppProperties.setProperty("source.folder", parentFile.getAbsolutePath()); + AppSetting.setProperty("source.folder", parentFile.getAbsolutePath()); } return collectFiles(files); } @@ -73,8 +73,8 @@ public static List<String> selectFilesDialog() { public static List<String> selectFolderDialog() { Window window = AudiobookConverter.getEnv().getWindow(); DirectoryChooser directoryChooser = new DirectoryChooser(); - String sourceFolder = AppProperties.getProperty("source.folder"); - directoryChooser.setInitialDirectory(Environment.getInitialDirecotory(sourceFolder)); + String sourceFolder = AppSetting.getProperty("source.folder"); + directoryChooser.setInitialDirectory(Platform.getInitialDirecotory(sourceFolder)); StringJoiner filetypes = new StringJoiner("/"); @@ -84,7 +84,7 @@ public static List<String> selectFolderDialog() { File selectedDirectory = directoryChooser.showDialog(window); if (selectedDirectory == null) return null; - AppProperties.setProperty("source.folder", selectedDirectory.getAbsolutePath()); + AppSetting.setProperty("source.folder", selectedDirectory.getAbsolutePath()); return collectFiles(Collections.singleton(selectedDirectory)); } diff --git a/src/main/java/uk/yermak/audiobookconverter/fx/OutputController.java b/src/main/java/uk/yermak/audiobookconverter/fx/OutputController.java index 18075e95..f2d1b804 100644 --- a/src/main/java/uk/yermak/audiobookconverter/fx/OutputController.java +++ b/src/main/java/uk/yermak/audiobookconverter/fx/OutputController.java @@ -2,8 +2,6 @@ import javafx.application.Platform; import javafx.beans.InvalidationListener; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.fxml.FXML; @@ -112,16 +110,18 @@ private void initialize() { // String savedPreset = Objects.requireNonNullElse(AppProperties.getProperty("last.preset"), "custom"); // Preset lastPreset = presets.stream().filter(preset -> preset.getPresetName().equals(Preset.LAST_USED)).findFirst().get(); - presetBox.getItems().addAll(presets.stream().map(Preset::getName).collect(Collectors.toList())); + presetBox.getItems().addAll(presets.stream().map(Preset::getName).toList()); presetBox.getSelectionModel().select(Preset.DEFAULT); presetBox.getSelectionModel().selectedItemProperty().addListener((observableValue, oldValue, newValue) -> { if (!presetBox.getItems().contains(newValue)) { presetBox.getItems().add(newValue); Preset preset = Preset.copy(newValue, Preset.instance(oldValue)); + AppSetting.savePreset(preset); AudiobookConverter.getContext().setOutputParameters(preset); } else { Preset preset = Preset.instance(newValue); + AppSetting.savePreset(preset); AudiobookConverter.getContext().setOutputParameters(preset); } });