Last active
August 29, 2015 14:13
-
-
Save eyeplum/bf577e19ae3bb86f85b0 to your computer and use it in GitHub Desktop.
RyCooder - Command Line Music Player written in Swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import AVFoundation | |
// AudioPlayer Class Definition | |
class AudioPlayer: NSObject { | |
private let runLoop: NSRunLoop = NSRunLoop.currentRunLoop() | |
private let stdinHandle: NSFileHandle = NSFileHandle.fileHandleWithStandardInput() | |
private let items: [AVPlayerItem]! | |
private var queuePlayer: AVQueuePlayer! | |
init(contentPath: String) { | |
super.init() | |
let musicFiles = musicFilesInDirectory(contentPath) | |
logMusicFiles(musicFiles) | |
items = preparePlayerItemsWithPaths(musicFiles) | |
queuePlayer = AVQueuePlayer.queuePlayerWithItems(items) as AVQueuePlayer | |
} | |
deinit { | |
NSNotificationCenter.defaultCenter().removeObserver(self) | |
} | |
private func handleInput() { | |
if let inputString = NSString(data: stdinHandle.availableData, encoding: NSUTF8StringEncoding) { | |
var input = inputString.stringByReplacingOccurrencesOfString("\n", withString:"") | |
var handledAsNumber = false | |
if let inputNumber = input.toInt() { | |
if inputNumber > 0 && inputNumber <= items.count { | |
jumpToItemAtIndex(inputNumber - 1) | |
queuePlayer.play() | |
handledAsNumber = true | |
} | |
} | |
if handledAsNumber == false { | |
switch input { | |
case "start": | |
logStart() | |
queuePlayer.play() | |
case "next": | |
queuePlayer.advanceToNextItem() | |
queuePlayer.play() | |
case "previous": | |
jumpToPreviousItem() | |
queuePlayer.play() | |
default: | |
println("Unrecognized selector \"\(input)\" 😦 .") | |
} | |
} | |
} | |
stdinHandle.waitForDataInBackgroundAndNotify() | |
logInputTips() | |
} | |
func start() { | |
handleInput() | |
NSNotificationCenter.defaultCenter().addObserverForName( | |
NSFileHandleDataAvailableNotification, | |
object: nil, | |
queue: NSOperationQueue.mainQueue()) { | |
(notification) in | |
self.handleInput() | |
} | |
runLoop.run() | |
} | |
private func jumpToItemAtIndex(index: Int) { | |
queuePlayer.removeAllItems() | |
for (_, item) in enumerate(items) { | |
item.seekToTime(kCMTimeZero) | |
queuePlayer.insertItem(item, afterItem: nil) | |
} | |
var i = 0 | |
while i < index { | |
queuePlayer.advanceToNextItem() | |
i++ | |
} | |
} | |
private func jumpToPreviousItem() { | |
} | |
private func logMusicFiles(musicFiles: [String]) { | |
println("Music added to player queue:") | |
for (index, musicPath) in enumerate(musicFiles) { | |
println("#\(index + 1) - \(musicPath.lastPathComponent)") | |
} | |
println("\n===== Type \"start\" to begin.") | |
} | |
private func logStart() { | |
println("\n=====> 🎵 RyCooder has taken the stage...") | |
} | |
private func logInputTips() { | |
println("\nType \"next\" or \"previous\" to change song.") | |
println("Type index number to play that song.") | |
} | |
private func preparePlayerItemsWithPaths(musicPaths: [String]) -> [AVPlayerItem] { | |
var items: [AVPlayerItem] = [] | |
for (_ , musicPath) in enumerate(musicPaths) { | |
let itemURL = NSURL.fileURLWithPath(musicPath) | |
let playerItem = AVPlayerItem(URL: itemURL) | |
items.append(playerItem) | |
} | |
return items | |
} | |
private func musicFilesInDirectory(dirPath: String) -> [String] { | |
var result: [String] = [] | |
if let directoryEnumerator = NSFileManager.defaultManager().enumeratorAtPath(dirPath) { | |
let isMusicFile: String -> Bool = { | |
fileName in | |
let pathExtension = fileName.pathExtension | |
return pathExtension == "m4a" || | |
pathExtension == "mp3" | |
} | |
var fileName: String? | |
let fileEnumeration: Void -> Void = { | |
fileName = directoryEnumerator.nextObject() as? String | |
if let validFileName = fileName { | |
if isMusicFile(validFileName) { | |
let fullPath = dirPath.stringByAppendingPathComponent(validFileName) | |
result.append(fullPath) | |
} | |
} | |
} | |
fileEnumeration() | |
while fileName != nil { | |
fileEnumeration() | |
} | |
} | |
return result | |
} | |
} | |
// Script | |
let path = NSFileManager.defaultManager().currentDirectoryPath | |
AudioPlayer(contentPath: path).start() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment