minor bugfixes and clean up

* fixed a bug that prevented posters from showing at the first start
* added the ability to start a series from the last watched episode
This commit is contained in:
Jannik 2019-06-22 21:04:43 +02:00
parent 9af3ad26bd
commit 5488bece2d
Signed by: Seil0
GPG Key ID: E8459F3723C52C24
10 changed files with 161 additions and 269 deletions

View File

@ -23,10 +23,8 @@
package kellerkinder.HomeFlix.application;
import java.awt.Desktop;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -217,53 +215,12 @@ public class FilmDetailView {
MainWindowController.getInstance().disableBlur(); // disable blur
}
// TODO rework
private void playFilm() {
if(new File(currentStreamURL).isDirectory()) {
return;
}
if (Player.isSupportedFormat(currentStreamURL)) {
new Player(currentStreamURL);
} 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("which vlc: " + output);
input.close();
} catch (IOException e1) {
e1.printStackTrace();
}
if (output.contains("which: no vlc") || output == "") {
// JFXInfoAlert vlcInfoAlert = new JFXInfoAlert("Info",
// XMLController.getLocalBundle().getString("vlcNotInstalled"), btnStyle, primaryStage);
// vlcInfoAlert.showAndWait();
} else {
try {
new ProcessBuilder("vlc", currentStreamURL).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(currentStreamURL));
} 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! ");
}
}
}
}

View File

@ -43,8 +43,8 @@ public class Main extends Application {
private MainWindowController mainWindowController;
private static XMLController xmlController;
private static Logger LOGGER;
public static final String version = "0.7.90";
public static final String buildNumber = "171";
public static final String version = "0.7.91";
public static final String buildNumber = "173";
public static final String versionName = "toothless dragon";
@Override
@ -100,12 +100,12 @@ public class Main extends Application {
xmlController = new XMLController();
if (XMLController.getConfigFile().exists()) {
xmlController.loadSettings();
} else {
xmlController.saveSettings();
if (!XMLController.getConfigFile().exists()) {
xmlController.saveSettings(); // save the settings file with default values if it doesn't exist
}
xmlController.loadSettings();
if (!XMLController.getPosterCache().exists()) {
XMLController.getPosterCache().mkdir();
}

View File

@ -22,16 +22,12 @@
package kellerkinder.HomeFlix.application;
import java.awt.Desktop;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Writer;
import java.math.BigInteger;
import java.net.URLConnection;
import java.time.LocalDate;
import java.util.Locale;
import java.util.ResourceBundle;
@ -73,7 +69,6 @@ import kellerkinder.HomeFlix.controller.UpdateController;
import kellerkinder.HomeFlix.controller.XMLController;
import kellerkinder.HomeFlix.datatypes.FilmTabelDataType;
import kellerkinder.HomeFlix.datatypes.PosterModeElement;
import kellerkinder.HomeFlix.player.Player;
public class MainWindowController {
@ -109,8 +104,6 @@ public class MainWindowController {
private String btnStyle;
private FilmTabelDataType currentTableFilm = new FilmTabelDataType("", "", "", "", false, null);
private ObservableList<PosterModeElement> posterEmenents = FXCollections.observableArrayList();
private LocalDate lastValidCache = LocalDate.now().minusDays(30); // current date - 30 days is the last valid cache date
@ -184,59 +177,6 @@ public class MainWindowController {
primaryStage.setMinWidth(1130.00);
}
// Table-Mode fxml actions
@FXML
private void playbtnclicked() {
if (currentTableFilm.getStreamUrl().length() > 0) {
if (currentTableFilm.getStreamUrl().contains("_rootNode")) {
LOGGER.info("rootNode found, getting last watched episode");
currentTableFilm = dbController.getLastWatchedEpisode(currentTableFilm.getTitle());
}
if (isSupportedFormat(currentTableFilm)) {
new Player(currentTableFilm.getStreamUrl());
} 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("which vlc: " + output);
input.close();
} catch (IOException e1) {
e1.printStackTrace();
}
if (output.contains("which: no vlc") || output == "") {
JFXInfoAlert vlcInfoAlert = new JFXInfoAlert("Info",
XMLController.getLocalBundle().getString("vlcNotInstalled"), btnStyle, primaryStage);
vlcInfoAlert.showAndWait();
} else {
try {
new ProcessBuilder("vlc", currentTableFilm.getStreamUrl()).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(currentTableFilm.getStreamUrl()));
} 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! ");
}
}
}
}
// general fxml actions
@FXML
private void aboutBtnAction() {
@ -272,6 +212,7 @@ public class MainWindowController {
if (selectedFolder != null && selectedFolder.exists()) {
selectFirstSource.getAlert().close();
writeSource(selectedFolder.getPath(), "local");
settingsViewController.loadInitSources();
} else {
LOGGER.error("The selected folder dosen't exist!");
System.exit(1);
@ -286,6 +227,7 @@ public class MainWindowController {
if (selectedFile != null && selectedFile.exists()) {
selectFirstSource.getAlert().close();
writeSource(selectedFile.getPath(), "stream");
settingsViewController.loadInitSources();
} else {
LOGGER.error("The selected file dosen't exist!");
System.exit(1);
@ -411,20 +353,9 @@ public class MainWindowController {
}
}
/**
* 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"));
}
/**
* Poser Mode WIP
* Poser Mode
*/
private void posterModeStartup() {
@ -437,13 +368,15 @@ public class MainWindowController {
* check if all posters are cached, if not cache the missing ones
*/
void checkAllPosters() {
dbController.refreshDataBase(); // refreshes the database after a source path was added
// get all not cached entries, none of them should have a cached poster
ExecutorService executor = Executors.newFixedThreadPool(5);
for (FilmTabelDataType entry : dbController.getAllNotCachedEntries()) {
System.out.println(entry.getStreamUrl() + " is NOT cached!");
Runnable OMDbAPIWorker = new OMDbAPIController(entry, XMLController.getOmdbAPIKey());
Runnable OMDbAPIWorker = new OMDbAPIController(entry);
executor.execute(OMDbAPIWorker);
}
executor.shutdown();
@ -457,8 +390,6 @@ public class MainWindowController {
LOGGER.error(e);
}
// update all elements from the database
dbController.refreshDataBase(); // refreshes the database after a source path was added
System.out.println("finished refresh");
}
@ -502,7 +433,7 @@ public class MainWindowController {
for(FilmTabelDataType entry : dbController.getStreamsList()) {
if (dbController.getCacheDate(entry.getStreamUrl()).isBefore(lastValidCache)) {
System.out.println(entry.getTitle() + " chached on: " + dbController.getCacheDate(entry.getStreamUrl()));
Runnable OMDbAPIWorker = new OMDbAPIController(entry, XMLController.getOmdbAPIKey());
Runnable OMDbAPIWorker = new OMDbAPIController(entry);
executor.execute(OMDbAPIWorker);
}
}

View File

@ -48,6 +48,7 @@ import javafx.util.Duration;
import kellerkinder.HomeFlix.controller.DBController;
import kellerkinder.HomeFlix.controller.XMLController;
import kellerkinder.HomeFlix.datatypes.SeriresDVEpisode;
import kellerkinder.HomeFlix.player.Player;
public class SeriesDetailView {
@ -121,7 +122,7 @@ public class SeriesDetailView {
@FXML
private void btnPlayAction() {
// playFilm(); // TODO
new Player(dbController.getLastWatchedEpisode(currentStreamURL));
}
@FXML

View File

@ -243,7 +243,8 @@ public class SettingsView {
}
// add a all elements of sourcesList to the sources table on the settings pane
private void loadInitSources() {
void loadInitSources() {
if(new File(XMLController.getDirHomeFlix() + "/sources.json").exists()) {
try {
// create a JsonArray, containing all sources, add each source to the mwc, get all films from it
JsonArray sources = Json.parse(new FileReader(XMLController.getDirHomeFlix() + "/sources.json")).asArray();
@ -256,6 +257,7 @@ public class SettingsView {
e.printStackTrace();
}
}
}
public void updateColor(String btnStyle) {
updateBtn.setStyle(btnStyle);

View File

@ -42,7 +42,6 @@ import org.apache.logging.log4j.Logger;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import kellerkinder.HomeFlix.datatypes.DatabaseDataType;
import kellerkinder.HomeFlix.datatypes.FilmTabelDataType;
import kellerkinder.HomeFlix.datatypes.OMDbAPIResponseDataType;
@ -52,8 +51,6 @@ public class DBController {
private static DBController instance = null;
private String DB_PATH;
private Image favorite_black = new Image("icons/baseline_favorite_black_48dp.png"); // TODO this should be removed
private Image favorite_border_black = new Image("icons/baseline_favorite_border_black_48dp.png"); // TODO this too
private List<DatabaseDataType> databaseStreams = new ArrayList<DatabaseDataType>(); // contains all films stored in the database
private List<DatabaseDataType> sourceStreams = new ArrayList<DatabaseDataType>(); // contains all films from the sources
private Connection connection = null;
@ -161,10 +158,8 @@ public class DBController {
ResultSet rs = stmt.executeQuery("SELECT * FROM films ORDER BY title");
while (rs.next()) {
ImageView imageView = rs.getBoolean("favorite") ? new ImageView(favorite_black) : new ImageView(favorite_border_black);
filmsList.add(new FilmTabelDataType(rs.getString("streamUrl"),
rs.getString("title"), rs.getString("season"), rs.getString("episode") ,rs.getBoolean("favorite"),
imageView));
rs.getString("title"), rs.getString("season"), rs.getString("episode")));
}
stmt.close();
rs.close();
@ -189,10 +184,8 @@ public class DBController {
ResultSet rs = ps.executeQuery();
while (rs.next()) {
ImageView imageView = rs.getBoolean("favorite") ? new ImageView(favorite_black) : new ImageView(favorite_border_black);
film = new FilmTabelDataType(rs.getString("streamUrl"),
rs.getString("title"), rs.getString("season"), rs.getString("episode"), rs.getBoolean("favorite"),
imageView);
rs.getString("title"), rs.getString("season"), rs.getString("episode"));
}
rs.close();
ps.close();
@ -597,8 +590,7 @@ public class DBController {
ResultSet rs = stmt.executeQuery("SELECT * FROM films WHERE cached = 0");
while (rs.next()) {
notCachedEntries.add(new FilmTabelDataType(rs.getString("streamUrl"),
rs.getString("title"), rs.getString("season"), rs.getString("episode"), rs.getBoolean("favorite"),
new ImageView(favorite_border_black)));
rs.getString("title"), rs.getString("season"), rs.getString("episode")));
}
stmt.close();
rs.close();
@ -682,7 +674,8 @@ public class DBController {
/**
* get the next episode of a series
* @param title title of the film
* @param episode episode currently played
* @param episode current episode
* @param season season of the current episode
* @return {@link FilmTabelDataType} the next episode as object
*/
public FilmTabelDataType getNextEpisode(String title, int episode, int season) {
@ -710,8 +703,7 @@ public class DBController {
// at this point we have found the correct episode
nextFilm = new FilmTabelDataType(rs.getString("streamUrl"), rs.getString("title"),
rs.getString("season"), rs.getString("episode"), rs.getBoolean("favorite"),
new ImageView());
rs.getString("season"), rs.getString("episode"));
rs.close();
ps.close();
@ -723,33 +715,31 @@ public class DBController {
/** TODO rework, we should save the next episode in the root entry
* get the last watched episode
* @param title the title of the series
* @return the last watched episode as {@link FilmTabelDataType} object
* @param streamURL URL of the stream
* @return the last watched episodes URL
*/
public FilmTabelDataType getLastWatchedEpisode(String title) {
LOGGER.info("last watched episode of: " + title);
FilmTabelDataType nextFilm = null;
public String getLastWatchedEpisode(String streamURL) {
LOGGER.info("last watched episode in: " + streamURL);
String lastEp = null;
double lastCurrentTime = 0;
try {
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM films WHERE title = \"" + title + "\";");
PreparedStatement ps = connection.prepareStatement("SELECT * FROM films WHERE streamUrl LIKE ?");
ps.setString(1, streamURL + "/%");
ResultSet rs = ps.executeQuery();
while (rs.next()) {
nextFilm = new FilmTabelDataType(rs.getString("streamUrl"), rs.getString("title"),
rs.getString("season"), rs.getString("episode"), rs.getBoolean("favorite"),
new ImageView());
// get the first episode where currentTime != 0
if (rs.getDouble("currentTime") > lastCurrentTime) {
break;
if (rs.getDouble("currentTime") > lastCurrentTime || lastEp == null) {
lastEp = rs.getString("streamUrl");
}
}
rs.close();
stmt.close();
ps.close();
} catch (Exception e) {
LOGGER.error("Ups! error while getting the last watched episode!", e);
}
return nextFilm;
return lastEp;
}
/**

View File

@ -55,9 +55,9 @@ public class OMDbAPIController implements Runnable {
* @param currentTableFilm the current film object
* @param omdbAPIKey the omdbAPI key
*/
public OMDbAPIController(FilmTabelDataType currentTableFilm, String omdbAPIKey) {
public OMDbAPIController(FilmTabelDataType currentTableFilm) {
this.currentTableFilm = currentTableFilm;
this.omdbAPIKey = omdbAPIKey;
omdbAPIKey = XMLController.getOmdbAPIKey();
dbController = DBController.getInstance();
}

View File

@ -20,20 +20,11 @@
*/
package kellerkinder.HomeFlix.datatypes;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.image.ImageView;
public class FilmTabelDataType {
private final StringProperty streamUrl = new SimpleStringProperty();
private final StringProperty title = new SimpleStringProperty();
private final StringProperty season = new SimpleStringProperty();
private final StringProperty episode = new SimpleStringProperty();
private final BooleanProperty favorite = new SimpleBooleanProperty();
private final SimpleObjectProperty<ImageView> image = new SimpleObjectProperty<>();
private String streamUrl;
private String title;
private String season;
private String episode;
/**
* tableData is the data-type of tree-table-view
@ -41,93 +32,44 @@ public class FilmTabelDataType {
* @param title title of the film
* @param season season if it's a series
* @param episode episode if it's a series
* @param favorite indicator for favorites, used for sorting the items
* @param cached indicator for caching status
* @param image favorite icon
*/
public FilmTabelDataType(final String streamUrl, final String title, final String season, final String episode,
final boolean favorite, final ImageView image) {
this.streamUrl.set(streamUrl);
this.title.set(title);
this.season.set(season);
this.episode.set(episode);
this.favorite.set(favorite);
this.image.set(image);
public FilmTabelDataType(String streamUrl, String title, String season, String episode) {
this.streamUrl = streamUrl;
this.title = title;
this.season = season;
this.episode = episode;
}
public StringProperty streamUrlProperty(){
public String getStreamUrl() {
return streamUrl;
}
public StringProperty titleProperty(){
public String getTitle() {
return title;
}
public StringProperty seasonProperty(){
public String getSeason() {
return season;
}
public StringProperty episodeProperty(){
public String getEpisode() {
return episode;
}
public BooleanProperty favoriteProperty(){
return favorite;
public void setStreamUrl(String streamUrl) {
this.streamUrl = streamUrl;
}
public SimpleObjectProperty<ImageView> imageProperty(){
return image;
public void setTitle(String title) {
this.title = title;
}
public final String getStreamUrl() {
return streamUrlProperty().get();
public void setSeason(String season) {
this.season = season;
}
public final String getTitle() {
return titleProperty().get();
public void setEpisode(String episode) {
this.episode = episode;
}
public final String getSeason() {
return seasonProperty().get();
}
public final String getEpisode() {
return episodeProperty().get();
}
public final boolean getFavorite() {
return favoriteProperty().get();
}
public final ImageView getImage() {
return imageProperty().get();
}
public final void setStreamUrl(String streamUrl) {
streamUrlProperty().set(streamUrl);
}
public final void setTitle(String title) {
titleProperty().set(title);
}
public final void setSeason(String season) {
seasonProperty().set(season);
}
public final void setEpisode(String season) {
episodeProperty().set(season);
}
public final void setFavorite(boolean favorite) {
favoriteProperty().set(favorite);
}
public final void setImage(ImageView image) {
imageProperty().set(image);
}
}

View File

@ -22,8 +22,16 @@
package kellerkinder.HomeFlix.player;
import java.awt.Desktop;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URLConnection;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.Image;
@ -31,13 +39,13 @@ import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
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;
private static final Logger LOGGER = LogManager.getLogger(Player.class.getName());
// TODO move the players choose logic to a separate static class
@ -46,6 +54,20 @@ public class Player {
* @param currentTableFilm the currently selected film
*/
public Player(String streamURL) {
if (isSupportedFormat(streamURL)) {
hfPlayer(streamURL);
} else {
legacyPlayer(streamURL);
}
}
/**
* start the integrated player
* @param streamURL
*/
private void hfPlayer(String streamURL) {
playerController = new PlayerController(this, streamURL);
try {
@ -73,6 +95,61 @@ public class Player {
}
}
/**
*
*/
private void legacyPlayer(String streamURL) {
LOGGER.warn("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("which vlc: " + output);
input.close();
} catch (IOException e1) {
e1.printStackTrace();
}
if (output.contains("which: no vlc") || output == "") {
// JFXInfoAlert vlcInfoAlert = new JFXInfoAlert("Info",
// XMLController.getLocalBundle().getString("vlcNotInstalled"), btnStyle, primaryStage);
// vlcInfoAlert.showAndWait();
} else {
try {
new ProcessBuilder("vlc", streamURL).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(streamURL));
} 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 streamURL URL of the stream you want to check
* @return true if so, false if not
*/
public static boolean isSupportedFormat(String streamURL) {
String mimeType = URLConnection.guessContentTypeFromName(streamURL);
return mimeType != null && (mimeType.contains("mp4") || mimeType.contains("vp6"));
}
public Stage getStage() {
return stage;
}
@ -81,16 +158,4 @@ public class Player {
return scene;
}
/**
* 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
*/
public static boolean isSupportedFormat(String streamURL) {
String mimeType = URLConnection.guessContentTypeFromName(streamURL);
return mimeType != null && (mimeType.contains("mp4") || mimeType.contains("vp6"));
}
}

View File

@ -90,7 +90,7 @@ public class JFX2BtnCancelAlert {
JFXButton cancelBtn = new JFXButton();
cancelBtn.setText(cancelText);
cancelBtn.addEventHandler(ActionEvent.ACTION, (e)-> alert.close());
cancelBtn.addEventHandler(ActionEvent.ACTION, (e)-> System.exit(0)); // TODO only on first start
cancelBtn.setButtonType(com.jfoenix.controls.JFXButton.ButtonType.RAISED);
cancelBtn.setPrefHeight(32);
cancelBtn.setStyle(btnStyle);
@ -100,11 +100,15 @@ public class JFX2BtnCancelAlert {
content.setHeading(new Text(headingText));
content.setBody(new Text(bodyText));
// TODO only on first start
// only on first start
if (stage == null) {
cancelBtn.addEventHandler(ActionEvent.ACTION, (e)-> System.exit(0));
Stage stage = (Stage) alert.getDialogPane().getScene().getWindow();
stage.setMinWidth(416);
stage.setMinHeight(162);
stage.setOnCloseRequest(event -> System.exit(0));
}
alert.setContent(content);
alert.showAndWait();