I am building a music player app meant to mimic radio or internet streaming automation. I have already succeeded in pulling music from playlists and filtering by last date played so songs do not frequently repeat (a pet peeve about my iPod). I want it to schedule playing short station IDs every quarter hour from a separate playlist, then return to the current playlist or switch to a new one. The roadblocks I’m hitting are getting a repeating timer to wait until a song is over before playing an ID, and playing only one ID before switching back to music. A notification observer…
NotificationCenter.default.addObserver(self, selector:#selector(ViewController.quarterHour), name: NSNotification.Name.MPMusicPlayerControllerNowPlayingItemDidChange, object: nil)
…trips a timer…
self.timer2 = Timer(fireAt: date, interval: 1, target: self, selector: #selector(ViewController.runVoicer(_:)), userInfo: nil, repeats: true)
self.timer2.tolerance = 0.1
…that runs this function:
@objc func quarterHour() {
self.timer2 = Timer.scheduledTimer(timeInterval: 900, target: self, selector: #selector(ViewController.runVoicer(_:)), userInfo: nil, repeats: true)
self.timer2.tolerance = 0.1
}
The media query that selects from the Voicers playlist…
@objc func runVoicer(_:AnyObject) {
mp.pause()
let queryVoice = MPMediaQuery.songs()
let predicate = MPMediaPropertyPredicate(value: "Voicers",
forProperty: MPMediaPlaylistPropertyName,
comparisonType: .equalTo)
queryVoice.addFilterPredicate(predicate)
var collection = [MPMediaItem]()
let unixDefault = Date(timeIntervalSince1970: 100)
if let voicers = queryVoice.items {
collection = voicers.sorted{$0.lastPlayedDate ?? unixDefault > $1.lastPlayedDate ?? unixDate}
}
let voiceCollection = MPMediaItemCollection(items: collection)
mp.setQueue(with: voiceCollection)
mp.play()
fetchRockPlaylist()
}
…not only interrupts a song when the timer goes off instead of using the “…NowPlayingItemDidChange” notification but also keeps playing instead returning to the function listed at bottom after one play, because I cannot land on any method for isolating the first item in the voiceCollection array.