From a918b0b1d832d566a30dfca611b2de4276df07cc Mon Sep 17 00:00:00 2001 From: Jannik Date: Mon, 2 Apr 2018 02:18:43 +0200 Subject: [PATCH] new player part 2 * homeflix now saves the progress you made for all films * added icons for the player * added a slider to set the play time for the player * disable contols and cursor if mous is not moved for 5sec, enable it if moved * autoplay, WIP needs testing --- .../application/MainWindowController.java | 23 +-- .../HomeFlix/controller/DBController.java | 56 +++++- .../controller/OMDbAPIController.java | 2 +- .../kellerkinder/HomeFlix/player/Player.java | 15 +- .../HomeFlix/player/PlayerController.java | 167 +++++++++++++++++- src/main/resources/fxml/PlayerWindow.fxml | 26 ++- .../icons/ic_fullscreen_black_24dp_1x.png | Bin 0 -> 90 bytes .../ic_fullscreen_exit_black_24dp_1x.png | Bin 0 -> 93 bytes .../icons/ic_pause_black_24dp_1x.png | Bin 0 -> 81 bytes .../icons/ic_play_arrow_black_24dp_1x.png | Bin 0 -> 150 bytes .../resources/icons/ic_stop_black_24dp_1x.png | Bin 0 -> 82 bytes 11 files changed, 259 insertions(+), 30 deletions(-) create mode 100644 src/main/resources/icons/ic_fullscreen_black_24dp_1x.png create mode 100644 src/main/resources/icons/ic_fullscreen_exit_black_24dp_1x.png create mode 100644 src/main/resources/icons/ic_pause_black_24dp_1x.png create mode 100644 src/main/resources/icons/ic_play_arrow_black_24dp_1x.png create mode 100644 src/main/resources/icons/ic_stop_black_24dp_1x.png diff --git a/src/main/java/kellerkinder/HomeFlix/application/MainWindowController.java b/src/main/java/kellerkinder/HomeFlix/application/MainWindowController.java index 2c41075..074fbf4 100644 --- a/src/main/java/kellerkinder/HomeFlix/application/MainWindowController.java +++ b/src/main/java/kellerkinder/HomeFlix/application/MainWindowController.java @@ -229,7 +229,6 @@ public class MainWindowController { private boolean settingsTrue = false; private boolean autoUpdate = false; private boolean useBeta = false; - private boolean betaPlayer = false; private static final Logger LOGGER = LogManager.getLogger(MainWindowController.class.getName()); private int hashA = -647380320; @@ -240,6 +239,7 @@ public class MainWindowController { private String color; private String title; private String streamUrl; + private String currentEp; private String ratingSortType; private String local; private String omdbAPIKey; @@ -500,6 +500,7 @@ public class MainWindowController { next = indexTable + 1; title = columnTitle.getCellData(indexTable); // get name of selected item streamUrl = columnStreamUrl.getCellData(indexTable); // get file path of selected item + currentEp = columnEpisode.getCellData(indexTable); // get the current episode of a series for (FilmTabelDataType helpData : filmsList) { if (helpData.getStreamUrl().equals(streamUrl)) { @@ -548,9 +549,12 @@ public class MainWindowController { private void playbtnclicked() { // TODO rework when #19 is coming - if (betaPlayer) { - new Player(streamUrl); - } else { + try { + System.out.println(); + new Player(streamUrl, currentEp, dbController); + } catch (Exception e) { + LOGGER.error("using fallback player!", e); // FIXME doesn't work! + if (System.getProperty("os.name").contains("Linux")) { String line; String output = ""; @@ -572,22 +576,21 @@ public class MainWindowController { } else { try { Runtime.getRuntime().exec(new String[] { "vlc", streamUrl }); // TODO switch to ProcessBuilder - } catch (IOException e) { - showErrorMsg(errorPlay, e); + } catch (IOException e1) { + showErrorMsg(errorPlay, e1); } } } 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); + } catch (IOException e1) { + showErrorMsg(errorPlay, e1); } } else { LOGGER.error(System.getProperty("os.name") + ", OS is not supported, please contact a developer! "); } - } - + } } @FXML diff --git a/src/main/java/kellerkinder/HomeFlix/controller/DBController.java b/src/main/java/kellerkinder/HomeFlix/controller/DBController.java index 7ca7306..410c561 100644 --- a/src/main/java/kellerkinder/HomeFlix/controller/DBController.java +++ b/src/main/java/kellerkinder/HomeFlix/controller/DBController.java @@ -99,7 +99,7 @@ public class DBController { 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," @@ -303,7 +303,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 @@ -317,7 +317,7 @@ public class DBController { 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"); @@ -334,7 +334,7 @@ public class DBController { LOGGER.info("Added \"" + file.getName() + "\", Episode: " + episode.getName() + " to database"); stmt.executeUpdate("insert into films values (" + "'" + episode.getPath().replace("'", "''") + "'," - + "'" + cutOffEnd(file.getName()) + "','" + sn + "','" + ep + "', 0, 0)"); + + "'" + cutOffEnd(file.getName()) + "','" + sn + "','" + ep + "', 0, 0, 0.0)"); connection.commit(); stmt.close(); filmsStreamURL.add(episode.getPath()); @@ -366,6 +366,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); @@ -392,7 +393,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(); @@ -579,6 +581,50 @@ public class DBController { } } + 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 refreshing mwc!", e); + } + + return currentTime; + } + + 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); + } + } + + public String getNextEpisode(String streamUrl, int nextEp) { + String nextStreamUrl = ""; + try { + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT * FROM films WHERE streamUrl = \"" + streamUrl + "\" AND episode = " + nextEp + ";"); + nextStreamUrl = rs.getString("streamUrl"); + rs.close(); + stmt.close(); + } catch (Exception e) { + LOGGER.error("Ups! error while refreshing mwc!", e); + } + return nextStreamUrl; + } + + // removes the ending private String cutOffEnd(String str) { if (str == null) return null; diff --git a/src/main/java/kellerkinder/HomeFlix/controller/OMDbAPIController.java b/src/main/java/kellerkinder/HomeFlix/controller/OMDbAPIController.java index 6e8f5cd..a3e7580 100644 --- a/src/main/java/kellerkinder/HomeFlix/controller/OMDbAPIController.java +++ b/src/main/java/kellerkinder/HomeFlix/controller/OMDbAPIController.java @@ -62,7 +62,7 @@ public class OMDbAPIController implements Runnable { String output = null; String posterPath = null; - // get by title, TODO implement search + // get by title, TODO implement search FIXME set correct info if film dosen't exist try { URL apiUrl = new URL(URL + mainWindowController.getOmdbAPIKey() + "&t=" + mainWindowController.getTitle().replace(" ", "%20")); diff --git a/src/main/java/kellerkinder/HomeFlix/player/Player.java b/src/main/java/kellerkinder/HomeFlix/player/Player.java index e1cc12e..2ee468f 100644 --- a/src/main/java/kellerkinder/HomeFlix/player/Player.java +++ b/src/main/java/kellerkinder/HomeFlix/player/Player.java @@ -10,29 +10,34 @@ import javafx.scene.layout.AnchorPane; import javafx.stage.Stage; import javafx.stage.WindowEvent; import kellerkinder.HomeFlix.application.Main; +import kellerkinder.HomeFlix.controller.DBController; public class Player { private PlayerController playerController; private Stage stage; private AnchorPane pane; + private Scene scene; - public Player(String file) { + public Player(String file, String currentEp, DBController dbController) { try { FXMLLoader fxmlLoader = new FXMLLoader(ClassLoader.getSystemResource("fxml/PlayerWindow.fxml")); pane = (AnchorPane) fxmlLoader.load(); stage = new Stage(); - stage.setScene(new Scene(pane)); + 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) { + dbController.setCurrentTime(file, playerController.getCurrentTime()); playerController.getMediaPlayer().stop(); + stage.close(); } }); playerController = fxmlLoader.getController(); - playerController.init(file, this); + playerController.init(file, currentEp, this, dbController); stage.setFullScreen(true); stage.show(); @@ -49,4 +54,8 @@ public class Player { 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 index cc79eef..238d561 100644 --- a/src/main/java/kellerkinder/HomeFlix/player/PlayerController.java +++ b/src/main/java/kellerkinder/HomeFlix/player/PlayerController.java @@ -1,27 +1,49 @@ 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.controller.DBController; public class PlayerController { @FXML private MediaView mediaView; + + @FXML + private VBox bottomVBox; @FXML - private HBox controllsHBox; + private HBox controlsHBox; + @FXML + private JFXSlider timeSlider; + + @FXML + private JFXButton stopBtn; + @FXML private JFXButton playBtn; @@ -29,14 +51,39 @@ public class PlayerController { private JFXButton fullscreenBtn; private Player player; + private DBController dbController; private Media media; private MediaPlayer mediaPlayer; + + private double currentTime = 0; + private double futureTime= 0; + private double duration = 0; + private boolean mousePressed = false; + private boolean showControls = true; + private String file; + private int nextEp; + + 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")); - public void init(String file, Player player) { + public void init(String file, String currentEp, Player player, DBController dbController) { + this.file = file; this.player = player; + this.dbController = dbController; + initActions(); + + if (currentEp.length() > 0) { + nextEp = Integer.parseInt(currentEp) + 1; + } else { + nextEp = 0; + } media = new Media(new File(file).toURI().toString()); mediaPlayer = new MediaPlayer(media); + mediaView.setPreserveRatio(true); mediaView.setMediaPlayer(mediaPlayer); final DoubleProperty width = mediaView.fitWidthProperty(); @@ -44,17 +91,123 @@ public class PlayerController { width.bind(Bindings.selectDouble(mediaView.sceneProperty(), "width")); height.bind(Bindings.selectDouble(mediaView.sceneProperty(), "height")); + + mediaPlayer.setOnReady(new Runnable() { + @Override + public void run() { + duration = media.getDuration().toMillis(); + + timeSlider.setMax((duration/1000)/60); - mediaView.setPreserveRatio(true); - mediaPlayer.play(); + mediaPlayer.setStartTime(Duration.millis(dbController.getCurrentTime(file))); + mediaPlayer.play(); + } + }); + + mediaPlayer.currentTimeProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue observable, Duration oldValue, Duration newValue) { + + + currentTime = newValue.toMillis(); + + if (duration - currentTime < 10000) { + if (nextEp != 0) { + dbController.getNextEpisode(file, nextEp); + System.out.println("next episode is: " + dbController.getNextEpisode(file, nextEp)); + } else { + if (duration - currentTime < 100) { + dbController.setCurrentTime(file, 0); + mediaPlayer.stop(); + player.getStage().close(); + } + } + } + + if (!mousePressed) { + timeSlider.setValue((currentTime/1000)/60); + } + } + }); + + stopBtn.setGraphic(stop_black); + playBtn.setGraphic(play_arrow_black); + fullscreenBtn.setGraphic(fullscreen_exit_black); + } + + private void initActions() { + + player.getScene().addEventFilter(MouseEvent.MOUSE_MOVED, new EventHandler() { + // hide controls timer init + final Timer timer = new Timer(); + TimerTask controlAnimationTask = null; // task to execute save operation + final long delayTime = 5000; + + @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); + } + }); + + timeSlider.setOnMouseReleased(new EventHandler() { + @Override + public void handle(MouseEvent event) { + mediaPlayer.seek(new Duration(futureTime)); + mousePressed = false; + } + }); + + timeSlider.setOnMousePressed(new EventHandler() { + @Override + public void handle(MouseEvent event) { + mousePressed = true; + } + }); + + timeSlider.valueProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue ov, Number old_val, Number new_val) { + futureTime = (double) new_val*1000*60; + } + }); + } + + @FXML + void stopBtnAction(ActionEvent event) { + + dbController.setCurrentTime(file, 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); } } @@ -63,8 +216,10 @@ public class PlayerController { if (mediaPlayer.getStatus().equals(Status.PLAYING)) { mediaPlayer.pause(); + playBtn.setGraphic(play_arrow_black); } else { mediaPlayer.play(); + playBtn.setGraphic(pause_black); } } @@ -72,4 +227,8 @@ public class PlayerController { return mediaPlayer; } + public double getCurrentTime() { + return currentTime; + } + } diff --git a/src/main/resources/fxml/PlayerWindow.fxml b/src/main/resources/fxml/PlayerWindow.fxml index 8abe8a4..9008334 100644 --- a/src/main/resources/fxml/PlayerWindow.fxml +++ b/src/main/resources/fxml/PlayerWindow.fxml @@ -1,9 +1,11 @@ + + @@ -13,14 +15,24 @@ - + - - + + + + + + + + + + + + + + + - - - - + 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 0000000000000000000000000000000000000000..3553d6a5d6c410575bb658b48e95e6a500f49e2c GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1MNb#UkP60RiI)%Td6K#U0-41e n)OimJ^3-g&q^R4Q!@v;bW`FSMsV|R!iWxjz{an^LB{Ts5YOxpV literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..c8394487c9c3e539520d57b899313ab0779ed6ab GIT binary patch literal 93 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*16;Bt(kP60RhQ`1T@*ERyFt2`S q&y&E=&B# wc=B>S&sUzDB`$N=G(DB)Hcp&$#GH%4Jltn(&bImcfEF=$y85}Sb4q9e09LOpNdN!< literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..0588f0b4cf92eca1c16aa65c47550dddf8a39099 GIT binary patch literal 82 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1NlzEYkP60R1<9VK{}u{-2CEW7 em^%|h7#LjB`wN$O|Lg=RV(@hJb6Mw<&;$UT`4g=G literal 0 HcmV?d00001