Screw it, more changes

master
Nekojimi 9 months ago
parent 95f838c392
commit 571139a59c
  1. 105
      src/main/java/moe/nekojimi/chords/Chords.java
  2. 22
      src/main/java/moe/nekojimi/chords/Downloader.java
  3. 17
      src/main/java/moe/nekojimi/chords/QueueThing.java
  4. 14
      src/main/java/moe/nekojimi/chords/TrackRequest.java
  5. 15
      src/main/java/moe/nekojimi/chords/Util.java
  6. 15
      src/main/java/moe/nekojimi/chords/commands/Command.java
  7. 34
      src/main/java/moe/nekojimi/chords/commands/JoinCommand.java
  8. 1
      src/main/java/moe/nekojimi/chords/commands/QueueCommand.java

@ -56,6 +56,7 @@ public final class Chords extends ListenerAdapter
private final Downloader downloader; private final Downloader downloader;
private final Searcher searcher; private final Searcher searcher;
private final QueueManager queueManager; private final QueueManager queueManager;
private Recommender recommender;
private JDA jda; private JDA jda;
private final Map<String, Command> commands = new HashMap<>(); private final Map<String, Command> commands = new HashMap<>();
@ -149,6 +150,7 @@ public final class Chords extends ListenerAdapter
// init queue manager // init queue manager
queueManager = new QueueManager(); queueManager = new QueueManager();
queueManager.addSource(downloader);
// init commands // init commands
addCommand(new JoinCommand(this)); addCommand(new JoinCommand(this));
@ -211,18 +213,29 @@ public final class Chords extends ListenerAdapter
log("MESG", "G:" + guild.getName() + " A:" + author.getName() + " C:" + content); log("MESG", "G:" + guild.getName() + " A:" + author.getName() + " C:" + content);
try Invocation invocation = null;
{
URL parseURL = new URL(content.trim());
playCommand.call(null);
} catch (MalformedURLException ex)
{
// not a URL, then
}
try try
{ {
try
{
URL parseURL = new URL(content.trim());
invocation = new Invocation(event, List.of(parseURL.toExternalForm()));
playCommand.call(invocation);
return;
} catch (MalformedURLException ex)
{
// not a URL, then
}
String[] split = content.split("\\s+"); String[] split = content.split("\\s+");
List<String> args = new ArrayList<>();
Collections.addAll(args, split);
args.remove(0);
invocation = new Invocation(event, args);
invocation.setRequestMessage(message);
String cmd = split[0].toLowerCase(); String cmd = split[0].toLowerCase();
if (!cmd.startsWith("!")) if (!cmd.startsWith("!"))
@ -231,12 +244,6 @@ public final class Chords extends ListenerAdapter
cmd = cmd.substring(1); // strip prefix char cmd = cmd.substring(1); // strip prefix char
// String arg = ""; // String arg = "";
List<String> args = new ArrayList<>();
Collections.addAll(args, split);
args.remove(0);
Invocation invocation = new Invocation(event, args);
invocation.setRequestMessage(message);
if (commands.containsKey(cmd)) if (commands.containsKey(cmd))
{ {
@ -248,32 +255,18 @@ public final class Chords extends ListenerAdapter
} }
} catch (Exception ex) } catch (Exception ex)
{ {
event.getChannel().sendMessage("Error in command! " + ex.getMessage()).queue(); if (invocation != null)
invocation.respond("Error: " + ex.getMessage());
else
event.getChannel().sendMessage("Error: " + ex.getMessage()).queue();
log("UERR", "Command error:" + ex.getMessage()); log("UERR", "Command error:" + ex.getMessage());
} }
} }
public void queueDownload(TrackRequest request) public void queueDownload(TrackRequest request)
{ {
// Track track;
// if (request.getUrl() != null)
// {
// track = new Track(request.getUrl());
// } else
// {
// // interpret search result
// throw new UnsupportedOperationException("Not supported yet.");
// }
// if (request.getInvocation().getRequestMessage() != null)
// {
//
// }
// track.setNumber(trackNumber);
// trackNumber++;
// request.addTrack(track);
request.getInvocation().respond("Request pending..."); request.getInvocation().respond("Request pending...");
downloader.accept(new Downloader.DownloadTask(request, queueManager)); downloader.accept(request);
// return track;
} }
public void setStatus(Track nowPlaying) public void setStatus(Track nowPlaying)
@ -361,6 +354,19 @@ public final class Chords extends ListenerAdapter
} }
} }
public void setRecommenderEnabled(boolean enabled)
{
if (recommender == null && enabled)
{
recommender = new Recommender();
downloader.addSource(recommender);
} else if (recommender != null && !enabled)
{
downloader.removeSource(recommender);
recommender = null;
}
}
public MusicHandler getMusicHandler() public MusicHandler getMusicHandler()
{ {
return musicHandler; return musicHandler;
@ -396,6 +402,36 @@ public final class Chords extends ListenerAdapter
return settings; return settings;
} }
public static CommandOptions getOptions()
{
return options;
}
public File getDataDirectory()
{
return dataDirectory;
}
public File getPlaylistsDirectory()
{
return playlistsDirectory;
}
public Map<String, Command> getCommands()
{
return commands;
}
public Map<String, Playlist> getPlaylists()
{
return playlists;
}
public Recommender getRecommender()
{
return recommender;
}
private class DownloaderMessageHandler implements BiConsumer<TrackRequest, Exception> private class DownloaderMessageHandler implements BiConsumer<TrackRequest, Exception>
{ {
@ -477,6 +513,9 @@ public final class Chords extends ListenerAdapter
jda.getPresence().setActivity(Activity.of(Activity.ActivityType.LISTENING, track.toString())); jda.getPresence().setActivity(Activity.of(Activity.ActivityType.LISTENING, track.toString()));
else else
jda.getPresence().setActivity(null); jda.getPresence().setActivity(null);
if (recommender != null)
recommender.addSeed(track);
} }
} }

@ -23,6 +23,7 @@ import javax.json.Json;
import javax.json.JsonArray; import javax.json.JsonArray;
import javax.json.JsonObject; import javax.json.JsonObject;
import javax.json.JsonReader; import javax.json.JsonReader;
import moe.nekojimi.musicsearcher.Result;
import net.dv8tion.jda.api.audio.AudioSendHandler; import net.dv8tion.jda.api.audio.AudioSendHandler;
/** /**
@ -87,6 +88,8 @@ public class Downloader extends QueueThing<TrackRequest, Track>
protected boolean completePromise(Promise<TrackRequest, Track> promise) protected boolean completePromise(Promise<TrackRequest, Track> promise)
{ {
TrackRequest request = promise.getInput(); TrackRequest request = promise.getInput();
if (request == null)
return false;
executor.submit(() -> executor.submit(() ->
{ {
@ -244,9 +247,13 @@ public class Downloader extends QueueThing<TrackRequest, Track>
JsonReader reader = Json.createReader(new StringReader(line)); JsonReader reader = Json.createReader(new StringReader(line));
JsonObject object = reader.readObject(); JsonObject object = reader.readObject();
Result result = request.getResult();
// look for metadata // look for metadata
if (track.getTitle() == null) if (track.getTitle() == null)
{ {
if (result != null && !result.getTitle().isBlank())
track.setTitle(result.getTitle());
for (String key : INFO_TITLE_KEYS) for (String key : INFO_TITLE_KEYS)
{ {
if (object.containsKey(key) && !object.getString(key).isBlank()) if (object.containsKey(key) && !object.getString(key).isBlank())
@ -258,6 +265,8 @@ public class Downloader extends QueueThing<TrackRequest, Track>
} }
if (track.getArtist() == null) if (track.getArtist() == null)
{ {
if (result != null && !result.getArtist().isBlank())
track.setArtist(result.getArtist());
for (String key : INFO_ARTIST_KEYS) for (String key : INFO_ARTIST_KEYS)
{ {
if (object.containsKey(key) && !object.getString(key).isBlank()) if (object.containsKey(key) && !object.getString(key).isBlank())
@ -393,10 +402,17 @@ public class Downloader extends QueueThing<TrackRequest, Track>
} }
} }
String error = new String(exec.getErrorStream().readAllBytes(), Charset.defaultCharset()); boolean exited = exec.waitFor(DOWNLOAD_TIMEOUT, TimeUnit.SECONDS);
if (exited)
{
String error = new String(exec.getErrorStream().readAllBytes(), Charset.defaultCharset());
if (exec.exitValue() != 0) if (exec.exitValue() != 0)
throw new RuntimeException("youtube-dl failed with error " + exec.exitValue() + ", output:\n" + error); throw new RuntimeException("youtube-dl failed with error " + exec.exitValue() + ", output:\n" + error);
} else
{
throw new RuntimeException("youtube-dl failed to exit.");
}
messageHandler.accept(request, null); messageHandler.accept(request, null);
} catch (Exception ex) } catch (Exception ex)

@ -44,7 +44,7 @@ public abstract class QueueThing<I, O> implements Consumer<I>
@Override @Override
public void accept(I t) public void accept(I t)
{ {
// FIXME: this causes queue-jumping
// if we've got pending promises, fullfill them, otherwise just put it in the queue and notify the sinks // if we've got pending promises, fullfill them, otherwise just put it in the queue and notify the sinks
if (pendingPromises.isEmpty()) if (pendingPromises.isEmpty())
{ {
@ -53,6 +53,7 @@ public abstract class QueueThing<I, O> implements Consumer<I>
} else } else
{ {
Promise<I, O> promise = pendingPromises.poll(); Promise<I, O> promise = pendingPromises.poll();
System.out.println(this.getClass().getSimpleName() + " now has " + pendingPromises + " promises.");
promise.setInput(t); promise.setInput(t);
handlePromise(promise); handlePromise(promise);
} }
@ -76,7 +77,7 @@ public abstract class QueueThing<I, O> implements Consumer<I>
public List<Promise<I, O>> request(int count, Consumer<O> destination) public List<Promise<I, O>> request(int count, Consumer<O> destination)
{ {
List<Promise<I, O>> ret = new ArrayList<>(); List<Promise<I, O>> ret = new ArrayList<>();
int demands = 0; int demandsForClient = 0;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
I input = null; I input = null;
@ -96,21 +97,23 @@ public abstract class QueueThing<I, O> implements Consumer<I>
} else } else
{ {
// we need to get more input from sources // we need to get more input from sources
demands++; demandsForClient++;
} }
} }
demands += queueTargetSize - inputQueue.size(); int demandsForMe = queueTargetSize - inputQueue.size();
int demandsTotal = demandsForMe + demandsForClient;
if (demands > 0) if (demandsTotal > 0)
{ {
// try to get more input from sources // try to get more input from sources
int sourcePromises = demandInput(demands); int sourcePromises = demandInput(demandsForClient);
// each promise of input we get represents a promise of output we can give // each promise of input we get represents a promise of output we can give
for (int i = 0; i < sourcePromises; i++) for (int i = 0; i < sourcePromises && i < demandsForClient; i++)
{ {
Promise<I, O> myPromise = new Promise<>(destination); Promise<I, O> myPromise = new Promise<>(destination);
pendingPromises.add(myPromise); pendingPromises.add(myPromise);
System.out.println(this.getClass().getSimpleName() + " has made " + pendingPromises + " promises.");
ret.add(myPromise); ret.add(myPromise);
} }
} }

@ -35,8 +35,6 @@ public class TrackRequest implements Comparable<TrackRequest>
private String query; private String query;
private URL url; private URL url;
private List<Result> searchResults;
private Result result; private Result result;
private final List<Track> tracks = new ArrayList<>(); private final List<Track> tracks = new ArrayList<>();
@ -58,16 +56,6 @@ public class TrackRequest implements Comparable<TrackRequest>
return ret; return ret;
} }
public List<Result> getSearchResults()
{
return searchResults;
}
public void setSearchResults(List<Result> searchResults)
{
this.searchResults = searchResults;
}
public Result getResult() public Result getResult()
{ {
return result; return result;
@ -162,7 +150,7 @@ public class TrackRequest implements Comparable<TrackRequest>
trackName = "Request"; trackName = "Request";
else else
{ {
trackName = tracks.get(1).toString(); trackName = tracks.get(0).toString();
if (tracks.size() > 1) if (tracks.size() > 1)
trackName += " & " + (tracks.size() - 1) + " more tracks"; trackName += " & " + (tracks.size() - 1) + " more tracks";
} }

@ -77,4 +77,19 @@ public class Util
} }
return -1L; return -1L;
} }
public static String formatProgressBar(double progressPercent, String[] symbols, int barLength)
{
String ret = "";
double filledSegments = (progressPercent / 100.0) * barLength;
for (int i = 0; i < barLength; i++)
{
double thisSegment = Math.min(1, Math.max(0, filledSegments - i));
int symbolIdx = (int) Math.floor(thisSegment * symbols.length);
String symbol = symbols[symbolIdx];
ret += symbol;
}
return ret;
}
} }

@ -30,8 +30,19 @@ public abstract class Command
return keyword; return keyword;
} }
// public abstract String synopsis(); public String argumentDescription()
{
return ""; // most commands take no arguments
}
public String synopsis()
{
throw new UnsupportedOperationException("Not supported yet.");
}
// //
// public abstract String help(); public String help()
{
throw new UnsupportedOperationException("Not supported yet.");
}
} }

@ -67,40 +67,20 @@ public class JoinCommand extends Command
if (channel == null) // I have no idea what you want mr user if (channel == null) // I have no idea what you want mr user
{ {
onUnknownChannel(textChannel, arg0); // Let the user know about our failure // onUnknownChannel(textChannel, arg0); // Let the user know about our failure
return; throw new RuntimeException("Unable to connect to \"" + channel.getName() + "\", no such channel!");
} }
} }
bot.connectTo(channel); // We found a channel to connect to! bot.connectTo(channel); // We found a channel to connect to!
onConnecting(channel, textChannel); // Let the user know, we were successful! invocation.respond("Connecting to " + channel.getName() + "...");
// onConnecting(channel, textChannel); // Let the user know, we were successful!
} }
/** @Override
* Inform user about successful connection. public String argumentDescription()
*
* @param channel
* The voice channel we connected to
* @param textChannel
* The text channel to send the message in
*/
public void onConnecting(VoiceChannel channel, MessageChannel textChannel)
{
textChannel.sendMessage("Connecting to " + channel.getName()).queue(); // never forget to queue()!
}
/**
* The channel to connect to is not known to us.
*
* @param channel
* The message channel (text channel abstraction) to send failure
* information to
* @param comment
* The information of this channel
*/
public void onUnknownChannel(MessageChannel channel, String comment)
{ {
channel.sendMessage("Unable to connect to ``" + comment + "``, no such channel!").queue(); // never forget to queue()! return "<Channel?>";
} }
} }

@ -18,7 +18,6 @@ package moe.nekojimi.chords.commands;
import java.util.List; import java.util.List;
import java.util.Queue; import java.util.Queue;
import moe.nekojimi.chords.Downloader;
import moe.nekojimi.chords.Chords; import moe.nekojimi.chords.Chords;
import moe.nekojimi.chords.Track; import moe.nekojimi.chords.Track;
import moe.nekojimi.chords.TrackRequest; import moe.nekojimi.chords.TrackRequest;

Loading…
Cancel
Save