Tinko

@Tinko2年前

2016-10-17
18:05
Tinkoの日常

用AppleScript玩弄网易云音乐

其实最早就是想用 AppleScript 来折腾,但是奈何……网……易……没……写……文……档……
这也没什么好奇怪的,国内 Mac 软件基本不写。
那么怎么办,之前用 Qt 写的日志解析是一条路
但是根据这么久的实际测试来看,网易云音乐写入 Log 的稳定性还是比较堪忧的,经常切歌之后不写 log
那么,回到最初的起点】呸,来玩玩 AppleScript 。

网易云音乐客户端由于用的是苹果的系统原生 UI 控件,自然也支持 AppleScript 最基础的共通的部分。折腾了一下午,来写写折腾结果。

1、歌词显示
歌词显示有两种方式,一种桌面歌词,一种菜单栏歌词。其中,菜单栏歌词我无论如何也抓不到, AppleScript 只能捕捉到一个 menu bar
2 ,里面只有一个 menu bar item ,没有实际内容。而包含歌词和按钮控件的则是一个在 AppleScript 捕获不到(或者我学艺不精)的 NSAccessibilityMenuExtrasMenuBar 里面,具体结构可以用 Xcode 自带的 Accessibility Inspector 去检查下。
桌面歌词模式就很简单粗暴,直接创建一个没有标题的窗口 YYYDesktopLyricsWindow ,结构很简单:

由于在这个模式下,在 NeteaseMusic 进程下这个窗口会插入到主窗体前面,在 AppleScript 数组从 1 开始, 0 和 1 等价,所以桌面歌词插入之后序号就是 1 ,主窗体则顺延到 2 。由于主窗体具有标题,在这里可以进行判断具体是哪个窗体。又同时因为主窗体具有标题,在有需要获取主窗体的时候可以直接使用 of window “网易云音乐”
下面的代码可以在显示桌面歌词的情况下获取到当前行歌词内容:

tell application "System Events" to tell process "NeteaseMusic"
	tell UI element 1 of window 1
		get value
	end tell
end tell

在不显示外部歌词的时候,唯一的获取办法就是通过展开当前播放的歌曲详情页面来观察滚动歌词。事实证明,在收起歌曲详情页面之后,页面上所有的 UI 都会被销毁,也就意味着要获得当前行必须随时展开详情页。根据检查,当前高亮行的高度比其他行高度大 1 像素……但是 AppleScript 我并没有发现单独抓取高度的方法,在转了一圈之后,无意之间选中了包含一行翻译和原文的一个 group 并在 Accessibility Inspector 中 DOM Class List 为 4 ,而其他行只有 3 !我就说嘛 cyzju 前辈他们不至于蛋疼到每高亮一行就去改变高度吧。抓出来之后,多出来的一项是 “z-crt” 。那么这样就可以抓到高亮行了:

tell application "System Events" to tell process "NeteaseMusic"
	tell group 7 of group 2 of group 12 of UI element 1 of scroll area 1 of window "网易云音乐"
		get value of UI element of every UI element whose "z-crt" is in the value of attribute "AXDOMClassList"
	end tell
end tell

通过上面抓取整个 group 的 value ,抓出来的结果是类似于这样的一串:

{{“トリックオアトリート* “, “【不给糖就捣乱*】”}}

如果没有翻译,那就是像这样

{{“Let’s trick or treat”}}

尝试在 get value 再加上一段 of UI element 1 之类的代码,输出结果立即异常,一大串 missing ,具体原因还没分析……
不过这样也好,总之……原文译文都有!
缺点就是还得再处理一遍,不能直接进 obs 用。

2、获取时长
当前时长可以通过下面的代码获得:

tell application "System Events" to tell process "NeteaseMusic"
	get value of UI element 1 of group 4 of group 1 of group 8 of UI element 1 of scroll area 1 of window "网易云音乐"
	--get value of UI element 1 of group 4 of group 1 of group 7 of UI element 1 of scroll area 1 of window "网易云音乐"
end tell

其中,第一行也就是 group 8 那行是给在收起详情页之后的,拉开详情页之后是 group 7 ,个人猜测是拉开详情页之后销毁了下面的左侧导航栏和右侧页面。

获取总时长直接在上面把第一个 group 4 换成 group 6 就行。总市场也可以通过运行日志抓取。在运行日志中也有 LRC 格式的歌词内容,通过结合日志中的 LRC 也可以实现同步滚动歌词。

如果不考虑绝对的稳定性和实时性,以下方法推荐不用(太繁琐了还不如读 log )

3、当前曲目

tell application "System Events" to tell process "NeteaseMusic"
	get value of UI element 1 of UI element 2 of group 1 of group 6 of UI element 1 of scroll area 1 of window "网易云音乐"
        --get value of UI element 1 of UI element 1 of group 5 of group 2 of group 12 of UI element 1 of scroll area 1 of window "网易云音乐"
end tell

第二行用于在展开详情页之后使用

4、歌手

tell application "System Events" to tell process "NeteaseMusic"
	get value of every UI element of every UI element of group 1 of group 1 of group 6 of UI element 1 of scroll area 1 of window "网易云音乐"
	--get value of every UI element of every UI element of group 2 of group 2 of group 6 of group 2 of group 12 of UI element 1 of scroll area 1 of window "网易云音乐"
end tell

第二行用于在展开详情页之后使用

5、专辑
专辑只能在展开之后才有

tell application "System Events" to tell process "NeteaseMusic"
	get value of UI element 1 of UI element 1 of group 2 of group 1 of group 6 of group 2 of group 12 of UI element 1 of scroll area 1 of window "网易云音乐"
end tell

 

 

 

另外……有人愿意来带带我 OSX 逆向入门么…………

用AppleScript玩弄网易云音乐