2018-04-02 18:29:59 +02:00
/ * *
* 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 .
*
* /
2018-04-01 23:24:49 +02:00
package kellerkinder.HomeFlix.player ;
import java.io.File ;
2018-04-02 02:18:43 +02:00
import java.util.Timer ;
import java.util.TimerTask ;
2018-04-01 23:24:49 +02:00
import com.jfoenix.controls.JFXButton ;
2018-04-02 02:18:43 +02:00
import com.jfoenix.controls.JFXSlider ;
2018-04-01 23:24:49 +02:00
import javafx.beans.binding.Bindings ;
import javafx.beans.property.DoubleProperty ;
2018-04-02 02:18:43 +02:00
import javafx.beans.value.ChangeListener ;
import javafx.beans.value.ObservableValue ;
2018-04-01 23:24:49 +02:00
import javafx.event.ActionEvent ;
2018-04-02 02:18:43 +02:00
import javafx.event.EventHandler ;
2018-04-01 23:24:49 +02:00
import javafx.fxml.FXML ;
2018-04-02 02:18:43 +02:00
import javafx.scene.Cursor ;
import javafx.scene.image.Image ;
import javafx.scene.image.ImageView ;
import javafx.scene.input.MouseEvent ;
2018-04-01 23:24:49 +02:00
import javafx.scene.layout.HBox ;
2018-04-02 02:18:43 +02:00
import javafx.scene.layout.VBox ;
2018-04-01 23:24:49 +02:00
import javafx.scene.media.Media ;
import javafx.scene.media.MediaPlayer ;
import javafx.scene.media.MediaPlayer.Status ;
import javafx.scene.media.MediaView ;
2018-04-02 02:18:43 +02:00
import javafx.util.Duration ;
2018-04-07 17:14:35 +02:00
import kellerkinder.HomeFlix.application.MainWindowController ;
2018-04-03 18:03:43 +02:00
import kellerkinder.HomeFlix.datatypes.FilmTabelDataType ;
2018-04-01 23:24:49 +02:00
public class PlayerController {
@FXML
private MediaView mediaView ;
2018-04-07 17:14:35 +02:00
2018-04-02 02:18:43 +02:00
@FXML
private VBox bottomVBox ;
2018-04-01 23:24:49 +02:00
@FXML
2018-04-02 02:18:43 +02:00
private HBox controlsHBox ;
2018-04-01 23:24:49 +02:00
2018-04-02 02:18:43 +02:00
@FXML
private JFXSlider timeSlider ;
2018-04-07 17:14:35 +02:00
2018-04-02 02:18:43 +02:00
@FXML
private JFXButton stopBtn ;
2018-04-07 17:14:35 +02:00
2018-04-01 23:24:49 +02:00
@FXML
private JFXButton playBtn ;
@FXML
private JFXButton fullscreenBtn ;
private Player player ;
2018-04-07 17:14:35 +02:00
private MainWindowController mainWCon ;
2018-04-01 23:24:49 +02:00
private Media media ;
private MediaPlayer mediaPlayer ;
2018-04-07 17:14:35 +02:00
2018-04-03 18:03:43 +02:00
private FilmTabelDataType film ;
2018-04-02 02:18:43 +02:00
private double currentTime = 0 ;
2018-04-03 18:03:43 +02:00
private double seekTime = 0 ;
private double startTime = 0 ;
2018-04-02 02:18:43 +02:00
private double duration = 0 ;
private boolean mousePressed = false ;
private boolean showControls = true ;
2018-04-07 17:14:35 +02:00
private boolean autoplay ;
2018-04-02 02:18:43 +02:00
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 " ) ) ;
2018-04-28 12:53:44 +02:00
/ * * FIXME double set currentTime ( )
2018-04-02 18:29:59 +02:00
* initialize the new PlayerWindow
2018-04-07 17:14:35 +02:00
* @param entry the film object
2018-04-02 18:29:59 +02:00
* @param player the player object ( needed for closing action )
* @param dbController the dbController object
* /
2018-04-07 17:14:35 +02:00
public void init ( MainWindowController mainWCon , Player player , FilmTabelDataType film ) {
this . mainWCon = mainWCon ;
2018-04-01 23:24:49 +02:00
this . player = player ;
2018-04-07 17:14:35 +02:00
this . film = film ;
startTime = mainWCon . getDbController ( ) . getCurrentTime ( film . getStreamUrl ( ) ) ;
autoplay = mainWCon . isAutoplay ( ) ;
2018-04-02 02:18:43 +02:00
initActions ( ) ;
2018-04-07 17:14:35 +02:00
2018-04-03 18:03:43 +02:00
if ( film . getStreamUrl ( ) . startsWith ( " http " ) ) {
media = new Media ( film . getStreamUrl ( ) ) ;
2018-04-02 02:18:43 +02:00
} else {
2018-04-03 18:03:43 +02:00
media = new Media ( new File ( film . getStreamUrl ( ) ) . toURI ( ) . toString ( ) ) ;
2018-04-02 02:18:43 +02:00
}
2018-04-07 17:14:35 +02:00
startTime = mainWCon . getDbController ( ) . getCurrentTime ( film . getStreamUrl ( ) ) ;
autoplay = mainWCon . isAutoplay ( ) ;
2018-04-01 23:24:49 +02:00
mediaPlayer = new MediaPlayer ( media ) ;
2018-04-02 02:18:43 +02:00
mediaView . setPreserveRatio ( true ) ;
2018-04-01 23:24:49 +02:00
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 " ) ) ;
2018-04-03 18:03:43 +02:00
2018-04-07 17:14:35 +02:00
// start the media if the player is ready
2018-04-02 02:18:43 +02:00
mediaPlayer . setOnReady ( new Runnable ( ) {
2018-04-07 17:14:35 +02:00
@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
2018-04-02 02:18:43 +02:00
mediaPlayer . currentTimeProperty ( ) . addListener ( new ChangeListener < Duration > ( ) {
2018-04-07 17:14:35 +02:00
@Override
public void changed ( ObservableValue < ? extends Duration > observable , Duration oldValue , Duration newValue ) {
currentTime = newValue . toMillis ( ) ; // set the current time
int episode = ! film . getEpisode ( ) . isEmpty ( ) ? Integer . parseInt ( film . getEpisode ( ) ) : 0 ;
2018-04-15 21:30:26 +02:00
int season = ! film . getSeason ( ) . isEmpty ( ) ? Integer . parseInt ( film . getSeason ( ) ) : 0 ;
2018-04-18 21:04:14 +02:00
2018-04-07 17:14:35 +02:00
// 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
2018-04-26 15:13:15 +02:00
FilmTabelDataType nextFilm = mainWCon . getDbController ( ) . getNextEpisode ( film . getTitle ( ) , episode , season ) ;
2018-04-07 17:14:35 +02:00
if ( nextFilm ! = null ) {
mediaPlayer . stop ( ) ;
2018-04-08 13:22:20 +02:00
init ( mainWCon , player , nextFilm ) ;
2018-04-07 17:14:35 +02:00
autoplay = true ;
2018-04-03 18:23:54 +02:00
}
2018-04-18 21:04:14 +02:00
} else if ( ( duration - currentTime ) < 120 ) {
// if we are -20ms stop the media
2018-04-03 18:03:43 +02:00
mediaPlayer . stop ( ) ;
2018-04-18 21:04:14 +02:00
mainWCon . getDbController ( ) . setCurrentTime ( film . getStreamUrl ( ) , 0 ) ; // reset old video start time
2018-04-02 02:18:43 +02:00
}
2018-04-07 17:14:35 +02:00
if ( ! mousePressed ) {
timeSlider . setValue ( ( currentTime / 1000 ) / 60 ) ;
2018-04-02 02:18:43 +02:00
}
2018-04-07 17:14:35 +02:00
}
2018-04-02 02:18:43 +02:00
} ) ;
2018-04-07 17:14:35 +02:00
// set the control elements to the correct value
2018-04-02 02:18:43 +02:00
stopBtn . setGraphic ( stop_black ) ;
2018-04-03 18:03:43 +02:00
playBtn . setGraphic ( pause_black ) ;
2018-04-02 02:18:43 +02:00
fullscreenBtn . setGraphic ( fullscreen_exit_black ) ;
2018-04-03 18:03:43 +02:00
timeSlider . setValue ( 0 ) ;
2018-04-02 02:18:43 +02:00
}
2018-04-07 17:14:35 +02:00
2018-04-02 18:29:59 +02:00
/ * *
* initialize some PlayerWindow GUI - Elements actions
* /
2018-04-02 02:18:43 +02:00
private void initActions ( ) {
2018-04-07 17:14:35 +02:00
2018-04-02 02:18:43 +02:00
player . getScene ( ) . addEventFilter ( MouseEvent . MOUSE_MOVED , new EventHandler < MouseEvent > ( ) {
2018-04-08 13:22:20 +02:00
// hide controls timer initialization
2018-04-02 02:18:43 +02:00
final Timer timer = new Timer ( ) ;
TimerTask controlAnimationTask = null ; // task to execute save operation
2018-04-18 21:04:14 +02:00
final long delayTime = 2000 ; // hide the controls after 2 seconds
2018-04-02 02:18:43 +02:00
@Override
public void handle ( MouseEvent mouseEvent ) {
2018-04-07 17:14:35 +02:00
2018-04-02 02:18:43 +02:00
// show controls
if ( ! showControls ) {
player . getScene ( ) . setCursor ( Cursor . DEFAULT ) ;
bottomVBox . setVisible ( true ) ;
}
2018-04-07 17:14:35 +02:00
2018-04-02 02:18:43 +02:00
// 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 ) ;
}
} ) ;
2018-04-07 17:14:35 +02:00
// if the mouse on the timeSlider is released seek to the new position
2018-04-02 02:18:43 +02:00
timeSlider . setOnMouseReleased ( new EventHandler < MouseEvent > ( ) {
2018-04-07 17:14:35 +02:00
@Override
public void handle ( MouseEvent event ) {
mediaPlayer . seek ( new Duration ( seekTime ) ) ;
mousePressed = false ;
}
2018-04-02 02:18:43 +02:00
} ) ;
2018-04-07 17:14:35 +02:00
2018-04-02 02:18:43 +02:00
timeSlider . setOnMousePressed ( new EventHandler < MouseEvent > ( ) {
@Override
public void handle ( MouseEvent event ) {
mousePressed = true ;
2018-04-07 17:14:35 +02:00
}
2018-04-02 02:18:43 +02:00
} ) ;
2018-04-07 17:14:35 +02:00
// get the new seek time
2018-04-02 02:18:43 +02:00
timeSlider . valueProperty ( ) . addListener ( new ChangeListener < Number > ( ) {
@Override
public void changed ( ObservableValue < ? extends Number > ov , Number old_val , Number new_val ) {
2018-04-07 17:14:35 +02:00
seekTime = ( double ) new_val * 1000 * 60 ;
2018-04-02 02:18:43 +02:00
}
} ) ;
}
2018-04-07 17:14:35 +02:00
2018-04-02 02:18:43 +02:00
@FXML
void stopBtnAction ( ActionEvent event ) {
2018-04-07 17:14:35 +02:00
mainWCon . getDbController ( ) . setCurrentTime ( film . getStreamUrl ( ) , currentTime ) ;
2018-04-02 02:18:43 +02:00
mediaPlayer . stop ( ) ;
player . getStage ( ) . close ( ) ;
2018-04-01 23:24:49 +02:00
}
@FXML
2018-04-07 17:14:35 +02:00
void fullscreenBtnAction ( ActionEvent event ) {
2018-04-01 23:24:49 +02:00
if ( player . getStage ( ) . isFullScreen ( ) ) {
player . getStage ( ) . setFullScreen ( false ) ;
2018-04-02 02:18:43 +02:00
fullscreenBtn . setGraphic ( fullscreen_black ) ;
2018-04-01 23:24:49 +02:00
} else {
player . getStage ( ) . setFullScreen ( true ) ;
2018-04-02 02:18:43 +02:00
fullscreenBtn . setGraphic ( fullscreen_exit_black ) ;
2018-04-01 23:24:49 +02:00
}
}
@FXML
void playBtnAction ( ActionEvent event ) {
if ( mediaPlayer . getStatus ( ) . equals ( Status . PLAYING ) ) {
mediaPlayer . pause ( ) ;
2018-04-02 02:18:43 +02:00
playBtn . setGraphic ( play_arrow_black ) ;
2018-04-01 23:24:49 +02:00
} else {
mediaPlayer . play ( ) ;
2018-04-02 02:18:43 +02:00
playBtn . setGraphic ( pause_black ) ;
2018-04-01 23:24:49 +02:00
}
}
public MediaPlayer getMediaPlayer ( ) {
return mediaPlayer ;
}
2018-04-02 02:18:43 +02:00
public double getCurrentTime ( ) {
return currentTime ;
}
2018-04-01 23:24:49 +02:00
}