Skip to content

Commit

Permalink
Implement jagrosh#1067 and jagrosh#1010
Browse files Browse the repository at this point in the history
  • Loading branch information
lilliepad1 committed Jul 10, 2024
1 parent 0bcbc6a commit d6bd8a8
Show file tree
Hide file tree
Showing 6 changed files with 239 additions and 9 deletions.
8 changes: 7 additions & 1 deletion src/main/java/com/jagrosh/jmusicbot/BotConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class BotConfig
private String token, prefix, altprefix, helpWord, playlistsFolder, logLevel,
successEmoji, warningEmoji, errorEmoji, loadingEmoji, searchingEmoji,
evalEngine;
private boolean stayInChannel, songInGame, npImages, updatealerts, useEval, dbots;
private boolean stayInChannel, songInGame, npImages, updatealerts, useEval, dbots, autoNowPlaying;
private long owner, maxSeconds, aloneTimeUntilStop;
private int maxYTPlaylistPages;
private double skipratio;
Expand Down Expand Up @@ -86,6 +86,7 @@ public void load()
status = OtherUtil.parseStatus(config.getString("status"));
stayInChannel = config.getBoolean("stayinchannel");
songInGame = config.getBoolean("songinstatus");
autoNowPlaying = config.getBoolean("autonowplaying");
npImages = config.getBoolean("npimages");
updatealerts = config.getBoolean("updatealerts");
logLevel = config.getString("loglevel");
Expand Down Expand Up @@ -303,6 +304,11 @@ public boolean getSongInStatus()
return songInGame;
}

public boolean getAutoNowPlaying()
{
return autoNowPlaying;
}

public String getPlaylistsFolder()
{
return playlistsFolder;
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/jagrosh/jmusicbot/JMusicBot.java
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ private static CommandClient createCommandClient(BotConfig config, SettingsManag
{
// instantiate about command
AboutCommand aboutCommand = new AboutCommand(Color.BLUE.brighter(),
"a music bot that is [easy to host yourself!](https://github.com/jagrosh/MusicBot) (v" + OtherUtil.getCurrentVersion() + ")",
"~~bigman bot dev fork~~ just the only version now. (v" + OtherUtil.getCurrentVersion() + ")",
new String[]{"High-quality music playback", "FairQueue™ Technology", "Easy to host yourself"},
RECOMMENDED_PERMS);
aboutCommand.setIsAuthor(false);
Expand Down Expand Up @@ -202,6 +202,7 @@ private static CommandClient createCommandClient(BotConfig config, SettingsManag
new SeekCmd(bot),
new ShuffleCmd(bot),
new SkipCmd(bot),
new skipSegCmd(bot),

new ForceRemoveCmd(bot),
new ForceskipCmd(bot),
Expand Down
24 changes: 17 additions & 7 deletions src/main/java/com/jagrosh/jmusicbot/audio/AudioHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ public void onTrackStart(AudioPlayer player, AudioTrack track)


// Formatting
public Message getNowPlaying(JDA jda)
public Message getNowPlaying(JDA jda, boolean includeProgress)
{
if(isMusicPlaying(jda))
{
Expand Down Expand Up @@ -252,18 +252,28 @@ public Message getNowPlaying(JDA jda)

if(track.getInfo().author != null && !track.getInfo().author.isEmpty())
eb.setFooter("Source: " + track.getInfo().author, null);
if(includeProgress)
{
double progress = (double)audioPlayer.getPlayingTrack().getPosition()/track.getDuration();
eb.setDescription(getStatusEmoji()
+ " "+FormatUtil.progressBar(progress)
+ " `[" + TimeUtil.formatTime(track.getPosition()) + "/" + TimeUtil.formatTime(track.getDuration()) + "]` "
+ FormatUtil.volumeIcon(audioPlayer.getVolume()));
}
else
eb.setDescription(" `[" + FormatUtil.formatTime(track.getDuration()) + "]` "
+ FormatUtil.volumeIcon(audioPlayer.getVolume()));

double progress = (double)audioPlayer.getPlayingTrack().getPosition()/track.getDuration();
eb.setDescription(getStatusEmoji()
+ " "+FormatUtil.progressBar(progress)
+ " `[" + TimeUtil.formatTime(track.getPosition()) + "/" + TimeUtil.formatTime(track.getDuration()) + "]` "
+ FormatUtil.volumeIcon(audioPlayer.getVolume()));

return mb.setEmbeds(eb.build()).build();
}
else return null;
}

public Message getNowPlaying(JDA jda)
{
return getNowPlaying(jda, true);
}

public Message getNoMusicPlaying(JDA jda)
{
Guild guild = guild(jda);
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/com/jagrosh/jmusicbot/audio/NowplayingHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,28 @@ private void updateAll()
toRemove.forEach(id -> lastNP.remove(id));
}

public void sendNowPlayingMessageForNewTrack(long guildId)
{
Guild guild = bot.getJDA().getGuildById(guildId);
if(guild==null)
return;

Settings settings = bot.getSettingsManager().getSettings(guildId);
TextChannel tchan = settings.getTextChannel(guild);
if (tchan == null)
return;

AudioHandler handler = (AudioHandler)guild.getAudioManager().getSendingHandler();
// Because useNPImages prevents now playing messages from automatically updating,
// there's no point in including the track progress because it will always be
// right at the beginning. Instead show a message just containing the track length:
Message msg = handler.getNowPlaying(bot.getJDA(), !bot.getConfig().useNPImages());
if(msg==null)
return;

tchan.sendMessage(msg).queue((m) -> setLastNPMessage(m));
}

// "event"-based methods
public void onTrackUpdate(AudioTrack track)
{
Expand All @@ -110,8 +132,14 @@ public void onTrackUpdate(AudioTrack track)
else
bot.resetGame();
}
// update channel topic if applicable
updateTopic(guildId, handler, false);

if(bot.getConfig().getAutoNowPlaying())
sendNowPlayingMessageForNewTrack(guildId);
}


public void onMessageDelete(Guild guild, long messageId)
{
Pair<Long,Long> pair = lastNP.get(guild.getIdLong());
Expand Down
177 changes: 177 additions & 0 deletions src/main/java/com/jagrosh/jmusicbot/commands/music/skipSegCmd.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package com.jagrosh.jmusicbot.commands.music;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.jagrosh.jdautilities.command.CommandEvent;
import com.jagrosh.jmusicbot.Bot;
import com.jagrosh.jmusicbot.audio.AudioHandler;
import com.jagrosh.jmusicbot.commands.MusicCommand;
import org.json.JSONArray;
import org.json.JSONObject;
import net.dv8tion.jda.api.Permission;
// import net.dv8tion.jda.api.entities.Message;

public class skipSegCmd extends MusicCommand {
public skipSegCmd(Bot bot) {

super(bot);
this.name = "skipsegment";
this.help = "Skips to the end of the current non-music segment if it is logged in the SponsorBlock database";
this.aliases = bot.getConfig().getAliases(this.name);
this.botPermissions = new Permission[] { Permission.MESSAGE_EMBED_LINKS };
}

/**
* compares given track URL to a regex to extract the unique video id code at
* the end of the URL.
* Needed for feeding into sponsorblock API
*
* @param youtubeVideoURL video URL string
* @return String of video ID code
*/

private String extractYTIDRegex(String youtubeVideoURL) {
String pattern = "(?<=youtu.be/|watch\\?v=|/videos/|embed\\/)[^#\\&\\?]*";
Pattern compiledPattern = Pattern.compile(pattern);
Matcher matcher = compiledPattern.matcher(youtubeVideoURL);
if (matcher.find()) {
return matcher.group();
} else {
return "fail"; //probably not a youtube video
}
}

/**
* Gets the current time stamp of the song in milliseconds
*
* @param handler audio handler object to extract the current time
* @return returns time in milliseconds
*/
private long getCurrentTimeStamp(AudioHandler handler) {
return handler.getPlayer().getPlayingTrack().getPosition();
}

/**
* Takes string response from api, and parses the JSON to extract any skippable
* segments. Compares start and end of segment to current time.
* If current time is within the bounds of a segment, return the time stamp of
* the end of that segment so it canbee skipped to.
*
* @param jsonString Raw string of API response
* @param curTime current time of track
* @return returns end of current skippable segment in milliseconds. If no
* segment is currently playing, return -1
*/

private long parseMusicJSON(String jsonString, long curTime) {
JSONObject obj = new JSONObject(jsonString);
JSONArray segmentArr = obj.getJSONArray("segments");
for (int i = 0; i < segmentArr.length(); i++) {
Float segStart = segmentArr.getJSONObject(i).getFloat("startTime");
Float segEnd = segmentArr.getJSONObject(i).getFloat("endTime");
if (curTime >= segStart && curTime <= segEnd) {
return (long) (segEnd * 1000);
}
}
return -1; //no skippable segment currently playing

}

/**
* connect to sponsorblock api and attempt to make a GET call to the
* searchSegments option. Attempts to get the end of whatever segment
* the player is currently in so the player can skip ahead.
*
* @param videoID string of the video id for the song that is currently playing
* off youtube
* @param handler audio handler to get current time
* @param event message event to send error responses
* @return either returns the end of the current segment in milliseconds, -2 if
* no segments were found, or -1 if segments were found but
* the track is not currently within a segment.
* @throws UnsupportedEncodingException
* @throws IOException
*/
public long connectToAPI(String videoID, AudioHandler handler, CommandEvent event)
throws UnsupportedEncodingException, IOException {
HttpURLConnection con = null;
long curTime = getCurrentTimeStamp(handler) / 1000; // convert to seconds
boolean musicSegment = false;

try {
String nonMusicURLString = "https://sponsor.ajay.app/api/searchSegments?videoID=";
nonMusicURLString += videoID;
URL nonMusicURL = new URL(nonMusicURLString);
String apiResponse = null;
try {
con = (HttpURLConnection) nonMusicURL.openConnection();
con.setRequestMethod("GET");
int responsecode = con.getResponseCode();
if (responsecode == 200) {
event.replySuccess("Found non-music segments in database!");
musicSegment = true;
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream()));
while ((apiResponse = in.readLine()) != null) {
return parseMusicJSON(apiResponse, curTime);
}

in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (MalformedURLException e) {
e.printStackTrace();
}

// no segments found
if (!musicSegment) {
return -2;

// segments found but player is not in one currently
} else {
return -1;
}
}

@Override
public void doCommand(CommandEvent event) {
AudioHandler handler = (AudioHandler) event.getGuild().getAudioManager().getSendingHandler();
try {
String videoId = extractYTIDRegex(handler.getPlayer().getPlayingTrack().getInfo().uri);
if (videoId != "fail") {
long reply = connectToAPI(videoId, handler, event);

if (reply == -2) {
event.replyError("No segments found!");
} else if (reply == -1) {
event.replyError("Cannot skip here because no segment is currently playing!");
} else {
handler.getPlayer().getPlayingTrack().setPosition(reply);

long absSeconds = reply / 1000;
long minutes = absSeconds / 60;
long modSeconds = absSeconds % 60;
String formattedSeconds = String.format("%02d", modSeconds);
String msg = "Skipping ahead to " + minutes + ":" + formattedSeconds + "!";
event.replySuccess(msg);
}
} else {
event.replyError("Could not get video ID!"); //should only come up on non-youtube links
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

}
}
8 changes: 8 additions & 0 deletions src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@ npimages = false
stayinchannel = false



// If you set this, the bot will automatically send a message displaying the current
// track and which user queued it when a track starts playing for guilds that have
// set a text channel for music commands.

autonowplaying = true


// This sets the maximum amount of seconds any track loaded can be. If not set or set
// to any number less than or equal to zero, there is no maximum time length. This time
// restriction applies to songs loaded from any source.
Expand Down

0 comments on commit d6bd8a8

Please sign in to comment.