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:
Dmitry Isaenko 2021-09-12 05:39:33 +03:00
parent 2fbdbc805f
commit 08aef521fe
16 changed files with 563 additions and 291 deletions

View file

@ -8,7 +8,7 @@
<name>mplayer4anime</name>
<artifactId>mplayer4anime</artifactId>
<version>0.14.1-SNAPSHOT</version>
<version>0.15-SNAPSHOT</version>
<packaging>jar</packaging>
@ -16,7 +16,7 @@
<description>
mplayer front end to play content pairs that are mostly used for anime (mka+mkv, mp4+ac3, mkv+srt)
</description>
<inceptionYear>2018-2019</inceptionYear>
<inceptionYear>2018</inceptionYear>
<organization>
<name>Dmitry Isaenko</name>
<url>https://developersu.blogspot.com/search/label/mplayer4anime</url>

View file

@ -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;
import java.util.prefs.Preferences;
// Rule application settings
public class AppPreferences {
private static AppPreferences INSTANCE = new AppPreferences();
private Preferences preferences = Preferences.userRoot().node("mplayer4anime");
private Preferences preferences;
private AppPreferences(){}
public AppPreferences(){
preferences = Preferences.userRoot().node("mplayer4anime");
public static AppPreferences getINSTANCE() {
return INSTANCE;
}
public void setPath(String path){
@ -96,5 +116,10 @@ public class AppPreferences {
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); }
}

View file

@ -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;
import javafx.application.HostServices;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
@ -18,38 +35,33 @@ import mplayer4anime.appPanes.ControllerSUB;
import java.io.*;
import java.net.URL;
import java.util.ListIterator;
import java.util.ResourceBundle;
public class Controller implements Initializable {
@FXML
private ControllerPane mkvPaneController;
@FXML
private ControllerPane mkaPaneController;
private ControllerPane mkvPaneController, mkaPaneController;
@FXML
private ControllerSUB subPaneController;
@FXML
private Label statusLbl;
@FXML
private Menu recentlyOpenedMenu;
// Get preferences
private AppPreferences appPreferences = new AppPreferences();
private ResourceBundle resourceBundle;
@FXML
private CheckMenuItem fullScreen;
// Get host services for opening URLs etc.
private HostServices hostServices;
@FXML
private TabPane tabPane;
@FXML
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).
public void setPlaylistAsArgument(String playlist) {
@ -79,150 +91,19 @@ public class Controller implements Initializable {
subsHide.setSelected(appPreferences.getSubtitlesHideSelected());
String[] recentPlaylists = appPreferences.getRecentPlaylists();
for (int i = recentPlaylists.length-1; i >= 0; i--)
if (!recentPlaylists[i].isEmpty())
addRecentlyOpened(recentPlaylists[i]);
for (int i = recentPlaylists.length-1; i >= 0; i--) {
if (recentPlaylists[i].isEmpty())
continue;
addRecentlyOpened(recentPlaylists[i]);
}
mplayer = new MplayerSlave(resourceBundle);
}
void setHostServices(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
private void closeBtn() {
Stage currentStage = (Stage) tabPane.getScene().getWindow();
@ -312,21 +193,21 @@ public class Controller implements Initializable {
}
private void addRecentlyOpened(String playlistPath){
ListIterator<MenuItem> iteratorItem = recentlyOpenedMenu.getItems().listIterator();
while (iteratorItem.hasNext()) {
MenuItem mi = iteratorItem.next();
if (mi.getUserData() != null && mi.getUserData().equals(playlistPath)) {
recentlyOpenedMenu.getItems().remove(mi);
recentlyOpenedMenu.getItems().add(0, mi);
ObservableList<MenuItem> items = recentlyOpenedMenu.getItems();
for (MenuItem item : items) {
if (item.getUserData() != null && item.getUserData().equals(playlistPath)) {
items.remove(item);
items.add(0, item);
return;
}
}
MenuItem menuItem = new MenuItem();
String fileNameOnly;
String playListName;
fileNameOnly = playlistPath.substring(playlistPath.lastIndexOf(File.separator) + 1);
menuItem.setText(fileNameOnly);
playListName = playlistPath.substring(
playlistPath.lastIndexOf(File.separator) + 1, playlistPath.lastIndexOf("."));
menuItem.setText(playListName);
menuItem.setUserData(playlistPath);
menuItem.setOnAction(actionEvent -> {
@ -334,9 +215,90 @@ public class Controller implements Initializable {
setAllLists(jsonStorage);
});
// Limit list to 13 elements (2 in the end are separator and clear button)
if (recentlyOpenedMenu.getItems().size() >= 11)
recentlyOpenedMenu.getItems().remove(9, recentlyOpenedMenu.getItems().size() - 2);
recentlyOpenedMenu.getItems().add(0, menuItem);
if (items.size() >= 11)
items.remove(9, recentlyOpenedMenu.getItems().size() - 2);
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();
}
}

View 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
}

View file

@ -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;
import java.io.*;
public class LineRedirecter extends Thread {
private InputStream inStr;
private OutputStream outStr;
private final InputStream inStream;
private final OutputStream outStream;
LineRedirecter(InputStream in, OutputStream out){
this.inStr = in;
this.outStr = out;
LineRedirecter(InputStream inStream, OutputStream outStream){
this.inStream = inStream;
this.outStream = outStream;
}
public void run(){
try {
BufferedReader bufferReader = new BufferedReader(new InputStreamReader(inStr));
PrintStream printStream = new PrintStream(outStr);
BufferedReader bufferReader = new BufferedReader(new InputStreamReader(inStream));
PrintStream printStream = new PrintStream(outStream);
String playerOutput;
while ((playerOutput = bufferReader.readLine()) != null) {
printStream.println(playerOutput);
}
}catch (IOException e){
}
catch (IOException e){
e.printStackTrace();
}

View file

@ -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;
/**
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.fxml.FXMLLoader;
@ -55,17 +64,22 @@ public class MainFX extends Application {
Runtime.getRuntime().addShutdownHook(new Thread(() -> tsih.interrupt()));
primaryStage.getIcons().addAll(
new Image(MainFX.class.getResourceAsStream("/res/app_icon32x32.png")),
new Image(MainFX.class.getResourceAsStream("/res/app_icon48x48.png")),
new Image(MainFX.class.getResourceAsStream("/res/app_icon64x64.png")),
new Image(MainFX.class.getResourceAsStream("/res/app_icon128x128.png"))
new Image(getClass().getResourceAsStream("/res/app_icon32x32.png")),
new Image(getClass().getResourceAsStream("/res/app_icon48x48.png")),
new Image(getClass().getResourceAsStream("/res/app_icon64x64.png")),
new Image(getClass().getResourceAsStream("/res/app_icon128x128.png"))
);
primaryStage.setTitle("mplayer4anime");
primaryStage.setMinWidth(500);
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.
primaryStage.setOnHidden(e -> {
AppPreferences.getINSTANCE().setSceneHeight(scene.getHeight());
AppPreferences.getINSTANCE().setSceneWidth(scene.getWidth());
tsih.interrupt();
controller.shutdown();
});

View 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");
}
}

View file

@ -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;
import javafx.scene.control.Alert;
import javafx.scene.layout.Region;
/**
* Creates window with notification
* */
public class ServiceWindow {
/**
* Create window with notification
* */
public static void getErrorNotification(String title, String body){
Alert alertBox = new Alert(Alert.AlertType.ERROR);
alertBox.setTitle(title);

View file

@ -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;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.input.KeyEvent;
import java.net.URL;
import java.util.Arrays;
import java.util.ResourceBundle;
public class ControllerListsSelector implements Initializable {
public class ControllerListsSelector{
@FXML
private ListView<String> listView;
@FXML
private TextField newRecordText;
private ObservableList<String> observableList;
private ResourceBundle resourceBundle;
private boolean isListOfExtensions;
@Override
public void initialize(URL url, ResourceBundle rb) {
resourceBundle = rb;
}
/**
* Must be run on start
* Set list content

View file

@ -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;
import javafx.fxml.FXML;
@ -14,16 +32,12 @@ import java.util.ResourceBundle;
import mplayer4anime.MediatorControl;
public class SettingsController implements Initializable {
private AppPreferences appPreferences;
@FXML
private ControllerListsSelector subExtensionListController;
@FXML
private ControllerListsSelector subEncodingListController;
@FXML
private ControllerListsSelector videoExtensionListController;
@FXML
private ControllerListsSelector audioExtensionListController;
private ControllerListsSelector subExtensionListController,
subEncodingListController,
videoExtensionListController,
audioExtensionListController;
@FXML
private Label pathToMplayerLbl;
@FXML
@ -31,7 +45,7 @@ public class SettingsController implements Initializable {
@Override
public void initialize(URL url, ResourceBundle resBundle) {
appPreferences = new AppPreferences();
appPreferences = AppPreferences.getINSTANCE();
pathToMplayerLbl.setText(appPreferences.getPath());
// Subtitles should be shown first? If TRUE, then set checkbox.
@ -72,16 +86,15 @@ public class SettingsController implements Initializable {
@FXML
private void Cancel(){
Stage thisStage = (Stage) pathToMplayerLbl.getScene().getWindow(); // TODO: consider refactoring. Non-urgent.
thisStage.close();
close();
}
@FXML
private void Ok(){
this.Apply();
Stage thisStage = (Stage) pathToMplayerLbl.getScene().getWindow(); // TODO: consider refactoring. Non-urgent.
thisStage.close();
Apply();
close();
}
@FXML
private void Apply(){
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
}
private void close(){
Stage currentWindowStage = (Stage) pathToMplayerLbl.getScene().getWindow();
currentWindowStage.close();
}
}

View file

@ -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;
import javafx.fxml.FXMLLoader;
@ -5,7 +23,6 @@ import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import mplayer4anime.MainFX;
import java.io.IOException;
import java.util.Locale;
@ -29,15 +46,14 @@ public class SettingsWindow {
try {
Parent parentAbout = loaderSettings.load();
//SettingsController settingsController = loaderSettings.getController();
stageAbout.setTitle(resourceBundle.getString("settings_SettingsName"));
stageAbout.getIcons().addAll(
new Image(MainFX.class.getResourceAsStream("/res/settings_icon32x32.png")),
new Image(MainFX.class.getResourceAsStream("/res/settings_icon48x48.png")),
new Image(MainFX.class.getResourceAsStream("/res/settings_icon64x64.png")),
new Image(MainFX.class.getResourceAsStream("/res/settings_icon128x128.png"))
); // TODO: change to something reliable
new Image("/res/settings_icon32x32.png"),
new Image("/res/settings_icon32x32.png"),
new Image("/res/settings_icon48x48.png"),
new Image("/res/settings_icon64x64.png"),
new Image("/res/settings_icon128x128.png"));
stageAbout.setScene(new Scene(parentAbout, 570, 500));
stageAbout.show();

View file

@ -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;
import javafx.collections.FXCollections;
@ -10,28 +28,23 @@ import javafx.scene.control.ListView;
import javafx.scene.input.KeyEvent;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.util.Callback;
import mplayer4anime.AppPreferences;
import java.io.File;
import java.io.FilenameFilter;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
public class ControllerPane implements Initializable {
public class ControllerPane implements Initializable {
private ResourceBundle resourceBundle;
// use folderToOpen same variable in all panes
private static String folderToOpen;
private AppPreferences appPreferences;
@FXML
private ListView<File> paneListView;
private ObservableList<File> paneFileList = FXCollections.observableArrayList();
private final ObservableList<File> paneFileList = FXCollections.observableArrayList();
@FXML
private Label paneLbl;
@ -42,8 +55,9 @@ public class ControllerPane implements Initializable {
public void initialize(URL url, ResourceBundle resBundle) {
SetCellFactory(paneListView);
resourceBundle = resBundle;
appPreferences = new AppPreferences();
appPreferences = AppPreferences.getINSTANCE();
}
public void setPaneType(String paneType){
this.paneType = paneType;
@ -69,12 +83,11 @@ public class ControllerPane implements Initializable {
}
/** Select element name (full path) using index recieved */
public String getElementSelected(){
if (this.paneListView.getSelectionModel().getSelectedItem() != null) {
return this.paneFileList.get(this.getElementSelectedIndex()).toPath().toString();
}
else {
return null;
File item = paneListView.getSelectionModel().getSelectedItem();
if (item != null) {
return item.getAbsolutePath();
}
return null;
}
/** Select element in pane using index recieved */
public void setElementSelectedByIndex(int index){
@ -98,33 +111,23 @@ public class ControllerPane implements Initializable {
return elementsArray;
}
private void SetCellFactory(ListView<File> lv) {
lv.setCellFactory(new Callback<ListView<File>, ListCell<File>>() {
@Override
public ListCell<File> call(ListView<File> fileListView) {
return new ListCell<File>(){
private void SetCellFactory(ListView<File> listView) {
listView.setCellFactory(cb -> new ListCell<File>() {
@Override
public void updateItem(File item, boolean empty){
public void updateItem(File item, boolean empty) {
// have to call super here
super.updateItem(item, empty);
String trimmedName;
if (item == null || empty){
if (item == null || empty) {
setText(null);
return;
}
else {
trimmedName = item.getName();
setText(trimmedName);
}
setText(item.getName());
}
};
}
});
});
}
/**
* Open file selector (Open folder button in UI).
* */
/** Open file selector (Open folder button in UI) */
@FXML
void openDirChooser(){
String[] filesExtensionTmp;
@ -166,30 +169,25 @@ public class ControllerPane implements Initializable {
if (directoryReceived != null) {
File[] files; // Store files mkv/mka
files = directoryReceived.listFiles(new FilenameFilter() {
@Override
public boolean accept(File file, String Name) {
if (Name.lastIndexOf('.') > 0) {
int lastindex = Name.lastIndexOf('.');
String ext = Name.substring(lastindex);
for (String key : filesExtension){ // TODO: add toLowerCase and validate whatever registry extension noted
if (ext.equals(key.substring(1)))
return true;
}
} else
return false;
return false;
files = directoryReceived.listFiles((file, Name) -> {
int lastIndexOfDot = Name.lastIndexOf('.');
if (lastIndexOfDot > 0) {
String ext = Name.substring(lastIndexOfDot);
for (String key : filesExtension){ // TODO: add toLowerCase and validate whatever registry extension noted
if (ext.equals(key.substring(1)))
return true;
}
}
return false;
});
displayFiles(files);
} else {
}
else {
System.out.println("No folder selected");
}
}
/**
* Open file selector (Open files button in UI).
* */
/** Open file selector (Open files button in UI) */
@FXML
void openFilesChooser(){
String[] filesExtension;
@ -213,9 +211,8 @@ public class ControllerPane implements Initializable {
lowerAndUpperExts.add(s);
lowerAndUpperExts.add(s.toUpperCase());
}
filesExtension = lowerAndUpperExts.toArray(new String[lowerAndUpperExts.size()]);
List<File> filesRecievedList;
List<File> filesReceivedList;
FileChooser fc = new FileChooser();
fc.setTitle(resourceBundle.getString("SelectFile"));
@ -223,16 +220,19 @@ public class ControllerPane implements Initializable {
fc.setInitialDirectory(new File(System.getProperty("user.home")));
else
fc.setInitialDirectory(new File(folderToOpen));
fc.getExtensionFilters().addAll(new FileChooser.ExtensionFilter(paneType, filesExtension));
filesRecievedList = fc.showOpenMultipleDialog(paneListView.getScene().getWindow());
if (filesRecievedList != null){ // TODO: and !filesRecieved.isEmpty()
File[] filesRecieved = new File[filesRecievedList.size()];
filesRecievedList.toArray(filesRecieved);
displayFiles(filesRecieved);
} else {
fc.getExtensionFilters().addAll(new FileChooser.ExtensionFilter(paneType,
lowerAndUpperExts.toArray(new String[0])));
filesReceivedList = fc.showOpenMultipleDialog(paneListView.getScene().getWindow());
if (filesReceivedList == null) {
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
@ -250,7 +250,6 @@ public class ControllerPane implements Initializable {
if (files != null && files.length > 0) {
// spiced java magic
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)
folderToOpen = files[0].getParent();
//System.out.println(folderToOpen);

View file

@ -1,5 +1,5 @@
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_AboutName=About
main_tab_audio=Audio

View file

@ -1,6 +1,6 @@
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_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_AboutName=\u041E \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0438
main_tab_audio=\u0410\u0443\u0434\u0438\u043E

View file

@ -97,7 +97,7 @@
-fx-fill: #000000;
}
.tab-paneSettings .tab:selected SVGPath{
-fx-fill: #f90000;
-fx-fill: #c30000;
}
.tab-paneSettings .tab{
-fx-background-color: #ffffff;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 34 KiB