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:
Martijn Brekhof 2016-10-20 20:26:43 +02:00 committed by Synced Synapse
parent f0cd9a67f8
commit eedd1e99b4
9 changed files with 92 additions and 49 deletions

View File

@ -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());

View File

@ -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";

View 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;");
}
}

View File

@ -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 =

View File

@ -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
};
/**

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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"