robinfriedli / aiode

Discord bot that plays Spotify tracks and YouTube videos or any URL including Soundcloud links and Twitch streams
Apache License 2.0
288 stars 74 forks source link

Multi-line commands #249

Closed vintium closed 3 years ago

vintium commented 3 years ago

I've just started using this bot in my servers and I think it's super powerful and am very happy to have found it. In my testing it out, I found this issue and I was so glad to see that it was open source! Heres the issue: There's been a couple times where I've accidentally lost my queue by using $botify play ... (an issue about this), and I've tried to restore the queue by copying a bunch of my $botify queue ... commands into a message and sending it. The bot returned to me a parsing error. Here's an example. If this was the message I sent to the bot (one message, not multiple):

$botify queue Empire State Of Mind artist:JAY-Z
$botify queue MONTERO artist:Lil Nas X
$botify queue Sense artist:King Gizz
$botify queue Mars For The Rich
$botify queue Under the Bridge artist:Red
$botify queue Somebody that i used to know artist:gotye

It responds with:

Invalid command
Undefined argument 'botify' on command 'queue'.
...f Mind artist:JAY-Z
$botify queue MONTER...
                       ^
Failed at: 34

Is this not supposed to be an argument? Botify interpreted it as one because it started with the argument prefix ('$' or your custom argument prefix defined with the property command). If this was a mistake and the argument prefix is supposed to be part of the command input you can escape the prefix by putting a \ in front of it. E.g. play $spotify \$trackname.

This seems like a pretty easy fix. Rather than parsing a whole message as a single command, Split the message by newlines and parse each line as a command.

def on_message(msg):
    commands = msg.splitlines()
    for command in commands:
        parse_and_run(command)

Obviously this pseudocode simplifies, but this would be the type of fix needed. (I would write it myself and send a PR, but I don't know java 🙁)

robinfriedli commented 3 years ago

If you're hosting an instance of botify you could add a script for that like so:

$botify script $identifier=runAll "
def commands = input.split('\\n')
for (def cmdStr : commands) {
    if (cmdStr.isBlank()) {
        continue
    }
    command.run(cmdStr)
}
"
"

then you could do

$botify runAll
queue Empire State Of Mind artist:JAY-Z
queue MONTERO artist:Lil Nas X
queue Sense artist:King Gizz
queue Mars For The Rich
queue Under the Bridge artist:Red
queue Somebody that i used to know artist:gotye

(would change the default $botify prefix to a custom one though ;))

Note that you couldn't run more than 5 commands though as command.run is limited to 5 invocations per script, though if you're hosting your own instance you could change that in the groovyWhitelist.xml file on line 454.

For this specific use case you could also create a script that queues several items separated by comma like so:

$botify script $identifier=queueAll "
def argsRaw = input.split(',')
def args = Arrays.stream(argsRaw).map({s -> s.trim()}).filter({s -> !s.isEmpty()}).collect(Collectors.toList())
if (args.size() > 5) {
    messages.sendError('Cannot select more than 5 items', channel)
    return null
}
for (def arg : args) {
    command.run('queue ' + arg)
}
return null
"

(remove the size check if you change the limit for command.run invocations, that's just the script I use)

then you can do $botify queueAll numb, "$album $spotify $select=1 meteora", in the end