1
0
Fork 0

IDK anymore...

master
Ambrose Chua 2015-10-14 22:38:03 +08:00
parent 5234de8abf
commit 0cf2a744fa
11 changed files with 287 additions and 88 deletions

View File

@ -1,7 +1,8 @@
package io.makerforce.undefined.model;
import io.makerforce.undefined.util.Util;
import javafx.collections.ObservableList;
import javafx.scene.image.Image;
import org.json.JSONArray;
import org.json.JSONObject;
import java.net.URL;
@ -12,19 +13,19 @@ public class Album extends ItemList<Track> {
super();
}
public Album(Image picture, String title, String artist) {
public Album(URL picture, String title, String artist) {
super(picture, title, artist);
}
public Album(JSONObject o, String albumName, String artistName, URL endPoint) {
this(new Image(endPoint.toString() + o.getString("picture")), albumName, artistName);
o.getJSONObject("tracks").keySet().forEach((key) -> {
Track a = new Track(o.getJSONObject("tracks").getJSONObject(key), endPoint); //, key, albumName, artistName);
this(Util.toURLOrNull(endPoint + o.getString("picture")), albumName, artistName);
JSONArray tracks = o.getJSONArray("tracks");
for (int i = 0; i < tracks.length(); i++) {
Track a = new Track(o.getJSONArray("tracks").getJSONObject(i), albumName, artistName, endPoint); // Track a = new Track(o.getJSONArray("tracks").getJSONObject(i), endPoint);
super.getItems().add(a);
});
}
}
public ObservableList<Track> getTracks() {
return this.getItems();
}

View File

@ -1,7 +1,7 @@
package io.makerforce.undefined.model;
import io.makerforce.undefined.util.Util;
import javafx.collections.ObservableList;
import javafx.scene.image.Image;
import org.json.JSONObject;
import java.net.URL;
@ -12,12 +12,12 @@ public class Artist extends ItemList<Album> {
super();
}
public Artist(Image picture, String title) {
public Artist(URL picture, String title) {
super(picture, title);
}
public Artist(JSONObject o, String artistName, URL endPoint) {
this(new Image(endPoint.toString() + o.getString("picture")), artistName);
this(Util.toURLOrNull(endPoint + o.getString("picture")), artistName);
o.getJSONObject("albums").keySet().forEach((key) -> {
Album a = new Album(o.getJSONObject("albums").getJSONObject(key), key, artistName, endPoint);
super.getItems().add(a);

View File

@ -1,10 +1,10 @@
package io.makerforce.undefined.model;
import javafx.scene.image.Image;
import java.net.URL;
public interface Item {
public Image getPicture();
public URL getPicture();
public String getTitle();

View File

@ -2,23 +2,24 @@ package io.makerforce.undefined.model;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.image.Image;
import java.net.URL;
public class ItemList<T> implements Item {
private Image picture;
private URL picture;
private String title;
private String subtitle;
private ObservableList<T> items = FXCollections.observableArrayList();
public ItemList(Image picture, String title, String subtitle) {
public ItemList(URL picture, String title, String subtitle) {
this.picture = picture;
this.title = title;
this.subtitle = subtitle;
}
public ItemList(Image picture, String title) {
public ItemList(URL picture, String title) {
this(picture, title, "");
}
@ -26,7 +27,7 @@ public class ItemList<T> implements Item {
this(null, "", "");
}
public Image getPicture() {
public URL getPicture() {
return picture;
}

View File

@ -1,18 +1,15 @@
package io.makerforce.undefined.model;
import javafx.scene.image.Image;
import io.makerforce.undefined.util.Util;
import org.json.JSONArray;
import org.json.JSONObject;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.StreamSupport;
public class Track implements Item {
private URL file;
private Image picture;
private URL picture;
private String title;
private String artist;
private String album;
@ -25,25 +22,38 @@ public class Track implements Item {
}
@Deprecated
public Track(JSONObject track, URL endPoint) {
this(track, "", "", endPoint);
}
public Track(JSONObject track, String albumName, String artistName, URL endPoint) {
this();
title = track.getString("title");
try {
file = new URL(endPoint.toString() + track.getString("file"));
} catch (MalformedURLException e) {
e.printStackTrace();
file = null;
}
picture = new Image(endPoint + track.getString("picture"));
artist = track.getString("artist");
album = track.getString("album");
title = Util.getNotEmpty(
track.getString("title"),
(track.has("filetitle") ? track.getString("filetitle") : "")
);
file = Util.toURLOrNull(endPoint + track.getString("file"));
picture = Util.toURLOrNull(endPoint + track.getString("picture"));
artist = Util.getNotEmpty(
(track.getJSONArray("artist").length() > 0 ? track.getJSONArray("artist").getString(0) : ""),
artistName
);
album = Util.getNotEmpty(
track.getString("album"),
albumName
);
year = track.getString("year");
trackNumber = track.getInt("number"); // track.getJSONObject("track").getInt("no");
totalTracks = track.getJSONObject("track").getInt("of");
genre = (String[]) StreamSupport.stream(Spliterators.spliteratorUnknownSize(track.getJSONArray("genre").iterator(), Spliterator.ORDERED), false).toArray();
JSONArray genres = track.getJSONArray("genre");
genre = new String[genres.length()];
for (int i = 0; i < genres.length(); i++) {
genre[i] = genres.getString(i);
}
}
public Image getPicture() {
public URL getPicture() {
return picture;
}

View File

@ -14,13 +14,17 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class LibraryManager extends SimpleObjectProperty<LibraryManager.LibraryManagerState> {
public class LibraryManager {
public static final LibraryManagerState EMPTY = new LibraryManagerState("empty");
public static final LibraryManagerState UPDATING = new LibraryManagerState("updating");
public static final LibraryManagerState ERROR = new LibraryManagerState("error");
public static final LibraryManagerState READY = new LibraryManagerState("ready");
public static final String DEFAULT_ENDPOINT = "http://ambrose.makerforce.io:8080/";
private SimpleObjectProperty<LibraryManagerState> state = new SimpleObjectProperty<>();
private URL endPoint;
private Library l;
@ -29,20 +33,20 @@ public class LibraryManager extends SimpleObjectProperty<LibraryManager.LibraryM
private boolean hasScheduled = false;
public LibraryManager() {
this.set(EMPTY);
state.set(EMPTY);
try {
this.endPoint = new URL("http://ambrose.makerforce.io:8080/");
this.endPoint = new URL(DEFAULT_ENDPOINT);
} catch (MalformedURLException e) {
e.printStackTrace(); // THIS SHOULD NEVER HAPPEN
}
}
public LibraryManager(URL endPoint) {
this.set(EMPTY);
state.set(EMPTY);
this.endPoint = endPoint;
if (!endPoint.toString().endsWith("/")) {
if (!this.endPoint.toString().endsWith("/")) {
try {
endPoint = new URL(endPoint.toString() + "/");
this.endPoint = new URL(endPoint.toString() + "/");
} catch (MalformedURLException e) {
e.printStackTrace(); // ALSO SHOULD NEVER HAPPEN
}
@ -60,7 +64,7 @@ public class LibraryManager extends SimpleObjectProperty<LibraryManager.LibraryM
public void update() {
new Thread(() -> {
try {
this.set(UPDATING);
state.set(UPDATING);
HttpURLConnection con = (HttpURLConnection) endPoint.openConnection();
con.setRequestMethod("GET");
@ -83,10 +87,10 @@ public class LibraryManager extends SimpleObjectProperty<LibraryManager.LibraryM
JSONObject obj = new JSONObject(response.toString());
l = new Library(obj, endPoint);
this.set(READY);
state.set(READY);
} catch (IOException e) {
e.printStackTrace();
this.set(ERROR);
state.set(ERROR);
}
}).run();
}

View File

@ -0,0 +1,137 @@
package io.makerforce.undefined.util;
import io.makerforce.undefined.model.Track;
import javafx.beans.property.*;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.util.Duration;
import java.util.ArrayList;
public class PlayManager {
public static final PlayManagerState STOPPED = new PlayManagerState("stopped");
public static final PlayManagerState PAUSED = new PlayManagerState("paused");
public static final PlayManagerState PLAYING = new PlayManagerState("playing");
public static final PlayManagerState ENDED = new PlayManagerState("ended");
private SimpleObjectProperty<PlayManagerState> state = new SimpleObjectProperty<>(STOPPED);
private ArrayList<Track> queue = new ArrayList<>();
private IntegerProperty currentTrack = new SimpleIntegerProperty(0);
private MediaPlayer player;
private BooleanProperty muted = new SimpleBooleanProperty();
private DoubleProperty volume = new SimpleDoubleProperty();
private DoubleProperty currentPercent = new SimpleDoubleProperty();
private ObjectProperty<Duration> timeLeft = new SimpleObjectProperty<>();
private ObjectProperty<Duration> currentTime = new SimpleObjectProperty<>();
private ObjectProperty<Duration> totalTime = new SimpleObjectProperty<>();
private ChangeListener<Duration> currentTimeChange = new ChangeListener<Duration>() {
@Override
public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration c) {
currentPercent.set(c.toMillis() / player.getTotalDuration().toMillis());
currentTime.set(c);
timeLeft.set(c.subtract(currentTime.get()));
}
};
public PlayManager() {
}
private void load(Track track) {
player = new MediaPlayer(new Media(track.getFile().toString()));
player.muteProperty().bind(muted);
player.volumeProperty().bind(volume);
player.currentTimeProperty().addListener(currentTimeChange);
totalTime.set(player.totalDurationProperty().get());
}
public void play() {
if (state.equals(PAUSED) || state.equals(STOPPED)) {
player.play();
state.set(PLAYING);
} else if (state.equals(ENDED)) {
next();
}
}
public void pause() {
if (state.equals(PLAYING)) {
player.pause();
state.set(PAUSED);
}
}
public void previous() {
if (currentTime.get().toSeconds() < 1) {
player.stop();
if (currentTrack.get() - 1 > 0) {
currentTrack.subtract(1);
load(queue.get(currentTrack.get()));
}
} else {
player.seek(new Duration(0));
}
}
public void next() {
player.stop();
if (currentTrack.get() + 1 < queue.size()) {
currentTrack.add(1);
load(queue.get(currentTrack.get()));
}
}
public void addToQueue(Track track) {
queue.add(track);
}
public BooleanProperty muteProperty() {
return muted;
}
public DoubleProperty volumeProperty() {
return volume;
}
public ObjectProperty<PlayManagerState> stateProperty() {
return state;
}
public DoubleProperty currentPercent() {
return currentPercent;
}
public ObjectProperty<Duration> currentTimeProperty() {
return currentTime;
}
public ObjectProperty<Duration> timeLeftProperty() {
return timeLeft;
}
public ObjectProperty<Duration> totalTimeProperty() {
return totalTime;
}
public static final class PlayManagerState {
private final String text;
public PlayManagerState(String text) {
this.text = text;
}
public String toString() {
return text;
}
}
}

View File

@ -1,16 +1,11 @@
package io.makerforce.undefined.util;
import io.makerforce.undefined.model.Album;
import io.makerforce.undefined.model.Artist;
import io.makerforce.undefined.model.Library;
import io.makerforce.undefined.model.Track;
import java.net.MalformedURLException;
public class TestClasses {
public static void main(String[] args) throws MalformedURLException {
/*
Library l = new Library();
Album a1 = new Album();
@ -30,6 +25,7 @@ public class TestClasses {
l.getItems().addAll(r1, r2);
System.out.println(l.toString()); // Should print [[[null (null, null), null (null, null), null (null, null), null (null, null)], [null (null, null), null (null, null), null (null, null), null (null, null)]], [[], []]]
*/
LibraryManager a = new LibraryManager();
a.update();

View File

@ -1,6 +1,12 @@
package io.makerforce.undefined.util;
import javafx.util.Duration;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.net.MalformedURLException;
import java.net.URL;
public class Util {
@ -8,4 +14,44 @@ public class Util {
int sec = (int) d.toSeconds();
return String.format((sec < 0 ? "-" : "") + "%d:%02d", (sec < 0 ? -sec : sec) / 60, ((sec < 0 ? -sec : sec) % 60));
}
public static URL toURLOrNull(String url) {
try {
return new URL(url);
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
}
}
@Deprecated
public static String getStringFromJSONObject(JSONObject object, String key) {
try {
return object.getString(key);
} catch (JSONException e) {
//e.printStackTrace();
return "";
}
}
@Deprecated
public static String getStringFromJSONArray(JSONArray array, int key) {
try {
return array.getString(key);
} catch (JSONException e) {
//e.printStackTrace();
return "";
}
}
public static String getNotEmpty(String... strings) {
for (String s : strings) {
if (!s.isEmpty()) {
return s;
}
}
return "";
}
}

View File

@ -1,10 +1,10 @@
package io.makerforce.undefined.view;
import io.makerforce.undefined.model.Track;
import io.makerforce.undefined.util.LibraryManager;
import io.makerforce.undefined.util.PlayManager;
import io.makerforce.undefined.util.Util;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
@ -13,10 +13,11 @@ import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.VBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.util.Duration;
import org.json.JSONObject;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@ -76,21 +77,21 @@ public class InterfaceController {
@FXML
private ImageView statusIcon;
private MediaPlayer player;
private BooleanProperty isPlaying = new SimpleBooleanProperty(false);
//private MediaPlayer player;
private PlayManager player = new PlayManager();
public InterfaceController() {
player = new MediaPlayer(new Media("http://ambrose.makerforce.io:8080/tracks/Alan%20Walker/Fade/Fade.mp3"));
}
public void initialize() {
// Temporary stuff
trackList = new TrackListController();
coverList = new CoverListController();
// Temporary stuff
/*
currentImage.setImage(new Image("http://ambrose.makerforce.io:8080/art/Alan%20Walker/Fade/1"));
currentArtist.setText("Alan Walker");
currentTitle.setText("Fade");
@ -101,7 +102,12 @@ public class InterfaceController {
flowPane.getChildren().add(new CoverItemController(new Image("http://ambrose.makerforce.io:8080/art/Alan%20Walker/Fade/1"), "Fade", "Alan Walker"));
flowPane.getChildren().add(new CoverItemController(new Image("http://ambrose.makerforce.io:8080/art/Alan%20Walker/Fade/1"), "Alan Walker"));
flowPane.getChildren().add(new CoverItemController(new Image("http://ambrose.makerforce.io:8080/art/Alan%20Walker/Fade/1"), "Alan Walker"));
*/
try {
player.addToQueue(new Track(new JSONObject(""), "", "", new URL(LibraryManager.DEFAULT_ENDPOINT)));
} catch (MalformedURLException e) {
e.printStackTrace();
}
// UI Bindings
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
@ -136,43 +142,31 @@ public class InterfaceController {
// Player events
// Playback status
player.statusProperty().addListener((observable, oldValue, s) -> {
if (
s == MediaPlayer.Status.PAUSED ||
s == MediaPlayer.Status.READY ||
s == MediaPlayer.Status.STOPPED ||
s == MediaPlayer.Status.UNKNOWN ||
s == MediaPlayer.Status.HALTED
) {
pausePlayButtonIcon.setImage(playIcon);
isPlaying.setValue(false);
} else {
player.stateProperty().addListener((observable, old, state) -> {
if (state == PlayManager.PLAYING) {
pausePlayButtonIcon.setImage(pauseIcon);
isPlaying.setValue(true);
} else {
pausePlayButtonIcon.setImage(playIcon);
}
});
// Update slider position when music plays.
ChangeListener<Duration> updateSlider = (observable, oldValue, c) -> {
playbackSlider.setValue(c.toMillis() / player.getTotalDuration().toMillis());
playbackTimeLabel.setText(Util.durationToString(player.getCurrentTime()));
};
player.currentTimeProperty().addListener(updateSlider);
playbackSlider.valueProperty().bind(player.currentPercent());
// Update labels.
playbackSlider.valueProperty().addListener((observable1, oldValue1, v) -> {
Duration d = new Duration(v.doubleValue() * player.getTotalDuration().toMillis());
Duration d = new Duration(v.doubleValue() * player.totalTimeProperty().get().toMillis());
playbackTimeLabel.setText(Util.durationToString(d));
playbackLeftLabel.setText(Util.durationToString(d.subtract(player.getTotalDuration())));
playbackLeftLabel.setText(Util.durationToString(d.subtract(player.totalTimeProperty().get())));
});
// Seek when slider is released.
playbackSlider.valueChangingProperty().addListener((observable, oldValue, c) -> {
if (c) {
player.currentTimeProperty().removeListener(updateSlider);
playbackSlider.valueProperty().unbind();
} else {
player.currentTimeProperty().addListener(updateSlider);
player.seek(new Duration(playbackSlider.getValue() * player.getTotalDuration().toMillis()));
playbackSlider.valueProperty().bind(player.currentPercent());
//player.seek(new Duration(playbackSlider.getValue() * player.totalTimeProperty().get().toMillis()));
}
});
@ -181,7 +175,7 @@ public class InterfaceController {
@FXML
private void pausePlay() {
if (isPlaying.get()) {
if (player.stateProperty().get() == PlayManager.PLAYING) {
player.pause();
} else {
player.play();

View File

@ -6,7 +6,7 @@
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="400.0"
minWidth="600.0" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/null"
minWidth="600.0" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40"
fx:controller="io.makerforce.undefined.view.InterfaceController">
<bottom>
<HBox alignment="CENTER_LEFT" spacing="7.0" BorderPane.alignment="CENTER_LEFT">
@ -73,8 +73,18 @@
<HBox alignment="CENTER" spacing="7.0" HBox.hgrow="ALWAYS">
<children>
<Label fx:id="playbackTimeLabel" minWidth="42.0" prefHeight="24.0" text="--:--"/>
<Slider fx:id="playbackSlider" max="1.0" min="0.0" prefHeight="16.0" prefWidth="156.0"
HBox.hgrow="ALWAYS"/>
<StackPane HBox.hgrow="ALWAYS">
<children>
<ProgressBar fx:id="bufferProgress" minHeight="-Infinity" prefHeight="8.0"
prefWidth="1000.0" progress="0.0" StackPane.alignment="BOTTOM_CENTER">
<StackPane.margin>
<Insets bottom="-5.0" left="4.0" right="6.0"/>
</StackPane.margin>
</ProgressBar>
<Slider fx:id="playbackSlider" max="1.0" min="0.0" prefHeight="16.0" prefWidth="1000.0"
StackPane.alignment="CENTER"/>
</children>
</StackPane>
<Label fx:id="playbackLeftLabel" alignment="CENTER_RIGHT" minWidth="42.0" prefHeight="24.0"
text="--:--"/>
</children>