现在住的地方离公园很近,想重新拾起跑步的习惯,跑步的时候不听点东西总觉得少了点什么东西,带着手机去跑步又觉得太重了,把ipod shuffle拿去跑步刚好,但是苹果这个老古董mp3播放器只支持mp3格式,喜马拉雅的专辑是m4a格式,需要经过转码才能存进播放器里面。 Windows平台下除了itunes,没有其他比较好的导入工具,Linux平台下我使用gtkpod,比官方的itunes简洁小巧多了。无论哪个平台导入前都需要转码为mp3,刚开始我是用faad和lame组合来进行转码的,写这个下载脚本时,发现ffmpeg这个工具更加高效。不通过编程的方式,可以使用windows 10的喜马拉雅fm下载到免费专辑的m4a。

最开始我是使用Win10的喜马拉雅fm来下载免费专辑的,然后用类似下面的脚本进行格式转换。Win10实在是做得太烂了,不知道为什么经常无故死机,还没有休止地下载巨大的更新包,实在没有办法忍受。

对Linux系统的学习,让我觉得是最划算的投资,这种投资的价值慢慢地开始显现出来了。特别是Emacs这个神器,确切地讲应该是org-mode,让我真是相见恨晚啊!

#sudo pacman -S gtkpod
# 参数y是指如果已经存在该文件将被覆盖的意思
# 写这个脚本的时候是用archlinux的-acodec liblamemp3
for i in $(ls *.mp3)
do
faad - $i | lame - ${i%.*}.mp3
ffmpeg -y -i $i -acodec liblamemp3 ${i%.*}.mp3
done

为了锻炼Linux下Shell编程的能力,我尝试着使用Shell来重新编写了这个下载工具。感谢Linux下强大的工具集,花了半天时间来查资料写,做出来却是精巧的几行的代码而已。

# jq 命令行程序用于解析json数据,-r 参数表示返回raw值,如果是字符串将直接打印,不添加引号包裹
#sudo apt-get install jq
URL=$1
# 有两种思路,
#一是先用sed将空格替换成逗号,然后交给awk处理
# MAXPAGE=$(curl $URL | grep '<div class="pagingBar_wrapper"' | sed 's/<[^>]*>/ /g;s/\s\+/,/g' | awk -F ',' '{print $(NF-2)}')
#二是awk中使用正则表达式作为分隔符,来处理多个空格的问题。
MAXPAGE=$(curl $URL | grep '<div class="pagingBar_wrapper"' | sed 's/<[^>]*>/ /g' | awk -F '[ ]+' '{print $(NF-2)}')
if [ ! -n "$MAXPAGE" ]; then
MAXPAGE=1
fi
PAGE="$URL?page=1"
for((p = 1; p <= $MAXPAGE; p++))
do
PAGE="$URL?page=$p"
# sed 必须使用两次,不能合并,或者可以,知道的同学请告诉我方法
SOUND_IDS=$(curl $PAGE | sed -n 's/\s*<div class="personal_body" sound_ids="\(.*\)">\r/\1/p' | sed 's/,/ /g')
for id in $SOUND_IDS
do
#保留注释# | bash是用于测试脚本是否正常,取消注释只下载不转码
#curl http://www.ximalaya.com/tracks/$id.json | jq -r '@sh "wget \(.play_path) -O \(.title).m4a"'# | bash
#一边下载一边转码
#-acodec libmp3lame 可能不同的系统名称会有所差别,也可以去掉,debian默认是libmp3lame
curl http://www.ximalaya.com/tracks/$id.json | jq -r '@sh "curl \(.play_path) | ffmpeg -i pipe:0 -y -acodec libmp3lame \(.title).mp3"' | bash
done
done

下文是用node.js写的命令行下载工具的思路,代码请看喜马拉雅免费专辑下载工具。会写程序的人总是喜欢自己重新发明轮子,写完这个js爬虫才发现已经有人写过类似的python小程序,nodejs的cheerio库提供了类似jQuery清晰简单的查找方式,对于解析html标签很有优势。虽然我在脚本中直接采用正则表达式的方式获取想要的数据,但面对复杂的查询场景时,我还是会优先考虑使用cheerio库的。 得到音频mp3文件之前,需要经历以下几个步骤:

喜马拉雅专辑首页的首页中,包含了分页总数和音频ID列表,可以通过在专辑的url之后添加page参数获取分页的内容,通过请求http://wwww.ximalaya.com/tracks/{ID}.json获取音频文件的相关信息

我把需要下载的对象抽象为有限状态机,包含音频文件信息的json文件、m4a和mp3文件之间存在着一种转化关系

通过建立任务队列和下载队列,分别用于缓存任务和控制下载进程的数量。取到所有分页中音频的id,然后利用异步请求的特性多线程下载音频文件,并能同时显示多个文件的下载进度。

Last Updated 2018-10-14 日 23:38.
Created by Emacs 25.1.1 (Org mode 9.1.14)