-
Notifications
You must be signed in to change notification settings - Fork 13
GMscrobber 脚本编写示例
如果我想记录 QQ 音乐到 Last.fm 怎么办? 下面将介绍整个用户脚本的编写过程.
现在的 javascript 程序越来越复杂, 再经过上线压缩过程后, 程序几乎没有可读性. 我们希望知道一些页面程序的调用情况, 而页面作者却没有义务为用户脚本提供接口. 好在 WEB 前端程序在运行过程中调用 javascript 的结果最终都反馈到 HTML 中, 对于一些不需要太精细的需要我们都可以通过监控 HTML 的变化来获得. 实际上, HTML 是 userscript 最好的接口.
新建 userscript, 并引用 simple scrobbler
进入 [QQ 音乐]页面, 并新建用户脚本, 并 require simple scrobbler, 大概如下:
// ==UserScript==
// @name qq music scrobbler
// @namespace http://gmscrobber.whosemind.net
// @description 记录QQ音乐到last.fm
// @include http://y.qq.com/*
// @require https://raw.github.com/justan/gmscrobber/master/simple_scrobbler_user.js
// @version 0.0.1
// ==/UserScript==
gmscrobber 提供了一个构造函数 Scrobbler, 我们首先需要新建一个 Scrobbler 示例和一个初始化函数:
var init = function(){
log('init');
};
var scrobber = new Scrobbler({
name: 'QQ 音乐',
ready: init
});
刷新页面, 在控制台发现打印出不止一个的 init. 分析页面, 发现页面中含有 iframe, 其地址同样匹配 @include
, 所以我们需要对 include 进行校正, 据官方说法, match 比较安全:
// ==UserScript==
// @name QQ音乐 online scrobbler
// @namespace http://gmscrobber.whosemind.net
// @description 记录qq在线音乐到 last.fm
// @match http://y.qq.com/
// @match http://y.qq.com/?*
// @match http://y.qq.com/#*
// @exclude http://y.qq.com/y/*
// @require https://raw.github.com/justan/gmscrobber/master/simple_scrobbler_user.js
// @version 0.0.1
// ==/UserScript==
对于那些播放器界面不是 Flash 的音乐网站, gmscrobber 提供了一个自动化的歌曲播放状态监测函数(scrobber.setSongInfoFN
), 在 QQ 音乐 scrobbler 用户脚本中只需要编写函数来提供歌曲信息. 通过页面调试工具, 找出包含歌曲信息的元素. 需要信息有: 歌名(song.title
), 歌手(song.artist
), 曲长(song.duration
), 专辑名(song.album
), 当前播放时间(song.playTime
)
var init = function(){
log('init');
scrobber.setSongInfoFN(getSongInfo, {checktime: 4000});
};
var getSongInfo = function(){
var song = {};
var songinfo = document.getElementById('divsonginfo');
song.title = songinfo.getElementsByClassName('music_name')[0].title;
song.artist = songinfo.getElementsByClassName('singer_name')[0].title;
song.duration = timeParse(document.getElementById('ptime').innerHTML);
song.playTime = song.duration * document.getElementById('spanplaybar').style.width.replace(/%/, '') / 100;
song.album = songinfo.getElementsByClassName('album_pic')[0].title;
return song;
};
var timeParse = function(timeStr){
var ts = timeStr.split(':');
return ts[0] * 60 + ts[1] * 1;
};
scrobber.setSongInfoFN
接受第二个参数, checktime 是重复检测歌曲信息变化的 timer 定时时长.
这一步完成后, QQ music scrobbler 就已经可以使用了, 它会向 last.fm 发送正在播放的歌曲, 播放一段时间后会自动记录.
last.fm 歌曲记录时间有一定的规则, 一首歌一般会在播放了 90%(可配置) 的时候记录, 最长会在 4 分钟后记录. 如果一首歌在刚刚开始播放的时候将其拖动到 90%(记录点) 的时候, 程序不应该将其记录. 增加 seek 的支持即可解决这个问题:
addEventListener('click', function(e){
var oldTime = getSongInfo().playTime;
setTimeout(function(){
var newTime = getSongInfo().playTime;
offset = oldTime - newTime;
scrobber.seek(offset);
}, 0);
}, true);
gmscrobber 提供了简单的事件系统, 默认的事件有 nowplaying, scrobble, love, unlove, ban, unban
.
每播放一首歌我希望看到该歌曲我总共记录了多少次. 调用 scrobber.getInfo
可以获得这一信息:
scrobber.on('nowplaying', function(){
scrobber.getInfo(scrobber.song, function(info){
document.getElementById('divplayer').title = '在 last.fm 中记录: ' + info.len + ' 次';
});
});
QQ 音乐和 last.fm 都有提供了爱歌曲功能, 现在我们需要将它们互相同步. 获取 QQ 音乐和 last.fm 上同一首歌曲的信息进行对比, 如果一方标示为喜爱, 而另一方未标示为喜爱, 程序应当将其标示为喜爱, 这样就完成了红心歌曲的同步.
仔细想想, 发现程序并不知道我们曾经的操作: 对于一首没有标为红心的歌曲, 它并不知道我是曾经将其红心取消还是我从来未操作过, 对于前者, 将其重新标为喜爱显然会惹恼我. 解决这个问题的办法是将 last.fm 的红心库列为标准, 程序只会自动新增/删除 QQ 音乐上歌曲的红心.
scrobber.on('nowplaying', function(){
var loveEle = document.getElementsByClassName('music_op')[0].firstChild;
loveEle.addEventListener('click', function(e){
if(loveEle.title == '喜欢'){
scrobber.love();
}else if(loveEle.title == '取消喜欢'){
scrobber.unlove();
}
}, false);
scrobber.getInfo(scrobber.song, function(info){
document.getElementById('divplayer').title = '在 last.fm 中记录: ' + info.len + ' 次';
//同步 last.fm 红心歌曲到 qq music
if(info.islove == '1' && loveEle.title == '喜欢' || info.islove == '0' && loveEle.title == '取消喜欢'){
unsafeWindow.g_topPlayer.like(null, loveEle, unsafeWindow.g_topPlayer.getCurSongInfo());
}
});
});
PS: Firefox 装了 greasemonkey 后打开 github 上以 *.user.js 为结尾的代码页面有些问题, 如果不能打开, 请禁用 greasemonkey 后重试.