使用Python获取Zune和Windows Media Player正在播放的歌曲的方法。

9
我的一个应用程序可以从多个音乐播放器中检索当前播放的歌曲。然而,我在实现Zune和Windows Media Player时遇到了很大的麻烦。
我已经在这个主题上做了很多谷歌搜索,不幸的是,它只让我越来越困惑。
对于我的其他应用程序,我通常会做以下操作:
1. 每4秒迭代所有打开的窗口 2. 获取所有窗口的标题 3. 检查标题是否符合某种模式(例如,“-Spotify”) 4. 如果有,调整标题以进行输出
WMP的标题中没有当前播放的歌曲。
Zune有,但它每隔几秒钟就在标题,专辑和艺术家之间旋转。这对于我的当前方法来说非常不可靠,尽管可能是可行的。
Windows Media Player 我还尝试使用Windows Media Player的COM组件。
import win32com.client
wmp = win32com.client.gencache.EnsureDispatch('WMPlayer.OCX')

# some function I don't have here, it retrieves the current playing song
# and other data

这个问题的主要问题在于它需要你以编程方式启动WMP,这将极大地不友好。
那么,我找到了什么?此SO帖子重定向到WMP.dll。但据我所知,它与COM具有相同的问题,必须以编程方式启动它。如果没有,我真的很想知道如何在Python中使用该dll。
还有另一个稍微不太hacky的解决方案,即为WMP编写插件,让我的用户下载该插件并从该插件检索数据。我不想去那里,因为我没有任何C语言的经验,也不想为此深入研究插件文档。
走Zune方法是循环遍历三种标题状态,确定当前处于哪种状态,并找到其他两种状态的位置。
例如: 前5秒钟的标题是:Super_song 接下来的5秒钟的标题是:By Power_artist 接下来的5秒钟的标题是:Good_album(日期)
所以,我可以通过制作一个日期的正则表达式来确定专辑标题,然后等待几秒钟找到标题和艺术家,但这显然不是一个好的解决方案,因为它需要一段时间,并且也不是非常可靠(例如,如果歌曲名称包含日期怎么办)。下一个问题是它也不一致,有时标题会长时间保持为Zune。不知道为什么。因此,继续下一个方法。有一个叫做ZuneNowPlaying的应用程序。这个应用程序“某种方式”从Zune获取当前播放的歌曲并将其放入注册表中,但这个东西不能与我的粗糙的标题方法一起使用,因为它在歌曲更改时立即更改注册表。这是我在程序的工作版本中使用的解决方案,但许多用户报告说它根本不起作用,什么都没有发生。我检查了程序,它并不总是可靠地更改注册表。我不知道为什么,也不知道如何修复它。因此,这个解决方案也被-取消-了。
“MsnMsgrUIManager”#000000”这个名称是否导致zune软件向其发送正在播放的歌曲信息?有没有一种方法可以在不进行此类黑客攻击的情况下获取此信息?
这是在讨论Zune Now Playing应用程序时发现的。不幸的是,源代码不可用,至少我找不到。有人对此有更多了解吗?
第三种方法是再次使用dll。它被称为ZuneShell.dll。我不记得在哪里读到过它,也无法通过谷歌找到它,因为所有结果都是“ZuneShell.dll是病毒吗?”。
再次遇到的问题是,即使我有文档,我也不知道如何使用它,甚至不知道它是否是我一直在寻找的东西。
可能要考虑的其他方向
在浏览有关此主题的内容时,我看到人们谈论直接从GUI中检索数据。我不确定它是否合法、可能或者我的记忆是否正确,但如果可能的话,有人能否将我重定向到更多相关内容?
还有其他任何事情。

你有没有考虑尝试从Zune进程的内存中读取数据?似乎有一个(过时的)Python库pymem可以实现这一功能。 - loopbackbee
@goncalopp 我还没有,我会去了解一下。 - Azeirah
似乎可以使用dll访问运行中的WMP实例,但我认为这并不容易,可以参考此处链接:http://www.darinhiggins.com/gaining-access-to-a-running-instance-of-windows-media-player-in-vb-net/。也许你可以从Pidgin的“CurrentTrack”插件源码中获取其他启示,链接:http://sourceforge.net/p/currenttrack/code/HEAD/tree/trunk/currenttrack/src/wmp.cpp。不过要注意了:它是用C++编写的,并且作者有评论说:“这个解决方案很糟糕……但在我找到如何使用COM API之前……” - user2379410
ZuneNowPlaying的源代码可在http://znp.codeplex.com/SourceControl/latest#ZuneNowPlaying/ZuneNowPlaying.cpp上获取。 - manuell
2个回答

3
我有一份C++代码,可以打印WMP当前播放的媒体名称。这是一个简单的控制台应用程序(78行代码)。
步骤:
1. 实现一个基本的COM对象,实现IUnknown、IOleClientSite、IServiceProvider和IWMPRemoteMediaServices接口。使用ATL模板CComObjectRootEx可以很容易地完成此操作。只有IServiceProvider::QueryService和IWMPRemoteMediaServices::GetServiceType方法需要编写(简单的)代码。所有其他方法都可以返回E_NOTIMPL。
2. 实例化“WMPlayer.OCX”COM对象(在我的情况下,通过CoCreateInstance)。
3. 通过QueryInterface从对象中检索IOleObject接口指针。
4. 从步骤1中看到的类中实例化一个对象(我使用CComObject<> :: CreateInstance模板)。
5. 使用从步骤3获得的接口的SetClientSite方法,传递指向您的OleClientSite实现的指针。
6. 在SetClientSite调用期间,WMP将回调您:首先要求IServiceProvider接口指针,其次调用QueryService方法,要求IWMPRemoteMediaServices接口指针。返回IWMPRemoteMediaServices的实现,第三次,您将再次被调用,通过GetServiceType。然后必须返回“Remote”。现在您已连接到运行的WMP实例。
7. 查询COM对象以获取IWMPMedia接口指针。
8. 如果7)没有返回NULL,则读取IWMPMedia :: name属性。
9. 完成
上述所有内容都是使用VS2010 / Windows Seven测试的,并且在WMP运行时进行了测试(如果没有媒体播放器进程正在运行,则不执行任何操作)。
我不知道您是否能够/想要在Python中实现COM接口和对象。如果您对我的C++代码感兴趣,请告诉我。您可以将该代码用于C++ DLL中,然后从Python调用它。

很遗憾,这个解释对我来说太模糊了,我对第一步应该做什么毫无头绪。而且关于如何在脚本语言(特别是Python)中使用COM的文档非常少。 编辑:如果你不能帮我解决Python的问题,我会开一个新的问题,把问题转到Python win32api用户那里。 - Azeirah
@Azeirah 我无法帮助你处理Python。你有两个选择:1)使用C++构建一个DLL(或EXE),它将是一个COM服务器,可以从Python中调用。或者2)如果可能在Python中实现一个不继承自IDispatch的接口,则直接在Python中实现整个过程。 - manuell
嘿,这是你的 poke :) - Azeirah
在我的旧电脑上发现。仍然可以工作。构建环境是Visual Studio 2010。你想要所有解决方案文件还是仅需要独特的C++文件? - manuell
明天早上会发送电子邮件。来自法国。 - manuell
显示剩余3条评论

1

我刚发现了一个很酷的Python工具,可以查询任何程序的所有控件。 简单、直接、易于阅读。在这里:

http://www.brunningonline.net/simon/blog/archives/winGuiAuto.py.html

通过这样做,您可以从图形用户界面获取信息。

您也可以获取加载的文件列表。它适用于大多数媒体播放器。 您可以通过编程方式获得此信息,如下所示:

http://www.codeproject.com/Articles/18975/Listing-Used-Files

这是C++,但在那个点上,你可以包装本地代码。这样你就需要自己提取ID3标签。这可能值得一试,因为它将是一个通用解决方案。

检索所有文件实际上听起来像是一个不错的备份计划。然而,WMP经常打开两个文件,所以这很难处理。如果其他方法都失败了,我想我会更深入地研究这个问题。 - Azeirah
它并不查询所有文件,只查询当前正在播放的文件。WMP 的播放列表中显示了每首歌曲,但只有当前播放的歌曲会被持续打开以进行读取。我的第二个建议的解决方案只查找那一个已打开的文件句柄。顺便问一下,你对 pywinauto 有什么看法? - Kobor42

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接