/*
* Copyright (c) 2010, the Last.fm Java Project and Committers
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package de.umass.lastfm;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import de.umass.util.StringUtilities;
import de.umass.xml.DomElement;
/**
* Bean for Tag data and provides methods for global tags.
*
* @author Janni Kovacs
*/
public class Tag implements Comparable<Tag> {
/**
* Implementation of {@link ItemFactory} for this class
*/
static final ItemFactory<Tag> FACTORY = new TagFactory();
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss ZZZZ", Locale.ENGLISH);
private String name;
private String url;
private int count;
private boolean streamable;
private int reach;
private Date wikiLastChanged;
private String wikiSummary;
private String wikiText;
private Tag(String name) {
this.name = name;
}
public int getCount() {
return count;
}
/**
* Returns the number of taggings of this specific tag. Alias for {@link #getCount()}.
*
* @return Number of Taggings
* @see Tag#getInfo(String, String)
*/
public int getTaggings() {
return count;
}
public String getName() {
return name;
}
public String getUrl() {
return url;
}
public boolean isStreamable() {
return streamable;
}
public int getReach() {
return reach;
}
public Date getWikiLastChanged() {
return wikiLastChanged;
}
public String getWikiSummary() {
return wikiSummary;
}
public String getWikiText() {
return wikiText;
}
/**
* Returns the sum of all <code>count</code> elements in the results.
*
* @param tags a list of tags
* @return the total count of all tags
*/
public static long getTagCountSum(Collection<Tag> tags) {
long total = 0;
for (Tag topTag : tags) {
total += topTag.count;
}
return total;
}
/**
* Filters tags from the given list; retains only those tags with a count
* higher than the given percentage of the total sum as from
* {@link #getTagCountSum(Collection)}.
*
* @param tags list of tags
* @param percentage cut off percentage
* @return the filtered list of tags
*/
public static List<Tag> filter(Collection<Tag> tags, double percentage) {
ArrayList<Tag> tops = new ArrayList<Tag>();
long total = getTagCountSum(tags);
double cutOff = total / 100.0 * percentage;
for (Tag tag : tags) {
if (tag.count > cutOff) {
tops.add(tag);
}
}
return tops;
}
/**
* Search for tags similar to this one. Returns tags ranked by similarity, based on listening data.
*
* @param tag The tag name
* @param apiKey A Last.fm API key
* @return a List of <code>Tag</code>s
*/
public static Collection<Tag> getSimilar(String tag, String apiKey) {
Result result = Caller.getInstance().call("tag.getSimilar", apiKey, "tag", tag);
return ResponseBuilder.buildCollection(result, Tag.class);
}
public static Collection<Tag> getTopTags(String apiKey) {
Result result = Caller.getInstance().call("tag.getTopTags", apiKey);
return ResponseBuilder.buildCollection(result, Tag.class);
}
public static Collection<Album> getTopAlbums(String tag, String apiKey) {
Result result = Caller.getInstance().call("tag.getTopAlbums", apiKey, "tag", tag);
return ResponseBuilder.buildCollection(result, Album.class);
}
public static Collection<Track> getTopTracks(String tag, String apiKey) {
Result result = Caller.getInstance().call("tag.getTopTracks", apiKey, "tag", tag);
return ResponseBuilder.buildCollection(result, Track.class);
}
public static Collection<Artist> getTopArtists(String tag, String apiKey) {
Result result = Caller.getInstance().call("tag.getTopArtists", apiKey, "tag", tag);
return ResponseBuilder.buildCollection(result, Artist.class);
}
public static Collection<Tag> search(String tag, String apiKey) {
return search(tag, 30, apiKey);
}
public static Collection<Tag> search(String tag, int limit, String apiKey) {
Result result = Caller.getInstance().call("tag.search", apiKey, "tag", tag, "limit", String.valueOf(limit));
Collection<DomElement> children = result.getContentElement().getChild("tagmatches").getChildren("tag");
List<Tag> tags = new ArrayList<Tag>(children.size());
for (DomElement s : children) {
tags.add(FACTORY.createItemFromElement(s));
}
return tags;
}
public static Chart<Artist> getWeeklyArtistChart(String tag, String apiKey) {
return getWeeklyArtistChart(tag, null, null, -1, apiKey);
}
public static Chart<Artist> getWeeklyArtistChart(String tag, int limit, String apiKey) {
return getWeeklyArtistChart(tag, null, null, limit, apiKey);
}
public static Chart<Artist> getWeeklyArtistChart(String tag, String from, String to, int limit, String apiKey) {
return Chart.getChart("tag.getWeeklyArtistChart", "tag", tag, "artist", from, to, limit, apiKey);
}
public static LinkedHashMap<String, String> getWeeklyChartList(String tag, String apiKey) {
return Chart.getWeeklyChartList("tag.getWeeklyChartList", "tag", tag, apiKey);
}
public static Collection<Chart> getWeeklyChartListAsCharts(String tag, String apiKey) {
return Chart.getWeeklyChartListAsCharts("tag", tag, apiKey);
}
/**
* Gets the metadata for a tag.
*
* @param tag The tag name
* @param apiKey A Last.fm API key
* @return Tag metdata such as Wiki Text, reach and tag count
*/
public static Tag getInfo(String tag, String apiKey) {
return getInfo(tag, null, apiKey);
}
/**
* Gets the metadata for a tag.
*
* @param tag The tag name
* @param locale The language to fetch info in, or <code>null</code>
* @param apiKey A Last.fm API key
* @return Tag metdata such as Wiki Text, reach and tag count
*/
public static Tag getInfo(String tag, Locale locale, String apiKey) {
Map<String, String> params = new HashMap<String, String>();
params.put("tag", tag);
if (locale != null && locale.getLanguage().length() != 0) {
params.put("lang", locale.getLanguage());
}
Result result = Caller.getInstance().call("tag.getInfo", apiKey, params);
return ResponseBuilder.buildItem(result, Tag.class);
}
public int compareTo(Tag o) {
// descending order
return Double.compare(o.getCount(), this.getCount());
}
/**
* This implementation of {@link ItemFactory} creates {@link Tag} objects based on the passed xml element.
*
* @see Tag
* @see Tag#FACTORY
*/
private static class TagFactory implements ItemFactory<Tag> {
public Tag createItemFromElement(DomElement element) {
Tag t = new Tag(element.getChildText("name"));
t.url = element.getChildText("url");
if (element.hasChild("count"))
t.count = Integer.parseInt(element.getChildText("count"));
else if (element.hasChild("taggings"))
t.count = Integer.parseInt(element.getChildText("taggings"));
if (element.hasChild("reach"))
t.reach = Integer.parseInt(element.getChildText("reach"));
if (element.hasChild("streamable"))
t.streamable = StringUtilities.convertToBoolean(element.getChildText("streamable"));
// wiki
DomElement wiki = element.getChild("wiki");
if (wiki != null) {
String publishedText = wiki.getChildText("published");
try {
t.wikiLastChanged = DATE_FORMAT.parse(publishedText);
} catch (ParseException e) {
// try parsing it with current locale
try {
DateFormat clFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss ZZZZ", Locale.getDefault());
t.wikiLastChanged = clFormat.parse(publishedText);
} catch (ParseException e2) {
// cannot parse date, wrong locale. wait for last.fm to fix.
}
}
t.wikiSummary = wiki.getChildText("summary");
t.wikiText = wiki.getChildText("content");
}
return t;
}
}
}