我正在尝试制作一个工具,可以自动识别非 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)
首先,仅供参考,我在
https://github.com/pywinrt上启动了 PyWinRT 和
winrt
包的社区分支,并在 PyPI 上发布了单独的命名空间包,例如 winrt.Windows.Media.Control 。其中包含对未维护的 winrt
包的许多修复,包括修复一些严重的问题,例如在 await
方法的每个 _async()
上泄漏 COM 对象。新软件包还包括类型提示,使解决此类问题变得更加容易。
事件处理程序的使用方式目前记录在here。
因此,对于这种特定情况,您的代码可能如下所示:
import asyncio
import contextlib
from winrt.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:
...
async def main():
async with contextlib.AsyncExitStack() as stack:
loop = asyncio.get_running_loop()
manager = await SessionManager.request_async()
# by default, callbacks happen on a background thread, so we need
# to use call_soon_threadsafe to run the update on the main thread
def handle_sessions_changed(
manager: SessionManager, args: SessionsChangedEventArgs
) -> None:
loop.call_soon_threadsafe(update_sessions(manager))
# add callback to handle any future changes
sessions_changed_token = manager.add_sessions_changed(handle_sessions_changed)
# ensure the callback is removed when the function exits
stack.callback(manager.remove_sessions_changed, sessions_changed_token)
# handle current state
await update_sessions(manager)
event = asyncio.Event()
# wait forever - a real app would call event.set() to end the app
await event.wait()
if __name__ == "__main__":
asyncio.run(main())
由于某种原因,该事件实际上似乎并未触发,但快速网络搜索表明这是
GlobalSystemMediaTransportControlsSessionManager.SesssionsChanged
的常见问题,并且似乎与 Python 绑定无关。