Get list of albums from ipod library in swift - ios

I want to make a simple media player in Swift. I want to make a table with all Albums on the iphone and after selecting the album i want to play the songs of it. But i can not get the album titles (and artwork).
I tried:
var query = MPMediaQuery.albumsQuery()
let mediaCollection = MPMediaItemCollection(items: query.items)
println(mediaCollection.items)
let player = MPMusicPlayerController.systemMusicPlayer()
player.setQueueWithItemCollection(mediaCollection)
player.play()

MPMediaItem has valueForProperty() function. The properties which you need are MPMediaItemPropertyAlbumTitle and MPMediaItemPropertyArtwork.

Related

Video's 'Artist' metadata not showing up on OS media player when played through AVPlayerViewController

When playing a video through AVPlayerViewController, its artist metadata does not show up in the player below the title in iOS control center / Lock Screen player.
Right now, I'm setting metadata to the AVPlayerItem itself in a function within an AVPlayerItem extension, along the lines of this:
func setMetadata(title: String, artist: String) {
let titleItem = AVMutableMetadataItem()
titleItem.identifier = AVMetadataIdentifier.commonIdentifierTitle
titleItem.value = title as (NSCopying & NSObjectProtocol)
self.externalMetadata.append(titleItem)
let artistItem = AVMutableMetadataItem()
artistItem.identifier = AVMetadataIdentifier.commonIdentifierArtist
artistItem.value = artist as (NSCopying & NSObjectProtocol)
self.externalMetadata.append(artistItem)
}
The title item works properly, but the artist is not updating. Any thoughts? Do videos have some other metadata field shown in the player that isn't artist?
I've tried .commonIdentifierDescription and .iTunesMetadataTrackSubtitle as alternate metadata identifiers but these are not working as expected.

How to enumerate Home Videos in iOS?

I understand how to enumerate images and video in the photo library using PHPhotoLibrary, but videos added through iTunes as "home videos", and visible only through the new TV app under the Home Video section, don't appear in that enumeration.
Is there another way of querying for them?
Well, it looks like the only other thing you can try to use are the Media Player API's.
https://developer.apple.com/documentation/mediaplayer/mpmediaquery
A query that specifies a set of media items from the device's media
library by way of a filter and a grouping type.
That might work, since I assume that your synced movies are part of the media library and not part of the photo library.
First you need to add the NSAppleMusicUsageDescription to your Info.plist. Then we can use MPMediaQuery and filter out the home video items.
let predicate: MPMediaPropertyPredicate = MPMediaPropertyPredicate(value: MPMediaType.homeVideo.rawValue, forProperty: MPMediaItemPropertyMediaType)
let query: MPMediaQuery = MPMediaQuery.init()
query.addFilterPredicate(predicate)
let items = query.items
for item : MPMediaItem in items!
{
// Here is your home video
}
See the MPMediaTypeHomeVideo item: https://developer.apple.com/documentation/mediaplayer/mpmediatype/mpmediatypehomevideo
Now items should contain all your home videos.
EDIT: I tested it, and it works for me on iOS 12, however title seems to be empty. You can access the video file itself using the assetURL property.
Here's an updated method.
import MediaPlayer
func video() {
MPMediaLibrary.requestAuthorization() { status in
if status == .authorized {
let predicate: MPMediaPropertyPredicate = MPMediaPropertyPredicate(value: MPMediaType.homeVideo.rawValue, forProperty: MPMediaItemPropertyMediaType)
let query: MPMediaQuery = MPMediaQuery.init()
query.addFilterPredicate(predicate)
if let items = query.items {
for item in items {
// Here is your home video
print(item.title ?? "title?")
}
}
}
}
}
you'll need to add this key to your info.plist
Privacy - Media Library Usage Description

how to resolve when MPMediaItem assetURL is nil?

I'm working on code that looks at the user's videos and passes them along to AVPlayer by way of an AVPlayerItem which takes a URL.
To get all the videos on an iOS device, you can do:
let videoNumber = MPMediaType.anyVideo.rawValue
let predicate = MPMediaPropertyPredicate.init(value: videoNumber, forProperty: MPMediaItemPropertyMediaType)
let query = MPMediaQuery.init()
query.addFilterPredicate(predicate)
if let items = query.items
{
mediaCollection = MPMediaItemCollection(items: items)
// -1 would indicate an error condition
print("number of items in collection is \(mediaCollection?.count ?? -1)")
}
When you select the MPMediaItem you want to use from the items array, there should be an assetURL to go with it.
Trouble is, on my device, all of my assetURL properties are NULL. Coincidentally, while hasProtectedAsset for each of these items is false, isCloudItem for each of these items is true.
How can I come up with a valid assetURL that I can pass along to any media player? It feels somewhat bogus that developers can't get proper references & access to media in a user's iPod library.

Play video from new URL without creating a new AVPlayer object

I'm trying to allow users to be able to cycle through videos, changing the AVPlayer URL on the fly without refreshing the view. However, right now I'm just instantiating AVPlayer objects every time a video is played (resulting in audio to be played over one another), which I feel isn't the best way to do this. Is there a more efficient way similar to changing the image in an imageView?
This is the code where I play the clip:
player = AVPlayer(URL: fileURL)
playerLayer = AVPlayerLayer(player: player)
playerLayer!.frame = self.view.bounds
self.view.layer.addSublayer(playerLayer!)
player!.play()
Do not use an AVPlayer.
Instead use an AVQueuePlayer which allows you to insert and remove items from a queue.
//create local player in setup methods
self.localPlayer = AVQueuePlayer.init()
to add items you can simply use
//optional: clear current queue if playing straight away
self.localPlayer.removeAllItems()
//get url of track
let url : URL? = URL.init(string: "http://urlOfItem")
if url != nil {
let playerItem = AVPlayerItem.init(url: url!)
//you can use the after property to insert
//it at a specific location or leave it nil
self.localPlayer.insert(playerItem, after: nil)
self.localPlayer.play()
}
AVQueuePlayer supports all of the functionality of the AVPlayer but has the added functionality of adding and removing items from a queue.
Use AVPlayerItem to add and remove outputs to an AVPlayer object.
Instead of adding a video to the AVPlayer when you create it, create an empty AVPlayer instance, and then use the addOutput method of the AVPlayerItem class to add the video.
To remove the video and add a new one, use the removeOutput method of the AVPlayerItem class to remove the old video, and then the addOutput method again to insert the new one.
Sample code is available from Apple's developer site at;
https://developer.apple.com/library/prerelease/content/samplecode/AVBasicVideoOutput/Introduction/Intro.html
It provides the same thing I would, were I to post code of my own.
Create AVPlayer Instance globally then override it again when you want to play a new video from new URL.
I am able to accomplish what you are looking for by doing this...
I have a tableView of song names, for which the mp3 files are stored on Parse.com. In didSelectRowAtIndexPath I do...
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
SelectedSongNumber = indexPath.row
grabSong()
}
func grabSong () {
let songQuery = PFQuery(className: "Songs")
songQuery.getObjectInBackgroundWithId(iDArray[SelectedSongNumber], block: {
(object: PFObject?, error : NSError?) -> Void in
if let audioFile = object?["SongFile"] as? PFFile {
let audioFileUrlString: String = audioFile.url!
let audioFileUrl = NSURL(string: audioFileUrlString)!
myAVPlayer = AVPlayer(URL: audioFileUrl)
myAVPlayer.play()
currentUser?.setObject(audioFileUrlString, forKey: "CurrentSongURL")
currentUser?.saveInBackground()
}
})
}
when I run this, i select a row and the song starts playing. If i then wait a few seconds and select a different row, the AVPlayer plays the song from the new cell that i selected and does NOT play one song over the other. My AVPlayer is declared as a public variable for all classes to see.

swift xcode play sound files from player list

I am looking for a swift coding playing sound out of the player list and not sounds added as resource to your project.
I mainly found the usage of
NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("sound_name", ofType: "wav"))
println(alertSound)
but for this you need to have the sound file in your bundle. But I couldn't find any example
selecting audio files bought thru itunes and play them.
Any idea how to do this? Can I access my music layer playlist files and using them in my app?
Thanks for any code lines.
rpw
These music files are represented by MPMediaItem instances. To fetch them, you could use an MPMediaQuery, as follows:
let mediaItems = MPMediaQuery.songsQuery().items
At this point, you have all songs included in Music App Library, so you can play them with a MPMusicPlayerController after setting a playlist queue:
let mediaCollection = MPMediaItemCollection(items: mediaItems)
let player = MPMusicPlayerController.iPodMusicPlayer()
player.setQueueWithItemCollection(mediaCollection)
player.play()
You might need to filter songs by genre, artist, album and so on. In that case, you should apply a predicate to the query before fetching the media items:
var query = MPMediaQuery.songsQuery()
let predicateByGenre = MPMediaPropertyPredicate(value: "Rock", forProperty: MPMediaItemPropertyGenre)
query.filterPredicates = NSSet(object: predicateByGenre)
let mediaCollection = MPMediaItemCollection(items: query.items)
let player = MPMusicPlayerController.iPodMusicPlayer()
player.setQueueWithItemCollection(mediaCollection)
player.play()
Cheers!

Resources