/*
* Jajuk
* Copyright (C) The Jajuk Team
* http://jajuk.info
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
package org.jajuk.ui.thumbnails;
import ext.services.lastfm.AlbumInfo;
import ext.services.lastfm.LastFmService;
import ext.services.lastfm.TrackInfo;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import net.miginfocom.swing.MigLayout;
import org.apache.commons.lang.StringUtils;
import org.jajuk.base.Album;
import org.jajuk.base.AlbumManager;
import org.jajuk.base.Item;
import org.jajuk.ui.helpers.FontManager;
import org.jajuk.ui.helpers.FontManager.JajukFont;
import org.jajuk.util.Const;
import org.jajuk.util.DownloadManager;
import org.jajuk.util.IconLoader;
import org.jajuk.util.JajukIcons;
import org.jajuk.util.Messages;
import org.jajuk.util.UtilGUI;
import org.jajuk.util.UtilString;
import org.jajuk.util.UtilSystem;
import org.jajuk.util.log.Log;
import org.jdesktop.swingx.border.DropShadowBorder;
/**
* Last.FM Album thumb represented as album cover + (optionally) others text
* information display...
*/
public class LastFmAlbumThumbnail extends AbstractThumbnail {
/** Generated serialVersionUID. */
private static final long serialVersionUID = -804471264407148566L;
/** Associated album. */
private AlbumInfo album;
/** Is this artist known in collection ?. */
private final boolean bKnown;
/** Thumb associated image *. */
private ImageIcon ii;
/**
* The Constructor.
*
* @param album :
* associated album
*/
public LastFmAlbumThumbnail(AlbumInfo album) {
super(100);
this.album = album;
bKnown = (AlbumManager.getInstance().getAlbumByName(album.getTitle()) != null);
}
/*
* (non-Javadoc)
*
* @see org.jajuk.ui.thumbnails.AbstractThumbnail#getItem()
*/
@Override
public Item getItem() {
Album item = AlbumManager.getInstance().getAlbumByName(album.getTitle());
if (item != null) {
return item;
}
return null;
}
/*
* (non-Javadoc)
*
* @see org.jajuk.ui.thumbnails.AbstractThumbnail#getDescription()
*/
@Override
public String getDescription() {
// populate album detail
if (album.getTracks() == null) {
AlbumInfo lAlbum = LastFmService.getInstance().getAlbum(this.album.getArtist(),
this.album.getTitle());
if (lAlbum != null) {
this.album = lAlbum;
}
}
Color bgcolor = UtilGUI.getUltraLightColor();
Color fgcolor = UtilGUI.getForegroundColor();
String sOut = "<html bgcolor='#" + UtilGUI.getHTMLColor(bgcolor) + "'><TABLE color='"
+ UtilGUI.getHTMLColor(fgcolor) + "'><TR><TD VALIGN='TOP'> <b>" + "<a href='file://"
+ Const.XML_URL + '?' + album.getUrl() + "'>" + album.getTitle() + "</a>" + "</b><br><br>";
// display cover
sOut += "<img src='" + album.getBigCoverURL() + "'><br>";
// Display artist as global value only if it is a single artist album
// We use file://<item type>?<item id> as HTML hyperlink format
sOut += "<br>" + Messages.getHumanPropertyName(Const.XML_ARTIST) + " : " + "<a href='file://"
+ Const.XML_URL + '?' + album.getArtistUrl() + "'>" + album.getArtist() + "</a>";
// Display year if available
String year = album.getYear();
if (!StringUtils.isBlank(year)) {
sOut += "<br>" + Messages.getHumanPropertyName(Const.XML_YEAR) + " : " + year;
}
sOut += "</TD><TD>";
// Show each track detail if available
if (album.getTracks() != null) {
for (TrackInfo track : album.getTracks()) {
sOut += "<b>" + "<a href='file://" + Const.XML_URL + '?' + track.getUrl() + "'>"
+ track.getTitle() + "</a></b><br>";
}
}
sOut += "</TD></TR></TABLE></html>";
return sOut;
}
/*
* (non-Javadoc)
*
* @see org.jajuk.ui.thumbnails.AbstractThumbnail#launch()
*/
@Override
public void launch() {
if (getItem() != null) {
// play the album
jmiPlay.doClick();
} else {
// Open the last.FM page
jmiOpenLastFMSite.doClick();
}
}
/**
* Long part of the populating process. Longest parts (images download) should
* have already been done by the caller outside the EDT. we only pop the image
* from the cache here.
*/
private void preLoad() {
try {
// Check if album image is null
String albumUrl = album.getBigCoverURL();
if (StringUtils.isBlank(albumUrl)) {
return;
}
// Download thumb
URL remote = new URL(albumUrl);
// Download image and store file reference (to generate the
// popup thumb for ie)
fCover = DownloadManager.downloadToCache(remote);
if (!fCover.exists()) {
Log.warn("Cache file not found: {{" + fCover.getAbsolutePath() + "}}");
return;
}
if (fCover.length() == 0) {
Log.warn("Cache file has zero bytes: {{" + fCover.getAbsolutePath() + "}}");
return;
}
BufferedImage image = ImageIO.read(fCover);
if (image == null) {
Log.warn("Could not read cover from: {{" + fCover.getAbsolutePath() + "}}");
return;
}
ImageIcon downloadedImage = new ImageIcon(image);
ii = UtilGUI.getScaledImage(downloadedImage, 100);
// Free images memory
downloadedImage.getImage().flush();
image.flush();
} catch (FileNotFoundException e) {
// only report a warning for FileNotFoundException and do not show a
// stack trace in the logfile as it is happening frequently
Log.warn("Could not load image, no content found at address: {{" + e.getMessage() + "}}");
} catch (SocketTimeoutException e) {
// only report a warning for FileNotFoundException and do not show a
// stacktrace in the logfile as it is happening frequently
Log.warn("Could not load image, timed out while reading address: {{" + e.getMessage() + "}}");
} catch (IOException e) {
if (e.getMessage().contains(" 403 ")) {
Log.warn("Could not access webpage, returned error 403: " + e.getMessage());
} else {
Log.error(e);
}
} catch (Exception e) {
Log.error(e);
// check for empty file to remove invalid cache entries
if (fCover.exists() && fCover.length() == 0) {
Log.warn("Removing empty file from cache: " + fCover.getAbsolutePath());
if (!fCover.delete()) {
Log.warn("Error removing file: " + fCover.getAbsolutePath());
}
}
}
}
/**
* Thumb populating done in EDT.
*/
@Override
public void populate() {
preLoad();
if (ii == null) {
return;
}
jlIcon = new JLabel();
postPopulate();
jlIcon.setIcon(ii);
setLayout(new MigLayout("ins 0,gapy 2"));
add(jlIcon, "center,wrap");
JLabel jlTitle;
String fullTitle = album.getTitle();
// Add year if available
String releaseDate = album.getReleaseDateString();
if (StringUtils.isNotBlank(releaseDate)) {
fullTitle += " (" + releaseDate + ")";
}
int textLength = 15;
if (isArtistView()) {
textLength = 50;
}
if (bKnown) {
// Album known in collection, display its name in bold
jlTitle = new JLabel(UtilString.getLimitedString(fullTitle, textLength),
IconLoader.getIcon(JajukIcons.ALBUM), SwingConstants.CENTER);
jlTitle.setFont(FontManager.getInstance().getFont(JajukFont.BOLD));
} else {
jlTitle = new JLabel(UtilString.getLimitedString(fullTitle, textLength));
jlTitle.setFont(FontManager.getInstance().getFont(JajukFont.PLAIN));
}
jlTitle.setToolTipText(album.getTitle());
jlIcon.setToolTipText(album.getTitle());
add(jlTitle, "center");
jlIcon.setBorder(new DropShadowBorder(Color.BLACK, 5, 0.5f, 5, false, true, false, true));
// disable inadequate menu items
jmiCDDBWizard.setEnabled(false);
jmiGetCovers.setEnabled(false);
if (getItem() == null) {
jmiDelete.setEnabled(false);
jmiPlay.setEnabled(false);
jmiPlayRepeat.setEnabled(false);
jmiPlayShuffle.setEnabled(false);
jmiFrontPush.setEnabled(false);
jmiPush.setEnabled(false);
jmiProperties.setEnabled(false);
}
// Set URL to open
if (UtilSystem.isBrowserSupported()) {
jmiOpenLastFMSite.putClientProperty(Const.DETAIL_CONTENT, album.getUrl());
}
}
}