diff --git a/src/main/java/musicplayer/LibraryCallbackInterface.java b/src/main/java/musicplayer/LibraryCallbackInterface.java new file mode 100644 index 0000000..d5cbaaf --- /dev/null +++ b/src/main/java/musicplayer/LibraryCallbackInterface.java @@ -0,0 +1,6 @@ +package musicplayer; + +public interface LibraryCallbackInterface { + + void libraryUpdated(boolean successful); +} diff --git a/src/main/java/musicplayer/Application.java b/src/main/java/musicplayer/LibraryUtils.java similarity index 52% rename from src/main/java/musicplayer/Application.java rename to src/main/java/musicplayer/LibraryUtils.java index 1fc3ae9..a9ec3a0 100644 --- a/src/main/java/musicplayer/Application.java +++ b/src/main/java/musicplayer/LibraryUtils.java @@ -1,9 +1,7 @@ package musicplayer; -import musicplayer.db.DatabaseManager; import musicplayer.db.Gateway; import musicplayer.model.ExtractedMetadata; -import musicplayer.model.Song; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; @@ -11,52 +9,15 @@ import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagException; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; -import java.util.List; import java.util.Optional; - -public class Application { +public final class LibraryUtils { static final String musicFileExtensionRegex = ".*\\.(mp3|mp4|flac)"; - public Application() { - DatabaseManager.init(); - List songs = Gateway.listAllSongs().get(); - boolean running = true; - BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); - Player player = new Player(null); - while (running) { - try { - System.out.println("Ready to read"); - String input = br.readLine(); - System.out.println(input); - switch (input) { - case "play": - player.playSong(songs.get(0)); - break; - case "stop": - player.stop(); - break; - case "pause": - player.pause(); - break; - case "resume": - player.resume(); - break; - case "quit": - running = false; - } - } catch (IOException e) { - e.printStackTrace(); - } - } - } - /** * Walk through all files and directories recursively and index any music files with a correct extension * @@ -66,7 +27,7 @@ public class Application { try { Files.walk(rootDirectory) .filter(f -> f.toString().matches(musicFileExtensionRegex)) - .map(Application::autoParse).filter(Optional::isPresent).map(Optional::get).forEach(Gateway::addSong); + .map(LibraryUtils::autoParse).filter(Optional::isPresent).map(Optional::get).forEach(Gateway::addSong); } catch (IOException e) { e.printStackTrace(); } @@ -78,7 +39,7 @@ public class Application { * @param targetFile Path to file to extract metadata from. * @return Metadata contained in targetFile. */ - public static Optional autoParse(Path targetFile) { + private static Optional autoParse(Path targetFile) { Tag audioTags = null; try { audioTags = AudioFileIO.read(targetFile.toFile()).getTag(); diff --git a/src/main/java/musicplayer/Player.java b/src/main/java/musicplayer/Player.java index 5cbd9b8..91843db 100644 --- a/src/main/java/musicplayer/Player.java +++ b/src/main/java/musicplayer/Player.java @@ -101,6 +101,21 @@ public class Player { return playBin.isPlaying() ? (int) (playBin.getClock().getTime().toSeconds() - playBin.getBaseTime().toSeconds()) : 0; } + /** + * Set the player volume. + * @param volume New volume in percent. + */ + public void setVolume(int volume){ + playBin.setVolumePercent(volume); + } + + /** + * @return Current Player volume in percent. + */ + public int getVolume(){ + return playBin.getVolumePercent(); + } + private class InternalThread implements Runnable { @Override diff --git a/src/main/java/musicplayer/PlayerGUI.form b/src/main/java/musicplayer/PlayerGUI.form index 71bbcf9..693a682 100644 --- a/src/main/java/musicplayer/PlayerGUI.form +++ b/src/main/java/musicplayer/PlayerGUI.form @@ -1,6 +1,6 @@
- + @@ -10,7 +10,7 @@ - + @@ -28,7 +28,10 @@ - + + + + @@ -51,7 +54,7 @@ - + @@ -64,7 +67,7 @@ - + @@ -91,8 +94,23 @@ + + + + + + + + + + + + + + + diff --git a/src/main/java/musicplayer/PlayerGUI.java b/src/main/java/musicplayer/PlayerGUI.java index 1f733dd..8e7b335 100644 --- a/src/main/java/musicplayer/PlayerGUI.java +++ b/src/main/java/musicplayer/PlayerGUI.java @@ -12,7 +12,7 @@ import javax.swing.tree.TreeNode; import java.awt.event.*; import java.util.*; -public class PlayerGUI implements PlayerCallbackInterface{ +public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterface{ private JTree libraryView; private JTable playList; private JPanel mainPanel; @@ -20,6 +20,8 @@ public class PlayerGUI implements PlayerCallbackInterface{ private JButton stopButton; private JButton nextButton; private JSlider seekBar; + private JSlider volumeSlider; + private JMenuBar menuBar; private Player player = new Player(this); private PlaylistTableModel playlistTableModel = new PlaylistTableModel(new ArrayList<>()); @@ -35,23 +37,12 @@ public class PlayerGUI implements PlayerCallbackInterface{ public PlayerGUI() { DatabaseManager.init(); - populateLibrary(new TreeMap<>(Gateway.listAllSongsGroupedByAlbum().get())); 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()); - + resetTree(); + volumeSlider.setValue(player.getVolume()); Thread seekBarUpdater = new Thread(() -> { boolean running = true; while (running) { @@ -64,6 +55,20 @@ public class PlayerGUI implements PlayerCallbackInterface{ } }); seekBarUpdater.start(); + + //Action Listeners + playButton.addActionListener(e -> { + if (playList.getSelectedColumn() == -1) { + player.playSong(playlistTableModel.getFirst().get()); + } + }); + MouseListener mouseListener = new libraryMouseAdapter(); + libraryView.addMouseListener(mouseListener); + stopButton.addActionListener(e -> player.stop()); + nextButton.addActionListener(e -> playNextSong()); + volumeSlider.addChangeListener(e -> player.setVolume(((JSlider)e.getSource()).getValue())); + + populateMenuBar(); } /** @@ -167,6 +172,23 @@ public class PlayerGUI implements PlayerCallbackInterface{ SwingUtilities.invokeLater(() -> seekBar.setMaximum(seconds)); } + public void refreshLibrary(){ + DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) libraryView.getModel().getRoot(); + DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("Refreshing Library..."); + addNodeToTreeModel(parentNode, newNode); + Thread populateThread = new Thread(() -> { + TreeMap treeMap = new TreeMap<>(Gateway.listAllSongsGroupedByAlbum().get()); + SwingUtilities.invokeLater(() -> populateLibrary(treeMap)); + }); + populateThread.start(); + } + + @Override + public void libraryUpdated(boolean successful) { + if(successful) + populateLibrary(new TreeMap<>(Gateway.listAllSongsGroupedByAlbum().get())); + } + private class libraryMouseAdapter extends MouseAdapter { @Override public void mousePressed(MouseEvent e) { @@ -187,4 +209,25 @@ public class PlayerGUI implements PlayerCallbackInterface{ } catch (NullPointerException ignored) {} } } + + /** + * Populate the top menu bar with items. + */ + private void populateMenuBar(){ + + // Tools menu + JMenu tools = new JMenu("Tools"); + JMenuItem menuItem = new JMenuItem("Refresh Library"); + menuItem.addActionListener(e -> refreshLibrary()); + tools.add(menuItem); + + menuItem = new JMenuItem("Update Library"); + menuItem.setToolTipText("Reindex and refresh library."); + + tools.add(menuItem); + + // Add everything to the menu bar itself + menuBar.add(tools); + + } } diff --git a/src/main/java/musicplayer/PlaylistTableModel.java b/src/main/java/musicplayer/PlaylistTableModel.java index 359d177..561a9c9 100644 --- a/src/main/java/musicplayer/PlaylistTableModel.java +++ b/src/main/java/musicplayer/PlaylistTableModel.java @@ -55,7 +55,6 @@ public class PlaylistTableModel extends AbstractTableModel { } public void addSong(Song song){ - System.out.println("Adding " + song.toString()); songList.add(song); fireTableDataChanged(); } diff --git a/src/main/java/musicplayer/model/ExtractedMetadata.java b/src/main/java/musicplayer/model/ExtractedMetadata.java index af4e48b..bb0e5c4 100644 --- a/src/main/java/musicplayer/model/ExtractedMetadata.java +++ b/src/main/java/musicplayer/model/ExtractedMetadata.java @@ -22,6 +22,7 @@ public class ExtractedMetadata { public final String songFile; public final String trackNumber; public final byte[] artwork; + public final String discNumber; private static final String albumArtRegex = ".*(Cover|Folder|cover|folder)\\.(jpg|png)"; @@ -35,6 +36,7 @@ public class ExtractedMetadata { this.album = audioTags.getFirst(FieldKey.ALBUM); this.artist = audioTags.getFirst(FieldKey.ARTIST); this.genre = audioTags.getFirst(FieldKey.GENRE); + this.discNumber = audioTags.getFirst(FieldKey.DISC_NO); this.songFile = songFile.getAbsolutePath(); byte[] tmpArt = null; try { @@ -54,16 +56,25 @@ public class ExtractedMetadata { artwork = tmpArt; } + /** + * Convert an Image into its' byte array representation. + * @param image Image to convert. + * @return image as byte[]. + */ private static byte[] convertImageToBytes(Image image){ int imageScaleToSize = 50; try (ByteArrayOutputStream baos = new ByteArrayOutputStream()){ ImageIO.write(convertToBufferedImage(image.getScaledInstance(imageScaleToSize, imageScaleToSize, Image.SCALE_SMOOTH)), "jpg", baos); baos.flush(); return baos.toByteArray(); - } catch (IOException ignored) {} - return null; + } catch (IOException e) { return null; } } + /** + * Convert an Image to a BufferedImage. + * @param image Source image. + * @return image as BufferedImage. + */ private static BufferedImage convertToBufferedImage(Image image) { BufferedImage newImage = new BufferedImage( image.getWidth(null), image.getHeight(null),