Browse Source

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
pull/24/head
Jannik 4 years ago
parent
commit
a918b0b1d8
  1. 23
      src/main/java/kellerkinder/HomeFlix/application/MainWindowController.java
  2. 56
      src/main/java/kellerkinder/HomeFlix/controller/DBController.java
  3. 2
      src/main/java/kellerkinder/HomeFlix/controller/OMDbAPIController.java
  4. 15
      src/main/java/kellerkinder/HomeFlix/player/Player.java
  5. 171
      src/main/java/kellerkinder/HomeFlix/player/PlayerController.java
  6. 26
      src/main/resources/fxml/PlayerWindow.fxml
  7. BIN
      src/main/resources/icons/ic_fullscreen_black_24dp_1x.png
  8. BIN
      src/main/resources/icons/ic_fullscreen_exit_black_24dp_1x.png
  9. BIN
      src/main/resources/icons/ic_pause_black_24dp_1x.png
  10. BIN
      src/main/resources/icons/ic_play_arrow_black_24dp_1x.png
  11. BIN
      src/main/resources/icons/ic_stop_black_24dp_1x.png

23
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

56
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;

2
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"));

15
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<WindowEvent>() {
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;
}
}

171
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;
public void init(String file, Player player) {
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, 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"));
mediaView.setPreserveRatio(true);
mediaPlayer.play();
mediaPlayer.setOnReady(new Runnable() {
@Override
public void run() {
duration = media.getDuration().toMillis();
timeSlider.setMax((duration/1000)/60);
mediaPlayer.setStartTime(Duration.millis(dbController.getCurrentTime(file)));
mediaPlayer.play();
}
});
mediaPlayer.currentTimeProperty().addListener(new ChangeListener<Duration>() {
@Override
public void changed(ObservableValue<? extends Duration> 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<MouseEvent>() {
// 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<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
mediaPlayer.seek(new Duration(futureTime));
mousePressed = false;
}
});
timeSlider.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
mousePressed = true;
}
});
timeSlider.valueProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> 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;
}
}

26
src/main/resources/fxml/PlayerWindow.fxml

@ -1,9 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXSlider?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.media.MediaView?>
<AnchorPane prefHeight="720.0" prefWidth="1280.0" style="-fx-background-color: black;" xmlns="http://javafx.com/javafx/9" xmlns:fx="http://javafx.com/fxml/1" fx:controller="kellerkinder.HomeFlix.player.PlayerController">
@ -13,14 +15,24 @@
<MediaView fx:id="mediaView" />
</children>
</HBox>
<HBox fx:id="controllsHBox" alignment="CENTER" spacing="10.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
<VBox fx:id="bottomVBox" alignment="CENTER" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
<children>
<JFXButton fx:id="playBtn" onAction="#playBtnAction" prefHeight="39.0" prefWidth="75.0" style="-fx-background-color: white;" text="play" />
<JFXButton fx:id="fullscreenBtn" onAction="#fullscreenBtnAction" prefHeight="39.0" style="-fx-background-color: white;" text="fullscreen" />
<JFXSlider fx:id="timeSlider">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</JFXSlider>
<HBox fx:id="controlsHBox" alignment="CENTER" spacing="10.0">
<children>
<JFXButton fx:id="stopBtn" buttonType="RAISED" onAction="#stopBtnAction" prefHeight="39.0" style="-fx-background-color: white;" />
<JFXButton fx:id="playBtn" buttonType="RAISED" onAction="#playBtnAction" prefHeight="39.0" style="-fx-background-color: white;" />
<JFXButton fx:id="fullscreenBtn" buttonType="RAISED" onAction="#fullscreenBtnAction" prefHeight="39.0" style="-fx-background-color: white;" />
</children>
<padding>
<Insets bottom="5.0" top="5.0" />
</padding>
</HBox>
</children>
<padding>
<Insets bottom="5.0" top="5.0" />
</padding>
</HBox>
</VBox>
</children>
</AnchorPane>

BIN
src/main/resources/icons/ic_fullscreen_black_24dp_1x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 B

BIN
src/main/resources/icons/ic_fullscreen_exit_black_24dp_1x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 B

BIN
src/main/resources/icons/ic_pause_black_24dp_1x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 B

BIN
src/main/resources/icons/ic_play_arrow_black_24dp_1x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 B

BIN
src/main/resources/icons/ic_stop_black_24dp_1x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 B

Loading…
Cancel
Save

Du besuchst diese Seite mit einem veralteten IPv4-Internetzugang. Möglicherweise treten in Zukunft Probleme mit der Erreichbarkeit und Performance auf. Bitte frage deinen Internetanbieter oder Netzwerkadministrator nach IPv6-Unterstützung.
You are visiting this site with an outdated IPv4 internet access. You may experience problems with accessibility and performance in the future. Please ask your ISP or network administrator for IPv6 support.
Weitere Infos | More Information
Klicke zum schließen | Click to close