Added functionality to add from library to playlist and play (currently automatic) songs.
This commit is contained in:
parent
6344e9dbe9
commit
de860fad1f
@ -29,7 +29,7 @@ public class Application {
|
||||
List<Song> 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();
|
||||
|
@ -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
|
||||
|
10
src/main/java/musicplayer/PlayerCallbackInterface.java
Normal file
10
src/main/java/musicplayer/PlayerCallbackInterface.java
Normal file
@ -0,0 +1,10 @@
|
||||
package musicplayer;
|
||||
|
||||
import musicplayer.model.Song;
|
||||
|
||||
public interface PlayerCallbackInterface {
|
||||
|
||||
Song getNextSong(Song currentSong);
|
||||
|
||||
void setSongHighlighting(Song playingSong);
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="musicplayer.PlayerGUI">
|
||||
<grid id="27dc6" binding="mainPanel" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<grid id="27dc6" binding="mainPanel" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="20" y="20" width="500" height="400"/>
|
||||
@ -10,7 +10,7 @@
|
||||
<children>
|
||||
<scrollpane id="2b209">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
<grid row="0" column="0" row-span="2" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
@ -28,12 +28,45 @@
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="b8fb" class="javax.swing.JList" binding="list1" default-binding="true">
|
||||
<component id="c10f" class="javax.swing.JTable" binding="playList">
|
||||
<constraints/>
|
||||
<properties/>
|
||||
<properties>
|
||||
<rowSelectionAllowed value="true"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</scrollpane>
|
||||
<toolbar id="56df">
|
||||
<constraints>
|
||||
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="-1" height="20"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="a01e9" class="javax.swing.JButton" binding="playButton">
|
||||
<constraints/>
|
||||
<properties>
|
||||
<label value="Play"/>
|
||||
<text value="&Play"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="c0e85" class="javax.swing.JButton" binding="stopButton" default-binding="true">
|
||||
<constraints/>
|
||||
<properties>
|
||||
<label value="Stop"/>
|
||||
<text value="&Stop"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="5cfc3" class="javax.swing.JButton" binding="nextButton">
|
||||
<constraints/>
|
||||
<properties>
|
||||
<text value="&Next"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</toolbar>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
|
@ -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) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
76
src/main/java/musicplayer/PlaylistTableModel.java
Normal file
76
src/main/java/musicplayer/PlaylistTableModel.java
Normal file
@ -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<Song> songList;
|
||||
|
||||
public PlaylistTableModel(List<Song> 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<Song> getFirst(){
|
||||
return songList.size() > 0 ? Optional.of(songList.get(0)) : Optional.<Song>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);
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ public class Album implements Comparable<Album> {
|
||||
@Column(name = "name")
|
||||
private String name;
|
||||
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "album")
|
||||
@OrderBy("trackNumber ASC")
|
||||
private Set<Song> songs;
|
||||
@Lob
|
||||
@Column(name = "art", nullable = true, length = 10000)
|
||||
|
@ -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);
|
||||
|
@ -30,13 +30,15 @@ public class Song implements Comparable<Song> {
|
||||
@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 = (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<Song> {
|
||||
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<Song> {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -20,5 +20,8 @@
|
||||
<property name="hibernate.hbm2ddl.auto">
|
||||
update
|
||||
</property>
|
||||
<property name="hibernate.enable_lazy_load_no_trans">
|
||||
true
|
||||
</property>
|
||||
</session-factory>
|
||||
</hibernate-configuration>
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user