Added album art icons and caching.
This commit is contained in:
parent
a1515ee9ad
commit
1d860760d6
@ -11,8 +11,9 @@ import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
|
||||
import org.jaudiotagger.tag.Tag;
|
||||
import org.jaudiotagger.tag.TagException;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
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;
|
||||
@ -21,15 +22,15 @@ import java.util.Optional;
|
||||
|
||||
public class Application {
|
||||
|
||||
final String musicFileExtensionRegex = ".*\\.(mp3|mp4|flac)";
|
||||
static final String musicFileExtensionRegex = ".*\\.(mp3|mp4|flac)";
|
||||
|
||||
public Application(){
|
||||
public Application() {
|
||||
DatabaseManager.init();
|
||||
List<Song> songs = Gateway.listAllSongs().get();
|
||||
boolean running = true;
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
|
||||
Player player = new Player();
|
||||
while(running){
|
||||
while (running) {
|
||||
try {
|
||||
System.out.println("Ready to read");
|
||||
String input = br.readLine();
|
||||
@ -58,13 +59,14 @@ public class Application {
|
||||
|
||||
/**
|
||||
* Walk through all files and directories recursively and index any music files with a correct extension
|
||||
*
|
||||
* @param rootDirectory Directory from which to start searching
|
||||
*/
|
||||
public void processSongs(Path rootDirectory){
|
||||
public static void processSongs(Path rootDirectory) {
|
||||
try {
|
||||
Files.walk(rootDirectory)
|
||||
.filter(f -> f.toString().matches(musicFileExtensionRegex))
|
||||
.map(this::autoParse).filter(Optional::isPresent).map(Optional::get).forEach(Gateway::addSong);
|
||||
.map(Application::autoParse).filter(Optional::isPresent).map(Optional::get).forEach(Gateway::addSong);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -72,10 +74,11 @@ public class Application {
|
||||
|
||||
/**
|
||||
* Extract music metadata from the target file.
|
||||
*
|
||||
* @param targetFile Path to file to extract metadata from.
|
||||
* @return Metadata contained in targetFile.
|
||||
*/
|
||||
public Optional<ExtractedMetadata> autoParse(Path targetFile){
|
||||
public static Optional<ExtractedMetadata> autoParse(Path targetFile) {
|
||||
Tag audioTags = null;
|
||||
try {
|
||||
audioTags = AudioFileIO.read(targetFile.toFile()).getTag();
|
||||
|
34
src/main/java/musicplayer/LibraryTreeCellRenderer.java
Normal file
34
src/main/java/musicplayer/LibraryTreeCellRenderer.java
Normal file
@ -0,0 +1,34 @@
|
||||
package musicplayer;
|
||||
|
||||
import musicplayer.model.Album;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.TreeCellRenderer;
|
||||
import java.awt.*;
|
||||
|
||||
public class LibraryTreeCellRenderer implements TreeCellRenderer {
|
||||
|
||||
private JLabel label;
|
||||
|
||||
LibraryTreeCellRenderer() {
|
||||
label = new JLabel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
|
||||
Object o = ((DefaultMutableTreeNode) value).getUserObject();
|
||||
if (o instanceof Album) {
|
||||
Album album = (Album) o;
|
||||
if (album.getAlbumArt().isPresent())
|
||||
label.setIcon(new ImageIcon(album.getAlbumArt().get()));
|
||||
else {
|
||||
label.setIcon(null);
|
||||
}
|
||||
} else
|
||||
label.setIcon(null);
|
||||
if (o != null)
|
||||
label.setText(o.toString());
|
||||
return label;
|
||||
}
|
||||
}
|
@ -7,21 +7,21 @@ import org.gstreamer.elements.PlayBin2;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class Player{
|
||||
public class Player {
|
||||
|
||||
private PlayBin2 playBin;
|
||||
|
||||
private InternalThread internalThread;
|
||||
private Thread thread;
|
||||
|
||||
public Player(){
|
||||
public Player() {
|
||||
Gst.init();
|
||||
playBin = new PlayBin2("BusMessages");
|
||||
playBin.setVideoSink(ElementFactory.make("fakesink", "videosink"));
|
||||
}
|
||||
|
||||
public void playSong(File songFile){
|
||||
if(playBin.getState() == State.PLAYING)
|
||||
public void playSong(File songFile) {
|
||||
if (playBin.getState() == State.PLAYING)
|
||||
stop();
|
||||
playBin.setURI(songFile.toURI());
|
||||
internalThread = new InternalThread();
|
||||
@ -39,11 +39,11 @@ public class Player{
|
||||
}
|
||||
}
|
||||
|
||||
public void resume(){
|
||||
public void resume() {
|
||||
playBin.play();
|
||||
}
|
||||
|
||||
public void pause(){
|
||||
public void pause() {
|
||||
playBin.pause();
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,8 @@ 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;
|
||||
|
||||
public class PlayerGUI {
|
||||
private JTree libraryView;
|
||||
@ -27,42 +29,43 @@ public class PlayerGUI {
|
||||
}
|
||||
|
||||
|
||||
public PlayerGUI(){
|
||||
public PlayerGUI() {
|
||||
DatabaseManager.init();
|
||||
populateLibrary(Gateway.listAllSongsGroupedByAlbum().get());
|
||||
populateLibrary(new TreeMap<>(Gateway.listAllSongsGroupedByAlbum().get()));
|
||||
}
|
||||
|
||||
private void resetTree(){
|
||||
private void resetTree() {
|
||||
libraryView.removeAll();
|
||||
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode();
|
||||
DefaultTreeModel treeModel = new DefaultTreeModel(rootNode);
|
||||
libraryView.setModel(treeModel);
|
||||
libraryView.setRootVisible(false);
|
||||
libraryView.setToggleClickCount(1);
|
||||
libraryView.setCellRenderer(new LibraryTreeCellRenderer());
|
||||
}
|
||||
|
||||
private void populateLibrary(Map<Album, List<Song>> libraryData){
|
||||
private void populateLibrary(Map<Album, List<Song>> libraryData) {
|
||||
resetTree();
|
||||
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode)libraryView.getModel().getRoot();
|
||||
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) libraryView.getModel().getRoot();
|
||||
libraryData.forEach((k, v) -> {
|
||||
DefaultMutableTreeNode albumNode = new DefaultMutableTreeNode(k);
|
||||
addNodeToTreeModel(parentNode, albumNode);
|
||||
v.forEach(x -> addNodeToTreeModel(albumNode, new DefaultMutableTreeNode(x)));
|
||||
new TreeSet<>(v).forEach(x -> addNodeToTreeModel(albumNode, new DefaultMutableTreeNode(x)));
|
||||
});
|
||||
}
|
||||
|
||||
private void populateLibrary(List<Song> libraryData){
|
||||
private void populateLibrary(List<Song> libraryData) {
|
||||
resetTree();
|
||||
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode)libraryView.getModel().getRoot();
|
||||
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) libraryView.getModel().getRoot();
|
||||
libraryData.forEach(x -> addNodeToTreeModel(parentNode, new DefaultMutableTreeNode(x)));
|
||||
|
||||
}
|
||||
|
||||
private void addNodeToTreeModel(DefaultMutableTreeNode parentNode, DefaultMutableTreeNode node ) {
|
||||
DefaultTreeModel libraryModel = (DefaultTreeModel)libraryView.getModel();
|
||||
private void addNodeToTreeModel(DefaultMutableTreeNode parentNode, DefaultMutableTreeNode node) {
|
||||
DefaultTreeModel libraryModel = (DefaultTreeModel) libraryView.getModel();
|
||||
libraryModel.insertNodeInto(node, parentNode, parentNode.getChildCount());
|
||||
if (parentNode == libraryModel.getRoot()) {
|
||||
libraryModel.nodeStructureChanged((TreeNode)libraryModel.getRoot());
|
||||
libraryModel.nodeStructureChanged((TreeNode) libraryModel.getRoot());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,8 +28,8 @@ public class DatabaseManager {
|
||||
/**
|
||||
* Open a SessionFactory to the database as defined in hibernate.cfg.xml
|
||||
*/
|
||||
public static void init(){
|
||||
if(getInstance().sessionFactory != null)
|
||||
public static void init() {
|
||||
if (getInstance().sessionFactory != null)
|
||||
getInstance().sessionFactory.close();
|
||||
getInstance().sessionFactory = new Configuration().configure()
|
||||
.addAnnotatedClass(Album.class)
|
||||
@ -41,8 +41,8 @@ public class DatabaseManager {
|
||||
/**
|
||||
* Open a SessionFactory to an in-memory database for testing
|
||||
*/
|
||||
public static void testMode(){
|
||||
if(getInstance().sessionFactory != null)
|
||||
public static void testMode() {
|
||||
if (getInstance().sessionFactory != null)
|
||||
getInstance().sessionFactory.close();
|
||||
Properties properties = new Properties();
|
||||
properties.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
|
||||
@ -61,13 +61,13 @@ public class DatabaseManager {
|
||||
/**
|
||||
* @return Session for database interaction.
|
||||
*/
|
||||
public Session getSession(){
|
||||
public Session getSession() {
|
||||
return sessionFactory.openSession();
|
||||
}
|
||||
|
||||
@SuppressWarnings("CloneDoesntCallSuperClone")
|
||||
@Override
|
||||
public Object clone() throws CloneNotSupportedException{
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
throw new CloneNotSupportedException();
|
||||
}
|
||||
}
|
||||
|
@ -22,10 +22,10 @@ public class Gateway {
|
||||
* @param name Name of the album to find.
|
||||
* @return Album found with name or Optional.empty()
|
||||
*/
|
||||
public static Optional<Album> getOneAlbum(String name){
|
||||
try(Session session = DatabaseManager.getInstance().getSession()){
|
||||
public static Optional<Album> getOneAlbum(String name) {
|
||||
try (Session session = DatabaseManager.getInstance().getSession()) {
|
||||
Criteria criteria = session.createCriteria(Album.class);
|
||||
Album album = (Album)criteria.add(Restrictions.eq("name", name)).uniqueResult();
|
||||
Album album = (Album) criteria.add(Restrictions.eq("name", name)).uniqueResult();
|
||||
return (album == null) ? Optional.empty() : Optional.of(album);
|
||||
}
|
||||
}
|
||||
@ -34,8 +34,8 @@ public class Gateway {
|
||||
* @param name Name of the artist to find.
|
||||
* @return Artist found with name or Optional.empty()
|
||||
*/
|
||||
public static Optional<Artist> getOneArtist(String name){
|
||||
try(Session session = DatabaseManager.getInstance().getSession()){
|
||||
public static Optional<Artist> getOneArtist(String name) {
|
||||
try (Session session = DatabaseManager.getInstance().getSession()) {
|
||||
Criteria criteria = session.createCriteria(Artist.class);
|
||||
Artist artist = (Artist) criteria.add(Restrictions.eq("name", name)).uniqueResult();
|
||||
return (artist == null) ? Optional.empty() : Optional.of(artist);
|
||||
@ -45,8 +45,8 @@ public class Gateway {
|
||||
/**
|
||||
* @return List of all songs currently stored in the database.
|
||||
*/
|
||||
public static Optional<List<Song>> listAllSongs(){
|
||||
try(Session session = DatabaseManager.getInstance().getSession()){
|
||||
public static Optional<List<Song>> listAllSongs() {
|
||||
try (Session session = DatabaseManager.getInstance().getSession()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Song> songs = session.createCriteria(Song.class).list();
|
||||
return (songs == null || songs.isEmpty()) ? Optional.empty() : Optional.of(songs);
|
||||
@ -56,7 +56,7 @@ public class Gateway {
|
||||
/**
|
||||
* @return All songs currently in the database, grouped by album.
|
||||
*/
|
||||
public static Optional<Map<Album, List<Song>>> listAllSongsGroupedByAlbum(){
|
||||
public static Optional<Map<Album, List<Song>>> listAllSongsGroupedByAlbum() {
|
||||
Optional<List<Song>> songList = listAllSongs();
|
||||
return (songList.isPresent()) ?
|
||||
Optional.of(songList.get().stream().collect(Collectors.groupingBy(Song::getAlbum)))
|
||||
@ -65,21 +65,38 @@ public class Gateway {
|
||||
|
||||
/**
|
||||
* Add a new song to the database.
|
||||
*
|
||||
* @param metadata New song information.
|
||||
*/
|
||||
public static void addSong(ExtractedMetadata metadata){
|
||||
try(Session session = DatabaseManager.getInstance().getSession()) {
|
||||
Optional<Album> albumObj = getOneAlbum(metadata.album);
|
||||
if(!albumObj.isPresent())
|
||||
albumObj = Optional.of(new Album(metadata.album));
|
||||
Optional<Artist> artistObj = getOneArtist(metadata.artist);
|
||||
if(!artistObj.isPresent())
|
||||
artistObj = Optional.of(new Artist(metadata.artist));
|
||||
public static void addSong(ExtractedMetadata metadata) {
|
||||
try (Session session = DatabaseManager.getInstance().getSession()) {
|
||||
session.beginTransaction();
|
||||
Optional<Album> albumObj = getOneAlbum(metadata.album);
|
||||
if (!albumObj.isPresent()) {
|
||||
Album album = new Album(metadata.album);
|
||||
albumObj = Optional.of(album);
|
||||
session.save(album);
|
||||
}
|
||||
Optional<Artist> artistObj = getOneArtist(metadata.artist);
|
||||
if (!artistObj.isPresent()) {
|
||||
Artist artist = new Artist(metadata.artist);
|
||||
artistObj = Optional.of(artist);
|
||||
session.save(artist);
|
||||
}
|
||||
session.save(new Song(metadata.trackNumber, metadata.title, artistObj.get(), albumObj.get(), metadata.genre, metadata.songFile));
|
||||
session.getTransaction().commit();
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateAllAlbumArt() {
|
||||
try (Session session = DatabaseManager.getInstance().getSession()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Album> albums = session.createCriteria(Album.class).list();
|
||||
session.beginTransaction();
|
||||
albums.forEach(Album::refreshAlbumArt);
|
||||
session.getTransaction().commit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,27 +1,71 @@
|
||||
package musicplayer.model;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.persistence.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
@Entity
|
||||
public class Album {
|
||||
public class Album implements Comparable<Album> {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy=GenerationType.AUTO)
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
@Column(name = "id")
|
||||
private long id;
|
||||
@Column(name = "name")
|
||||
private String name;
|
||||
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "album")
|
||||
private Set<Song> songs;
|
||||
@Lob
|
||||
@Column(name = "art", nullable = true, length = 10000)
|
||||
private byte[] art;
|
||||
@Transient
|
||||
private static int imageScaleToSize = 50;
|
||||
|
||||
protected Album(){}
|
||||
protected Album() {
|
||||
}
|
||||
|
||||
public Album(String name){
|
||||
public Album(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Set<Song> getSongs() {
|
||||
return songs;
|
||||
}
|
||||
|
||||
public Optional<Image> getAlbumArt() {
|
||||
if (art == null) return Optional.empty();
|
||||
try (InputStream in = new ByteArrayInputStream(art)) {
|
||||
return Optional.of(ImageIO.read(in));
|
||||
} catch (IOException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Transient
|
||||
public void refreshAlbumArt() {
|
||||
Optional<BufferedImage> artGet = songs.iterator().next().getAlbumArt();
|
||||
if (artGet.isPresent()) {
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
||||
ImageIO.write(convertToBufferedImage(artGet.get().getScaledInstance(imageScaleToSize, imageScaleToSize, Image.SCALE_SMOOTH)), "jpg", baos);
|
||||
baos.flush();
|
||||
art = baos.toByteArray();
|
||||
} catch (IOException e) {
|
||||
art = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("MethodWithMultipleReturnPoints")
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
@ -41,11 +85,27 @@ public class Album {
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getName(){
|
||||
@Transient
|
||||
public static BufferedImage convertToBufferedImage(Image image) {
|
||||
BufferedImage newImage = new BufferedImage(
|
||||
image.getWidth(null), image.getHeight(null),
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = newImage.createGraphics();
|
||||
g.drawImage(image, 0, 0, null);
|
||||
g.dispose();
|
||||
return newImage;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public long getId(){
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Album o) {
|
||||
return toString().compareToIgnoreCase(o.toString());
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,24 @@
|
||||
package musicplayer.model;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.Set;
|
||||
|
||||
@Entity
|
||||
public class Artist {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy=GenerationType.AUTO)
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
@Column(name = "id")
|
||||
private long id;
|
||||
@Column(name = "name")
|
||||
private String name;
|
||||
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "artist")
|
||||
private Set<Song> songs;
|
||||
|
||||
protected Artist(){}
|
||||
protected Artist() {
|
||||
}
|
||||
|
||||
public Artist(String name){
|
||||
public Artist(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@ -25,10 +29,14 @@ public class Artist {
|
||||
return result;
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Set<Song> getSongs() {
|
||||
return songs;
|
||||
}
|
||||
|
||||
@SuppressWarnings("MethodWithMultipleReturnPoints")
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
@ -41,11 +49,11 @@ public class Artist {
|
||||
|
||||
}
|
||||
|
||||
public String getName(){
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public long getId(){
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
@ -18,9 +18,9 @@ public class ExtractedMetadata {
|
||||
|
||||
/**
|
||||
* @param audioTags jaudiotagger tag data.
|
||||
* @param songFile Location of the song file on the filesystem.
|
||||
* @param songFile Location of the song file on the filesystem.
|
||||
*/
|
||||
public ExtractedMetadata(Tag audioTags, File songFile){
|
||||
public ExtractedMetadata(Tag audioTags, File songFile) {
|
||||
this.trackNumber = audioTags.getFirst(FieldKey.TRACK);
|
||||
this.title = audioTags.getFirst(FieldKey.TITLE);
|
||||
this.album = audioTags.getFirst(FieldKey.ALBUM);
|
||||
|
@ -5,33 +5,37 @@ import javax.persistence.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
|
||||
@Entity
|
||||
public class Song {
|
||||
public class Song implements Comparable<Song> {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy=GenerationType.AUTO)
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
@Column(name = "id")
|
||||
private long id;
|
||||
@ManyToOne(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
|
||||
@ManyToOne
|
||||
private Artist artist;
|
||||
@Column(name = "genre")
|
||||
private String genre;
|
||||
@Column(name = "title")
|
||||
private String title;
|
||||
@ManyToOne(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
|
||||
@ManyToOne
|
||||
private Album album;
|
||||
@Column(name = "songFile")
|
||||
private String songFile;
|
||||
@Column(name = "trackNumber")
|
||||
private String trackNumber;
|
||||
|
||||
protected Song(){}
|
||||
protected Song() {
|
||||
}
|
||||
|
||||
public Song(String trackNumber, String title, Artist artist, Album album, String genre, String songFile){
|
||||
public Song(String trackNumber, String title, Artist artist, Album album, String genre, String songFile) {
|
||||
this.trackNumber = trackNumber;
|
||||
this.title = title;
|
||||
this.artist = artist;
|
||||
@ -41,7 +45,7 @@ public class Song {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
public String toString() {
|
||||
return title;
|
||||
}
|
||||
|
||||
@ -72,14 +76,14 @@ public class Song {
|
||||
|
||||
/**
|
||||
* Try to find album art for this song based on likely image file names in the folder.
|
||||
*
|
||||
* @return BufferedImage of album art or Optional.empty()
|
||||
*/
|
||||
public Optional<BufferedImage> getAlbumArt(){
|
||||
try {
|
||||
Optional<Path> imageFile = Files.walk(getSongFile().getParentFile().toPath())
|
||||
.filter(f -> f.toString().matches("(Folder|Cover).jpg")).findFirst();
|
||||
return (imageFile.isPresent()) ? Optional.of(ImageIO.read(imageFile.get().toFile())) : Optional.empty();
|
||||
} catch (IOException e) {
|
||||
public Optional<BufferedImage> getAlbumArt() {
|
||||
Path dir = Paths.get(songFile).getParent();
|
||||
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.{jpg,png}")) {
|
||||
return Optional.of(ImageIO.read(stream.iterator().next().toFile()));
|
||||
} catch (IOException | NoSuchElementException ignored) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
@ -111,4 +115,11 @@ public class Song {
|
||||
public String 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());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user