Externalized many strings, converted playlist view to tables, and made the playlist show command more pretty.

This commit is contained in:
Andrew Lalis 2017-07-31 12:54:23 +02:00 committed by Andrew Lalis
parent 0cefc0946a
commit 53608d9a93
15 changed files with 183 additions and 40 deletions

View File

@ -14,7 +14,9 @@ import handiebot.utils.YoutubeSearch;
import handiebot.view.BotLog;
import sx.blah.discord.handle.obj.IChannel;
import sx.blah.discord.handle.obj.IMessage;
import sx.blah.discord.util.EmbedBuilder;
import java.awt.*;
import java.io.File;
import java.text.MessageFormat;
import java.util.ArrayList;
@ -148,14 +150,20 @@ public class PlaylistCommand extends ContextCommand {
return;
Playlist playlist = new Playlist(context.getArgs()[1]);
playlist.load();
sendMessage(playlist.toString(), context.getChannel());
sendMessage(playlist.getEmbed(), context.getChannel());
} else {
List<String> playlists = Playlist.getAvailablePlaylists();
StringBuilder sb = new StringBuilder("**Playlists:**\n");
EmbedBuilder eb = new EmbedBuilder();
eb.withTitle("Playlists:");
eb.withColor(Color.red);
StringBuilder sb = new StringBuilder();
for (String playlist : playlists) {
sb.append(playlist).append('\n');
Playlist p = new Playlist(playlist);
p.load();
sb.append(p.getName()).append(", ").append(p.getTrackCount()).append(" tracks.\n");
}
sendMessage(sb.toString(), context.getChannel());
eb.withDescription(sb.toString());
sendMessage(eb.build(), context.getChannel());
}
}
@ -176,7 +184,6 @@ public class PlaylistCommand extends ContextCommand {
sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.add.message"), playlist.getName()), context.getChannel());
}
playlist.save();
sendMessage(playlist.toString(), context.getChannel());
log.log(BotLog.TYPE.INFO, MessageFormat.format(resourceBundle.getString("commands.command.playlist.add.log"), playlist.getName()));
} else {
//This is a youtube search query.

View File

@ -43,13 +43,14 @@ public class QueueCommand extends ContextCommand {
}
break;
case ("save"):
//TODO: add some error messages so users know how to use this.
if (context.getArgs().length == 2 && Commands.hasPermission(context, 8)) {
Playlist p = HandieBot.musicPlayer.getAllSongsInQueue(context.getGuild());
p.setName(context.getArgs()[1]);
p.save();
sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.queue.save.message"), p.getTrackCount(), p.getName()), context.getChannel());
log.log(BotLog.TYPE.INFO, MessageFormat.format(resourceBundle.getString("commands.command.queue.save.log"), p.getName()));
} else {
sendMessage(resourceBundle.getString("commands.command.queue.error.save"), context.getChannel());
}
break;
}

View File

@ -6,16 +6,18 @@ import handiebot.view.BotLog;
import sx.blah.discord.handle.obj.IMessage;
import sx.blah.discord.handle.obj.IUser;
import java.text.MessageFormat;
import java.util.List;
import static handiebot.HandieBot.log;
import static handiebot.HandieBot.resourceBundle;
/**
* @author Andrew Lalis
* Specific Listener for choices in the Play command, where songs chosen are added to the active queue.
*/
public class YoutubePlayListener extends YoutubeChoiceListener {
//TODO: Externalize strings
public YoutubePlayListener(IMessage message, IUser user, List<String> urls) {
super(message, user, urls);
}
@ -24,7 +26,7 @@ public class YoutubePlayListener extends YoutubeChoiceListener {
protected void onChoice(int choice) {
try {
HandieBot.musicPlayer.addToQueue(message.getGuild(), new UnloadedTrack(urls.get(choice)), this.user);
log.log(BotLog.TYPE.MUSIC, message.getGuild(), this.user.getName()+" chose item "+(choice+1)+" from the Youtube query.");
log.log(BotLog.TYPE.MUSIC, message.getGuild(), MessageFormat.format(resourceBundle.getString("commands.youtube.choiceMade.log"), this.user.getName(), choice+1));
} catch (Exception e) {
e.printStackTrace();
}

View File

@ -4,8 +4,10 @@ import handiebot.lavaplayer.playlist.Playlist;
import sx.blah.discord.handle.obj.IMessage;
import sx.blah.discord.handle.obj.IUser;
import java.text.MessageFormat;
import java.util.List;
import static handiebot.HandieBot.resourceBundle;
import static handiebot.utils.MessageUtils.sendMessage;
/**
@ -13,7 +15,7 @@ import static handiebot.utils.MessageUtils.sendMessage;
* Specific Listener for adding songs to a playlist that must be saved.
*/
public class YoutubePlaylistAddListener extends YoutubeChoiceListener {
//TODO: externalize strings
private Playlist playlist;
public YoutubePlaylistAddListener(IMessage message, IUser user, List<String> urls, Playlist playlist) {
@ -25,6 +27,6 @@ public class YoutubePlaylistAddListener extends YoutubeChoiceListener {
protected void onChoice(int choice) {
this.playlist.loadTrack(this.urls.get(choice));
this.playlist.save();
sendMessage("Added song to *"+this.playlist.getName()+"*.", message.getChannel());
sendMessage(MessageFormat.format(resourceBundle.getString("commands.command.playlist.add.message"), this.playlist.getName()), message.getChannel());
}
}

View File

@ -1,11 +1,16 @@
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;
@ -22,7 +27,7 @@ import static handiebot.HandieBot.resourceBundle;
* on the playlist.
*/
public class Playlist {
//TODO: Externalize strings.
private String name;
private List<UnloadedTrack> tracks;
@ -104,9 +109,9 @@ public class Playlist {
try {
UnloadedTrack track = new UnloadedTrack(url);
this.tracks.add(track);
log.log(BotLog.TYPE.MUSIC, "Added "+track.getTitle()+" to playlist ["+this.name+"].");
log.log(BotLog.TYPE.MUSIC, MessageFormat.format(resourceBundle.getString("playlist.loadTrack.log"), track.getTitle(), this.name));
} catch (Exception e) {
log.log(BotLog.TYPE.ERROR, "Unable to add "+url+" to the playlist ["+this.name+"].");
log.log(BotLog.TYPE.ERROR, MessageFormat.format(resourceBundle.getString("playlist.loadTrack.error"), url, this.name));
e.printStackTrace();
}
}
@ -135,12 +140,11 @@ public class Playlist {
File playlistDir = new File(homeDir+"/.handiebot/playlist");
if (!playlistDir.exists()){
if (!playlistDir.mkdirs()){
log.log(BotLog.TYPE.ERROR, "Unable to make directory: "+playlistDir.getPath());
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");
log.log(BotLog.TYPE.INFO, "Saving playlist to: "+playlistFile.getAbsolutePath());
try(Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(playlistFile)))){
writer.write(Integer.toString(this.tracks.size())+'\n');
for (UnloadedTrack track : this.tracks){
@ -148,7 +152,7 @@ public class Playlist {
writer.write('\n');
}
} catch (FileNotFoundException e) {
log.log(BotLog.TYPE.ERROR, "Unable to find file to write playlist: "+this.name);
log.log(BotLog.TYPE.ERROR, MessageFormat.format(resourceBundle.getString("playlist.save.error.fileNotFound"), this.name));
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
@ -171,11 +175,11 @@ public class Playlist {
this.tracks.add(new UnloadedTrack(words[0], words[1], Long.parseLong(words[2])));
}
} catch (IOException e) {
log.log(BotLog.TYPE.ERROR, "IOException while loading playlist ["+this.name+"]. "+e.getMessage());
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, "The playlist ["+this.name+"] does not exist.");
log.log(BotLog.TYPE.ERROR, MessageFormat.format(resourceBundle.getString("playlist.load.error.exists"), this.name));
}
}
@ -223,4 +227,24 @@ public class Playlist {
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();
}
}

View File

@ -92,6 +92,10 @@ public class UnloadedTrack implements Cloneable {
return this.title;
}
public void setTitle(String newTitle){
this.title = newTitle;
}
public String getURL(){
return this.url;
}

View File

@ -29,6 +29,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.GeneralSecurityException;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
@ -36,6 +37,7 @@ import java.util.List;
import java.util.Locale;
import static handiebot.HandieBot.APPLICATION_NAME;
import static handiebot.HandieBot.resourceBundle;
import static handiebot.utils.MessageUtils.addReaction;
import static handiebot.utils.MessageUtils.sendMessage;
@ -44,7 +46,7 @@ import static handiebot.utils.MessageUtils.sendMessage;
* Class to query Youtube Data API for results to searches, and return these in a nice list.
*/
public class YoutubeSearch {
//TODO: Externalize Strings
private static final String KEY = "AIzaSyAjYuxCYBCuZCNvW4w573LQ-jw5UKL64G8";
private static final int NUMBER_OF_VIDEOS_RETURNED = 5;
@ -153,7 +155,7 @@ public class YoutubeSearch {
public static EmbedObject createEmbed(List<Video> results){
EmbedBuilder builder = new EmbedBuilder();
if (results != null) {
builder.withTitle("Showing the first " + NUMBER_OF_VIDEOS_RETURNED + " results from YouTube.com");
builder.withTitle(MessageFormat.format(resourceBundle.getString("commands.youtube.title"), NUMBER_OF_VIDEOS_RETURNED));
builder.withColor(Color.red);
for (int i = 0; i < results.size(); i++) {
Video video = results.get(i);
@ -186,7 +188,7 @@ public class YoutubeSearch {
"\n"+ WATCH_URL + video.getId(),
false);
}
builder.withFooterText("Please add a reaction to select a song, or cancel. Choice times out in 30 seconds.");
builder.withFooterText(resourceBundle.getString("commands.youtube.footerInstruction"));
}
return builder.build();
}

View File

@ -1,12 +1,14 @@
package handiebot.view;
import handiebot.HandieBot;
import handiebot.view.listeners.CommandLineListener;
import handiebot.view.listeners.PlaylistSelectionListener;
import handiebot.view.listeners.SongRenameListener;
import handiebot.view.tableModels.PlaylistTableModel;
import handiebot.view.tableModels.SongsTableModel;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
@ -26,7 +28,6 @@ public class BotWindow extends JFrame {
//Playlist display variables.
private PlaylistTableModel playlistTableModel;
private SongsTableModel songsTableModel;
private ListSelectionListener playlistListener;
private JPanel playlistDisplayPanel;
public BotWindow(){
@ -54,19 +55,29 @@ public class BotWindow extends JFrame {
//Playlist name scroll pane.
playlistTable.setRowSelectionAllowed(true);
playlistTable.setDragEnabled(false);
playlistTable.getTableHeader().setResizingAllowed(false);
playlistTable.getTableHeader().setReorderingAllowed(false);
playlistTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
playlistTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
playlistTable.getSelectionModel().addListSelectionListener(new PlaylistSelectionListener(this.songsTableModel, playlistTable, songsTable));
JScrollPane playlistNamesScrollPane = new JScrollPane(playlistTable);
playlistNamesScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
playlistNamesScrollPane.setPreferredSize(new Dimension(250, 200));
playlistTable.getColumnModel().getColumn(0).setPreferredWidth(190);
playlistTable.getColumnModel().getColumn(1).setPreferredWidth(42);
playlistDisplayPanel.add(playlistNamesScrollPane, BorderLayout.PAGE_START);
//Song names scroll pane.
songsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
songsTable.setDragEnabled(false);
songsTable.getTableHeader().setResizingAllowed(false);
songsTable.getTableHeader().setReorderingAllowed(false);
songsTable.setRowSelectionAllowed(true);
songsTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
songsTable.addMouseListener(new SongRenameListener());
JScrollPane songNamesScrollPane = new JScrollPane(songsTable);
songNamesScrollPane.setColumnHeaderView(new JLabel("Selected Playlist"));
songNamesScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
playlistDisplayPanel.add(songNamesScrollPane, BorderLayout.CENTER);
getContentPane().add(playlistDisplayPanel, BorderLayout.EAST);
@ -110,7 +121,7 @@ public class BotWindow extends JFrame {
* Updates the list of playlist names.
*/
public void updatePlaylistNames(){
this.playlistTableModel = new PlaylistTableModel();
this.playlistTableModel.loadPlaylistData();
}
/**

View File

@ -1,4 +1,4 @@
package handiebot.view;
package handiebot.view.listeners;
import handiebot.HandieBot;
import handiebot.command.CommandContext;
@ -6,6 +6,7 @@ import handiebot.command.types.Command;
import handiebot.command.types.CommandLineCommand;
import handiebot.command.types.ContextCommand;
import handiebot.command.types.StaticCommand;
import handiebot.view.BotLog;
import javax.swing.*;
import java.awt.event.KeyEvent;

View File

@ -1,4 +1,4 @@
package handiebot.view;
package handiebot.view.listeners;
import handiebot.lavaplayer.playlist.Playlist;
import handiebot.utils.TableColumnAdjuster;
@ -19,15 +19,12 @@ public class PlaylistSelectionListener implements ListSelectionListener {
//The table that shows the playlist names.
private JTable table;
//The table for the songs.
private JTable songsTable;
private TableColumnAdjuster tca;
public PlaylistSelectionListener(SongsTableModel songsModel, JTable table, JTable songsTable){
this.songsModel = songsModel;
this.table = table;
this.songsTable = songsTable;
this.tca = new TableColumnAdjuster(songsTable);
}
@Override
@ -47,7 +44,8 @@ public class PlaylistSelectionListener implements ListSelectionListener {
Playlist playlist = new Playlist(selectedValue);
playlist.load();
this.songsModel.setPlaylist(playlist);
this.tca.adjustColumns();
this.songsTable.setName(playlist.getName());
new TableColumnAdjuster(this.songsTable).adjustColumns();
}
}

View File

@ -0,0 +1,56 @@
package handiebot.view.listeners;
import handiebot.lavaplayer.playlist.Playlist;
import handiebot.utils.TableColumnAdjuster;
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
/**
* @author Andrew Lalis
* Listener to check if the user has double-clicked on a song's name, and give them an option to rename that song.
*/
public class SongRenameListener implements MouseListener {
//TODO: Externalize strings.
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2){
JTable table = (JTable) e.getSource();
int row = table.rowAtPoint(e.getPoint());
int col = table.columnAtPoint(e.getPoint());
if (col == 1){
String oldValue = (String) table.getModel().getValueAt(row, col);
String result = JOptionPane.showInputDialog(table, "Enter a modified name for the song.", oldValue);
if (result != null){
table.getModel().setValueAt(result, row, col);
new TableColumnAdjuster(table).adjustColumns();
Playlist playlist = new Playlist(table.getName());
playlist.load();
playlist.getTracks().get(row).setTitle(result);
playlist.save();
}
}
}
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}

View File

@ -19,14 +19,7 @@ public class PlaylistTableModel extends AbstractTableModel {
private String[][] data;
public PlaylistTableModel(){
List<String> playlistNames = Playlist.getAvailablePlaylists();
data = new String[playlistNames.size()][columnNames.length];
for (int i = 0; i < playlistNames.size(); i++){
data[i][0] = playlistNames.get(i);
Playlist p = new Playlist(playlistNames.get(i));
p.load();
data[i][1] = Integer.toString(p.getTrackCount());
}
loadPlaylistData();
}
@Override
@ -53,4 +46,20 @@ public class PlaylistTableModel extends AbstractTableModel {
public Object getValueAt(int rowIndex, int columnIndex) {
return data[rowIndex][columnIndex];
}
/**
* Loads from the file system a list of playlists and sets the data to the updated list.
*/
public void loadPlaylistData(){
List<String> playlistNames = Playlist.getAvailablePlaylists();
data = new String[playlistNames.size()][columnNames.length];
for (int i = 0; i < playlistNames.size(); i++){
data[i][0] = playlistNames.get(i);
Playlist p = new Playlist(playlistNames.get(i));
p.load();
data[i][1] = Integer.toString(p.getTrackCount());
}
this.fireTableDataChanged();
}
}

View File

@ -45,6 +45,12 @@ public class SongsTableModel extends AbstractTableModel {
return data[rowIndex][columnIndex];
}
@Override
public void setValueAt(Object obj, int rowIndex, int columnIndex){
this.data[rowIndex][columnIndex] = (String) obj;
this.fireTableDataChanged();
}
public void setPlaylist(Playlist playlist){
this.data = new String[playlist.getTrackCount()][columnNames.length];
for (int i = 0; i < playlist.getTrackCount(); i++){

View File

@ -98,6 +98,7 @@ commands.command.queue.description.save=Saves the queue to a playlist.
commands.command.queue.clear=Cleared queue.
commands.command.queue.save.message=Saved {0} tracks to playlist **{1}**.
commands.command.queue.save.log=Saved queue to playlist [{0}].
commands.command.queue.error.save=Unable to save the queue to a playlist.
#Repeat
commands.command.repeat.description=Sets repeating.
#Shuffle
@ -108,6 +109,10 @@ commands.command.skip.description=Skips the current song.
commands.command.stop.description=Stops playing music.
#Tengwar translator
commands.command.tengwar.description=Translates text to tengwar, or decodes tengwar text back into human readable form.
#Youtube Interface
commands.youtube.choiceMade.log={0} chose item {1} from the Youtube query.
commands.youtube.title=Showing the first {0} results from YouTube.com.
commands.youtube.footerInstruction=Please add a reaction to select a song, or cancel. Choice times out in 30 seconds.
#Music Player
player.setRepeat=Set **Repeat** to *{0}*.
player.setShuffle=Set **Shuffle** to *{0}*.
@ -131,5 +136,12 @@ fileutil.fileCreateError=Unable to create file. {0}
fileutil.writeError=Unable to write to file. {0}
#Playlist strings
playlist.empty=There are no songs in this playlist.
playlist.embedTooLarge=The playlist is too large for a discord message. Please follow the link in the title to the full list on Pastebin.com.
playlist.loadTrack.log=Added {0} to playlist [{1}].
playlist.loadTrack.error=Unable to add {0} to the playlist [{1}].
playlist.save.error.directory=Unable to make directory: {0}
playlist.save.error.fileNotFound=Unable to find file to write playlist: {0}
playlist.load.error.IOException=IOException while loading playlist [{0}]. {1}
playlist.load.error.exists=The playlist [{0}] does not exist.

View File

@ -5,7 +5,7 @@
#Log
log.loggingIn=Bezig met inloggen van de client...
log.init=HandieBot geïnitialiseerd.
log.init=HandieBot ge<EFBFBD>nitialiseerd.
log.shuttingDown=Bezig met het afsluiten van de bot.
log.deleteMessageError=Niet mogelijk het bericht te vewijderen. Zorg er alstublieft voor dat de bot MANAGE_MESSAGES aan heeft, met name in dit kanaal.
log.creatingChatChannel=Geen chat gevonden. Bezig met het maken er van.
@ -121,5 +121,13 @@ fileutil.fileCreateError=Unable to create file. {0}
fileutil.writeError=Unable to write to file. {0}
#Playlist strings
playlist.empty=There are no songs in this playlist.
playlist.embedTooLarge=The playlist is too large for a discord message. Please follow the link in the title to the full list on Pastebin.com.
playlist.loadTrack.log=Added {0} to playlist [{1}].
playlist.loadTrack.error=Unable to add {0} to the playlist [{1}].
playlist.save.error=Unable to make directory: {0}
playlist.save.error.fileNotFound=Unable to find file to write playlist: {0}
playlist.load.IOException=IOException while loading playlist [{0}]. {1}
playlist.load.error.exists=The playlist [{0}] does not exist.
commands.youtube.footerInstruction=Please add a reaction to select a song, or cancel. Choice times out in 30 seconds.