From e89cad31ef86d7bbf3458a10cbc6ff3a0b594ce2 Mon Sep 17 00:00:00 2001 From: Dmitry Isaenko Date: Sun, 12 Sep 2021 16:32:55 +0300 Subject: [PATCH] Drafting JNI for mpv API. Refactoring & code cleanup. --- mpv_library/Makefile | 37 +++++ mpv_library/mplayer4anime_mpv_MpvSlave.h | 21 +++ mpv_library/mpvjni.c | 6 + .../java/mplayer4anime/AppPreferences.java | 3 + src/main/java/mplayer4anime/Controller.java | 109 +++++++++------ .../java/mplayer4anime/IMediatorContol.java | 6 - .../IPC/ServerSocketProvider.java | 23 ++- .../IPC/SingleInstanceHandler.java | 15 +- .../ISlaveModeAppOrchestration.java | 22 ++- .../java/mplayer4anime/MediatorControl.java | 4 +- .../mplayer4anime/Playlists/Playlists.java | 132 ++++++++++-------- .../java/mplayer4anime/ServiceWindow.java | 9 +- .../Settings/SettingsController.java | 5 + .../appPanes/ControllerPane.java | 1 + .../{ => mplayer}/LineRedirecter.java | 2 +- .../{ => mplayer}/MplayerSlave.java | 23 +-- .../mpv/MpvJniLibraryLoader.java | 108 ++++++++++++++ src/main/java/mplayer4anime/mpv/MpvSlave.java | 96 +++++++++++++ .../resources/Settings/SettingsLayout.fxml | 7 + src/main/resources/locale.properties | 1 + src/main/resources/locale_rus.properties | 1 + .../resources/native/linux/amd64/mpvjni.so | Bin 0 -> 14760 bytes src/main/resources/native/linux/x86/mpvjni.so | Bin 0 -> 14092 bytes 23 files changed, 500 insertions(+), 131 deletions(-) create mode 100644 mpv_library/Makefile create mode 100644 mpv_library/mplayer4anime_mpv_MpvSlave.h create mode 100644 mpv_library/mpvjni.c delete mode 100644 src/main/java/mplayer4anime/IMediatorContol.java rename src/main/java/mplayer4anime/{ => mplayer}/LineRedirecter.java (97%) rename src/main/java/mplayer4anime/{ => mplayer}/MplayerSlave.java (96%) create mode 100644 src/main/java/mplayer4anime/mpv/MpvJniLibraryLoader.java create mode 100644 src/main/java/mplayer4anime/mpv/MpvSlave.java create mode 100755 src/main/resources/native/linux/amd64/mpvjni.so create mode 100755 src/main/resources/native/linux/x86/mpvjni.so diff --git a/mpv_library/Makefile b/mpv_library/Makefile new file mode 100644 index 0000000..2dccfb8 --- /dev/null +++ b/mpv_library/Makefile @@ -0,0 +1,37 @@ +# Compiler +CC=gcc +# Flags +CFLAGS=-O2 +MKDIR_P = mkdir -p +APP_NAME = mpvjni + +all: x86 amd64 + +x86: + $(MKDIR_P) ./x86 + $(CC) ${CFLAGS} -m32 -c -fPIC -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/linux" ${APP_NAME}.c -o ${APP_NAME}_x86.o + $(CC) ${CFLAGS} -m32 -shared -fPIC -o ./x86/${APP_NAME}.so ${APP_NAME}_x86.o -lc + +amd64: + $(MKDIR_P) ./amd64 + $(CC) ${CFLAGS} -m64 -c -fPIC -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/linux" ${APP_NAME}.c -o ${APP_NAME}_amd64.o + $(CC) ${CFLAGS} -m64 -shared -fPIC -o ./amd64/${APP_NAME}.so ${APP_NAME}_amd64.o -lc + +clean: + rm -rf \ + ${APP_NAME}_amd64.o \ + ${APP_NAME}_x86.o \ + ./x86 \ + ./amd64 + +headers: + cd /src/main/java + javac mplayer4anime/mpv/MpvJni.java -h ../../../mpv_library/ + +install: x86 amd64 + install ./x86/${APP_NAME}.so ../src/main/resources/native/linux/x86/ + install ./amd64/${APP_NAME}.so ../src/main/resources/native/linux/amd64/ + +uninstall: + rm ../src/main/resources/native/linux/x86/${APP_NAME}.so + rm ../src/main/resources/native/linux/amd64/${APP_NAME}.so diff --git a/mpv_library/mplayer4anime_mpv_MpvSlave.h b/mpv_library/mplayer4anime_mpv_MpvSlave.h new file mode 100644 index 0000000..9c9fbbe --- /dev/null +++ b/mpv_library/mplayer4anime_mpv_MpvSlave.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class mplayer4anime_mpv_MpvSlave */ + +#ifndef _Included_mplayer4anime_mpv_MpvSlave +#define _Included_mplayer4anime_mpv_MpvSlave +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: mplayer4anime_mpv_MpvSlave + * Method: play + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_mplayer4anime_mpv_MpvSlave_play + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/mpv_library/mpvjni.c b/mpv_library/mpvjni.c new file mode 100644 index 0000000..f3e3b1c --- /dev/null +++ b/mpv_library/mpvjni.c @@ -0,0 +1,6 @@ +#include +#include "mplayer4anime_mpv_MpvSlave.h" + +JNIEXPORT void JNICALL Java_mplayer4anime_mpv_MpvSlave_play(JNIEnv * jnienv, jobject jobject){ + +}; \ No newline at end of file diff --git a/src/main/java/mplayer4anime/AppPreferences.java b/src/main/java/mplayer4anime/AppPreferences.java index 47d54db..8ab3e07 100644 --- a/src/main/java/mplayer4anime/AppPreferences.java +++ b/src/main/java/mplayer4anime/AppPreferences.java @@ -122,4 +122,7 @@ public class AppPreferences { public double getSceneHeight(){ return preferences.getDouble("window_height", 800.0); } public void setSceneHeight(double value){ preferences.putDouble("window_height", value); } + + public int getBackendEngineIndexId(){ return preferences.getInt("backend_player", 0); } + public void setBackendEngineIndexId(int value){ preferences.putInt("backend_player", value); } } diff --git a/src/main/java/mplayer4anime/Controller.java b/src/main/java/mplayer4anime/Controller.java index eaec6ba..bcc90af 100644 --- a/src/main/java/mplayer4anime/Controller.java +++ b/src/main/java/mplayer4anime/Controller.java @@ -32,6 +32,8 @@ import mplayer4anime.Playlists.Playlists; import mplayer4anime.Settings.SettingsWindow; import mplayer4anime.appPanes.ControllerPane; import mplayer4anime.appPanes.ControllerSUB; +import mplayer4anime.mplayer.MplayerSlave; +import mplayer4anime.mpv.MpvSlave; import java.io.*; import java.net.URL; @@ -56,12 +58,10 @@ public class Controller implements Initializable { private final AppPreferences appPreferences = AppPreferences.getINSTANCE(); private ResourceBundle resourceBundle; - // Get host services for opening URLs etc. private HostServices hostServices; - private String currentPlaylistLocation; - - private MplayerSlave mplayer; + private String backend; + private ISlaveModeAppOrchestration player; // If application started with playlist passed as an argument, then we'll try to load it (if it's valid). public void setPlaylistAsArgument(String playlist) { @@ -96,8 +96,14 @@ public class Controller implements Initializable { continue; addRecentlyOpened(recentPlaylists[i]); } - - mplayer = new MplayerSlave(resourceBundle); + if (appPreferences.getBackendEngineIndexId() == 0) { + backend = "mplayer"; + player = new MplayerSlave(resourceBundle); + } + else { + backend = "mpv"; + player = new MpvSlave(resourceBundle); + } } void setHostServices(HostServices hostServices) { @@ -126,11 +132,15 @@ public class Controller implements Initializable { } @FXML - private void infoBtn(){ new AboutWindow(this.hostServices); } // TODO: fix this shit with hostSerivces that doesn't work @ linux + private void infoBtn(){ + new AboutWindow(this.hostServices); + } // TODO: fix this shit with hostSerivces that doesn't work @ linux /** SETTINGS HANDLE */ @FXML - private void settingsBtn(){ new SettingsWindow(); } + private void settingsBtn(){ + new SettingsWindow(); + } // Get event that notify application in case some settings has been changed // This function called from MediatorControl after mediator receives request form SettingsController indicating that user updated some required fields. void updateAfterSettingsChanged(){ @@ -138,6 +148,18 @@ public class Controller implements Initializable { subPaneController.setEncoding(appPreferences.getSubsEncodingList(), null); // In case of application failure should be better to save this immediately appPreferences.setLastTimeUsedSubsEncoding(subPaneController.getSelectedEncoding()); + switchBackend(appPreferences.getBackendEngineIndexId()); + } + private void switchBackend(int newBackEndId){ + if (newBackEndId == 0 && backend.equals("mpv")){ + backend = "mplayer"; + player = new MplayerSlave(resourceBundle); + return; + } + if (newBackEndId == 1 && backend.equals("mplayer")){ + backend = "mpv"; + player = new MpvSlave(resourceBundle); + } } @FXML @@ -147,44 +169,51 @@ public class Controller implements Initializable { } private void setAllLists(JsonStorage jsonStorage){ if (jsonStorage != null) { - mkvPaneController.cleanList(); - mkaPaneController.cleanList(); - subPaneController.cleanList(); mkvPaneController.setFilesFromList(jsonStorage.getVideo()); mkaPaneController.setFilesFromList(jsonStorage.getAudio()); subPaneController.setFilesFromList(jsonStorage.getSubs()); subPaneController.selectEncodingValue(jsonStorage.getSubEncoding(), appPreferences); - currentPlaylistLocation = Playlists.getPlaylistLocation(); // TODO: Implement listener? mmm... - //System.out.println(currentPlaylistLocation); + currentPlaylistLocation = Playlists.getPlaylistLocation(); // TODO: Implement listener? mmm... statusLbl.setText(currentPlaylistLocation); addRecentlyOpened(currentPlaylistLocation); } } @FXML private void saveBtn() { - if (mkvPaneController.getElementsCount() == 0) - ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), resourceBundle.getString("ErrorUnableToSaveEmptyPlaylist")); - else { - JsonStorage jsonStorage = new JsonStorage(mkvPaneController.getElementsAll(), mkaPaneController.getElementsAll(), subPaneController.getElementsAll(), subPaneController.getSelectedEncoding()); - if (Playlists.SaveCurrent(resourceBundle, jsonStorage)) { - this.currentPlaylistLocation = Playlists.getPlaylistLocation(); - this.statusLbl.setText(currentPlaylistLocation); //TODO: update header of the application to include this? - addRecentlyOpened(currentPlaylistLocation); - } + if (mkvPaneController.getElementsCount() == 0) { + ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), + resourceBundle.getString("ErrorUnableToSaveEmptyPlaylist")); + return; + } + JsonStorage jsonStorage = new JsonStorage( + mkvPaneController.getElementsAll(), + mkaPaneController.getElementsAll(), + subPaneController.getElementsAll(), + subPaneController.getSelectedEncoding()); + if (Playlists.SaveCurrent(resourceBundle, jsonStorage)) { + this.currentPlaylistLocation = Playlists.getPlaylistLocation(); + this.statusLbl.setText(currentPlaylistLocation); //TODO: update header of the application to include this? + addRecentlyOpened(currentPlaylistLocation); } } @FXML private void saveAsBtn() { - if (mkvPaneController.getElementsCount() == 0) - ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), resourceBundle.getString("ErrorUnableToSaveEmptyPlaylist")); - else { - JsonStorage jsonStorage = new JsonStorage(mkvPaneController.getElementsAll(), mkaPaneController.getElementsAll(), subPaneController.getElementsAll(), subPaneController.getSelectedEncoding()); - if (Playlists.SaveAs(resourceBundle, jsonStorage)) { - this.currentPlaylistLocation = Playlists.getPlaylistLocation(); - this.statusLbl.setText(currentPlaylistLocation); //TODO: update header of the application to include this? - addRecentlyOpened(currentPlaylistLocation); - } + if (mkvPaneController.getElementsCount() == 0) { + ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), + resourceBundle.getString("ErrorUnableToSaveEmptyPlaylist")); + return; + } + + JsonStorage jsonStorage = new JsonStorage( + mkvPaneController.getElementsAll(), + mkaPaneController.getElementsAll(), + subPaneController.getElementsAll(), + subPaneController.getSelectedEncoding()); + if (Playlists.SaveAs(resourceBundle, jsonStorage)) { + this.currentPlaylistLocation = Playlists.getPlaylistLocation(); + this.statusLbl.setText(currentPlaylistLocation); //TODO: update header of the application to include this? + addRecentlyOpened(currentPlaylistLocation); } } @FXML @@ -223,15 +252,15 @@ public class Controller implements Initializable { /* PLAYER */ @FXML private void subsTriggerBtn(){ - mplayer.subtitlesSwitch(); + player.subtitlesSwitch(); } @FXML private void fullscreenBtn(){ - mplayer.fullscreenSwitch(); + player.fullscreenSwitch(); } @FXML private void muteBtn(){ - mplayer.mute(); + player.mute(); } @FXML private void playPrevTrackBtn(){ @@ -240,7 +269,7 @@ public class Controller implements Initializable { return; mkvPaneController.setElementSelectedByIndex(index-1); - mplayer.forcePlay(appPreferences.getPath(), + player.forcePlay(appPreferences.getPath(), mkvPaneController.getElementSelected(), mkaPaneController.getElementSelected(), subPaneController.getElementSelected(), @@ -265,7 +294,7 @@ public class Controller implements Initializable { subPaneController.setElementSelectedByIndex(index + 1); } - mplayer.forcePlay(appPreferences.getPath(), + player.forcePlay(appPreferences.getPath(), mkvPaneController.getElementSelected(), mkaPaneController.getElementSelected(), subPaneController.getElementSelected(), @@ -279,7 +308,7 @@ public class Controller implements Initializable { if (mkvPaneController.getElementSelected() == null) return; - mplayer.playPause(appPreferences.getPath(), + player.playPause(appPreferences.getPath(), mkvPaneController.getElementSelected(), mkaPaneController.getElementSelected(), subPaneController.getElementSelected(), @@ -290,15 +319,15 @@ public class Controller implements Initializable { } @FXML private void stopBtn(){ - mplayer.stop(); + player.stop(); } @FXML private void volumeUpBtn(){ - mplayer.volumeUp(); + player.volumeUp(); } @FXML private void volumeDownBtn(){ - mplayer.volumeDown(); + player.volumeDown(); } } diff --git a/src/main/java/mplayer4anime/IMediatorContol.java b/src/main/java/mplayer4anime/IMediatorContol.java deleted file mode 100644 index 584cf96..0000000 --- a/src/main/java/mplayer4anime/IMediatorContol.java +++ /dev/null @@ -1,6 +0,0 @@ -package mplayer4anime; - -public interface IMediatorContol { - void registerMainController(mplayer4anime.Controller mc); - void sentUpdates(); -} diff --git a/src/main/java/mplayer4anime/IPC/ServerSocketProvider.java b/src/main/java/mplayer4anime/IPC/ServerSocketProvider.java index 5ee1142..73a389b 100644 --- a/src/main/java/mplayer4anime/IPC/ServerSocketProvider.java +++ b/src/main/java/mplayer4anime/IPC/ServerSocketProvider.java @@ -1,3 +1,21 @@ +/* + Copyright 2018-2021 Dmitry Isaenko + + This file is part of mplayer4anime. + + mplayer4anime is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + mplayer4anime is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with mplayer4anime. If not, see . + */ package mplayer4anime.IPC; import javafx.application.Platform; @@ -11,8 +29,8 @@ import java.net.Socket; class ServerSocketProvider implements Runnable{ - private ServerSocket serverSocket; - private Controller controller; + private final ServerSocket serverSocket; + private final Controller controller; ServerSocketProvider(Controller mainCntrl, ServerSocket srvSock){ this.serverSocket = srvSock; @@ -42,6 +60,7 @@ class ServerSocketProvider implements Runnable{ } } catch (IOException ex){ + ex.printStackTrace(); System.out.println("Socket has been closed."); } } diff --git a/src/main/java/mplayer4anime/IPC/SingleInstanceHandler.java b/src/main/java/mplayer4anime/IPC/SingleInstanceHandler.java index 2ddecac..17bcd30 100644 --- a/src/main/java/mplayer4anime/IPC/SingleInstanceHandler.java +++ b/src/main/java/mplayer4anime/IPC/SingleInstanceHandler.java @@ -7,6 +7,7 @@ import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; +// TODO: Rewrite and remove. Or just remove. public class SingleInstanceHandler implements Runnable{ private ServerSocket servSock; @@ -41,15 +42,9 @@ public class SingleInstanceHandler implements Runnable{ @Override public void run() { - while (true) { - if ( Thread.currentThread().isInterrupted() ){ - try { - servSock.close(); - } catch (IOException e) { - System.out.println("Internal issue: unable to create client socket."); - } - break; - } - } + while (! Thread.currentThread().isInterrupted()); + try { + servSock.close(); + } catch (IOException ignore) {} } } \ No newline at end of file diff --git a/src/main/java/mplayer4anime/ISlaveModeAppOrchestration.java b/src/main/java/mplayer4anime/ISlaveModeAppOrchestration.java index 463e840..fe830a0 100644 --- a/src/main/java/mplayer4anime/ISlaveModeAppOrchestration.java +++ b/src/main/java/mplayer4anime/ISlaveModeAppOrchestration.java @@ -19,5 +19,25 @@ package mplayer4anime; public interface ISlaveModeAppOrchestration { - // TODO: implement unified interface for mplayer and mpv + void subtitlesSwitch(); + void fullscreenSwitch(); + void mute(); + void forcePlay(String mplayerPath, + String VideoFile, + String AudioFile, + String SubtitlesFile, + String subtitlesEncoding, + boolean subtitlesHidden, + boolean isFullscreen); + boolean pause(); + void playPause(String mplayerPath, + String VideoFile, + String AudioFile, + String SubtitlesFile, + String subtitlesEncoding, + boolean subtitlesHidden, + boolean isFullscreen); + void stop(); + void volumeUp(); + void volumeDown(); } diff --git a/src/main/java/mplayer4anime/MediatorControl.java b/src/main/java/mplayer4anime/MediatorControl.java index b9d9e51..783e397 100644 --- a/src/main/java/mplayer4anime/MediatorControl.java +++ b/src/main/java/mplayer4anime/MediatorControl.java @@ -1,14 +1,12 @@ package mplayer4anime; -public class MediatorControl implements IMediatorContol{ +public class MediatorControl{ private Controller mainController; - @Override public void registerMainController(Controller mc) { mainController = mc; } - @Override public void sentUpdates() { mainController.updateAfterSettingsChanged(); } diff --git a/src/main/java/mplayer4anime/Playlists/Playlists.java b/src/main/java/mplayer4anime/Playlists/Playlists.java index 32a4392..20f881b 100644 --- a/src/main/java/mplayer4anime/Playlists/Playlists.java +++ b/src/main/java/mplayer4anime/Playlists/Playlists.java @@ -1,3 +1,21 @@ +/* + Copyright 2018-2021 Dmitry Isaenko + + This file is part of mplayer4anime. + + mplayer4anime is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + mplayer4anime is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with mplayer4anime. If not, see . + */ package mplayer4anime.Playlists; import com.google.gson.*; @@ -9,12 +27,10 @@ import java.nio.charset.StandardCharsets; import java.util.ResourceBundle; public class Playlists { - private static String playlistLocation; + //TODO: Show popUp if unable to write! Or nothing to write! Or overwrite! - /** - * Interface for Save As functionality - * */ + //TODO: Disable 'Save' button if no files added public static boolean SaveAs(ResourceBundle resourceBundle, JsonStorage jStorage){ File playlistFile; FileChooser fileChooser = new FileChooser(); @@ -27,48 +43,50 @@ public class Playlists { return writeFile(resourceBundle, playlistFile, jStorage); } - /** - * Interface for Save functionality - * */ + public static boolean SaveCurrent(ResourceBundle resourceBundle, JsonStorage jStorage) { if (playlistLocation == null || playlistLocation.equals("")){ return Playlists.SaveAs(resourceBundle, jStorage); } - else { - return writeFile(resourceBundle, new File(playlistLocation), jStorage); - } + return writeFile(resourceBundle, new File(playlistLocation), jStorage); } - // Working with file itself + /** + * @return true for success, false for failure + * */ private static boolean writeFile(ResourceBundle resourceBundle, File playlistFile, JsonStorage jStorage){ - // TODO: Add 'Override pop-up notification!' - if (playlistFile != null) { - if (!playlistFile.getAbsolutePath().endsWith(".alpr")) { - playlistFile = new File(playlistFile.getAbsolutePath() + ".alpr"); - } - try (Writer writer = new OutputStreamWriter(new FileOutputStream(playlistFile.getAbsolutePath()), StandardCharsets.UTF_8)) - { - Gson jsonObject = new GsonBuilder().setPrettyPrinting().create(); - jsonObject.toJson(jStorage, writer); - writer.close(); - - playlistLocation = playlistFile.getAbsolutePath(); - // Return success notification - return true; - - } catch (java.io.FileNotFoundException e){ - ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), resourceBundle.getString("ErrorFileNotFound")); - } catch (java.io.UnsupportedEncodingException e){ - ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), resourceBundle.getString("ErrorOnSaveIncorrectEncoding")); - } catch (java.io.IOException e){ - ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), resourceBundle.getString("ErrorOnSaveIOProblem")); - } + if (playlistFile == null) { + ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), + "Unable to save: File not selected");// TODO: translate return false; } - else { - System.out.println("Unable to save: File not selected"); - return false; + + if (!playlistFile.getAbsolutePath().endsWith(".alpr")) { + playlistFile = new File(playlistFile.getAbsolutePath() + ".alpr"); } + + try (Writer writer = new OutputStreamWriter( + new FileOutputStream(playlistFile.getAbsolutePath()), StandardCharsets.UTF_8)) + { + Gson jsonObject = new GsonBuilder().setPrettyPrinting().create(); + jsonObject.toJson(jStorage, writer); + writer.close(); + + playlistLocation = playlistFile.getAbsolutePath(); + + return true; + + } catch (java.io.FileNotFoundException e){ + ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), + resourceBundle.getString("ErrorFileNotFound")); + } catch (java.io.UnsupportedEncodingException e){ + ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), + resourceBundle.getString("ErrorOnSaveIncorrectEncoding")); + } catch (java.io.IOException e){ + ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), + resourceBundle.getString("ErrorOnSaveIOProblem")); + } + return false; } /** * Interface for Opening playlists via FileChooser @@ -89,29 +107,29 @@ public class Playlists { * Interface for Opening playlists using file itself * */ public static JsonStorage ReadByPath(ResourceBundle resourceBundle, File playlistFile){ - if (playlistFile != null) { - try (Reader reader = new InputStreamReader(new FileInputStream(playlistFile))) { - JsonStorage jStorage = new Gson().fromJson(reader, JsonStorage.class); - if (jStorage != null){ - playlistLocation = playlistFile.getAbsolutePath(); - //System.out.println("FILE:|"+playlistLocation+"|"); - return jStorage; - } - else - return null; - } catch (java.io.FileNotFoundException e){ - ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), resourceBundle.getString("ErrorFileNotFound")); - } catch (com.google.gson.JsonSyntaxException e){ - ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), resourceBundle.getString("ErrorOnOpenIncorrectFormatOfFile")); - } catch (java.io.IOException e){ - ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), resourceBundle.getString("ErrorOnOpenIOProblem")); + if (playlistFile == null) { + ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), + "Playlist file not selected");// TODO: translate + return null; + } + + try (Reader reader = new InputStreamReader(new FileInputStream(playlistFile))) { + JsonStorage jStorage = new Gson().fromJson(reader, JsonStorage.class); + if (jStorage != null){ + playlistLocation = playlistFile.getAbsolutePath(); + return jStorage; } - return null; - } - else { - System.out.println("Playlist file not selected"); - return null; + } catch (java.io.FileNotFoundException e){ + ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), + resourceBundle.getString("ErrorFileNotFound")); + } catch (com.google.gson.JsonSyntaxException e){ + ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), + resourceBundle.getString("ErrorOnOpenIncorrectFormatOfFile")); + } catch (java.io.IOException e){ + ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), + resourceBundle.getString("ErrorOnOpenIOProblem")); } + return null; } /** Return path to file opened */ diff --git a/src/main/java/mplayer4anime/ServiceWindow.java b/src/main/java/mplayer4anime/ServiceWindow.java index 7e42bbe..644f537 100644 --- a/src/main/java/mplayer4anime/ServiceWindow.java +++ b/src/main/java/mplayer4anime/ServiceWindow.java @@ -20,6 +20,7 @@ package mplayer4anime; import javafx.scene.control.Alert; import javafx.scene.layout.Region; +import javafx.stage.Stage; /** * Creates window with notification @@ -30,7 +31,13 @@ public class ServiceWindow { alertBox.setTitle(title); alertBox.setHeaderText(null); alertBox.setContentText(body); - alertBox.getDialogPane().setMinHeight(Region.USE_PREF_SIZE); // Java bug workaround for linux + alertBox.getDialogPane().setMinWidth(Region.USE_PREF_SIZE); + alertBox.getDialogPane().setMinHeight(Region.USE_PREF_SIZE); + alertBox.setResizable(true); alertBox.show(); + + Stage dialogStage = (Stage) alertBox.getDialogPane().getScene().getWindow(); + dialogStage.setAlwaysOnTop(true); + dialogStage.toFront(); } } diff --git a/src/main/java/mplayer4anime/Settings/SettingsController.java b/src/main/java/mplayer4anime/Settings/SettingsController.java index 5600412..404dca4 100644 --- a/src/main/java/mplayer4anime/Settings/SettingsController.java +++ b/src/main/java/mplayer4anime/Settings/SettingsController.java @@ -42,6 +42,8 @@ public class SettingsController implements Initializable { private Label pathToMplayerLbl; @FXML private CheckBox subtitlesFirstCheckBox; + @FXML + private ChoiceBox backEndEngineChoiceBox; @Override public void initialize(URL url, ResourceBundle resBundle) { @@ -55,6 +57,8 @@ public class SettingsController implements Initializable { subEncodingListController.setList(appPreferences.getSubsEncodingList(), false); videoExtensionListController.setList(appPreferences.getVideoExtensionsList(), true); audioExtensionListController.setList(appPreferences.getAudioExtensionsList(), true); + backEndEngineChoiceBox.getItems().addAll("mplayer", "mpv"); + backEndEngineChoiceBox.getSelectionModel().select(appPreferences.getBackendEngineIndexId()); } @FXML @@ -103,6 +107,7 @@ public class SettingsController implements Initializable { appPreferences.setSubsEncodingList(subEncodingListController.getList()); appPreferences.setVideoExtensionsList(videoExtensionListController.getList()); appPreferences.setAudioExtensionsList(audioExtensionListController.getList()); + appPreferences.setBackendEngineIndexId(backEndEngineChoiceBox.getSelectionModel().getSelectedIndex()); MediatorControl.getInstance().sentUpdates(); // TODO: implement list to track what should be updated } diff --git a/src/main/java/mplayer4anime/appPanes/ControllerPane.java b/src/main/java/mplayer4anime/appPanes/ControllerPane.java index 0416fe3..2e1cc29 100644 --- a/src/main/java/mplayer4anime/appPanes/ControllerPane.java +++ b/src/main/java/mplayer4anime/appPanes/ControllerPane.java @@ -238,6 +238,7 @@ public class ControllerPane implements Initializable { * Set files using lists. Used if playlist loaded * */ public void setFilesFromList(String[] fileLocations){ + cleanList(); if (fileLocations != null && fileLocations.length != 0) { File[] files = new File[fileLocations.length]; for (int i=0; i < fileLocations.length; i++) diff --git a/src/main/java/mplayer4anime/LineRedirecter.java b/src/main/java/mplayer4anime/mplayer/LineRedirecter.java similarity index 97% rename from src/main/java/mplayer4anime/LineRedirecter.java rename to src/main/java/mplayer4anime/mplayer/LineRedirecter.java index 4867d69..e5c9467 100644 --- a/src/main/java/mplayer4anime/LineRedirecter.java +++ b/src/main/java/mplayer4anime/mplayer/LineRedirecter.java @@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License along with mplayer4anime. If not, see . */ -package mplayer4anime; +package mplayer4anime.mplayer; import java.io.*; diff --git a/src/main/java/mplayer4anime/MplayerSlave.java b/src/main/java/mplayer4anime/mplayer/MplayerSlave.java similarity index 96% rename from src/main/java/mplayer4anime/MplayerSlave.java rename to src/main/java/mplayer4anime/mplayer/MplayerSlave.java index c552baa..5a7c653 100644 --- a/src/main/java/mplayer4anime/MplayerSlave.java +++ b/src/main/java/mplayer4anime/mplayer/MplayerSlave.java @@ -16,7 +16,10 @@ You should have received a copy of the GNU General Public License along with mplayer4anime. If not, see . */ -package mplayer4anime; +package mplayer4anime.mplayer; + +import mplayer4anime.ISlaveModeAppOrchestration; +import mplayer4anime.ServiceWindow; import java.io.*; import java.util.ResourceBundle; @@ -42,7 +45,7 @@ public class MplayerSlave implements ISlaveModeAppOrchestration { } return false; } - + @Override public void subtitlesSwitch(){ if (! playerSingleCommand("get_sub_visibility")) return; @@ -66,15 +69,15 @@ public class MplayerSlave implements ISlaveModeAppOrchestration { System.out.println("Can't determine whether subtitles enabled or disabled"); } } - + @Override public void fullscreenSwitch(){ playerSingleCommand("vo_fullscreen"); } - + @Override public void mute(){ playerSingleCommand("mute"); } - + @Override public void forcePlay(String mplayerPath, String VideoFile, String AudioFile, @@ -94,7 +97,7 @@ public class MplayerSlave implements ISlaveModeAppOrchestration { e.printStackTrace(); } } - + @Override public boolean pause(){ if (player == null || !player.isAlive()) return false; @@ -103,7 +106,7 @@ public class MplayerSlave implements ISlaveModeAppOrchestration { playerIn.flush(); return true; } - + @Override public void playPause(String mplayerPath, String VideoFile, String AudioFile, @@ -155,15 +158,15 @@ public class MplayerSlave implements ISlaveModeAppOrchestration { ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), resourceBundle.getString("ErrorUnableToStartMplayer")); } } - + @Override public void stop(){ playerSingleCommand("stop"); } - + @Override public void volumeUp(){ playerSingleCommand("volume +1 0"); } - + @Override public void volumeDown(){ playerSingleCommand("volume -1 0"); } diff --git a/src/main/java/mplayer4anime/mpv/MpvJniLibraryLoader.java b/src/main/java/mplayer4anime/mpv/MpvJniLibraryLoader.java new file mode 100644 index 0000000..48bd958 --- /dev/null +++ b/src/main/java/mplayer4anime/mpv/MpvJniLibraryLoader.java @@ -0,0 +1,108 @@ +/* + Copyright 2018-2021 Dmitry Isaenko + + This file is part of mplayer4anime. + + mplayer4anime is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + mplayer4anime is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with mplayer4anime. If not, see . + */ +package mplayer4anime.mpv; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URISyntaxException; +import java.net.URL; + +public final class MpvJniLibraryLoader { + private MpvJniLibraryLoader(){} + public static boolean load(){ + String osName = System.getProperty("os.name").toLowerCase().replace(" ", ""); + String osArch = System.getProperty("os.arch").toLowerCase().replace(" ", ""); + String libPostfix = "so"; + + if (osName.equals("linux")){ + switch (osArch){ + case "i386": + case "i586": + case "i686": + osArch = "x86"; + break; + case "x86_64": + case "amd64": + osArch = "amd64"; + break; +// case "arm": +// osArch = "arm"; +// break; + default: + return false; + } + } + else + return false; + + final URL url_ = MpvJniLibraryLoader.class.getResource("/native/"+osName+"/"+osArch+"/mpvjni."+libPostfix); + if (url_ == null) + return false; + + String proto = url_.getProtocol(); + + File libraryFile; + if (proto.equals("file")){ + // We can pick file from disk as is. + try { + libraryFile = new File(url_.toURI()); + } + catch (URISyntaxException e){ + e.printStackTrace(); + return false; + } + } + else if (proto.equals("jar")){ + // We have to export file to temp dir. + InputStream inStream = MpvJniLibraryLoader.class.getResourceAsStream("/native/"+osName+"/"+osArch+"/mpvjni."+libPostfix); + if (inStream == null) + return false; + // Create temp folder + try{ + File tmpDirFile = File.createTempFile("jni", null); + if (! tmpDirFile.delete()) + return false; + if (! tmpDirFile.mkdirs()) + return false; + libraryFile = new File(tmpDirFile, "mpvjni."+libPostfix); + byte[] ioBuffer = new byte[8192]; + FileOutputStream foStream = new FileOutputStream(libraryFile); + while (inStream.read(ioBuffer) != -1) + foStream.write(ioBuffer); + foStream.close(); + inStream.close(); + libraryFile.deleteOnExit(); + tmpDirFile.deleteOnExit(); + } + catch (IOException ioe){ + ioe.printStackTrace(); + return false; + } + } + else + return false; + + //System.out.println("LIB LOCATION: "+libraryFile); + System.load(libraryFile.getAbsolutePath()); + //System.out.println("LIB LOADED"); + return true; + } +} diff --git a/src/main/java/mplayer4anime/mpv/MpvSlave.java b/src/main/java/mplayer4anime/mpv/MpvSlave.java new file mode 100644 index 0000000..3a5a068 --- /dev/null +++ b/src/main/java/mplayer4anime/mpv/MpvSlave.java @@ -0,0 +1,96 @@ +/* + Copyright 2018-2021 Dmitry Isaenko + + This file is part of mplayer4anime. + + mplayer4anime is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + mplayer4anime is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with mplayer4anime. If not, see . + */ +package mplayer4anime.mpv; + +import mplayer4anime.ISlaveModeAppOrchestration; +import mplayer4anime.ServiceWindow; + +import java.util.ResourceBundle; + +public class MpvSlave implements ISlaveModeAppOrchestration { + static { + if (! MpvJniLibraryLoader.load()){ + ServiceWindow.getErrorNotification("Error", + "Unable to load mpv back end library. Please use mplayer instead"); // TODO: use bundle & translate + } + } + + native void play(); + + public MpvSlave(ResourceBundle resourceBundle){ + + } + + @Override + public void subtitlesSwitch() { + + } + + @Override + public void fullscreenSwitch() { + + } + + @Override + public void mute() { + + } + + @Override + public void forcePlay(String mplayerPath, + String VideoFile, + String AudioFile, + String SubtitlesFile, + String subtitlesEncoding, + boolean subtitlesHidden, + boolean isFullscreen) { + + } + + @Override + public boolean pause() { + return false; + } + + @Override + public void playPause(String mplayerPath, + String VideoFile, + String AudioFile, + String SubtitlesFile, + String subtitlesEncoding, + boolean subtitlesHidden, + boolean isFullscreen) { + + } + + @Override + public void stop() { + + } + + @Override + public void volumeUp() { + + } + + @Override + public void volumeDown() { + + } +} diff --git a/src/main/resources/Settings/SettingsLayout.fxml b/src/main/resources/Settings/SettingsLayout.fxml index 7bec19c..ab58379 100644 --- a/src/main/resources/Settings/SettingsLayout.fxml +++ b/src/main/resources/Settings/SettingsLayout.fxml @@ -3,6 +3,7 @@ + @@ -42,6 +43,12 @@ + + + + diff --git a/src/main/resources/locale.properties b/src/main/resources/locale.properties index b245891..7537564 100644 --- a/src/main/resources/locale.properties +++ b/src/main/resources/locale.properties @@ -53,6 +53,7 @@ settings_Tab_Subtitles=Subtitles settings_videoExtensionList=Avaliable video files extensions: settings_audioExtensionList=Avaliable audio layer extensions: ApplyBtn=Apply +settings_backendSelect=Backend engine: diff --git a/src/main/resources/locale_rus.properties b/src/main/resources/locale_rus.properties index aa4b42e..e7df953 100644 --- a/src/main/resources/locale_rus.properties +++ b/src/main/resources/locale_rus.properties @@ -53,4 +53,5 @@ settings_Tab_Video=\u0412\u0438\u0434\u0435\u043E settings_videoExtensionList=\u0414\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F \u0434\u043B\u044F \u0444\u0430\u0439\u043B\u043E\u0432 \u0432\u0438\u0434\u0435\u043E: settings_audioExtensionList=\u0414\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F \u0434\u043B\u044F \u0430\u0443\u0434\u0438\u043E\u0434\u043E\u0440\u043E\u0436\u0435\u043A: ApplyBtn=\u041F\u0440\u0438\u043C\u0435\u043D\u0438\u0442\u044C +settings_backendSelect=\u0414\u0432\u0438\u0436\u043E\u043A \u0432\u043E\u0441\u043F\u0440\u043E\u0438\u0437\u0432\u0435\u0434\u0435\u043D\u0438\u044F: diff --git a/src/main/resources/native/linux/amd64/mpvjni.so b/src/main/resources/native/linux/amd64/mpvjni.so new file mode 100755 index 0000000000000000000000000000000000000000..5ec25db53784fac3c754c013fb30b7929ea81672 GIT binary patch literal 14760 zcmeHOTWB0*6#h3Co7ziat(dk-hR{kYcA6%(SWDW;Ws_-1dPx&dv<#DElHIbGuse-u zMGUkGrBv#Rh>v{`eX`P*K1pk(FA83s^g#$>C4y*tQ0hy@b7s!BI~kKw5Jbv=9;(%c+*^U#B$Gcxa`i5k@mDYDd<_W|yd3}5ySg(#-XNBj6 zY}dYgyFjp_@c70uUhZ!>`!g%p`^er(ucVBSVS{>DsYfCY_Zy1iOy-LPr|i2W-*J?4 zXn4>W_e$Pmw(NVQ;lZ9FimmM85%SCgq>K{1N-Q%>I?dBfLO4Wp!f$sWo5yh zAIKGK`;m@~Ef%#trPjn{1lX54zhmyD`fnKa-Sr=%?%w1!b+6Y_RYJscIvkM^`gI#Iv9}-8iKir#+KeHf3`DAE_Hg>h<&beFE{NA zcl@>X#m>W|%%2Q`U_L{K+x1QwO? zj%#08)<#e%gk2|koz(Mg5*_uhTSUii#Lc3kE|!05vcUhxVo(eXQsj!d{Qen3iyjbG@lnFp6)h>^Fv<}$UOz6DsI{G6aVGh;h z?0kM|)Eb5B13dn3A*CKwm>29%hV~|vT*p&k09}0sA|u>K!2KB3QhPeIZ=eSRmfBw; zwMNlZ5dOJQ^|{nEs%oY68nu?ISHD7bqY_nZe7u7FbF#Nq!>TPRNIzA`nq!K~*0aiS z#>+(~;}*ub(7pG?BVB`sddS*;WW-6^PTx@1VA`>JhsZ=V@lN_kFBi-A4;=088gP#G z^_@r$JHuVw18K5SfBroS>F=vPe!0T@`zXG*mQ>T5qsE7SL8=oseG^fJyw$)&3Q z%s5e?MHI&^m8kkZj6|FIbMx6T8m#DZk2Dq6ca=F>E-Q1an9tMOrh4Z7Rg3q zUI;$+KOjCQ;7?*V@p*5B9s4WLkinAk7qdD}jXHXPkNq5o{T%+}`gtGVHR1E5vLDF4 z@HqM6!ehnd8YywUAv~a{6$*5qo8Y&J1Bm&e1L(k03BDzK;7t$(F)qwg2|o5`AU+2X zpIra6@R46-NTeXHU$I8dctIgNPcP0N_}dLqNPs-QxM1C|y+w`n^up&XzHi`psboBK z;CsYvjPdb(#Fpp65Jw@QKnK20R=##HK0dGTTp6ApgC9Jc2amYCe)#d+&)hCDk{IE! zdH^5z5xL@gWl3yXgm|BewetQ4|2jG1e0&Z!3mVMQKe1wM}zms_N; zO~NZK@LMaEr~!T)aqYxIZRs#0f&4z^?;uzY^1|0Q<{sx?-5qH^#f{X)xG?kA-R1c2 Nv_}zNAW$&L{~IWuw}k)z literal 0 HcmV?d00001 diff --git a/src/main/resources/native/linux/x86/mpvjni.so b/src/main/resources/native/linux/x86/mpvjni.so new file mode 100755 index 0000000000000000000000000000000000000000..46cdf99b3a8daf0136c1bcb6234392d38786abaf GIT binary patch literal 14092 zcmeHOU2GIp6u#T8SYd@ynjn8+(yUmFjHMJrF=6{pNei@H{3B+VcBkEy-JQBSZ3;2b zvKqzOWcAHA6Jnw<@xhY#U`(V-OpOmJPd@m-3rR_uSYp*i3FG(8?5$H$f1(fia1VTQ z&bjBzxpTkWxy{|V^J05>&yO?-O;m|`u|?eH#brMAdlf#y zba0+m4VpIb6dH)Tf^iK_8E?QOg6C@wBYfD$0%D868i4iCov25=9&ut8KEXI^oVe~J zWNqpw+6cyoUdC4up3h6}Lp<33HM9{t7sK%S=U8ZaV-jJ_*FsEx^=1~$D}*(rXfQgY z16>EOjuZ{XL(+k!e-emo^z&-OS|JQ$IAdpxykq7Z!w^PSyvImbIcqqTcdT5zr!{S7 zt++Xmw*1)Y5o2)NG=@@HGo3nTiKFJ2X=Fyy=2qyM^7vQe} z5sTC)wnSYi#4TzPuS7AR7*Gr-1{4E|0mXn~Krx^gPz)#r{uKlLh54$vM^Iv-^fQ*! zlZ7SMbzk|+sc^q8T&X%$a;LfYaxZetMsY7LB4McLdpKcxv@}%w{omX*L?&iFK&`3Q zxd@y(&*P)B&W_3R3x4fQCofzt%-8m^i|Q{*Q_e0?EKOb7g*-9$4h|DDXK+5U`hztJ z^WojI7fP4sc3%FqBJ}MyOHS?NTen#9s~1!LVxr6$dSJxuq_T;K|d&?L@}TkPz)#r6a$I@#eiZ!F`yVw3@8Q^1OGV#4cK>m z4GUJTQ@O91Pl>s?`Ch0t#I`_lPxCftJ}KV{aBnl$#q@u??b=N^nft>pL359J92&d0 zMG;sBa6QcRHy6q%DMqmWxd!?munFM08Bdq(6KKcNXPei8rL)}z{}*WQT(tcY;r@9k z+>71W+WMGQ-)UtX+t&6r===1BJ-J40WZ&+xCzAu3*CQn?Zo1N@rq8j)Fi7%Ifst#_ zpQjPyfqsp6l?F+M zREWF9ly7=R4afHbejV&9KybhPjX+$3y>y2!uu=ZGY)T)*#{BVv2lQdfF-8UrCpnru zqYsP=Zn96U7E2&zB=WYAG_whA)^B_ISaVNTD_T2`oiy5y7#)4hJ?+MkwmvjrU%%0Q ztc@G~JG+m!GrMn%i=*9W-mjPC6`Huzn@c*st|Es-suPch6~4lgixnbJl*Gm{!bU$(=FxDwMbg+7qa3w_Ye zWN;S*KI*?TIS2fN`w_RL;5|=hu<29y{U`1Rc;B;~a{+N0Ht%DYUJk#md&+IhyMzEy zge`@+l>Gqb1?F*1AUIFar%)3u0Ot|foJ$A|cCcT#q8GqR8{RpbiwMp|P@ZrMoRgjb zcnzG>y!#6mtdEr@;WCP*UVL3TTjdQ4KjjQYJymJkBrc0rKj-!-S1TGKMD4 zrvEmu0bm~gW<>uW?_I>nG4s54o{%?N_MyCb(NYLe^5q{zIFVaq(u#}VW)CPmtxqJjOhU(UnTcjU1KWd@*)uqVu`E8A3zNqC<{Io5={ qY6LdJ=l7cZRs;NwvQH^(d+~RZ1