diff --git a/.classpath b/.classpath index e83910a..d9ff1e3 100644 --- a/.classpath +++ b/.classpath @@ -17,11 +17,16 @@ + + + + + + - diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 4a6c6b8..6f1d295 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,13 @@ eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=9 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=9 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning org.eclipse.jdt.core.compiler.source=9 diff --git a/README.md b/README.md index 7a798c0..2491954 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ sqlite-jdbc: https://github.com/xerial/sqlite-jdbc apache commons io : https://commons.apache.org/proper/commons-io/ ## screenshots -![Screenshot](https://github.com/Seil0/Seil0.github.io/blob/master/pictures/Project-HomeFlix_MainWindow.png) +![Screenshot](https://github.com/Seil0/Seil0.github.io/blob/master/images/Project-HomeFlix_MainWindow.png) Project-HomeFlix © 2016-2018 Kellerkinder ([Seil0](https://github.com/Seil0), [Windoofs](https://github.com/Windoofs)) www.kellerkinder.xyz diff --git a/pom.xml b/pom.xml index b5a8a73..95f22a2 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.kellerkinder Project-HomeFlix - 0.6.0 + 0.7.0 jar Project-HomeFlix @@ -19,7 +19,7 @@ junit junit - 4.11 + 4.12 test @@ -32,7 +32,7 @@ com.jfoenix jfoenix - 9.0.2 + 9.0.3 @@ -50,13 +50,13 @@ org.apache.logging.log4j log4j-api - 2.10.0 + 2.11.0 org.apache.logging.log4j log4j-core - 2.10.0 + 2.11.0 @@ -78,21 +78,21 @@ org.apache.maven.plugins maven-shade-plugin - 3.1.0 + 3.1.1 + + true + + + kellerkinder.HomeFlix.application.Main + + + package shade - - true - - - kellerkinder.HomeFlix.application.Main - - - diff --git a/src/main/java/com/cemu_UI/uiElements/JFXOkayCancelDialog.java b/src/main/java/com/cemu_UI/uiElements/JFXOkayCancelDialog.java deleted file mode 100644 index 5dd4d1a..0000000 --- a/src/main/java/com/cemu_UI/uiElements/JFXOkayCancelDialog.java +++ /dev/null @@ -1,142 +0,0 @@ -/** - * cemu_UI - * - * Copyright 2017 <@Seil0> - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - - -package com.cemu_UI.uiElements; - -import java.util.ResourceBundle; - -import com.jfoenix.controls.JFXButton; -import com.jfoenix.controls.JFXDialog; -import com.jfoenix.controls.JFXDialogLayout; - -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.Pane; -import javafx.scene.layout.StackPane; -import javafx.scene.text.Text; - -public class JFXOkayCancelDialog { - - private String headingText; - private String bodyText; - private String dialogBtnStyle; - private String okayText; - private String cancelText; - private int dialogWidth; - private int dialogHeight; - private EventHandler okayAction; - private EventHandler cancelAction; - private Pane pane; - - /** - * Creates a new JFoenix Dialog to show some information with okay and cancel option - * @param headingText Heading Text, just the heading - * @param bodyText body Text, all other text belongs here - * @param dialogBtnStyle Style of the okay button - * @param dialogWidth dialog width - * @param dialogHeight dialog height - * @param okayAction action which is performed if the okay button is clicked - * @param cancelAction action which is performed if the cancel button is clicked - * @param pane pane to which the dialog belongs - */ - public JFXOkayCancelDialog(String headingText, String bodyText, String dialogBtnStyle, int dialogWidth, - int dialogHeight, EventHandler okayAction, EventHandler cancelAction, Pane pane, - ResourceBundle bundle) { - this.headingText = headingText; - this.bodyText = bodyText; - this.dialogBtnStyle = dialogBtnStyle; - this.dialogWidth = dialogWidth; - this.dialogHeight = dialogHeight; - this.okayAction = okayAction; - this.cancelAction = cancelAction; - this.pane = pane; - okayText = bundle.getString("okayBtnText"); - cancelText = bundle.getString("cancelBtnText"); - } - - public void show() { - - JFXDialogLayout content = new JFXDialogLayout(); - content.setHeading(new Text(headingText)); - content.setBody(new Text(bodyText)); - StackPane stackPane = new StackPane(); - stackPane.autosize(); - JFXDialog dialog = new JFXDialog(stackPane, content, JFXDialog.DialogTransition.LEFT, true); - JFXButton okayBtn = new JFXButton(okayText); - okayBtn.addEventHandler(ActionEvent.ACTION, (e)-> { - dialog.close(); - }); - okayBtn.addEventHandler(ActionEvent.ACTION, okayAction); - okayBtn.setButtonType(com.jfoenix.controls.JFXButton.ButtonType.RAISED); - okayBtn.setPrefHeight(32); - okayBtn.setStyle(dialogBtnStyle); - JFXButton cancelBtn = new JFXButton(cancelText); - cancelBtn.addEventHandler(ActionEvent.ACTION, (e)-> { - dialog.close(); - }); - cancelBtn.addEventHandler(ActionEvent.ACTION, cancelAction); - cancelBtn.setButtonType(com.jfoenix.controls.JFXButton.ButtonType.RAISED); - cancelBtn.setPrefHeight(32); - cancelBtn.setStyle(dialogBtnStyle); - content.setActions(cancelBtn, okayBtn); - content.setPrefSize(dialogWidth, dialogHeight); - pane.getChildren().add(stackPane); - AnchorPane.setTopAnchor(stackPane, (pane.getHeight()-content.getPrefHeight())/2); - AnchorPane.setLeftAnchor(stackPane, (pane.getWidth()-content.getPrefWidth())/2); - dialog.show(); - } - - public String getOkayText() { - return okayText; - } - - public void setOkayText(String okayText) { - this.okayText = okayText; - } - - public String getCancelText() { - return cancelText; - } - - public void setCancelText(String cancelText) { - this.cancelText = cancelText; - } - - public EventHandler getOkayAction() { - return okayAction; - } - - public void setOkayAction(EventHandler okayAction) { - this.okayAction = okayAction; - } - - public EventHandler getCancelAction() { - return cancelAction; - } - - public void setCancelAction(EventHandler cancelAction) { - this.cancelAction = cancelAction; - } - -} - diff --git a/src/main/java/com/cemu_UI/uiElements/JFXTextAreaInfoDialog.java b/src/main/java/com/cemu_UI/uiElements/JFXTextAreaInfoDialog.java deleted file mode 100644 index fd8ff2f..0000000 --- a/src/main/java/com/cemu_UI/uiElements/JFXTextAreaInfoDialog.java +++ /dev/null @@ -1,98 +0,0 @@ -/** - * cemu_UI - * - * Copyright 2017 <@Seil0> - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -package com.cemu_UI.uiElements; - -import com.jfoenix.controls.JFXButton; -import com.jfoenix.controls.JFXDialog; -import com.jfoenix.controls.JFXDialogLayout; -import com.jfoenix.controls.JFXTextArea; - -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.Pane; -import javafx.scene.layout.StackPane; -import javafx.scene.text.Text; - -public class JFXTextAreaInfoDialog { - - private String headingText; - private String bodyText; - private String dialogBtnStyle; - private int dialogWidth; - private int dialogHeight; - private JFXTextArea textArea; - private Pane pane; - - /** - * Creates a new JFoenix Dialog to show some information - * @param headingText Heading Text, just the heading - * @param bodyText body Text, all other text belongs here - * @param dialogBtnStyle Style of the okay button - * @param dialogWidth dialog width - * @param dialogHeight dialog height - * @param pane pane to which the dialog belongs - */ - public JFXTextAreaInfoDialog(String headingText, String bodyText, String dialogBtnStyle, int dialogWidth, int dialogHeight, Pane pane) { - this.headingText = headingText; - this.bodyText = bodyText; - this.dialogBtnStyle = dialogBtnStyle; - this.dialogWidth = dialogWidth; - this.dialogHeight = dialogHeight; - this.pane = pane; - } - - public void show() { - textArea = new JFXTextArea(bodyText); - - JFXDialogLayout content = new JFXDialogLayout(); - content.setHeading(new Text(headingText)); - content.setBody(textArea); - content.setPrefSize(dialogWidth, dialogHeight); - StackPane stackPane = new StackPane(); - stackPane.autosize(); - JFXDialog dialog = new JFXDialog(stackPane, content, JFXDialog.DialogTransition.LEFT, true); - JFXButton button = new JFXButton("Okay"); - button.setOnAction(new EventHandler() { - @Override - public void handle(ActionEvent event) { - dialog.close(); - } - }); - button.setButtonType(com.jfoenix.controls.JFXButton.ButtonType.RAISED); - button.setPrefHeight(32); - button.setStyle(dialogBtnStyle); - content.setActions(button); - pane.getChildren().add(stackPane); - AnchorPane.setTopAnchor(stackPane, (pane.getHeight() - content.getPrefHeight()) / 2); - AnchorPane.setLeftAnchor(stackPane, (pane.getWidth() - content.getPrefWidth()) / 2); - dialog.show(); - } - - public JFXTextArea getTextArea() { - return textArea; - } - - public void setTextArea(JFXTextArea textArea) { - this.textArea = textArea; - } -} diff --git a/src/main/java/kellerkinder/HomeFlix/application/Main.java b/src/main/java/kellerkinder/HomeFlix/application/Main.java index 9d211f6..d9012c4 100644 --- a/src/main/java/kellerkinder/HomeFlix/application/Main.java +++ b/src/main/java/kellerkinder/HomeFlix/application/Main.java @@ -19,31 +19,31 @@ * MA 02110-1301, USA. * */ - package kellerkinder.HomeFlix.application; import java.io.File; import java.io.IOException; import java.util.Locale; -import java.util.Optional; import java.util.ResourceBundle; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.kellerkinder.Alerts.JFX2BtnCancelAlert; import javafx.application.Application; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; -import javafx.scene.control.Alert; -import javafx.scene.control.Alert.AlertType; -import javafx.scene.control.ButtonType; import javafx.scene.image.Image; import javafx.scene.layout.AnchorPane; import javafx.stage.DirectoryChooser; +import javafx.stage.FileChooser; import javafx.stage.Stage; +import javafx.stage.WindowEvent; public class Main extends Application { - + private Stage primaryStage; private Scene scene; private AnchorPane pane; @@ -54,30 +54,30 @@ public class Main extends Application { private static String osArch = System.getProperty("os.arch"); private static String osVers = System.getProperty("os.version"); private static String javaVers = System.getProperty("java.version"); - private static String javaVend= System.getProperty("java.vendor"); - private String dirWin = userHome + "/Documents/HomeFlix"; //Windows: C:/Users/"User"/Documents/HomeFlix - private String dirLinux = userHome + "/HomeFlix"; //Linux: /home/"User"/HomeFlix + private static String javaVend = System.getProperty("java.vendor"); + private static String local = System.getProperty("user.language") + "_" + System.getProperty("user.country"); + private String dirWin = userHome + "/Documents/HomeFlix"; // Windows: C:/Users/"User"/Documents/HomeFlix + private String dirLinux = userHome + "/HomeFlix"; // Linux: /home/"User"/HomeFlix private File directory; private File configFile; private File posterCache; - - private String path; - private String FONT_FAMILY = "System"; - private String local = System.getProperty("user.language")+"_"+System.getProperty("user.country"); - private double FONT_SIZE = 17; private ResourceBundle bundle; private static Logger LOGGER; - + @Override public void start(Stage primaryStage) throws IOException { LOGGER.info("OS: " + osName + " " + osVers + " " + osArch); LOGGER.info("Java: " + javaVend + " " + javaVers); LOGGER.info("User: " + userName + " " + userHome); - - this.primaryStage = primaryStage; + + this.primaryStage = primaryStage; mainWindow(); } - + + /** + * initialize the mainWindowController, GUI and load the saved settings or call addFirstSource + * initialize the primaryStage and set the file/directory paths + */ private void mainWindow(){ try { FXMLLoader loader = new FXMLLoader(); @@ -88,12 +88,18 @@ public class Main extends Application { primaryStage.setResizable(false); primaryStage.setTitle("Project HomeFlix"); primaryStage.getIcons().add(new Image(Main.class.getResourceAsStream("/icons/Homeflix_Icon_64x64.png"))); //adds application icon + primaryStage.setOnCloseRequest(new EventHandler() { + public void handle(WindowEvent we) { + System.exit(1); + } + }); + mainWindowController = loader.getController(); //Link of FXMLController and controller class mainWindowController.setMain(this); //call setMain // get OS and the specific paths - if (osName.equals("Windows")) { + if (osName.contains("Windows")) { directory = new File(dirWin); configFile = new File(dirWin + "/config.xml"); posterCache = new File(dirWin + "/posterCache"); @@ -103,33 +109,27 @@ public class Main extends Application { posterCache = new File(dirLinux + "/posterCache"); } - // startup checks - if (!configFile.exists()) { - directory.mkdir(); - mainWindowController.addSource(firstStart(), "local"); - mainWindowController.setColor("ee3523"); - mainWindowController.setSize(FONT_SIZE); - mainWindowController.setAutoUpdate(false); - mainWindowController.setLocal(local); - mainWindowController.saveSettings(); - try { - Runtime.getRuntime().exec("java -jar ProjectHomeFlix.jar"); // start again (preventing Bugs) TODO is this really needed - System.exit(0); // finishes it self - } catch (Exception e) { - LOGGER.error("error while restarting HomeFlix", e); - } - } - - if (!posterCache.exists()) { - posterCache.mkdir(); - } - // generate window scene = new Scene(pane); // create new scene, append pane to scene scene.getStylesheets().add(getClass().getResource("/css/MainWindow.css").toExternalForm()); primaryStage.setScene(scene); // append scene to stage primaryStage.show(); // show stage + // startup checks + if (!configFile.exists()) { + directory.mkdir(); + addFirstSource(); + mainWindowController.setColor("ee3523"); + mainWindowController.setFontSize(17.0); + mainWindowController.setAutoUpdate(false); + mainWindowController.setLocal(local); + mainWindowController.saveSettings(); + } + + if (!posterCache.exists()) { + posterCache.mkdir(); + } + // init here as it loads the games to the mwc and the gui, therefore the window must exist mainWindowController.init(); mainWindowController.getDbController().init(); @@ -137,10 +137,13 @@ public class Main extends Application { LOGGER.error(e); } } - - // Method for first Start - private String firstStart(){ - switch (System.getProperty("user.language") + "_" + System.getProperty("user.country")) { + + /** + * we need to get the path for the first source from the user and add it to + * sources.json, if the user ends the file-/directory-chooser the program will exit + */ + private void addFirstSource() { + switch (local) { case "en_US": bundle = ResourceBundle.getBundle("locals.HomeFlix-Local", Locale.US); // us_english break; @@ -152,30 +155,61 @@ public class Main extends Application { break; } - Alert alert = new Alert(AlertType.CONFIRMATION); //new alert with file-chooser - alert.setTitle("Project HomeFlix"); - alert.setHeaderText(bundle.getString("firstStartHeader")); - alert.setContentText(bundle.getString("firstStartContent")); + JFX2BtnCancelAlert selectFirstSource = new JFX2BtnCancelAlert(bundle.getString("addSourceHeader"), + bundle.getString("addSourceBody"), + "-fx-button-type: RAISED; -fx-background-color: #ee3523; -fx-text-fill: BLACK;", + bundle.getString("addDirectory"), bundle.getString("addStreamSource"), + bundle.getString("cancelBtnText"), primaryStage); - Optional result = alert.showAndWait(); - if (result.get() == ButtonType.OK){ - DirectoryChooser directoryChooser = new DirectoryChooser(); - File selectedDirectory = - directoryChooser.showDialog(primaryStage); - path = selectedDirectory.getAbsolutePath(); - - } else { - path = ""; - } - return path; + // directory action + EventHandler btn1Action = new EventHandler() { + @Override + public void handle(ActionEvent event) { + DirectoryChooser directoryChooser = new DirectoryChooser(); + directoryChooser.setTitle(bundle.getString("addDirectory")); + File selectedFolder = directoryChooser.showDialog(primaryStage); + if (selectedFolder != null && selectedFolder.exists()) { + mainWindowController.addSource(selectedFolder.getPath(), "local"); + selectFirstSource.getAlert().close(); + } else { + LOGGER.error("The selected folder dosen't exist!"); + System.exit(1); + } + } + }; + + // streaming action + EventHandler btn2Action = new EventHandler() { + @Override + public void handle(ActionEvent event) { + FileChooser fileChooser = new FileChooser(); + fileChooser.setTitle("addStreamSource"); + File selectedFile = fileChooser.showOpenDialog(getPrimaryStage()); + if (selectedFile != null && selectedFile.exists()) { + mainWindowController.addSource(selectedFile.getPath(), "stream"); + selectFirstSource.getAlert().close(); + } else { + LOGGER.error("The selected file dosen't exist!"); + System.exit(1); + } + } + }; + selectFirstSource.setBtn1Action(btn1Action); + selectFirstSource.setBtn2Action(btn2Action); + selectFirstSource.showAndWait(); } + /** + * set the log file location and initialize the logger + * launch the GUI + * @param args arguments given at the start + */ public static void main(String[] args) { - if(System.getProperty("os.name").equals("Windows")){ + if (System.getProperty("os.name").equals("Windows")) { System.setProperty("logFilename", userHome + "/Documents/HomeFlix/app.log"); File logFile = new File(userHome + "/Documents/HomeFlix/app.log"); logFile.delete(); - }else{ + } else { System.setProperty("logFilename", userHome + "/HomeFlix/app.log"); File logFile = new File(userHome + "/HomeFlix/app.log"); logFile.delete(); @@ -188,22 +222,10 @@ public class Main extends Application { return primaryStage; } - public void setPrimaryStage(Stage primaryStage) { - this.primaryStage = primaryStage; - } - - public AnchorPane getPane( ) { + public AnchorPane getPane() { return pane; } - public String getFONT_FAMILY() { - return FONT_FAMILY; - } - - public void setFONT_FAMILY(String FONT_FAMILY) { - this.FONT_FAMILY = FONT_FAMILY; - } - public File getDirectory() { return directory; } diff --git a/src/main/java/kellerkinder/HomeFlix/application/MainWindowController.java b/src/main/java/kellerkinder/HomeFlix/application/MainWindowController.java index 918c9e6..45cb8b0 100644 --- a/src/main/java/kellerkinder/HomeFlix/application/MainWindowController.java +++ b/src/main/java/kellerkinder/HomeFlix/application/MainWindowController.java @@ -1,6 +1,6 @@ /** * Project-HomeFlix - * + * * Copyright 2016-2018 <@Seil0> * * This program is free software; you can redistribute it and/or modify @@ -19,7 +19,6 @@ * MA 02110-1301, USA. * */ - package kellerkinder.HomeFlix.application; import java.awt.Desktop; @@ -33,19 +32,17 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.StringWriter; import java.io.Writer; import java.math.BigInteger; -import java.util.ArrayList; +import java.net.URLConnection; import java.util.Locale; import java.util.Properties; import java.util.ResourceBundle; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.kellerkinder.Alerts.JFXInfoAlert; -import com.cemu_UI.uiElements.JFXInfoDialog; import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonArray; import com.eclipsesource.json.JsonObject; @@ -65,8 +62,6 @@ import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.fxml.FXML; -import javafx.scene.control.Alert; -import javafx.scene.control.Alert.AlertType; import javafx.scene.control.ChoiceBox; import javafx.scene.control.ContextMenu; import javafx.scene.control.Label; @@ -74,7 +69,6 @@ import javafx.scene.control.MenuItem; import javafx.scene.control.ScrollPane; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; -import javafx.scene.control.TextArea; import javafx.scene.control.TreeItem; import javafx.scene.control.TreeTableColumn; import javafx.scene.control.TreeTableColumn.SortType; @@ -83,9 +77,7 @@ import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; -import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.text.Font; @@ -97,16 +89,18 @@ import kellerkinder.HomeFlix.controller.DBController; import kellerkinder.HomeFlix.controller.OMDbAPIController; import kellerkinder.HomeFlix.controller.UpdateController; import kellerkinder.HomeFlix.datatypes.SourceDataType; +import kellerkinder.HomeFlix.player.Player; import kellerkinder.HomeFlix.datatypes.FilmTabelDataType; public class MainWindowController { @FXML private AnchorPane mainAnchorPane; + @FXML + private AnchorPane tableModeAnchorPane; @FXML private ScrollPane settingsScrollPane; - @FXML private ScrollPane textScrollPane; @@ -127,82 +121,65 @@ public class MainWindowController { @FXML private JFXButton playbtn; - @FXML private JFXButton openfolderbtn; - @FXML private JFXButton returnBtn; - @FXML private JFXButton forwardBtn; - - @FXML - private JFXButton aboutBtn; - - @FXML - private JFXButton settingsBtn; - - @FXML - private JFXButton debugBtn; - - @FXML - public JFXButton updateBtn; - - @FXML - private JFXButton addDirectoryBtn; - - @FXML - private JFXButton addStreamSourceBtn; - - @FXML - private JFXHamburger menuHam; - - @FXML - private JFXToggleButton autoUpdateToggleBtn; - - @FXML - private JFXTextField searchTextField; - - @FXML - public JFXColorPicker colorPicker; - @FXML - public ChoiceBox languageChoisBox = new ChoiceBox<>(); + private JFXButton aboutBtn; + @FXML + private JFXButton settingsBtn; + @FXML + private JFXButton updateBtn; + @FXML + private JFXButton addDirectoryBtn; + @FXML + private JFXButton addStreamSourceBtn; + + @FXML + private JFXHamburger menuHam; @FXML - public ChoiceBox branchChoisBox = new ChoiceBox<>(); + private JFXToggleButton autoUpdateToggleBtn; + @FXML + private JFXToggleButton autoplayToggleBtn; @FXML - public JFXSlider fontsizeSlider; - - @FXML - private Label homeflixSettingsLbl; - - @FXML - private Label mainColorLbl; - + private JFXTextField searchTextField; + + @FXML + private JFXColorPicker colorPicker; + + @FXML + private ChoiceBox languageChoisBox = new ChoiceBox<>(); + @FXML + private ChoiceBox branchChoisBox = new ChoiceBox<>(); + + @FXML + private JFXSlider fontsizeSlider; + + @FXML + private Label homeflixSettingsLbl; + @FXML + private Label mainColorLbl; @FXML private Label fontsizeLbl; - - @FXML - private Label languageLbl; - + @FXML + private Label languageLbl; @FXML private Label updateLbl; - @FXML private Label branchLbl; - @FXML private Label sourcesLbl; - @FXML private Label versionLbl; - @FXML + @FXML private ImageView posterImageView; - private ImageView imv1; + private ImageView imv1; @FXML private TreeItem filmRoot = new TreeItem<>(new FilmTabelDataType("", "", "", "", false, false, imv1)); @@ -216,46 +193,44 @@ public class MainWindowController { private TreeTableColumn columnEpisode = new TreeTableColumn<>("Episode"); @FXML private TreeTableColumn columnFavorite = new TreeTableColumn<>("Favorite"); - - @FXML - private TreeItem sourceRoot =new TreeItem<>(new SourceDataType("", "")); - @FXML - private TableColumn sourceColumn; - @FXML - private TableColumn modeColumn; - + + @FXML + private TreeItem sourceRoot = new TreeItem<>(new SourceDataType("", "")); + @FXML + private TableColumn sourceColumn; + @FXML + private TableColumn modeColumn; + private boolean menuTrue = false; private boolean settingsTrue = false; private boolean autoUpdate = false; private boolean useBeta = false; - private static final Logger LOGGER = LogManager.getLogger(MainWindowController.class.getName()); + private boolean autoplay = false; + private static final Logger LOGGER = LogManager.getLogger(MainWindowController.class.getName()); private int hashA = -647380320; - - private String version = "0.6.0"; - private String buildNumber = "141"; - private String versionName = "plasma vampire"; + + private final String version = "0.7.0"; + private final String buildNumber = "151"; + private final String versionName = "toothless dragon"; private String dialogBtnStyle; private String color; - private String title; - private String streamUrl; - private String ratingSortType; private String local; private String omdbAPIKey; // text strings - private String errorPlay; private String errorLoad; private String errorSave; private String infoText; private String vlcNotInstalled; - public double size; + private double fontSize; private int last; private int indexTable; private int indexList; private int next; private ResourceBundle bundle; - + private FilmTabelDataType currentTableFilm = new FilmTabelDataType("", "", "", "", false, false, null); + private ObservableList languages = FXCollections.observableArrayList("English (en_US)", "Deutsch (de_DE)"); private ObservableList branches = FXCollections.observableArrayList("stable", "beta"); private ObservableList filterData = FXCollections.observableArrayList(); @@ -267,9 +242,8 @@ public class MainWindowController { private ImageView skip_next_black = new ImageView(new Image("icons/ic_skip_next_black_18dp_1x.png")); private ImageView play_arrow_white = new ImageView(new Image("icons/ic_play_arrow_white_18dp_1x.png")); private ImageView play_arrow_black = new ImageView(new Image("icons/ic_play_arrow_black_18dp_1x.png")); - private DirectoryChooser directoryChooser = new DirectoryChooser(); - private MenuItem like = new MenuItem("like"); - private MenuItem dislike = new MenuItem("dislike"); //TODO one option (like or dislike) + private MenuItem like = new MenuItem("like"); + private MenuItem dislike = new MenuItem("dislike"); // TODO one option (like or dislike) private ContextMenu menu = new ContextMenu(like, dislike); private Properties props = new Properties(); @@ -290,12 +264,14 @@ public class MainWindowController { omdbAPIController = new OMDbAPIController(this, dbController, this.main); } + // call all initialize methods void init() { + LOGGER.info("Initializing Project-HomeFlix build " + buildNumber); loadSettings(); checkAutoUpdate(); initTabel(); - initActions(); initUI(); + initActions(); } // Initialize the tables (treeTableViewfilm and sourcesTable) @@ -326,18 +302,18 @@ public class MainWindowController { filmsTreeTable.getColumns().add(columnFavorite); filmsTreeTable.getColumns().add(columnSeason); filmsTreeTable.getColumns().add(columnEpisode); - filmsTreeTable.getColumns().get(0).setVisible(false); //hide columnStreamUrl (important) - - // context menu for treeTableViewfilm + filmsTreeTable.getColumns().get(0).setVisible(false); // hide columnStreamUrl (important) + + // context menu for treeTableViewfilm filmsTreeTable.setContextMenu(menu); - - // sourcesTreeTable - sourceColumn.setCellValueFactory(cellData -> cellData.getValue().pathProperty()); - modeColumn.setCellValueFactory(cellData -> cellData.getValue().modeProperty()); - sourcesTable.setItems(sourcesList); + + // sourcesTreeTable + sourceColumn.setCellValueFactory(cellData -> cellData.getValue().pathProperty()); + modeColumn.setCellValueFactory(cellData -> cellData.getValue().modeProperty()); + sourcesTable.setItems(sourcesList); } - - //Initializing the actions + + // Initializing the actions private void initActions() { HamburgerBackArrowBasicTransition burgerTask = new HamburgerBackArrowBasicTransition(menuHam); @@ -364,7 +340,7 @@ public class MainWindowController { @Override public void changed(ObservableValue observable, String oldValue, String newValue) { ObservableList helpData; - filterData.removeAll(filterData); + filterData.clear(); filmRoot.getChildren().removeAll(filmRoot.getChildren()); helpData = filmsList; @@ -412,9 +388,9 @@ public class MainWindowController { fontsizeSlider.valueProperty().addListener(new ChangeListener() { @Override public void changed(ObservableValue ov, Number old_val, Number new_val) { - setSize(fontsizeSlider.getValue()); - if (title != null) { - dbController.readCache(streamUrl); + setFontSize(fontsizeSlider.getValue()); + if (!getCurrentTitle().isEmpty()) { + dbController.readCache(getCurrentStreamUrl()); } // ta1.setFont(Font.font("System", size)); saveSettings(); @@ -424,8 +400,8 @@ public class MainWindowController { like.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { - dbController.like(streamUrl); - dbController.refresh(streamUrl, indexList); + dbController.like(getCurrentStreamUrl()); + dbController.refresh(getCurrentStreamUrl(), indexList); refreshTable(); } }); @@ -433,59 +409,41 @@ public class MainWindowController { dislike.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { - dbController.dislike(streamUrl); - dbController.refresh(streamUrl, indexList); + dbController.dislike(getCurrentStreamUrl()); + dbController.refresh(getCurrentStreamUrl(), indexList); refreshTable(); } }); /** * FIXME fix bug when sort by ASCENDING, wrong order - * FIXME when sorting, series are expanded */ columnFavorite.sortTypeProperty().addListener(new ChangeListener() { @Override public void changed(ObservableValue paramObservableValue, SortType paramT1, SortType paramT2) { - LOGGER.info("NAME Clicked -- sortType = " + paramT1 + ", SortType=" + paramT2); - ArrayList fav_true = new ArrayList(); - ArrayList fav_false = new ArrayList(); - ObservableList helpData; - filterData.removeAll(filterData); -// treeTableViewfilm.getSelectionModel().clearSelection(selected); - filmRoot.getChildren().removeAll(filmRoot.getChildren()); - - helpData = filmsList; - - for (int i = 0; i < helpData.size(); i++) { - if (helpData.get(i).getFavorite() == true) { - fav_true.add(i); - } else { - fav_false.add(i); - } - } - if (paramT2.toString().equals("DESCENDING")) { - LOGGER.info("Absteigend"); // Debug, delete? - for (int i = 0; i < fav_true.size(); i++) { - filterData.add(helpData.get(fav_true.get(i))); - } - for (int i = 0; i < fav_false.size(); i++) { - filterData.add(helpData.get(fav_false.get(i))); + filmRoot.getChildren().clear(); + filterData.clear(); + + if (paramT2.equals(SortType.DESCENDING)) { + for (FilmTabelDataType film : filmsList) { + if (film.getFavorite()) { + filterData.add(0, film); + } else { + filterData.add(film); + } } } else { - for (int i = 0; i < fav_false.size(); i++) { - filterData.add(helpData.get(fav_false.get(i))); - } - for (int i = 0; i < fav_true.size(); i++) { - filterData.add(helpData.get(fav_true.get(i))); +// System.out.println("ascending"); + for (FilmTabelDataType film : filmsList) { + if (!film.getFavorite()) { + filterData.add(0, film); + } else { + filterData.add(film); + } } } - - LOGGER.info(filterData.size()); // Debug, delete? - for (int i = 0; i < filterData.size(); i++) { -// LOGGER.info(filterData.get(i).getTitle()+"; "+filterData.get(i).getRating()); // Debugging - // add filtered data to root node after search - filmRoot.getChildren().add(new TreeItem(filterData.get(i))); - } + + addDataUI(filterData); } }); @@ -493,22 +451,25 @@ public class MainWindowController { filmsTreeTable.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() { @Override public void changed(ObservableValue observable, Object oldVal, Object newVal) { - indexTable = filmsTreeTable.getSelectionModel().getSelectedIndex(); // get selected item - last = indexTable - 1; - next = indexTable + 1; - title = columnTitle.getCellData(indexTable); // get name of selected item - streamUrl = columnStreamUrl.getCellData(indexTable); // get file path of selected item + if (filmsTreeTable.getSelectionModel().getSelectedItem() == null) { + return; + } - for (FilmTabelDataType helpData : filmsList) { - if (helpData.getStreamUrl().equals(streamUrl)) { - indexList = filmsList.indexOf(helpData); + currentTableFilm = filmsTreeTable.getSelectionModel().getSelectedItem().getValue(); // set the current film object + indexTable = filmsTreeTable.getSelectionModel().getSelectedIndex(); // get selected items table index + for (FilmTabelDataType film : filmsList) { + if (film.equals(currentTableFilm)) { + indexList = filmsList.indexOf(film); // get selected items list index } } - if (filmsList.get(indexList).getCached()) { - LOGGER.info("loading from cache: " + title); - dbController.readCache(streamUrl); - } else { + last = indexTable - 1; + next = indexTable + 1; + + if (currentTableFilm.getCached() || dbController.searchCache(getCurrentStreamUrl())) { + LOGGER.info("loading from cache: " + getCurrentTitle()); + dbController.readCache(getCurrentStreamUrl()); + } else { omdbAPIController = new OMDbAPIController(mainWindowController, dbController, main); Thread omdbAPIThread = new Thread(omdbAPIController); omdbAPIThread.setName("OMDbAPI"); @@ -520,15 +481,13 @@ public class MainWindowController { // initialize UI elements private void initUI() { - debugBtn.setDisable(true); // debugging button for tests - debugBtn.setVisible(false); - versionLbl.setText("Version: " + version + " (Build: " + buildNumber + ")"); - fontsizeSlider.setValue(getSize()); + fontsizeSlider.setValue(getFontSize()); colorPicker.setValue(Color.valueOf(getColor())); updateBtn.setFont(Font.font("System", 12)); autoUpdateToggleBtn.setSelected(isAutoUpdate()); + autoplayToggleBtn.setSelected(isAutoplay()); languageChoisBox.setItems(languages); branchChoisBox.setItems(branches); @@ -544,48 +503,67 @@ public class MainWindowController { @FXML private void playbtnclicked() { - // TODO rework when #19 is coming - - if (System.getProperty("os.name").contains("Linux")) { - String line; - String output = ""; - Process p; - try { - p = Runtime.getRuntime().exec("which vlc"); - BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream())); - while ((line = input.readLine()) != null) { - output = line; - } - LOGGER.info(output); - input.close(); - } catch (IOException e1) { - e1.printStackTrace(); - } - if (output.contains("which: no vlc") || output == "") { - JFXInfoDialog vlcInfoDialog = new JFXInfoDialog("Info", vlcNotInstalled, dialogBtnStyle, 350, 200, main.getPane()); - vlcInfoDialog.show(); - } else { - try { - Runtime.getRuntime().exec(new String[] { "vlc", streamUrl }); // TODO switch to ProcessBuilder - } catch (IOException e) { - showErrorMsg(errorPlay, e); - } - } - - } else if (System.getProperty("os.name").contains("Windows") || System.getProperty("os.name").contains("Mac OS X")) { - try { - Desktop.getDesktop().open(new File(streamUrl)); - } catch (IOException e) { - showErrorMsg(errorPlay, e); - } - } else { - LOGGER.error(System.getProperty("os.name") + ", OS is not supported, please contact a developer! "); + if (currentTableFilm.getStreamUrl().contains("_rootNode")) { + LOGGER.info("rootNode found, getting last watched episode"); + currentTableFilm = dbController.getLastWatchedEpisode(currentTableFilm.getTitle()); } + + if (isSupportedFormat(currentTableFilm)) { + new Player(mainWindowController); + } else { + LOGGER.error("using fallback player!"); + if (System.getProperty("os.name").contains("Linux")) { + String line; + String output = ""; + Process p; + try { + p = Runtime.getRuntime().exec("which vlc"); + BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream())); + while ((line = input.readLine()) != null) { + output = line; + } + LOGGER.info(output); + input.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + if (output.contains("which: no vlc") || output == "") { + JFXInfoAlert vlcInfoAlert = new JFXInfoAlert("Info", vlcNotInstalled, dialogBtnStyle, main.getPrimaryStage()); + vlcInfoAlert.showAndWait(); + } else { + try { + new ProcessBuilder("vlc", getCurrentStreamUrl()).start(); + } catch (IOException e) { + LOGGER.warn("An error has occurred while opening the file!", e); + } + } + + } else if (System.getProperty("os.name").contains("Windows") || System.getProperty("os.name").contains("Mac OS X")) { + try { + Desktop.getDesktop().open(new File(getCurrentStreamUrl())); + } catch (IOException e) { + LOGGER.warn("An error has occurred while opening the file!", e); + } + } else { + LOGGER.error(System.getProperty("os.name") + ", OS is not supported, please contact a developer! "); + } + } + } + + /** + * check if a film is supported by the HomeFlixPlayer or not + * this is the case if the mime type is mp4 + * @param entry the film you want to check + * @return true if so, false if not + */ + private boolean isSupportedFormat(FilmTabelDataType film) { + String mimeType = URLConnection.guessContentTypeFromName(film.getStreamUrl()); + return mimeType != null && (mimeType.contains("mp4") || mimeType.contains("vp6")); } @FXML private void openfolderbtnclicked() { - String dest = new File(streamUrl).getParentFile().getAbsolutePath(); + String dest = new File(getCurrentStreamUrl()).getParentFile().getAbsolutePath(); if (!System.getProperty("os.name").contains("Linux")) { try { Desktop.getDesktop().open(new File(dest)); @@ -609,8 +587,8 @@ public class MainWindowController { private void aboutBtnAction() { String bodyText = "cemu_UI by @Seil0 \nVersion: " + version + " (Build: " + buildNumber + ") \"" + versionName + "\" \n" + infoText; - JFXInfoDialog aboutDialog = new JFXInfoDialog("Project HomeFlix", bodyText, dialogBtnStyle, 350, 200, main.getPane()); - aboutDialog.show(); + JFXInfoAlert infoAlert = new JFXInfoAlert("Project HomeFlix", bodyText, dialogBtnStyle, main.getPrimaryStage()); + infoAlert.showAndWait(); } @FXML @@ -625,17 +603,13 @@ public class MainWindowController { } } - @FXML - private void debugBtnclicked(){ - //for testing - } - @FXML private void addDirectoryBtnAction(){ - File selectedFolder = directoryChooser.showDialog(null); + DirectoryChooser directoryChooser = new DirectoryChooser(); + directoryChooser.setTitle(bundle.getString("addDirectory")); + File selectedFolder = directoryChooser.showDialog(main.getPrimaryStage()); if (selectedFolder != null && selectedFolder.exists()) { - addSource(selectedFolder.getPath(), "local"); - dbController.refreshDataBase(); + mainWindowController.addSource(selectedFolder.getPath(), "local"); } else { LOGGER.error("The selected folder dosen't exist!"); } @@ -644,7 +618,7 @@ public class MainWindowController { @FXML private void addStreamSourceBtnAction(){ FileChooser fileChooser = new FileChooser(); - fileChooser.setTitle("Open Resource File"); + fileChooser.setTitle("addStreamSource"); File selectedFile = fileChooser.showOpenDialog(main.getPrimaryStage()); if (selectedFile != null && selectedFile.exists()) { addSource(selectedFile.getPath(), "stream"); @@ -670,7 +644,7 @@ public class MainWindowController { @FXML private void autoUpdateToggleBtnAction(){ - if (autoUpdate) { + if (isAutoUpdate()) { setAutoUpdate(false); } else { setAutoUpdate(true); @@ -678,6 +652,16 @@ public class MainWindowController { saveSettings(); } + @FXML + private void autoplayToggleBtnAction(){ + if (isAutoplay()) { + setAutoplay(false); + } else { + setAutoplay(true); + } + saveSettings(); + } + // refresh the selected child of the root node private void refreshTable() { filmRoot.getChildren().get(indexTable).setValue(filmsList.get(indexList)); @@ -686,32 +670,32 @@ public class MainWindowController { /** * add data from films-list to films-table */ - public void addDataUI() { + public void addDataUI(ObservableList elementsList) { - for (FilmTabelDataType element : filmsList) { + for (FilmTabelDataType element : elementsList) { // only if the entry contains a season and a episode it's a valid series if (!element.getSeason().isEmpty() && !element.getEpisode().isEmpty()) { -// System.out.println("Found Series: " + element.getTitle()); - // check if there is a series node to add the item + + // check if there is a series node to add the item for (int i = 0; i < filmRoot.getChildren().size(); i++) { if (filmRoot.getChildren().get(i).getValue().getTitle().equals(element.getTitle())) { -// System.out.println("Found a root node to add child"); -// System.out.println("Adding: " + element.getStreamUrl()); - TreeItem episodeNode = new TreeItem<>(new FilmTabelDataType(element.getStreamUrl(), - element.getTitle(), element.getSeason(), element.getEpisode(), element.getFavorite(), - element.getCached(), element.getImage())); + // if a root node exists, add element as child + TreeItem episodeNode = new TreeItem<>(new FilmTabelDataType( + element.getStreamUrl(), element.getTitle(), element.getSeason(), element.getEpisode(), + element.getFavorite(), element.getCached(), element.getImage())); filmRoot.getChildren().get(i).getChildren().add(episodeNode); - } else if (i == filmRoot.getChildren().size() - 1) { -// System.out.println("Create a root node to add child"); -// System.out.println("Adding: " + element.getStreamUrl()); - TreeItem seriesRootNode = new TreeItem<>(new FilmTabelDataType(element.getStreamUrl(), - element.getTitle(), "", "", element.getFavorite(), element.getCached(), element.getImage())); + } else if (filmRoot.getChildren().get(i).nextSibling() == null) { + // if no root node exists, create one and add element as child + TreeItem seriesRootNode = new TreeItem<>(new FilmTabelDataType( + element.getTitle() + "_rootNode", element.getTitle(), "", "", element.getFavorite(), + false, element.getImage())); filmRoot.getChildren().add(seriesRootNode); } } } else { - filmRoot.getChildren().add(new TreeItem(element)); // add data to root-node + // if season and episode are empty, we can assume the object is a film + filmRoot.getChildren().add(new TreeItem(element)); } } } @@ -729,12 +713,17 @@ public class MainWindowController { try { // read old array - newsources = Json.parse(new FileReader(main.getDirectory() + "/sources.json")).asArray(); + File oldSources = new File(main.getDirectory() + "/sources.json"); + if (oldSources.exists()) { + newsources = Json.parse(new FileReader(main.getDirectory() + "/sources.json")).asArray(); + } else { + newsources = Json.array(); + } // add new source - Writer writer = new FileWriter(main.getDirectory() + "/sources.json"); source = Json.object().add("path", path).add("mode", mode); newsources.add(source); + Writer writer = new FileWriter(main.getDirectory() + "/sources.json"); newsources.writeTo(writer); writer.close(); } catch (IOException e) { @@ -742,23 +731,25 @@ public class MainWindowController { } } - //set color of UI-Elements + /** + * set the color of the GUI-Elements + * if usedColor is less than checkColor set text fill white, else black + */ private void applyColor() { String style = "-fx-background-color: #" + getColor() + ";"; String btnStyleBlack = "-fx-button-type: RAISED; -fx-background-color: #" + getColor() + "; -fx-text-fill: BLACK;"; String btnStyleWhite = "-fx-button-type: RAISED; -fx-background-color: #" + getColor() + "; -fx-text-fill: WHITE;"; - BigInteger icolor = new BigInteger(getColor(), 16); - BigInteger ccolor = new BigInteger("78909cff", 16); + BigInteger usedColor = new BigInteger(getColor(), 16); + BigInteger checkColor = new BigInteger("78909cff", 16); sideMenuVBox.setStyle(style); topHBox.setStyle(style); searchTextField.setFocusColor(Color.valueOf(getColor())); - if (icolor.compareTo(ccolor) == -1) { + if (usedColor.compareTo(checkColor) == -1) { dialogBtnStyle = btnStyleWhite; settingsBtn.setStyle("-fx-text-fill: WHITE;"); aboutBtn.setStyle("-fx-text-fill: WHITE;"); - debugBtn.setStyle("-fx-text-fill: WHITE;"); addDirectoryBtn.setStyle(btnStyleWhite); addStreamSourceBtn.setStyle(btnStyleWhite); updateBtn.setStyle(btnStyleWhite); @@ -774,7 +765,6 @@ public class MainWindowController { dialogBtnStyle = btnStyleBlack; settingsBtn.setStyle("-fx-text-fill: BLACK;"); aboutBtn.setStyle("-fx-text-fill: BLACK;"); - debugBtn.setStyle("-fx-text-fill: BLACK;"); addDirectoryBtn.setStyle(btnStyleBlack); addStreamSourceBtn.setStyle(btnStyleBlack); updateBtn.setStyle(btnStyleBlack); @@ -806,6 +796,9 @@ public class MainWindowController { translateTransition.play(); } + /** + * set the local based on the languageChoisBox selection + */ void setLocalUI() { switch (getLocal()) { case "en_US": @@ -833,72 +826,45 @@ public class MainWindowController { fontsizeLbl.setText(getBundle().getString("fontsizeLbl")); languageLbl.setText(getBundle().getString("languageLbl")); autoUpdateToggleBtn.setText(getBundle().getString("autoUpdate")); + autoplayToggleBtn.setText(getBundle().getString("autoplay")); branchLbl.setText(getBundle().getString("branchLbl")); columnStreamUrl.setText(getBundle().getString("columnStreamUrl")); columnTitle.setText(getBundle().getString("columnName")); columnSeason.setText(getBundle().getString("columnSeason")); columnEpisode.setText(getBundle().getString("columnEpisode")); columnFavorite.setText(getBundle().getString("columnFavorite")); - errorPlay = getBundle().getString("errorPlay"); errorLoad = getBundle().getString("errorLoad"); errorSave = getBundle().getString("errorSave"); infoText = getBundle().getString("infoText"); vlcNotInstalled = getBundle().getString("vlcNotInstalled"); } - // TODO remove after #19 has landed - public void showErrorMsg(String msg, Exception exception) { - Alert alert = new Alert(AlertType.ERROR); - alert.setTitle("Error"); - alert.setHeaderText(""); - alert.setContentText(msg); - alert.initOwner(main.getPrimaryStage()); - - // Create expandable Exception. - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - exception.printStackTrace(pw); - String exceptionText = sw.toString(); - - TextArea textArea = new TextArea(exceptionText); - textArea.setEditable(false); - textArea.setWrapText(true); - - textArea.setMaxWidth(Double.MAX_VALUE); - textArea.setMaxHeight(Double.MAX_VALUE); - GridPane.setVgrow(textArea, Priority.ALWAYS); - GridPane.setHgrow(textArea, Priority.ALWAYS); - - GridPane expContent = new GridPane(); - expContent.setMaxWidth(Double.MAX_VALUE); - expContent.add(textArea, 0, 1); - - // Set expandable Exception into the dialog pane. - alert.getDialogPane().setExpandableContent(expContent); - alert.showAndWait(); - LOGGER.error("An error occurred", exception); - } - - // save settings + /** + * save the configuration to the config.xml file + */ public void saveSettings() { LOGGER.info("saving settings ..."); try { props.setProperty("color", getColor()); props.setProperty("autoUpdate", String.valueOf(isAutoUpdate())); props.setProperty("useBeta", String.valueOf(isUseBeta())); - props.setProperty("size", getSize().toString()); + props.setProperty("autoplay", String.valueOf(isAutoplay())); + props.setProperty("size", getFontSize().toString()); props.setProperty("local", getLocal()); props.setProperty("ratingSortType", columnFavorite.getSortType().toString()); OutputStream outputStream = new FileOutputStream(main.getConfigFile()); // new output-stream - props.storeToXML(outputStream, "Project HomeFlix settings"); // writes new .xml + props.storeToXML(outputStream, "Project HomeFlix settings"); // write new .xml outputStream.close(); } catch (IOException e) { LOGGER.error(errorLoad, e); } } - // load settings + /** + * load the configuration from the config.xml file + * and try to load the API keys from apiKeys.json + */ public void loadSettings() { LOGGER.info("loading settings ..."); @@ -914,10 +880,10 @@ public class MainWindowController { } try { - setSize(Double.parseDouble(props.getProperty("size"))); + setFontSize(Double.parseDouble(props.getProperty("size"))); } catch (Exception e) { LOGGER.error("cloud not load fontsize", e); - setSize(17.0); + setFontSize(17.0); } try { @@ -933,6 +899,13 @@ public class MainWindowController { LOGGER.error("cloud not load autoUpdate", e); setUseBeta(false); } + + try { + setAutoplay(Boolean.parseBoolean(props.getProperty("autoplay"))); + } catch (Exception e) { + LOGGER.error("cloud not load autoplay", e); + setAutoplay(false); + } try { setLocal(props.getProperty("local")); @@ -941,13 +914,6 @@ public class MainWindowController { setLocal(System.getProperty("user.language") + "_" + System.getProperty("user.country")); } - try { - setRatingSortType(props.getProperty("ratingSortType")); - } catch (Exception e) { - LOGGER.error("cloud not load autoUpdate", e); - setRatingSortType(""); - } - inputStream.close(); } catch (IOException e) { LOGGER.error(errorSave, e); @@ -956,9 +922,15 @@ public class MainWindowController { // try loading the omdbAPI key try { InputStream in = getClass().getClassLoader().getResourceAsStream("apiKeys.json"); - BufferedReader reader = new BufferedReader(new InputStreamReader(in)); - JsonObject apiKeys = Json.parse(reader).asObject(); - omdbAPIKey = apiKeys.getString("omdbAPIKey", ""); + if (in != null) { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + JsonObject apiKeys = Json.parse(reader).asObject(); + omdbAPIKey = apiKeys.getString("omdbAPIKey", ""); + reader.close(); + in.close(); + } else { + LOGGER.warn("Cloud not load apiKeys.json. No such file"); + } } catch (Exception e) { LOGGER.error("Cloud not load the omdbAPI key. Please contact the developer!", e); } @@ -1001,21 +973,25 @@ public class MainWindowController { public String getColor() { return color; } - - public String getTitle() { - return title; + + public FilmTabelDataType getCurrentTableFilm() { + return currentTableFilm; } - public String getStreamUrl() { - return streamUrl; + public String getCurrentTitle() { + return currentTableFilm.getTitle(); } - public void setSize(Double input) { - this.size = input; + public String getCurrentStreamUrl() { + return currentTableFilm.getStreamUrl(); } - public Double getSize() { - return size; + public void setFontSize(Double input) { + this.fontSize = input; + } + + public Double getFontSize() { + return fontSize; } public int getIndexTable() { @@ -1041,6 +1017,14 @@ public class MainWindowController { public void setUseBeta(boolean useBeta) { this.useBeta = useBeta; } + + public boolean isAutoplay() { + return autoplay; + } + + public void setAutoplay(boolean autoplay) { + this.autoplay = autoplay; + } public void setLocal(String input) { this.local = input; @@ -1062,14 +1046,6 @@ public class MainWindowController { return sourcesList; } - public String getRatingSortType() { - return ratingSortType; - } - - public void setRatingSortType(String ratingSortType) { - this.ratingSortType = ratingSortType; - } - public ResourceBundle getBundle() { return bundle; } diff --git a/src/main/java/kellerkinder/HomeFlix/controller/DBController.java b/src/main/java/kellerkinder/HomeFlix/controller/DBController.java index 36fd8fc..8ef2aac 100644 --- a/src/main/java/kellerkinder/HomeFlix/controller/DBController.java +++ b/src/main/java/kellerkinder/HomeFlix/controller/DBController.java @@ -18,13 +18,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ - package kellerkinder.HomeFlix.controller; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; +import java.net.URLConnection; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; @@ -53,12 +53,7 @@ import kellerkinder.HomeFlix.datatypes.SourceDataType; import kellerkinder.HomeFlix.datatypes.FilmTabelDataType; public class DBController { - - public DBController(Main main, MainWindowController mainWindowController) { - this.main = main; - this.mainWindowController = mainWindowController; - } - + private MainWindowController mainWindowController; private Main main; private String DB_PATH = System.getProperty("user.home") + "\\Documents\\HomeFlix" + "\\" + "Homeflix.db"; //path to database file @@ -71,6 +66,22 @@ public class DBController { private Connection connection = null; private static final Logger LOGGER = LogManager.getLogger(DBController.class.getName()); + /** + * constructor for DBController + * @param main the Main object + * @param mainWindowController the MainWindowController object + */ + public DBController(Main main, MainWindowController mainWindowController) { + this.main = main; + this.mainWindowController = mainWindowController; + } + + /** + * initialize the {@link DBController} + * initialize the database connection + * check if there is a need to create a new database + * refresh the database + */ public void init() { LOGGER.info("<========== starting loading sql ==========>"); initDatabaseConnection(); @@ -79,12 +90,16 @@ public class DBController { LOGGER.info("<========== finished loading sql ==========>"); } + /** + * create a new connection to the HomeFlix.db database + * AutoCommit is set to false to prevent some issues, so manual commit is active! + */ private void initDatabaseConnection() { DB_PATH = main.getDirectory() + "/Homeflix.db"; try { // create a database connection connection = DriverManager.getConnection("jdbc:sqlite:" + DB_PATH); - connection.setAutoCommit(false); //AutoCommit to false -> manual commit is active + connection.setAutoCommit(false); } catch (SQLException e) { // if the error message is "out of memory", it probably means no database file is found LOGGER.error("error while loading the ROM database", e); @@ -94,12 +109,13 @@ public class DBController { /** * if tables don't exist create them + * films table: streamUrl is primary key * cache table: streamUrl is primary key */ private void createDatabase() { try { Statement stmt = connection.createStatement(); - stmt.executeUpdate("create table if not exists films (streamUrl, title, season, episode, favorite, cached)"); + stmt.executeUpdate("create table if not exists films (streamUrl, title, season, episode, favorite, cached, currentTime)"); stmt.executeUpdate("create table if not exists cache (" + "streamUrl, Title, Year, Rated, Released, Runtime, Genre, Director, Writer," + " Actors, Plot, Language, Country, Awards, Metascore, imdbRating, imdbVotes," @@ -110,6 +126,9 @@ public class DBController { } } + /** + * get all database entries + */ private void loadDatabase() { // get all entries from the table try { @@ -131,7 +150,11 @@ public class DBController { LOGGER.info("filme in db: " + filmsdbStreamURL.size()); } - // load the sources from sources.json + /** + * load sources from sources.json + * if mode == local, get all files and series-folder from the directory + * else mode must be streaming, read all entries from the streaming file + */ private void loadSources() { // remove sources from table mainWindowController.getSourcesList().removeAll(mainWindowController.getSourcesList()); @@ -145,10 +168,9 @@ public class DBController { mainWindowController.addSourceToTable(path, mode); // add source to source-table if (mode.equals("local")) { for (File file : new File(path).listFiles()) { - if (file.isFile()) { - // get all files (films) + if (file.isFile() && isVideoFile(file.getPath())) { filmsStreamURL.add(file.getPath()); - } else { + } else if(file.isDirectory()) { // get all folders (series) for (File season : file.listFiles()) { if (season.isDirectory()) { @@ -181,7 +203,10 @@ public class DBController { } } - // loading data from database to mainWindowController + /** + * load the data to the mainWindowController + * order entries by title + */ private void loadDataToMWC() { LOGGER.info("loading data to mwc ..."); try { @@ -207,11 +232,11 @@ public class DBController { } LOGGER.info("loading data to the GUI ..."); - mainWindowController.addDataUI(); + mainWindowController.addDataUI(mainWindowController.getFilmsList()); } /** - * refresh data in mainWindowController localFilms and streamingFilms + * refresh data in mainWindowController for one element * @param streamUrl of the film * @param index of the film in LocalFilms list */ @@ -221,16 +246,17 @@ public class DBController { Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM films WHERE streamUrl = \"" + streamUrl + "\";"); - if (rs.getBoolean("favorite") == true) { - mainWindowController.getFilmsList().set(indexList, new FilmTabelDataType(rs.getString("streamUrl"), - rs.getString("title"), rs.getString("season"), rs.getString("episode"), rs.getBoolean("favorite"), - rs.getBoolean("cached"), new ImageView(favorite_black))); - } else { - mainWindowController.getFilmsList().set(indexList, new FilmTabelDataType(rs.getString("streamUrl"), - rs.getString("title"), rs.getString("season"), rs.getString("episode"), rs.getBoolean("favorite"), - rs.getBoolean("cached"), new ImageView(favorite_border_black))); + while (rs.next()) { + if (rs.getBoolean("favorite") == true) { + mainWindowController.getFilmsList().set(indexList, new FilmTabelDataType(rs.getString("streamUrl"), + rs.getString("title"), rs.getString("season"), rs.getString("episode"), rs.getBoolean("favorite"), + rs.getBoolean("cached"), new ImageView(favorite_black))); + } else { + mainWindowController.getFilmsList().set(indexList, new FilmTabelDataType(rs.getString("streamUrl"), + rs.getString("title"), rs.getString("season"), rs.getString("episode"), rs.getBoolean("favorite"), + rs.getBoolean("cached"), new ImageView(favorite_border_black))); + } } - rs.close(); stmt.close(); } catch (Exception e) { @@ -247,15 +273,14 @@ public class DBController { LOGGER.info("refreshing the Database ..."); // clean all ArraLists - filmsdbAll.removeAll(filmsdbAll); - filmsdbDir.removeAll(filmsdbDir); - filmsdbStreamURL.removeAll(filmsdbStreamURL); - filmsStreamURL.removeAll(filmsStreamURL); + filmsdbAll.clear(); + filmsdbDir.clear(); + filmsdbStreamURL.clear(); + filmsStreamURL.clear(); loadSources(); // reload all sources loadDatabase(); // reload all films saved in the DB - try { checkAddEntry(); checkRemoveEntry(); @@ -275,14 +300,12 @@ public class DBController { */ private void checkRemoveEntry() { LOGGER.info("checking for entrys to remove to DB ..."); - try { Statement stmt = connection.createStatement(); for (String entry : filmsdbStreamURL) { + // if the directory doen't contain the entry form the db, remove it if (!filmsStreamURL.contains(entry)) { - System.out.println(filmsdbStreamURL + "\n"); - System.out.println(filmsStreamURL); stmt.executeUpdate("delete from films where streamUrl = \"" + entry + "\""); connection.commit(); LOGGER.info("removed \"" + entry + "\" from database"); @@ -303,7 +326,7 @@ public class DBController { */ private void checkAddEntry() throws SQLException, FileNotFoundException, IOException { Statement stmt = connection.createStatement(); - PreparedStatement ps = connection.prepareStatement("insert into films values (?, ?, ?, ?, ?, ?)"); + PreparedStatement ps = connection.prepareStatement("insert into films values (?, ?, ?, ?, ?, ?, ?)"); LOGGER.info("checking for entrys to add to DB ..."); // source is a single source of the sources list @@ -311,19 +334,20 @@ public class DBController { // if it's a local source check the folder for new film if (source.getMode().equals("local")) { for (File file : new File(source.getPath()).listFiles()) { - - if (file.isFile()) { + String mimeType = URLConnection.guessContentTypeFromName(file.getPath()); + // if file is file and has mime type "video" + if (file.isFile() && mimeType != null && mimeType.contains("video")) { // get all files (films) if (!filmsdbStreamURL.contains(file.getPath())) { stmt.executeUpdate("insert into films values (" + "'" + file.getPath() + "'," - + "'" + cutOffEnd(file.getName()) + "', '', '', 0, 0)"); + + "'" + cutOffEnd(file.getName()) + "', '', '', 0, 0, 0.0)"); connection.commit(); stmt.close(); LOGGER.info("Added \"" + file.getName() + "\" to database"); filmsdbStreamURL.add(file.getPath()); } - } else { + } else if (file.isDirectory()) { // get all folders (series) int sn = 1; for (File season : file.listFiles()) { @@ -333,8 +357,8 @@ public class DBController { if (!filmsdbStreamURL.contains(episode.getPath())) { LOGGER.info("Added \"" + file.getName() + "\", Episode: " + episode.getName() + " to database"); stmt.executeUpdate("insert into films values (" - + "'" + episode.getPath() + "'," - + "'" + cutOffEnd(file.getName()) + "','" + sn + "','" + ep + "', 0, 0)"); + + "'" + episode.getPath().replace("'", "''") + "'," + + "'" + cutOffEnd(file.getName()) + "','" + sn + "','" + ep + "', 0, 0, 0.0)"); connection.commit(); stmt.close(); filmsStreamURL.add(episode.getPath()); @@ -366,6 +390,7 @@ public class DBController { ps.setString(4, item.asObject().getString("episode", "")); ps.setInt(5, 0); ps.setBoolean(6, false); + ps.setDouble(7, 0); ps.addBatch(); // adds the entry LOGGER.info("Added \"" + title + "\" to database"); filmsdbStreamURL.add(streamUrl); @@ -380,7 +405,10 @@ public class DBController { } } - // prints all entries from the database to the console + /** + * DEBUG + * prints all entries from the database to the console + */ public void printAllDBEntriesDEBUG() { System.out.println("Outputting all entries ... \n"); try { @@ -392,7 +420,8 @@ public class DBController { System.out.println(rs.getString("season")); System.out.println(rs.getString("episode")); System.out.println(rs.getString("rating")); - System.out.println(rs.getString("cached") + "\n"); + System.out.println(rs.getString("cached")); + System.out.println(rs.getString("currentTime") + "\n"); } stmt.close(); rs.close(); @@ -513,19 +542,39 @@ public class DBController { } } + /** + * checks if there is already a entry with the given streamUrl in the cache + * @param streamUrl URL of the element + * @return true if the element is already cached, else false + */ + public boolean searchCache(String streamUrl) { + boolean retValue = false; + try { + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM cache WHERE streamUrl = \"" + streamUrl + "\";"); + retValue = rs.next(); + rs.close(); + stmt.close(); + } catch (Exception e) { + LOGGER.error("Ups! error while getting the current time!", e); + } + + return retValue; + } + /** * sets the cached data to mwc's TextFlow * @param streamUrl URL of the film */ public void readCache(String streamUrl) { try { + Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM cache WHERE streamUrl=\"" + streamUrl + "\";"); ArrayList nameText = new ArrayList(); ArrayList responseText = new ArrayList(); - String fontFamily = main.getFONT_FAMILY(); Image im; - int fontSize = (int) Math.round(mainWindowController.size); + int fontSize = (int) Math.round(mainWindowController.getFontSize()); int j = 2; nameText.add(0, new Text(mainWindowController.getBundle().getString("title") + ": ")); @@ -549,6 +598,7 @@ public class DBController { responseText.add(new Text(rs.getString(j) + "\n")); j++; } + responseText.add(new Text(rs.getString(19) + "\n")); im = new Image(new File(rs.getString(20)).toURI().toString()); @@ -556,8 +606,8 @@ public class DBController { rs.close(); for (int i = 0; i < nameText.size(); i++) { - nameText.get(i).setFont(Font.font(fontFamily, FontWeight.BOLD, fontSize)); - responseText.get(i).setFont(Font.font(fontFamily, fontSize)); + nameText.get(i).setFont(Font.font("System", FontWeight.BOLD, fontSize)); + responseText.get(i).setFont(Font.font("System", fontSize)); } mainWindowController.getTextFlow().getChildren().remove(0, @@ -579,6 +629,154 @@ public class DBController { } } + /** + * return the currentTime in ms saved in the database + * @param streamUrl URL of the film + * @return {@link Double} currentTime in ms + */ + public double getCurrentTime(String streamUrl) { + LOGGER.info("currentTime: " + streamUrl); + double currentTime = 0; + try { + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM films WHERE streamUrl = \"" + streamUrl + "\";"); + currentTime = rs.getDouble("currentTime"); + rs.close(); + stmt.close(); + } catch (Exception e) { + LOGGER.error("Ups! error while getting the current time!", e); + } + + return currentTime; + } + + /** + * save the currentTime to the database + * @param streamUrl URL of the film + * @param currentTime currentTime in ms of the film + */ + public void setCurrentTime(String streamUrl, double currentTime) { + LOGGER.info("currentTime: " + streamUrl); + try { + Statement stmt = connection.createStatement(); + stmt.executeUpdate("UPDATE films SET currentTime=" + currentTime + " WHERE streamUrl=\"" + streamUrl + "\";"); + connection.commit(); + stmt.close(); + } catch (SQLException e) { + LOGGER.error("Ups! an error occured!", e); + } + } + + /** + * get the next episode of a + * @param title URL of the film + * @param nextEp number of the next episode + * @return {@link FilmTabelDataType} the next episode as object + */ + public FilmTabelDataType getNextEpisode(String title, int episode, int season) { + FilmTabelDataType nextFilm = null; + ResultSet rs; + int nextEpisode = 3000; + + try { + Statement stmt = connection.createStatement(); + + rs = stmt.executeQuery("SELECT * FROM films WHERE title = \"" + title + "\" AND season = \"" + season + "\";"); + while(rs.next()) { + int rsEpisode = Integer.parseInt(rs.getString("episode")); + if (rsEpisode > episode && rsEpisode < nextEpisode) { + // fitting episode found in current season, if rsEpisode < nextEpisode -> nextEpisode = rsEpisode + nextEpisode = rsEpisode; + System.out.println("next episode is: " + nextEpisode); + // favorite image is black + nextFilm = new FilmTabelDataType(rs.getString("streamUrl"), rs.getString("title"), + rs.getString("season"), rs.getString("episode"), rs.getBoolean("favorite"), + rs.getBoolean("cached"), new ImageView(favorite_black)); + } + } + + if (nextFilm == null) { + int nextSeason = 3000; + System.out.println("searching next season"); + rs = stmt.executeQuery("SELECT * FROM films WHERE title = \"" + title + "\";"); + while(rs.next()) { + int rsSeason = Integer.parseInt(rs.getString("season")); + if (rsSeason > season && rsSeason < nextSeason) { + nextSeason = rsSeason; + } + } + + if (nextSeason != 3000) { + System.out.println("next season is: " + nextSeason); + rs = stmt.executeQuery("SELECT * FROM films WHERE title = \"" + title + "\" AND season = \"" + season + "\";"); + while(rs.next()) { + int rsEpisode = Integer.parseInt(rs.getString("episode")); + if (rsEpisode > episode && rsEpisode < nextEpisode) { + // fitting episode found in current season, if rsEpisode < nextEpisode -> nextEpisode = rsEpisode + nextEpisode = rsEpisode; + System.out.println("next episode is: " + nextEpisode); + // favorite image is black + nextFilm = new FilmTabelDataType(rs.getString("streamUrl"), rs.getString("title"), + rs.getString("season"), rs.getString("episode"), rs.getBoolean("favorite"), + rs.getBoolean("cached"), new ImageView(favorite_black)); + } + } + } + } + rs.close(); + stmt.close(); + } catch (Exception e) { + LOGGER.error("Ups! error while getting next episode!", e); + } + return nextFilm; + } + + /** TODO check if we relay need to separate between favorites and none favorites + * get the last watched episode + * @param title the title of the series + * @return the last watched episode as {@link FilmTabelDataType} object + */ + public FilmTabelDataType getLastWatchedEpisode(String title) { + LOGGER.info("last watched episode of: " + title); + FilmTabelDataType nextFilm = null; + double lastCurrentTime = 0; + + try { + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM films WHERE title = \"" + title + "\";"); + while (rs.next()) { + if (rs.getBoolean("favorite") == true) { + nextFilm = new FilmTabelDataType(rs.getString("streamUrl"), + rs.getString("title"), rs.getString("season"), rs.getString("episode") ,rs.getBoolean("favorite"), + rs.getBoolean("cached"), new ImageView(favorite_black)); + } else { + nextFilm = new FilmTabelDataType(rs.getString("streamUrl"), + rs.getString("title"), rs.getString("season"), rs.getString("episode"), rs.getBoolean("favorite"), + rs.getBoolean("cached"), new ImageView(favorite_border_black)); + } + if (rs.getDouble("currentTime") > lastCurrentTime) { + lastCurrentTime = rs.getDouble("currentTime"); + if (rs.getBoolean("favorite") == true) { + nextFilm = new FilmTabelDataType(rs.getString("streamUrl"), + rs.getString("title"), rs.getString("season"), rs.getString("episode") ,rs.getBoolean("favorite"), + rs.getBoolean("cached"), new ImageView(favorite_black)); + } else { + nextFilm = new FilmTabelDataType(rs.getString("streamUrl"), + rs.getString("title"), rs.getString("season"), rs.getString("episode"), rs.getBoolean("favorite"), + rs.getBoolean("cached"), new ImageView(favorite_border_black)); + } + break; + } + } + rs.close(); + stmt.close(); + } catch (Exception e) { + LOGGER.error("Ups! error while getting the last watched episode!", e); + } + + return nextFilm; + } + // removes the ending private String cutOffEnd(String str) { if (str == null) return null; @@ -587,4 +785,14 @@ public class DBController { return str.substring(0, pos); } + /** + * check if a file is a video + * @param path the path to the file + * @return true if the file is a video, else false + */ + public static boolean isVideoFile(String path) { + String mimeType = URLConnection.guessContentTypeFromName(path); + return mimeType != null && mimeType.startsWith("video"); + } + } diff --git a/src/main/java/kellerkinder/HomeFlix/controller/OMDbAPIController.java b/src/main/java/kellerkinder/HomeFlix/controller/OMDbAPIController.java index 6e8f5cd..bc4db09 100644 --- a/src/main/java/kellerkinder/HomeFlix/controller/OMDbAPIController.java +++ b/src/main/java/kellerkinder/HomeFlix/controller/OMDbAPIController.java @@ -19,7 +19,6 @@ * MA 02110-1301, USA. * */ - package kellerkinder.HomeFlix.controller; import java.awt.image.BufferedImage; @@ -35,6 +34,7 @@ import org.apache.logging.log4j.Logger; import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonObject; +import com.eclipsesource.json.JsonValue; import javafx.application.Platform; import kellerkinder.HomeFlix.application.Main; @@ -49,6 +49,12 @@ public class OMDbAPIController implements Runnable { private String URL = "https://www.omdbapi.com/?apikey="; private static final Logger LOGGER = LogManager.getLogger(MainWindowController.class.getName()); + /** + * constructor for the OMDbAPIController + * @param mainWindowController the MainWindowController object + * @param dbController the DBController object + * @param main the Main object + */ public OMDbAPIController(MainWindowController mainWindowController, DBController dbController, Main main){ this.mainWindowController = mainWindowController; this.dbController = dbController; @@ -62,23 +68,61 @@ public class OMDbAPIController implements Runnable { String output = null; String posterPath = null; - // get by title, TODO implement search + // get information by title try { URL apiUrl = new URL(URL + mainWindowController.getOmdbAPIKey() + "&t=" - + mainWindowController.getTitle().replace(" ", "%20")); + + mainWindowController.getCurrentTitle().replace(" ", "%20")); BufferedReader ina = new BufferedReader(new InputStreamReader(apiUrl.openStream())); output = ina.readLine(); ina.close(); - LOGGER.info("response from " + URL + " was valid"); - LOGGER.info(output); + System.out.println(apiUrl); + LOGGER.info("response from '" + URL + "&t=" + mainWindowController.getCurrentTitle() + "' was:" + output); } catch (IOException e) { LOGGER.error("error while making api request or reading response"); - LOGGER.error("response from " + URL + " was: \n" + output, e); + LOGGER.error("response from '" + URL + "&t=" + mainWindowController.getCurrentTitle() + "' was:" + output, e); return; } JsonObject object = Json.parse(output).asObject(); + if (object.getString("Error", "").equals("Movie not found!")) { + // if the movie was not found try to search it + LOGGER.warn("Movie was not found at first try, searching again!"); + /** TODO + * split the name intelligent as it may contain the film title + * search for English name + * use tmdb + */ + try { + URL apiUrl = new URL(URL + mainWindowController.getOmdbAPIKey() + "&s=" + + mainWindowController.getCurrentTitle().replace(" ", "%20")); + BufferedReader ina = new BufferedReader(new InputStreamReader(apiUrl.openStream())); + output = ina.readLine(); + ina.close(); + LOGGER.info("response from '" + URL + "&s=" + mainWindowController.getCurrentTitle() + "' was:" + output); + } catch (Exception e) { + LOGGER.error("error while making api request or reading response"); + LOGGER.error("response from '" + URL + "&s=" + mainWindowController.getCurrentTitle() + "' was:" + output, e); + return; + } + + JsonObject searchObject = Json.parse(output).asObject(); + if (searchObject.getString("Response", "").equals("True")) { + for (JsonValue movie : searchObject.get("Search").asArray()) { + // get first entry from the array and set object = movie + object = (JsonObject) movie; + System.out.println(movie.toString()); + break; + + } + System.out.println(object.getString("Title", "")); + } else { + LOGGER.warn("Movie not found! Not adding cache!"); + return; + } + } + + // add the response to the responseString[] responseString[0] = object.getString("Title", ""); responseString[1] = object.getString("Year", ""); responseString[2] = object.getString("Rated", ""); @@ -103,7 +147,7 @@ public class OMDbAPIController implements Runnable { //resize the image to fit in the posterImageView and add it to the cache try { BufferedImage originalImage = ImageIO.read(new URL(responseString[18])); //change path to where file is located - posterPath = main.getPosterCache() + "/" + mainWindowController.getTitle() + ".png"; + posterPath = main.getPosterCache() + "/" + mainWindowController.getCurrentTitle() + ".png"; ImageIO.write(originalImage, "png", new File(posterPath)); LOGGER.info("adding poster to cache: "+posterPath); } catch (Exception e) { @@ -111,16 +155,16 @@ public class OMDbAPIController implements Runnable { } // adding strings to the cache - dbController.addCache(mainWindowController.getStreamUrl(), responseString[0], responseString[1], + dbController.addCache(mainWindowController.getCurrentStreamUrl(), responseString[0], responseString[1], responseString[2], responseString[3], responseString[4], responseString[5], responseString[6], responseString[7], responseString[8], responseString[9], responseString[10], responseString[11], responseString[12], responseString[13], responseString[14], responseString[15], responseString[16], responseString[17], posterPath, responseString[19]); - dbController.setCached(mainWindowController.getStreamUrl()); + dbController.setCached(mainWindowController.getCurrentStreamUrl()); // load data to the MainWindowController Platform.runLater(() -> { - dbController.readCache(mainWindowController.getStreamUrl()); + dbController.readCache(mainWindowController.getCurrentStreamUrl()); }); } } diff --git a/src/main/java/kellerkinder/HomeFlix/controller/UpdateController.java b/src/main/java/kellerkinder/HomeFlix/controller/UpdateController.java index a21b376..efa3ffe 100644 --- a/src/main/java/kellerkinder/HomeFlix/controller/UpdateController.java +++ b/src/main/java/kellerkinder/HomeFlix/controller/UpdateController.java @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ - package kellerkinder.HomeFlix.controller; import java.io.BufferedReader; @@ -61,6 +60,9 @@ public class UpdateController implements Runnable { /** * updater for Project HomeFlix based on cemu_UIs, checks for Updates and download it + * @param mwc the MainWindowController object + * @param buildNumber the buildNumber of the used HomeFlix version + * @param useBeta if the updater should query the beta channel */ public UpdateController(MainWindowController mwc, String buildNumber, boolean useBeta) { mainWindowController = mwc; @@ -149,8 +151,8 @@ public class UpdateController implements Runnable { FileUtils.copyInputStreamToFile(pmis, new File("ProjectHomeFlix_update.jar")); // download update org.apache.commons.io.FileUtils.copyFile(new File("ProjectHomeFlix_update.jar"), new File("ProjectHomeFlix.jar")); org.apache.commons.io.FileUtils.deleteQuietly(new File("ProjectHomeFlix_update.jar")); // delete update - Runtime.getRuntime().exec("java -jar ProjectHomeFlix.jar"); // start again TODO consider ProcessBuilder to execute - System.exit(0); // finishes itself + new ProcessBuilder("java", "-jar", "ProjectHomeFlix.jar").start(); // start the new application + System.exit(0); // close the current application } catch (IOException e) { Platform.runLater(() -> { LOGGER.info("could not download update files", e); diff --git a/src/main/java/kellerkinder/HomeFlix/datatypes/FilmTabelDataType.java b/src/main/java/kellerkinder/HomeFlix/datatypes/FilmTabelDataType.java index 3bc51b1..c2b86da 100644 --- a/src/main/java/kellerkinder/HomeFlix/datatypes/FilmTabelDataType.java +++ b/src/main/java/kellerkinder/HomeFlix/datatypes/FilmTabelDataType.java @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ - package kellerkinder.HomeFlix.datatypes; import javafx.beans.property.BooleanProperty; @@ -36,7 +35,6 @@ public class FilmTabelDataType { private final BooleanProperty favorite = new SimpleBooleanProperty(); private final BooleanProperty cached = new SimpleBooleanProperty(); private final SimpleObjectProperty image = new SimpleObjectProperty<>(); - /** * tableData is the data-type of tree-table-view diff --git a/src/main/java/kellerkinder/HomeFlix/datatypes/SourceDataType.java b/src/main/java/kellerkinder/HomeFlix/datatypes/SourceDataType.java index aab7fa5..fec991a 100644 --- a/src/main/java/kellerkinder/HomeFlix/datatypes/SourceDataType.java +++ b/src/main/java/kellerkinder/HomeFlix/datatypes/SourceDataType.java @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ - package kellerkinder.HomeFlix.datatypes; import javafx.beans.property.SimpleStringProperty; diff --git a/src/main/java/kellerkinder/HomeFlix/player/Player.java b/src/main/java/kellerkinder/HomeFlix/player/Player.java new file mode 100644 index 0000000..1c8d946 --- /dev/null +++ b/src/main/java/kellerkinder/HomeFlix/player/Player.java @@ -0,0 +1,86 @@ +/** + * Project-HomeFlix + * + * Copyright 2016-2018 <@Seil0> + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ +package kellerkinder.HomeFlix.player; + +import javafx.event.EventHandler; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.scene.image.Image; +import javafx.scene.layout.AnchorPane; +import javafx.stage.Stage; +import javafx.stage.WindowEvent; +import kellerkinder.HomeFlix.application.Main; +import kellerkinder.HomeFlix.application.MainWindowController; + +public class Player { + + private PlayerController playerController; + private Stage stage; + private AnchorPane pane; + private Scene scene; + + /** + * generate a new PlayerWindow + * @param mainWindowController the MainWindowController + */ + public Player(MainWindowController mainWindowController) { + try { + FXMLLoader fxmlLoader = new FXMLLoader(ClassLoader.getSystemResource("fxml/PlayerWindow.fxml")); + pane = (AnchorPane) fxmlLoader.load(); + stage = new Stage(); + scene = new Scene(pane); + stage.setScene(scene); + stage.setTitle("HomeFlix"); + stage.getIcons().add(new Image(Main.class.getResourceAsStream("/icons/Homeflix_Icon_64x64.png"))); + stage.setOnCloseRequest(new EventHandler() { + public void handle(WindowEvent we) { + mainWindowController.getDbController().setCurrentTime(mainWindowController.getCurrentStreamUrl(), + playerController.getCurrentTime()); + playerController.getMediaPlayer().stop(); + stage.close(); + } + }); + + playerController = fxmlLoader.getController(); + playerController.init(mainWindowController, this, mainWindowController.getCurrentTableFilm()); + + stage.setFullScreen(true); + stage.show(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public Stage getStage() { + return stage; + } + + public Parent getPane() { + return pane; + } + + public Scene getScene() { + return scene; + } + +} diff --git a/src/main/java/kellerkinder/HomeFlix/player/PlayerController.java b/src/main/java/kellerkinder/HomeFlix/player/PlayerController.java new file mode 100644 index 0000000..40fcee6 --- /dev/null +++ b/src/main/java/kellerkinder/HomeFlix/player/PlayerController.java @@ -0,0 +1,276 @@ +/** + * Project-HomeFlix + * + * Copyright 2016-2018 <@Seil0> + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ +package kellerkinder.HomeFlix.player; + +import java.io.File; +import java.util.Timer; +import java.util.TimerTask; + +import com.jfoenix.controls.JFXButton; +import com.jfoenix.controls.JFXSlider; + +import javafx.beans.binding.Bindings; +import javafx.beans.property.DoubleProperty; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.fxml.FXML; +import javafx.scene.Cursor; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import javafx.scene.media.Media; +import javafx.scene.media.MediaPlayer; +import javafx.scene.media.MediaPlayer.Status; +import javafx.scene.media.MediaView; +import javafx.util.Duration; +import kellerkinder.HomeFlix.application.MainWindowController; +import kellerkinder.HomeFlix.datatypes.FilmTabelDataType; + +public class PlayerController { + + @FXML + private MediaView mediaView; + + @FXML + private VBox bottomVBox; + + @FXML + private HBox controlsHBox; + + @FXML + private JFXSlider timeSlider; + + @FXML + private JFXButton stopBtn; + + @FXML + private JFXButton playBtn; + + @FXML + private JFXButton fullscreenBtn; + + private Player player; + private MainWindowController mainWCon; + private Media media; + private MediaPlayer mediaPlayer; + + private FilmTabelDataType film; + private double currentTime = 0; + private double seekTime = 0; + private double startTime = 0; + private double duration = 0; + private boolean mousePressed = false; + private boolean showControls = true; + private boolean autoplay; + + private ImageView stop_black = new ImageView(new Image("icons/ic_stop_black_24dp_1x.png")); + private ImageView play_arrow_black = new ImageView(new Image("icons/ic_play_arrow_black_24dp_1x.png")); + private ImageView pause_black = new ImageView(new Image("icons/ic_pause_black_24dp_1x.png")); + private ImageView fullscreen_black = new ImageView(new Image("icons/ic_fullscreen_black_24dp_1x.png")); + private ImageView fullscreen_exit_black = new ImageView(new Image("icons/ic_fullscreen_exit_black_24dp_1x.png")); + + /** FIXME double set currentTime( + * initialize the new PlayerWindow + * @param entry the film object + * @param player the player object (needed for closing action) + * @param dbController the dbController object + */ + public void init(MainWindowController mainWCon, Player player, FilmTabelDataType film) { + this.mainWCon = mainWCon; + this.player = player; + this.film = film; + startTime = mainWCon.getDbController().getCurrentTime(film.getStreamUrl()); + autoplay = mainWCon.isAutoplay(); + initActions(); + + if (film.getStreamUrl().startsWith("http")) { + media = new Media(film.getStreamUrl()); + } else { + media = new Media(new File(film.getStreamUrl()).toURI().toString()); + } + startTime = mainWCon.getDbController().getCurrentTime(film.getStreamUrl()); + autoplay = mainWCon.isAutoplay(); + + mediaPlayer = new MediaPlayer(media); + mediaView.setPreserveRatio(true); + mediaView.setMediaPlayer(mediaPlayer); + + final DoubleProperty width = mediaView.fitWidthProperty(); + final DoubleProperty height = mediaView.fitHeightProperty(); + + width.bind(Bindings.selectDouble(mediaView.sceneProperty(), "width")); + height.bind(Bindings.selectDouble(mediaView.sceneProperty(), "height")); + + // start the media if the player is ready + mediaPlayer.setOnReady(new Runnable() { + @Override + public void run() { + duration = media.getDuration().toMillis(); + + timeSlider.setMax((duration / 1000) / 60); + + mediaPlayer.play(); + mediaPlayer.seek(Duration.millis(startTime)); + } + }); + + // every time the play time changes execute this + mediaPlayer.currentTimeProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue observable, Duration oldValue, Duration newValue) { + currentTime = newValue.toMillis(); // set the current time + int episode = !film.getEpisode().isEmpty() ? Integer.parseInt(film.getEpisode()) : 0; + int season = !film.getSeason().isEmpty() ? Integer.parseInt(film.getSeason()) : 0; + + // if we are end time -10 seconds, do autoplay, if activated + if ((duration - currentTime) < 10000 && episode != 0 && autoplay) { + autoplay = false; + mainWCon.getDbController().setCurrentTime(film.getStreamUrl(), 0); // reset old video start time + FilmTabelDataType nextFilm = mainWCon.getDbController().getNextEpisode(film.getTitle(), episode, season); + if (nextFilm != null) { + mediaPlayer.stop(); + init(mainWCon, player, nextFilm); + autoplay = true; + } + } else if ((duration - currentTime) < 120) { + // if we are -20ms stop the media + mediaPlayer.stop(); + mainWCon.getDbController().setCurrentTime(film.getStreamUrl(), 0); // reset old video start time + } + + if (!mousePressed) { + timeSlider.setValue((currentTime / 1000) / 60); + } + } + }); + + // set the control elements to the correct value + stopBtn.setGraphic(stop_black); + playBtn.setGraphic(pause_black); + fullscreenBtn.setGraphic(fullscreen_exit_black); + timeSlider.setValue(0); + } + + /** + * initialize some PlayerWindow GUI-Elements actions + */ + private void initActions() { + + player.getScene().addEventFilter(MouseEvent.MOUSE_MOVED, new EventHandler() { + // hide controls timer initialization + final Timer timer = new Timer(); + TimerTask controlAnimationTask = null; // task to execute save operation + final long delayTime = 2000; // hide the controls after 2 seconds + + @Override + public void handle(MouseEvent mouseEvent) { + + // show controls + if (!showControls) { + player.getScene().setCursor(Cursor.DEFAULT); + bottomVBox.setVisible(true); + } + + // hide controls + if (controlAnimationTask != null) + controlAnimationTask.cancel(); + + controlAnimationTask = new TimerTask() { + @Override + public void run() { + bottomVBox.setVisible(false); + player.getScene().setCursor(Cursor.NONE); + showControls = false; + } + }; + timer.schedule(controlAnimationTask, delayTime); + } + }); + + // if the mouse on the timeSlider is released seek to the new position + timeSlider.setOnMouseReleased(new EventHandler() { + @Override + public void handle(MouseEvent event) { + mediaPlayer.seek(new Duration(seekTime)); + mousePressed = false; + } + }); + + timeSlider.setOnMousePressed(new EventHandler() { + @Override + public void handle(MouseEvent event) { + mousePressed = true; + } + }); + + // get the new seek time + timeSlider.valueProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue ov, Number old_val, Number new_val) { + seekTime = (double) new_val * 1000 * 60; + } + }); + } + + @FXML + void stopBtnAction(ActionEvent event) { + mainWCon.getDbController().setCurrentTime(film.getStreamUrl(), currentTime); + mediaPlayer.stop(); + player.getStage().close(); + } + + @FXML + void fullscreenBtnAction(ActionEvent event) { + if (player.getStage().isFullScreen()) { + player.getStage().setFullScreen(false); + fullscreenBtn.setGraphic(fullscreen_black); + } else { + player.getStage().setFullScreen(true); + fullscreenBtn.setGraphic(fullscreen_exit_black); + } + } + + @FXML + void playBtnAction(ActionEvent event) { + + if (mediaPlayer.getStatus().equals(Status.PLAYING)) { + mediaPlayer.pause(); + playBtn.setGraphic(play_arrow_black); + } else { + mediaPlayer.play(); + playBtn.setGraphic(pause_black); + } + } + + public MediaPlayer getMediaPlayer() { + return mediaPlayer; + } + + public double getCurrentTime() { + return currentTime; + } + +} diff --git a/src/main/java/org/kellerkinder/Alerts/JFX2BtnCancelAlert.java b/src/main/java/org/kellerkinder/Alerts/JFX2BtnCancelAlert.java new file mode 100644 index 0000000..63b8ff2 --- /dev/null +++ b/src/main/java/org/kellerkinder/Alerts/JFX2BtnCancelAlert.java @@ -0,0 +1,189 @@ +/** + * Kellerkinder Framework Alerts + * + * Copyright 2018 <@Seil0> + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package org.kellerkinder.Alerts; + +import com.jfoenix.controls.JFXAlert; +import com.jfoenix.controls.JFXButton; +import com.jfoenix.controls.JFXDialogLayout; + +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.scene.text.Text; +import javafx.stage.Stage; + +public class JFX2BtnCancelAlert { + + private String headingText; + private String bodyText; + private String btnStyle; + private String btn1Text; + private String btn2Text; + private String cancelText; + private EventHandler btn1Action; + private EventHandler btn2Action; + private Stage stage; + private JFXAlert alert; + + /** + * Creates a new JFoenix Alert with 2 buttons and one cancel button + * @param titleText Title text of the alert + * @param headerText Heading text of the alert + * @param contentText Content text of the alert + * @param btnStyle Style of the okay button + * @param btn1Text btn1 text + * @param btn2Text btn2 text + * @param cancelText cancel button text + * @param stage stage to which the dialog belongs + */ + public JFX2BtnCancelAlert(String headingText, String bodyText, String btnStyle, String btn1Text, String btn2Text, + String cancelText, Stage stage) { + setHeadingText(headingText); + setBodyText(bodyText); + setBtnStyle(btnStyle); + setBtn1Text(btn1Text); + setBtn2Text(btn2Text); + setCancelText(cancelText); + setStage(stage); + } + + public JFX2BtnCancelAlert() { + // Auto-generated constructor stub + } + + public void showAndWait() { + alert = new JFXAlert<>(stage); + + JFXButton btnOne = new JFXButton(); + + btnOne.setText(btn1Text); + btnOne.setOnAction(btn1Action); + btnOne.setButtonType(com.jfoenix.controls.JFXButton.ButtonType.RAISED); + btnOne.setPrefHeight(32); + btnOne.setStyle(btnStyle); + + JFXButton btnTwo = new JFXButton(); + btnTwo.setText(btn2Text); + btnTwo.setOnAction(btn2Action); + btnTwo.setButtonType(com.jfoenix.controls.JFXButton.ButtonType.RAISED); + btnTwo.setPrefHeight(32); + btnTwo.setStyle(btnStyle); + + JFXButton cancelBtn = new JFXButton(); + cancelBtn.setText(cancelText); + cancelBtn.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent event) { + alert.close(); + System.exit(1); + } + }); + cancelBtn.setButtonType(com.jfoenix.controls.JFXButton.ButtonType.RAISED); + cancelBtn.setPrefHeight(32); + cancelBtn.setStyle(btnStyle); + + JFXDialogLayout content = new JFXDialogLayout(); + content.setActions(btnOne, btnTwo, cancelBtn); + content.setHeading(new Text(headingText)); + content.setBody(new Text(bodyText)); + alert.setContent(content); + alert.showAndWait(); + } + + public String getHeadingText() { + return headingText; + } + + public void setHeadingText(String headingText) { + this.headingText = headingText; + } + + public String getBodyText() { + return bodyText; + } + + public void setBodyText(String bodyText) { + this.bodyText = bodyText; + } + + public String getBtnStyle() { + return btnStyle; + } + + public void setBtnStyle(String btnStyle) { + this.btnStyle = btnStyle; + } + + public String getBtn1Text() { + return btn1Text; + } + + public void setBtn1Text(String btn1Text) { + this.btn1Text = btn1Text; + } + + public String getBtn2Text() { + return btn2Text; + } + + public void setBtn2Text(String btn2Text) { + this.btn2Text = btn2Text; + } + + public String getCancelText() { + return cancelText; + } + + public void setCancelText(String cancelText) { + this.cancelText = cancelText; + } + + public EventHandler getBtn1Action() { + return btn1Action; + } + + public void setBtn1Action(EventHandler btn1Action) { + this.btn1Action = btn1Action; + } + + public EventHandler getBtn2Action() { + return btn2Action; + } + + public void setBtn2Action(EventHandler btn2Action) { + this.btn2Action = btn2Action; + } + + public Stage getStage() { + return stage; + } + + public void setStage(Stage stage) { + this.stage = stage; + } + + public JFXAlert getAlert() { + return alert; + } + + public void setAlert(JFXAlert alert) { + this.alert = alert; + } +} diff --git a/src/main/java/com/cemu_UI/uiElements/JFXInfoDialog.java b/src/main/java/org/kellerkinder/Alerts/JFXInfoAlert.java similarity index 50% rename from src/main/java/com/cemu_UI/uiElements/JFXInfoDialog.java rename to src/main/java/org/kellerkinder/Alerts/JFXInfoAlert.java index 9c2b710..ab31c4d 100644 --- a/src/main/java/com/cemu_UI/uiElements/JFXInfoDialog.java +++ b/src/main/java/org/kellerkinder/Alerts/JFXInfoAlert.java @@ -1,7 +1,7 @@ /** - * cemu_UI + * Kellerkinder Framework Alerts * - * Copyright 2017 <@Seil0> + * Copyright 2018 <@Seil0> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,69 +18,94 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ +package org.kellerkinder.Alerts; -package com.cemu_UI.uiElements; - +import com.jfoenix.controls.JFXAlert; import com.jfoenix.controls.JFXButton; -import com.jfoenix.controls.JFXDialog; import com.jfoenix.controls.JFXDialogLayout; import javafx.event.ActionEvent; import javafx.event.EventHandler; -import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.Pane; -import javafx.scene.layout.StackPane; import javafx.scene.text.Text; +import javafx.stage.Stage; -public class JFXInfoDialog { - +public class JFXInfoAlert { + private String headingText; private String bodyText; - private String dialogBtnStyle; - private int dialogWidth; - private int dialogHeight; - private Pane pane; + private String btnStyle; + private Stage stage; /** - * Creates a new JFoenix Dialog to show some information - * @param headingText Heading Text, just the heading - * @param bodyText body Text, all other text belongs here - * @param dialogBtnStyle Style of the okay button - * @param dialogWidth dialog width - * @param dialogHeight dialog height - * @param pane pane to which the dialog belongs + * Creates a new JFoenix Alert to show some information + * @param headerText Heading text of the alert + * @param bodyText Content text of the alert + * @param btnStyle Style of the okay button + * @param stage stage to which the dialog belongs */ - public JFXInfoDialog(String headingText, String bodyText, String dialogBtnStyle, int dialogWidth, int dialogHeight, Pane pane) { - this.headingText = headingText; - this.bodyText = bodyText; - this.dialogBtnStyle = dialogBtnStyle; - this.dialogWidth = dialogWidth; - this.dialogHeight = dialogHeight; - this.pane = pane; + public JFXInfoAlert(String headingText, String bodyText, String btnStyle, Stage stage) { + setHeadingText(headingText); + setBodyText(bodyText); + setBtnStyle(btnStyle); + setStage(stage); } - - public void show() { - JFXDialogLayout content = new JFXDialogLayout(); - content.setHeading(new Text(headingText)); - content.setBody(new Text(bodyText)); - content.setPrefSize(dialogWidth, dialogHeight); - StackPane stackPane = new StackPane(); - stackPane.autosize(); - JFXDialog dialog = new JFXDialog(stackPane, content, JFXDialog.DialogTransition.LEFT, true); + + public JFXInfoAlert() { + // Auto-generated constructor stub + } + + public void showAndWait( ) { + JFXAlert alert = new JFXAlert<>(stage); + JFXButton button = new JFXButton("Okay"); button.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { - dialog.close(); + alert.close(); } }); button.setButtonType(com.jfoenix.controls.JFXButton.ButtonType.RAISED); button.setPrefHeight(32); - button.setStyle(dialogBtnStyle); + button.setStyle(btnStyle); + + JFXDialogLayout content = new JFXDialogLayout(); content.setActions(button); - pane.getChildren().add(stackPane); - AnchorPane.setTopAnchor(stackPane, (pane.getHeight() - content.getPrefHeight()) / 2); - AnchorPane.setLeftAnchor(stackPane, (pane.getWidth() - content.getPrefWidth()) / 2); - dialog.show(); + content.setHeading(new Text(headingText)); + content.setBody(new Text(bodyText)); + alert.setContent(content); + alert.showAndWait(); } -} + + public String getHeadingText() { + return headingText; + } + + public void setHeadingText(String headingText) { + this.headingText = headingText; + } + + public String getBodyText() { + return bodyText; + } + + public void setBodyText(String bodyText) { + this.bodyText = bodyText; + } + + public String getBtnStyle() { + return btnStyle; + } + + public void setBtnStyle(String btnStyle) { + this.btnStyle = btnStyle; + } + + public Stage getStage() { + return stage; + } + + public void setStage(Stage stage) { + this.stage = stage; + } + +} \ No newline at end of file diff --git a/src/main/resources/fxml/MainWindow.fxml b/src/main/resources/fxml/MainWindow.fxml index cec24f0..45b120a 100644 --- a/src/main/resources/fxml/MainWindow.fxml +++ b/src/main/resources/fxml/MainWindow.fxml @@ -22,60 +22,40 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + @@ -139,10 +119,26 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/fxml/PlayerWindow.fxml b/src/main/resources/fxml/PlayerWindow.fxml new file mode 100644 index 0000000..9008334 --- /dev/null +++ b/src/main/resources/fxml/PlayerWindow.fxml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/icons/ic_fullscreen_black_24dp_1x.png b/src/main/resources/icons/ic_fullscreen_black_24dp_1x.png new file mode 100644 index 0000000..3553d6a Binary files /dev/null and b/src/main/resources/icons/ic_fullscreen_black_24dp_1x.png differ diff --git a/src/main/resources/icons/ic_fullscreen_exit_black_24dp_1x.png b/src/main/resources/icons/ic_fullscreen_exit_black_24dp_1x.png new file mode 100644 index 0000000..c839448 Binary files /dev/null and b/src/main/resources/icons/ic_fullscreen_exit_black_24dp_1x.png differ diff --git a/src/main/resources/icons/ic_pause_black_24dp_1x.png b/src/main/resources/icons/ic_pause_black_24dp_1x.png new file mode 100644 index 0000000..6145664 Binary files /dev/null and b/src/main/resources/icons/ic_pause_black_24dp_1x.png differ diff --git a/src/main/resources/icons/ic_play_arrow_black_24dp_1x.png b/src/main/resources/icons/ic_play_arrow_black_24dp_1x.png new file mode 100644 index 0000000..d78c57b Binary files /dev/null and b/src/main/resources/icons/ic_play_arrow_black_24dp_1x.png differ diff --git a/src/main/resources/icons/ic_stop_black_24dp_1x.png b/src/main/resources/icons/ic_stop_black_24dp_1x.png new file mode 100644 index 0000000..0588f0b Binary files /dev/null and b/src/main/resources/icons/ic_stop_black_24dp_1x.png differ diff --git a/src/main/resources/locals/HomeFlix-Local_de_DE.properties b/src/main/resources/locals/HomeFlix-Local_de_DE.properties index 544d512..166e686 100644 --- a/src/main/resources/locals/HomeFlix-Local_de_DE.properties +++ b/src/main/resources/locals/HomeFlix-Local_de_DE.properties @@ -20,6 +20,7 @@ updateBtnChecking = Es wird nach Updates gesucht... updateBtnUpdateAvailable = Update verf\u00FCgbar updateBtnNoUpdateAvailable = Kein Update verf\u00FCgbar autoUpdate = beim Start nach Updates suchen: +autoplay = autoplay branchLbl = Updatezweig #column translations @@ -32,7 +33,6 @@ columnFavorite = Favorit #error translations errorUpdateV = Beim ausf\u00FChren des Updates ist ein Fehler aufgetreten! \nError: could not check update version (nvc)\nWeitere Hilfe erhalten sie unter www.kellerkinder.xyz \noder wenden sie sich an support@kellerkinder.xyz errorUpdateD = Beim ausf\u00FChren des Updates ist ein Fehler aufgetreten! \nError: could not download update files (ndf)\nWeitere Hilfe erhalten sie unter www.kellerkinder.xyz \noder wenden sie sich an support@kellerkinder.xyz -errorPlay = Beim \u00F6ffnen der Datei ist ein Fehler aufgetreten! \nError: could not open file (nof) \nWeitere Hilfe erhalten sie unter www.kellerkinder.xyz \noder wenden sie sich an support@kellerkinder.xyz errorMode = Oh, da lief etwas falsch! Da hat jemand einen falschen Modus verwendet. \nError: mode unknow (muk)\nWeitere Hilfe erhalten sie unter www.kellerkinder.xyz \noder wenden sie sich an support@kellerkinder.xyz errorOpenStream = Beim \u00F6ffnen des Streams ist ein Fehler aufgetreten! errorLoad = Beim laden der Einstellungen ist ein Fehler aufgetreten! @@ -59,5 +59,7 @@ metascore = Metascore imdbRating = IMDB-Bewertung type = Type -firstStartHeader = Es ist kein Stammverzeichnis f\u00FCr Filme angegeben! -firstStartContent = Stammverzeichniss angeben? +#first start +addSourceHeader = Neue Quelle hinzuf\u00FCgen +addSourceBody = HomeFlix konnte keine Quelle finden. \nFüge eine loakels Verzeichniss oder eine Sreaming Datei als neue Quelle hinzu. +cancelBtnText = Abbrechen diff --git a/src/main/resources/locals/HomeFlix-Local_en_US.properties b/src/main/resources/locals/HomeFlix-Local_en_US.properties index ce5f4af..8b16294 100644 --- a/src/main/resources/locals/HomeFlix-Local_en_US.properties +++ b/src/main/resources/locals/HomeFlix-Local_en_US.properties @@ -20,6 +20,7 @@ updateBtnChecking = checking for updates... updateBtnUpdateAvailable = update available updateBtnNoUpdateAvailable = no update available autoUpdate = check at startup for updates: +autoplay = autoplay branchLbl = Branch #column translations @@ -32,7 +33,6 @@ columnFavorite = Favorite #error translations errorUpdateV = An error has occurred during update! \nError: could not check update version (nvc) \nTo get help, visit www.kellerkinder.xyz \nor contcat support@kellerkinder.xyz errorUpdateD = An error has occurred during update! \nError: could not download update files (ndf) \nTo get help, visit www.kellerkinder.xyz \nor contcat support@kellerkinder.xyz -errorPlay = An error has occurred during opening the file! \nError: could not open file (nof) \nTo get help, visit www.kellerkinder.xyz \nor contcat support@kellerkinder.xyz errorMode = Oh, something went wrong! It seems someone has used a wrong mode. \nError: mode unknow (muk) \nTo get help, visit www.kellerkinder.xyz \nor contcat support@kellerkinder.xyz errorOpenStream = An error has occurred during opening the stream! errorLoad = An error occurred while loading the settings! @@ -59,5 +59,7 @@ metascore = Metascore imdbRating = IMDB-Rating type = Type -firstStartHeader = There is no root directory for movies! -firstStartContent = Specify a root directory? +#first start +addSourceHeader = add a new source +addSourceBody = HomeFlix was not able to load a source. \nAdd a new local directory oa a streaming file as new source. +cancelBtnText = cancel