From de860fad1f0b4436bc2c5d79ffabeead6b22c944 Mon Sep 17 00:00:00 2001 From: Nathan Cannon Date: Thu, 11 Feb 2016 04:54:36 +0000 Subject: [PATCH] Added functionality to add from library to playlist and play (currently automatic) songs. --- src/main/java/musicplayer/Application.java | 4 +- src/main/java/musicplayer/Player.java | 27 ++++++- .../musicplayer/PlayerCallbackInterface.java | 10 +++ src/main/java/musicplayer/PlayerGUI.form | 41 +++++++++- src/main/java/musicplayer/PlayerGUI.java | 67 ++++++++++++++-- .../java/musicplayer/PlaylistTableModel.java | 76 +++++++++++++++++++ src/main/java/musicplayer/model/Album.java | 1 + .../musicplayer/model/ExtractedMetadata.java | 4 +- src/main/java/musicplayer/model/Song.java | 16 ++-- src/main/resources/hibernate.cfg.xml | 3 + src/test/java/musicplayer/db/GatewayTest.java | 6 +- 11 files changed, 228 insertions(+), 27 deletions(-) create mode 100644 src/main/java/musicplayer/PlayerCallbackInterface.java create mode 100644 src/main/java/musicplayer/PlaylistTableModel.java diff --git a/src/main/java/musicplayer/Application.java b/src/main/java/musicplayer/Application.java index cac2211..1fc3ae9 100644 --- a/src/main/java/musicplayer/Application.java +++ b/src/main/java/musicplayer/Application.java @@ -29,7 +29,7 @@ public class Application { List songs = Gateway.listAllSongs().get(); boolean running = true; BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); - Player player = new Player(); + Player player = new Player(null); while (running) { try { System.out.println("Ready to read"); @@ -37,7 +37,7 @@ public class Application { System.out.println(input); switch (input) { case "play": - player.playSong(songs.get(0).getSongFile()); + player.playSong(songs.get(0)); break; case "stop": player.stop(); diff --git a/src/main/java/musicplayer/Player.java b/src/main/java/musicplayer/Player.java index 3c0b9e2..bf13311 100644 --- a/src/main/java/musicplayer/Player.java +++ b/src/main/java/musicplayer/Player.java @@ -1,5 +1,6 @@ package musicplayer; +import musicplayer.model.Song; import org.gstreamer.ElementFactory; import org.gstreamer.Gst; import org.gstreamer.State; @@ -13,14 +14,32 @@ public class Player { private InternalThread internalThread; private Thread thread; + private Song currentSong; + private PlayerCallbackInterface callbackInterface; - public Player() { + public Player(PlayerCallbackInterface callbackInterface) { + this.callbackInterface = callbackInterface; Gst.init(); playBin = new PlayBin2("BusMessages"); playBin.setVideoSink(ElementFactory.make("fakesink", "videosink")); + + playBin.connect((PlayBin2.ABOUT_TO_FINISH) playBin2 -> { + Thread callbackThing = new Thread(() -> { + try { + Thread.sleep(1500); // Song is about to finish, wait so we don't cut it off early. + } catch (InterruptedException e) { + e.printStackTrace(); + } + playSong(callbackInterface.getNextSong(currentSong)); + }); + callbackThing.start(); + }); } - public void playSong(File songFile) { + public void playSong(Song song) { + callbackInterface.setSongHighlighting(song); + currentSong = song; + File songFile = song.getSongFile(); if (playBin.getState() == State.PLAYING) stop(); playBin.setURI(songFile.toURI()); @@ -47,6 +66,10 @@ public class Player { playBin.pause(); } + public Song getCurrentSong(){ + return currentSong; + } + private class InternalThread implements Runnable { @Override diff --git a/src/main/java/musicplayer/PlayerCallbackInterface.java b/src/main/java/musicplayer/PlayerCallbackInterface.java new file mode 100644 index 0000000..28c7da4 --- /dev/null +++ b/src/main/java/musicplayer/PlayerCallbackInterface.java @@ -0,0 +1,10 @@ +package musicplayer; + +import musicplayer.model.Song; + +public interface PlayerCallbackInterface { + + Song getNextSong(Song currentSong); + + void setSongHighlighting(Song playingSong); +} diff --git a/src/main/java/musicplayer/PlayerGUI.form b/src/main/java/musicplayer/PlayerGUI.form index d1ec8f2..1909841 100644 --- a/src/main/java/musicplayer/PlayerGUI.form +++ b/src/main/java/musicplayer/PlayerGUI.form @@ -1,6 +1,6 @@
- + @@ -10,7 +10,7 @@ - + @@ -28,12 +28,45 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/musicplayer/PlayerGUI.java b/src/main/java/musicplayer/PlayerGUI.java index 656d4e9..b250ee3 100644 --- a/src/main/java/musicplayer/PlayerGUI.java +++ b/src/main/java/musicplayer/PlayerGUI.java @@ -9,15 +9,18 @@ import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeNode; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.TreeSet; +import java.awt.event.*; +import java.util.*; -public class PlayerGUI { +public class PlayerGUI implements PlayerCallbackInterface{ private JTree libraryView; - private JList list1; + private JTable playList; private JPanel mainPanel; + private JButton playButton; + private JButton stopButton; + private JButton nextButton; + private Player player = new Player(this); + private PlaylistTableModel playlistTableModel = new PlaylistTableModel(new ArrayList<>()); public static void main(String[] args) { @@ -35,6 +38,18 @@ public class PlayerGUI { libraryView.setRootVisible(false); libraryView.setToggleClickCount(1); libraryView.setCellRenderer(new LibraryTreeCellRenderer()); + + MouseListener mouseListener = new libraryMouseAdapter(); + + libraryView.addMouseListener(mouseListener); + playList.setModel(playlistTableModel); + playButton.addActionListener(e -> { + if (playList.getSelectedColumn() == -1) { + player.playSong(playlistTableModel.getFirst().get()); + } + }); + stopButton.addActionListener(e -> player.stop()); + nextButton.addActionListener(e -> playNextSong()); } private void resetTree() { @@ -69,4 +84,44 @@ public class PlayerGUI { } } + private void addToPlaylist(Song song){ + playlistTableModel.addSong(song); + playList.revalidate(); + } + + @Override + public Song getNextSong(Song currentSong) { + return playlistTableModel.nextSong(currentSong); + } + + @Override + public void setSongHighlighting(Song playingSong) { + int index = playlistTableModel.getSongIndex(playingSong); + playList.setRowSelectionInterval(index, index); + } + + public void playNextSong(){ + player.playSong(getNextSong(player.getCurrentSong())); + } + + private class libraryMouseAdapter extends MouseAdapter { + @Override + public void mousePressed(MouseEvent e) { + int selRow = libraryView.getRowForLocation(e.getX(), e.getY()); + try { + Object selectedItem = ((DefaultMutableTreeNode) libraryView.getPathForLocation(e.getX(), e.getY()).getLastPathComponent()).getUserObject(); + if (selRow != -1) { + if (e.getClickCount() == 2) { + if (selectedItem != null) { + if (selectedItem instanceof Song) { + addToPlaylist((Song) selectedItem); + } else if (selectedItem instanceof Album) { + ((Album) selectedItem).getSongs().forEach(PlayerGUI.this::addToPlaylist); + } + } + } + } + } catch (NullPointerException ignored) {} + } + } } diff --git a/src/main/java/musicplayer/PlaylistTableModel.java b/src/main/java/musicplayer/PlaylistTableModel.java new file mode 100644 index 0000000..9495ec4 --- /dev/null +++ b/src/main/java/musicplayer/PlaylistTableModel.java @@ -0,0 +1,76 @@ +package musicplayer; + +import musicplayer.model.Song; + +import javax.swing.table.AbstractTableModel; +import java.util.List; +import java.util.Optional; + +public class PlaylistTableModel extends AbstractTableModel { + + private List songList; + + public PlaylistTableModel(List songList){ + this.songList = songList; + } + + @Override + public int getRowCount() { + return songList.size(); + } + + @Override + public int getColumnCount() { + return 4; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + Object o = "?"; + Song song = songList.get(rowIndex); + switch (columnIndex){ + case 0: o = song.getTrackNumber(); break; + case 1: o = song.getTitle(); break; + case 2: o = song.getArtist(); break; + case 3: o = song.getAlbum(); break; + } + return o; + } + + @Override + public Class getColumnClass(int columnIndex) { + return Song.class; + } + + @Override + public String getColumnName(int column) { + String name = ""; + switch (column){ + case 0: name = "Track"; break; + case 1: name = "Title"; break; + case 2: name = "Artist"; break; + case 3: name = "Album"; break; + } + return name; + } + + public void addSong(Song song){ + System.out.println("Adding " + song.toString()); + songList.add(song); + fireTableDataChanged(); + } + + public Optional getFirst(){ + return songList.size() > 0 ? Optional.of(songList.get(0)) : Optional.empty(); + } + + public Song nextSong(Song song){ + int index = songList.indexOf(song) + 1; + if(index >= songList.size()) index = 0; + return songList.get(index); + } + + public int getSongIndex(Song song){ + return songList.indexOf(song); + } +} diff --git a/src/main/java/musicplayer/model/Album.java b/src/main/java/musicplayer/model/Album.java index 51c1705..a88f13a 100644 --- a/src/main/java/musicplayer/model/Album.java +++ b/src/main/java/musicplayer/model/Album.java @@ -19,6 +19,7 @@ public class Album implements Comparable { @Column(name = "name") private String name; @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "album") + @OrderBy("trackNumber ASC") private Set songs; @Lob @Column(name = "art", nullable = true, length = 10000) diff --git a/src/main/java/musicplayer/model/ExtractedMetadata.java b/src/main/java/musicplayer/model/ExtractedMetadata.java index 95c6ade..af4e48b 100644 --- a/src/main/java/musicplayer/model/ExtractedMetadata.java +++ b/src/main/java/musicplayer/model/ExtractedMetadata.java @@ -23,7 +23,7 @@ public class ExtractedMetadata { public final String trackNumber; public final byte[] artwork; - static final String albumArtRegex = ".*(Cover|Folder|cover|folder)\\.(jpg|png)"; + private static final String albumArtRegex = ".*(Cover|Folder|cover|folder)\\.(jpg|png)"; /** * @param audioTags jaudiotagger tag data. @@ -64,7 +64,7 @@ public class ExtractedMetadata { return null; } - public static BufferedImage convertToBufferedImage(Image image) { + private static BufferedImage convertToBufferedImage(Image image) { BufferedImage newImage = new BufferedImage( image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB); diff --git a/src/main/java/musicplayer/model/Song.java b/src/main/java/musicplayer/model/Song.java index f84af65..b6b4344 100644 --- a/src/main/java/musicplayer/model/Song.java +++ b/src/main/java/musicplayer/model/Song.java @@ -30,13 +30,15 @@ public class Song implements Comparable { @Column(name = "songFile") private String songFile; @Column(name = "trackNumber") - private String trackNumber; + private int trackNumber; protected Song() { } public Song(String trackNumber, String title, Artist artist, Album album, String genre, String songFile) { - this.trackNumber = trackNumber; + try { + this.trackNumber = Integer.parseInt(trackNumber); + } catch (NumberFormatException e){ this.trackNumber = 0; } this.title = title; this.artist = artist; this.genre = genre; @@ -58,7 +60,7 @@ public class Song implements Comparable { Song song = (Song) o; return id == song.id && artist.equals(song.artist) && genre.equals(song.genre) && title.equals(song.title) - && album.equals(song.album) && songFile.equals(song.songFile) && trackNumber.equals(song.trackNumber); + && album.equals(song.album) && songFile.equals(song.songFile) && trackNumber == song.trackNumber; } @@ -70,7 +72,7 @@ public class Song implements Comparable { result = 31 * result + title.hashCode(); result = 31 * result + album.hashCode(); result = 31 * result + songFile.hashCode(); - result = 31 * result + trackNumber.hashCode(); + result = 31 * result + trackNumber; return result; } @@ -112,14 +114,12 @@ public class Song implements Comparable { return new File(songFile); } - public String getTrackNumber() { + public Integer getTrackNumber() { return trackNumber; } @Override public int compareTo(Song o) { - if (trackNumber != null && o.getTrackNumber() != null && !trackNumber.isEmpty() && !o.getTrackNumber().isEmpty()) - return Integer.parseInt(getTrackNumber()) - Integer.parseInt(o.getTrackNumber()); - return (int) (id - o.getId()); + return trackNumber - o.getTrackNumber(); } } diff --git a/src/main/resources/hibernate.cfg.xml b/src/main/resources/hibernate.cfg.xml index 16f8bea..370c017 100644 --- a/src/main/resources/hibernate.cfg.xml +++ b/src/main/resources/hibernate.cfg.xml @@ -20,5 +20,8 @@ update + + true + \ No newline at end of file diff --git a/src/test/java/musicplayer/db/GatewayTest.java b/src/test/java/musicplayer/db/GatewayTest.java index 894400a..8bd8d0f 100644 --- a/src/test/java/musicplayer/db/GatewayTest.java +++ b/src/test/java/musicplayer/db/GatewayTest.java @@ -7,7 +7,7 @@ import musicplayer.model.Song; import org.hibernate.Session; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; -import org.jaudiotagger.tag.id3.ID3v1Tag; +import org.jaudiotagger.tag.id3.ID3v11Tag; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -120,7 +120,7 @@ public class GatewayTest { @Test public void testAddSong() throws Exception { - Tag tags = new ID3v1Tag(); + Tag tags = new ID3v11Tag(); tags.addField(FieldKey.ALBUM, "Test Album"); tags.addField(FieldKey.ARTIST, "Test Artist"); tags.addField(FieldKey.TRACK, "1"); @@ -131,7 +131,7 @@ public class GatewayTest { Song song = (Song)session.createCriteria(Song.class).uniqueResult(); assertEquals(song.getAlbum().getName(), metadata.album); assertEquals(song.getArtist().getName(), metadata.artist); - assertEquals(song.getTrackNumber(), metadata.trackNumber); + assertEquals(song.getTrackNumber(), Integer.valueOf(1)); assertEquals(song.getTitle(), metadata.title); assertEquals(song.getGenre(), metadata.genre); }