任务
我正在尝试制作一个工具,可以自动识别非 Spotify 源的播放,并在其他音频播放期间暂停 Spotify。我一直在使用 Microsoft 的 Python WinRT 投影 ( https://github.com/Microsoft/xlang/tree/master/src/package/pywinrt/projection )。我可以让程序识别音频源和播放状态,但只能从调用该函数的那一刻开始。之后就停止更新。
问题
我的主要问题是理解 WinRT 如何在 Python 中实现事件处理。 Windows 文档讨论了“更改的播放事件”( https://learn.microsoft.com/en-us/uwp/api/windows.media.control.globalsystemmediatransportcontrolssession.playbackinfochanged?view=winrt-22000 ),但我找不到任何关于如何在 API 的 Python 投影中完成此操作的线索。
当前状态
这是到目前为止我的代码,感谢任何帮助。
import asyncio
import time
from winrt.windows.media.control import \
GlobalSystemMediaTransportControlsSessionManager as MediaManager
from winrt.windows.media.control import \
GlobalSystemMediaTransportControlsSession as SessionMananger
from winrt.windows.media.control import \
PlaybackInfoChangedEventArgs as PlaybackEventArgs
async def toggle_spotify():
sessions = await MediaManager.request_async() #grab session manager instance
all_sessions = sessions.get_sessions() #grab sequence of current instances
for current_session in all_sessions: #iterate and grab desired instances
if "chrome" in current_session.source_app_user_model_id.lower():
chrome_info = current_session.get_playback_info()
if "spotify" in current_session.source_app_user_model_id.lower():
spotify_manager = current_session
spotify_info = current_session.get_playback_info()
if chrome_info.playback_status == 4 and spotify_info.playback_status == 4: #status of 4 is playing, 5 is paused
await spotify_manager.try_toggle_play_pause_async()
elif chrome_info.playback_status == 5 and spotify_info.playback_status == 5:
await spotify_manager.try_toggle_play_pause_async()
# print(f"chrome playback status: {chrome_info.playback_status}")
# print(f"chrome playback status: {spotify_info.playback_status}")
# print("+++++++++++++++++")
# time.sleep(2)
if __name__ == '__main__':
#asyncio.run(get_media_info())
while True: #mimicking event handling by looping
asyncio.run(toggle_spotify())
time.sleep(0.1)
最佳答案
首先,仅供引用,我已经启动了 PyWinRT 和 winrt
的社区分支。包裹在https://github.com/pywinrt并发表了winsdk PyPI 上的包。这包含对看似未维护的许多修复 winrt
包,包括修复一些严重的问题,例如在每个 await
上泄漏 COM 对象的_async()
方法。新winsdk
包还包含类型提示,使解决此类问题变得更加容易。
当前记录了事件处理程序的使用方式 here .
因此,对于这种特定情况,您的代码可能如下所示:
import asyncio
from winsdk.windows.media.control import (
GlobalSystemMediaTransportControlsSessionManager as SessionManager,
GlobalSystemMediaTransportControlsSessionPlaybackStatus as PlaybackStatus,
SessionsChangedEventArgs,
)
async def update_sessions(manager: SessionManager) -> None:
for session in manager.get_sessions():
if "chrome" in session.source_app_user_model_id.lower():
chrome_info = session.get_playback_info()
if chrome_info.playback_status == PlaybackStatus.PLAYING:
...
def handle_sessions_changed(manager: SessionManager, args: SessionsChangedEventArgs) -> None:
asyncio.create_task(update_sessions(manager))
async def main():
manager = await SessionManager.request_async()
# add callback to handle any future changes
sessions_changed_token = manager.add_sessions_changed(handle_sessions_changed)
try:
# handle current state
asyncio.create_task(update_sessions(manager))
event = asyncio.Event()
# wait forever - a real app would call event.set() to end the app
await event.wait()
finally:
# remove the callback
manager.remove_sessions_changed(sessions_changed_token)
if __name__ == '__main__':
asyncio.run(main())
出于某种原因,该事件实际上似乎并未触发,但快速网络搜索表明这是 GlobalSystemMediaTransportControlsSessionManager.SesssionsChanged
的常见问题。并且似乎与 Python 绑定(bind)无关。
另请注意 asyncio.create_task()
仅当 update_sessions()
时才需要实际上是在等待一些东西,否则可以直接调用。
关于python - 使用 WinRT for python 进行事件处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71005262/