def start(self): self.timer = objc.ObjCClass("NSTimer").timerWithTimeInterval( 0.1, target=self, selector=objc.SEL("pollControllerWithSender:"), userInfo=None, repeats=True) objc.ObjCClass("NSRunLoop").currentRunLoop().addTimer( self.timer, forMode="kCFRunLoopCommonModes") pass
def tableView_cellForRowAtIndexPath_(self, tableView, indexPath): if self.isEnumerating: cellIdentifer = "MQVActivityCell" cell = tableView.dequeueReusableCellWithIdentifier( cellIdentifer) if cell is None: cell = objc.ObjCClass( "UITableViewCell").alloc().initWithStyle( 0, reuseIdentifier=cellIdentifer) pass cell.userInteractionEnabled = False activityIndicator = objc.ObjCClass( "UIActivityIndicatorView").alloc( ).initWithActivityIndicatorStyle(100) activityIndicator.hidesWhenStopped = True activityIndicator.center = objc.NSPoint( self.tableView.frame.size.width / 2, cell.frame.size.height / 2) cell.contentView.addSubview(activityIndicator) activityIndicator.startAnimating() return cell cellIdentifer = "MQVSongCell" cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifer) if cell is None: cell = objc.ObjCClass("UITableViewCell").alloc().initWithStyle( 3, reuseIdentifier=cellIdentifer) pass if len(self.songList) < indexPath.row: return cell song = self.songList[indexPath.row] cell.textLabel.text = song.title cell.detailTextLabel.text = song.artist cell.imageView.image = song.art if song.exists: cell.userInteractionEnabled = True cell.textLabel.enabled = True cell.detailTextLabel.enabled = True pass else: cell.userInteractionEnabled = False cell.textLabel.enabled = False cell.detailTextLabel.enabled = False pass return cell
def reorder(self, targetItemIndex: int, targetPositionIndex: int): """Reorders the song at the targetItemIndex to the targetPositionIndex.""" tracklist = self._getResponse().tracklist # convert the indices from the queue to the tracklist indices. nowPlayingitemIndex = tracklist.playingItem.indexPath.row targetItemIndex += nowPlayingitemIndex + 1 targetPositionIndex += nowPlayingitemIndex + 1 collection = tracklist.items maxTargetPosition = collection.numberOfItemsInSection(0) if targetItemIndex > maxTargetPosition: raise IndexError( "targetItemIndex ({}) must be lower than {}.".format( targetItemIndex - (nowPlayingitemIndex + 1), maxTargetPosition - nowPlayingitemIndex)) elif targetPositionIndex > maxTargetPosition: raise IndexError( "targetPositionIndex ({}) must be lower than {}.".format( targetPositionIndex - (nowPlayingitemIndex + 1), maxTargetPosition - nowPlayingitemIndex)) elif targetPositionIndex < 0: raise IndexError( "targetPositionIndex ({}) must be 0 or higher.".format( targetPositionIndex - (nowPlayingitemIndex + 1))) targetItemIndexPath = objc.ObjCClass("NSIndexPath").indexPathForRow( targetItemIndex, inSection=0) targetItem = collection.itemAtIndexPath(targetItemIndexPath) positionalItemIndexPath = objc.ObjCClass( "NSIndexPath").indexPathForRow(targetPositionIndex - 1, inSection=0) positionalItem = collection.itemAtIndexPath(positionalItemIndexPath) reorderCommand = tracklist.reorderCommand() if reorderCommand.canMoveItem(targetItem) is False: raise RuntimeError("Unable to move item at targetItemIndex.") reorderRequest = reorderCommand.moveItem(targetItem, afterItem=positionalItem) self.reorderRequestCompletion.clear() objc.ObjCClass("MPCPlayerChangeRequest").performRequest( reorderRequest, completion=self._reorderRequestHandler) self.reorderRequestCompletion.wait() # wait for the command to actually take effect. time.sleep(0.1) pass
def __init__(self, callback, allowMultiple=False): self.callback = callback self.tableViewController = objc.ObjCClass("UITableViewController").alloc().initWithStyle(0) self.tableViewController.tableView.allowsMultipleSelection = allowMultiple self.dataSource = objc.ObjCClass("MQVDataSource").alloc().initWithTableView(self.tableViewController.tableView) self.tableViewController.tableView.dataSource = self.dataSource self.navigationController = objc.ObjCClass("MQVNavigationController").alloc().initWithRootViewController(self.tableViewController) self.navigationController.MQVDelegate = self self.closeEvent = threading.Event() pass
def __init__(self): self.musicPlayer = objc.ObjCClass( "MPMusicPlayerController").systemMusicPlayer self.requestController = self.musicPlayer.requestController self.reorderRequestCompletion = threading.Event() self.clearRequestCompletion = threading.Event() self.prepareCompletion = threading.Event() def reorderRequestHandler(arg1: objc.ObjCInstance, arg2: objc.ObjCInstance, arg3: objc.ObjCInstance, arg4: int) -> None: self.reorderRequestCompletion.set() pass self._reorderRequestHandler = objc.Block(reorderRequestHandler) def clearRequestHandler(arg1: objc.ObjCInstance, arg2: objc.ObjCInstance, arg3: objc.ObjCInstance, arg4: int) -> None: self.clearRequestCompletion.set() pass self._clearRequestHandler = objc.Block(clearRequestHandler) def prepareHandler(error: objc.ObjCInstance) -> None: self.prepareCompletion.set() pass self._prepareHandler = objc.Block(prepareHandler) pass
def initWithTableView_(self, tableView): self.musicPlayer = objc.ObjCClass( "MPMusicPlayerController").systemMusicPlayer self.tableView = tableView self.songList = [] self.isEnumerating = False self.enumerationLock = threading.Lock() self.beginEnumeratingSongs() self.changeDetector = objc.ObjCClass( "MQVSongChangeDetector").alloc().init() self.changeDetector.MQVCallback = self.beginEnumeratingSongs self.changeDetector.start() return self
def present(self): """Presents the viewer.""" application = objc.ObjCClass("UIApplication").sharedApplication rootViewController = application.keyWindow.rootViewController rootViewController.presentViewController(self.navigationController, animated=True, completion=None) self.closeEvent.clear() pass
def reloadTable(self): self.tableView.reloadData() if self.tableView.numberOfRowsInSection(0) != 0: indexZero = objc.ObjCClass("NSIndexPath").indexPathForRow( 0, inSection=0) self.tableView.scrollToRowAtIndexPath(indexZero, atScrollPosition=1, animated=True) pass pass
def init(self): """set attribute MQVCallback to receive notifications.""" self.musicPlayer = objc.ObjCClass( "MPMusicPlayerController").systemMusicPlayer self.MQVCallback = None index = self.musicPlayer.indexOfNowPlayingItem + 1 song = self.musicPlayer.nowPlayingItemAtIndex(index) if song: self.lastSong = song.copy() return self
def replaceQueue(self, songList: list): """ Clears the current queue and replaces it with the given list. This will preserve the currently playing song. parameters ---------- songList : list A list of MQVSong instances. """ songList = [song.songObject for song in songList] songList.insert(0, self.musicPlayer.nowPlayingItem) self.musicPlayer.pause() currentTime = self.musicPlayer.currentPlaybackTime clearRequest = self._getResponse().tracklist.resetCommand().clear() self.clearRequestCompletion.clear() objc.ObjCClass("MPCPlayerChangeRequest").performRequest( clearRequest, completion=self._clearRequestHandler) self.clearRequestCompletion.wait() self.musicPlayer.shuffleMode = 1 songCollection = objc.ObjCClass( "MPMediaItemCollection").collectionWithItems(songList) self.musicPlayer.setQueueWithItemCollection(songCollection) self.musicPlayer.prepareToPlay() self.prepareCompletion.clear() self.musicPlayer.prepareToPlayWithCompletionHandler( self._prepareHandler) self.prepareCompletion.wait() self.musicPlayer.play() self.musicPlayer.currentPlaybackTime = currentTime pass
def initWithRootViewController_(self, rootController): self = objc.ObjCInstance( objc.send_super(__class__, self, "initWithRootViewController:", rootController)) # pylint: disable=undefined-variable if self: self.MQVDelegate = None self.modalPresentationStyle = 0 stopButton = objc.ObjCClass( "UIBarButtonItem").alloc().initWithBarButtonSystemItem( 14, target=self, action=objc.SEL("closeAction")) reloadButton = objc.ObjCClass( "UIBarButtonItem").alloc().initWithTitle( "Reload", style=0, target=self, action=objc.SEL("reloadAction")) shuffleButton = objc.ObjCClass( "UIBarButtonItem").alloc().initWithTitle( "Shuffle", style=0, target=self, action=objc.SEL("shuffleAction")) doneButton = objc.ObjCClass( "UIBarButtonItem").alloc().initWithTitle( "Done", style=2, target=self, action=objc.SEL("doneAction")) self.navigationBar.topItem.leftBarButtonItem = stopButton self.navigationBar.topItem.rightBarButtonItems = [ doneButton, shuffleButton, reloadButton ] pass return self
def enumerateSongs(self): newSongList = [] currentIndex = self.musicPlayer.indexOfNowPlayingItem + 1 maxIndex = self.musicPlayer.numberOfItems() for index in range(currentIndex, maxIndex): song = self.musicPlayer.nowPlayingItemAtIndex(index) if song and "MPModelObjectMediaItem" in song.debugDescription and song.title is None: break else: newSongList.append( objc.ObjCClass("MQVSong").alloc().initWithSong(song)) pass pass self.songList = newSongList self.enumerationLock.release() self.isEnumerating = False self.reloadTable() pass
import rubicon.objc as objc import objc_util # pylint: disable=import-error import threading import time from .mqv_song import MQVSong from .mqv_songchangedetector import MQVSongChangeDetector _warnForDefinedClass = False NSLog = objc_util.c.NSLog NSLog.argtypes = [objc_util.c_void_p] try: MQVDataSource = objc.ObjCClass("MQVDataSource") if _warnForDefinedClass: print("MQVDataSource already defined") except NameError: UITableViewDataSource = objc.ObjCProtocol("UITableViewDataSource") class MQVDataSource(objc.NSObject, protocols=[UITableViewDataSource]): @objc.objc_method def initWithTableView_(self, tableView): self.musicPlayer = objc.ObjCClass( "MPMusicPlayerController").systemMusicPlayer self.tableView = tableView self.songList = [] self.isEnumerating = False
import rubicon.objc as objc _warnForDefinedClass = False try: MQVNavigationController = objc.ObjCClass("MQVNavigationController") if _warnForDefinedClass: print("MQVNavigationController already defined") except NameError: UINavigationController = objc.ObjCClass("UINavigationController") class MQVNavigationController(UINavigationController): @objc.objc_method def initWithRootViewController_(self, rootController): self = objc.ObjCInstance( objc.send_super(__class__, self, "initWithRootViewController:", rootController)) # pylint: disable=undefined-variable if self: self.MQVDelegate = None self.modalPresentationStyle = 0 stopButton = objc.ObjCClass( "UIBarButtonItem").alloc().initWithBarButtonSystemItem( 14, target=self, action=objc.SEL("closeAction")) reloadButton = objc.ObjCClass( "UIBarButtonItem").alloc().initWithTitle( "Reload", style=0, target=self, action=objc.SEL("reloadAction")) shuffleButton = objc.ObjCClass(
from musicruntime.musicqueueviewer import MusicQueueViewer from musicruntime.musicplayercontroller import MusicPlayerController def callback(selected: list, sender: MusicQueueViewer): controller = MusicPlayerController() currentIndex = 0 for selection in selected: try: controller.reorder(selection[0], currentIndex) pass except Exception as e: print("Unable to move song ({}), Exception({})".format( selection[1].title, e)) pass currentIndex += 1 pass pass viewer = MusicQueueViewer(callback, allowMultiple=True) viewer.present() viewer.waitModal() app = objc.ObjCClass("UIApplication").sharedApplication nav = app._systemNavigationAction() if nav: nav.sendResponseForDestination(0) pass
import rubicon.objc as objc _warnForDefinedClass = False try: MQVSong = objc.ObjCClass("MQVSong") if _warnForDefinedClass: print("MQVSong already defined") except NameError: class MQVSong(objc.NSObject): """ A wrapper around MPMediaItem. Since this is a ObjCClass, it should be initialized like so, MQVSong.alloc().initWithSong(songObject) Attributes ---------- title : str artist : str exists : bool If the song exists in the users library art : rubicon.objc.ObjCInstance A UIImage instance of the song's artwork parameters ----------
def shuffleAction(self): musicPlayer = objc.ObjCClass("MPMusicPlayerController").systemMusicPlayer musicPlayer.shuffleMode = 1 musicPlayer.shuffleMode = 2 pass
import rubicon.objc as objc import objc_util # pylint: disable=import-error _warnForDefinedClass = False try: MQVSongChangeDetector = objc.ObjCClass("MQVSongChangeDetector") if _warnForDefinedClass: print("MQVSongChangeDetector already defined") except NameError: class MQVSongChangeDetector(objc.NSObject): lastSong = objc.objc_property() @objc.objc_method def init(self): """set attribute MQVCallback to receive notifications.""" self.musicPlayer = objc.ObjCClass( "MPMusicPlayerController").systemMusicPlayer self.MQVCallback = None index = self.musicPlayer.indexOfNowPlayingItem + 1 song = self.musicPlayer.nowPlayingItemAtIndex(index) if song: self.lastSong = song.copy() return self @objc.objc_method def pollControllerWithSender_(self, sender): index = self.musicPlayer.indexOfNowPlayingItem + 1