I try to get file list from the Music Library (iPod Music Library), but I can't do it, my list is always empty. I sure that I have tracks in Music Library, I check it in other app - and it works. But as I remember that application sent me a request to access the Music Library. Perhaps I also need to create such a request? Help me solve the problem. I use this code to get file list:
func fetchFileList() {
let mediaItems = MPMediaQuery.songs().items
let mediaCollection = MPMediaItemCollection(items: mediaItems ?? [])
print("mediaCollectionItems: \(mediaCollection.items)") //It's always empty
//Then I'd like to get url of the track
//let item = mediaCollection.items[0]
//let pathURL = item.value(forProperty: MPMediaItemPropertyAssetURL) as? URL
//print("pathURL: \(pathURL)")
}
If you want to access the Music Library, you have to add NSAppleMusicUsageDescription key to your Info.plist with a description about what you want to do with the music.
Se apple documentation for more info: MediaPlayer Documentation
Related
I'm trying to download a youtube video on the phone so the user can later play it offline. I hooked a button to where the user can download. The code of how I'm currently downloading the video is here below.
#objc func downloadSelectedVideo() {
if let audioUrl = URL(string: "http://freetone.org/ring/stan/iPhone_5-Alarm.mp3") {
// create your document folder url
let documentsUrl = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
// your destination file url
let destination = documentsUrl.appendingPathComponent(audioUrl.lastPathComponent)
print(destination)
// check if it exists before downloading it
if FileManager().fileExists(atPath: destination.path) {
print("The file already exists at path")
} else {
// if the file doesn't exist
// just download the data from your url
URLSession.shared.downloadTask(with: audioUrl, completionHandler: { (location, response, error) in
// after downloading your data you need to save it to your destination url
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("audio"),
let location = location, error == nil
else { return }
do {
try FileManager.default.moveItem(at: location, to: destination)
print("file saved")
} catch {
print(error)
}
}).resume()
}
}
}
as you can see I have hooked up the URL to a free music which is in mp3 and it works fine I can download the music and everything works just fine, however when I try to hook up a YouTube video then it never gets to the print statement file saved I tried this as the URL if let audioUrl = URL(string: "https://www.youtube.com/watch?v=3WSgJCYIewM")
but the print statement file saved never ran, but when I tried with the other I mentioned earlier it print file saved.
What URL should use to download the youtube videos, and do I have to use an mp3 or mp4 source to download the videos. I'm trying not to use any third-party sites if you can come up with any solution it would be great and helpful. Thanks
YouTube spells this out pretty specifically that you cannot do this.
YouTube API Services - Developer Policies
Found this under E. Handling YouTube Data and Content
You and your API Clients must not, and must not encourage, enable, or
require others to:
download, import, backup, cache, or store copies of YouTube
audiovisual content without YouTube's prior written approval,
IANAL, but I'd rather not go up against their legal team.
YouTube does not provide a simple URL that taps into the video or audio directly. Instead, you would have to extract thier link using some algorithm. If you'd like to achieve that I would recommend you use XCDYouTubeKit as it is well maintained and easy to use. However, If you'd like a ready made app, I have developed an open source application - YouTag - that you can simply install on your iOS device and use directly without having to go through developing one.
My application is having trouble locating the files that are in the music folder on my iOS device.
If the files are held below as application data (in my playpen), no problem. But when I go looking for the "Music" folder, using the following lines:
dest_dir = try! FileManager.default.url(for: .musicDirectory, in: .allDomainsMask, appropriateFor: nil, create: false)
musicDir = dest_dir
if UIApplication.shared.canOpenURL(musicDir) {
print("found music directory")
}else {
print("did not find music directory")
}
When the code executes the canOpenURL, I get a permissions complaint.
I also tried accessing the user directory (thinking I could then navigate into Music).
Any clues on how an application can access the files and playlists held under the music system folder on the iOS device?
There is no such thing as "the Music folder" in iOS. To access the user's music library, use the Media Player framework.
Example (assuming you have obtained the necessary authorization from the user):
let query = MPMediaQuery()
let result = query.items
Here you go! (Swift 4.2)
Inside a button method or #IBAction button
let mediaItems = MPMediaQuery.songs().items
let mediaCollection = MPMediaItemCollection(items: mediaItems ?? [])
let player = MPMusicPlayerController.systemMusicPlayer
player.setQueue(with: mediaCollection)
player.play()
let picker = MPMediaPickerController(mediaTypes: .anyAudio)
picker.delegate = self
picker.allowsPickingMultipleItems = false
picker.prompt = "Choose a song"
present(picker, animated: true, completion: nil)
iOS doesn’t give you direct access to the Music folder, for security and privacy reasons; you need to use the APIs in the MediaPlayer framework. Assuming you’re trying to play content from the user’s library, take a look at MPMusicPlayerController; you’ll need to provide it some MPMediaItem instances retrieved with an MPMediaQuery, then call methods from the MPMediaPlayback protocol on the controller to make it play the content.
So I'm building some playlist and song retrieval into my app at the moment, and I'm really confused by some of the results I'm getting back from the API. It seems to be returning songs that no longer exist on Spotify or have been long removed from a playlist.
Retrieving a list of Playlists from a user is working fine, but just in case this problem is arising from the way I draw that playlist's tracks, here is the code I use to get them:
SPTPlaylistSnapshot.playlistWithURI(uri, accessToken: session.accessToken) { (error, playlistSnapshotOb) -> Void in
if let playlistSnapshot = playlistSnapshotOb as? SPTPlaylistSnapshot {
let itemz = playlistSnapshot.firstTrackPage.items //tracksForPlayback()
for item in itemz{
let track = item as! SPTPlaylistTrack
let splice = "\(track.uri)"
let trackURI = splice.stringByReplacingOccurrencesOfString("spotify:track:", withString: "")
var displayArtist = String()
let artistz = track.artists
if artistz.count > 1{
for i in 0...(artistz.count - 1){
let itz = artistz[i] as! SPTPartialArtist
if i > 0 {
displayArtist += ", \(itz.name)"
}else{
displayArtist += "\(itz.name)"
}
}
self.tracks.append(track.name)
self.ArtistObjects.append(displayArtist)
self.uriS.append(trackURI)
}else{
let singularArtist = artistz[0] as! SPTPartialArtist
displayArtist = singularArtist.name
self.tracks.append(track.name)
self.ArtistObjects.append(displayArtist)
self.uriS.append(trackURI)
}
Additionally, below is a screenshot of the desktop Spotify app showing the real content of the playlist I am pulling:
Spotify per Desktop
You'll see that the songs "Big Bank Dank" and "Light Day Remix" are not actually on this playlist, but for some reason, on my app below, when I pull this playlist, it has these songs listed:
Spotify In My App
(Apparently I can't post an actual image because of my rep - apologies)
Any idea why it's doing this?
The tracks are probably just not available any longer for some unspecified reason. This is quite common. By default, the Spotify client does not show unavailable tracks in playlists, but in settings there is a toggle you can flip so that they are shown as greyed out instead.
I don't know about iOS SDK, but there should be either an attribute telling you the available markets for the tracks or if it is playable or not, depending on the country of the user being logged in.
This is how it works in the Web API, which should be similar.
https://developer.spotify.com/web-api/track-relinking-guide/
I have tried the following:
let nowPlaying = MPNowPlayingInfoCenter.defaultCenter().nowPlayingInfo
However I get back nil everytime I run it with a song playing.
I would like to be able to grab the track title and artist and display it in my app.
You're going about this completely the wrong way. MPNowPlayingInfoCenter has nothing to do with learning what is currently playing. If you want to know what the Music app is currently playing, ask the "iPod music player" (in iOS 8, it is called MPMusicPlayerController.systemMusicPlayer).
try this, if you are writing an iOS app
let musicPlayer = MPMusicPlayerController.systemMusicPlayer
if let nowPlayingItem = musicPlayer.nowPlayingItem {
print(nowPlayingItem.title)
} else {
print("Nothing's playing")
}
This is a modified version of this answer.
Using Swift, you can get the Now Playing info, including title, artist, artwork and app on an iOS device using the following private API:
// Load framework
let bundle = CFBundleCreate(kCFAllocatorDefault, NSURL(fileURLWithPath: "/System/Library/PrivateFrameworks/MediaRemote.framework"))
// Get a Swift function for MRMediaRemoteGetNowPlayingInfo
guard let MRMediaRemoteGetNowPlayingInfoPointer = CFBundleGetFunctionPointerForName(bundle, "MRMediaRemoteGetNowPlayingInfo" as CFString) else { return }
typealias MRMediaRemoteGetNowPlayingInfoFunction = #convention(c) (DispatchQueue, #escaping ([String: Any]) -> Void) -> Void
let MRMediaRemoteGetNowPlayingInfo = unsafeBitCast(MRMediaRemoteGetNowPlayingInfoPointer, to: MRMediaRemoteGetNowPlayingInfoFunction.self)
// Get song info
MRMediaRemoteGetNowPlayingInfo(DispatchQueue.main, { (information) in
let bundleInfo = Dynamic._MRNowPlayingClientProtobuf.initWithData(information["kMRMediaRemoteNowPlayingInfoClientPropertiesData"])
print("\(information["kMRMediaRemoteNowPlayingInfoTitle"] as! String) by \(information["kMRMediaRemoteNowPlayingInfoArtist"] as! String) playing on \(bundleInfo.displayName.asString!)")
})
Returns SONG by ARTIST playing on APP.
Note this uses the Dynamic package to easily execute private headers.
This cannot be used in an App Store app due to the use of private API.
This is not an API to get the current playing item information from Music or another app, but to tell the system that your app is currently playing something and give it the information needed to display it on lock screen.
So basically what you're trying to do won't work as you expect it.
Did you set them?
var audioPlayer:MPMoviePlayerController=MPMoviePlayerController()
MPNowPlayingInfoCenter.defaultCenter().nowPlayingInfo = [
MPMediaItemPropertyAlbumTitle: "Album Title",
MPMediaItemPropertyTitle: "Title",
MPNowPlayingInfoPropertyElapsedPlaybackTime: audioPlayer.currentPlaybackTime,
MPMediaItemPropertyPlaybackDuration: audioPlayer.duration]
The now playing info center supports the following media item property keys:
MPMediaItemPropertyAlbumTitle
MPMediaItemPropertyAlbumTrackCount
MPMediaItemPropertyAlbumTrackNumber
MPMediaItemPropertyArtist
MPMediaItemPropertyArtwork
MPMediaItemPropertyComposer
MPMediaItemPropertyDiscCount
MPMediaItemPropertyDiscNumber
MPMediaItemPropertyGenre
MPMediaItemPropertyPersistentID
MPMediaItemPropertyPlaybackDuration
MPMediaItemPropertyTitle
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!