Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I want to know when a song is played on music app and get its info. But I don't want to get all songs from library, It's just the songs that was played since the app starts to scan.
It's like you play something, then you open the app and it scan what you played.
I've searching about this but didn't find nothing, and I don't know where to start to implement this.
First, add the NSAppleMusicUsageDescription key to your Info.plist with a description of why you need access to the user's media library
Then you can find all songs that have been played since a certain time with the following code:
import MediaPlayer
#IBAction func getSongs(_ sender: Any) {
let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: Calendar.current.startOfDay(for: Date()))!
// Check for permissions
switch MPMediaLibrary.authorizationStatus() {
case .authorized, .restricted:
fetchSongPlayed(since: yesterday)
case .notDetermined:
MPMediaLibrary.requestAuthorization { _ in
let auth = MPMediaLibrary.authorizationStatus()
if auth == .authorized || auth == .restricted {
self.fetchSongPlayed(since: yesterday)
}
}
case .denied:
print("No access to the Media Library")
}
}
func fetchSongPlayed(since date: Date) {
let query = MPMediaQuery.songs()
var results = [MPMediaItem]()
if let songs = query.items {
results = songs.filter { ($0.lastPlayedDate ?? Date.distantPast) > date }
} else {
print("Can't fetch songs")
}
// Now do whatever you want with results
// It's an array of MPMediaItem
print(results.count)
}
One more tip: sync some music from iTunes to your device as the Simulator doesn't have any bye default. There's a way to add it to the simulator but it's just easier to test on device.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I want to convert this Swift code to Objective C. I searched and did not find a way to convert automatically . Is there any way that can help convert ?
let token="0000000009"
SkyIdConfig.shared.setup(With: token)
var skyIdView:SkyDocumentsAnalyzer?
SkyIdConfig.shared.loadAndConfigure(){[unowned self] isConfigured,error in
if error != nil || !isConfigured {
print(error?.localizedDescription ?? "Error !!!!")
return
}
DispatchQueue.main.async {[unowned self] in
self.skyIdView=SkyIdBuilder.shared.getDocumentAnalyzerInstance(with: "03", lang: "fra")
if self.skyIdView != nil
{
self.skyIdView!.delegate=self
self.skyIdView?.modalPresentationStyle = .fullScreen
self.present(self.skyIdView!, animated: true, completion: nil)
}else{
print("Error in config loading")
}
}
}
Of course there is a way to convert ..
..manually. Which is the best way to understand whats going on.
your token is probably an
NSString *token = #"0000000009";
depending on the Class definition you have to look up how SkyIdConfig is done..
//assuming its something like..
[[SkyIdConfig shared] setupWith:token];
SkyDocumentsAnalyzer *skyIdView = [[SkyDocumentsAnalyzer alloc] init];
[[SkyIdConfig shared] loadAndConfigure];
before going forward in code read more about dispatching in objective-c (aka c) here...
I need to build a quiz type application using Siri.
Here, let us consider, my application have only one question along with multiple choices as answers.
Now with the Siri voice commands, I need to load that question along with choices onto the Label/ textview.
Once that question gets loaded onto the Lable/textview, this question should be spoken by Siri.
Now the user can choose his/her answer either a or b or c or d using their voice command.
Then Siri should validate the user's input with the correct answer.
If its correct, Siri should say”correct answer”. Otherwise It should say “wrong answer. The correct answer is and so on..”
I have implemented half part of my requirements, Using Siri shortcuts, I can able to load the question onto a Label and Siri can speak that question.
for your reference, please find my code below.
In ViewController.swift file I have implemented below code,
Public fund createShortcutForloadingQuestion(){
let userAct = NSUserActivity(activityType: "com.organization.QuizSpeakingApp.loadQuestion")
userAct.title = "get the text from document"
userAct.userInfo = ["question" : "what is the capital of India? \n a. Kolkata \n b. Mumbai, \n c. Bengaluru,\n d. New Delhi"]
userAct.isEligibleForSearch = true
userAct.isEligibleForPrediction = true
userAct.persistentIdentifier = NSUserActivityPersistentIdentifier("com.organization.QuizSpeakingApp.loadQuestion")
textLbl.userActivity = userAct
userAct.becomeCurrent()
displayTextOnLabel()
}
public func displayTextOnLabel() {
textLbl.text = “what is the capital of India? \n a. Kolkata \n b. Mumbai, \n c. Bengaluru,\n d. New Delhi.”
}
To speak the loaded question I have implemented the code like below,
public func speakTheQuestion(){
let speechUtterance = AVSpeechUtterance(string: textLbl.text ?? "Label Doesnt have any text")
speechUtterance.rate = 0.5
speechUtterance.pitchMultiplier = 1.0
speechUtterance.volume = 1.0
speechUtterance.postUtteranceDelay = 0.005
speechSynthesizer.speak(speechUtterance)
}
Now to create a shortcut for loading the question and to speak the loaded question,
I have implemented the below method in AppDelegate.swift.
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
let viewController = window?.rootViewController as! ViewController
viewController.displayTextOnLabel()
viewController.speakTheQuestion()
return true
}
With the above implementation I can able to load the question and spoken it by Siri.
Now, Anyone can help me how to take user answer with voice command, and how to validate their answer with the correct answer and how to give update about his answer with Siri?
Thanks in andvance.
as of now Sirikit handle only a specific domains and intents.
More about SiriKit
For your use case I would suggest you to use SpeechKit. Speechkit take voice as input and convert it to text. It has accuracy and works amazingly. You can ask question to user and then starts speech recognition using speechKit and read user's reply.
recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in
var isFinal = false
if result != nil {
let string = result?.bestTranscription.formattedString
self.textView.text = string
if((string?.elementsEqual("A"))! || (string?.elementsEqual("Option A"))!)
{
//user said option A is correct, perform your action
}
else if((string?.elementsEqual("B"))! || (string?.elementsEqual("Option B"))!)
{
//user said option B is correct, perform your action
}
//......
isFinal = (result?.isFinal)!
}
if error != nil || isFinal {
self.audioEngine.stop()
inputNode.removeTap(onBus: 0)
self.recognitionRequest = nil
self.recognitionTask = nil
self.microPhoneButton.isEnabled = true
}
})
more about SpeechKit in iOS
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I basically have this issue where this Reporting API only allows me to call it once each 90 seconds.
I'm building an app where I get the data each time you open it, to get the latest data, but I somehow need to stop the app from calling the API if it was before 90s wait and show cached data, how can I do this?
Each time you go to ping the API compare the current time to the last time it was done. Kinda like this:
// set defaults for storage
let userDefaults = UserDefaults.standard
// set time
let date = Date()
//Check Storage
if let theDate = userDefaults.object(forKey: "date") as? Date {
// on successful load compare times
if date.timeIntervalSince(theDate) > 90000 /* I think it runs in milliseconds so I put 90 seconds worth there*/ {
// do API call here
// save time
userDefaults.set(date as! Any, forKey: "date")
} else {
print("too soon")
} else {
// data not successfully loaded
// try to ping API here too
// save time
userDefaults.set(date as! Any, forKey: "date")
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I'm working on creating a Tinder clone on Firebase 100%, from authentication up to real-time chat. I've been successful to the point of showing users their mutually interested matches on the Messages View Controller's tableview. Now my problem lies in creating a chatroom for the matched users. What is the most efficient way of going about this?
Do I create chatroom objects from the Firebase base reference, and assign the chatroom both users, and plug in the chatroom's key into both users?
I'm just confused on how to go about that, because I've written the code to start on that idea above, but how can I make sure that once a chatroom is created, the users will always have that room, and not have a brand new room initialized for them? I think I'm going about it the wrong way... The way I have the code now, the chat rooms will be made on the Messages View Controller when I run this block of code:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
currentUserKey = DataService.ds.REF_CURRENT_USER.key
DataService.ds.REF_CURRENT_USER.observeSingleEventOfType(.Value, withBlock: { snapshot in
if let matchesInterestedIn = snapshot.value["matchesInterestedIn"] {
if matchesInterestedIn != nil {
for (_, value) in matchesInterestedIn as! [String: String] {
self.currentUserInterests.append(value)
}
}
}
})
DataService.ds.REF_USERS.observeSingleEventOfType(.Value, withBlock: { snapshot in
self.admirers = [Match]()
self.matches = [Match]()
if snapshot != nil {
for potentialMatch in snapshot.children {
let potentialMatchData = potentialMatch.valueInExportFormat()
if potentialMatchData["matchesInterestedIn"] != nil {
if let potentialMatchInterests = potentialMatchData["matchesInterestedIn"] as? Dictionary<String, String> {
if potentialMatchInterests.values.contains(self.currentUserKey) {
let interestedMatch = Match(snapshot: potentialMatch as! FDataSnapshot)
self.admirers.append(interestedMatch)
}
}
}
}
}
if self.admirers.count > 0 {
for potentialMatch in self.admirers {
if self.currentUserInterests.contains(potentialMatch.key) {
self.matches.append(potentialMatch)
let chatRoomInitializer = ["user1": self.currentUserKey, "user2": potentialMatch.key]
let chatRoomRef = DataService.ds.REF_CHATROOMS.childByAutoId()
let chatRoomID = chatRoomRef.key
// For some odd reason, the next two lines of code create an endless amount of chatroom objects from the base reference
let currentUserChatRoomRef = DataService.ds.REF_CURRENT_USER.childByAppendingPath("chatrooms").childByAutoId()
currentUserChatRoomRef.setValue(chatRoomID)
let potentialMatchRef = DataService.ds.REF_USERS.childByAppendingPath(potentialMatch.key).childByAppendingPath("chatrooms").childByAutoId()
potentialMatchRef.setValue(chatRoomRef.key)
chatRoomRef.setValue(chatRoomInitializer)
}
}
}
self.tableView.reloadData()
})
}
A common way is to create a room name based on the users in that room.
So if your uid is ron and mine is puf, we end up in a room puf_ron.
Note that I ordered the uids before concatenating, so that they are in the same order no matter who happened to end up first in the list of users.
This approach doesn't require keeping track of what rooms a user is in and ensures that the same two (or more) users always end up in the same room.
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