diff --git a/src/main/java/moe/nekojimi/chords/Chords.java b/src/main/java/moe/nekojimi/chords/Chords.java index 071376d..d5eedc6 100644 --- a/src/main/java/moe/nekojimi/chords/Chords.java +++ b/src/main/java/moe/nekojimi/chords/Chords.java @@ -30,7 +30,6 @@ import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.entities.channel.middleman.AudioChannel; import net.dv8tion.jda.api.events.guild.voice.GuildVoiceUpdateEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.managers.AudioManager; import net.dv8tion.jda.api.requests.GatewayIntent; @@ -65,8 +64,6 @@ public final class Chords extends ListenerAdapter private AudioChannel currentVoiceChannel = null; - private int trackNumber = 1; - private final Map playlists = new HashMap<>(); /** @@ -256,49 +253,29 @@ public final class Chords extends ListenerAdapter } } - public Song queueDownload(SongRequest request) + public void queueDownload(SongRequest request) { - Song song; - if (request.getUrl() != null) - { - song = new Song(request.getUrl()); - } else - { - // interpret search result - throw new UnsupportedOperationException("Not supported yet."); - } - if (request.getInvocation().getRequestMessage() != null) - { - song.setRequestedBy(request.getInvocation().getRequestMessage().getAuthor().getName()); - song.setRequestedIn(request.getInvocation().getRequestMessage().getChannel().getId()); - } - song.setNumber(trackNumber); - trackNumber++; - request.setSong(song); +// Song song; +// if (request.getUrl() != null) +// { +// song = new Song(request.getUrl()); +// } else +// { +// // interpret search result +// throw new UnsupportedOperationException("Not supported yet."); +// } +// if (request.getInvocation().getRequestMessage() != null) +// { +// +// } +// song.setNumber(trackNumber); +// trackNumber++; +// request.addSong(song); request.getInvocation().respond("Request pending..."); downloader.accept(new Downloader.DownloadTask(request, queueManager)); - return song; +// return song; } -// public Song queueDownload(final URL url, GuildMessageReceivedEvent event) -// { -// Song song = new Song(url); -// song.setRequestedBy(event.getAuthor().getName()); -// song.setRequestedIn(event.getChannel().getId()); -// song.setNumber(trackNumber); -// trackNumber++; -// downloader.accept(new Downloader.DownloadTask(song, musicHandler)); -// return song; -// } -// -// public Song queueDownload(Result res, GuildMessageReceivedEvent event) -// { -// Song song = queueDownload(res.getLink(), event); -// song.setArtist(res.getArtist()); -// song.setTitle(res.getTitle()); -// song.setNumber(trackNumber); -// return song; -// } public void setStatus(Song nowPlaying) { jda.getPresence().setActivity(Activity.listening(nowPlaying.toString())); @@ -414,11 +391,6 @@ public final class Chords extends ListenerAdapter return queueManager; } - public int getTrackNumber() - { - return trackNumber; - } - public static Settings getSettings() { return settings; @@ -437,39 +409,47 @@ public final class Chords extends ListenerAdapter @Override public void accept(SongRequest request, Exception ex) { - Song song = request.getSong(); + String response = ""; + if (request.getSongs().size() > 1) + response += "Downloading " + request.getSongs().size() + " tracks:\n"; + for (Song song : request.getSongs()) + { // TextChannel channel = jda.getTextChannelById(song.getRequestedIn()); // String bracketNo = "[" + song.getNumber() + "] "; - if (ex == null) - if (song.getLocation() != null && request.getProgress() >= 100) - { - request.getInvocation().respond("Finished downloading " + song + ", added to queue!"); - log("DOWN", "Downloaded " + song); - } else - { - Format format = song.getBestFormat(); - String formatDetails = ""; - if (format != null) + if (ex == null) + if (song.getLocation() != null && song.getProgress() >= 100) { - final int bitrate = format.getSampleRate() / 1000; - final long size = format.getSize(); - String sizeFmt = (size <= 0 ? "?.??" : String.format("%.2f", size / (1024.0 * 1024.0))) + "MiB"; - String bitFmt = (bitrate <= 0 ? "??" : bitrate) + "k"; - formatDetails = " (" + bitFmt + ", " + sizeFmt + ")"; - } - String progressDetails = ""; - if (request.getProgress() >= 0) + response += ("Finished downloading " + song + ", added to queue!"); + log("DOWN", "Downloaded " + song); + } else { - progressDetails = " [" + String.format("%.1f", request.getProgress()) + "%]"; + Format format = song.getBestFormat(); + String formatDetails = ""; + if (format != null) + { + final int bitrate = format.getSampleRate() / 1000; + final long size = format.getSize(); + String sizeFmt = (size <= 0 ? "?.??" : String.format("%.2f", size / (1024.0 * 1024.0))) + "MiB"; + String bitFmt = (bitrate <= 0 ? "??" : bitrate) + "k"; + formatDetails = " (" + bitFmt + ", " + sizeFmt + ")"; + } + + String progressDetails = ""; + if (song.getProgress() >= 0) + progressDetails = " [" + String.format("%.1f", song.getProgress()) + "%]"; + + response += ("Now downloading " + song + formatDetails + progressDetails + " ..."); + log("DOWN", "Downloading " + song + "..."); } - request.getInvocation().respond("Now downloading " + song + formatDetails + progressDetails + " ..."); - log("DOWN", "Downloading " + song + "..."); + else + { + response += ("Failed to download " + song + "! Reason: " + ex.getMessage()); + log("DOWN", "Failed to download " + song + "! Reason: " + ex.getMessage()); } - else - { - request.getInvocation().respond("Failed to download " + song + "! Reason: " + ex.getMessage()); - log("DOWN", "Failed to download " + song + "! Reason: " + ex.getMessage()); + response += "\n"; } + if (!response.isEmpty()) + request.getInvocation().respond(response); } } diff --git a/src/main/java/moe/nekojimi/chords/Downloader.java b/src/main/java/moe/nekojimi/chords/Downloader.java index a125987..65db535 100644 --- a/src/main/java/moe/nekojimi/chords/Downloader.java +++ b/src/main/java/moe/nekojimi/chords/Downloader.java @@ -8,15 +8,11 @@ package moe.nekojimi.chords; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.StringReader; import java.nio.charset.Charset; import java.nio.file.Files; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Scanner; -import java.util.concurrent.LinkedBlockingDeque; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; +import java.util.*; +import java.util.concurrent.*; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.logging.Level; @@ -39,7 +35,7 @@ public class Downloader implements Consumer { private static final int DOWNLOAD_TIMEOUT = 300; - private static final int INFO_TIMEOUT = 30; + private static final int INFO_TIMEOUT = 60; private static final int FORMAT_TIMEOUT = 5; private static final int BITRATE_TARGET = (int) AudioSendHandler.INPUT_FORMAT.getSampleRate(); @@ -47,15 +43,19 @@ public class Downloader implements Consumer public static final Pattern DESTINATION_PATTERN = Pattern.compile("Destination: (.*\\.wav)"); public static final Pattern PROGRESS_PATTERN = Pattern.compile("\\[download\\].*?([\\d\\.]+)%"); private static final Pattern ETA_PATTERN = Pattern.compile("\\[download\\].*?ETA\\s+(\\d{1,2}:\\d{2})"); + private static final Pattern DOWNLOAD_ITEM_PATTERN = Pattern.compile("\\[download\\] Downloading item (\\d+) of (\\d+)"); private final List downloadQueue = new LinkedList<>(); private final LinkedBlockingDeque workQueue = new LinkedBlockingDeque<>(); private final ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 30, TimeUnit.SECONDS, workQueue); + private final ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1); // private Consumer next; private BiConsumer messageHandler; private File downloadDir = null; + private int trackNumber = 1; + public Downloader() { @@ -64,21 +64,22 @@ public class Downloader implements Consumer @Override public void accept(DownloadTask task) { - // if already downloaded, just skip - Song song = task.request.getSong(); - if (song.isDownloaded()) + // if all songs of the request are already downloaded, just skip + if (!task.request.getSongs().isEmpty() && task.request.getSongs().stream().allMatch((t) -> t.isDownloaded())) { - task.getDestination().accept(song); + for (Song song : task.request.getSongs()) + task.getDestination().accept(song); return; } downloadQueue.add(task); - getInfo(song); + getInfo(task.request); + // TODO: get info should also use the thread pool executor.submit(() -> { try { - getFormats(song); +// getFormats(song); download(task); } catch (Exception ex) { @@ -87,11 +88,9 @@ public class Downloader implements Consumer }); } - private void chooseFormats(Song song) + private List sortFormats(Collection input) { - List formats = song.getFormats(); - if (formats.isEmpty()) - return; + List formats = new ArrayList<>(input); formats.sort((Format a, Format b) -> { // audio only preferred to video @@ -127,7 +126,7 @@ public class Downloader implements Consumer } return -comp; }); - song.setFormats(formats); + return formats; } private void getFormats(Song song) @@ -205,36 +204,52 @@ public class Downloader implements Consumer } } - private void getInfo(Song song) + private List getInfo(SongRequest request) { + List ret = new ArrayList<>(); try { - String cmd = Chords.getSettings().getYtdlCommand() + " --skip-download --print-json " + song.getUrl().toString(); + String cmd = Chords.getSettings().getYtdlCommand() + " --skip-download --print-json " + request.getUrl().toString(); Process exec = runCommand(cmd, INFO_TIMEOUT); InputStream input = exec.getInputStream(); - JsonReader reader = Json.createReader(input); - JsonObject object = reader.readObject(); - if (song.getTitle() == null) - song.setTitle(object.getString("title", null)); - if (song.getArtist() == null) - song.setArtist(object.getString("uploader", null)); - - JsonArray formatsJSON = object.getJsonArray("formats"); - if (formatsJSON != null) + + // read each line as JSON, turn each into a song object + Scanner sc = new Scanner(input); + while (sc.hasNextLine()) { - List formats = new ArrayList<>(); - for (JsonObject formatJson : formatsJSON.getValuesAs(JsonObject.class)) + Song song = new Song(request.getUrl()); + song.setNumber(trackNumber); + trackNumber++; + request.addSong(song); + + String line = sc.nextLine(); + JsonReader reader = Json.createReader(new StringReader(line)); + JsonObject object = reader.readObject(); + if (song.getTitle() == null) + song.setTitle(object.getString("title", null)); + if (song.getArtist() == null) + song.setArtist(object.getString("uploader", null)); + + JsonArray formatsJSON = object.getJsonArray("formats"); + if (formatsJSON != null) { - Format format = Format.fromJSON(formatJson); - if (format != null) - formats.add(format); + List formats = new ArrayList<>(); + for (JsonObject formatJson : formatsJSON.getValuesAs(JsonObject.class)) + { + Format format = Format.fromJSON(formatJson); + if (format != null) + formats.add(format); + } + song.setFormats(formats); } - song.setFormats(formats); + + ret.add(song); } } catch (Exception ex) { Logger.getLogger(Downloader.class.getName()).log(Level.SEVERE, null, ex); } + return ret; } private File getDownloadDir() throws IOException @@ -244,15 +259,35 @@ public class Downloader implements Consumer return downloadDir; } + private Song getSongFromRequest(SongRequest request, int idx) + { + // if there's less songs in the request than expected, fill the array + while (idx >= request.getSongs().size()) + { + Song song = new Song(request.getUrl()); + song.setNumber(trackNumber); + trackNumber++; + request.addSong(song); + } + return request.getSongs().get(idx); + } + private void download(DownloadTask task) { - Song song = task.request.getSong(); - chooseFormats(song); + Set uniqueFormats = new HashSet<>(); + for (Song song : task.request.getSongs()) + { + uniqueFormats.addAll(song.getFormats()); + } + + List sortedFormats = sortFormats(uniqueFormats); String formatCodes = ""; - final List formats = song.getFormats(); - for (int i = 0; i < 3 && i < song.getFormats().size(); i++) + final List formats = sortedFormats; + for (int i = 0; i < 5 && i < sortedFormats.size(); i++) formatCodes += formats.get(i).getCode() + "/"; + int downloadIdx = 0; + try { messageHandler.accept(task.request, null); @@ -263,7 +298,7 @@ public class Downloader implements Consumer + " --no-playlist" + " --extractor-args youtube:player_client=android" + " -o " + getDownloadDir().getAbsolutePath() + "/%(title)s.%(ext)s " - + song.getUrl().toString(); + + task.request.getUrl().toString(); Process exec = runCommand(cmd, DOWNLOAD_TIMEOUT); InputStream in = exec.getInputStream(); @@ -274,30 +309,47 @@ public class Downloader implements Consumer String line = sc.nextLine(); System.out.println(line); + Matcher itemMatcher = DOWNLOAD_ITEM_PATTERN.matcher(line); + if (itemMatcher.find()) + { + int idx = Integer.parseInt(itemMatcher.group(1)) - 1; + int total = Integer.parseInt(cmd); + + downloadIdx = idx; + } + Matcher progMatcher = PROGRESS_PATTERN.matcher(line); if (progMatcher.find()) { - task.request.setProgress(Double.parseDouble(progMatcher.group(1))); + getSongFromRequest(task.request, downloadIdx).setProgress(Double.parseDouble(progMatcher.group(1))); messageHandler.accept(task.request, null); } Matcher destMatcher = DESTINATION_PATTERN.matcher(line); if (destMatcher.find()) + { + Song song = getSongFromRequest(task.request, downloadIdx); + song.setLocation(new File(destMatcher.group(1))); + + // this is currently our criteria for completion; submit the song and move on + if (task.getDestination() != null) + task.getDestination().accept(song); + + downloadIdx++; + } } -// String output = new String(in.readAllBytes(), Charset.defaultCharset()); + // String output = new String(in.readAllBytes(), Charset.defaultCharset()); String error = new String(exec.getErrorStream().readAllBytes(), Charset.defaultCharset()); -// System.out.println(output); + // System.out.println(output); if (exec.exitValue() != 0) throw new RuntimeException("youtube-dl failed with error " + exec.exitValue() + ", output:\n" + error); - task.request.setProgress(100); -// return true; +// task.request.setProgress(100); + // return true; - if (task.getDestination() != null) - task.getDestination().accept(song); downloadQueue.remove(task); messageHandler.accept(task.request, null); } catch (Exception ex) @@ -314,12 +366,20 @@ public class Downloader implements Consumer System.out.println("Running command: " + cmd); // Process exec = Runtime.getRuntime().exec().split(" ")); Process exec = new ProcessBuilder(cmd.split(" ")).redirectOutput(ProcessBuilder.Redirect.PIPE).redirectError(ProcessBuilder.Redirect.PIPE).start(); - boolean done = exec.waitFor(timeoutSecs, TimeUnit.SECONDS); - if (!done) + scheduler.schedule(() -> { - exec.destroyForcibly(); - throw new RuntimeException("Took too long, giving up."); - } + if (exec.isAlive()) + { + exec.destroyForcibly(); + System.err.println("Process " + cmd + " took too long, killing process."); + } + }, timeoutSecs, TimeUnit.SECONDS); +// boolean done = exec.waitFor(timeoutSecs, TimeUnit.SECONDS); +// if (!done) +// { +// exec.destroyForcibly(); +// throw new RuntimeException("Took too long, giving up."); +// } return exec; } diff --git a/src/main/java/moe/nekojimi/chords/MusicHandler.java b/src/main/java/moe/nekojimi/chords/MusicHandler.java index 974dcec..7e28d09 100644 --- a/src/main/java/moe/nekojimi/chords/MusicHandler.java +++ b/src/main/java/moe/nekojimi/chords/MusicHandler.java @@ -7,12 +7,13 @@ package moe.nekojimi.chords; import java.io.*; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; import javax.sound.sampled.*; import net.dv8tion.jda.api.audio.AudioSendHandler; -import org.apache.commons.io.input.buffer.CircularByteBuffer; /** * @@ -37,7 +38,8 @@ public class MusicHandler implements AudioSendHandler, Closeable } private Song currentSong; - private TrackPlayer player; +// private TrackPlayer player; + private final List playingTracks = new ArrayList<>(); private File debugOutFile; private BufferedOutputStream debugOut; @@ -67,12 +69,11 @@ public class MusicHandler implements AudioSendHandler, Closeable nextSong(true); } -// public boolean restartSong() -// { -//// songQueue.addFirst(currentSong); -// currentSong = null; -// return nextSong(true); -// } + public void playOver(Song song) + { + + } + private boolean nextSong() { @@ -84,8 +85,7 @@ public class MusicHandler implements AudioSendHandler, Closeable if (immediate) { System.out.println("Immediate next - clearing buffer"); - player = null; -// audioBuffer.clear(); + playingTracks.clear(); } try @@ -108,7 +108,8 @@ public class MusicHandler implements AudioSendHandler, Closeable System.out.println("Playing song " + currentSong.getLocation().getAbsolutePath()); arrayErr = false; byteCount = 3840; - player = new TrackPlayer(currentSong); + TrackPlayer player = new TrackPlayer(currentSong); + playingTracks.add(player); // System.out.println("Queue filled to " + audioBuffer.getCurrentNumberOfBytes()); return true; } catch (UnsupportedAudioFileException | IOException ex) @@ -122,7 +123,7 @@ public class MusicHandler implements AudioSendHandler, Closeable public boolean isPlaying() { - return player != null; + return !playingTracks.isEmpty(); } public boolean isShouldPlay() @@ -140,7 +141,12 @@ public class MusicHandler implements AudioSendHandler, Closeable @Override public boolean canProvide() { - return player != null && player.has(1); + if (playingTracks.isEmpty()) + return false; + for (TrackPlayer player : playingTracks) + if (player.has(1)) + return true; + return false; // If we have something in our buffer we can provide it to the send system // return audioBuffer.getCurrentNumberOfBytes() > byteCount && shouldPlay; } @@ -149,27 +155,35 @@ public class MusicHandler implements AudioSendHandler, Closeable public ByteBuffer provide20MsAudio() { ByteBuffer ret = ByteBuffer.allocate(byteCount); - while (ret.position() < byteCount && player != null) + while (ret.position() < byteCount && !playingTracks.isEmpty()) { -// System.out.println("Position: " + ret.position() + " Remaining: " + ret.remaining()); - try + boolean outOfInput = true; + List mixes = new ArrayList<>(); + List emptyPlayers = new ArrayList<>(); + for (TrackPlayer player : playingTracks) { - ByteBuffer read = player.read(ret.remaining()); - // System.out.println("SAMPLES from player: " + Util.printSamples(read)); -// System.out.println("Wanted: " + byteCount + " Space:" + space + " Available: " + din.available() + " To read: " + bytesToRead + " Read: " + read); - -// System.out.println("Read: " + read.remaining()); - ret.put(read); - } catch (TrackPlayer.OutOfInputException | IOException ex) + try + { + ByteBuffer read = player.read(ret.remaining()); + if (ret.limit() + read.position() >= byteCount) + outOfInput = false; + mixes.add(read); + // ret.put(read); + } catch (TrackPlayer.OutOfInputException | IOException ex) + { +// System.out.println("Track player " + player + " stopped giving input: " + ex.getMessage()); + emptyPlayers.add(player); + // System.out.println("Track ended, starting next."); + // outOfInput = true; + } + } + playingTracks.removeAll(emptyPlayers); + ret.put(mixBuffers(mixes)); + if (outOfInput) { -// System.out.println("Track ended, starting next."); boolean foundNext = nextSong(); - if (!foundNext) - { -// System.out.println("Out of tracks!"); break; - } } } @@ -180,56 +194,6 @@ public class MusicHandler implements AudioSendHandler, Closeable } -// private void fillBuffer(boolean canSkip) -// { -// // use what we have in our buffer to send audio as PCM -// while (audioBuffer.getCurrentNumberOfBytes() < DESIRED_BUFFER_SIZE) -// if (!readData()) -// if (!canSkip || !nextSong()) -// break; -// } -// -// private boolean readData() -// { -// if (din == null) -// return false; -// try -// { -// // if (din.available() == 0) -// // return false; -// int bytesToRead = DESIRED_BUFFER_SIZE - audioBuffer.getCurrentNumberOfBytes(); -// int space = audioBuffer.getSpace(); -// if (din.available() > 0 && din.available() < bytesToRead) -// bytesToRead = din.available(); -// if (bytesToRead > space) -// bytesToRead = space; -// if (bytesToRead == 0) -// return false; -// byte[] bytes = new byte[bytesToRead]; -// // byte[] bytes = din.readNBytes(bytesToRead); -// int read = din.read(bytes); -//// System.out.println("Wanted: " + byteCount + " Space:" + space + " Available: " + din.available() + " To read: " + bytesToRead + " Read: " + read); -// if (read < 0) -// return false; -//// queue.add(bytes); -// -// audioBuffer.add(bytes, 0, read); -// } catch (IOException ex) -// { -// Logger.getLogger(Chords.class.getName()).log(Level.SEVERE, null, ex); -// return false; -// } catch (ArrayIndexOutOfBoundsException ex) -// { -// if (!arrayErr) -// arrayErr = true; -// else -// { -// Logger.getLogger(Chords.class.getName()).log(Level.SEVERE, null, ex); -// return false; -// } -// } -// return true; -// } public Song getCurrentSong() { return currentSong; @@ -246,4 +210,38 @@ public class MusicHandler implements AudioSendHandler, Closeable { } + private ByteBuffer mixBuffers(List mixes) + { +// System.out.println("Mixing " + mixes.size() + " buffers"); + if (mixes.size() == 1) + return mixes.get(0); + + int maxSize = 0; + for (ByteBuffer buf : mixes) + { + if (buf.limit() > maxSize) + maxSize = buf.position(); + } + ByteBuffer ret = ByteBuffer.allocate(maxSize); + + for (int i = 0; i < ret.limit(); i++) + { + int byteTotal = 0; + int mixCount = 0; + for (ByteBuffer buf : mixes) + { + if (i < buf.limit()) + { + byteTotal += buf.get(i); + mixCount++; + } + } + double avg = ((double) byteTotal) / mixCount; + byte byteVal = (byte) Math.round(avg); + ret.put(byteVal); + } + ret.rewind(); + return ret; + } + } diff --git a/src/main/java/moe/nekojimi/chords/Song.java b/src/main/java/moe/nekojimi/chords/Song.java index 3b2a0e6..1733e58 100644 --- a/src/main/java/moe/nekojimi/chords/Song.java +++ b/src/main/java/moe/nekojimi/chords/Song.java @@ -19,7 +19,7 @@ import java.util.List; * * @author jimj316 */ -public class Song +public class Song implements Comparable { private String title; private String artist; @@ -28,10 +28,11 @@ public class Song private int number; private List formats = new ArrayList<>(); - private String requestedBy; - private String requestedIn; private boolean kept = false; + private double progress = -1; + private double eta = -1; + public Song(URL url) { this.url = url; @@ -50,8 +51,8 @@ public class Song .add("location", location.getAbsolutePath()) .add("num", Integer.toString(number)) .add("formats", build.build()) - .add("requestedBy", requestedBy) - .add("requestedIn", requestedIn) + // .add("requestedBy", requestedBy) + // .add("requestedIn", requestedIn) .add("kept", Boolean.toString(kept)) .build(); } @@ -64,8 +65,8 @@ public class Song song.setLocation(new File(map.string("location"))); song.setNumber(map.integer("num")); song.setKept(Boolean.parseBoolean(map.string("kept"))); - song.setRequestedBy(map.string("requestedBy")); - song.setRequestedIn(map.string("requestedIn")); +// song.setRequestedBy(map.string("requestedBy")); +// song.setRequestedIn(map.string("requestedIn")); List formats = new ArrayList<>(); YamlSequence formatSeq = map.yamlSequence("formats"); @@ -133,26 +134,6 @@ public class Song location = null; } - public String getRequestedBy() - { - return requestedBy; - } - - public void setRequestedBy(String requestedBy) - { - this.requestedBy = requestedBy; - } - - public String getRequestedIn() - { - return requestedIn; - } - - public void setRequestedIn(String requestedIn) - { - this.requestedIn = requestedIn; - } - public boolean isKept() { return kept; @@ -197,4 +178,30 @@ public class Song return formats.get(0); } + public double getProgress() + { + return progress; + } + + public void setProgress(double progress) + { + this.progress = progress; + } + + public double getEta() + { + return eta; + } + + public void setEta(double eta) + { + this.eta = eta; + } + + @Override + public int compareTo(Song o) + { + return Integer.compare(number, o.number); + } + } diff --git a/src/main/java/moe/nekojimi/chords/SongRequest.java b/src/main/java/moe/nekojimi/chords/SongRequest.java index ca119df..7979a1e 100644 --- a/src/main/java/moe/nekojimi/chords/SongRequest.java +++ b/src/main/java/moe/nekojimi/chords/SongRequest.java @@ -17,6 +17,7 @@ package moe.nekojimi.chords; import java.net.URL; +import java.util.ArrayList; import java.util.List; import moe.nekojimi.chords.commands.Invocation; import moe.nekojimi.musicsearcher.Result; @@ -36,10 +37,10 @@ public class SongRequest private Result result; - private Song song; + private final List songs = new ArrayList<>(); - private double progress = -1; - private double eta = -1; + private String requestedBy; + private String requestedIn; public List getSearchResults() @@ -70,6 +71,8 @@ public class SongRequest public void setInvocation(Invocation invocation) { this.invocation = invocation; + requestedBy = invocation.getRequestMessage().getAuthor().getName(); + requestedIn = invocation.getRequestMessage().getChannel().getId(); } // public Message getRequestMessage() @@ -112,34 +115,29 @@ public class SongRequest this.url = url; } - public Song getSong() + public List getSongs() { - return song; + return songs; } - public void setSong(Song song) + public void addSong(Song song) { - this.song = song; + songs.add(song); } - public double getProgress() + public void clearSongs() { - return progress; + songs.clear(); } - public void setProgress(double progress) + public String getRequestedBy() { - this.progress = progress; + return requestedBy; } - public double getEta() + public String getRequestedIn() { - return eta; - } - - public void setEta(double eta) - { - this.eta = eta; + return requestedIn; } }