Fix music player can't load demo files from jrt #61

This commit is contained in:
mkpaz 2023-06-17 14:23:40 +04:00
parent 47bbf9d97e
commit 0e6987d4c7
6 changed files with 44 additions and 14 deletions

@ -247,7 +247,7 @@
<configuration> <configuration>
<toolName>jlink</toolName> <toolName>jlink</toolName>
<addModules> <addModules>
java.base,java.logging,jdk.localedata,java.desktop,java.prefs,javafx.controls,javafx.fxml,javafx.swing,javafx.web java.base,java.logging,jdk.localedata,jdk.zipfs,java.desktop,java.prefs,javafx.controls,javafx.fxml,javafx.swing,javafx.web
</addModules> </addModules>
<modulePath>${build.platformModulesDir}</modulePath> <modulePath>${build.platformModulesDir}</modulePath>
<output>${build.package.runtimeImageDir}</output> <output>${build.package.runtimeImageDir}</output>

@ -8,7 +8,7 @@ import static atlantafx.sampler.page.showcase.musicplayer.MediaFile.Metadata.NO_
import static atlantafx.sampler.page.showcase.musicplayer.Utils.copyImage; import static atlantafx.sampler.page.showcase.musicplayer.Utils.copyImage;
import atlantafx.sampler.Resources; import atlantafx.sampler.Resources;
import java.io.File; import java.nio.file.Path;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -17,7 +17,7 @@ import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer; import javafx.scene.media.MediaPlayer;
@SuppressWarnings("StringOperationCanBeSimplified") @SuppressWarnings("StringOperationCanBeSimplified")
record MediaFile(File file) { record MediaFile(Path path) {
private static final Map<String, Metadata> METADATA_CACHE = new HashMap<>(); private static final Map<String, Metadata> METADATA_CACHE = new HashMap<>();
@ -25,7 +25,7 @@ record MediaFile(File file) {
// media file metadata you have to load it to media player instance, which // media file metadata you have to load it to media player instance, which
// is costly and that instance is not even reusable. // is costly and that instance is not even reusable.
public void readMetadata(Consumer<Metadata> callback) { public void readMetadata(Consumer<Metadata> callback) {
var media = new Media(file.toURI().toString()); var media = new Media(path.toUri().toString());
var mediaPlayer = new MediaPlayer(media); var mediaPlayer = new MediaPlayer(media);
// The media information is obtained asynchronously and so not necessarily // The media information is obtained asynchronously and so not necessarily
@ -34,7 +34,7 @@ record MediaFile(File file) {
// MediaPlayer and that player has transitioned to Status.READY status. // MediaPlayer and that player has transitioned to Status.READY status.
mediaPlayer.setOnReady(() -> { mediaPlayer.setOnReady(() -> {
Map<String, Object> metadata = media.getMetadata(); Map<String, Object> metadata = media.getMetadata();
callback.accept(METADATA_CACHE.computeIfAbsent(file.getAbsolutePath(), k -> { callback.accept(METADATA_CACHE.computeIfAbsent(path.toAbsolutePath().toString(), k -> {
var image = getTag(metadata, "image", Image.class, null); var image = getTag(metadata, "image", Image.class, null);
// clone everything to make sure media player will be garbage collected // clone everything to make sure media player will be garbage collected
return new Metadata( return new Metadata(
@ -51,7 +51,7 @@ record MediaFile(File file) {
} }
public Media createMedia() { public Media createMedia() {
return new Media(file.toURI().toString()); return new Media(path.toUri().toString());
} }
private <T> T getTag(Map<String, Object> metadata, String key, Class<T> type, T defaultValue) { private <T> T getTag(Map<String, Object> metadata, String key, Class<T> type, T defaultValue) {

@ -2,10 +2,16 @@
package atlantafx.sampler.page.showcase.musicplayer; package atlantafx.sampler.page.showcase.musicplayer;
import atlantafx.sampler.Launcher;
import atlantafx.sampler.Resources; import atlantafx.sampler.Resources;
import java.io.File; import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.property.ReadOnlyBooleanProperty;
@ -18,10 +24,32 @@ import javafx.scene.paint.Color;
final class Model { final class Model {
private static final List<File> DEMO_FILES = List.of( private static final List<Path> DEMO_FILES = getDemoFiles();
Paths.get(Resources.getResource("media/Beat Thee.mp3")).toFile(),
Paths.get(Resources.getResource("media/Study and Relax.mp3")).toFile() private static List<Path> getDemoFiles() {
// for the runtime image as it won't create zipfs automatically
URL media = Launcher.class.getResource(Resources.MODULE_DIR + "media");
if (media != null && media.toString().startsWith("jar")) {
try {
try (var fs = FileSystems.newFileSystem(
media.toURI(),
Map.of("create", "true")
)) {
return List.of(
fs.getPath(Resources.MODULE_DIR + "media/Beat Thee.mp3"),
fs.getPath(Resources.MODULE_DIR + "media/Study and Relax.mp3")
); );
}
} catch (URISyntaxException | IOException e) {
throw new RuntimeException(e);
}
}
return List.of(
Paths.get(Resources.getResource("media/Beat Thee.mp3")),
Paths.get(Resources.getResource("media/Study and Relax.mp3"))
);
}
private final ObservableList<MediaFile> playlist = FXCollections.observableArrayList(); private final ObservableList<MediaFile> playlist = FXCollections.observableArrayList();
private final ReadOnlyBooleanWrapper canGoBack = new ReadOnlyBooleanWrapper(); private final ReadOnlyBooleanWrapper canGoBack = new ReadOnlyBooleanWrapper();

@ -135,7 +135,7 @@ final class PlaylistPane extends VBox {
public Void call() throws InterruptedException { public Void call() throws InterruptedException {
for (File file : files) { for (File file : files) {
Thread.sleep(500); // add artificial delay to demonstrate progress bar Thread.sleep(500); // add artificial delay to demonstrate progress bar
Platform.runLater(() -> model.addFile(new MediaFile(file))); Platform.runLater(() -> model.addFile(new MediaFile(file.toPath())));
progress++; progress++;
updateProgress(progress, files.size()); updateProgress(progress, files.size());
} }

@ -86,7 +86,7 @@ final class StartScreen extends BorderPane {
} }
for (File file : files) { for (File file : files) {
model.addFile(new MediaFile(file)); model.addFile(new MediaFile(file.toPath()));
} }
} }
@ -108,7 +108,7 @@ final class StartScreen extends BorderPane {
if (!p.toAbsolutePath().toString().endsWith(s)) { if (!p.toAbsolutePath().toString().endsWith(s)) {
continue; continue;
} }
model.addFile(new MediaFile(p.toFile())); model.addFile(new MediaFile(p));
} }
}); });
} catch (Exception e) { } catch (Exception e) {

@ -10,6 +10,7 @@ module atlantafx.sampler {
requires javafx.media; requires javafx.media;
requires javafx.web; requires javafx.web;
requires javafx.fxml; requires javafx.fxml;
requires jdk.zipfs;
requires org.kordamp.ikonli.core; requires org.kordamp.ikonli.core;
requires org.kordamp.ikonli.javafx; requires org.kordamp.ikonli.javafx;
@ -39,6 +40,7 @@ module atlantafx.sampler {
opens atlantafx.sampler.assets.styles; opens atlantafx.sampler.assets.styles;
opens atlantafx.sampler.images; opens atlantafx.sampler.images;
opens atlantafx.sampler.images.modena; opens atlantafx.sampler.images.modena;
opens atlantafx.sampler.media;
opens atlantafx.sampler.page.general; opens atlantafx.sampler.page.general;
opens atlantafx.sampler.page.showcase; opens atlantafx.sampler.page.showcase;
} }