diff --git a/libresonic-main/pom.xml b/libresonic-main/pom.xml
index d26d8cc8..3f820085 100644
--- a/libresonic-main/pom.xml
+++ b/libresonic-main/pom.xml
@@ -127,14 +127,8 @@
com.google.guava
- guava-base
- r03
-
-
-
- com.google.guava
- guava-collections
- r03
+ guava
+ 18.0
diff --git a/libresonic-main/src/main/java/org/libresonic/player/ajax/CoverArtService.java b/libresonic-main/src/main/java/org/libresonic/player/ajax/CoverArtService.java
index 360c668d..c626250b 100644
--- a/libresonic-main/src/main/java/org/libresonic/player/ajax/CoverArtService.java
+++ b/libresonic-main/src/main/java/org/libresonic/player/ajax/CoverArtService.java
@@ -23,6 +23,7 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.List;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.config.RequestConfig;
@@ -32,7 +33,9 @@ import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.libresonic.player.Logger;
+import org.libresonic.player.domain.LastFmCoverArt;
import org.libresonic.player.domain.MediaFile;
+import org.libresonic.player.service.LastFmService;
import org.libresonic.player.service.MediaFileService;
import org.libresonic.player.service.SecurityService;
import org.libresonic.player.util.StringUtil;
@@ -50,6 +53,11 @@ public class CoverArtService {
private SecurityService securityService;
private MediaFileService mediaFileService;
+ private LastFmService lastFmService;
+
+ public List searchCoverArt(String artist, String album) {
+ return lastFmService.searchCoverArt(artist, album);
+ }
/**
* Downloads and saves the cover art at the given URL.
@@ -162,4 +170,8 @@ public class CoverArtService {
public void setMediaFileService(MediaFileService mediaFileService) {
this.mediaFileService = mediaFileService;
}
-}
\ No newline at end of file
+
+ public void setLastFmService(LastFmService lastFmService) {
+ this.lastFmService = lastFmService;
+ }
+}
diff --git a/libresonic-main/src/main/java/org/libresonic/player/controller/ChangeCoverArtController.java b/libresonic-main/src/main/java/org/libresonic/player/controller/ChangeCoverArtController.java
index 9e977ea2..9047564a 100644
--- a/libresonic-main/src/main/java/org/libresonic/player/controller/ChangeCoverArtController.java
+++ b/libresonic-main/src/main/java/org/libresonic/player/controller/ChangeCoverArtController.java
@@ -25,6 +25,7 @@ import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.lang.StringUtils;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.ParameterizableViewController;
@@ -49,10 +50,10 @@ public class ChangeCoverArtController extends ParameterizableViewController {
String album = request.getParameter("album");
MediaFile dir = mediaFileService.getMediaFile(id);
- if (artist == null) {
+ if (StringUtils.isBlank(artist)) {
artist = dir.getArtist();
}
- if (album == null) {
+ if (StringUtils.isBlank(album)) {
album = dir.getAlbumName();
}
diff --git a/libresonic-main/src/main/java/org/libresonic/player/domain/AlbumNotes.java b/libresonic-main/src/main/java/org/libresonic/player/domain/AlbumNotes.java
new file mode 100644
index 00000000..d3d48237
--- /dev/null
+++ b/libresonic-main/src/main/java/org/libresonic/player/domain/AlbumNotes.java
@@ -0,0 +1,69 @@
+/*
+ * This file is part of Libresonic.
+ *
+ * Libresonic 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libresonic 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 Libresonic. If not, see .
+ *
+ * Copyright 2016 (C) Libresonic Authors
+ * Based upon Subsonic, Copyright 2009 (C) Sindre Mehus
+ */
+
+package org.libresonic.player.domain;
+
+/**
+ * @author Sindre Mehus
+ * @version $Id$
+ */
+public class AlbumNotes {
+
+ private final String notes;
+ private final String musicBrainzId;
+ private final String lastFmUrl;
+ private final String smallImageUrl;
+ private final String mediumImageUrl;
+ private final String largeImageUrl;
+
+ public AlbumNotes(String notes, String musicBrainzId, String lastFmUrl, String smallImageUrl,
+ String mediumImageUrl, String largeImageUrl) {
+ this.notes = notes;
+ this.musicBrainzId = musicBrainzId;
+ this.lastFmUrl = lastFmUrl;
+ this.smallImageUrl = smallImageUrl;
+ this.mediumImageUrl = mediumImageUrl;
+ this.largeImageUrl = largeImageUrl;
+ }
+
+ public String getNotes() {
+ return notes;
+ }
+
+ public String getMusicBrainzId() {
+ return musicBrainzId;
+ }
+
+ public String getLastFmUrl() {
+ return lastFmUrl;
+ }
+
+ public String getSmallImageUrl() {
+ return smallImageUrl;
+ }
+
+ public String getMediumImageUrl() {
+ return mediumImageUrl;
+ }
+
+ public String getLargeImageUrl() {
+ return largeImageUrl;
+ }
+}
diff --git a/libresonic-main/src/main/java/org/libresonic/player/domain/LastFmCoverArt.java b/libresonic-main/src/main/java/org/libresonic/player/domain/LastFmCoverArt.java
new file mode 100644
index 00000000..d328113a
--- /dev/null
+++ b/libresonic-main/src/main/java/org/libresonic/player/domain/LastFmCoverArt.java
@@ -0,0 +1,50 @@
+/*
+ * This file is part of Libresonic.
+ *
+ * Libresonic 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libresonic 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 Libresonic. If not, see .
+ *
+ * Copyright 2014 (C) Sindre Mehus
+ */
+
+package org.libresonic.player.domain;
+
+/**
+ * @author Sindre Mehus
+ * @version $Id$
+ */
+public class LastFmCoverArt {
+
+ private final String imageUrl;
+ private final String artist;
+ private final String album;
+
+ public LastFmCoverArt(String imageUrl, String artist, String album) {
+ this.imageUrl = imageUrl;
+ this.artist = artist;
+ this.album = album;
+ }
+
+ public String getImageUrl() {
+ return imageUrl;
+ }
+
+ public String getArtist() {
+ return artist;
+ }
+
+ public String getAlbum() {
+ return album;
+ }
+}
+
diff --git a/libresonic-main/src/main/java/org/libresonic/player/service/LastFmExpirationPolicy.java b/libresonic-main/src/main/java/org/libresonic/player/service/LastFmExpirationPolicy.java
new file mode 100644
index 00000000..e5a378a5
--- /dev/null
+++ b/libresonic-main/src/main/java/org/libresonic/player/service/LastFmExpirationPolicy.java
@@ -0,0 +1,49 @@
+/**
+ * This file is part of Libresonic.
+ *
+ * Libresonic 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libresonic 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 Libresonic. If not, see .
+ *
+ * Copyright 2014 (C) Sindre Mehus
+ */
+
+package org.libresonic.player.service;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import de.umass.lastfm.cache.ExpirationPolicy;
+
+/**
+ * Artist and album info is cached permanently. Everything else is cached one year.
+ *
+ * @author Sindre Mehus
+ * @version $Id$
+ */
+public class LastFmExpirationPolicy implements ExpirationPolicy {
+
+ private final static long ONE_YEAR = 12 * 30 * 24 * 3600 * 1000L;
+
+ private final Map methodToExpirationTime = new LinkedHashMap() {{
+ put("artist.getInfo", Long.MAX_VALUE); // Cache forever
+ put("album.getInfo", Long.MAX_VALUE); // Cache forever
+ put("album.search", -1L); // Don't cache
+ }};
+
+ @Override
+ public long getExpirationTime(String method, Map params) {
+ Long expirationTime = methodToExpirationTime.get(method);
+ return expirationTime == null ? ONE_YEAR : expirationTime;
+ }
+}
+
diff --git a/libresonic-main/src/main/java/org/libresonic/player/service/LastFmService.java b/libresonic-main/src/main/java/org/libresonic/player/service/LastFmService.java
index fcb75ce6..037c8d7e 100644
--- a/libresonic-main/src/main/java/org/libresonic/player/service/LastFmService.java
+++ b/libresonic-main/src/main/java/org/libresonic/player/service/LastFmService.java
@@ -22,6 +22,7 @@ package org.libresonic.player.service;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -30,13 +31,23 @@ import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
+import com.google.common.base.Function;
+import com.google.common.base.Predicates;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Lists;
+
+import de.umass.lastfm.Album;
import de.umass.lastfm.Artist;
import de.umass.lastfm.Caller;
import de.umass.lastfm.ImageSize;
import de.umass.lastfm.Track;
+import de.umass.lastfm.cache.Cache;
+
import org.libresonic.player.Logger;
import org.libresonic.player.dao.ArtistDao;
import org.libresonic.player.dao.MediaFileDao;
+import org.libresonic.player.domain.LastFmCoverArt;
+import org.libresonic.player.domain.AlbumNotes;
import org.libresonic.player.domain.ArtistBio;
import org.libresonic.player.domain.MediaFile;
import org.libresonic.player.domain.MusicFolder;
@@ -273,6 +284,96 @@ public class LastFmService {
}
}
+ /**
+ * Returns album notes and images.
+ *
+ * @param mediaFile The media file (song or album).
+ * @return Album notes.
+ */
+ public AlbumNotes getAlbumNotes(MediaFile mediaFile) {
+ return getAlbumNotes(getCanonicalArtistName(getArtistName(mediaFile)), mediaFile.getAlbumName());
+ }
+
+ /**
+ * Returns album notes and images.
+ *
+ * @param album The album.
+ * @return Album notes.
+ */
+ public AlbumNotes getAlbumNotes(org.libresonic.player.domain.Album album) {
+ return getAlbumNotes(getCanonicalArtistName(album.getArtist()), album.getName());
+ }
+
+ /**
+ * Returns album notes and images.
+ *
+ * @param artist The artist name.
+ * @param album The album name.
+ * @return Album notes.
+ */
+ private AlbumNotes getAlbumNotes(String artist, String album) {
+ if (artist == null || album == null) {
+ return null;
+ }
+ try {
+ Album info = Album.getInfo(artist, album, LAST_FM_KEY);
+ if (info == null) {
+ return null;
+ }
+ return new AlbumNotes(processWikiText(info.getWikiSummary()),
+ info.getMbid(),
+ info.getUrl(),
+ info.getImageURL(ImageSize.MEDIUM),
+ info.getImageURL(ImageSize.LARGE),
+ info.getImageURL(ImageSize.MEGA));
+ } catch (Throwable x) {
+ LOG.warn("Failed to find album notes for " + artist + " - " + album, x);
+ return null;
+ }
+ }
+
+ public List searchCoverArt(String artist, String album) {
+ if (artist == null && album == null) {
+ return Collections.emptyList();
+ }
+ try {
+ StringBuilder query = new StringBuilder();
+ if (artist != null) {
+ query.append(artist).append(" ");
+ }
+ if (album != null) {
+ query.append(album);
+ }
+
+ Collection matches = Album.search(query.toString(), LAST_FM_KEY);
+ return FluentIterable.from(matches)
+ .transform(new Function() {
+ @Override
+ public LastFmCoverArt apply(Album album) {
+ return convert(album);
+ }
+ })
+ .filter(Predicates.notNull())
+ .toList();
+ } catch (Throwable x) {
+ LOG.warn("Failed to search for cover art for " + artist + " - " + album, x);
+ return Collections.emptyList();
+ }
+ }
+
+ private LastFmCoverArt convert(Album album) {
+ String imageUrl = null;
+ for (ImageSize imageSize : Lists.reverse(Arrays.asList(ImageSize.values()))) {
+ imageUrl = StringUtils.trimToNull(album.getImageURL(imageSize));
+ if (imageUrl != null) {
+ break;
+ }
+ }
+
+ return imageUrl == null ? null : new LastFmCoverArt(imageUrl, album.getArtist(), album.getName());
+ }
+
+
private ArtistBio getArtistBio(String artistName) {
try {
if (artistName == null) {
diff --git a/libresonic-main/src/main/resources/org/libresonic/player/i18n/ResourceBundle_en.properties b/libresonic-main/src/main/resources/org/libresonic/player/i18n/ResourceBundle_en.properties
index b23e08b9..512346ff 100644
--- a/libresonic-main/src/main/resources/org/libresonic/player/i18n/ResourceBundle_en.properties
+++ b/libresonic-main/src/main/resources/org/libresonic/player/i18n/ResourceBundle_en.properties
@@ -666,11 +666,12 @@ changecoverart.title = Change cover art
changecoverart.address = Or enter image address
changecoverart.artist = Artist
changecoverart.album = Album
-changecoverart.search = Google Image Search
+changecoverart.search = Search Last.fm
changecoverart.wait = Please wait...
changecoverart.success = Image was successfully downloaded.
changecoverart.error = Failed to download image.
changecoverart.noimagesfound = No images found.
+changecoverart.courtesy = Images courtesy of Last.fm
# changeCoverArtConfirm.jsp
changeCoverArtConfirm.failed = Failed to change cover art: "{0}"
diff --git a/libresonic-main/src/main/webapp/WEB-INF/applicationContext-service.xml b/libresonic-main/src/main/webapp/WEB-INF/applicationContext-service.xml
index daa22901..45e6f641 100644
--- a/libresonic-main/src/main/webapp/WEB-INF/applicationContext-service.xml
+++ b/libresonic-main/src/main/webapp/WEB-INF/applicationContext-service.xml
@@ -274,6 +274,7 @@
+
diff --git a/libresonic-main/src/main/webapp/WEB-INF/dwr.xml b/libresonic-main/src/main/webapp/WEB-INF/dwr.xml
index 2ac93368..548027f0 100644
--- a/libresonic-main/src/main/webapp/WEB-INF/dwr.xml
+++ b/libresonic-main/src/main/webapp/WEB-INF/dwr.xml
@@ -53,6 +53,8 @@
+
+
@@ -63,4 +65,4 @@
-
\ No newline at end of file
+
diff --git a/libresonic-main/src/main/webapp/WEB-INF/jsp/changeCoverArt.jsp b/libresonic-main/src/main/webapp/WEB-INF/jsp/changeCoverArt.jsp
index 724ec653..6665cad1 100644
--- a/libresonic-main/src/main/webapp/WEB-INF/jsp/changeCoverArt.jsp
+++ b/libresonic-main/src/main/webapp/WEB-INF/jsp/changeCoverArt.jsp
@@ -6,13 +6,14 @@
">
">
">
-
-
+