Adds full support for YouTube playback.
While a few optimizations could be made, YouTube playback is almost as seamless as local playback.
This commit is contained in:
@@ -4,13 +4,20 @@ var numTabMessages = 0;
|
|||||||
/*
|
/*
|
||||||
On startup, connect to the "ping_pong" app.
|
On startup, connect to the "ping_pong" app.
|
||||||
*/
|
*/
|
||||||
var port = browser.runtime.connectNative("universalmusic");
|
var interfacePort = browser.runtime.connectNative("universalmusic");
|
||||||
|
|
||||||
var tabPort = null;
|
var tabPort = null;
|
||||||
|
|
||||||
function setupTab(port)
|
function setupTab(port)
|
||||||
{
|
{
|
||||||
console.info("Tab " + port.sender.tab.url + " loaded.");
|
if (port.sender)
|
||||||
|
{
|
||||||
|
console.info("Tab " + port.sender.tab.url + " loaded.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
console.info("Tab loaded");
|
||||||
|
}
|
||||||
tabPort = port;
|
tabPort = port;
|
||||||
tabPort.onDisconnect.addListener(e => {
|
tabPort.onDisconnect.addListener(e => {
|
||||||
tabPort = null;
|
tabPort = null;
|
||||||
@@ -25,9 +32,21 @@ function setupTab(port)
|
|||||||
browser.tabs.remove(e.sender.tab.id);
|
browser.tabs.remove(e.sender.tab.id);
|
||||||
});
|
});
|
||||||
tabPort.onMessage.addListener(message => {
|
tabPort.onMessage.addListener(message => {
|
||||||
if (typeof message == "object" && message.type == "response")
|
if (typeof message == "object")
|
||||||
{
|
{
|
||||||
tabMessages.set(message.num, message.data);
|
if (message.type == "response")
|
||||||
|
{
|
||||||
|
tabMessages.set(message.num, message.data);
|
||||||
|
}
|
||||||
|
else if (message.type == "update")
|
||||||
|
{
|
||||||
|
returnValue = {
|
||||||
|
"messageNum": -1,
|
||||||
|
"message": message.data
|
||||||
|
}
|
||||||
|
console.trace("Sending update ", returnValue)
|
||||||
|
interfacePort.postMessage(returnValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
@@ -70,15 +89,20 @@ var listeners = [function (message, returnValue) {
|
|||||||
}
|
}
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case "CommandSong":
|
case "CommandLoadSong":
|
||||||
returnValue = () => browser.tabs.create({url: message.song}).then(setupTab);
|
returnValue = () => {
|
||||||
|
if (message.song)
|
||||||
|
{
|
||||||
|
browser.tabs.create({url: message.song});
|
||||||
|
}
|
||||||
|
}
|
||||||
if (tabPort)
|
if (tabPort)
|
||||||
{
|
{
|
||||||
console.log("Replacing tab");
|
console.log("Replacing tab");
|
||||||
/*
|
/*
|
||||||
* Closes the existing tab first
|
* Closes the existing tab first
|
||||||
*/
|
*/
|
||||||
returnValue = browser.tabs.remove(e.sender.tab.id).then(returnValue);
|
returnValue = browser.tabs.remove(tabPort.sender.tab.id).then(returnValue);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -89,7 +113,7 @@ var listeners = [function (message, returnValue) {
|
|||||||
case "QueryStatus":
|
case "QueryStatus":
|
||||||
if (!tabPort)
|
if (!tabPort)
|
||||||
{
|
{
|
||||||
returnValue = 4;
|
returnValue = "EMPTY";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "QueryTime":
|
case "QueryTime":
|
||||||
@@ -139,6 +163,7 @@ function handleMessage(message)
|
|||||||
{
|
{
|
||||||
returnValue = listeners[index](message, returnValue);
|
returnValue = listeners[index](message, returnValue);
|
||||||
}
|
}
|
||||||
|
console.debug("Message returned ", returnValue);
|
||||||
if (returnValue instanceof Promise)
|
if (returnValue instanceof Promise)
|
||||||
{
|
{
|
||||||
returnValue.then(resolve).catch(reject);
|
returnValue.then(resolve).catch(reject);
|
||||||
@@ -158,7 +183,7 @@ function handleMessage(message)
|
|||||||
/*
|
/*
|
||||||
* Listen for messages from the app.
|
* Listen for messages from the app.
|
||||||
*/
|
*/
|
||||||
port.onMessage.addListener((message) => {
|
interfacePort.onMessage.addListener((message) => {
|
||||||
console.log("Received from interface: ", message);
|
console.log("Received from interface: ", message);
|
||||||
|
|
||||||
handleMessage(message.message).then((response) => {
|
handleMessage(message.message).then((response) => {
|
||||||
@@ -175,9 +200,9 @@ port.onMessage.addListener((message) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log("Sending ", returnValue)
|
console.log("Sending ", returnValue)
|
||||||
port.postMessage(returnValue);
|
interfacePort.postMessage(returnValue);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
console.error("Error in evaluating message: ", error)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,16 @@ function handleMessage(message)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onStatusUpdate(status, time, songData)
|
||||||
|
{
|
||||||
|
sendUpdate({
|
||||||
|
type: "edu.regis.universeplayer.PlaybackInfo",
|
||||||
|
currentSong: songData,
|
||||||
|
status: status,
|
||||||
|
playTime: time
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function sendUpdate(response)
|
function sendUpdate(response)
|
||||||
{
|
{
|
||||||
post = data => background.postMessage({
|
post = data => background.postMessage({
|
||||||
|
|||||||
@@ -3,26 +3,51 @@ var video;
|
|||||||
|
|
||||||
function onload()
|
function onload()
|
||||||
{
|
{
|
||||||
video = document.getElementsByClassName('video-stream html5-main-video')[0]
|
video = document.getElementsByClassName('video-stream html5-main-video')[0];
|
||||||
|
statusUpdate = e => {
|
||||||
|
return onStatusUpdate(getState(), e.srcElement.currentTime, getSongData());
|
||||||
|
};
|
||||||
|
// video.addListener("timeupdate", statusUpdate);
|
||||||
|
// video.addListener("play", statusUpdate);
|
||||||
|
// video.addListener("pause", statusUpdate);
|
||||||
|
// video.addListener("ended", statusUpdate);
|
||||||
|
video.ontimeupdate = statusUpdate;
|
||||||
|
video.onplay = statusUpdate;
|
||||||
|
video.onpause = statusUpdate;
|
||||||
|
video.onended = statusUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSongData()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
type: "edu.regis.universeplayer.browser.InternetSong",
|
||||||
|
location: "window.location.href",
|
||||||
|
title: getTitle(),
|
||||||
|
artists: getArtists(),
|
||||||
|
trackNum: 0,
|
||||||
|
discNum: 0,
|
||||||
|
duration: parseInt(getLength() * 1000),
|
||||||
|
album: null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getState()
|
function getState()
|
||||||
{
|
{
|
||||||
if (!video)
|
if (!video)
|
||||||
{
|
{
|
||||||
return 4;
|
return "EMPTY";
|
||||||
}
|
}
|
||||||
else if (video.ended)
|
else if (video.ended)
|
||||||
{
|
{
|
||||||
return 3;
|
return "FINISHED";
|
||||||
}
|
}
|
||||||
else if (video.paused)
|
else if (video.paused)
|
||||||
{
|
{
|
||||||
return 1;
|
return "PAUSED";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return 0;
|
return "PLAYING";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +61,16 @@ function getLength()
|
|||||||
return video.duration;
|
return video.duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTitle()
|
||||||
|
{
|
||||||
|
return document.getElementsByTagName("meta").title.content;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getArtists()
|
||||||
|
{
|
||||||
|
return [document.getElementById("channel-name").getElementsByTagName("a")[0].text];
|
||||||
|
}
|
||||||
|
|
||||||
function play()
|
function play()
|
||||||
{
|
{
|
||||||
if (video != null)
|
if (video != null)
|
||||||
|
|||||||
@@ -219,7 +219,15 @@ public class BrowserLink extends MessageRunner
|
|||||||
|
|
||||||
if (clazz != null)
|
if (clazz != null)
|
||||||
{
|
{
|
||||||
return gson.fromJson(message, clazz);
|
try
|
||||||
|
{
|
||||||
|
return gson.fromJson(message, clazz);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.error("Could not parse " + message, e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,6 +52,10 @@ public class Main
|
|||||||
* Pretty much just forwards any messages to the browser and
|
* Pretty much just forwards any messages to the browser and
|
||||||
* returns their value.
|
* returns their value.
|
||||||
*/
|
*/
|
||||||
|
browserLink.addUpdateListener((update, link) -> {
|
||||||
|
logger.debug("Sending update {}", update);
|
||||||
|
interfaceLink.sendUpdate(update);
|
||||||
|
});
|
||||||
interfaceLink.addListener((providedValue, previousReturn) -> {
|
interfaceLink.addListener((providedValue, previousReturn) -> {
|
||||||
logger.debug("Forwarding message to browser: {}", providedValue);
|
logger.debug("Forwarding message to browser: {}", providedValue);
|
||||||
Object returnValue = browserLink.sendObject(providedValue).get();
|
Object returnValue = browserLink.sendObject(providedValue).get();
|
||||||
|
|||||||
@@ -21,6 +21,6 @@
|
|||||||
<Logger name="edu.regis.universeplayer.browserCommands.MessageHandler" level="trace"/>
|
<Logger name="edu.regis.universeplayer.browserCommands.MessageHandler" level="trace"/>
|
||||||
<Logger name="edu.regis.universeplayer.browserCommands.memoryMapping.MemoryRunner" level="trace"/>
|
<Logger name="edu.regis.universeplayer.browserCommands.memoryMapping.MemoryRunner" level="trace"/>
|
||||||
<Logger name="edu.regis.universeplayer.browserCommands.memoryMapping.MemoryHandler" level="trace"/>
|
<Logger name="edu.regis.universeplayer.browserCommands.memoryMapping.MemoryHandler" level="trace"/>
|
||||||
<Logger name="edu.regis.universeplayer.addon.BrowserLink" level="trace"/>
|
<Logger name="BrowserLink" level="trace"/>
|
||||||
</Loggers>
|
</Loggers>
|
||||||
</Configuration>
|
</Configuration>
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 William Hubbard. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package edu.regis.universeplayer;
|
||||||
|
|
||||||
|
import edu.regis.universeplayer.PlaybackStatus;
|
||||||
|
import edu.regis.universeplayer.data.Song;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.EventObject;
|
||||||
|
|
||||||
|
public class PlaybackInfo implements Serializable
|
||||||
|
{
|
||||||
|
private final Song currentSong;
|
||||||
|
/**
|
||||||
|
* The time we are currently at in the song, in seconds.
|
||||||
|
*/
|
||||||
|
private final float playTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current status of the player.
|
||||||
|
*/
|
||||||
|
private final PlaybackStatus status;
|
||||||
|
|
||||||
|
public PlaybackInfo(Song song, float playTime, PlaybackStatus status)
|
||||||
|
{
|
||||||
|
this.currentSong = song;
|
||||||
|
this.playTime = playTime;
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the song currently playing.
|
||||||
|
*
|
||||||
|
* @return The current song, or null if none is loaded.
|
||||||
|
*/
|
||||||
|
public Song getSong()
|
||||||
|
{
|
||||||
|
return this.currentSong;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the current play time.
|
||||||
|
*
|
||||||
|
* @return The play time of the player. This will be zero if the song is
|
||||||
|
* stopped or not loaded.
|
||||||
|
*/
|
||||||
|
public float getPlayTime()
|
||||||
|
{
|
||||||
|
return this.playTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the current status of the player.
|
||||||
|
*
|
||||||
|
* @return - The player's playback status.
|
||||||
|
*/
|
||||||
|
public PlaybackStatus getStatus()
|
||||||
|
{
|
||||||
|
return this.status;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,10 +9,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
@@ -33,11 +30,12 @@ public class MessageHandler implements Runnable, MessageSerializer
|
|||||||
private final ExecutorService executor;
|
private final ExecutorService executor;
|
||||||
private final LinkedList<MessageListener> listeners = new LinkedList<>();
|
private final LinkedList<MessageListener> listeners = new LinkedList<>();
|
||||||
protected final HashMap<Integer, Future<Object>> messageResponses = new HashMap<>();
|
protected final HashMap<Integer, Future<Object>> messageResponses = new HashMap<>();
|
||||||
|
protected final Queue<Object> updates = new LinkedList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a message handler.
|
* Creates a message handler.
|
||||||
*
|
*
|
||||||
* @param name - The name of the handler. This is used in logging.
|
* @param name - The name of the handler. This is used in logging.
|
||||||
* @param input - The input from our external source.
|
* @param input - The input from our external source.
|
||||||
* @param output - The output to the external source.
|
* @param output - The output to the external source.
|
||||||
*/
|
*/
|
||||||
@@ -142,6 +140,29 @@ public class MessageHandler implements Runnable, MessageSerializer
|
|||||||
toRemove.clear();
|
toRemove.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send in any updates
|
||||||
|
*/
|
||||||
|
synchronized (this.updates)
|
||||||
|
{
|
||||||
|
if (this.updates.size() > 0)
|
||||||
|
{
|
||||||
|
Object update;
|
||||||
|
while ((update = this.updates.poll()) != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
messageByte = serializeObject(update);
|
||||||
|
writeMessage(browserOut, -1, messageByte);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
logger.error("Could not send response message for " + update, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Throwable e)
|
catch (Throwable e)
|
||||||
@@ -231,6 +252,19 @@ public class MessageHandler implements Runnable, MessageSerializer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends an object through the handler as an update not associated with any message.
|
||||||
|
*
|
||||||
|
* @param object - The object to send.
|
||||||
|
*/
|
||||||
|
public void sendUpdate(Object object)
|
||||||
|
{
|
||||||
|
synchronized (this.updates)
|
||||||
|
{
|
||||||
|
this.updates.add(object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks to see if a listener has been added to the list.
|
* Checks to see if a listener has been added to the list.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ public abstract class MessageRunner implements Runnable, MessageSerializer
|
|||||||
protected final HashMap<Integer, MessagePacket> sentQueue = new HashMap<>();
|
protected final HashMap<Integer, MessagePacket> sentQueue = new HashMap<>();
|
||||||
protected int messagesSent = 0;
|
protected int messagesSent = 0;
|
||||||
|
|
||||||
|
protected final LinkedList<UpdateListener> listeners = new LinkedList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a message runner.
|
* Creates a message runner.
|
||||||
*
|
*
|
||||||
@@ -77,6 +79,7 @@ public abstract class MessageRunner implements Runnable, MessageSerializer
|
|||||||
BufferedOutputStream browserOut = null;
|
BufferedOutputStream browserOut = null;
|
||||||
MessagePacket packet;
|
MessagePacket packet;
|
||||||
|
|
||||||
|
int messageNum = -1;
|
||||||
byte[][] returnMessage;
|
byte[][] returnMessage;
|
||||||
ByteBuffer numBuffer = ByteBuffer.allocate(4);
|
ByteBuffer numBuffer = ByteBuffer.allocate(4);
|
||||||
|
|
||||||
@@ -98,18 +101,19 @@ public abstract class MessageRunner implements Runnable, MessageSerializer
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
packet.returnValue.index = this.messagesSent;
|
messageNum = this.messagesSent;
|
||||||
writeMessage(browserOut, this.messagesSent, packet.message);
|
packet.returnValue.index = messageNum;
|
||||||
|
writeMessage(browserOut, messageNum, packet.message);
|
||||||
|
|
||||||
synchronized (this.sentQueue)
|
synchronized (this.sentQueue)
|
||||||
{
|
{
|
||||||
this.sentQueue.put(this.messagesSent, packet);
|
this.sentQueue.put(messageNum, packet);
|
||||||
this.messagesSent++;
|
this.messagesSent++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
logger.error("Could not send message " + this.messagesSent + " " + new String(packet.message, StandardCharsets.UTF_8), e);
|
logger.error("Could not send message " + messageNum + " " + new String(packet.message, StandardCharsets.UTF_8), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,35 +122,44 @@ public abstract class MessageRunner implements Runnable, MessageSerializer
|
|||||||
*/
|
*/
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!this.sentQueue.isEmpty())
|
if (browserIn.available() > 0)
|
||||||
{
|
{
|
||||||
if (browserIn.available() > 0)
|
logger.trace("Reading message");
|
||||||
|
/*
|
||||||
|
* Wait for a response from the browser.
|
||||||
|
*/
|
||||||
|
returnMessage = this.readMessage(browserIn);
|
||||||
|
if (returnMessage == null)
|
||||||
{
|
{
|
||||||
/*
|
logger.info("Connection closed.");
|
||||||
* Wait for a response from the browser.
|
break;
|
||||||
*/
|
}
|
||||||
returnMessage = this.readMessage(browserIn);
|
else
|
||||||
if (returnMessage == null)
|
{
|
||||||
|
numBuffer.clear();
|
||||||
|
numBuffer.put(returnMessage[0]);
|
||||||
|
numBuffer.clear();
|
||||||
|
messageNum = numBuffer.getInt();
|
||||||
|
if (messageNum == -1)
|
||||||
{
|
{
|
||||||
logger.info("Connection closed.");
|
/*
|
||||||
break;
|
* Not a response, just a generic update.
|
||||||
|
*/
|
||||||
|
Object ob = deserializeObject(returnMessage[1]);
|
||||||
|
this.triggerUpdateListeners(ob);
|
||||||
|
logger.debug("Received update {}", ob);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
numBuffer.clear();
|
packet = this.sentQueue.get(messageNum);
|
||||||
numBuffer.put(returnMessage[0]);
|
|
||||||
numBuffer.clear();
|
|
||||||
packet = this.sentQueue.get(numBuffer.getInt());
|
|
||||||
if (packet == null)
|
if (packet == null)
|
||||||
{
|
{
|
||||||
numBuffer.clear();
|
logger.warn("Received message {} for nonexistant packet", messageNum);
|
||||||
logger.warn("Received message {} for nonexistant packet", numBuffer.getInt());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
packet.returnMessage = returnMessage[1];
|
packet.returnMessage = returnMessage[1];
|
||||||
numBuffer.clear();
|
logger.debug("Reading message {} {}", messageNum, new String(packet.returnMessage, StandardCharsets.UTF_8));
|
||||||
logger.debug("Reading message {} {}", numBuffer.getInt(), new String(packet.returnMessage, StandardCharsets.UTF_8));
|
|
||||||
synchronized (this.readLock)
|
synchronized (this.readLock)
|
||||||
{
|
{
|
||||||
logger.trace("Received message {}, notifying futures.", packet.returnValue.index);
|
logger.trace("Received message {}, notifying futures.", packet.returnValue.index);
|
||||||
@@ -236,6 +249,48 @@ public abstract class MessageRunner implements Runnable, MessageSerializer
|
|||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a listener for when an update not associated with a message comes
|
||||||
|
* through the runner.
|
||||||
|
*
|
||||||
|
* @param listener - The listener to add.
|
||||||
|
*/
|
||||||
|
public void addUpdateListener(UpdateListener listener)
|
||||||
|
{
|
||||||
|
this.listeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an update listener is present.
|
||||||
|
*
|
||||||
|
* @param listener - The listener to check for.
|
||||||
|
* @return Whether the provided listener is present.
|
||||||
|
*/
|
||||||
|
public boolean hasUpdateListener(UpdateListener listener)
|
||||||
|
{
|
||||||
|
return this.listeners.contains(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a listener for when an update not associated with a message comes
|
||||||
|
* through the runner.
|
||||||
|
*
|
||||||
|
* @param listener - The listener to remove.
|
||||||
|
*/
|
||||||
|
public void removeUpdateListener(UpdateListener listener)
|
||||||
|
{
|
||||||
|
this.listeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers update listeners
|
||||||
|
* @param ob - The update that came through.
|
||||||
|
*/
|
||||||
|
protected void triggerUpdateListeners(Object ob)
|
||||||
|
{
|
||||||
|
this.listeners.forEach(l -> l.onUpdate(ob, this));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This represents a sent message in storage.
|
* This represents a sent message in storage.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 William Hubbard. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package edu.regis.universeplayer.browserCommands;
|
||||||
|
|
||||||
|
import java.util.EventListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An update listener is called when an update is sent through the message
|
||||||
|
* runner that is not associated with a message.
|
||||||
|
*
|
||||||
|
* @author William Hubbard
|
||||||
|
* @version 0.1
|
||||||
|
*/
|
||||||
|
public interface UpdateListener extends EventListener
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Called when an update is received from a message runner.
|
||||||
|
*
|
||||||
|
* @param object - The received object
|
||||||
|
* @param runner - The runner that received the object.
|
||||||
|
*/
|
||||||
|
void onUpdate(Object object, MessageRunner runner);
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ public class Album implements Comparable<Album>
|
|||||||
public int id;
|
public int id;
|
||||||
public String name;
|
public String name;
|
||||||
public String[] artists;
|
public String[] artists;
|
||||||
public ImageIcon art;
|
public transient ImageIcon art;
|
||||||
public int year;
|
public int year;
|
||||||
public String[] genres;
|
public String[] genres;
|
||||||
public int totalTracks;
|
public int totalTracks;
|
||||||
@@ -2,9 +2,7 @@
|
|||||||
* Copyright (c) 2021 William Hubbard. All Rights Reserved.
|
* Copyright (c) 2021 William Hubbard. All Rights Reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package edu.regis.universeplayer.browser;
|
package edu.regis.universeplayer.data;
|
||||||
|
|
||||||
import edu.regis.universeplayer.data.Song;
|
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ import java.io.Serializable;
|
|||||||
/**
|
/**
|
||||||
* Contains data for a song.
|
* Contains data for a song.
|
||||||
*/
|
*/
|
||||||
public abstract class Song implements Comparable<Song>, Serializable
|
public class Song implements Comparable<Song>, Serializable
|
||||||
{
|
{
|
||||||
public String title;
|
public String title;
|
||||||
public String[] artists;
|
public String[] artists;
|
||||||
@@ -4,17 +4,16 @@
|
|||||||
|
|
||||||
package edu.regis.universeplayer;
|
package edu.regis.universeplayer;
|
||||||
|
|
||||||
import edu.regis.universeplayer.data.Song;
|
import edu.regis.universeplayer.data.PlaybackEvent;
|
||||||
|
|
||||||
import java.util.EventListener;
|
import java.util.EventListener;
|
||||||
import java.util.EventObject;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A playback listener allows a class to listen for events regarding player
|
* A playback listener allows a class to listen for events regarding player
|
||||||
* updates.
|
* updates.
|
||||||
*
|
*
|
||||||
* @author William Hubbard
|
* @author William Hubbard
|
||||||
* @verison 0.1
|
* @version 0.1
|
||||||
*/
|
*/
|
||||||
public interface PlaybackListener extends EventListener
|
public interface PlaybackListener extends EventListener
|
||||||
{
|
{
|
||||||
@@ -23,64 +22,6 @@ public interface PlaybackListener extends EventListener
|
|||||||
*
|
*
|
||||||
* @param status - The playback status.
|
* @param status - The playback status.
|
||||||
*/
|
*/
|
||||||
void onPlaybackChanged(PlaybackInfo status);
|
void onPlaybackChanged(PlaybackEvent status);
|
||||||
|
|
||||||
class PlaybackInfo extends EventObject
|
|
||||||
{
|
|
||||||
private final Song currentSong;
|
|
||||||
/**
|
|
||||||
* The time we are currently at in the song, in seconds.
|
|
||||||
*/
|
|
||||||
private final float playTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current status of the player.
|
|
||||||
*/
|
|
||||||
private final PlaybackStatus status;
|
|
||||||
|
|
||||||
public PlaybackInfo(Player<? extends Song> player, Song song, float playTime, PlaybackStatus status)
|
|
||||||
{
|
|
||||||
super(player);
|
|
||||||
this.currentSong = song;
|
|
||||||
this.playTime = playTime;
|
|
||||||
this.status = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Player<? extends Song> getSource()
|
|
||||||
{
|
|
||||||
return (Player<? extends Song>) super.getSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtains the song currently playing.
|
|
||||||
*
|
|
||||||
* @return The current song, or null if none is loaded.
|
|
||||||
*/
|
|
||||||
public Song getSong()
|
|
||||||
{
|
|
||||||
return this.currentSong;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtains the current play time.
|
|
||||||
*
|
|
||||||
* @return The play time of the player. This will be zero if the song is
|
|
||||||
* stopped or not loaded.
|
|
||||||
*/
|
|
||||||
public float getPlayTime()
|
|
||||||
{
|
|
||||||
return this.playTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtains the current status of the player.
|
|
||||||
*
|
|
||||||
* @return - The player's playback status.
|
|
||||||
*/
|
|
||||||
public PlaybackStatus getStatus()
|
|
||||||
{
|
|
||||||
return this.status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,20 +4,20 @@
|
|||||||
|
|
||||||
package edu.regis.universeplayer.browser;
|
package edu.regis.universeplayer.browser;
|
||||||
|
|
||||||
|
import edu.regis.universeplayer.PlaybackInfo;
|
||||||
import edu.regis.universeplayer.PlaybackListener;
|
import edu.regis.universeplayer.PlaybackListener;
|
||||||
import edu.regis.universeplayer.PlaybackStatus;
|
import edu.regis.universeplayer.PlaybackStatus;
|
||||||
import edu.regis.universeplayer.Player;
|
import edu.regis.universeplayer.Player;
|
||||||
import edu.regis.universeplayer.browserCommands.*;
|
import edu.regis.universeplayer.browserCommands.*;
|
||||||
|
import edu.regis.universeplayer.data.InternetSong;
|
||||||
|
import edu.regis.universeplayer.data.PlaybackEvent;
|
||||||
import edu.regis.universeplayer.data.Song;
|
import edu.regis.universeplayer.data.Song;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.ConnectException;
|
import java.net.*;
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
@@ -227,7 +227,7 @@ public class Browser extends MessageRunner implements Player<InternetSong>
|
|||||||
@Override
|
@Override
|
||||||
public void addPlaybackListener(PlaybackListener listener)
|
public void addPlaybackListener(PlaybackListener listener)
|
||||||
{
|
{
|
||||||
|
this.listeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -239,7 +239,7 @@ public class Browser extends MessageRunner implements Player<InternetSong>
|
|||||||
@Override
|
@Override
|
||||||
public boolean hasPlaybackListener(PlaybackListener listener)
|
public boolean hasPlaybackListener(PlaybackListener listener)
|
||||||
{
|
{
|
||||||
return false;
|
return this.listeners.contains(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -250,9 +250,21 @@ public class Browser extends MessageRunner implements Player<InternetSong>
|
|||||||
@Override
|
@Override
|
||||||
public void removePlaybackListener(PlaybackListener listener)
|
public void removePlaybackListener(PlaybackListener listener)
|
||||||
{
|
{
|
||||||
|
this.listeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void triggerUpdateListeners(Object ob)
|
||||||
|
{
|
||||||
|
PlaybackEvent status;
|
||||||
|
super.triggerUpdateListeners(ob);
|
||||||
|
if (ob instanceof PlaybackInfo)
|
||||||
|
{
|
||||||
|
status = new PlaybackEvent(this, (PlaybackInfo) ob);
|
||||||
|
this.listeners.forEach(l -> l.onPlaybackChanged(status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QueryFuture<Void> play()
|
public QueryFuture<Void> play()
|
||||||
{
|
{
|
||||||
@@ -301,7 +313,15 @@ public class Browser extends MessageRunner implements Player<InternetSong>
|
|||||||
@Override
|
@Override
|
||||||
public QueryFuture<Void> stopSong()
|
public QueryFuture<Void> stopSong()
|
||||||
{
|
{
|
||||||
return null;
|
try
|
||||||
|
{
|
||||||
|
return new ForwardedFuture(this.sendObject(new CommandLoadSong((URL) null)));
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
logger.error("Could not send message", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -331,14 +351,14 @@ public class Browser extends MessageRunner implements Player<InternetSong>
|
|||||||
Future future = this.sendObject(new QueryStatus());
|
Future future = this.sendObject(new QueryStatus());
|
||||||
return new QueryFuture<>() {
|
return new QueryFuture<>() {
|
||||||
|
|
||||||
private CommandReturn<Double> getVal() throws ExecutionException, InterruptedException
|
private CommandReturn<String> getVal() throws ExecutionException, InterruptedException
|
||||||
{
|
{
|
||||||
return ((CommandReturn<Double>) future.get());
|
return ((CommandReturn<String>) future.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
private CommandReturn<Double> getVal(long timeout, TimeUnit unit) throws ExecutionException, InterruptedException, TimeoutException
|
private CommandReturn<String> getVal(long timeout, TimeUnit unit) throws ExecutionException, InterruptedException, TimeoutException
|
||||||
{
|
{
|
||||||
return ((CommandReturn<Double>) future.get(timeout, unit));
|
return ((CommandReturn<String>) future.get(timeout, unit));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -374,15 +394,15 @@ public class Browser extends MessageRunner implements Player<InternetSong>
|
|||||||
@Override
|
@Override
|
||||||
public PlaybackStatus get() throws InterruptedException, ExecutionException
|
public PlaybackStatus get() throws InterruptedException, ExecutionException
|
||||||
{
|
{
|
||||||
Double value = getVal().getReturnValue();
|
String value = getVal().getReturnValue();
|
||||||
return PlaybackStatus.values()[value.intValue()];
|
return PlaybackStatus.valueOf(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PlaybackStatus get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
|
public PlaybackStatus get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
|
||||||
{
|
{
|
||||||
Double value = getVal(timeout, unit).getReturnValue();
|
String value = getVal(timeout, unit).getReturnValue();
|
||||||
return PlaybackStatus.values()[value.intValue()];
|
return PlaybackStatus.valueOf(value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
package edu.regis.universeplayer.data;
|
package edu.regis.universeplayer.data;
|
||||||
|
|
||||||
import edu.regis.universeplayer.browser.InternetSong;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
|||||||
@@ -1,120 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2021 William Hubbard. All Rights Reserved.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package edu.regis.universeplayer.data;
|
|
||||||
|
|
||||||
import com.mpatric.mp3agic.ID3v1;
|
|
||||||
import com.mpatric.mp3agic.ID3v2;
|
|
||||||
import com.mpatric.mp3agic.InvalidDataException;
|
|
||||||
import com.mpatric.mp3agic.Mp3File;
|
|
||||||
import com.mpatric.mp3agic.UnsupportedTagException;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This will specifically import an MP3 file.
|
|
||||||
*
|
|
||||||
* @author William Hubbard
|
|
||||||
* @version 0.1
|
|
||||||
*/
|
|
||||||
public class MP3Song extends LocalSong
|
|
||||||
{
|
|
||||||
public MP3Song(File file)
|
|
||||||
{
|
|
||||||
Mp3File metadata;
|
|
||||||
ID3v1 tag1;
|
|
||||||
ID3v2 tag2;
|
|
||||||
this.file = file;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
metadata = new Mp3File(file);
|
|
||||||
this.album = new Album();
|
|
||||||
if (metadata.hasId3v1Tag())
|
|
||||||
{
|
|
||||||
tag1 = metadata.getId3v1Tag();
|
|
||||||
this.title = tag1.getTitle();
|
|
||||||
this.artists = tag1.getArtist().split(";");
|
|
||||||
/**
|
|
||||||
* Trim the artists as needed.
|
|
||||||
*/
|
|
||||||
for (int i = 0, l = this.artists.length; i < l; i++)
|
|
||||||
{
|
|
||||||
this.artists[i] = this.artists[i].trim();
|
|
||||||
}
|
|
||||||
this.trackNum = Integer.parseInt(tag1.getTrack().split("/")[0]);
|
|
||||||
|
|
||||||
this.album.name = tag1.getAlbum();
|
|
||||||
this.album.genres = tag1.getGenreDescription().split(";");
|
|
||||||
for (int i = 0, l = this.album.genres.length; i < l; i++)
|
|
||||||
{
|
|
||||||
this.album.genres[i] = this.album.genres[i].trim();
|
|
||||||
}
|
|
||||||
this.album.year = Integer.parseInt(tag1.getYear());
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Make sure that the v2 tag doesn't contain any contradictory information.
|
|
||||||
*/
|
|
||||||
if (metadata.hasId3v2Tag())
|
|
||||||
{
|
|
||||||
tag2 = metadata.getId3v2Tag();
|
|
||||||
if (!tag2.getTitle().isEmpty())
|
|
||||||
{
|
|
||||||
this.title = tag2.getTitle();
|
|
||||||
}
|
|
||||||
if (!tag2.getTitle().isEmpty())
|
|
||||||
{
|
|
||||||
this.artists = tag2.getArtist().split(";");
|
|
||||||
/**
|
|
||||||
* Trim the artists as needed.
|
|
||||||
*/
|
|
||||||
for (int i = 0, l = this.artists.length; i < l; i++)
|
|
||||||
{
|
|
||||||
this.artists[i] = this.artists[i].trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!tag2.getTitle().isEmpty())
|
|
||||||
{
|
|
||||||
this.trackNum = Integer.parseInt(tag2.getTrack().split("/")[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tag2.getAlbum().isEmpty())
|
|
||||||
{
|
|
||||||
this.album.name = tag2.getAlbum();
|
|
||||||
}
|
|
||||||
if (!tag2.getAlbumArtist().isEmpty())
|
|
||||||
{
|
|
||||||
this.album.artists = tag2.getAlbumArtist().split(";");
|
|
||||||
/**
|
|
||||||
* Trim the artists as needed.
|
|
||||||
*/
|
|
||||||
for (int i = 0, l = this.album.artists.length; i < l; i++)
|
|
||||||
{
|
|
||||||
this.album.artists[i] = this.album.artists[i].trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!tag2.getGenreDescription().isEmpty())
|
|
||||||
{
|
|
||||||
this.album.genres = tag2.getGenreDescription().split(";");
|
|
||||||
for (int i = 0, l = this.album.genres.length; i < l; i++)
|
|
||||||
{
|
|
||||||
this.album.genres[i] = this.album.genres[i].trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!tag2.getYear().isEmpty())
|
|
||||||
{
|
|
||||||
this.album.year = Integer.parseInt(tag2.getYear());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("Invalid MP3 File", e);
|
|
||||||
}
|
|
||||||
catch (UnsupportedTagException | InvalidDataException e)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 William Hubbard. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package edu.regis.universeplayer.data;
|
||||||
|
|
||||||
|
import edu.regis.universeplayer.PlaybackInfo;
|
||||||
|
import edu.regis.universeplayer.Player;
|
||||||
|
import edu.regis.universeplayer.localPlayer.LocalPlayer;
|
||||||
|
|
||||||
|
import java.util.EventObject;
|
||||||
|
|
||||||
|
public class PlaybackEvent extends EventObject
|
||||||
|
{
|
||||||
|
private final PlaybackInfo info;
|
||||||
|
|
||||||
|
public PlaybackEvent(Player<? extends Song> player, PlaybackInfo playbackInfo)
|
||||||
|
{
|
||||||
|
super(player);
|
||||||
|
this.info = playbackInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlaybackInfo getInfo()
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,12 +4,14 @@
|
|||||||
package edu.regis.universeplayer.localPlayer;
|
package edu.regis.universeplayer.localPlayer;
|
||||||
|
|
||||||
import com.intervigil.wave.WaveReader;
|
import com.intervigil.wave.WaveReader;
|
||||||
|
import edu.regis.universeplayer.PlaybackInfo;
|
||||||
import edu.regis.universeplayer.PlaybackListener;
|
import edu.regis.universeplayer.PlaybackListener;
|
||||||
import edu.regis.universeplayer.PlaybackStatus;
|
import edu.regis.universeplayer.PlaybackStatus;
|
||||||
import edu.regis.universeplayer.Player;
|
import edu.regis.universeplayer.Player;
|
||||||
import edu.regis.universeplayer.browserCommands.CommandConfirmation;
|
import edu.regis.universeplayer.browserCommands.CommandConfirmation;
|
||||||
import edu.regis.universeplayer.browserCommands.QueryFuture;
|
import edu.regis.universeplayer.browserCommands.QueryFuture;
|
||||||
import edu.regis.universeplayer.data.LocalSong;
|
import edu.regis.universeplayer.data.LocalSong;
|
||||||
|
import edu.regis.universeplayer.data.PlaybackEvent;
|
||||||
import edu.regis.universeplayer.data.Song;
|
import edu.regis.universeplayer.data.Song;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -310,7 +312,7 @@ public class LocalPlayer implements Player<LocalSong>, MediaPlayerEventListener
|
|||||||
public void playing(MediaPlayer mediaPlayer)
|
public void playing(MediaPlayer mediaPlayer)
|
||||||
{
|
{
|
||||||
logger.debug("Local player playing.");
|
logger.debug("Local player playing.");
|
||||||
SwingUtilities.invokeLater(() -> this.listeners.forEach(playbackListener -> playbackListener.onPlaybackChanged(new PlaybackListener.PlaybackInfo(this, this.currentSong, mediaPlayer.status().time(), PlaybackStatus.PLAYING))));
|
SwingUtilities.invokeLater(() -> this.listeners.forEach(playbackListener -> playbackListener.onPlaybackChanged(new PlaybackEvent(this, new PlaybackInfo(this.currentSong, mediaPlayer.status().time(), PlaybackStatus.PLAYING)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -322,7 +324,7 @@ public class LocalPlayer implements Player<LocalSong>, MediaPlayerEventListener
|
|||||||
public void paused(MediaPlayer mediaPlayer)
|
public void paused(MediaPlayer mediaPlayer)
|
||||||
{
|
{
|
||||||
logger.debug("Local player paused.");
|
logger.debug("Local player paused.");
|
||||||
SwingUtilities.invokeLater(() -> this.listeners.forEach(playbackListener -> playbackListener.onPlaybackChanged(new PlaybackListener.PlaybackInfo(this, this.currentSong, mediaPlayer.status().time(), PlaybackStatus.PAUSED))));
|
SwingUtilities.invokeLater(() -> this.listeners.forEach(playbackListener -> playbackListener.onPlaybackChanged(new PlaybackEvent(this, new PlaybackInfo(this.currentSong, mediaPlayer.status().time(), PlaybackStatus.PAUSED)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -338,7 +340,7 @@ public class LocalPlayer implements Player<LocalSong>, MediaPlayerEventListener
|
|||||||
public void stopped(MediaPlayer mediaPlayer)
|
public void stopped(MediaPlayer mediaPlayer)
|
||||||
{
|
{
|
||||||
logger.debug("Local player stopped prematurely.");
|
logger.debug("Local player stopped prematurely.");
|
||||||
SwingUtilities.invokeLater(() -> this.listeners.forEach(playbackListener -> playbackListener.onPlaybackChanged(new PlaybackListener.PlaybackInfo(this, this.currentSong, mediaPlayer.status().time(), PlaybackStatus.STOPPED))));
|
SwingUtilities.invokeLater(() -> this.listeners.forEach(playbackListener -> playbackListener.onPlaybackChanged(new PlaybackEvent(this, new PlaybackInfo(this.currentSong, mediaPlayer.status().time(), PlaybackStatus.STOPPED)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -372,7 +374,7 @@ public class LocalPlayer implements Player<LocalSong>, MediaPlayerEventListener
|
|||||||
public void finished(MediaPlayer mediaPlayer)
|
public void finished(MediaPlayer mediaPlayer)
|
||||||
{
|
{
|
||||||
logger.debug("Local player finished.");
|
logger.debug("Local player finished.");
|
||||||
SwingUtilities.invokeLater(() -> this.listeners.forEach(playbackListener -> playbackListener.onPlaybackChanged(new PlaybackListener.PlaybackInfo(this, this.currentSong, mediaPlayer.status().time(), PlaybackStatus.FINISHED))));
|
SwingUtilities.invokeLater(() -> this.listeners.forEach(playbackListener -> playbackListener.onPlaybackChanged(new PlaybackEvent(this, new PlaybackInfo(this.currentSong, mediaPlayer.status().time(), PlaybackStatus.FINISHED)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -384,7 +386,7 @@ public class LocalPlayer implements Player<LocalSong>, MediaPlayerEventListener
|
|||||||
@Override
|
@Override
|
||||||
public void timeChanged(MediaPlayer mediaPlayer, long newTime)
|
public void timeChanged(MediaPlayer mediaPlayer, long newTime)
|
||||||
{
|
{
|
||||||
SwingUtilities.invokeLater(() -> this.listeners.forEach(playbackListener -> playbackListener.onPlaybackChanged(new PlaybackListener.PlaybackInfo(this, this.currentSong, newTime / 1000F, PlaybackStatus.PLAYING))));
|
SwingUtilities.invokeLater(() -> this.listeners.forEach(playbackListener -> playbackListener.onPlaybackChanged(new PlaybackEvent(this, new PlaybackInfo(this.currentSong, newTime / 1000F, PlaybackStatus.PLAYING)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ package edu.regis.universeplayer.player;
|
|||||||
|
|
||||||
import edu.regis.universeplayer.Player;
|
import edu.regis.universeplayer.Player;
|
||||||
import edu.regis.universeplayer.browser.Browser;
|
import edu.regis.universeplayer.browser.Browser;
|
||||||
import edu.regis.universeplayer.browser.InternetSong;
|
import edu.regis.universeplayer.data.InternetSong;
|
||||||
import edu.regis.universeplayer.data.Queue;
|
import edu.regis.universeplayer.data.Queue;
|
||||||
import edu.regis.universeplayer.data.*;
|
import edu.regis.universeplayer.data.*;
|
||||||
import edu.regis.universeplayer.localPlayer.LocalPlayer;
|
import edu.regis.universeplayer.localPlayer.LocalPlayer;
|
||||||
@@ -22,9 +22,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.Future;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Interface class serves as the primary GUI that the player interacts with.
|
* The Interface class serves as the primary GUI that the player interacts with.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
package edu.regis.universeplayer.player;
|
package edu.regis.universeplayer.player;
|
||||||
|
|
||||||
import edu.regis.universeplayer.browser.InternetSong;
|
import edu.regis.universeplayer.data.InternetSong;
|
||||||
import edu.regis.universeplayer.data.InternetSongProvider;
|
import edu.regis.universeplayer.data.InternetSongProvider;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|||||||
@@ -4,9 +4,11 @@
|
|||||||
|
|
||||||
package edu.regis.universeplayer.player;
|
package edu.regis.universeplayer.player;
|
||||||
|
|
||||||
|
import edu.regis.universeplayer.PlaybackInfo;
|
||||||
import edu.regis.universeplayer.PlaybackListener;
|
import edu.regis.universeplayer.PlaybackListener;
|
||||||
import edu.regis.universeplayer.PlaybackStatus;
|
import edu.regis.universeplayer.PlaybackStatus;
|
||||||
import edu.regis.universeplayer.Player;
|
import edu.regis.universeplayer.Player;
|
||||||
|
import edu.regis.universeplayer.data.PlaybackEvent;
|
||||||
import edu.regis.universeplayer.data.Queue;
|
import edu.regis.universeplayer.data.Queue;
|
||||||
import edu.regis.universeplayer.data.Song;
|
import edu.regis.universeplayer.data.Song;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -323,17 +325,18 @@ public class PlayerControls extends JPanel implements Queue.SongChangeListener,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlaybackChanged(PlaybackInfo status)
|
public void onPlaybackChanged(PlaybackEvent status)
|
||||||
{
|
{
|
||||||
if (status.getSource() != null && status.getSource() == this.currentPlayer)
|
if (status.getSource() != null && status.getSource() == this.currentPlayer)
|
||||||
{
|
{
|
||||||
switch (status.getStatus())
|
switch (status.getInfo().getStatus())
|
||||||
{
|
{
|
||||||
case PLAYING -> this.playButton.setIcon(PAUSE_ICON);
|
case PLAYING -> this.playButton.setIcon(PAUSE_ICON);
|
||||||
case FINISHED -> Queue.getInstance().skipNext();
|
case FINISHED -> Queue.getInstance().skipNext();
|
||||||
case PAUSED, STOPPED, EMPTY -> this.playButton.setIcon(PLAY_ICON);
|
case PAUSED, STOPPED, EMPTY -> this.playButton.setIcon(PLAY_ICON);
|
||||||
}
|
}
|
||||||
this.progress.setValue((int) status.getPlayTime());
|
this.progress.setValue((int) status.getInfo().getPlayTime());
|
||||||
|
this.progress.setMaximum((int) (status.getInfo().getSong().duration / 1000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user