-->

曾经大家以为Typecho还会蓬勃发展的时候,它停下了脚步;现在大家以为Typecho必然行之将死的时候,它居然更新了!是的,在半个月前,历时几年后Typecho终于发布了新版。虽然只是小小的0.1,但是这是一个契机,之后Typecho开始了疯狂的更新,Github上也开始活跃了起来。不管怎么说,这是一件值得令人高兴的事情。

新版最重要的一个功能就是把Markdown编辑器给加上去了,而且样式上都有比较大的变化,所以我的XiaMiPlayer插件对于新版也出现了一点问题。在前几个版本Typecho终于恢复了文章/页面编辑页面上的插件接口之后,我就立马做了一下优化。目前这个版本应该能比较完美的支持Typecho 0.9了。

目前的版本号是3.0.1,算是Alpha版吧。如果大家有什么意见建议的话请留言。以后的打算是这样的,基数版本号(3.x)对应新版,偶数版本号(2.x)对应老版本,想要下载老版本的可以在这里下载:XiaMiPlayer插件 for typecho 0.8


本插件更新至3.0.2版,增强了插件与Typecho后台的兼容性(推荐使用默认Markdown编辑器效果会更好),并增加了多个快捷键。

快捷键一览:

  • Ctrl + Shift + M :进入插件
  • Esc :退出插件
  • Ctrl + ← :虾米搜索
  • Ctrl + → :输入链接
  • Ctrl + ↑ :上一页
  • Ctrl + ↓ :下一页
  • Ctrl + Enter : 搜索
  • Ctrl + [1-8] :插入相应行的歌曲

本插件紧急更新至3.0.3版,修复了搜索结果页码不重置的问题,同时为搜索结果增加数字提示以方便使用快捷键。


本插件更新至3.0.4版,增加了对非默认Markdown编辑器的支持,更新播放器代码,设置为默认不自动加载歌曲文件,减少页面加载时间。


本插件更新至3.0.5版,修复了自定义歌曲地址不支持自定义配色的BUG。


本插件更新至3.0.6版,修复了之前版本播放器的一些样式问题。增加了添加列表播放器的功能(暂时还没有简洁好看的播放器样式,所以还是先用了官方的Flash播放器,所以只支持虾米搜索添加,直链添加会在之后的版本中支持)。选择了列表模式之后添加的歌曲会进入列表中,上下拖拽列表歌曲可以对歌曲进行排序,左右拖拽至外侧可删除歌曲。新功能写的比较仓促没做过多的测试,欢迎反馈意见。


本插件更新至3.0.7版,更改音乐的插入方式(由iframe替换为script)。列表播放支持自定义地址。代码改动较大,为了兼容老版本没有将一些废弃文件去除掉,想要研究代码的可以进插件内查看。


本插件更新至3.0.8版,修复了音乐搜索不可用的问题


本插件更新至3.0.9,修复了一些小BUG,增加直接解析文章内以http://开头的虾米链接插入歌曲、专辑、精选集功能。例如在文章中直接插入“http:// www.xiami.com/album/435293“(请自行去除空格)即可插入该专辑的所有音乐,同时支持Markdown模式和非Markdown模式。 http://www.xiami.com/album/435293


本插件更新至3.1.0,修改插件内以相对协议加载相关文件,防止https阻止非https的资源加载。同时修改播放器的class名称防止与主题自带样式冲突。


插件更新至3.1.1,主要是修改了接口地址,另外修改了一个多歌曲时无法切换的 BUG。之前的服务放在 SAE 上由于 SAE 开始收费遂切换到另外一个免费服务提供商。由于该服务商未提供 SSL 服务所以对于 https 用户只能抱歉。如果需要替换之前已经发布的歌曲链接可以在数据库中执行以下命令进行批量替换:


UPDATE `typecho_contents` SET `text` = REPLACE(`text`, 'songs.sinaapp.com', 'xiamiplayer.songs.ali-sh.goodrain.net:10080')

插件更新至 3.1.2,还是修改接口地址,求个国内主机啊卧槽 T_T

下载地址:百度云 | 微盘

批量下载虾米已下载歌曲(新)

前言

呵呵,没错,公子我又再次光荣的把硬盘搞挂了,然后音乐又没了!鉴于之前已经有过一次经验(批量下载虾米已下载歌曲),所以本以为这次也会轻而易举了的。没想到居然在我写出那篇日志后没多久,官方居然各种更新(更新页面,下载机制,Flash播放器),然后我那篇日志的方法就没法用了。不过官方这个也都是小改,所以我也只要小改下代码就成啦!哈哈!

有什么变化

首先要说的是虾米官方的下载思路还是没变的,基本上还是之前日志里头说的那样:

在网站点击下载之后,网站向你的账户中未下载列表传递下载歌曲信息,之后未下载列表则返回一个以emoun://特有协议开头的文件,用以打开虾歌(这个和迅雷thunder://以及电骡等的ed2k://是一个道理)。虾歌打开后查询未下载的表单,返回表单中的歌曲,然后下载。同时将未下载列表中的歌曲提交到已下载列表中,并在未下载列表中删除。 - 批量下载虾米已下载歌曲

官方改变的就是下载列表和网站点击下载这两步:

下载列表

老版的是直接显示列表显示每首歌的,新版则是按照下载时间来显示,一次下载为一次订单,订单内再显示此次下载的歌曲。这样正则匹配获取歌曲的ID就需要发生变化了。

点击下载提交订单

以前只要登陆后向服务器POST歌曲的ID就能提交订单了。新版则需要提交sign_xiamitoken这两个新参数,三个参数一块POST才行。sign参数暂时还不知道如何算出来的,_xiamitoken则是你的cookies。看源码意外的让我发现了参数居然都直接写在页面里头了,为了简便,我就直接抓取订单页面正则获取这两个参数了。同时还加了判断Referer这种老手段,这个也不算难。

VIP机制

以前是没有VIP的,自从被阿里收购之后就增加了VIP功能。好在现在可以用体验点(以前的红包)购买VIP,15个体验点可以买一个月的VIP,一个月的VIP能免费下100首歌曲。我的歌曲数在400+,花了80个体验店办了半年的,可以免费下600首歌曲。等于用80个体验店下600首歌的意思,变相的节省了下体验点,哈哈!

解题步骤

一、获取登陆COOKIES

这一步和老版还是一样的,直接复制过来吧。

获取登陆后的COOKIES文件,方便之后的抓取工作。修改代码中的第2行和第3行,填入自己的账号和密码。如果成功的话,会在该文件的同级目录下得到一个cookies.txt文件。

<?php
$name = ''; //输入你的账号
$password = ''; //输入你的密码
$curl_post = 'email='.$name.'&amp;password='.$password.'&amp;done=/&amp;submit=登 录';
$cookie_file = dirname(__FILE__).'/cookie.txt';
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, &quot;http://www.xiami.com/member/login&quot;);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $curl_post);
curl_setopt($curl, CURLOPT_COOKIEJAR, $cookie_file);
curl_exec($curl);
curl_close($curl);
?>

二、抓取下载列表并提交到未下载列表

这一步因为列表的改变有些许变化。而且新版订单还有个新订单和旧订单之分,真是蛋疼,还得做两次解析。

<?php
set_time_limit(0); //设置成不限制页面运行时间
function get($url) {
    $cookie_file = dirname(__FILE__).'/cookie.txt';
    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_COOKIEFILE, $cookie_file);
    $data = curl_exec($curl);
    curl_close($curl);
    return $data;
}
$song = array();
$pageinfo = get('http://www.xiami.com/account/myorders-old');
$preg = '/\…\<\/a\>\<a href\=\"\/account\/myorders-old\/page\/(.*?)\" class\=\"p\_num\">/s';
preg_match_all($preg, $pageinfo, $match);
$page = $match[1][0];
for($i=1;$i<$page;$i++) {
    $data = get("http://www.xiami.com/account/myorders-old/page/".$i);
    $preg = '/\<td class\=\"iname\"\>\<a href\=\"\/song\/(.*?)\"/s';
    preg_match_all($preg, $data, $match);
    foreach($match[1] as $item) $song[] = $item;
}
$pageinfo = get('http://www.xiami.com/account/myorders');
$preg = '/\…\<\/a\>\<a href\=\"\/account\/myorders\/page\/(.*?)\" class\=\"p\_num\">/s';
preg_match_all($preg, $pageinfo, $match);
$page = $match[1][0];
for($i=1;$i<$page;$i++) {
    $data = get("http://www.xiami.com/account/myorders-old/page/".$i);
    $preg = '/\<td class\=\"iname\"\>\<a href\=\"\/song\/(.*?)\"/s';
    preg_match_all($preg, $data, $match);
    foreach($match[1] as $item) $song[] = $item;
}
$song = array_unique($song, SORT_NUMERIC);
echo 'var song = new Array('.implode(',', $song).')';
?>

批量提交下载歌曲

我之前也讲了,新版新增sign_xiamitoken两个参数,同时还增加了Referer验证。整体代码还是采用上版中的PHP+AJAX异步提交,只是在PHP部分有稍许修改。

将上一步得到的代码复制替换掉相同的那部分,保存为download.html

<script type="text/javascript">
//将第二步获得的代码复制到下面
var song = new Array(1769629171,3338870,1769902385,1770432131,2868586,1770149760,367633,1769832130,35526,1769962750,1770551145,1770457081,3486103,1769400110,127903,3367334,2078855,71830,376007,376015,2074918,2730,1770450144,3455520,79157,79151,81366,65256,390070,2138604,1770345727,376050,376006,149193,388168,1769665592,3497062,1769236069,3632104,1768923954,1769491757,3608275,2092882,1770354410,3480460,3620143,2095376,2561774,3664677,1770462404,1769056924,3527076,2126340,2089410,1769177482,2083322,1769831952,1769316186,1770524409,1769517803,1190507,1964547,1769107542,3486203,1769686818,1769028326,1858814,2084011,1769235816,1770614545,2083187,2605276,378268,2515019,1122167,1769176497,3302053,2083102,3638520,189072,371017,1770168732,1083760,2122948,2070331,2128868,3319126,2561592,1381654,3441719,1768939471,2091290,2098665,2067235,1770060224,3562953,54342,1769831786,1770145312,76323,2067242,173117,136054,1770068043,1769833104,1769833105,1769833106,1769833107,1769833108,2082305,1768989931,1769356638,1769082273,1769776879,1769740304,1205851,1768984809,1769102373,1769740095,1768989928,1769381931,1769227674,3599015,1768962602,3463177,1769381938,1769381935,1769381934,1769381932,3410377,2067242,3381901,3381903,373969,2072395,373971,373990,374039,3381910,3381911,3381912,382134,378711,193010,162269,143775,127673,120041,89443,52732,382512,383210,1769274527,1769004670,1768958960,3599311,3365855,2314604,2080987,2073790,385907,115384,374057,377936,380029,382560,382852,383962,33806,378041,380287,385729,385760,388406,389153,381833,83126,386773,389072,389080,389077,43542,52726,375183,382821,384595,385074,386954,373818,376387,378307,379302,382777,384646,384670,385137,385976,386073,386347,2342433,3550893,1769699970,2095102,2095107,2017034,2286524,2342421,2286523,3338183,1768988423,2286527,2380720,3464931,1176114,1769334977,2155384,1769839800,3225258,2091936,1769334987,3187867,2095104,3413844,1769072635,1007695,3636957,3467770,1768940269,1769292436,1769850021,1769102619,3409064,1769870173,1769850022,1769850019,1769463117,3446206,2028877,2136483,1769072646,1769291745,1769072643,1769113798,196142,3187959,2079575,2286522,2079581,2385273,1769673320,3513664,1769071426,3502285,1769801604,1769801605,3484274,1769303054,1769303056,1769303057,1769303058,1769303059,1769303060,1769303061,1769303062,1769303055,1768914983,378646,3586293,1769830111,1769830112,1769830113,1769830114,1769830115,1769830116,1769830117,1769830118,1769830119,1769830120,1769570445,);

//复制结束

//下面的代码不需要修改 
var XHR; //定义一个全局对象 
function xm_download(id){  
    if(window.ActiveXObject){//IE的低版本系类 
        XHR=new ActiveXObject('Microsoft.XMLHTTP');
    }else if(window.XMLHttpRequest){//非IE系列的浏览器,但包括IE7 IE8 
        XHR=new XMLHttpRequest(); 
    } 
    XHR.open("GET","download.php?id="+id,true);        
    XHR.send(null); 
} 
for (var i=0;i<song.length;i++) {
    xm_download(song[i]);
}
</script>

将下面的代码保存为download.php,放在与download.html同级目录中

<?php
$cookie_file = dirname(__FILE__).'/cookie.txt'; //登陆COOKIES文件地址
$id = $_GET['id'];
$url = "http://www.xiami.com/download/pay?id=$id";
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_COOKIEFILE, $cookie_file);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($curl);
curl_close($curl);
$preg = '/\<input type\=\"hidden\" name\=\"sign\" id\=\"sign\" value\=\"(.*?)" \/\>/s';
preg_match_all($preg, $data, $match);
$sign = $match[1][0];
$pieces = explode('<input type="hidden" value="', $data);
$piece = end($pieces);
$cookies = explode('"', $piece);
$cookie = $cookies[0];
$data = "song_ids[]=$id&amp;use_vip=1&amp;down=1&amp;inpour_amount=0&amp;sign=$sign&amp;_xiamitoken=$cookie";
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_COOKIEFILE, $cookie_file);
curl_setopt($curl, CURLOPT_REFERER, $url);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);    
$data = curl_exec($curl);
curl_close($curl);
?>

四、打开虾歌查询订单

最后一步是打开虾歌,选择“文件”→“检查未完成下载”,静候片刻你就可以欢呼了!之后静静等待虾歌批量下载成功就好了。

XiaMiPlayer插件 for typecho 0.8(更新至2.1版)

2.1版对应的是typecho 0.8版,如果想要下载对应最新版(typecho 0.9)的同学,请跳转到此页:XiaMiPlayer插件 for typecho 0.9

2.1版新增自定义播放器颜色(换颜色,全球浪潮~),默认提供了六种颜色,同时用户也可以自定义颜色哟!

2.0版本新增同步显示歌词和外链MP3地址的支持,提供移动端支持(需要支持html5)!欢迎大家更新使用!

本插件是基于MiniPlay1g1g插件的基础上修改过来的,所以插件的基本样式和MiniPlay1g1g是一样的,如果大家介意的话我会在下个版本中修改过来。在此感谢MiniPlay1g1g插件的作者vfasky君给我们带来了这么好的一个插件。

XiaMiPlayer插件的主要功能:

  • 根据关键词获取虾米音乐搜索结果
  • 生成音乐播放器代码,并自动插入到文中
  • 歌曲同步显示歌词(如果歌曲有歌词的话,2.0版本以上支持)
  • 支持插入外链MP3地址(2.0版本以上支持)
  • 自定义播放器样式(2.1版以上支持)

本插件是在typecho 0.8的基础上开发的,没有做对老版本兼容的测试,没有做对其它编辑器兼容的测试,同时没有做浏览器兼容测试,以及各种其它有的没有的测试。如果有不能用的,欢迎大家来报BUG,我会尽我所能DeBug的。

更新:
2.1 - 新增自定义播放器样式功能
2.0 - 更换播放器代码,支持所有支持HTML5平台的客户端。增加同步显示歌词功能,以及支持外链MP3地址。
1.3 - 修改翻页样式,修复了开启插件之后无法使用附件的插入功能。
1.2 - 增加了Ckeditor, xheditor编辑器的支持,修复了之前支持的编辑器无法插入的问题。
1.1 - 增加了TinyMce, KindEditor, FCKeditor三个编辑器的支持。

下载地址:BOX | 百度云

初探<audio>标签实现同步显示歌词

今天群里的小胖说用<audio>标签写了个听评书的网页给父母用,技术实在是低级真心非常有孝心的说!然后我也顺带去了解了一下audio标签现在的支持情况,一不小心就脑补了一些新知识。看到了audio标签有duration属性和currentTime属性,分别用来读取歌曲总时间和当前播放时间,正好弥补了我之前想写播放器同步显示歌词一直卡在的如何获取播放时间的问题上。所以就开始操刀了。

歌曲和歌词的准备

我暂时是写到了之前的虾米搜索页面里面,实现搜索获得歌曲用audio标签播放并显示歌词。所以歌曲和歌词文件自然就来自盗版帝国虾米了。由于虾米的歌曲文件都是MP3格式的,所以悲剧如FireFox等虽然支持了HTML5但是不支持MP3格式的文件这让我也是感到很捉急的,所以暂时是推荐大家使用Chrome浏览器制作并访问的。关于目前各浏览器的支持情况可以看这里:居然连IE都支持了!这里利用了一下虾米的API:http://www.xiami.com/song/playlist/id/歌曲ID 获取歌曲的相关信息,其中就有歌曲地址和歌词。获取到的XML文件中,歌曲地址是加密放置的,至于解析原理,大家可以参见虾米音乐文件绝对地址解析。详细的解释一下就是:

获取到的字符串第一个字母是矩阵的行数,除去第一个字母的字符总数除以行数得到的整数是每行放置多少个字符,余数则是前余数行要在末尾多放置一个字符。这样就能组成引文中的矩阵了。按照竖行读取,^替换为0的处理后就可以获得绝对地址了。

懒惰如我为了方便自己,我把解析的过程写成了函数。最开始我是将字符串打散成为二维数组,然后嵌套循环连接字符串。后来觉得打散成一位数组应该会更方便一点,所以为了算获取数组索引顺序的规律,死了好多个脑细胞啊,果然数学已经忘到姥姥家了。

歌词由于后期要用js处理,js又不能跨域获取什么的。所以只能劳烦PHP获取到歌词地址后远程抓取过来了。以上解析得到绝对地址和歌词都是在服务器端完成的。我写成了API的形式,http://imnerd.org/lab/search/api.php?id=歌曲ID可以查看获取到的内容格式。

audio歌曲播放与暂停

果然我还是对解码什么的比较感兴趣,一不小心就偏题了呢。好啦好啦,以上都不应该是本文的重点啦,下面我们开始好好的蹂躏学习一下audio标签啦。audio标签的简单写法为

<audio src="歌曲地址"></audio>

控制歌曲的播放和暂停也是非常简单的,只要利用play()和pause()事件就好了,代码如下:

m = document.getElementsByTagName('audio')[0];
m.play(); //歌曲的播放
m.pause(); //歌曲的暂停

想要了解更多audio标签的属性和事件的话可以点击这里:HTML 5 视频/音频参考手册

同步显示歌词的实现

我在开头已经讲了,audio的currentTime属性可以获取当前播放时间。又如果你刚才有去点击上面的参考手册的链接的话,你就会发现audio还有一个神奇的timeupdate事件,目的是当目前的播放位置已更改时做出动作。也就是说我们可以利用timeupdate事件在currentTime变化的时候做出判断,然后放置相应的歌词。

基本方法大概就是这个样子,播放器的当前播放时间我们已经获取到了,剩下的就是获取歌词的播放时间的问题了。由于标准的歌词每行应该是“[你好我是播放时间,我的格式是分:秒]你好我是该播放时间下的歌词”这种格式的,想必大家早就了解了吧。利用正则获取split分割等一系列方法将歌词分割成一个二维数组,一纬为每行歌词,二维为每行歌词的时间和每行歌词的内容。其中歌词的时间由于是分钟:秒的形式,需要转化为单位为秒的数字。下面给出歌词转化为二维数组的方法。方法可能坑爹不是最好的,但是基本凑合,这一部分大家可以随意发挥:

//写成函数的形式大家可能会更好理解一点
function parseLyric(text) {
lyric = text.split('\r\n'); //先按行分割
var _l = lyric.length; //获取歌词行数
lrc = new Array(); //新建一个数组存放最后结果
for(i=0;i<_l;i++) {
    var d = lyric[i].match(/\[\d{2}:\d{2}((\.|\:)\d{2})\]/g);  //正则匹配播放时间
    var t = lyric[i].split(d); //以时间为分割点分割每行歌词,数组最后一个为歌词正文
    if(d != null) { //过滤掉空行等非歌词正文部分
        //换算时间,保留两位小数
        var dt = String(d).split(':'); //不知道为什么一定要转换时间为字符串之后才能split,难道之前正则获取的时间已经不是字符串了么? 
        var _t = Math.round(parseInt(dt[0].split('[')[1])*60+parseFloat(dt[1].split(']')[0])*100)/100; //这一步我自己都觉得甚是坑爹啊!
        lrc.push([_t, t[1]]);
    }
return lrc;
}

这样我们只要匹配歌词每行的时间和crrentTime就行了,如果当前播放时间超过了这一句歌词的时间,则显示这一句歌词,否则不显示。这是我们下面代码的关键判断。另外,这里我使用了一个自我感觉还不错的小技巧:显示完歌词之后立即将这行歌词从歌词数组中剔除出去,这样我们就永远只要将currentTime和lrc[1][0]比较就好了,而不用麻烦的去每个都去比较一下。

m.addEventListener('timeupdate', function() {
    if(audio.currentTime > lrc[1][0]) {
        document.getElementById('lrc').innerHTML = lrc[1][1];
        lrc.shift();
    }
},false);
//addEventListener等同于m.timeupdate(function() {...});

歌曲播放并显示歌词的思路大概就这个样子了,具体的代码可以去看我的DEMO。DEMO只是给出了大概的功能,UI方面都还木有美化,大家习惯就好,这个是在是力不从心啊!本人一向也不是很在意UI的。最后的最后,感谢一下Jclyn帮我做了测试并推荐了本文开头的歌曲。哦,又突然想起来了,DEMO的范例是用JQuery操作的,虽然跟Javascript有些不同,但是对于思路什么的是没有问题的,有不懂的可以留言提问哦,我会看心情耐心解答的。

自建虾米音乐搜索

<button>搜索</button>

加载jQuery库文件


添加获取搜索结果的异步事件,增加搜索框回车快捷获取结果效果。第7行用于清除播放器代码显示结果,以防是得到播放器显示结果后重新搜索。第10行用于当搜索结果时不加载载入更多代码。

function search() {
  $.ajax({
      url: "http://www.xiami.com/app/nineteen/search/key/"+$('#text').val()+"/page/"+$('#page').val(),
      type: "get",
      dataType: "jsonp",
      success: function(data, status) {
                  $('#show').html('');
                  $("#list").css('display','block'); 
                  if(data.total / 8 != 1) {
                    $('#navi').html('
载入更多
'); } $.each(data.results, function(i,item){ $('

'+decodeURIComponent(item.song_name)+' - '+decodeURIComponent(item.artist_name)+'

').appendTo('#result'); }); }, error: function() { alert('failed!'); } }); } //当点击搜索按钮时先清除结果显示防止是重新搜索,然后再一步加载搜索结果 $('button').click(function(){ $("#result").html(''); search(); }); //搜索框回车时触发搜索按钮点击事件 $("body").keydown(function() { if (event.keyCode == "13") { $('button').click(); } });

增加点击歌曲名获取歌曲播放器代码事件,先是在页面中显示播放器,再用一个textarea框显示引用代码,并增加了当textarea框获得焦点时自动全选框内代码效果。

function show(id) {
    //搜索结束搜索起始页面自动返回到1
    $('#page').val('1');
    $('#list').css('display', 'none');
    var html = '';
    $("#show").html(html);
    $("#show").append('<textarea onfocus="this.select();" onmouseover="this.focus()">'+html+'</textarea>');
}

-->

预览

预览地址:虾米音乐搜索  主要目的是搜索音乐并获取播放器代码

原理

本段代码主要利用了http://www.xiami.com/app/nineteen/search/key/搜索内容/page/搜索结果页数虾米这个隐藏的API,例如http://www.xiami.com/app/nineteen/search/key/传奇/page/1可以获取到搜索结果总数已经相关歌曲的信息等。

简单的思路是搜索框输入搜索信息点击搜索AJAX载入API搜索结果并返回给页面解析显示,单击一条歌曲时根据搜索结果获得的歌曲ID返回播放器代码。

代码分析

首先是基本的HTML代码

<input type="text" id="text" value="" />
<input type="hidden" id="page" value="1" />

<button>搜索</button>

加载jQuery库文件


添加获取搜索结果的异步事件,增加搜索框回车快捷获取结果效果。第7行用于清除播放器代码显示结果,以防是得到播放器显示结果后重新搜索。第10行用于当搜索结果时不加载载入更多代码。

function search() {
  $.ajax({
      url: "http://www.xiami.com/app/nineteen/search/key/"+$('#text').val()+"/page/"+$('#page').val(),
      type: "get",
      dataType: "jsonp",
      success: function(data, status) {
                  $('#show').html('');
                  $("#list").css('display','block'); 
                  if(data.total / 8 != 1) {
                    $('#navi').html('
载入更多
'); } $.each(data.results, function(i,item){ $('

'+decodeURIComponent(item.song_name)+' - '+decodeURIComponent(item.artist_name)+'

').appendTo('#result'); }); }, error: function() { alert('failed!'); } }); } //当点击搜索按钮时先清除结果显示防止是重新搜索,然后再一步加载搜索结果 $('button').click(function(){ $("#result").html(''); search(); }); //搜索框回车时触发搜索按钮点击事件 $("body").keydown(function() { if (event.keyCode == "13") { $('button').click(); } });

增加点击歌曲名获取歌曲播放器代码事件,先是在页面中显示播放器,再用一个textarea框显示引用代码,并增加了当textarea框获得焦点时自动全选框内代码效果。

function show(id) {
    //搜索结束搜索起始页面自动返回到1
    $('#page').val('1');
    $('#list').css('display', 'none');
    var html = '';
    $("#show").html(html);
    $("#show").append('<textarea onfocus="this.select();" onmouseover="this.focus()">'+html+'</textarea>');
}

虾米自动签到的实现

前言

今天抽空整理了下把它写成了一个多账号版本的,放在了SAE上头,网址是:http://autocheck.sinaapp.com 。 上头输玩账号密码程序就可以自动帮你的账号签到了。切记程序会记住你的账号密码,如果有介意的请千万不要使用,本人不对你的账号问题进行负责。

上一篇文章中,我们讲述了如何利用PHP批量下载虾米已下载的歌曲。其中我们实现了如何用PHP+CURL模拟虾米登陆,这回我们来实现一下如何自动签到。(对于我这样的只是拿虾米当下载音乐的地方,而且经常忘记签到的孩子真的是非常有用啊有木有!T_T)

一、获取登陆COOKIES

还是老样子,我们先获取到登陆的COOKIES文件。修改代码中的第2行和第3行,填入自己的账号和密码。如果成功的话,会在该文件的同级目录下得到一个cookies.txt文件。

$name = ''; //输入你的账号
$password = ''; //输入你的密码
//获取登陆cookie
$curl_post = 'email='.$name.'&password='.$password.'&done=/&submit=登 录';
$cookie_file = dirname(__FILE__).'/cookie.txt';
$curl = curl_init();
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_URL, "http://www.xiami.com/member/login");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $curl_post);
curl_setopt($curl, CURLOPT_COOKIEJAR, $cookie_file);
curl_exec($curl);
curl_close($curl);

二、获取签到地址

虾米的签到其实是向http://www.xiami.com/task/signin这个网页发送一个POST,这个POST的Data长度是0。代码利用虾米手机页面的签到机制,向一个特定的地址发送一个POST过去就可以了。所以再要就是获取签到的地址。

三、进行签到

利用上一步中获取到的地址进行签到。但是要注意的是,网页会判断页面来源,如果不是从虾米网站POST过去的会签到失败。所以我添加了自定义Referer来源。之前就一直因为这个没有更改而一直都没有成功,后来索性模拟了所有的HTTP Header才发现了问题的所在。另外,虽然POST空数据过去,但千万不要以为不POST数据过去就行了,无和0还是有点区别的,哈哈!其它的就没有什么问题了。签到成功的话页面会返回你的签到天数。

//自动签到
$url = 'http://www.xiami.com' . $match[1][0];
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_COOKIEFILE, $cookie_file);
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_REFERER, 'http://www.xiami.com/web');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$num = curl_exec($curl);
curl_close($curl);

四、Cron添加自动签到任务

我这里以SAE为例,将第一步获取到的cookies.txt文件和第二步的xiami.auto.sign.php一起上传到应用中。例如存放位置是/xiami。在cron.yaml末尾添加如下代码:

  - description:cron XiamiAutoSign
    url: xiami/xiami.auto.sign.php
    schedule: every day of month 00:10
    timezone: Beijing
设置成功的话会在每天的00:10访问这个页面,完成自动签到功能!

如何批量下载虾米已下载歌曲

本文方法已失效,新版见:如何批量下载虾米已下载歌曲(新)

前言

首先要说明的是,这不是一篇讲述如何免费批量下载虾米高质量音乐的文章,而是讲述一个杯具男如何因为懒惰而DIY出的成果。所以如果抱有前述心理的同学到此可以关闭网页了。另外本文中代码运用到了PHP+CURL+JavaScript,推荐大家在本地环境中进行操作。同时最重要的是,本文不是讨论如何绕过虾米的收费机制下载歌曲,所以你必须保证你有足够的虾米币或者红包用来下载歌曲才行,否则一切免谈。

事出有因

事情是这样的。前两天安装了Linux Mint,在Linux中打开了音乐,没过一会儿就卡掉了,当时我也没在意。结果一回到Windows就提示我文件夹损坏了,里面的文件也自然都悲剧了。用恢复软件恢复了效果也不太理想。400首歌总共2G多的文件也不是说割舍就能割舍的,所以就有了下面这些。

解题思路

虾米下载的机制是这样的:在网站点击下载之后,网站向你的账户中未下载列表传递下载歌曲信息,之后未下载列表则返回一个以emoun://特有协议开头的文件,用以打开虾歌(这个和迅雷thunder://以及电骡等的ed2k://是一个道理)。虾歌打开后查询未下载的表单,返回表单中的歌曲,然后下载。同时将未下载列表中的歌曲提交到已下载列表中,并在未下载列表中删除。这样,一次下载就完成了。

download

如图所示,点击下载歌曲,网站向http://www.xiami.com/download/song页面POST提交了相关Data,同时网页返回一个emoun://协议开头的文件(图中左侧红色方框标记的)。

所以我的想法是这样的:首先登陆网页抓取已下载列表中已经下载过歌曲的信息,然后批量的提交到未下载列表。然后打开虾歌去查询未下载列表中的歌曲就好了。如果和我所想一样的话,虾歌应该会一次性批量得到所有歌曲,那么我们只要等待下载完成就好了。

解题步骤

一、获取登陆COOKIES

获取登陆后的COOKIES文件,方便之后的抓取工作。修改代码中的第2行和第3行,填入自己的账号和密码。如果成功的话,会在该文件的同级目录下得到一个cookies.txt文件。

$name = ''; //输入你的账号
$password = ''; //输入你的密码
$curl_post = 'email='.$name.'&password='.$password.'&done=/&submit=登 录';
$cookie_file = dirname(__FILE__).'/cookie.txt';
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "http://www.xiami.com/member/login");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $curl_post);
curl_setopt($curl, CURLOPT_COOKIEJAR, $cookie_file);
curl_exec($curl);
curl_close($curl);

二、抓取下载列表并提交到未下载列表

有了上一步之后,这一步就变的非常的简单。这里主要考虑的是效率的问题,由于我的歌曲打开400首,虾米一页显示20首。所以我大概有20页要抓取,这对于PHP来说是一个不小的工作量,在本地运行更甚。如果你的页面少可以使用下面的代码,如果你要抓的页面多,可以尝试将其改写成multi\_curl同步抓取,或者改写成AJAX形式,亦或是分批抓取都行。使用代码时候记得修改第三行的抓取页数。

set_time_limit(0); //设置成不限制页面运行时间
$page = ''; //填写你的已经下载页面的页数
$cookie_file = dirname(__FILE__).'/cookie.txt';
       
$song = '';
//如果页数过多可以分批获取,以免等待时间过长
for($i=1;$i<=$page;$i++) {
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, "http://www.xiami.com/account/mysongs/s/2/page/".$i);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_COOKIEFILE, $cookie_file);
    $data = curl_exec($curl);
    curl_close($curl);

    $preg = '/\\(.*?)\<\/a\>/s';
    preg_match_all($preg, $data, $match);
    foreach($match[1] as $item) {
        $song .= $item . ',';
    }
}
$song = str_replace(' ', '', $song);
$song = substr($song, 0, -1);
echo "var song = new Array($song);";
/*end*/

三、批量提交下载歌曲

上一步的代码中,我将下载歌曲的ID输出成了JavaScript数组的形式。因为这一步中我们将以歌曲数为基数向虾米网站POST提交信息,400对于PHP来说仍然是一个庞大的数字,对于本地更甚。你可以修改成multi_curl的形式,不过我第一反应是AJAX异步传输,这就是为什么我将歌曲的ID输出成了JavaScript数组的原因。

原理很简单,JS用来模拟循环,PHP则负责POST提交数据。使用代码时记得将xiami.song.download.html中的第3行替换成你在上一步中获得的代码。


$data = 'pid=&ptype=&song_count=1&id='.$_GET['id'];     
$cookie_file = dirname(__FILE__).'/cookie.txt'; //登陆COOKIES文件地址
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "http://www.xiami.com/download/song");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_COOKIEFILE, $cookie_file);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);  
$data = curl_exec($curl);
curl_close($curl);

四、打开虾歌查询订单

最后一步是打开虾歌,选择“文件”→“检查未完成下载”,静候片刻你就可以欢呼了!之后静静等待虾歌批量下载成功就好了。