Skip to content
This repository has been archived by the owner on Apr 9, 2021. It is now read-only.

Added queue position and approx wait time. #402 #404

Open
wants to merge 18 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 59 additions & 26 deletions FredBoat/src/main/java/fredboat/audio/queue/AudioLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,19 @@
import fredboat.feature.togglz.FeatureFlags;
import fredboat.jda.JdaEntityProvider;
import fredboat.messaging.CentralMessaging;
import fredboat.util.PlayerUtil;
import fredboat.util.TextUtils;
import fredboat.util.ratelimit.Ratelimiter;
import fredboat.util.rest.YoutubeAPI;
import fredboat.util.rest.YoutubeVideo;
import net.dv8tion.jda.core.MessageBuilder;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand All @@ -61,6 +63,7 @@ public class AudioLoader implements AudioLoadResultHandler {
//Matches a timestamp and the description
private static final Pattern SPLIT_DESCRIPTION_PATTERN = Pattern.compile("(.*?)[( \\[]*((?:\\d?\\d:)?\\d?\\d:\\d\\d)[) \\]]*(.*)");
private static final int QUEUE_TRACK_LIMIT = 10000;
private static final int MAX_QUEUE_MESSAGE_DISPLAY = 3;

private final JdaEntityProvider jdaEntityProvider;
private final Ratelimiter ratelimiter;
Expand Down Expand Up @@ -182,11 +185,8 @@ public void trackLoaded(AudioTrack at) {
} else {

if (!context.isQuiet()) {
context.reply(gplayer.isPlaying() ?
context.i18nFormat("loadSingleTrack", TextUtils.escapeAndDefuse(at.getInfo().title))
:
context.i18nFormat("loadSingleTrackAndPlay", TextUtils.escapeAndDefuse(at.getInfo().title))
);
context.reply(this.buildMusicQueueMessage(at.getInfo().title, at.getInfo().length));

} else {
log.info("Quietly loaded " + at.getIdentifier());
}
Expand All @@ -208,18 +208,30 @@ public void trackLoaded(AudioTrack at) {
public void playlistLoaded(AudioPlaylist ap) {
Metrics.tracksLoaded.inc(ap.getTracks() == null ? 0 : ap.getTracks().size());
try {
int statusMessageCount = 0;
if(context.isSplit()){
context.reply(context.i18n("loadPlaySplitListFail"));
loadNextAsync();
return;
}

List<AudioTrackContext> toAdd = new ArrayList<>();
StringBuilder replyMessage = new StringBuilder();
for (AudioTrack at : ap.getTracks()) {
toAdd.add(new AudioTrackContext(jdaEntityProvider, at, context.getMember()));
if (statusMessageCount < MAX_QUEUE_MESSAGE_DISPLAY) {
statusMessageCount++;

replyMessage.append(this.buildMusicQueueMessage(at.getInfo().title, at.getInfo().length))
.append("\n\n");
}

trackProvider.add(new AudioTrackContext(jdaEntityProvider, at, context.getMember()));
}
trackProvider.addAll(toAdd);
context.reply(context.i18nFormat("loadListSuccess", ap.getTracks().size(), ap.getName()));

if (ap.getTracks().size() > MAX_QUEUE_MESSAGE_DISPLAY) {
replyMessage.append("...\n");
context.reply(replyMessage + context.i18nFormat("loadListSuccess", ap.getTracks().size(), ap.getName()));
}

if (!gplayer.isPaused()) {
gplayer.play();
}
Expand Down Expand Up @@ -276,18 +288,16 @@ private void loadSplit(AudioTrack at, IdentifierContext ic){
} else {
pairs.add(new ImmutablePair<>(timestamp, title2));
}


}

if(pairs.size() < 2) {
ic.reply(ic.i18n("loadSplitNotResolves"));
return;
}

ArrayList<SplitAudioTrackContext> list = new ArrayList<>();

int i = 0;
MessageBuilder mb = CentralMessaging.getClearThreadLocalMessageBuilder();

for(Pair<Long, String> pair : pairs){
long startPos;
long endPos;
Expand All @@ -307,26 +317,27 @@ private void loadSplit(AudioTrack at, IdentifierContext ic){

SplitAudioTrackContext atc = new SplitAudioTrackContext(jdaEntityProvider, newAt, ic.getMember(), startPos, endPos, pair.getRight());

list.add(atc);
if (i < MAX_QUEUE_MESSAGE_DISPLAY
&& !StringUtils.isBlank(atc.getEffectiveTitle())) {

mb.append(this.buildMusicQueueMessage(atc.getEffectiveTitle(), atc.getEffectiveDuration()))
.append("\n\n");
}

gplayer.queue(atc);

i++;
}

MessageBuilder mb = CentralMessaging.getClearThreadLocalMessageBuilder()
.append(ic.i18n("loadFollowingTracksAdded")).append("\n");
for(SplitAudioTrackContext atc : list) {
mb.append("`[")
.append(TextUtils.formatTime(atc.getEffectiveDuration()))
.append("]` ")
.append(TextUtils.escapeAndDefuse(atc.getEffectiveTitle()))
.append("\n");
if (i > MAX_QUEUE_MESSAGE_DISPLAY) {
mb.append("...\n");
mb.append(context.i18nFormat("loadListSuccess", i, at.getInfo().title));
}

//This is pretty spammy .. let's use a shorter one
if(mb.length() > 800){
// This is pretty spammy .. let's use a shorter one
if (mb.length() > 800) {
mb = CentralMessaging.getClearThreadLocalMessageBuilder()
.append(ic.i18nFormat("loadPlaylistTooMany", list.size()));
.append(ic.i18nFormat("loadPlaylistTooMany", i));
}

context.reply(mb.build());
Expand Down Expand Up @@ -362,4 +373,26 @@ private void handleThrowable(IdentifierContext ic, Throwable th) {
}
}

/**
* Build queue message based on title and duration.
* It will use player and context object to determine if something is playing.
* <p>
* NOTE: It will not add a new line for each string, this assume the caller will handle newline.
* </p>
*
* @param title Title of the music.
* @param duration Duration of the music.
* @return String object representing the message to reply for each queue.
*/
private String buildMusicQueueMessage(@Nonnull String title, long duration){

String playingStatusOrQueueTime = PlayerUtil.resolveStatusOrQueueMessage(gplayer, context);
String songTitleAndMusic =
TextUtils.boldenText(TextUtils.escapeAndDefuse(title)) + " " +
"(" + TextUtils.formatTime(duration) + ")";

return playingStatusOrQueueTime +
"\n\t" +
songTitleAndMusic;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@
import fredboat.commandmeta.abs.CommandContext;
import fredboat.commandmeta.abs.ICommandRestricted;
import fredboat.commandmeta.abs.IMusicCommand;
import fredboat.definitions.PermissionLevel;
import fredboat.main.Launcher;
import fredboat.messaging.CentralMessaging;
import fredboat.messaging.internal.Context;
import fredboat.util.PlayerUtil;
import fredboat.definitions.PermissionLevel;
import fredboat.main.Launcher;
import fredboat.util.TextUtils;
import net.dv8tion.jda.core.entities.Member;
import net.dv8tion.jda.core.entities.TextChannel;
Expand Down Expand Up @@ -109,13 +110,31 @@ static void select(CommandContext context, VideoSelectionCache videoSelectionCac
for (int i = 0; i < validChoices.size(); i++) {
selectedTracks[i] = selection.choices.get(validChoices.get(i) - 1);

String msg = context.i18nFormat("selectSuccess", validChoices.get(i),
TextUtils.escapeAndDefuse(selectedTracks[i].getInfo().title),
TextUtils.formatTime(selectedTracks[i].getInfo().length));
String playingStatusOrQueueTime = PlayerUtil.resolveStatusOrQueueMessage(player, context);

// Print the selection string.
String selectionSuccessString = context.i18nFormat(
"selectSuccess",
TextUtils.boldenText("\\#" + validChoices.get(i)) +
" ~ " + playingStatusOrQueueTime);
outputMsgBuilder.append(selectionSuccessString);
outputMsgBuilder.append("\n");

// Print the song title and length.
outputMsgBuilder.append("\t\t");

// Merge title and the length in one string.
String songTitleAndMusic =
TextUtils.boldenText(TextUtils.escapeAndDefuse(selectedTracks[i].getInfo().title)) + " " +
"(" + TextUtils.formatTime(selectedTracks[i].getInfo().length) + ")";

outputMsgBuilder.append(songTitleAndMusic);
outputMsgBuilder.append("\n");

// if there are more selections.
if (i < validChoices.size()) {
outputMsgBuilder.append("\n");
}
outputMsgBuilder.append(msg);

player.queue(new AudioTrackContext(Launcher.getBotController().getJdaEntityProvider(),
selectedTracks[i], invoker));
Expand Down
51 changes: 51 additions & 0 deletions FredBoat/src/main/java/fredboat/util/PlayerUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package fredboat.util;

import fredboat.audio.player.GuildPlayer;
import fredboat.messaging.internal.Context;

import javax.annotation.Nonnull;

public class PlayerUtil {

/**
* No initialization!
*/
private PlayerUtil() {
}

/**
* Resolve which message to be replying to the discord channel based on how many audio is in the queue.
*
* @param player Guild player.
* @param context Context object to be used for retrieving i18n strings.
* @return String represent of the current state of the player for adding audio.
*/
public static String resolveStatusOrQueueMessage(@Nonnull GuildPlayer player, @Nonnull Context context) {
String playingStatusOrQueueTime;
int positionInQueue = player.getTrackCount() + 1;
if (player.getTrackCount() < 1) {
playingStatusOrQueueTime = TextUtils.italicizeText(context.i18n("selectSuccessPartNowPlaying"));
} else {
if (player.getRemainingTracks()
.stream()
.noneMatch(
audioTrackContext -> audioTrackContext.getTrack().getInfo().isStream)) {

// Currently is not playing any live stream.
long remainingTimeInMillis = player.getTotalRemainingMusicTimeMillis();
String remainingTime = TextUtils.formatTime(remainingTimeInMillis);
playingStatusOrQueueTime = context.i18nFormat(
"selectSuccessPartQueueWaitTime",
TextUtils.boldenText(positionInQueue),
TextUtils.boldenText(remainingTime));

} else {
playingStatusOrQueueTime = context.i18nFormat(
"selectSuccessPartQueueHasStream",
TextUtils.boldenText(positionInQueue));
}
}

return playingStatusOrQueueTime;
}
}
23 changes: 23 additions & 0 deletions FredBoat/src/main/java/fredboat/util/TextUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,28 @@ public static String shorten(@Nonnull String input, int size) {
return shortened.toString();
}

/**
* Wraps input with discord's markdown bold marker.
*
* @param input Object#toString() to be wrapped in bold. Must be non null.
* @return String with ** wrapped.
*/
@Nonnull
public static <T> String boldenText(@Nonnull T input) {
return "**" + input + "**";
}

/**
* Wraps input with discord's markdown italic marker.
*
* @param input Object#toString() to be wrapped in italic marker. Must be non null.
* @return String with * wrapped.
*/
@Nonnull
public static <T> String italicizeText(@Nonnull T input) {
return "*" + input + "*";
}

/**
* @return the input, with escaped markdown and defused mentions and URLs
* It is a good idea to use this on any user generated values that we reply in plain text.
Expand Down Expand Up @@ -414,6 +436,7 @@ private static String defuseUrls(@Nonnull String input) {
.filteredBy(CharacterPredicates.LETTERS, CharacterPredicates.DIGITS)
.build();

@Nonnull
public static String randomAlphaNumericString(int length) {
if (length < 1) {
throw new IllegalArgumentException();
Expand Down
5 changes: 4 additions & 1 deletion FredBoat/src/main/resources/lang/en_US.properties
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ pauseSuccess=The player is now paused. You can unpause it with `{0}unpause`.
repeatOnSingle=The player will now repeat the current track.
repeatOnAll=The player will now repeat the queue.
repeatOff=The player is no longer on repeat.
selectSuccess=Song **\#{0}** has been selected\: **{1}** ({2})
selectSuccess=Song selected {0}
selectSuccessPartNowPlaying=Now playing
selectSuccessPartQueueWaitTime=Queued as #{0}, playing in: {1}.
selectSuccessPartQueueHasStream=Queued as #{0}, playing after live stream.
selectInterval=Must be a number 1-{0}.
selectSelectionNotGiven=You must first be given a selection to choose from.
shuffleOn=The player is now shuffled.
Expand Down