From 4ffca843b4ac92ce5591c9bc52998db6564db1df Mon Sep 17 00:00:00 2001 From: Nathan Cannon Date: Fri, 25 Mar 2016 03:40:16 +0000 Subject: [PATCH] Moved LibraryUtils to default implementations in ILibrary. --- .../callbacks/LibraryCallbackInterface.java | 8 +- .../java/musicplayer/library/ILibrary.java | 57 +++++++++++++ .../musicplayer/library/JTreeLibrary.java | 11 ++- .../java/musicplayer/util/LibraryUtils.java | 75 ------------------ .../java/musicplayer/util/PlaylistUtils.java | 3 +- .../musicplayer/library/ILibraryTest.java | 79 +++++++++++++++++++ .../player/GStreamerPlayerTest.java | 4 +- 7 files changed, 154 insertions(+), 83 deletions(-) delete mode 100644 src/main/java/musicplayer/util/LibraryUtils.java create mode 100644 src/test/java/musicplayer/library/ILibraryTest.java diff --git a/src/main/java/musicplayer/callbacks/LibraryCallbackInterface.java b/src/main/java/musicplayer/callbacks/LibraryCallbackInterface.java index 5a723eb..2a02e03 100644 --- a/src/main/java/musicplayer/callbacks/LibraryCallbackInterface.java +++ b/src/main/java/musicplayer/callbacks/LibraryCallbackInterface.java @@ -4,9 +4,13 @@ public interface LibraryCallbackInterface { /** * Call this after performing library updates so the front-end knows that updating has completed. - * @param successful Was the update function successful. + * @param message Error message. */ - void libraryUpdated(boolean successful); + void libraryUpdated(String message); + /** + * Call this after performing library updates so the front-end knows that updating has completed. + */ + void libraryUpdated(); /** * Update the current display with the file/folder currently being parsed. diff --git a/src/main/java/musicplayer/library/ILibrary.java b/src/main/java/musicplayer/library/ILibrary.java index 1af778d..68cf167 100644 --- a/src/main/java/musicplayer/library/ILibrary.java +++ b/src/main/java/musicplayer/library/ILibrary.java @@ -1,10 +1,67 @@ package musicplayer.library; +import musicplayer.callbacks.LibraryCallbackInterface; +import musicplayer.db.IDatabase; +import musicplayer.model.ExtractedMetadata; import musicplayer.model.HasSongs; +import org.jaudiotagger.audio.AudioFileIO; +import org.jaudiotagger.audio.exceptions.CannotReadException; +import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; +import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; +import org.jaudiotagger.tag.Tag; +import org.jaudiotagger.tag.TagException; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; public interface ILibrary { void showSongs(); > void showGroupedSongs(Class grouping); void updateLibrary(); void refreshLibrary(); + + String musicFileExtensionRegex = "(?iu).*\\.(mp3|mp4|flac|ogg)"; + + /** + * Add all songs contained with all paths in rootDirectory to the database. + * @param rootDirectory Folder(s) containing music files to index. + * @param callbackInterface Object to send callback data to, set to null if the application doesn't require update data. + */ + static void processSongsWithCallback(IDatabase database, List rootDirectory, LibraryCallbackInterface callbackInterface){ + boolean callbacksEnabled = callbackInterface != null; + rootDirectory.forEach(dir -> { + try { + Files.walk(dir) + .filter(f -> f.toString().matches(musicFileExtensionRegex)).map(ILibrary::autoParse) + .forEach(x -> x.ifPresent(i -> { + database.addSong(i); + if (callbacksEnabled) + callbackInterface.currentlyUpdating(i.toString()); + })); + } catch (IOException e) { + if(callbacksEnabled) + callbackInterface.libraryUpdated(e.getMessage()); + } + }); + if(callbacksEnabled) + callbackInterface.libraryUpdated(); + } + + /** + * Extract music metadata from the target file. + * + * @param targetFile Path to file to extract metadata from. + * @return Metadata contained in targetFile. + */ + static Optional autoParse(Path targetFile) { + Tag audioTags = null; + try { + audioTags = AudioFileIO.read(targetFile.toFile()).getTag(); + } catch (CannotReadException | IOException | ReadOnlyFileException | TagException | InvalidAudioFrameException ignored) { + } + return audioTags == null ? Optional.empty() : Optional.of(new ExtractedMetadata(audioTags, targetFile.toFile())); + } } diff --git a/src/main/java/musicplayer/library/JTreeLibrary.java b/src/main/java/musicplayer/library/JTreeLibrary.java index 34b653e..44e5052 100644 --- a/src/main/java/musicplayer/library/JTreeLibrary.java +++ b/src/main/java/musicplayer/library/JTreeLibrary.java @@ -9,7 +9,6 @@ import musicplayer.model.Artist; import musicplayer.model.HasSongs; import musicplayer.model.Song; import musicplayer.playlist.IPlaylist; -import musicplayer.util.LibraryUtils; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; @@ -137,7 +136,8 @@ public class JTreeLibrary extends JPanel implements ILibrary, LibraryCallbackInt addNodeToTreeModel(model, parentNode, updatingNode); libraryTree.setModel(model); List dirs = ConfigManager.getLibraryDirectories().stream().map(File::toPath).collect(Collectors.toList()); - LibraryUtils.processSongsWithCallback(database, dirs, this); + Thread updaterThread = new Thread(() -> ILibrary.processSongsWithCallback(database, dirs, this), "updater"); + updaterThread.start(); } } @@ -165,7 +165,12 @@ public class JTreeLibrary extends JPanel implements ILibrary, LibraryCallbackInt } @Override - public void libraryUpdated(boolean successful) { + public void libraryUpdated(String message) { + JOptionPane.showMessageDialog(this, message, "Update Error", JOptionPane.ERROR_MESSAGE); + libraryUpdated(); + } + + public void libraryUpdated() { libraryUpdating.set(false); refreshLibrary(); } diff --git a/src/main/java/musicplayer/util/LibraryUtils.java b/src/main/java/musicplayer/util/LibraryUtils.java deleted file mode 100644 index 72eaffe..0000000 --- a/src/main/java/musicplayer/util/LibraryUtils.java +++ /dev/null @@ -1,75 +0,0 @@ -package musicplayer.util; - -import musicplayer.callbacks.LibraryCallbackInterface; -import musicplayer.db.IDatabase; -import musicplayer.model.ExtractedMetadata; -import org.jaudiotagger.audio.AudioFileIO; -import org.jaudiotagger.audio.exceptions.CannotReadException; -import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; -import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; -import org.jaudiotagger.tag.Tag; -import org.jaudiotagger.tag.TagException; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.Optional; - -public final class LibraryUtils { - - private static final String musicFileExtensionRegex = "(?iu).*\\.(mp3|mp4|flac|ogg)"; - private static Thread updaterThread; - - /** - * Add all songs contained with all paths in rootDirectory to the database. - * @param rootDirectory Folder(s) containing music files to index. - * @param callbackInterface Object to send callback data to, set to null if the application doesn't require update data. - */ - public static void processSongsWithCallback(IDatabase database, List rootDirectory, LibraryCallbackInterface callbackInterface){ - boolean callbacksEnabled = callbackInterface != null; - updaterThread = new Thread(() -> { - rootDirectory.forEach(dir -> { - try { - Files.walk(dir) - .filter(f -> f.toString().matches(musicFileExtensionRegex)).map(LibraryUtils::autoParse) - .forEach(x -> x.ifPresent(i -> { - database.addSong(i); - if (callbacksEnabled) - callbackInterface.currentlyUpdating(i.toString()); - })); - } catch (IOException e) { - if(callbacksEnabled) - callbackInterface.libraryUpdated(false); - } - }); - if(callbacksEnabled) - callbackInterface.libraryUpdated(true); - }, "libraryUpdater"); - updaterThread.start(); - } - - /** - * Halt execution of the library updater thread (if running) - */ - public static void cancelProcessing(){ - if(updaterThread.isAlive()) - updaterThread.interrupt(); - } - - /** - * Extract music metadata from the target file. - * - * @param targetFile Path to file to extract metadata from. - * @return Metadata contained in targetFile. - */ - public static Optional autoParse(Path targetFile) { - Tag audioTags = null; - try { - audioTags = AudioFileIO.read(targetFile.toFile()).getTag(); - } catch (CannotReadException | IOException | ReadOnlyFileException | TagException | InvalidAudioFrameException e) { - e.printStackTrace(); - } - return audioTags == null ? Optional.empty() : Optional.of(new ExtractedMetadata(audioTags, targetFile.toFile())); - } -} diff --git a/src/main/java/musicplayer/util/PlaylistUtils.java b/src/main/java/musicplayer/util/PlaylistUtils.java index 624094f..95c7a42 100644 --- a/src/main/java/musicplayer/util/PlaylistUtils.java +++ b/src/main/java/musicplayer/util/PlaylistUtils.java @@ -1,5 +1,6 @@ package musicplayer.util; +import musicplayer.library.ILibrary; import musicplayer.model.Album; import musicplayer.model.Artist; import musicplayer.model.Song; @@ -51,7 +52,7 @@ public final class PlaylistUtils { songPaths.set(i, Paths.get(targetFile.getParent(), songPaths.get(i).toString())); } } - songPaths.stream().map(LibraryUtils::autoParse).filter(Optional::isPresent).map(Optional::get) + songPaths.stream().map(ILibrary::autoParse).filter(Optional::isPresent).map(Optional::get) .forEach(x -> result.add(new Song(x.getTrackNumber(), x.getDiscNumber(), x.getTitle(), new Artist(x.getArtist()), new Album(x.getAlbum()), x.getGenre(), x.getSongFile()))); } } catch (IOException ignored) { } diff --git a/src/test/java/musicplayer/library/ILibraryTest.java b/src/test/java/musicplayer/library/ILibraryTest.java new file mode 100644 index 0000000..637fcdf --- /dev/null +++ b/src/test/java/musicplayer/library/ILibraryTest.java @@ -0,0 +1,79 @@ +package musicplayer.library; + +import musicplayer.callbacks.LibraryCallbackInterface; +import musicplayer.db.HibernateDatabase; +import musicplayer.db.IDatabase; +import musicplayer.model.ExtractedMetadata; +import musicplayer.model.Song; +import org.jaudiotagger.audio.AudioFileIO; +import org.jaudiotagger.tag.FieldKey; +import org.jaudiotagger.tag.Tag; +import org.junit.Test; + +import java.io.File; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.junit.Assert.*; + +public class ILibraryTest { + + @Test + public void testAutoParse() throws Exception { + File inputFile = new File(ILibraryTest.class.getResource("/sample.mp3").getFile()); + Optional data = ILibrary.autoParse(inputFile.toPath()); + Tag audioTags = AudioFileIO.read(inputFile).getTag(); + assertTrue(data.isPresent()); + ExtractedMetadata internal = data.get(); + assertEquals(audioTags.getFirst(FieldKey.ARTIST), internal.getArtist()); + assertEquals(audioTags.getFirst(FieldKey.GENRE), internal.getGenre()); + assertEquals(audioTags.getFirst(FieldKey.TITLE), internal.getTitle()); + assertEquals(audioTags.getFirst(FieldKey.ALBUM), internal.getAlbum()); + assertEquals(audioTags.getFirst(FieldKey.TRACK), internal.getTrackNumber()); + assertEquals(audioTags.getFirst(FieldKey.DISC_NO), internal.getDiscNumber()); + assertEquals(inputFile.getPath(), internal.getSongFile()); + } + + @Test + public void testAutoParseInvalidFile() throws Exception { + File inputFile = new File(""); + Optional data = ILibrary.autoParse(inputFile.toPath()); + assertFalse(data.isPresent()); + } + + @Test + public void testProcessSongsWithCallback() throws Exception { + CallbackInterface callbackInterface = new CallbackInterface(); + Path dir = new File(ILibraryTest.class.getResource("/sample.mp3").getFile()).getParentFile().toPath(); + List dirList = new ArrayList<>(); + dirList.add(dir); + IDatabase database = new HibernateDatabase(true); + ILibrary.processSongsWithCallback(database, dirList, callbackInterface); + assertEquals(1, database.listAllT(Song.class).get().size()); + assertTrue(callbackInterface.status); + assertFalse(callbackInterface.error); + } + + private class CallbackInterface implements LibraryCallbackInterface{ + public boolean status = false; + public String update = ""; + public boolean error = false; + + @Override + public void libraryUpdated(String message) { + error = true; + } + + @Override + public void libraryUpdated() { + status = true; + } + + @Override + public void currentlyUpdating(String name) { + update = name; + } + } +} \ No newline at end of file diff --git a/src/test/java/musicplayer/player/GStreamerPlayerTest.java b/src/test/java/musicplayer/player/GStreamerPlayerTest.java index 396c433..e61fb5b 100644 --- a/src/test/java/musicplayer/player/GStreamerPlayerTest.java +++ b/src/test/java/musicplayer/player/GStreamerPlayerTest.java @@ -1,9 +1,9 @@ package musicplayer.player; +import musicplayer.library.ILibrary; import musicplayer.model.Song; import musicplayer.playlist.IPlaylist; import musicplayer.playlist.JTablePlaylist; -import musicplayer.util.LibraryUtils; import org.junit.Before; import org.junit.Test; @@ -16,7 +16,7 @@ public class GStreamerPlayerTest { GStreamerPlayer player; IPlaylist playlist; - Song sampleSong = new Song(LibraryUtils.autoParse( + Song sampleSong = new Song(ILibrary.autoParse( new File(GStreamerPlayerTest.class.getResource("/sample.mp3").getFile()).toPath()).get()); @Before