PyObjC: Accessing MPNowPlayingInfoCenter



我正在用Python(3.10版(创建一个MacOS媒体播放器,并希望将其连接到MacOS"正在播放";地位

为了监听媒体密钥事件,我曾使用过PyObjC,但未能连接到MPNowPlayingInfoCenter接口。根据MPNowPlayingInfoCenter文档,我需要通过default()方法访问共享实例,但方法MediaPlayer.MPNowPlayingInfoCenter.default()不存在。

有人通过PyObjC开始使用"正在播放"功能吗?

在Objective-C中,用于获取默认中心的工厂方法被命名为"defaultCenter",这也是您可以在Python中使用的名称。

https://developer.apple.com/documentation/mediaplayer/mpnowplayinginfocenter?language=objc

如果有人发现这个问题,试图在MacOS上的python应用程序中添加"正在播放"功能,下面是用于更新正在播放信息和从操作系统接收命令的连接示例代码。

还请注意,此代码将接收来自键盘媒体键的输入,而无需事件敲击。

我发现这段代码消除了我的音乐播放器中的许多奇怪行为,并建议MacOS上的所有音乐播放器应用程序使用这条路线。

from AppKit import NSImage
from AppKit import NSMakeRect
from AppKit import NSCompositingOperationSourceOver
from Foundation import NSMutableDictionary
from MediaPlayer import MPNowPlayingInfoCenter
from MediaPlayer import MPRemoteCommandCenter
from MediaPlayer import MPMediaItemArtwork
from MediaPlayer import MPMediaItemPropertyTitle
from MediaPlayer import MPMediaItemPropertyArtist
from MediaPlayer import MPMediaItemPropertyPlaybackDuration
from MediaPlayer import MPMediaItemPropertyArtwork
from MediaPlayer import MPMusicPlaybackState
from MediaPlayer import MPMusicPlaybackStatePlaying
from MediaPlayer import MPMusicPlaybackStatePaused

class MacNowPlaying:
def __init__(self):
# Get the Remote Command center
# ... which is how the OS sends commands to the application
self.cmd_center = MPRemoteCommandCenter.sharedCommandCenter()
# Get the Now Playing Info Center
# ... which is how this application notifies MacOS of what is playing
self.info_center = MPNowPlayingInfoCenter.defaultCenter()
# Enable Commands
self.cmd_center.playCommand()           .addTargetWithHandler_(self.hPlay)
self.cmd_center.pauseCommand()          .addTargetWithHandler_(self.hPause)
self.cmd_center.togglePlayPauseCommand().addTargetWithHandler_(self.hTogglePause)
self.cmd_center.nextTrackCommand()      .addTargetWithHandler_(self.hNextTrack)
self.cmd_center.previousTrackCommand()  .addTargetWithHandler_(self.hPrevTrack)
def hPlay(self, event):
"""
Handle an external 'playCommand' event
"""
...
return 0
def hPause(self, event):
"""
Handle an external 'pauseCommand' event
"""
...
return 0
def hTogglePause(self, event):
"""
Handle an external 'togglePlayPauseCommand' event
"""
...
return 0
def hNextTrack(self, event):
"""
Handle an external 'nextTrackCommand' event
"""
...
return 0
def hPrevTrack(self, event):
"""
Handle an external 'previousTrackCommand' event
"""
...
return 0
def onStopped(self):
"""
Call this method to update 'Now Playing' state to: stopped
"""
self.info_center.setPlaybackState_(MPMusicPlaybackStateStopped)
return 0
def onPaused(self):
"""
Call this method to update 'Now Playing' state to: paused
"""
self.info_center.setPlaybackState_(MPMusicPlaybackStatePaused)
return 0
def onPlaying(self, title: str, artist: str, length, int, cover: bytes = None):
"""
Call this method to update 'Now Playing' state to: playing
:param title: Track Title
:param artist: Track Artist
:param length: Track Length
:param cover: Track cover art as byte array
"""
nowplaying_info = NSMutableDictionary.dictionary()
# Set basic track information
nowplaying_info[MPMediaItemPropertyTitle]            = title
nowplaying_info[MPMediaItemPropertyArtist]           = artist
nowplaying_info[MPMediaItemPropertyPlaybackDuration] = length
# Set the cover art
# ... which requires creation of a proper MPMediaItemArtwork object
cover = ptr.record.cover
if cover is not None:
# Apple documentation on how to load and set cover artwork is less than clear
# The below code was cobbled together from numerous sources
# ... REF: https://stackoverflow.com/questions/11949250/how-to-resize-nsimage/17396521#17396521
# ... REF: https://developer.apple.com/documentation/mediaplayer/mpmediaitemartwork?language=objc
# ... REF: https://developer.apple.com/documentation/mediaplayer/mpmediaitemartwork/1649704-initwithboundssize?language=objc
img = NSImage.alloc().initWithData_(cover)
def resize(size):
new = NSImage.alloc().initWithSize_(size)
new.lockFocus()
img.drawInRect_fromRect_operation_fraction_(
NSMakeRect(0, 0, size.width, size.height),
NSMakeRect(0, 0, img.size().width, img.size().height),
NSCompositingOperationSourceOver,
1.0,
)
new.unlockFocus()
return new
art = MPMediaItemArtwork.alloc().initWithBoundsSize_requestHandler_(img.size(), resize)
nowplaying_info[MPMediaItemPropertyArtwork] = art
# Set the metadata information for the 'Now Playing' service
self.info_center.setNowPlayingInfo_(nowplaying_info)
# Set the 'Now Playing' state to: playing
self.info_center.setPlaybackState_(MPMusicPlaybackStatePlaying)
return 0

上面的代码是从我自己的项目中简化的,作为通过PyObjC连接到MacOS的示例。这是苹果提供的功能的部分实现,旨在仅支持基本的"正在播放"信息中心交互。在macOS Monterey(12.4(上测试。

相关内容

  • 没有找到相关文章

最新更新