249 lines
9.0 KiB
Java
249 lines
9.0 KiB
Java
package handiebot.lavaplayer.playlist;
|
|
|
|
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
|
import handiebot.utils.Pastebin;
|
|
import handiebot.view.BotLog;
|
|
import sx.blah.discord.api.internal.json.objects.EmbedObject;
|
|
import sx.blah.discord.util.EmbedBuilder;
|
|
|
|
import java.awt.*;
|
|
import java.io.*;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Paths;
|
|
import java.text.MessageFormat;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
import java.util.Random;
|
|
|
|
import static handiebot.HandieBot.log;
|
|
import static handiebot.HandieBot.resourceBundle;
|
|
|
|
/**
|
|
* @author Andrew Lalis
|
|
* A Playlist is a list of Tracks which a track scheduler can pull from to create a queue filled with songs. The
|
|
* playlist is persistent, i.e. it is saved into a file.
|
|
* Be careful, though, as the playlist is not saved in this class, but must be saved manually by whoever is operating
|
|
* on the playlist.
|
|
*/
|
|
public class Playlist {
|
|
|
|
private String name;
|
|
|
|
private List<UnloadedTrack> tracks;
|
|
|
|
/**
|
|
* Creates an empty playlist template.
|
|
* Depending on the circumstances, you may need to call {@code load()} to fill the playlist from a file.
|
|
* @param name The name of the playlist.
|
|
*/
|
|
public Playlist(String name){
|
|
this.name = name;
|
|
this.tracks = new ArrayList<>();
|
|
}
|
|
|
|
public String getName() {
|
|
return this.name;
|
|
}
|
|
|
|
public void setName(String name){
|
|
this.name = name;
|
|
}
|
|
|
|
public int getTrackCount(){
|
|
return this.tracks.size();
|
|
}
|
|
|
|
public List<UnloadedTrack> getTracks(){
|
|
return this.tracks;
|
|
}
|
|
|
|
public void addTrack(UnloadedTrack track){
|
|
this.tracks.add(track);
|
|
}
|
|
|
|
public void removeTrack(UnloadedTrack track){
|
|
this.tracks.remove(track);
|
|
}
|
|
|
|
/**
|
|
* Copies all the tracks from another playlist onto this one.
|
|
* @param playlist A playlist.
|
|
*/
|
|
public void copy(Playlist playlist){
|
|
this.getTracks().clear();
|
|
for (UnloadedTrack track : playlist.getTracks()){
|
|
this.tracks.add(track.clone());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clears the list of tracks.
|
|
*/
|
|
public void clear(){
|
|
this.tracks.clear();
|
|
}
|
|
|
|
/**
|
|
* Loads and returns the audio track that's first on the list.
|
|
* This removes that track from the playlist.
|
|
* @param shouldShuffle If this is true, the track returned will be chosen randomly.
|
|
* @return The AudioTrack corresponding to the next UnloadedTrack in the list.
|
|
*/
|
|
public AudioTrack loadNextTrack(boolean shouldShuffle){
|
|
if (this.getTrackCount() == 0){
|
|
return null;
|
|
}
|
|
if (shouldShuffle){
|
|
return this.tracks.remove(getShuffledIndex(this.tracks.size())).loadAudioTrack();
|
|
} else {
|
|
return this.tracks.remove(0).loadAudioTrack();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Attempts to load a track or playlist from a URL, and add it to the tracks list.
|
|
* @param url The URL to get the song/playlist from.
|
|
*/
|
|
public void loadTrack(String url){
|
|
try {
|
|
UnloadedTrack track = new UnloadedTrack(url);
|
|
this.tracks.add(track);
|
|
log.log(BotLog.TYPE.MUSIC, MessageFormat.format(resourceBundle.getString("playlist.loadTrack.log"), track.getTitle(), this.name));
|
|
} catch (Exception e) {
|
|
log.log(BotLog.TYPE.ERROR, MessageFormat.format(resourceBundle.getString("playlist.loadTrack.error"), url, this.name));
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets a 'shuffled index' from a given list length. That means:
|
|
* - A random number from 0 to (listLength-1) - threshold*(listLength), where threshold is some percentage of
|
|
* recent songs that should be ignored; for example, the most recent 20% of the playlist can be ignored.
|
|
* @param listLength The number of items in a potential list to choose from.
|
|
* @return A pseudo-random choice as to which item to pick from the list.
|
|
*/
|
|
private static int getShuffledIndex(int listLength){
|
|
float threshold = 0.2f;
|
|
int trueLength = listLength - (int)(threshold*(float)listLength);
|
|
Random rand = new Random();
|
|
return rand.nextInt(trueLength);
|
|
}
|
|
|
|
/**
|
|
* Saves the playlist to a file in its name. The playlists are saved into a file in the user's home directory.
|
|
*/
|
|
public void save(){
|
|
String homeDir = System.getProperty("user.home");
|
|
File playlistDir = new File(homeDir+"/.handiebot/playlist");
|
|
if (!playlistDir.exists()){
|
|
if (!playlistDir.mkdirs()){
|
|
log.log(BotLog.TYPE.ERROR, MessageFormat.format(resourceBundle.getString("playlist.save.error.directory"), playlistDir.getPath()));
|
|
return;
|
|
}
|
|
}
|
|
File playlistFile = new File(playlistDir.getPath()+"/"+this.name.replace(" ", "_")+".txt");
|
|
try(Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(playlistFile)))){
|
|
writer.write(Integer.toString(this.tracks.size())+'\n');
|
|
for (UnloadedTrack track : this.tracks){
|
|
writer.write(track.toString());
|
|
writer.write('\n');
|
|
}
|
|
} catch (FileNotFoundException e) {
|
|
log.log(BotLog.TYPE.ERROR, MessageFormat.format(resourceBundle.getString("playlist.save.error.fileNotFound"), this.name));
|
|
e.printStackTrace();
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Loads the playlist from a file with the playlist's name.
|
|
*/
|
|
public void load(){
|
|
String path = System.getProperty("user.home")+"/.handiebot/playlist/"+name.replace(" ", "_")+".txt";
|
|
File playlistFile = new File(path);
|
|
if (playlistFile.exists()){
|
|
try {
|
|
List<String> lines = Files.readAllLines(Paths.get(playlistFile.toURI()));
|
|
int trackCount = Integer.parseInt(lines.remove(0));
|
|
this.tracks = new ArrayList<>(trackCount);
|
|
for (int i = 0; i < trackCount; i++){
|
|
String[] words = lines.remove(0).split(" / ");
|
|
this.tracks.add(new UnloadedTrack(words[0], words[1], Long.parseLong(words[2])));
|
|
}
|
|
} catch (IOException e) {
|
|
log.log(BotLog.TYPE.ERROR, MessageFormat.format(resourceBundle.getString("playlist.load.error.IOException"), this.name, e.getMessage()));
|
|
e.printStackTrace();
|
|
}
|
|
} else {
|
|
log.log(BotLog.TYPE.ERROR, MessageFormat.format(resourceBundle.getString("playlist.load.error.exists"), this.name));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a list of all playlists, or essentially all playlist files.
|
|
* @return A list of all playlists.
|
|
*/
|
|
public static List<String> getAvailablePlaylists(){
|
|
File playlistFolder = new File(System.getProperty("user.home")+"/.handiebot/playlist");
|
|
@SuppressWarnings("ConstantConditions") List<String> names = new ArrayList<>(Arrays.asList(playlistFolder.list()));
|
|
for (int i = 0; i < names.size(); i++){
|
|
String name = names.get(i);
|
|
name = name.replace(".txt", "");
|
|
name = name.replace("_", " ");
|
|
names.set(i, name);
|
|
}
|
|
return names;
|
|
}
|
|
|
|
/**
|
|
* Returns true if a playlist exists.
|
|
* @param name The name of the playlist.
|
|
* @return True if the playlist exists.
|
|
*/
|
|
public static boolean playlistExists(String name){
|
|
List<String> names = getAvailablePlaylists();
|
|
for (String n : names){
|
|
if (n.equals(name)){
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public String toString(){
|
|
StringBuilder sb = new StringBuilder("Playlist: "+this.getName()+'\n');
|
|
if (this.getTrackCount() == 0){
|
|
sb.append(resourceBundle.getString("playlist.empty"));
|
|
} else {
|
|
for (int i = 0; i < this.getTrackCount(); i++) {
|
|
sb.append(i + 1).append(". ").append(this.tracks.get(i).getTitle()).append(" ").append(this.tracks.get(i).getFormattedDuration()).append("\n");
|
|
}
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
public EmbedObject getEmbed(){
|
|
EmbedBuilder eb = new EmbedBuilder();
|
|
eb.withTitle(this.getName());
|
|
eb.withFooterText(this.getTrackCount()+" tracks.");
|
|
eb.withColor(Color.red);
|
|
StringBuilder sb = new StringBuilder();
|
|
boolean needsPastebin = this.getTrackCount() > 20;
|
|
for (int i = 0; i < this.getTrackCount(); i++){
|
|
sb.append(i+1).append(". ").append(this.tracks.get(i).getTitle()).append(' ').append(this.tracks.get(i).getFormattedDuration()).append('\n');
|
|
}
|
|
if (needsPastebin){
|
|
String result = Pastebin.paste(this.getName(), sb.toString());
|
|
eb.withUrl(result);
|
|
eb.withDescription(resourceBundle.getString("playlist.embedTooLarge"));
|
|
} else {
|
|
eb.withDescription(sb.toString());
|
|
}
|
|
return eb.build();
|
|
}
|
|
|
|
}
|