Implemented showing artist names in song lists (#281)
* Song lists for artist, album, and overall now shows the artist name for each individual song * Added display artist column to songs table. This required a DB upgrade and users should do a refresh for music items to be able to see the display artist in the song lists.
This commit is contained in:
parent
f0cd9a67f8
commit
eedd1e99b4
|
@ -31,6 +31,7 @@ import org.junit.Test;
|
|||
import org.junit.runner.RunWith;
|
||||
import org.xbmc.kore.host.HostInfo;
|
||||
import org.xbmc.kore.provider.MediaContract;
|
||||
import org.xbmc.kore.provider.MediaProvider;
|
||||
import org.xbmc.kore.testhelpers.Database;
|
||||
import org.xbmc.kore.testhelpers.TestUtils;
|
||||
import org.xbmc.kore.testhelpers.Utils;
|
||||
|
@ -161,7 +162,7 @@ public class MediaProviderMusicTest {
|
|||
public void queryAlbumSongsTest() {
|
||||
Uri uri = MediaContract.Songs.buildAlbumSongsListUri(hostInfo.getId(), TestValues.Album.albumId);
|
||||
|
||||
Cursor cursor = contentResolver.query(uri, new String[] {MediaContract.Songs.SONGID}, null, null, null);
|
||||
Cursor cursor = contentResolver.query(uri, new String[] {MediaProvider.Qualified.SONGS_SONGID}, null, null, null);
|
||||
|
||||
assertNotNull(cursor);
|
||||
assertEquals("cursor size ", 17, cursor.getCount());
|
||||
|
|
|
@ -571,7 +571,7 @@ public class MediaContract {
|
|||
String HOST_ID = "host_id";
|
||||
String ALBUMID = "albumid";
|
||||
String SONGID = "songid";
|
||||
|
||||
String DISPLAYARTIST = "displayartist";
|
||||
String DURATION = "duration";
|
||||
String THUMBNAIL = "thumbnail";
|
||||
String FILE = "file";
|
||||
|
|
|
@ -32,7 +32,9 @@ public class MediaDatabase extends SQLiteOpenHelper {
|
|||
|
||||
private static final String DB_NAME = "xbmc.sqlite";
|
||||
private static final int DB_VERSION_PRE_EVENT_SERVER = 4,
|
||||
DB_VERSION_PRE_SONG_ARTISTS = 5, DB_VERSION = 6;
|
||||
DB_VERSION_PRE_SONG_ARTISTS = 5,
|
||||
DB_VERSION_PRE_SONG_DISPLAY_ARTIST = 6,
|
||||
DB_VERSION = 7;
|
||||
|
||||
/**
|
||||
* Tables exposed
|
||||
|
@ -94,7 +96,7 @@ public class MediaDatabase extends SQLiteOpenHelper {
|
|||
* Join to get Songs for an Artist or Album with artist info and album info only if available
|
||||
*/
|
||||
String SONGS_FOR_ARTIST_AND_OR_ALBUM_JOIN =
|
||||
SONG_ARTISTS + " JOIN " + SONGS + " ON " +
|
||||
SONGS + " JOIN " + SONG_ARTISTS + " ON " +
|
||||
SONG_ARTISTS + "." + MediaContract.SongArtists.HOST_ID + "=" + SONGS + "." + MediaContract.Songs.HOST_ID +
|
||||
" AND " +
|
||||
SONG_ARTISTS + "." + MediaContract.SongArtists.SONGID + "=" + SONGS + "." + MediaContract.Songs.SONGID +
|
||||
|
@ -102,10 +104,14 @@ public class MediaDatabase extends SQLiteOpenHelper {
|
|||
SONG_ARTISTS + "." + MediaContract.SongArtists.HOST_ID + "=" + ARTISTS + "." + MediaContract.Artists.HOST_ID +
|
||||
" AND " +
|
||||
SONG_ARTISTS + "." + MediaContract.SongArtists.ARTISTID + "=" + ARTISTS + "." + MediaContract.Artists.ARTISTID +
|
||||
" LEFT JOIN " + ALBUM_ARTISTS + " ON " +
|
||||
SONG_ARTISTS + "." + MediaContract.SongArtists.HOST_ID + "=" + ALBUM_ARTISTS + "." + MediaContract.AlbumArtists.HOST_ID +
|
||||
" AND " +
|
||||
SONGS + "." + MediaContract.Songs.ALBUMID + "=" + ALBUM_ARTISTS + "." + MediaContract.AlbumArtists.ALBUMID +
|
||||
" LEFT JOIN " + ALBUMS + " ON " +
|
||||
SONG_ARTISTS + "." + MediaContract.SongArtists.HOST_ID + "=" + ALBUMS + "." + MediaContract.Albums.HOST_ID +
|
||||
" AND " +
|
||||
SONGS + "." + MediaContract.Songs.ALBUMID + "=" + ALBUMS + "." + MediaContract.Albums.ALBUMID;
|
||||
ALBUM_ARTISTS + "." + MediaContract.AlbumArtists.ALBUMID + "=" + ALBUMS + "." + MediaContract.Albums.ALBUMID;
|
||||
}
|
||||
|
||||
|
||||
|
@ -355,6 +361,7 @@ public class MediaDatabase extends SQLiteOpenHelper {
|
|||
MediaContract.SongsColumns.FILE + " TEXT, " +
|
||||
MediaContract.SongsColumns.TRACK + " INTEGER, " +
|
||||
MediaContract.SongsColumns.TITLE + " TEXT, " +
|
||||
MediaContract.SongsColumns.DISPLAYARTIST + " TEXT, " +
|
||||
"UNIQUE (" +
|
||||
MediaContract.SongsColumns.HOST_ID + ", " +
|
||||
MediaContract.SongsColumns.ALBUMID + ", " +
|
||||
|
@ -452,6 +459,7 @@ public class MediaDatabase extends SQLiteOpenHelper {
|
|||
db.execSQL(buildHostsDeleteTrigger(Tables.SONGS, MediaContract.SongsColumns.HOST_ID));
|
||||
db.execSQL(buildHostsDeleteTrigger(Tables.AUDIO_GENRES, MediaContract.AudioGenresColumns.HOST_ID));
|
||||
db.execSQL(buildHostsDeleteTrigger(Tables.ALBUM_ARTISTS, MediaContract.AlbumArtistsColumns.HOST_ID));
|
||||
db.execSQL(buildHostsDeleteTrigger(Tables.SONG_ARTISTS, MediaContract.SongArtistsColumns.HOST_ID));
|
||||
db.execSQL(buildHostsDeleteTrigger(Tables.ALBUM_GENRES, MediaContract.AlbumGenresColumns.HOST_ID));
|
||||
db.execSQL(buildHostsDeleteTrigger(Tables.MUSIC_VIDEOS, MediaContract.MusicVideosColumns.HOST_ID));
|
||||
|
||||
|
@ -478,6 +486,10 @@ public class MediaDatabase extends SQLiteOpenHelper {
|
|||
" INTEGER DEFAULT " + HostInfo.DEFAULT_EVENT_SERVER_PORT + ";");
|
||||
case DB_VERSION_PRE_SONG_ARTISTS:
|
||||
createSongArtistsTable(db);
|
||||
case DB_VERSION_PRE_SONG_DISPLAY_ARTIST:
|
||||
db.execSQL("ALTER TABLE " + Tables.SONGS +
|
||||
" ADD COLUMN " + MediaContract.SongsColumns.DISPLAYARTIST +
|
||||
" TEXT;");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ import android.database.Cursor;
|
|||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.net.Uri;
|
||||
import android.provider.BaseColumns;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.xbmc.kore.utils.LogUtils;
|
||||
import org.xbmc.kore.utils.SelectionBuilder;
|
||||
|
@ -671,8 +670,9 @@ public class MediaProvider extends ContentProvider {
|
|||
.mapToTable(MediaContract.Songs.SONGID, MediaDatabase.Tables.SONGS)
|
||||
.mapToTable(MediaContract.Songs.TITLE, MediaDatabase.Tables.SONGS)
|
||||
.mapToTable(MediaContract.Songs.ALBUMID, MediaDatabase.Tables.SONGS)
|
||||
.mapToTable(MediaContract.Songs.UPDATED, MediaDatabase.Tables.SONGS)
|
||||
.mapToTable(MediaContract.Songs.THUMBNAIL, MediaDatabase.Tables.SONGS)
|
||||
.mapToTable(MediaContract.Songs.DISPLAYARTIST, MediaDatabase.Tables.SONGS)
|
||||
.mapToTable(MediaContract.AlbumArtists.ARTISTID, MediaDatabase.Tables.ALBUM_ARTISTS)
|
||||
.mapToTable(MediaContract.SongArtists.ARTISTID, MediaDatabase.Tables.SONG_ARTISTS)
|
||||
.where(Qualified.SONGS_HOST_ID + "=?", hostId)
|
||||
.groupBy(Qualified.SONGS_SONGID);
|
||||
|
@ -681,8 +681,8 @@ public class MediaProvider extends ContentProvider {
|
|||
final String hostId = MediaContract.Hosts.getHostId(uri);
|
||||
final String albumId = MediaContract.Albums.getAlbumId(uri);
|
||||
return builder.table(MediaDatabase.Tables.SONGS)
|
||||
.where(MediaContract.Songs.HOST_ID + "=?", hostId)
|
||||
.where(MediaContract.Songs.ALBUMID + "=?", albumId);
|
||||
.where(Qualified.SONGS_HOST_ID + "=?", hostId)
|
||||
.where(Qualified.SONGS_ALBUMID + "=?", albumId);
|
||||
}
|
||||
case SONGS_ID: {
|
||||
final String hostId = MediaContract.Hosts.getHostId(uri);
|
||||
|
@ -737,11 +737,14 @@ public class MediaProvider extends ContentProvider {
|
|||
.mapToTable(MediaContract.Songs.SONGID, MediaDatabase.Tables.SONGS)
|
||||
.mapToTable(MediaContract.Songs.TITLE, MediaDatabase.Tables.SONGS)
|
||||
.mapToTable(MediaContract.Songs.ALBUMID, MediaDatabase.Tables.SONGS)
|
||||
.mapToTable(MediaContract.Songs.UPDATED, MediaDatabase.Tables.SONGS)
|
||||
.mapToTable(MediaContract.Songs.THUMBNAIL, MediaDatabase.Tables.SONGS)
|
||||
.mapToTable(MediaContract.Songs.DISPLAYARTIST, MediaDatabase.Tables.SONGS)
|
||||
.mapToTable(MediaContract.AlbumArtists.ARTISTID, MediaDatabase.Tables.ALBUM_ARTISTS)
|
||||
.mapToTable(MediaContract.SongArtists.ARTISTID, MediaDatabase.Tables.SONG_ARTISTS)
|
||||
.where(Qualified.SONG_ARTISTS_HOST_ID + "=?", hostId)
|
||||
.where(Qualified.SONG_ARTISTS_ARTISTID + "=?", artistId);
|
||||
.where(Qualified.SONG_ARTISTS_ARTISTID + "=?"
|
||||
+ " OR " +
|
||||
Qualified.ALBUM_ARTISTS_ARTISTID + "=?", artistId, artistId)
|
||||
.groupBy(Qualified.SONGS_ID);
|
||||
}
|
||||
case ALBUM_ARTISTS_LIST: {
|
||||
// Artists for Album
|
||||
|
@ -806,6 +809,14 @@ public class MediaProvider extends ContentProvider {
|
|||
* parent {@link MediaDatabase.Tables}. Used when needed to work around SQL ambiguity.
|
||||
*/
|
||||
public interface Qualified {
|
||||
String ALBUMS_TITLE =
|
||||
MediaDatabase.Tables.ALBUMS + "." + MediaContract.Albums.TITLE;
|
||||
String ALBUMS_GENRE =
|
||||
MediaDatabase.Tables.ALBUMS + "." + MediaContract.Albums.GENRE;
|
||||
String ALBUMS_YEAR =
|
||||
MediaDatabase.Tables.ALBUMS + "." + MediaContract.Albums.YEAR;
|
||||
String ALBUMS_THUMBNAIL =
|
||||
MediaDatabase.Tables.ALBUMS + "." + MediaContract.Albums.THUMBNAIL;
|
||||
String ALBUM_ARTISTS_HOST_ID =
|
||||
MediaDatabase.Tables.ALBUM_ARTISTS + "." + MediaContract.AlbumArtists.HOST_ID;
|
||||
String ALBUM_ARTISTS_ARTISTID =
|
||||
|
@ -818,10 +829,24 @@ public class MediaProvider extends ContentProvider {
|
|||
MediaDatabase.Tables.ALBUM_GENRES + "." + MediaContract.AlbumGenres.GENREID;
|
||||
String ALBUM_GENRES_ALBUMID =
|
||||
MediaDatabase.Tables.ALBUM_GENRES + "." + MediaContract.AlbumGenres.ALBUMID;
|
||||
String SONGS_ID =
|
||||
MediaDatabase.Tables.SONGS + "." + MediaContract.Songs._ID;
|
||||
String SONGS_TRACK =
|
||||
MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.TRACK;
|
||||
String SONGS_DURATION =
|
||||
MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.DURATION;
|
||||
String SONGS_FILE =
|
||||
MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.FILE;
|
||||
String SONGS_HOST_ID =
|
||||
MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.HOST_ID;
|
||||
String SONGS_SONGID =
|
||||
MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.SONGID;
|
||||
String SONGS_DISPLAYARTIST =
|
||||
MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.DISPLAYARTIST;
|
||||
String SONGS_TITLE =
|
||||
MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.TITLE;
|
||||
String SONGS_ALBUMID =
|
||||
MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.ALBUMID;
|
||||
String SONG_ARTISTS_HOST_ID =
|
||||
MediaDatabase.Tables.SONG_ARTISTS + "." + MediaContract.SongArtists.HOST_ID;
|
||||
String SONG_ARTISTS_ARTISTID =
|
||||
|
|
|
@ -272,7 +272,8 @@ public class SyncMusic extends SyncItem {
|
|||
//AudioType.FieldsSong.LASTPLAYED, AudioType.FieldsSong.DISC,
|
||||
//AudioType.FieldsSong.GENREID,
|
||||
AudioType.FieldsSong.ARTISTID,
|
||||
//AudioType.FieldsSong.DISPLAYARTIST, AudioType.FieldsSong.ALBUMARTISTID
|
||||
// AudioType.FieldsSong.ALBUMARTISTID,
|
||||
AudioType.FieldsSong.DISPLAYARTIST
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -336,6 +336,7 @@ public class SyncUtils {
|
|||
songValues.put(MediaContract.Songs.FILE, song.file);
|
||||
songValues.put(MediaContract.Songs.TRACK, song.track);
|
||||
songValues.put(MediaContract.Songs.TITLE, song.title);
|
||||
songValues.put(MediaContract.Songs.DISPLAYARTIST, song.displayartist);
|
||||
|
||||
return songValues;
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ import org.xbmc.kore.jsonrpc.method.Player;
|
|||
import org.xbmc.kore.jsonrpc.method.Playlist;
|
||||
import org.xbmc.kore.jsonrpc.type.PlaylistType;
|
||||
import org.xbmc.kore.provider.MediaContract;
|
||||
import org.xbmc.kore.provider.MediaDatabase;
|
||||
import org.xbmc.kore.utils.FileDownloadHelper;
|
||||
import org.xbmc.kore.utils.LogUtils;
|
||||
import org.xbmc.kore.utils.UIUtils;
|
||||
|
@ -651,7 +652,7 @@ public class AlbumDetailsFragment extends AbstractDetailsFragment
|
|||
.inflate(R.layout.list_item_song, songListView, false);
|
||||
TextView songTitle = (TextView)songView.findViewById(R.id.song_title);
|
||||
TextView trackNumber = (TextView)songView.findViewById(R.id.track_number);
|
||||
TextView duration = (TextView)songView.findViewById(R.id.duration);
|
||||
TextView details = (TextView)songView.findViewById(R.id.details);
|
||||
ImageView contextMenu = (ImageView)songView.findViewById(R.id.list_context_menu);
|
||||
|
||||
// Add this song to the list
|
||||
|
@ -665,8 +666,14 @@ public class AlbumDetailsFragment extends AbstractDetailsFragment
|
|||
songInfoList.add(songInfo);
|
||||
|
||||
songTitle.setText(songInfo.title);
|
||||
|
||||
|
||||
trackNumber.setText(String.valueOf(songInfo.track));
|
||||
duration.setText(UIUtils.formatTime(cursor.getInt(AlbumSongsListQuery.DURATION)));
|
||||
|
||||
String artist = cursor.getString(AlbumSongsListQuery.ARTIST);
|
||||
String duration = UIUtils.formatTime(cursor.getInt(AlbumSongsListQuery.DURATION));
|
||||
String detailsText = TextUtils.isEmpty(artist) ? duration : duration + " | " + artist;
|
||||
details.setText(detailsText);
|
||||
|
||||
contextMenu.setTag(songInfo);
|
||||
contextMenu.setOnClickListener(songItemMenuClickListener);
|
||||
|
@ -737,7 +744,7 @@ public class AlbumDetailsFragment extends AbstractDetailsFragment
|
|||
}
|
||||
|
||||
/**
|
||||
* Movie cast list query parameters.
|
||||
* Album songs list query parameters.
|
||||
*/
|
||||
public interface AlbumSongsListQuery {
|
||||
String[] PROJECTION = {
|
||||
|
@ -747,15 +754,17 @@ public class AlbumDetailsFragment extends AbstractDetailsFragment
|
|||
MediaContract.Songs.DURATION,
|
||||
MediaContract.Songs.FILE,
|
||||
MediaContract.Songs.SONGID,
|
||||
MediaContract.Songs.DISPLAYARTIST
|
||||
};
|
||||
|
||||
String SORT = MediaContract.Songs.TRACK + " ASC";
|
||||
|
||||
final int ID = 0;
|
||||
final int TITLE = 1;
|
||||
final int TRACK = 2;
|
||||
final int DURATION = 3;
|
||||
final int FILE = 4;
|
||||
final int SONGID = 5;
|
||||
int ID = 0;
|
||||
int TITLE = 1;
|
||||
int TRACK = 2;
|
||||
int DURATION = 3;
|
||||
int FILE = 4;
|
||||
int SONGID = 5;
|
||||
int ARTIST = 6;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.xbmc.kore.host.HostManager;
|
|||
import org.xbmc.kore.jsonrpc.type.PlaylistType;
|
||||
import org.xbmc.kore.provider.MediaContract;
|
||||
import org.xbmc.kore.provider.MediaDatabase;
|
||||
import org.xbmc.kore.provider.MediaProvider;
|
||||
import org.xbmc.kore.service.library.LibrarySyncService;
|
||||
import org.xbmc.kore.utils.LogUtils;
|
||||
import org.xbmc.kore.utils.MediaPlayerUtils;
|
||||
|
@ -136,23 +137,20 @@ public class SongsListFragment extends AbstractCursorListFragment {
|
|||
*/
|
||||
public interface SongsListQuery {
|
||||
String[] PROJECTION = {
|
||||
MediaDatabase.Tables.SONGS + "." + BaseColumns._ID,
|
||||
MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.TITLE,
|
||||
MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.TRACK,
|
||||
MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.DURATION,
|
||||
MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.FILE,
|
||||
MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.SONGID,
|
||||
MediaDatabase.Tables.ALBUMS + "." + MediaContract.Albums.TITLE,
|
||||
MediaDatabase.Tables.ALBUMS + "." + MediaContract.Albums.DISPLAYARTIST,
|
||||
MediaDatabase.Tables.ALBUMS + "." + MediaContract.Albums.GENRE,
|
||||
MediaDatabase.Tables.ALBUMS + "." + MediaContract.Albums.YEAR,
|
||||
MediaDatabase.Tables.ALBUMS + "." + MediaContract.Albums.THUMBNAIL,
|
||||
MediaDatabase.Tables.ARTISTS + "." + MediaContract.Artists.ARTIST
|
||||
MediaProvider.Qualified.SONGS_ID,
|
||||
MediaProvider.Qualified.SONGS_TITLE,
|
||||
MediaProvider.Qualified.SONGS_TRACK,
|
||||
MediaProvider.Qualified.SONGS_DURATION,
|
||||
MediaProvider.Qualified.SONGS_FILE,
|
||||
MediaProvider.Qualified.SONGS_SONGID,
|
||||
MediaProvider.Qualified.SONGS_DISPLAYARTIST,
|
||||
MediaProvider.Qualified.ALBUMS_TITLE,
|
||||
MediaProvider.Qualified.ALBUMS_GENRE,
|
||||
MediaProvider.Qualified.ALBUMS_YEAR,
|
||||
MediaProvider.Qualified.ALBUMS_THUMBNAIL
|
||||
};
|
||||
|
||||
String SORT = MediaDatabase.sortCommonTokens(MediaDatabase.Tables.SONGS
|
||||
+ "." +
|
||||
MediaContract.Songs.TITLE) + " ASC";
|
||||
String SORT = MediaDatabase.sortCommonTokens(MediaProvider.Qualified.SONGS_TITLE) + " ASC";
|
||||
|
||||
int ID = 0;
|
||||
int TITLE = 1;
|
||||
|
@ -160,12 +158,11 @@ public class SongsListFragment extends AbstractCursorListFragment {
|
|||
int DURATION = 3;
|
||||
int FILE = 4;
|
||||
int SONGID = 5;
|
||||
int ALBUMTITLE = 6;
|
||||
int ALBUMARTIST = 7;
|
||||
int SONGARTIST = 6;
|
||||
int ALBUMTITLE = 7;
|
||||
int GENRE = 8;
|
||||
int YEAR = 9;
|
||||
int THUMBNAIL = 10;
|
||||
int ARTIST = 11;
|
||||
}
|
||||
|
||||
private class SongsAdapter extends CursorAdapter {
|
||||
|
@ -213,10 +210,7 @@ public class SongsListFragment extends AbstractCursorListFragment {
|
|||
|
||||
viewHolder.title.setText(title);
|
||||
|
||||
String artist = cursor.getString(SongsListQuery.ALBUMARTIST);
|
||||
if (TextUtils.isEmpty(artist))
|
||||
artist = cursor.getString(SongsListQuery.ARTIST);
|
||||
|
||||
String artist = cursor.getString(SongsListQuery.SONGARTIST);
|
||||
viewHolder.artist.setText(artist);
|
||||
|
||||
int year = cursor.getInt(SongsListQuery.YEAR);
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
-->
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground">
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/track_number"
|
||||
|
@ -53,7 +53,7 @@
|
|||
android:layout_toStartOf="@id/list_context_menu"
|
||||
android:layout_alignBottom="@id/track_number"/>
|
||||
<TextView
|
||||
android:id="@+id/duration"
|
||||
android:id="@+id/details"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignLeft="@id/song_title"
|
||||
|
|
Loading…
Reference in New Issue