Album art is no longer cached in db.
This commit is contained in:
parent
b91729004b
commit
5856248a7d
@ -2,14 +2,12 @@ package musicplayer.db;
|
|||||||
|
|
||||||
import musicplayer.util.ConfigManager;
|
import musicplayer.util.ConfigManager;
|
||||||
import musicplayer.model.*;
|
import musicplayer.model.*;
|
||||||
import musicplayer.util.AlbumArtExtractor;
|
|
||||||
import org.hibernate.Criteria;
|
import org.hibernate.Criteria;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.SessionFactory;
|
import org.hibernate.SessionFactory;
|
||||||
import org.hibernate.cfg.Configuration;
|
import org.hibernate.cfg.Configuration;
|
||||||
import org.hibernate.criterion.Restrictions;
|
import org.hibernate.criterion.Restrictions;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
@ -154,8 +152,7 @@ public class HibernateDatabase implements IDatabase{
|
|||||||
session.beginTransaction();
|
session.beginTransaction();
|
||||||
Optional<Album> albumObj = getOneAlbum(metadata.getAlbum());
|
Optional<Album> albumObj = getOneAlbum(metadata.getAlbum());
|
||||||
if (!albumObj.isPresent()) {
|
if (!albumObj.isPresent()) {
|
||||||
byte[] art = AlbumArtExtractor.getImageData(new File(metadata.getSongFile()));
|
Album album = new Album(metadata.getAlbum());
|
||||||
Album album = new Album(metadata.getAlbum(), art);
|
|
||||||
albumObj = Optional.of(album);
|
albumObj = Optional.of(album);
|
||||||
}
|
}
|
||||||
Optional<Artist> artistObj = getOneArtist(metadata.getArtist());
|
Optional<Artist> artistObj = getOneArtist(metadata.getArtist());
|
||||||
|
@ -37,6 +37,8 @@ public class JTreeLibrary extends JPanel implements ILibrary, LibraryCallbackInt
|
|||||||
private final JXTextField librarySearchField = new JXTextField();
|
private final JXTextField librarySearchField = new JXTextField();
|
||||||
final JTree libraryTree = new JTree();
|
final JTree libraryTree = new JTree();
|
||||||
private final Map<String, Runnable> libraryDisplayVariants = createDisplayVariantMap();
|
private final Map<String, Runnable> libraryDisplayVariants = createDisplayVariantMap();
|
||||||
|
private final static Map<Long, ImageIcon> albumArt = new HashMap<>();
|
||||||
|
private Thread albumArtCollector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Map of display types for the library paired code to populate the library with data in the correct format.
|
* @return Map of display types for the library paired code to populate the library with data in the correct format.
|
||||||
@ -78,6 +80,11 @@ public class JTreeLibrary extends JPanel implements ILibrary, LibraryCallbackInt
|
|||||||
otherContainer.add(libraryDisplayType);
|
otherContainer.add(libraryDisplayType);
|
||||||
otherContainer.add(librarySearchField);
|
otherContainer.add(librarySearchField);
|
||||||
this.add(otherContainer, BorderLayout.NORTH);
|
this.add(otherContainer, BorderLayout.NORTH);
|
||||||
|
Optional<List<Album>> dbQuery = database.listAllT(Album.class);
|
||||||
|
dbQuery.ifPresent(x -> x.forEach(y -> {
|
||||||
|
albumArtCollector = new Thread(() -> y.getAlbumArt().ifPresent(art -> albumArt.put(y.getId(), art)));
|
||||||
|
albumArtCollector.start();
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -208,6 +215,13 @@ public class JTreeLibrary extends JPanel implements ILibrary, LibraryCallbackInt
|
|||||||
*/
|
*/
|
||||||
public void libraryUpdated() {
|
public void libraryUpdated() {
|
||||||
libraryUpdating.set(false);
|
libraryUpdating.set(false);
|
||||||
|
albumArtCollector.interrupt();
|
||||||
|
albumArtCollector = new Thread(() -> {
|
||||||
|
Optional<List<Album>> dbQuery = database.listAllT(Album.class);
|
||||||
|
dbQuery.ifPresent(x -> x.forEach(y -> y.getAlbumArt().ifPresent(art -> albumArt.put(y.getId(),
|
||||||
|
art))));
|
||||||
|
});
|
||||||
|
albumArtCollector.start();
|
||||||
refreshLibrary();
|
refreshLibrary();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,7 +266,8 @@ public class JTreeLibrary extends JPanel implements ILibrary, LibraryCallbackInt
|
|||||||
|
|
||||||
private final JLabel label;
|
private final JLabel label;
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
private final Icon missingIcon = new ImageIcon(JTreeLibrary.class.getClassLoader().getResource("missing.gif"));
|
private final ImageIcon missingIcon = new ImageIcon(JTreeLibrary.class.getClassLoader().getResource("missing" +
|
||||||
|
".gif"));
|
||||||
|
|
||||||
LibraryTreeCellRenderer() {
|
LibraryTreeCellRenderer() {
|
||||||
label = new JLabel();
|
label = new JLabel();
|
||||||
@ -266,8 +281,12 @@ public class JTreeLibrary extends JPanel implements ILibrary, LibraryCallbackInt
|
|||||||
label.setText(o.toString());
|
label.setText(o.toString());
|
||||||
if (o instanceof Album) {
|
if (o instanceof Album) {
|
||||||
Album album = (Album) o;
|
Album album = (Album) o;
|
||||||
label.setIcon(missingIcon);
|
if(albumArt.containsKey(album.getId())){
|
||||||
album.getAlbumArt().ifPresent(x -> label.setIcon(new ImageIcon(x)));
|
label.setIcon(albumArt.get(album.getId()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
label.setIcon(missingIcon);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return label;
|
return label;
|
||||||
|
@ -1,11 +1,22 @@
|
|||||||
package musicplayer.model;
|
package musicplayer.model;
|
||||||
|
|
||||||
|
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 javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.nio.file.DirectoryStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -21,21 +32,17 @@ public class Album implements Comparable<Album>, IDBType, HasSongs {
|
|||||||
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "album")
|
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "album")
|
||||||
@OrderBy("discNumber ASC, trackNumber ASC")
|
@OrderBy("discNumber ASC, trackNumber ASC")
|
||||||
private Set<Song> songs;
|
private Set<Song> songs;
|
||||||
@Lob
|
|
||||||
@Column(name = "art", nullable = true, length = 10000)
|
@Transient
|
||||||
private byte[] art;
|
private static final String albumArtRegex = ".*(Cover|Folder|cover|folder)\\.(jpg|png)";
|
||||||
|
@Transient
|
||||||
|
private static final int imageScaleToSize = 50;
|
||||||
|
|
||||||
protected Album() {
|
protected Album() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Album(String name){
|
public Album(String name){
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.art = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Album(String name, byte[] art) {
|
|
||||||
this.name = name;
|
|
||||||
this.art = art;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
@ -46,15 +53,6 @@ public class Album implements Comparable<Album>, IDBType, HasSongs {
|
|||||||
return songs;
|
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 | NullPointerException e) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("MethodWithMultipleReturnPoints")
|
@SuppressWarnings("MethodWithMultipleReturnPoints")
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
@ -86,4 +84,28 @@ public class Album implements Comparable<Album>, IDBType, HasSongs {
|
|||||||
public int compareTo(Album o) {
|
public int compareTo(Album o) {
|
||||||
return toString().compareToIgnoreCase(o.toString());
|
return toString().compareToIgnoreCase(o.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get album art for a given album.
|
||||||
|
* @return Album art.
|
||||||
|
*/
|
||||||
|
public Optional<ImageIcon> getAlbumArt(){
|
||||||
|
Tag audioTags;
|
||||||
|
File targetFile = songs.iterator().next().getSongFile();
|
||||||
|
Path baseDir = targetFile.getParentFile().toPath();
|
||||||
|
try {
|
||||||
|
audioTags = AudioFileIO.read(targetFile).getTag();
|
||||||
|
if(audioTags != null && audioTags.getFirstArtwork() != null) {
|
||||||
|
return Optional.of(new ImageIcon(((Image)audioTags.getFirstArtwork().getImage()).getScaledInstance
|
||||||
|
(imageScaleToSize, imageScaleToSize, Image.SCALE_SMOOTH)));
|
||||||
|
}
|
||||||
|
} catch (CannotReadException | IOException | ReadOnlyFileException | TagException | InvalidAudioFrameException ignored) {
|
||||||
|
}
|
||||||
|
try (DirectoryStream<Path> stream = Files.newDirectoryStream(baseDir, albumArtRegex)) {
|
||||||
|
return Optional.of(new ImageIcon(ImageIO.read(stream.iterator().next().toFile()).getScaledInstance
|
||||||
|
(imageScaleToSize, imageScaleToSize, Image.SCALE_SMOOTH)));
|
||||||
|
} catch (IOException | NoSuchElementException ignored) {
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,94 +0,0 @@
|
|||||||
package musicplayer.util;
|
|
||||||
|
|
||||||
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 javax.imageio.ImageIO;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
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;
|
|
||||||
|
|
||||||
public final class AlbumArtExtractor {
|
|
||||||
|
|
||||||
private static final String albumArtRegex = ".*(Cover|Folder|cover|folder)\\.(jpg|png)";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the album art for a song file.
|
|
||||||
* @param songFile File from which to get album art data
|
|
||||||
* (Data is either extracted from file metadata or an image in the same folder).
|
|
||||||
* @return Album art as a byte array.
|
|
||||||
*/
|
|
||||||
public static byte[] getImageData(File songFile){
|
|
||||||
Tag audioTags;
|
|
||||||
try {
|
|
||||||
audioTags = AudioFileIO.read(songFile).getTag();
|
|
||||||
} catch (CannotReadException | IOException | ReadOnlyFileException | TagException | InvalidAudioFrameException e) {
|
|
||||||
return getImageDataFromFolder(songFile);
|
|
||||||
}
|
|
||||||
byte[] tmpArt;
|
|
||||||
try {
|
|
||||||
tmpArt = audioTags.getFirstArtwork().getBinaryData();
|
|
||||||
BufferedImage image = ImageIO.read(new ByteArrayInputStream(tmpArt));
|
|
||||||
tmpArt = convertImageToBytes(image);
|
|
||||||
} catch (IOException | NullPointerException ignored) {
|
|
||||||
return getImageDataFromFolder(songFile);
|
|
||||||
}
|
|
||||||
return 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 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),
|
|
||||||
BufferedImage.TYPE_INT_ARGB);
|
|
||||||
Graphics2D g = newImage.createGraphics();
|
|
||||||
g.drawImage(image, 0, 0, null);
|
|
||||||
g.dispose();
|
|
||||||
return newImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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()
|
|
||||||
*/
|
|
||||||
private static byte[] getImageDataFromFolder(File songFile) {
|
|
||||||
Path dir = songFile.getParentFile().toPath();
|
|
||||||
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, albumArtRegex)) {
|
|
||||||
return convertImageToBytes(ImageIO.read(stream.iterator().next().toFile()));
|
|
||||||
} catch (IOException | NoSuchElementException ignored) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user