Update image, add save-window-size-on-close feature, start separating mplayer controls out of the in-app controller-class that should make application architecture more solid in future and give a chance to add other back ends support. Start code refactoring, adding copyleft banners.
This commit is contained in:
parent
2fbdbc805f
commit
08aef521fe
16 changed files with 563 additions and 291 deletions
4
pom.xml
4
pom.xml
|
@ -8,7 +8,7 @@
|
||||||
<name>mplayer4anime</name>
|
<name>mplayer4anime</name>
|
||||||
|
|
||||||
<artifactId>mplayer4anime</artifactId>
|
<artifactId>mplayer4anime</artifactId>
|
||||||
<version>0.14.1-SNAPSHOT</version>
|
<version>0.15-SNAPSHOT</version>
|
||||||
|
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
<description>
|
<description>
|
||||||
mplayer front end to play content pairs that are mostly used for anime (mka+mkv, mp4+ac3, mkv+srt)
|
mplayer front end to play content pairs that are mostly used for anime (mka+mkv, mp4+ac3, mkv+srt)
|
||||||
</description>
|
</description>
|
||||||
<inceptionYear>2018-2019</inceptionYear>
|
<inceptionYear>2018</inceptionYear>
|
||||||
<organization>
|
<organization>
|
||||||
<name>Dmitry Isaenko</name>
|
<name>Dmitry Isaenko</name>
|
||||||
<url>https://developersu.blogspot.com/search/label/mplayer4anime</url>
|
<url>https://developersu.blogspot.com/search/label/mplayer4anime</url>
|
||||||
|
|
|
@ -1,14 +1,34 @@
|
||||||
|
/*
|
||||||
|
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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package mplayer4anime;
|
package mplayer4anime;
|
||||||
|
|
||||||
import java.util.prefs.Preferences;
|
import java.util.prefs.Preferences;
|
||||||
|
|
||||||
// Rule application settings
|
// Rule application settings
|
||||||
public class AppPreferences {
|
public class AppPreferences {
|
||||||
|
private static AppPreferences INSTANCE = new AppPreferences();
|
||||||
|
private Preferences preferences = Preferences.userRoot().node("mplayer4anime");
|
||||||
|
|
||||||
private Preferences preferences;
|
private AppPreferences(){}
|
||||||
|
|
||||||
public AppPreferences(){
|
public static AppPreferences getINSTANCE() {
|
||||||
preferences = Preferences.userRoot().node("mplayer4anime");
|
return INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPath(String path){
|
public void setPath(String path){
|
||||||
|
@ -96,5 +116,10 @@ public class AppPreferences {
|
||||||
preferences.put("RECENT_PLS_" + i, "");
|
preferences.put("RECENT_PLS_" + i, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Window size
|
||||||
|
public double getSceneWidth(){ return preferences.getDouble("window_width", 1200.0); }
|
||||||
|
public void setSceneWidth(double value){ preferences.putDouble("window_width", value); }
|
||||||
|
|
||||||
|
public double getSceneHeight(){ return preferences.getDouble("window_height", 800.0); }
|
||||||
|
public void setSceneHeight(double value){ preferences.putDouble("window_height", value); }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,26 @@
|
||||||
|
/*
|
||||||
|
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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package mplayer4anime;
|
package mplayer4anime;
|
||||||
|
|
||||||
import javafx.application.HostServices;
|
import javafx.application.HostServices;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.event.EventHandler;
|
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
|
@ -18,38 +35,33 @@ import mplayer4anime.appPanes.ControllerSUB;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ListIterator;
|
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
public class Controller implements Initializable {
|
public class Controller implements Initializable {
|
||||||
@FXML
|
@FXML
|
||||||
private ControllerPane mkvPaneController;
|
private ControllerPane mkvPaneController, mkaPaneController;
|
||||||
@FXML
|
|
||||||
private ControllerPane mkaPaneController;
|
|
||||||
@FXML
|
@FXML
|
||||||
private ControllerSUB subPaneController;
|
private ControllerSUB subPaneController;
|
||||||
@FXML
|
@FXML
|
||||||
private Label statusLbl;
|
private Label statusLbl;
|
||||||
@FXML
|
@FXML
|
||||||
private Menu recentlyOpenedMenu;
|
private Menu recentlyOpenedMenu;
|
||||||
// Get preferences
|
|
||||||
private AppPreferences appPreferences = new AppPreferences();
|
|
||||||
|
|
||||||
private ResourceBundle resourceBundle;
|
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private CheckMenuItem fullScreen;
|
private CheckMenuItem fullScreen;
|
||||||
|
|
||||||
// Get host services for opening URLs etc.
|
|
||||||
private HostServices hostServices;
|
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private TabPane tabPane;
|
private TabPane tabPane;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private CheckMenuItem subsHide;
|
private CheckMenuItem subsHide;
|
||||||
|
|
||||||
private String currentPlaylistLocation = null; //TODO: move to the constructor?
|
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;
|
||||||
|
|
||||||
// If application started with playlist passed as an argument, then we'll try to load it (if it's valid).
|
// 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) {
|
public void setPlaylistAsArgument(String playlist) {
|
||||||
|
@ -79,150 +91,19 @@ public class Controller implements Initializable {
|
||||||
subsHide.setSelected(appPreferences.getSubtitlesHideSelected());
|
subsHide.setSelected(appPreferences.getSubtitlesHideSelected());
|
||||||
|
|
||||||
String[] recentPlaylists = appPreferences.getRecentPlaylists();
|
String[] recentPlaylists = appPreferences.getRecentPlaylists();
|
||||||
for (int i = recentPlaylists.length-1; i >= 0; i--)
|
for (int i = recentPlaylists.length-1; i >= 0; i--) {
|
||||||
if (!recentPlaylists[i].isEmpty())
|
if (recentPlaylists[i].isEmpty())
|
||||||
addRecentlyOpened(recentPlaylists[i]);
|
continue;
|
||||||
|
addRecentlyOpened(recentPlaylists[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mplayer = new MplayerSlave(resourceBundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setHostServices(HostServices hostServices) {
|
void setHostServices(HostServices hostServices) {
|
||||||
this.hostServices = hostServices;
|
this.hostServices = hostServices;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PLAYER COMMANDS */
|
|
||||||
private boolean playerSingleCommand(String command){
|
|
||||||
if (player != null && player.isAlive()) {
|
|
||||||
playerIn.print(command);
|
|
||||||
playerIn.print("\n");
|
|
||||||
playerIn.flush();
|
|
||||||
return true;
|
|
||||||
} else { return false; }
|
|
||||||
}
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private void subsTriggerBtn(){
|
|
||||||
if (playerSingleCommand("get_sub_visibility")) {
|
|
||||||
String returnedStr;
|
|
||||||
int returnedInt = 1;
|
|
||||||
try {
|
|
||||||
while ((returnedStr = playerOutErr.readLine()) != null) {
|
|
||||||
//System.out.println(returnedStr);
|
|
||||||
if (returnedStr.startsWith("ANS_SUB_VISIBILITY=")) {
|
|
||||||
returnedInt = Integer.parseInt(returnedStr.substring("ANS_SUB_VISIBILITY=".length()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.out.println("Can't determine whether subtitles enabled or disabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (returnedInt == 1)
|
|
||||||
playerSingleCommand("sub_visibility 0");
|
|
||||||
else
|
|
||||||
playerSingleCommand("sub_visibility 1");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@FXML
|
|
||||||
private void fullscreenBtn(){ playerSingleCommand("vo_fullscreen"); }
|
|
||||||
@FXML
|
|
||||||
private void muteBtn(){ playerSingleCommand("mute"); }
|
|
||||||
@FXML
|
|
||||||
private void playPrevTrackBtn(){
|
|
||||||
if (player != null && player.isAlive()) {
|
|
||||||
playerSingleCommand("quit");
|
|
||||||
while (player.isAlive()); // TODO: remove crutch, implement bike
|
|
||||||
}
|
|
||||||
int index;
|
|
||||||
index = mkvPaneController.getElementSelectedIndex();
|
|
||||||
if (index > 0) {
|
|
||||||
mkvPaneController.setElementSelectedByIndex(index-1); // .selectNext / .selectPrevious
|
|
||||||
playBtn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@FXML
|
|
||||||
private void playNextTrackBtn(){
|
|
||||||
if (player != null && player.isAlive()) {
|
|
||||||
playerSingleCommand("quit");
|
|
||||||
while (player.isAlive()); // TODO: remove crutch, implement bike
|
|
||||||
}
|
|
||||||
int index;
|
|
||||||
index = mkvPaneController.getElementSelectedIndex();
|
|
||||||
// TODO: add 'link' button
|
|
||||||
if (index+1 < mkvPaneController.getElementsCount() ) {
|
|
||||||
mkvPaneController.setElementSelectedByIndex(index+1);
|
|
||||||
}
|
|
||||||
index = mkaPaneController.getElementSelectedIndex();
|
|
||||||
if (index+1 < mkaPaneController.getElementsCount() ) {
|
|
||||||
mkaPaneController.setElementSelectedByIndex(index+1);
|
|
||||||
}
|
|
||||||
index = subPaneController.getElementSelectedIndex();
|
|
||||||
if (index+1 < subPaneController.getElementsCount() ) {
|
|
||||||
subPaneController.setElementSelectedByIndex(index+1);
|
|
||||||
}
|
|
||||||
playBtn();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Process player;
|
|
||||||
private PrintStream playerIn;
|
|
||||||
private BufferedReader playerOutErr;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private void playBtn(){
|
|
||||||
if (mkvPaneController.getElementSelected() != null) {
|
|
||||||
boolean Audio = !mkaPaneController.isElementsListEmpty() && mkvPaneController.getElementSelectedIndex() < mkaPaneController.getElementsCount();
|
|
||||||
boolean Subtitles = !subPaneController.isElementsListEmpty() && mkvPaneController.getElementSelectedIndex() < subPaneController.getElementsCount();
|
|
||||||
boolean SubEncodingDefault = subPaneController.getSelectedEncoding().equals("default");
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (player == null || !player.isAlive()) {
|
|
||||||
player = new ProcessBuilder( // FUCKING MAGIC! DON'T CHANGE SEQUENCE
|
|
||||||
appPreferences.getPath(), // It's a chance for Windows ;)
|
|
||||||
"-slave",
|
|
||||||
Audio?"-audiofile":"",
|
|
||||||
Audio? mkaPaneController.getElementSelected():"",
|
|
||||||
"-quiet",
|
|
||||||
fullScreen.isSelected() ? "-fs" : "",
|
|
||||||
mkvPaneController.getElementSelected(),
|
|
||||||
subsHide.isSelected()||Subtitles?"-nosub":"", // Turn off subtitles embedded into MKV file (and replace by localy-stored subs file if needed)
|
|
||||||
Subtitles?"-sub":"",
|
|
||||||
Subtitles? subPaneController.getElementSelected():"",
|
|
||||||
Subtitles?SubEncodingDefault?"":"-subcp":"", // Use subtitles -> YES -> Check if we need encoding
|
|
||||||
Subtitles?SubEncodingDefault?"": subPaneController.getSelectedEncoding():""
|
|
||||||
).start();
|
|
||||||
|
|
||||||
PipedInputStream readFrom = new PipedInputStream(256 * 1024);
|
|
||||||
PipedOutputStream writeTo = new PipedOutputStream(readFrom);
|
|
||||||
|
|
||||||
playerOutErr = new BufferedReader(new InputStreamReader(readFrom));
|
|
||||||
|
|
||||||
new LineRedirecter(player.getInputStream(), writeTo).start();
|
|
||||||
new LineRedirecter(player.getErrorStream(), writeTo).start();
|
|
||||||
|
|
||||||
playerIn = new PrintStream(player.getOutputStream());
|
|
||||||
|
|
||||||
/* If user desired to disable subtitles but populated the list in the SUB pane, then load them and disable visibility.
|
|
||||||
* It's should be done this way because if we won't pass them to mplayer during start them user won't be able to enable them later on.
|
|
||||||
* There is another bike could be implemented such as passing input file during load but it's far more dumb idea then current implementation.
|
|
||||||
*/
|
|
||||||
if (subsHide.isSelected())
|
|
||||||
playerSingleCommand("sub_visibility 0");
|
|
||||||
} else {
|
|
||||||
playerIn.print("pause");
|
|
||||||
playerIn.print("\n");
|
|
||||||
playerIn.flush();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), resourceBundle.getString("ErrorUnableToStartMplayer"));
|
|
||||||
}
|
|
||||||
} else { System.out.println("File not selected"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private void stopBtn(){playerSingleCommand("stop"); }
|
|
||||||
@FXML
|
|
||||||
private void volumeUpBtn(){ playerSingleCommand("volume +1 0"); }
|
|
||||||
@FXML
|
|
||||||
private void volumeDownBtn(){ playerSingleCommand("volume -1 0"); }
|
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void closeBtn() {
|
private void closeBtn() {
|
||||||
Stage currentStage = (Stage) tabPane.getScene().getWindow();
|
Stage currentStage = (Stage) tabPane.getScene().getWindow();
|
||||||
|
@ -312,21 +193,21 @@ public class Controller implements Initializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addRecentlyOpened(String playlistPath){
|
private void addRecentlyOpened(String playlistPath){
|
||||||
ListIterator<MenuItem> iteratorItem = recentlyOpenedMenu.getItems().listIterator();
|
ObservableList<MenuItem> items = recentlyOpenedMenu.getItems();
|
||||||
while (iteratorItem.hasNext()) {
|
for (MenuItem item : items) {
|
||||||
MenuItem mi = iteratorItem.next();
|
if (item.getUserData() != null && item.getUserData().equals(playlistPath)) {
|
||||||
if (mi.getUserData() != null && mi.getUserData().equals(playlistPath)) {
|
items.remove(item);
|
||||||
recentlyOpenedMenu.getItems().remove(mi);
|
items.add(0, item);
|
||||||
recentlyOpenedMenu.getItems().add(0, mi);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuItem menuItem = new MenuItem();
|
MenuItem menuItem = new MenuItem();
|
||||||
String fileNameOnly;
|
String playListName;
|
||||||
|
|
||||||
fileNameOnly = playlistPath.substring(playlistPath.lastIndexOf(File.separator) + 1);
|
playListName = playlistPath.substring(
|
||||||
menuItem.setText(fileNameOnly);
|
playlistPath.lastIndexOf(File.separator) + 1, playlistPath.lastIndexOf("."));
|
||||||
|
menuItem.setText(playListName);
|
||||||
|
|
||||||
menuItem.setUserData(playlistPath);
|
menuItem.setUserData(playlistPath);
|
||||||
menuItem.setOnAction(actionEvent -> {
|
menuItem.setOnAction(actionEvent -> {
|
||||||
|
@ -334,9 +215,90 @@ public class Controller implements Initializable {
|
||||||
setAllLists(jsonStorage);
|
setAllLists(jsonStorage);
|
||||||
});
|
});
|
||||||
// Limit list to 13 elements (2 in the end are separator and clear button)
|
// Limit list to 13 elements (2 in the end are separator and clear button)
|
||||||
if (recentlyOpenedMenu.getItems().size() >= 11)
|
if (items.size() >= 11)
|
||||||
recentlyOpenedMenu.getItems().remove(9, recentlyOpenedMenu.getItems().size() - 2);
|
items.remove(9, recentlyOpenedMenu.getItems().size() - 2);
|
||||||
recentlyOpenedMenu.getItems().add(0, menuItem);
|
items.add(0, menuItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PLAYER */
|
||||||
|
@FXML
|
||||||
|
private void subsTriggerBtn(){
|
||||||
|
mplayer.subtitlesSwitch();
|
||||||
|
}
|
||||||
|
@FXML
|
||||||
|
private void fullscreenBtn(){
|
||||||
|
mplayer.fullscreenSwitch();
|
||||||
|
}
|
||||||
|
@FXML
|
||||||
|
private void muteBtn(){
|
||||||
|
mplayer.mute();
|
||||||
|
}
|
||||||
|
@FXML
|
||||||
|
private void playPrevTrackBtn(){
|
||||||
|
int index = mkvPaneController.getElementSelectedIndex();
|
||||||
|
if (index <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mkvPaneController.setElementSelectedByIndex(index-1);
|
||||||
|
mplayer.forcePlay(appPreferences.getPath(),
|
||||||
|
mkvPaneController.getElementSelected(),
|
||||||
|
mkaPaneController.getElementSelected(),
|
||||||
|
subPaneController.getElementSelected(),
|
||||||
|
subPaneController.getSelectedEncoding(),
|
||||||
|
subsHide.isSelected(),
|
||||||
|
fullScreen.isSelected()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@FXML
|
||||||
|
private void playNextTrackBtn(){
|
||||||
|
int index = mkvPaneController.getElementSelectedIndex();
|
||||||
|
|
||||||
|
if (index + 1 < mkvPaneController.getElementsCount()) {
|
||||||
|
mkvPaneController.setElementSelectedByIndex(index + 1);
|
||||||
|
}
|
||||||
|
index = mkaPaneController.getElementSelectedIndex();
|
||||||
|
if (index + 1 < mkaPaneController.getElementsCount()) {
|
||||||
|
mkaPaneController.setElementSelectedByIndex(index + 1);
|
||||||
|
}
|
||||||
|
index = subPaneController.getElementSelectedIndex();
|
||||||
|
if (index + 1 < subPaneController.getElementsCount()) {
|
||||||
|
subPaneController.setElementSelectedByIndex(index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
mplayer.forcePlay(appPreferences.getPath(),
|
||||||
|
mkvPaneController.getElementSelected(),
|
||||||
|
mkaPaneController.getElementSelected(),
|
||||||
|
subPaneController.getElementSelected(),
|
||||||
|
subPaneController.getSelectedEncoding(),
|
||||||
|
subsHide.isSelected(),
|
||||||
|
fullScreen.isSelected()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@FXML
|
||||||
|
private void playBtn(){
|
||||||
|
if (mkvPaneController.getElementSelected() == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mplayer.playPause(appPreferences.getPath(),
|
||||||
|
mkvPaneController.getElementSelected(),
|
||||||
|
mkaPaneController.getElementSelected(),
|
||||||
|
subPaneController.getElementSelected(),
|
||||||
|
subPaneController.getSelectedEncoding(),
|
||||||
|
subsHide.isSelected(),
|
||||||
|
fullScreen.isSelected()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@FXML
|
||||||
|
private void stopBtn(){
|
||||||
|
mplayer.stop();
|
||||||
|
}
|
||||||
|
@FXML
|
||||||
|
private void volumeUpBtn(){
|
||||||
|
mplayer.volumeUp();
|
||||||
|
}
|
||||||
|
@FXML
|
||||||
|
private void volumeDownBtn(){
|
||||||
|
mplayer.volumeDown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
23
src/main/java/mplayer4anime/ISlaveModeAppOrchestration.java
Normal file
23
src/main/java/mplayer4anime/ISlaveModeAppOrchestration.java
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package mplayer4anime;
|
||||||
|
|
||||||
|
public interface ISlaveModeAppOrchestration {
|
||||||
|
// TODO: implement unified interface for mplayer and mpv
|
||||||
|
}
|
|
@ -1,27 +1,44 @@
|
||||||
|
/*
|
||||||
|
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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package mplayer4anime;
|
package mplayer4anime;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
public class LineRedirecter extends Thread {
|
public class LineRedirecter extends Thread {
|
||||||
private InputStream inStr;
|
private final InputStream inStream;
|
||||||
private OutputStream outStr;
|
private final OutputStream outStream;
|
||||||
|
|
||||||
LineRedirecter(InputStream in, OutputStream out){
|
LineRedirecter(InputStream inStream, OutputStream outStream){
|
||||||
this.inStr = in;
|
this.inStream = inStream;
|
||||||
this.outStr = out;
|
this.outStream = outStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run(){
|
public void run(){
|
||||||
try {
|
try {
|
||||||
BufferedReader bufferReader = new BufferedReader(new InputStreamReader(inStr));
|
BufferedReader bufferReader = new BufferedReader(new InputStreamReader(inStream));
|
||||||
PrintStream printStream = new PrintStream(outStr);
|
PrintStream printStream = new PrintStream(outStream);
|
||||||
String playerOutput;
|
String playerOutput;
|
||||||
|
|
||||||
while ((playerOutput = bufferReader.readLine()) != null) {
|
while ((playerOutput = bufferReader.readLine()) != null) {
|
||||||
printStream.println(playerOutput);
|
printStream.println(playerOutput);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}catch (IOException e){
|
catch (IOException e){
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,22 @@
|
||||||
|
/*
|
||||||
|
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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package mplayer4anime;
|
package mplayer4anime;
|
||||||
/**
|
|
||||||
Name: mplayer4anime
|
|
||||||
@author Dmitry Isaenko
|
|
||||||
License: GNU GPL v.3
|
|
||||||
@version 0.12
|
|
||||||
@see https://developersu.blogspot.com/search/label/mplayer4anime
|
|
||||||
@see https://github.com/developersu/mplayer4anime
|
|
||||||
2018-2019, Russia
|
|
||||||
*/
|
|
||||||
|
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
|
@ -55,17 +64,22 @@ public class MainFX extends Application {
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> tsih.interrupt()));
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> tsih.interrupt()));
|
||||||
|
|
||||||
primaryStage.getIcons().addAll(
|
primaryStage.getIcons().addAll(
|
||||||
new Image(MainFX.class.getResourceAsStream("/res/app_icon32x32.png")),
|
new Image(getClass().getResourceAsStream("/res/app_icon32x32.png")),
|
||||||
new Image(MainFX.class.getResourceAsStream("/res/app_icon48x48.png")),
|
new Image(getClass().getResourceAsStream("/res/app_icon48x48.png")),
|
||||||
new Image(MainFX.class.getResourceAsStream("/res/app_icon64x64.png")),
|
new Image(getClass().getResourceAsStream("/res/app_icon64x64.png")),
|
||||||
new Image(MainFX.class.getResourceAsStream("/res/app_icon128x128.png"))
|
new Image(getClass().getResourceAsStream("/res/app_icon128x128.png"))
|
||||||
);
|
);
|
||||||
primaryStage.setTitle("mplayer4anime");
|
primaryStage.setTitle("mplayer4anime");
|
||||||
primaryStage.setMinWidth(500);
|
primaryStage.setMinWidth(500);
|
||||||
primaryStage.setMinHeight(375);
|
primaryStage.setMinHeight(375);
|
||||||
primaryStage.setScene(new Scene(root, 1200, 800));
|
Scene scene = new Scene(root,
|
||||||
|
AppPreferences.getINSTANCE().getSceneWidth(),
|
||||||
|
AppPreferences.getINSTANCE().getSceneHeight());
|
||||||
|
primaryStage.setScene(scene);
|
||||||
// Make linkage to controller method to handle exit() event in there.
|
// Make linkage to controller method to handle exit() event in there.
|
||||||
primaryStage.setOnHidden(e -> {
|
primaryStage.setOnHidden(e -> {
|
||||||
|
AppPreferences.getINSTANCE().setSceneHeight(scene.getHeight());
|
||||||
|
AppPreferences.getINSTANCE().setSceneWidth(scene.getWidth());
|
||||||
tsih.interrupt();
|
tsih.interrupt();
|
||||||
controller.shutdown();
|
controller.shutdown();
|
||||||
});
|
});
|
||||||
|
|
170
src/main/java/mplayer4anime/MplayerSlave.java
Normal file
170
src/main/java/mplayer4anime/MplayerSlave.java
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
/*
|
||||||
|
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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package mplayer4anime;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class MplayerSlave implements ISlaveModeAppOrchestration {
|
||||||
|
private Process player;
|
||||||
|
private PrintStream playerIn;
|
||||||
|
private BufferedReader playerOutErr;
|
||||||
|
|
||||||
|
private final ResourceBundle resourceBundle;
|
||||||
|
|
||||||
|
public MplayerSlave(ResourceBundle resourceBundle){
|
||||||
|
this.resourceBundle = resourceBundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean playerSingleCommand(String command){
|
||||||
|
if (player != null && player.isAlive()) {
|
||||||
|
playerIn.print(command);
|
||||||
|
playerIn.print("\n");
|
||||||
|
playerIn.flush();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void subtitlesSwitch(){
|
||||||
|
if (! playerSingleCommand("get_sub_visibility"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
String returnedStr;
|
||||||
|
int returnedInt = 1;
|
||||||
|
while ((returnedStr = playerOutErr.readLine()) != null) {
|
||||||
|
if (returnedStr.startsWith("ANS_SUB_VISIBILITY=")) {
|
||||||
|
returnedInt = Integer.parseInt(returnedStr.substring("ANS_SUB_VISIBILITY=".length()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (returnedInt == 1)
|
||||||
|
playerSingleCommand("sub_visibility 0");
|
||||||
|
else
|
||||||
|
playerSingleCommand("sub_visibility 1");
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
System.out.println("Can't determine whether subtitles enabled or disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fullscreenSwitch(){
|
||||||
|
playerSingleCommand("vo_fullscreen");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mute(){
|
||||||
|
playerSingleCommand("mute");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void forcePlay(String mplayerPath,
|
||||||
|
String VideoFile,
|
||||||
|
String AudioFile,
|
||||||
|
String SubtitlesFile,
|
||||||
|
String subtitlesEncoding,
|
||||||
|
boolean subtitlesHidden,
|
||||||
|
boolean isFullscreen){
|
||||||
|
try {
|
||||||
|
if (player != null && player.isAlive()){
|
||||||
|
playerSingleCommand("quit");
|
||||||
|
player.waitFor(500, TimeUnit.MILLISECONDS);
|
||||||
|
player.destroyForcibly();
|
||||||
|
}
|
||||||
|
playPause(mplayerPath, VideoFile, AudioFile, SubtitlesFile, subtitlesEncoding, subtitlesHidden, isFullscreen);
|
||||||
|
}
|
||||||
|
catch (InterruptedException e){
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean pause(){
|
||||||
|
if (player == null || !player.isAlive())
|
||||||
|
return false;
|
||||||
|
playerIn.print("pause");
|
||||||
|
playerIn.print("\n");
|
||||||
|
playerIn.flush();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playPause(String mplayerPath,
|
||||||
|
String VideoFile,
|
||||||
|
String AudioFile,
|
||||||
|
String SubtitlesFile,
|
||||||
|
String subtitlesEncoding,
|
||||||
|
boolean subtitlesHidden,
|
||||||
|
boolean isFullscreen){
|
||||||
|
if (pause())
|
||||||
|
return;
|
||||||
|
|
||||||
|
boolean isAudio = AudioFile != null;
|
||||||
|
boolean isSubtitles = SubtitlesFile != null;
|
||||||
|
boolean SubEncodingDefault = subtitlesEncoding.equals("default");
|
||||||
|
|
||||||
|
try {
|
||||||
|
player = new ProcessBuilder( // FUCKING MAGIC! DON'T CHANGE SEQUENCE
|
||||||
|
mplayerPath, // It's a chance for Windows ;)
|
||||||
|
"-slave",
|
||||||
|
isAudio?"-audiofile":"",
|
||||||
|
isAudio?AudioFile:"",
|
||||||
|
"-quiet",
|
||||||
|
isFullscreen ? "-fs" : "",
|
||||||
|
VideoFile,
|
||||||
|
subtitlesHidden||isSubtitles?"-nosub":"", // Turn off subtitles embedded into MKV file (and replace by localy-stored subs file if needed)
|
||||||
|
isSubtitles?"-sub":"",
|
||||||
|
isSubtitles? SubtitlesFile:"",
|
||||||
|
isSubtitles?SubEncodingDefault?"":"-subcp":"", // Use subtitles -> YES -> Check if we need encoding
|
||||||
|
isSubtitles?SubEncodingDefault?"": subtitlesEncoding:""
|
||||||
|
).start();
|
||||||
|
|
||||||
|
PipedInputStream readFrom = new PipedInputStream(256 * 1024);
|
||||||
|
PipedOutputStream writeTo = new PipedOutputStream(readFrom);
|
||||||
|
|
||||||
|
playerOutErr = new BufferedReader(new InputStreamReader(readFrom));
|
||||||
|
|
||||||
|
new LineRedirecter(player.getInputStream(), writeTo).start();
|
||||||
|
new LineRedirecter(player.getErrorStream(), writeTo).start();
|
||||||
|
|
||||||
|
playerIn = new PrintStream(player.getOutputStream());
|
||||||
|
|
||||||
|
/* If user desired to disable subtitles but populated the list in the SUB pane, then load them and disable visibility.
|
||||||
|
* It should be done this way because if we didn't pass them to mplayer during start then user won't be able to enable them later on.
|
||||||
|
* There is another bike could be implemented such as passing input file during load but it's far more dumb idea than current implementation.
|
||||||
|
*/
|
||||||
|
if (subtitlesHidden)
|
||||||
|
playerSingleCommand("sub_visibility 0");
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
ServiceWindow.getErrorNotification(resourceBundle.getString("Error"), resourceBundle.getString("ErrorUnableToStartMplayer"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop(){
|
||||||
|
playerSingleCommand("stop");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void volumeUp(){
|
||||||
|
playerSingleCommand("volume +1 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void volumeDown(){
|
||||||
|
playerSingleCommand("volume -1 0");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,30 @@
|
||||||
|
/*
|
||||||
|
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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package mplayer4anime;
|
package mplayer4anime;
|
||||||
|
|
||||||
import javafx.scene.control.Alert;
|
import javafx.scene.control.Alert;
|
||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates window with notification
|
||||||
|
* */
|
||||||
public class ServiceWindow {
|
public class ServiceWindow {
|
||||||
/**
|
|
||||||
* Create window with notification
|
|
||||||
* */
|
|
||||||
public static void getErrorNotification(String title, String body){
|
public static void getErrorNotification(String title, String body){
|
||||||
Alert alertBox = new Alert(Alert.AlertType.ERROR);
|
Alert alertBox = new Alert(Alert.AlertType.ERROR);
|
||||||
alertBox.setTitle(title);
|
alertBox.setTitle(title);
|
||||||
|
|
|
@ -1,32 +1,42 @@
|
||||||
|
/*
|
||||||
|
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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package mplayer4anime.Settings;
|
package mplayer4anime.Settings;
|
||||||
|
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
|
||||||
import javafx.scene.control.ListView;
|
import javafx.scene.control.ListView;
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
import javafx.scene.control.TextFormatter;
|
import javafx.scene.control.TextFormatter;
|
||||||
import javafx.scene.input.KeyEvent;
|
import javafx.scene.input.KeyEvent;
|
||||||
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.ResourceBundle;
|
|
||||||
|
|
||||||
public class ControllerListsSelector implements Initializable {
|
public class ControllerListsSelector{
|
||||||
@FXML
|
@FXML
|
||||||
private ListView<String> listView;
|
private ListView<String> listView;
|
||||||
@FXML
|
@FXML
|
||||||
private TextField newRecordText;
|
private TextField newRecordText;
|
||||||
private ObservableList<String> observableList;
|
private ObservableList<String> observableList;
|
||||||
private ResourceBundle resourceBundle;
|
|
||||||
|
|
||||||
private boolean isListOfExtensions;
|
private boolean isListOfExtensions;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(URL url, ResourceBundle rb) {
|
|
||||||
resourceBundle = rb;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Must be run on start
|
* Must be run on start
|
||||||
* Set list content
|
* Set list content
|
||||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package mplayer4anime.Settings;
|
package mplayer4anime.Settings;
|
||||||
|
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
|
@ -14,16 +32,12 @@ import java.util.ResourceBundle;
|
||||||
import mplayer4anime.MediatorControl;
|
import mplayer4anime.MediatorControl;
|
||||||
|
|
||||||
public class SettingsController implements Initializable {
|
public class SettingsController implements Initializable {
|
||||||
|
|
||||||
private AppPreferences appPreferences;
|
private AppPreferences appPreferences;
|
||||||
@FXML
|
@FXML
|
||||||
private ControllerListsSelector subExtensionListController;
|
private ControllerListsSelector subExtensionListController,
|
||||||
@FXML
|
subEncodingListController,
|
||||||
private ControllerListsSelector subEncodingListController;
|
videoExtensionListController,
|
||||||
@FXML
|
audioExtensionListController;
|
||||||
private ControllerListsSelector videoExtensionListController;
|
|
||||||
@FXML
|
|
||||||
private ControllerListsSelector audioExtensionListController;
|
|
||||||
@FXML
|
@FXML
|
||||||
private Label pathToMplayerLbl;
|
private Label pathToMplayerLbl;
|
||||||
@FXML
|
@FXML
|
||||||
|
@ -31,7 +45,7 @@ public class SettingsController implements Initializable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL url, ResourceBundle resBundle) {
|
public void initialize(URL url, ResourceBundle resBundle) {
|
||||||
appPreferences = new AppPreferences();
|
appPreferences = AppPreferences.getINSTANCE();
|
||||||
pathToMplayerLbl.setText(appPreferences.getPath());
|
pathToMplayerLbl.setText(appPreferences.getPath());
|
||||||
|
|
||||||
// Subtitles should be shown first? If TRUE, then set checkbox.
|
// Subtitles should be shown first? If TRUE, then set checkbox.
|
||||||
|
@ -72,16 +86,15 @@ public class SettingsController implements Initializable {
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void Cancel(){
|
private void Cancel(){
|
||||||
Stage thisStage = (Stage) pathToMplayerLbl.getScene().getWindow(); // TODO: consider refactoring. Non-urgent.
|
close();
|
||||||
thisStage.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void Ok(){
|
private void Ok(){
|
||||||
this.Apply();
|
Apply();
|
||||||
Stage thisStage = (Stage) pathToMplayerLbl.getScene().getWindow(); // TODO: consider refactoring. Non-urgent.
|
close();
|
||||||
thisStage.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void Apply(){
|
private void Apply(){
|
||||||
appPreferences.setPath(pathToMplayerLbl.getText());
|
appPreferences.setPath(pathToMplayerLbl.getText());
|
||||||
|
@ -93,4 +106,9 @@ public class SettingsController implements Initializable {
|
||||||
|
|
||||||
MediatorControl.getInstance().sentUpdates(); // TODO: implement list to track what should be updated
|
MediatorControl.getInstance().sentUpdates(); // TODO: implement list to track what should be updated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void close(){
|
||||||
|
Stage currentWindowStage = (Stage) pathToMplayerLbl.getScene().getWindow();
|
||||||
|
currentWindowStage.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package mplayer4anime.Settings;
|
package mplayer4anime.Settings;
|
||||||
|
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
|
@ -5,7 +23,6 @@ import javafx.scene.Parent;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import mplayer4anime.MainFX;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
@ -29,15 +46,14 @@ public class SettingsWindow {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Parent parentAbout = loaderSettings.load();
|
Parent parentAbout = loaderSettings.load();
|
||||||
//SettingsController settingsController = loaderSettings.getController();
|
|
||||||
|
|
||||||
stageAbout.setTitle(resourceBundle.getString("settings_SettingsName"));
|
stageAbout.setTitle(resourceBundle.getString("settings_SettingsName"));
|
||||||
stageAbout.getIcons().addAll(
|
stageAbout.getIcons().addAll(
|
||||||
new Image(MainFX.class.getResourceAsStream("/res/settings_icon32x32.png")),
|
new Image("/res/settings_icon32x32.png"),
|
||||||
new Image(MainFX.class.getResourceAsStream("/res/settings_icon48x48.png")),
|
new Image("/res/settings_icon32x32.png"),
|
||||||
new Image(MainFX.class.getResourceAsStream("/res/settings_icon64x64.png")),
|
new Image("/res/settings_icon48x48.png"),
|
||||||
new Image(MainFX.class.getResourceAsStream("/res/settings_icon128x128.png"))
|
new Image("/res/settings_icon64x64.png"),
|
||||||
); // TODO: change to something reliable
|
new Image("/res/settings_icon128x128.png"));
|
||||||
stageAbout.setScene(new Scene(parentAbout, 570, 500));
|
stageAbout.setScene(new Scene(parentAbout, 570, 500));
|
||||||
stageAbout.show();
|
stageAbout.show();
|
||||||
|
|
||||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package mplayer4anime.appPanes;
|
package mplayer4anime.appPanes;
|
||||||
|
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
|
@ -10,28 +28,23 @@ import javafx.scene.control.ListView;
|
||||||
import javafx.scene.input.KeyEvent;
|
import javafx.scene.input.KeyEvent;
|
||||||
import javafx.stage.DirectoryChooser;
|
import javafx.stage.DirectoryChooser;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import javafx.util.Callback;
|
|
||||||
import mplayer4anime.AppPreferences;
|
import mplayer4anime.AppPreferences;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FilenameFilter;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
public class ControllerPane implements Initializable {
|
public class ControllerPane implements Initializable {
|
||||||
|
|
||||||
private ResourceBundle resourceBundle;
|
private ResourceBundle resourceBundle;
|
||||||
// use folderToOpen same variable in all panes
|
|
||||||
private static String folderToOpen;
|
private static String folderToOpen;
|
||||||
|
|
||||||
private AppPreferences appPreferences;
|
private AppPreferences appPreferences;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ListView<File> paneListView;
|
private ListView<File> paneListView;
|
||||||
private ObservableList<File> paneFileList = FXCollections.observableArrayList();
|
private final ObservableList<File> paneFileList = FXCollections.observableArrayList();
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Label paneLbl;
|
private Label paneLbl;
|
||||||
|
@ -42,8 +55,9 @@ public class ControllerPane implements Initializable {
|
||||||
public void initialize(URL url, ResourceBundle resBundle) {
|
public void initialize(URL url, ResourceBundle resBundle) {
|
||||||
SetCellFactory(paneListView);
|
SetCellFactory(paneListView);
|
||||||
resourceBundle = resBundle;
|
resourceBundle = resBundle;
|
||||||
appPreferences = new AppPreferences();
|
appPreferences = AppPreferences.getINSTANCE();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPaneType(String paneType){
|
public void setPaneType(String paneType){
|
||||||
this.paneType = paneType;
|
this.paneType = paneType;
|
||||||
|
|
||||||
|
@ -69,12 +83,11 @@ public class ControllerPane implements Initializable {
|
||||||
}
|
}
|
||||||
/** Select element name (full path) using index recieved */
|
/** Select element name (full path) using index recieved */
|
||||||
public String getElementSelected(){
|
public String getElementSelected(){
|
||||||
if (this.paneListView.getSelectionModel().getSelectedItem() != null) {
|
File item = paneListView.getSelectionModel().getSelectedItem();
|
||||||
return this.paneFileList.get(this.getElementSelectedIndex()).toPath().toString();
|
if (item != null) {
|
||||||
}
|
return item.getAbsolutePath();
|
||||||
else {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
/** Select element in pane using index recieved */
|
/** Select element in pane using index recieved */
|
||||||
public void setElementSelectedByIndex(int index){
|
public void setElementSelectedByIndex(int index){
|
||||||
|
@ -98,33 +111,23 @@ public class ControllerPane implements Initializable {
|
||||||
return elementsArray;
|
return elementsArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetCellFactory(ListView<File> lv) {
|
private void SetCellFactory(ListView<File> listView) {
|
||||||
lv.setCellFactory(new Callback<ListView<File>, ListCell<File>>() {
|
listView.setCellFactory(cb -> new ListCell<File>() {
|
||||||
@Override
|
|
||||||
public ListCell<File> call(ListView<File> fileListView) {
|
|
||||||
return new ListCell<File>(){
|
|
||||||
@Override
|
@Override
|
||||||
public void updateItem(File item, boolean empty){
|
public void updateItem(File item, boolean empty) {
|
||||||
// have to call super here
|
// have to call super here
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
String trimmedName;
|
if (item == null || empty) {
|
||||||
|
|
||||||
if (item == null || empty){
|
|
||||||
setText(null);
|
setText(null);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else {
|
setText(item.getName());
|
||||||
trimmedName = item.getName();
|
|
||||||
setText(trimmedName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Open file selector (Open folder button in UI).
|
/** Open file selector (Open folder button in UI) */
|
||||||
* */
|
|
||||||
@FXML
|
@FXML
|
||||||
void openDirChooser(){
|
void openDirChooser(){
|
||||||
String[] filesExtensionTmp;
|
String[] filesExtensionTmp;
|
||||||
|
@ -166,30 +169,25 @@ public class ControllerPane implements Initializable {
|
||||||
if (directoryReceived != null) {
|
if (directoryReceived != null) {
|
||||||
File[] files; // Store files mkv/mka
|
File[] files; // Store files mkv/mka
|
||||||
|
|
||||||
files = directoryReceived.listFiles(new FilenameFilter() {
|
files = directoryReceived.listFiles((file, Name) -> {
|
||||||
@Override
|
int lastIndexOfDot = Name.lastIndexOf('.');
|
||||||
public boolean accept(File file, String Name) {
|
if (lastIndexOfDot > 0) {
|
||||||
if (Name.lastIndexOf('.') > 0) {
|
String ext = Name.substring(lastIndexOfDot);
|
||||||
int lastindex = Name.lastIndexOf('.');
|
for (String key : filesExtension){ // TODO: add toLowerCase and validate whatever registry extension noted
|
||||||
String ext = Name.substring(lastindex);
|
if (ext.equals(key.substring(1)))
|
||||||
for (String key : filesExtension){ // TODO: add toLowerCase and validate whatever registry extension noted
|
return true;
|
||||||
if (ext.equals(key.substring(1)))
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
return false;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
displayFiles(files);
|
displayFiles(files);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
System.out.println("No folder selected");
|
System.out.println("No folder selected");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/** Open file selector (Open files button in UI) */
|
||||||
* Open file selector (Open files button in UI).
|
|
||||||
* */
|
|
||||||
@FXML
|
@FXML
|
||||||
void openFilesChooser(){
|
void openFilesChooser(){
|
||||||
String[] filesExtension;
|
String[] filesExtension;
|
||||||
|
@ -213,9 +211,8 @@ public class ControllerPane implements Initializable {
|
||||||
lowerAndUpperExts.add(s);
|
lowerAndUpperExts.add(s);
|
||||||
lowerAndUpperExts.add(s.toUpperCase());
|
lowerAndUpperExts.add(s.toUpperCase());
|
||||||
}
|
}
|
||||||
filesExtension = lowerAndUpperExts.toArray(new String[lowerAndUpperExts.size()]);
|
|
||||||
|
|
||||||
List<File> filesRecievedList;
|
List<File> filesReceivedList;
|
||||||
|
|
||||||
FileChooser fc = new FileChooser();
|
FileChooser fc = new FileChooser();
|
||||||
fc.setTitle(resourceBundle.getString("SelectFile"));
|
fc.setTitle(resourceBundle.getString("SelectFile"));
|
||||||
|
@ -223,16 +220,19 @@ public class ControllerPane implements Initializable {
|
||||||
fc.setInitialDirectory(new File(System.getProperty("user.home")));
|
fc.setInitialDirectory(new File(System.getProperty("user.home")));
|
||||||
else
|
else
|
||||||
fc.setInitialDirectory(new File(folderToOpen));
|
fc.setInitialDirectory(new File(folderToOpen));
|
||||||
fc.getExtensionFilters().addAll(new FileChooser.ExtensionFilter(paneType, filesExtension));
|
|
||||||
|
|
||||||
filesRecievedList = fc.showOpenMultipleDialog(paneListView.getScene().getWindow());
|
fc.getExtensionFilters().addAll(new FileChooser.ExtensionFilter(paneType,
|
||||||
if (filesRecievedList != null){ // TODO: and !filesRecieved.isEmpty()
|
lowerAndUpperExts.toArray(new String[0])));
|
||||||
File[] filesRecieved = new File[filesRecievedList.size()];
|
|
||||||
filesRecievedList.toArray(filesRecieved);
|
filesReceivedList = fc.showOpenMultipleDialog(paneListView.getScene().getWindow());
|
||||||
displayFiles(filesRecieved);
|
if (filesReceivedList == null) {
|
||||||
} else {
|
|
||||||
System.out.println("No files selected");
|
System.out.println("No files selected");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File[] filesReceived = new File[filesReceivedList.size()];
|
||||||
|
filesReceivedList.toArray(filesReceived);
|
||||||
|
displayFiles(filesReceived);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Set files using lists. Used if playlist loaded
|
* Set files using lists. Used if playlist loaded
|
||||||
|
@ -250,7 +250,6 @@ public class ControllerPane implements Initializable {
|
||||||
if (files != null && files.length > 0) {
|
if (files != null && files.length > 0) {
|
||||||
// spiced java magic
|
// spiced java magic
|
||||||
Arrays.sort(files);
|
Arrays.sort(files);
|
||||||
|
|
||||||
// Remember the folder used for MKV and reuse it when user opens MKA/subs folder (as new default path instead of user.home)
|
// Remember the folder used for MKV and reuse it when user opens MKA/subs folder (as new default path instead of user.home)
|
||||||
folderToOpen = files[0].getParent();
|
folderToOpen = files[0].getParent();
|
||||||
//System.out.println(folderToOpen);
|
//System.out.println(folderToOpen);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
about_line1=mplayer4amine distributes under GNU GPLv3 license.
|
about_line1=mplayer4amine distributes under GNU GPLv3 license.
|
||||||
about_line2=Release: v0.14.1
|
about_line2=Release: v0.15
|
||||||
about_line3=Development & maintenance by Dmitry Isaenko.
|
about_line3=Development & maintenance by Dmitry Isaenko.
|
||||||
about_AboutName=About
|
about_AboutName=About
|
||||||
main_tab_audio=Audio
|
main_tab_audio=Audio
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
menu_File_Recent=\u041F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u0435 \u0444\u0430\u0439\u043B\u044B...
|
menu_File_Recent=\u041F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u0435 \u0444\u0430\u0439\u043B\u044B...
|
||||||
about_line1=mplayer4amine \u0440\u0430\u0441\u043F\u0440\u043E\u0441\u0442\u0440\u0430\u043D\u044F\u0435\u0442\u0441\u044F \u043F\u043E \u043B\u0438\u0446\u0435\u043D\u0437\u0438\u0438 GNU GPLv3.
|
about_line1=mplayer4amine \u0440\u0430\u0441\u043F\u0440\u043E\u0441\u0442\u0440\u0430\u043D\u044F\u0435\u0442\u0441\u044F \u043F\u043E \u043B\u0438\u0446\u0435\u043D\u0437\u0438\u0438 GNU GPLv3.
|
||||||
about_line2=\u0420\u0435\u043B\u0438\u0437: v0.14.1
|
about_line2=\u0420\u0435\u043B\u0438\u0437: v0.15
|
||||||
about_line3=\u0420\u0430\u0437\u0440\u0430\u0431\u043E\u0442\u0430\u043D\u043E \u0438 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F \u0414\u043C\u0438\u0442\u0440\u0438\u0435\u043C \u0418\u0441\u0430\u0435\u043D\u043A\u043E.
|
about_line3=\u0420\u0430\u0437\u0440\u0430\u0431\u043E\u0442\u0430\u043D\u043E \u0438 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F \u0414\u043C\u0438\u0442\u0440\u0438\u0435\u043C \u0418\u0441\u0430\u0435\u043D\u043A\u043E.
|
||||||
about_AboutName=\u041E \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0438
|
about_AboutName=\u041E \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0438
|
||||||
main_tab_audio=\u0410\u0443\u0434\u0438\u043E
|
main_tab_audio=\u0410\u0443\u0434\u0438\u043E
|
||||||
|
|
|
@ -97,7 +97,7 @@
|
||||||
-fx-fill: #000000;
|
-fx-fill: #000000;
|
||||||
}
|
}
|
||||||
.tab-paneSettings .tab:selected SVGPath{
|
.tab-paneSettings .tab:selected SVGPath{
|
||||||
-fx-fill: #f90000;
|
-fx-fill: #c30000;
|
||||||
}
|
}
|
||||||
.tab-paneSettings .tab{
|
.tab-paneSettings .tab{
|
||||||
-fx-background-color: #ffffff;
|
-fx-background-color: #ffffff;
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 34 KiB |
Loading…
Reference in a new issue