/***************************************************************************
* Copyright 2005-2009 Last.fm Ltd. *
* Portions contributed by Casey Link, Lukasz Wisniewski, *
* Mike Jennings, and Michael Novak Jr. *
* *
* 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 *
* (at your option) 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., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
package fm.last.android.scrobbler;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.FileHandler;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ComponentName;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import fm.last.android.utils.AsyncTaskEx;
import android.os.IBinder;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.widget.Toast;
import fm.last.android.AndroidLastFmServerFactory;
import fm.last.android.LastFMApplication;
import fm.last.android.LastFm;
import fm.last.android.R;
import fm.last.android.RadioWidgetProvider;
import fm.last.android.db.ScrobblerQueueDao;
import fm.last.api.LastFmServer;
import fm.last.api.RadioTrack;
import fm.last.api.Session;
import fm.last.api.WSError;
/**
* A Last.fm scrobbler for Android
*
* @author Sam Steele <sam@last.fm>
*
* This is a scrobbler that can scrobble both our radio player as well
* as the built-in media player and other 3rd party apps that broadcast
* fm.last.android.metachanged notifications. We can't rely on
* com.android.music.metachanged due to a bug in the built-in media
* player that does not broadcast this notification when playing the
* first track, only when starting the next track.
*
* Scrobbles and Now Playing data are serialized between launches, and
* will be sent when the track or network state changes. This service
* has a very short lifetime and is only started for a few seconds at a
* time when there's work to be done. This server is started when music
* state or network state change.
*
* Scrobbles are submitted to the server after Now Playing info is sent,
* or when a network connection becomes available.
*
* Sample code for a 3rd party to integrate with us is located at
* http://wiki.github.com/c99koder/lastfm-android/scrobbler-interface
*
*/
public class ScrobblerService extends Service {
private Session mSession;
public static final String LOVE = "fm.last.android.LOVE";
public static final String BAN = "fm.last.android.BAN";
private Lock mScrobblerLock = new ReentrantLock();
SubmitTracksTask mSubmissionTask = null;
NowPlayingTask mNowPlayingTask = null;
ClearNowPlayingTask mClearNowPlayingTask = null;
ScrobblerQueueEntry mCurrentTrack = null;
public static final String META_CHANGED = "fm.last.android.metachanged";
public static final String PLAYBACK_FINISHED = "fm.last.android.playbackcomplete";
public static final String PLAYBACK_STATE_CHANGED = "fm.last.android.playstatechanged";
public static final String STATION_CHANGED = "fm.last.android.stationchanged";
public static final String PLAYBACK_ERROR = "fm.last.android.playbackerror";
public static final String PLAYBACK_PAUSED = "fm.last.android.playbackpaused";
public static final String UNKNOWN = "fm.last.android.unknown";
private Logger logger;
private String player = null;
@Override
public void onCreate() {
super.onCreate();
logger = Logger.getLogger("fm.last.android.scrobbler");
try {
if (logger.getHandlers().length < 1) {
FileHandler handler = new FileHandler(getFilesDir().getAbsolutePath() + "/scrobbler.log", 4096, 1, true);
handler.setFormatter(new SimpleFormatter());
logger.addHandler(handler);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mSession = LastFMApplication.getInstance().session;
if (mSession == null || !PreferenceManager.getDefaultSharedPreferences(this).getBoolean("scrobble", true)) {
// User not authenticated, shutting down...
stopSelf();
return;
}
try {
ScrobblerQueueEntry entry = ScrobblerQueueDao.getInstance().loadCurrentTrack();
if (entry != null) {
if (entry.startTime > System.currentTimeMillis()) {
logger.info("Serialized start time is in the future! ignoring");
}
else {
mCurrentTrack = entry;
}
}
} catch (Exception e) {
mCurrentTrack = null;
}
try {
if (getFileStreamPath("queue.dat").exists()) {
logger.info("Migrating old scrobble queue");
FileInputStream fileStream = openFileInput("queue.dat");
ObjectInputStream objectStream = new ObjectInputStream(fileStream);
Object obj = objectStream.readObject();
if (obj instanceof Integer) {
Integer count = (Integer) obj;
for (int i = 0; i < count.intValue(); i++) {
obj = objectStream.readObject();
if (obj != null && obj instanceof ScrobblerQueueEntry) {
try {
ScrobblerQueueDao.getInstance().addToQueue((ScrobblerQueueEntry) obj);
} catch (IllegalStateException e) {
break; //The queue is full!
}
}
}
logger.info("Imported " + count + " tracks");
}
objectStream.close();
fileStream.close();
deleteFile("queue.dat");
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDestroy() {
super.onDestroy();
try {
Intent intent = new Intent("fm.last.android.scrobbler.FLUSH");
PendingIntent alarmIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
am.cancel(alarmIntent); // cancel any pending alarm intents
if (ScrobblerQueueDao.getInstance().getQueueSize() > 0) {
// schedule an alarm to wake the device and try again in an hour
logger.info("Scrobbles are pending, will retry in an hour");
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 3600000, alarmIntent);
}
ScrobblerQueueDao.getInstance().saveCurrentTrack(mCurrentTrack);
} catch (Exception e) {
logger.severe("Unable to save current track state");
e.printStackTrace();
}
}
/*
* This will check the distance between the start time and the current time
* to determine whether this is a skip or a played track, and will add it to
* our scrobble queue.
*/
public void enqueueCurrentTrack() {
if (mCurrentTrack != null) {
long playTime = (System.currentTimeMillis() / 1000) - mCurrentTrack.startTime;
int scrobble_perc = PreferenceManager.getDefaultSharedPreferences(this).getInt("scrobble_percentage", 50);
int track_duration = (int) (mCurrentTrack.duration / 1000);
scrobble_perc = (int)(track_duration * (scrobble_perc * 0.01));
boolean played = (playTime > 30 && playTime > scrobble_perc) || (playTime > 240);
if (played || mCurrentTrack.rating.length() > 0) {
logger.info("Enqueuing track (Rating:" + mCurrentTrack.rating + ")");
boolean queued = ScrobblerQueueDao.getInstance().addToQueue(mCurrentTrack);
if (!queued) {
logger.severe("Scrobble queue is full! Have " + ScrobblerQueueDao.MAX_QUEUE_SIZE + " scrobbles!");
}
}
mCurrentTrack = null;
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return START_NOT_STICKY;
}
@Override
public void onStart(Intent intent, int startId) {
final Intent i = intent;
/*
* The Android media player doesn't send a META_CHANGED notification for
* the first track, so we'll have to catch PLAYBACK_STATE_CHANGED and
* check to see whether the player is currently playing. We'll then send
* our own META_CHANGED intent to the scrobbler.
*/
if (intent.getAction().equals("com.android.music.playstatechanged") || intent.getAction().equals("com.android.music.metachanged")
|| intent.getAction().equals("com.android.music.queuechanged")) {
long id = -1;
try {
id = intent.getLongExtra("id", -1);
} catch (Exception e) {
//ignore this
}
if(id == -1)
id = intent.getIntExtra("id", -1);
if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("scrobble_music_player", true) && id != -1) {
if(RadioWidgetProvider.isAndroidMusicInstalled(this)) {
try {
bindService(new Intent().setClassName(RadioWidgetProvider.getAndroidMusicPackageName(this), "com.android.music.MediaPlaybackService"), new ServiceConnection() {
public void onServiceConnected(ComponentName comp, IBinder binder) {
com.android.music.IMediaPlaybackService s = com.android.music.IMediaPlaybackService.Stub.asInterface(binder);
try {
if (s.isPlaying()) {
i.setAction(META_CHANGED);
i.putExtra("position", s.position());
i.putExtra("duration", s.duration());
handleIntent(i);
} else { // Media player was paused
mCurrentTrack = null;
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.cancel(1338);
stopSelf();
}
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
LastFMApplication.getInstance().unbindService(this);
} catch (IllegalArgumentException e) {
}
}
public void onServiceDisconnected(ComponentName comp) {
}
}, 0);
} catch (Exception e) {
intentFromMediaDB(i);
}
} else {
intentFromMediaDB(i);
}
} else {
// Clear the current track in case the user has disabled
// scrobbling of the media player
// during the middle of this track.
mCurrentTrack = null;
stopIfReady();
}
} else if ((intent.getAction().equals("com.htc.music.playstatechanged") && intent.getIntExtra("id", -1) != -1)
|| intent.getAction().equals("com.htc.music.metachanged")) {
if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("scrobble_music_player", true)) {
bindService(new Intent().setClassName("com.htc.music", "com.htc.music.MediaPlaybackService"), new ServiceConnection() {
public void onServiceConnected(ComponentName comp, IBinder binder) {
com.htc.music.IMediaPlaybackService s = com.htc.music.IMediaPlaybackService.Stub.asInterface(binder);
try {
if (s.isPlaying()) {
i.setAction(META_CHANGED);
i.putExtra("position", s.position());
i.putExtra("duration", s.duration());
i.putExtra("track", s.getTrackName());
i.putExtra("artist", s.getArtistName());
i.putExtra("album", s.getAlbumName());
handleIntent(i);
} else { // Media player was paused
mCurrentTrack = null;
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.cancel(1338);
stopSelf();
}
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
LastFMApplication.getInstance().unbindService(this);
} catch (IllegalArgumentException e) {
}
}
public void onServiceDisconnected(ComponentName comp) {
}
}, 0);
} else {
// Clear the current track in case the user has disabled
// scrobbling of the media player
// during the middle of this track.
mCurrentTrack = null;
stopIfReady();
}
} else if(intent.getAction().equals("com.adam.aslfms.notify.playstatechanged")) {
int state = intent.getIntExtra("state", -1);
if(state > -1) {
if(state < 2) { //start or resume
i.setAction(META_CHANGED);
//convert the duration from int to long
long duration = intent.getIntExtra("duration", 0);
i.removeExtra("duration");
i.putExtra("duration", duration * 1000);
} else if(state == 2) { //pause
i.setAction(PLAYBACK_PAUSED);
} else if(state == 3) { //complete
i.setAction(PLAYBACK_FINISHED);
}
handleIntent(i);
}
} else if(intent.getAction().equals("net.jjc1138.android.scrobbler.action.MUSIC_STATUS")) {
intentFromMediaDB(intent);
} else { //
handleIntent(i);
}
}
public void intentFromMediaDB(Intent intent) {
final Intent i = intent;
boolean playing = false;
SharedPreferences settings = getSharedPreferences(LastFm.PREFS, 0);
boolean mediaPlayerIsPlaying = settings.getBoolean("mediaPlayerIsPlaying", false);
if(intent.getAction().endsWith("metachanged"))
playing = mediaPlayerIsPlaying;
else if(intent.getBooleanExtra("playing", false))
playing = true;
else if(intent.getBooleanExtra("playstate", false) || (intent.getSerializableExtra("playstate") == null && intent.getBooleanExtra("playing", true)))
playing = true;
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("mediaPlayerIsPlaying", playing);
editor.commit();
if(!playing) {
i.setAction(PLAYBACK_FINISHED);
} else {
i.setAction(META_CHANGED);
long id = -1;
try {
id = intent.getIntExtra("id", -1);
} catch (Exception e) {
//ignore this
}
if(id == -1)
id = intent.getLongExtra("id", -1);
if(id != -1) {
final String[] columns = new String[] {
MediaStore.Audio.AudioColumns.ARTIST,
MediaStore.Audio.AudioColumns.TITLE,
MediaStore.Audio.AudioColumns.DURATION,
MediaStore.Audio.AudioColumns.ALBUM,
MediaStore.Audio.AudioColumns.TRACK, };
Cursor cur = getContentResolver().query(
ContentUris.withAppendedId(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
id), columns, null, null, null);
if (cur == null) {
logger.severe("could not open cursor to media in media store");
return;
}
try {
if (!cur.moveToFirst()) {
//Search internal storage if external storage fails
cur = getContentResolver().query(
ContentUris.withAppendedId(
MediaStore.Audio.Media.INTERNAL_CONTENT_URI,
id), columns, null, null, null);
}
if (!cur.moveToFirst()) {
logger.info("no such media in media store: " + id);
cur.close();
//This isn't fatal if the intent still contains the artist and track,
//however without the duration, the track will be scrobbled regardless of whether
//it's passed the scrobble point or not. Also, Now Playing requests require a
//duration so they expire properly on the site, so they wont appear.
if(i.getStringExtra("artist") == null || i.getStringExtra("track") == null)
return;
else
i.putExtra("duration", 0);
} else {
String artist = cur.getString(cur.getColumnIndex(MediaStore.Audio.AudioColumns.ARTIST));
if(i.getStringExtra("artist") == null)
i.putExtra("artist", artist);
String track = cur.getString(cur.getColumnIndex(MediaStore.Audio.AudioColumns.TITLE));
if(i.getStringExtra("track") == null)
i.putExtra("track", track);
String album = cur.getString(cur.getColumnIndex(MediaStore.Audio.AudioColumns.ALBUM));
if(i.getStringExtra("album") == null)
i.putExtra("album", album);
long duration = cur.getLong(cur.getColumnIndex(MediaStore.Audio.AudioColumns.DURATION));
if (duration != 0) {
i.putExtra("duration", duration);
}
}
} finally {
cur.close();
}
} else {
//convert the duration from int to long
long duration = intent.getIntExtra("secs", 0);
i.removeExtra("secs");
i.putExtra("duration", duration * 1000);
}
}
handleIntent(i);
}
public void handleIntent(Intent intent) {
if (intent.getAction().equals(META_CHANGED)) {
long startTime = System.currentTimeMillis() / 1000;
long position = intent.getLongExtra("position", 0) / 1000;
if (position > 0) {
startTime -= position;
}
String title = intent.getStringExtra("track");
String artist = intent.getStringExtra("artist");
player = intent.getStringExtra("player");
if (mCurrentTrack != null) {
int scrobble_perc = PreferenceManager.getDefaultSharedPreferences(this).getInt("scrobble_percentage", 50);
long scrobblePoint = mCurrentTrack.duration * (scrobble_perc / 100);
if (scrobblePoint > 240000)
scrobblePoint = 240000;
if (startTime < (mCurrentTrack.startTime + scrobblePoint) && mCurrentTrack.title.equals(title) && mCurrentTrack.artist.equals(artist)) {
logger.warning("Ignoring duplicate scrobble");
stopIfReady();
return;
}
enqueueCurrentTrack();
}
mCurrentTrack = new ScrobblerQueueEntry();
mCurrentTrack.startTime = startTime;
mCurrentTrack.title = title;
mCurrentTrack.artist = artist;
mCurrentTrack.album = intent.getStringExtra("album");
mCurrentTrack.duration = intent.getLongExtra("duration", 0);
if(mCurrentTrack.duration == 0)
mCurrentTrack.duration = (long)intent.getIntExtra("duration", 0);
if (mCurrentTrack.title == null || mCurrentTrack.artist == null) {
mCurrentTrack = null;
stopIfReady();
return;
}
String auth = intent.getStringExtra("trackAuth");
if (auth != null && auth.length() > 0) {
mCurrentTrack.trackAuth = auth;
}
boolean scrobbleRealtime = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("scrobble_realtime", true);
if (scrobbleRealtime || auth != null) {
ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
if (ni != null) {
boolean scrobbleWifiOnly = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("scrobble_wifi_only", false);
if (cm.getBackgroundDataSetting() && (!scrobbleWifiOnly || (scrobbleWifiOnly && ni.getType() == ConnectivityManager.TYPE_WIFI) || auth != null && mNowPlayingTask == null)) {
mNowPlayingTask = new NowPlayingTask(mCurrentTrack.toRadioTrack());
mNowPlayingTask.execute();
}
}
}
if (auth == null) {
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.cancel(1338);
Notification notification = new Notification(R.drawable.as_statusbar, getString(R.string.scrobbler_ticker_text, mCurrentTrack.title,
mCurrentTrack.artist), System.currentTimeMillis());
Intent metaIntent = new Intent(this, fm.last.android.activity.Metadata.class);
metaIntent.putExtra("artist", mCurrentTrack.artist);
metaIntent.putExtra("track", mCurrentTrack.title);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, metaIntent, PendingIntent.FLAG_UPDATE_CURRENT);
String info = mCurrentTrack.title + " - " + mCurrentTrack.artist;
notification.setLatestEventInfo(this, getString(R.string.scrobbler_info_title), info, contentIntent);
notification.flags |= Notification.FLAG_ONGOING_EVENT;
nm.notify(1338, notification);
}
}
if (intent.getAction().equals(PLAYBACK_FINISHED) || intent.getAction().equals("com.android.music.playbackcomplete")
|| intent.getAction().equals("com.htc.music.playbackcomplete")) {
enqueueCurrentTrack();
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.cancel(1338);
}
if (intent.getAction().equals(PLAYBACK_PAUSED) && mCurrentTrack != null) {
if(intent.getLongExtra("position", 0) > 0 || !intent.hasExtra("position")) { //Work-around for buggy DoubleTwist player
mClearNowPlayingTask = new ClearNowPlayingTask(mCurrentTrack.toRadioTrack());
mClearNowPlayingTask.execute();
mCurrentTrack = null;
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.cancel(1338);
}
}
if (intent.getAction().equals(LOVE) && mCurrentTrack != null) {
mCurrentTrack.rating = "L";
Toast.makeText(this, getString(R.string.scrobbler_trackloved), Toast.LENGTH_SHORT).show();
}
if (intent.getAction().equals(BAN) && mCurrentTrack != null) {
mCurrentTrack.rating = "B";
Toast.makeText(this, getString(R.string.scrobbler_trackbanned), Toast.LENGTH_SHORT).show();
}
if (intent.getAction().equals("fm.last.android.scrobbler.FLUSH") || mNowPlayingTask == null) {
ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
if(ni != null) {
boolean scrobbleWifiOnly = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("scrobble_wifi_only", false);
if (cm.getBackgroundDataSetting() && (!scrobbleWifiOnly || (scrobbleWifiOnly && ni.getType() == ConnectivityManager.TYPE_WIFI))) {
int queueSize = ScrobblerQueueDao.getInstance().getQueueSize();
if (queueSize > 0 && mSubmissionTask == null) {
mSubmissionTask = new SubmitTracksTask();
mSubmissionTask.execute();
}
}
}
}
stopIfReady();
}
public void stopIfReady() {
if (mSubmissionTask == null && mNowPlayingTask == null && mClearNowPlayingTask == null)
stopSelf();
}
/*
* We don't currently offer any bindable functions. Perhaps in the future we
* can add a function to get the queue size / last scrobbler result / etc.
*/
@Override
public IBinder onBind(Intent intent) {
return null;
}
private class ClearNowPlayingTask extends AsyncTaskEx<Void, Void, Boolean> {
RadioTrack mTrack;
public ClearNowPlayingTask(RadioTrack track) {
mTrack = track;
}
@Override
public Boolean doInBackground(Void... params) {
boolean success = false;
LastFmServer server = AndroidLastFmServerFactory.getServer();
try {
mScrobblerLock.lock();
server.removeNowPlaying(mTrack.getCreator(), mTrack.getTitle(), mTrack.getAlbum(), new Integer(mTrack.getDuration() / 1000), ScrobblerService.this.player, mSession.getKey());
success = true;
} catch (Exception e) {
e.printStackTrace();
success = false;
} catch (WSError e) {
e.printStackTrace();
success = false;
} finally {
mScrobblerLock.unlock();
}
return success;
}
@Override
public void onPostExecute(Boolean result) {
mClearNowPlayingTask = null;
stopIfReady();
}
}
private class NowPlayingTask extends AsyncTaskEx<Void, Void, Boolean> {
RadioTrack mTrack;
public NowPlayingTask(RadioTrack track) {
mTrack = track;
}
@Override
public void onPreExecute() {
/* If we have any scrobbles in the queue, try to send them now */
if (mSubmissionTask == null && ScrobblerQueueDao.getInstance().getQueueSize() > 0) {
mSubmissionTask = new SubmitTracksTask();
mSubmissionTask.execute();
}
}
@Override
public Boolean doInBackground(Void... params) {
boolean success = false;
LastFmServer server = AndroidLastFmServerFactory.getServer();
try {
mScrobblerLock.lock();
server.updateNowPlaying(mTrack.getCreator(), mTrack.getTitle(), mTrack.getAlbum(), new Integer(mTrack.getDuration() / 1000), ScrobblerService.this.player, mSession.getKey());
success = true;
} catch (Exception e) {
e.printStackTrace();
success = false;
} catch (WSError e) {
e.printStackTrace();
success = false;
} finally {
mScrobblerLock.unlock();
}
return success;
}
@Override
public void onPostExecute(Boolean result) {
if (mCurrentTrack != null)
mCurrentTrack.postedNowPlaying = result;
mNowPlayingTask = null;
stopIfReady();
}
}
private class SubmitTracksTask extends AsyncTaskEx<Void, Void, Boolean> {
@Override
public Boolean doInBackground(Void... p) {
boolean success = false;
mScrobblerLock.lock();
logger.info("Going to submit " + ScrobblerQueueDao.getInstance().getQueueSize() + " tracks");
LastFmServer server = AndroidLastFmServerFactory.getServer();
ScrobblerQueueEntry e = null;
while ((e = ScrobblerQueueDao.getInstance().nextQueueEntry()) != null) {
try {
success = false;
if (e != null && e.title != null && e.artist != null && e.toRadioTrack() != null) {
if (e.rating.equals("L")) {
server.loveTrack(e.artist, e.title, mSession.getKey());
}
if (e.rating.equals("B")) {
if(e.trackAuth.length() == 0) {
//Local tracks can't be banned, so drop them
logger.info("Removing banned local track from queue");
ScrobblerQueueDao.getInstance().removeFromQueue(e);
continue;
}
server.banTrack(e.artist, e.title, mSession.getKey());
}
if(!e.rating.equals("B") && !e.rating.equals("S"))
server.scrobbleTrack(e.artist, e.title, e.album, e.startTime, (int)(e.duration / 1000), ScrobblerService.this.player, e.trackAuth, mSession.getKey());
success = true;
}
}
catch (Exception ex) {
logger.severe("Unable to submit track: " + ex.toString());
ex.printStackTrace();
success = false;
}
catch (WSError ex) {
logger.severe("Unable to submit track: " + ex.toString());
ex.printStackTrace();
success = true; //Remove the track from the queue
}
if(success) {
ScrobblerQueueDao.getInstance().removeFromQueue(e);
}
else {
logger.severe("Scrobble submission aborted");
break;
}
}
mScrobblerLock.unlock();
return success;
}
@Override
public void onPostExecute(Boolean result) {
mSubmissionTask = null;
stopIfReady();
}
}
}