package com.simplecity.amp_library.model;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.simplecity.amp_library.R;
import com.simplecity.amp_library.ShuttleApplication;
import com.simplecity.amp_library.http.HttpClient;
import com.simplecity.amp_library.lastfm.ItunesResult;
import com.simplecity.amp_library.lastfm.LastFmResult;
import com.simplecity.amp_library.sql.SqlUtils;
import com.simplecity.amp_library.sql.providers.PlayCountTable;
import com.simplecity.amp_library.sql.sqlbrite.SqlBriteUtils;
import com.simplecity.amp_library.utils.ArtworkUtils;
import com.simplecity.amp_library.utils.ComparisonUtils;
import com.simplecity.amp_library.utils.FileHelper;
import com.simplecity.amp_library.utils.StringUtils;
import java.io.File;
import java.io.InputStream;
import java.io.Serializable;
import java.util.List;
import retrofit2.Call;
import rx.Observable;
public class Song implements
Serializable,
Comparable<Song>,
ArtworkProvider,
Sortable {
private static final String TAG = "Song";
public long id;
public String name;
public String artistName;
public long artistId;
public String albumName;
public long albumId;
public long duration;
public int year;
public int dateAdded;
public long playlistSongId;
public long playlistSongPlayOrder;
public int playCount;
public long lastPlayed;
public long startTime;
private long elapsedTime = 0;
private boolean isPaused;
public int track;
public int discNumber;
public boolean isPodcast;
public String path;
public int bookMark;
public String albumArtistName;
private TagInfo tagInfo;
private String durationLabel;
private String bitrateLabel;
private String sampleRateLabel;
private String formatLabel;
private String trackNumberLabel;
private String discNumberLabel;
private String fileSizeLabel;
private String artworkKey;
private String sortKey;
public static String[] getProjection() {
return new String[]{
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST_ID,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ALBUM_ID,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.YEAR,
MediaStore.Audio.Media.TRACK,
MediaStore.Audio.Media.DATE_ADDED,
MediaStore.Audio.Media.IS_PODCAST,
MediaStore.Audio.Media.BOOKMARK,
"album_artist"
};
}
public static Query getQuery() {
return new Query.Builder()
.uri(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI)
.projection(Song.getProjection())
.selection(MediaStore.Audio.Media.IS_MUSIC + "=1 OR " + MediaStore.Audio.Media.IS_PODCAST + "=1")
.args(null)
.sort(MediaStore.Audio.Media.TRACK)
.build();
}
public Song(Cursor cursor) {
id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));
name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
artistId = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST_ID));
artistName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
albumId = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID));
albumName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));
duration = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));
year = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.YEAR));
track = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TRACK));
if (track >= 1000) {
discNumber = track / 1000;
track = track % 1000;
}
dateAdded = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATE_ADDED));
path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
albumArtistName = artistName;
if (cursor.getColumnIndex("album_artist") != -1) {
String albumArtist = cursor.getString(cursor.getColumnIndex("album_artist"));
if (albumArtist != null) {
albumArtistName = albumArtist;
}
}
isPodcast = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.IS_PODCAST)) == 1;
bookMark = cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.BOOKMARK));
//Populate the artwork key & sort key properties if null.
setSortKey();
setArtworkKey();
}
public Genre getGenre() {
Query query = Genre.getQuery();
query.uri = MediaStore.Audio.Genres.getContentUriForAudioId("external", (int) id);
return SqlUtils.createSingleQuery(ShuttleApplication.getInstance(), Genre::new, query);
}
public int getPlayCount(Context context) {
int playCount = 0;
Uri playCountUri = PlayCountTable.URI;
Uri appendedUri = ContentUris.withAppendedId(playCountUri, id);
if (appendedUri != null) {
Query query = new Query.Builder()
.uri(appendedUri)
.projection(new String[]{PlayCountTable.COLUMN_ID, PlayCountTable.COLUMN_PLAY_COUNT})
.build();
playCount = SqlUtils.createSingleQuery(context, cursor ->
cursor.getInt(cursor.getColumnIndex(PlayCountTable.COLUMN_PLAY_COUNT)), 0, query);
}
return playCount;
}
public void setStartTime() {
startTime = System.currentTimeMillis();
}
/**
* Checks whether this track has been played for at least 75% of it's duration
*
* @return true if the elapsed time is > 75% of the duration false otherwise
*/
public boolean hasPlayed() {
return getElapsedTime() != 0 && ((float) getElapsedTime() / (float) duration) > 0.75f;
}
/**
* Sets this track as 'paused' to make sure the elapsed time doesn't continue to increase
*/
public void setPaused() {
elapsedTime = elapsedTime + System.currentTimeMillis() - startTime;
isPaused = true;
}
/**
* Sets this track as 'resumed' to resume incrementing the elapsed time
*/
public void setResumed() {
startTime = System.currentTimeMillis();
isPaused = false;
}
/**
* Gets the elapsed time of this track (in millis)
*
* @return the elapsed time of this track (in millis)
*/
private long getElapsedTime() {
if (isPaused) {
return elapsedTime;
} else {
return elapsedTime + System.currentTimeMillis() - startTime;
}
}
public String getDurationLabel() {
if (durationLabel == null) {
durationLabel = StringUtils.makeTimeString(ShuttleApplication.getInstance(), duration / 1000);
}
return durationLabel;
}
public TagInfo getTagInfo() {
if (tagInfo == null) {
tagInfo = new TagInfo(path);
}
return tagInfo;
}
public String getBitrateLabel() {
if (bitrateLabel == null) {
bitrateLabel = getTagInfo().bitrate + ShuttleApplication.getInstance().getString(R.string.song_info_bitrate_suffix);
}
return bitrateLabel;
}
public String getSampleRateLabel() {
if (sampleRateLabel == null) {
sampleRateLabel = ((float) getTagInfo().sampleRate) / 1000 + ShuttleApplication.getInstance().getString(R.string.song_info_sample_rate_suffix);
}
return sampleRateLabel;
}
public String getFormatLabel() {
if (formatLabel == null) {
formatLabel = getTagInfo().format;
}
return formatLabel;
}
public String getTrackNumberLabel() {
if (trackNumberLabel == null) {
if (track == -1) {
trackNumberLabel = String.valueOf(getTagInfo().trackNumber);
} else {
trackNumberLabel = String.valueOf(track);
}
}
return trackNumberLabel;
}
public String getDiscNumberLabel() {
if (discNumberLabel == null) {
if (discNumber == -1) {
discNumberLabel = String.valueOf(getTagInfo().discNumber);
} else {
discNumberLabel = String.valueOf(discNumber);
}
}
return discNumberLabel;
}
public String getFileSizeLabel() {
if (fileSizeLabel == null) {
if (!TextUtils.isEmpty(path)) {
File file = new File(path);
fileSizeLabel = FileHelper.getHumanReadableSize(file.length());
}
}
return fileSizeLabel;
}
public Album getAlbum() {
return new Album.Builder()
.id(albumId)
.name(albumName)
.addArtist(new Artist(artistId, artistName))
.albumArtist(albumArtistName)
.year(year)
.numSongs(1)
.numDiscs(discNumber)
.lastPlayed(lastPlayed)
.dateAdded(dateAdded)
.path(path)
.songPlayCount(playCount)
.build();
}
public AlbumArtist getAlbumArtist() {
return new AlbumArtist.Builder()
.name(albumArtistName)
.album(getAlbum())
.build();
}
public Observable<Genre> getGenreObservable(Context context) {
Query query = Genre.getQuery();
query.uri = MediaStore.Audio.Genres.getContentUriForAudioId("external", (int) id);
return SqlBriteUtils.createSingleQuery(context, Genre::new, query);
}
public Genre getGenre(Context context) {
Query query = Genre.getQuery();
query.uri = MediaStore.Audio.Genres.getContentUriForAudioId("external", (int) id);
return SqlUtils.createSingleQuery(context, Genre::new, query);
}
public void share(Context context) {
final Intent intent = new Intent(Intent.ACTION_SEND).setType("audio/*");
intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file:///" + path));
context.startActivity(Intent.createChooser(intent, context.getString(R.string.share_via)));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Song song = (Song) o;
return id == song.id && artistId == song.artistId && albumId == song.albumId;
}
@Override
public int hashCode() {
int result = (int) (id ^ (id >>> 32));
result = 31 * result + (int) (artistId ^ (artistId >>> 32));
result = 31 * result + (int) (albumId ^ (albumId >>> 32));
return result;
}
@Override
public String getSortKey() {
if (sortKey == null) {
setSortKey();
}
return sortKey;
}
@Override
public void setSortKey() {
sortKey = StringUtils.keyFor(name);
}
@Override
public String getArtworkKey() {
if (artworkKey == null) setArtworkKey();
return artworkKey;
}
private void setArtworkKey() {
artworkKey = String.format("%s_%s", albumArtistName, albumName);
}
@Override
public Call<? extends LastFmResult> getLastFmArtwork() {
return HttpClient.getInstance().lastFmService.getLastFmAlbumResult(artistName, albumName);
}
@Override
public Call<ItunesResult> getItunesArtwork() {
return HttpClient.getInstance().itunesService.getItunesAlbumResult(String.format("%s %s", artistName, albumName));
}
@Override
public InputStream getMediaStoreArtwork() {
return ArtworkUtils.getMediaStoreArtwork(this);
}
@Override
public InputStream getFolderArtwork() {
return ArtworkUtils.getFolderArtwork(path);
}
@Override
public InputStream getTagArtwork() {
return ArtworkUtils.getTagArtwork(path);
}
@Override
public List<File> getFolderArtworkFiles() {
return ArtworkUtils.getAllFolderArtwork(path);
}
@Override
public String toString() {
return "\nSong{" +
"\nid='" + id +
"\nname='" + name +
"\nalbumArtistName='" + albumArtistName +
'}';
}
@Nullable
@Override
public int compareTo(@NonNull Song song) {
return ComparisonUtils.compare(getSortKey(), song.getSortKey());
}
public boolean delete() {
if (path == null) return false;
boolean success = false;
File file = new File(path);
if (file.exists()) {
success = file.delete();
}
return success;
}
}