I am trying to implement Spotify integration with current user's playlist to display it in my tableview. I have integrated with login and access token everything works fine. I have gone through stack overflow link:- How to get the list of songs using Spotify in Swift3 iOS? but didn't work for me.
Then to get print for canonicalUsername as below, its showing nil value
SPTUser.requestCurrentUser(withAccessToken:(SPTAuth.defaultInstance().session.accessToken)!) { (error, data) in
guard let user = data as? SPTUser else { print("Couldn't cast as SPTUser"); return }
let userId = user.canonicalUsername
})
I have even tried this link Spotify iOS SDK Swift display all (!) playlists (20+) due to beginner may be it also didn't work for me. Is there any way to get Spotify's current user-id? How could I show the current user's playlist in my table view?
Just go through online tutorial in youtube :- https://www.youtube.com/watch?v=KLsP7oThgHU&t=1s for latest version in 2019.
Download full source code with Spotify Integration + search options + default Spotify url and fetch current user's playlist and play in our native iOS App
Source:- https://github.com/azeemohd786/Spotify-Demo
Based on your question the solution to get print canonicalUsername or current user's id try as below,
SPTUser.requestCurrentUser(withAccessToken: session.accessToken) { (error, data) in
guard let user = data as? SPTUser else { print("Couldn't cast as SPTUser"); return }
let userID = user.canonicalUserName
print(userID!)
}
Then to get current user's playlist and play in ur device, first call the SPT Delegate in your view controller like and then function call,
class PlayVC: UIViewController, SPTAudioStreamingDelegate, SPTAudioStreamingPlaybackDelegate {
func audioStreamingDidLogin(_ audioStreaming: SPTAudioStreamingController) {
let playListRequest = try! SPTPlaylistList.createRequestForGettingPlaylists(forUser: session.canonicalUsername, withAccessToken: session.accessToken)
Alamofire.request(playListRequest)
.response { response in
let list = try! SPTPlaylistList(from: response.data, with: response.response)
for playList in list.items {
if let playlist = playList as? SPTPartialPlaylist {
print( playlist.name! ) // playlist name
print( playlist.uri!) // playlist uri
// self.tableView.reloadData()// if u want to display playlist name and other stuffs like so..
SPTAudioStreamingController.sharedInstance().playSpotifyURI("\(playlist.uri!)", startingWith: 0, startingWithPosition: 10) { error in
if error != nil {
print("*** failed to play: \(error)")
return
}
}
}}}
}
}
Related
I am struggling to understand why my event listener that I initialize on a document is not being triggered whenever I update the document within the app in a different UIViewController. If I update it manually in Google firebase console, the listener event gets triggered successfully. I am 100% updating the correct document too because I see it get updated when I update it in the app. What I am trying to accomplish is have a running listener on the current user that is logged in and all of their fields so i can just use 1 global singleton variable throughout my app and it will always be up to date with their most current fields (name, last name, profile pic, bio, etc.). One thing I noticed is when i use setData instead of updateData, the listener event gets triggered. For some reason it doesn't with updateData. But i don't want to use setData because it will wipe all the other fields as if it is a new doc. Is there something else I should be doing?
Below is the code that initializes the Listener at the very beginning of the app after the user logs in.
static func InitalizeWhistleListener() {
let currentUser = Auth.auth().currentUser?.uid
let userDocRef = Firestore.firestore().collection("users").document(currentUser!)
WhistleListener.shared.listener = userDocRef.addSnapshotListener { documentSnapshot, error in
guard let document = documentSnapshot else {
print("Error fetching document: \(error!)")
return
}
guard let data = document.data() else {
print("Document data was empty.")
return
}
print("INSIDE LISTENER")
}
}
Below is the code that update's this same document in a different view controller whenever the user updates their profile pic
func uploadProfilePicture(_ image: UIImage) {
guard let uid = currentUser!.UID else { return }
let filePath = "user/\(uid).jpg"
let storageRef = Storage.storage().reference().child(filePath)
guard let imageData = image.jpegData(compressionQuality: 0.75) else { return }
storageRef.putData(imageData) { metadata, error in
if error == nil && metadata != nil {
self.userProfileDoc!.updateData([
"profilePicURL": filePath
]) { err in
if let err = err {
print("Error updating document: \(err)")
} else {
print("Document successfully updated")
}
}
}
}
}
You can use set data with merge true it doesn't wipe any other property only merge to specific one that you declared as like I am only update the name of the user without wiping the age or address
db.collection("User")
.document(id)
.setData(["name":"Zeeshan"],merge: true)
The answer is pretty obvious (and sad at the same time). I was constantly updating the filepath to be the user's UID therefore, it would always be the same and the snapshot wouldn't recognize a difference in the update. It had been some time since I had looked at this code so i forgot this is what it was doing. I was looking past this and simply thinking an update (no matter if it was different from the last or not) would trigger an event. That is not the case! So what I did was append an additional UUID to the user's UID so that it changed.
How can I only retrieve playlists that are editable? Or in other words how can I retrieve playlists that are only created by the user?
We can get the playlists of the user by the following code block:
var request = MusicLibraryRequest<Playlist>()
request.sort(by: \.lastPlayedDate, ascending: false)
let response = try await request.response()
Also, we can add a track to the playlist with the following code block:
TASK {
do {
try await MusicLibrary.shared.add(track, to: playlist)
} catch (let error) {
print(error)
}
}
However not all playlists are editable. For instance if the playlist created by Apple or another Apple Music user, we receive an error while adding track to the playlist because we don't have a permission to do it.
I receive the following error:
Error Domain=MPErrorDomain Code=5 "The requested action is not supported" UserInfo={NSLocalizedDescription=The requested action is not supported}
I wanna streaming my app to twitch, youtube or such a streaming service without any other application likes mob crush.
According to Apple, by using Broadcast Extension I can stream my application screen.
Broadcast Extension gave video data as a type of CMSampleBuffer. Then I should send that data to rtmp sever like youtube, twitch or etc.
I think if I can get video data, I can stream the other things without using Broadcast Extension in my app. So I try to send RPScreenRecorder data to rtmp server, but I doesn't work.
Here is a code I wrote.
I use HaishinKit open source framework to rtmp communication.
(https://github.com/shogo4405/HaishinKit.swift/tree/master/Examples/iOS/Screencast)
let rpScreenRecorder : RPScreenRecorder = RPScreenRecorder.shared()
private var broadcaster: RTMPBroadcaster = RTMPBroadcaster()
rpScreenRecorder.startCapture(handler: { (cmSampleBuffer, rpSampleBufferType, error) in
if (error != nil) {
print("Error is occured \(error.debugDescription)")
} else {
if let description: CMVideoFormatDescription = CMSampleBufferGetFormatDescription(cmSampleBuffer) {
let dimensions: CMVideoDimensions = CMVideoFormatDescriptionGetDimensions(description)
self.broadcaster.stream.videoSettings = [
"width": dimensions.width,
"height": dimensions.height ,
"profileLevel": kVTProfileLevel_H264_Baseline_AutoLevel
]
}
self.broadcaster.appendSampleBuffer(cmSampleBuffer, withType: .video)
}
}) { (error) in
if ( error != nil) {
print ( "Error occured \(error.debugDescription)")
} else {
print ("Success")
}
}
}
If you have any solution, please answer me :)
I've tried a similar setup and it is possible to achieve what you'd like, just need to adjust it a little:
I don't see it in your example, but make sure that the broadcaster's endpoint is correctly set up. For example:
let endpointURL: String = "rtmps://live-api-s.facebook.com:443/rtmp/"
let streamName: String = "..."
self.broadcaster.streamName = streamName
self.broadcaster.connect(endpointURL, arguments: nil)
Then in the startCapture's handler block you need to filter by the buffer type to send the correct data to the stream. In this case you're only sending the video so we can ignore audio. (You can also find some examples with HaishinKit to send audio too.) For example:
RPScreenRecorder.shared().startCapture(handler: { (sampleBuffer, type, error) in
if type == .video, broadcaster.connected {
if let description: CMVideoFormatDescription = CMSampleBufferGetFormatDescription(sampleBuffer) {
let dimensions: CMVideoDimensions = CMVideoFormatDescriptionGetDimensions(description)
broadcaster.stream.videoSettings = [
.width: dimensions.width,
.height: dimensions.height ,
.profileLevel: kVTProfileLevel_H264_Baseline_AutoLevel
]
}
broadcaster.appendSampleBuffer(sampleBuffer, withType: .video)
}
}) { (error) in }
Also make sure that the screen is updated during streaming. I've noticed that if you're recording a static window with RPScreenRecorder, then it will only update the handler when there's actually new video data to send. For testing I've added a simple UISlider which will update the feed when you move it around.
I've tested it with Facebook Live and I think it should work with other RTMP services too.
I want to show the first photo of the place with the geo-coordinates from google API but I am not getting any proper way. But what I got is https://developers.google.com/places/ios-api/photos now this needs Place-id I am even unable to find place-id with geo-coordinates. Can anyone tell me how can I extract photos of the place with geo-coordinate? Any Help would be appreciated.
You should first search first for the place with the API.
The response contains an 'placeID', now you can use this ID in your 2nd request.
try this
func loadFirstPhotoForPlace(placeID: String) {
GMSPlacesClient.shared().lookUpPhotos(forPlaceID: placeID) { (photos, error) -> Void in
if let error = error {
// TODO: handle the error.
print("Error: \(error.localizedDescription)")
} else {
if let firstPhoto = photos?.results.first {
self.loadImageForMetadata(photoMetadata: firstPhoto)
}
}
}
}
I am retrieving and displaying a list of tweets in a table view. The following code grabs a bunch of tweets from a search and displays them. This works fine!
Twitter.sharedInstance().logInGuestWithCompletion { session, error in
if let _ = session {
let client = Twitter.sharedInstance().APIClient
self.dataSource = TWTRSearchTimelineDataSource(searchQuery: "cats", APIClient: client)
} else {
print("error: \(error.localizedDescription)")
}
}
However, when I change the search query in order to get tweets referring to a specific user, I just get a blank screen.
Twitter.sharedInstance().logInGuestWithCompletion { session, error in
if let _ = session {
let client = Twitter.sharedInstance().APIClient
self.dataSource = TWTRSearchTimelineDataSource(searchQuery: "#mtasummit", APIClient: client)
} else {
print("error: \(error.localizedDescription)")
}
}
I've trying to encode the '#' symbol a couple of ways, and that didn't seem to work either. What am I doing wrong?
I overlooked a small detail in the API:
"Also note that the search results at twitter.com may return historical results while the Search API usually only serves tweets from the past week." (https://dev.twitter.com/rest/public/search)
The reason I was not seeing any tweets, was because my search term "#mtasummit" only contained results several months old, so they weren't being retrieved.