Album art is no longer cached in db.

This commit is contained in:
neviyn 2016-08-18 17:56:10 +01:00
parent b91729004b
commit 5856248a7d
4 changed files with 65 additions and 121 deletions

View File

@ -2,14 +2,12 @@ package musicplayer.db;
import musicplayer.util.ConfigManager;
import musicplayer.model.*;
import musicplayer.util.AlbumArtExtractor;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Restrictions;
import java.io.File;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
@ -154,8 +152,7 @@ public class HibernateDatabase implements IDatabase{
session.beginTransaction();
Optional<Album> albumObj = getOneAlbum(metadata.getAlbum());
if (!albumObj.isPresent()) {
byte[] art = AlbumArtExtractor.getImageData(new File(metadata.getSongFile()));
Album album = new Album(metadata.getAlbum(), art);
Album album = new Album(metadata.getAlbum());
albumObj = Optional.of(album);
}
Optional<Artist> artistObj = getOneArtist(metadata.getArtist());

View File

@ -37,6 +37,8 @@ public class JTreeLibrary extends JPanel implements ILibrary, LibraryCallbackInt
private final JXTextField librarySearchField = new JXTextField();
final JTree libraryTree = new JTree();
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.
@ -78,6 +80,11 @@ public class JTreeLibrary extends JPanel implements ILibrary, LibraryCallbackInt
otherContainer.add(libraryDisplayType);
otherContainer.add(librarySearchField);
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() {
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();
}
@ -252,7 +266,8 @@ public class JTreeLibrary extends JPanel implements ILibrary, LibraryCallbackInt
private final JLabel label;
@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() {
label = new JLabel();
@ -266,8 +281,12 @@ public class JTreeLibrary extends JPanel implements ILibrary, LibraryCallbackInt
label.setText(o.toString());
if (o instanceof Album) {
Album album = (Album) o;
label.setIcon(missingIcon);
album.getAlbumArt().ifPresent(x -> label.setIcon(new ImageIcon(x)));
if(albumArt.containsKey(album.getId())){
label.setIcon(albumArt.get(album.getId()));
}
else {
label.setIcon(missingIcon);
}
}
}
return label;

View File

@ -1,11 +1,22 @@
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.persistence.*;
import javax.swing.*;
import java.awt.*;
import java.io.ByteArrayInputStream;
import java.io.File;
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.Set;
@ -21,21 +32,17 @@ public class Album implements Comparable<Album>, IDBType, HasSongs {
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "album")
@OrderBy("discNumber ASC, trackNumber ASC")
private Set<Song> songs;
@Lob
@Column(name = "art", nullable = true, length = 10000)
private byte[] art;
@Transient
private static final String albumArtRegex = ".*(Cover|Folder|cover|folder)\\.(jpg|png)";
@Transient
private static final int imageScaleToSize = 50;
protected Album() {
}
public Album(String name){
this.name = name;
this.art = null;
}
public Album(String name, byte[] art) {
this.name = name;
this.art = art;
}
public String toString() {
@ -46,15 +53,6 @@ public class Album implements Comparable<Album>, IDBType, HasSongs {
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")
@Override
public boolean equals(Object o) {
@ -86,4 +84,28 @@ public class Album implements Comparable<Album>, IDBType, HasSongs {
public int compareTo(Album o) {
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();
}
}

View File

@ -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;
}
}
}