Using MPMediaQuery to query ios library by rating - ios

I'm developing an iphone 4 app that filters the local media library by different criteria. I have been able to filter by song name, artist, and genre. Now I need to add a rating filter mechanism. I was thinking in something like "rating >= N stars" (N:0..5)
The code I use to filter is:
allMedia = [MPMediaQuery songsQuery];
MPMediaPropertyPredicate *mpp1 = [MPMediaPropertyPredicate predicateWithValue:#"2" forProperty:MPMediaItemPropertyRating comparisonType:MPMediaPredicateComparisonEqualTo];
[allMedia addFilterPredicate:mpp1];
But MPMediaPropertyPredicate does not allow to filter by MPMediaItemPropertyRating (and actually it works ok with artist and song title).
2011-05-12 11:37:39.060 Radio3[1525:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'MPMediaPropertyPredicate cannot filter using the rating property.'
I google by MPMediaItemPropertyRating but it seems that I should find an alternative approach to filter by track rating.
Can somebody give me a tip?
thanks
UPDATE: This is my code to solve this:
allMedia = [MPMediaQuery songsQuery];
//MPMediaPropertyPredicate *mpp1 = [MPMediaPropertyPredicate predicateWithValue:#"2" forProperty:MPMediaItemPropertyRating comparisonType:MPMediaPredicateComparisonEqualTo];
//MPMediaPropertyPredicate *mpp2 = [MPMediaPropertyPredicate predicateWithValue:#"Pop" forProperty:MPMediaItemPropertyGenre comparisonType:MPMediaPredicateComparisonContains];
//[allMedia addFilterPredicate:mpp1];
//[allMedia addFilterPredicate:mpp2];
//[myPlayer setQueueWithQuery:allMedia];
NSArray *itemsFromGenericQuery = [allMedia items];
NSMutableArray *mArray = [[NSMutableArray alloc] init];
int i = 0;
int j=0;
NSLog(#"itemCount: %d",[itemsFromGenericQuery count]);
float playsQuery = sliderPlays.value;
if(playsQuery == 20){playsQuery = 10000;}
NSLog(#"sliderRating.value %f sliderPlays.value %.1f", [sliderRating value], playsQuery);
while(i++ < 1000){
int trackNumber = arc4random() % [itemsFromGenericQuery count];
MPMediaItem *song = [itemsFromGenericQuery objectAtIndex:trackNumber];
NSString *artistName = [song valueForProperty: MPMediaItemPropertyArtist];
NSString *title = [song valueForProperty: MPMediaItemPropertyTitle];
NSString *rating = [song valueForKey:MPMediaItemPropertyRating];
double lengh = [[song valueForProperty:MPMediaItemPropertyPlaybackDuration] doubleValue];
NSNumber *playCount = [song valueForKey:MPMediaItemPropertyPlayCount];
if ([rating intValue] >= sliderRating.value && [playCount intValue] <= playsQuery) {
if(j++ > 50){break;}
NSLog (#"tracknumber: %d j: %d artistName: %# title: %# lengh: %.1f rating: %# playcount: %d",trackNumber, j, artistName, title, lengh, rating, [playCount intValue]);
[mArray addObject:song];
}
if(i++ > 1000)break;
}
MPMediaItemCollection *itemCol = [[MPMediaItemCollection alloc] initWithItems:mArray];
[myPlayer setQueueWithItemCollection:itemCol];
[myPlayer setShuffleMode: MPMusicShuffleModeSongs];
[myPlayer setRepeatMode: MPMusicRepeatModeNone];

MPMediaItemPropertyRating is a user-defined property, and according to the Apple docs:
User-defined properties cannot be used to build media property predicates.
One way to get around this would be to initially iterate over all the songs, store the ratings in a database (or something else) and sort the data from there.

Related

NSArray unrecognized selector sent to instance on Json

I am new to Objective-C And here I have a Json that I've stored into a NSArray. And I am trying to get the English, Dutch, Portuguese
{
English = (
One,
Two,
Three
);
Dutch = (
Een
);
Portuguese = (
Um,
Dois
}
And here's what I've done:
languageArray = result;
for (i = [languageArray count] - 1; i >= 0; i--)
{
NSString *languageTitle = [languageArray objectAtIndex:i];
NSLog(#"languageTitle %#", languageTitle);
}
And I have this error -[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x7f8c68e53610 but my languageArray count is 3. I don't know why I can't get the objectAtIndex:i I've tried to use objectAtIndex:0 but still the same result
just use
NSArray*languages = [result allKeys];
for getting values for languages you have to do this
NSMutableArray *mutableArray = [[NSMutableArray alloc]init];
for (int i=0 ; i<languages.count ; i++){
[mutableArray addObject:[result valueForKey:[languages objectAtIndex:indexpath.row]]];
}
So finally you have mutable array which contains values for every language as array;
You can get values for english with respect to index of language.
For example you can get values for Dutch as
NSArray *dutchValues = [mutableArray objectAtIndex:1];

calculate full album length

I need to get the full length of an album that is on a device but don't get the correct result. What I have is the follwing to get an Array with the songs of one album:
MPMediaPropertyPredicate *albumNamePredicate = [MPMediaPropertyPredicate predicateWithValue:albumTitle
forProperty: MPMediaItemPropertyAlbumTitle];
MPMediaQuery *myAlbumQuery = [[MPMediaQuery alloc] init];
[myAlbumQuery addFilterPredicate: albumNamePredicate];
songsAlbumList = [myAlbumQuery items];
To get the length of a song, I use this:
NSNumber *songTrackLength = [song valueForProperty:MPMediaItemPropertyPlaybackDuration];
int minutes = floor([songTrackLength floatValue] / 60);
int seconds = trunc([songTrackLength floatValue] - minutes * 60);
TracklengthLabel.text = [NSString stringWithFormat:#"%d:%02d", minutes, seconds];
So the above works fine, I just do not get a correct addition of the songdurations ... Any ideas?
So I solved it - my problem was that I did not know how to correctly do the math with NSNumbers - I did not know that I was looking for that, that's why I did not ask for it. Here is the code I came up with to calculate the length of an album on you device:
- (void)fullAlbumLength
{
for (int i=0; i < songsAlbumList.count; i++)
{
if (addLength == NULL) // addLength and addLengthNew are NSNumber variables
{
addLength = [[self.albumTracksList objectAtIndex:i] valueForProperty: #"playbackDuration"];
}
else
{
addLengthNew = [[self.albumTracksList objectAtIndex:i] valueForProperty: #"playbackDuration"];
addLength = [NSNumber numberWithFloat:([addLength floatValue] + [addLengthNew floatValue])];
}
}
fullminutes = floor([addLength floatValue] / 60); // fullminutes is an int
fullseconds = trunc([addLength floatValue] - fullminutes * 60); // fullseconds is an int
fullLength.text = [NSString stringWithFormat:#"%02d:%02d", fullminutes, fullseconds];
}
Hope this is helpful for someone else out there.

Index of NowPlayingItem is wronging when Shuffle Mode is on in iOS

I'm now playing song from iPod Library that loaded into myArray with iPodMusicPlayer.
We can use indexOfNowPlayingItem to get index from NowPlaying music.
But when i Shuffle Mode is on, that indexOfNowPlayingItem Property's return index is completely wrong.
before ShuffleMode is off,indexOfNowPlayingItem can be used and correct.
However when ShuffleMode is on, indexOfNowPlayingItem count is only increase 1 (++).
like that
indexOfNowPlayingItem++;
Not a correct for ShuffleMode on.
So how can i get correct index when ShuffleMode on?
Thanks for your help.
My solution was when you set your playlist, set also a NSMutableDictionary with (index, MPMediaEntityPropertyPersistentID) of playlist.
When you need the song index, just get with the song persistent id.
- (void) setPlaylistIndexDictionary:(MPMediaItemCollection *)playlistItems
{
playlistIndexDict = [[NSMutableDictionary alloc] init];
NSNumber *count = [[NSNumber alloc] initWithInt:0];
for (MPMediaItem *item in [playlistItems items]) {
[playlistIndexDict setObject:count forKey:[item valueForProperty:MPMediaEntityPropertyPersistentID]];
count = [NSNumber numberWithInt:count.intValue + 1];
}
}
- (NSString *) getCurrentSongId
{
NSString* songId = [[musicPlayer nowPlayingItem] valueForProperty:MPMediaEntityPropertyPersistentID];
return songId;
}
Using:
NSString *songId = [musicController getCurrentSongId];
int songIndex = [[[musicController playlistIndexDict] objectForKey:songId] intValue];

How to get iTunes Library top 10 song by playcount within recent 5days?

I'm trying to fetch iTunes library in ios.
And trying to retrieve top 10 playcount song in 5days.
Could you tell me how to do? Here's my code.
MPMediaPropertyPredicate is not right answer...I guess.
MPMediaQuery *everything = [[MPMediaQuery alloc] init];
NSLog(#"Logging items from a generic query...");
NSArray *itemsFromGenericQuery = [everything items];
for (MPMediaItem *song in itemsFromGenericQuery) {
NSString *songTitle = [song valueForProperty: MPMediaItemPropertyTitle];
NSString *artistName = [song valueForProperty:MPMediaItemPropertyArtist];
NSString *lastPlayeddate = [song valueForProperty:MPMediaItemPropertyLastPlayedDate];
NSString *playCount = [song valueForProperty:MPMediaItemPropertyPlayCount];
NSLog (#"%#", songTitle);
text.text = [NSString stringWithFormat:#"%#\n%# %# %# %#", text.text, songTitle, artistName, lastPlayeddate, playCount];
}
All the best.
Apparently, play count is considered a "user defined" key, and therefore cannot be used in MPMediaPropertyPredicate
See http://developer.apple.com/library/ios/documentation/mediaplayer/reference/MPMediaItem_ClassReference/Reference/Reference.html#//apple_ref/doc/uid/TP40008211-CH1-SW38
You will have to iterate the songs and retrieve these properties manually.
enumerateValuesForProperties:usingBlock: is probably your most efficient option here.
http://developer.apple.com/library/ios/documentation/mediaplayer/reference/MPMediaEntity_ClassReference/Reference/Reference.html#//apple_ref/occ/instm/MPMediaEntity/enumerateValuesForProperties:usingBlock:

iPhone play a specific playlist/iMix

I want to play a specific playlist (that was constructed as an iMix) from my program, as long as it exists. I am able to use
[[MPMediaQuery albumsQuery] addFilterPredicate:[MPMediaPropertyPredicate predicateWithValue:#"MyAlbum" forProperty:MPMediaItemPropertyAlbumTitle]];
to get all songs in an album (as well as many other options for artists, etc.) but there seems to be no way to access playlists.
Is there a different way to do this, or will I be forced to store all the songs in the playlist within my code and access them all that way?
I haven't used it myself, but I see a [MPMediaQuery playlistsQuery] and MPMediaGroupingPlaylist in the docs...
Does this link help?
http://discussions.apple.com/thread.jspa?threadID=2084104&tstart=0&messageID=9838244
I ended up having to roll my own via a text file that contains playlist information. here is the code. The [Globals split] function just takes a string and splits it into an array of strings using either a single character ([Globals split: with:]) or each character in a string ([Globals split: withMany:]).
//Create the music player for our application.
musicPlayer = [MPMusicPlayerController applicationMusicPlayer];
[musicPlayer setShuffleMode: MPMusicShuffleModeOff];
[musicPlayer setRepeatMode: MPMusicRepeatModeAll];
//Get our song list from the text file.
NSError *error = nil;
NSString *songList = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Playlist" ofType:#"txt"] encoding:NSUTF8StringEncoding error:&error];
//Split it into each song using newlines or carriage returns.
NSArray *allSongs = [Globals split:songList withMany:#"\r\n"];
NSMutableArray *music = [NSMutableArray arrayWithCapacity:[allSongs count]];
for (int i = 0; i < [allSongs count]; i++)
{
//Split the line into tab-delimited info: title, artist, album.
NSArray *songInfo = [Globals split:[allSongs objectAtIndex:i] with:'\t'];
//Get a query using all the data we have. This should return one song.
MPMediaQuery *songQuery = [MPMediaQuery songsQuery];
if ([songInfo count] > 0)
{
[songQuery addFilterPredicate:[MPMediaPropertyPredicate predicateWithValue:[songInfo objectAtIndex:0] forProperty:MPMediaItemPropertyTitle]];
}
if ([songInfo count] > 1)
{
[songQuery addFilterPredicate:[MPMediaPropertyPredicate predicateWithValue:[songInfo objectAtIndex:1] forProperty:MPMediaItemPropertyArtist]];
}
if ([songInfo count] > 2)
{
[songQuery addFilterPredicate:[MPMediaPropertyPredicate predicateWithValue:[songInfo objectAtIndex:2] forProperty:MPMediaItemPropertyAlbumTitle]];
}
//Add the song to our collection if we were able to find it.
NSArray *matching = [songQuery items];
if ([matching count] > 0)
{
[music addObject:[matching objectAtIndex:0]];
printf("Added in: %s\n",[(NSString *)[(MPMediaItem *)[matching objectAtIndex:0] valueForProperty:MPMediaItemPropertyTitle] UTF8String]);
}
else
{
printf("Couldn't add in: %s\n",[(NSString *)[songInfo objectAtIndex:0] UTF8String]);
}
}
//Now that we have a collection, make our playlist.
if ([music count] > 0)
{
itunesLoaded = YES;
// just get the first album with this name (there should only be one)
MPMediaItemCollection *itunesAlbum = [MPMediaItemCollection collectionWithItems:music];
//Shuffle our songs.
musicPlayer.shuffleMode = MPMusicShuffleModeSongs;
[musicPlayer setQueueWithItemCollection: itunesAlbum];
}
The text file is very easily generated using iTunes. All you need to do is create your playlist in iTunes, remove all the song info from your list except for Title, Artist, and Album, select all, and then paste into a text file. It will automatically be tab-delimitted and split by carriage returns. You also won't need to worry about mistyping or anything like that.

Resources