Ubuntu下自制douban.fm播放器


douban.fm 是我常用的網絡音樂電台,但因為是web應用,無法使用全局熱鍵控制,官方又沒有提供linux桌面版本,故打算自己開發一個linux doufan.fm播放器。

要實現的功能:

  1. 全局熱鍵控制
  2. 開始播放時桌面通知
  3. 登錄、選頻道

想要實現並不一定能實現,但我會花時間來慢慢攻破困難,目前為止已經簡單的實現了基本功能。

 

douban.fm 播放器的簡單實現

既然是簡單實現,那么在保證功能的前提下應該盡量保持實現的簡單,以便后續完善。在開發工具上我選擇python,以便快速交付和測試我的想法。

數據來源

如何獲取要播放的音樂及相關信息是首要解決的問題,這就必須要研究douban.fm的工作流程。其實我們可以思考一下,如果要我們實現一個網絡電台,該怎么實現?不可能把所有的播放列表都放在客戶端,是了,一個很好的方案是先由客戶端發送請求播放列表,服務端返回播放列表,客戶端再根據播放列表中的url請求文件以播放。

當然,具體情況還是要實際分析過才可得知,我們可以用網頁調試工具(firebug或chrome的開發者工具),甚至抓包軟件,分析douban.fm的數據通信。

刷新后,可以看到douban.fm發出的所有http請求,接下來,我們要有目的的尋找攜帶播放列表的http響應:

從url可以明顯的看到playlist字樣,展開該請求響應,可以看出響應數據的格式是json,繼續展開,終於找到了我們想要的數據。

接着,我們要研究該url的參數,以便定制我們的播放器。在新標簽打開該url:

經過多次嘗試,大概可以確定這幾個參數的行為:

  • type:字面意義是類型,具體作用不明,由douban.fm發出的所有請求都使用了type=n,缺少該參數將無法正常獲取播放列表;
  • sid:作用不明,可省,猜測與用戶相關;
  • pt:作用不明,可省,猜測與音樂類型相關;
  • chanel:頻道ID,經過測試發現,0:公共/私人(指定sid時)兆赫、1:華語、-3:紅心兆赫;
  • from:客戶端來源,可省;
  • r:從值來看,應該是random的縮寫,可省;

所以,一條最簡單的獲取播放列表的url是:http://douban.fm/j/mine/playlist?type=n&channel=0

播放音樂

有了音樂文件,怎么用python播放呢?我們沒有必要先把mp3文件下載到,又自己實現一個播放器。即使利用已有的模塊或庫都顯得過於麻煩。linux如此多基於命令行的流媒體播放器,為什么不直接拿來用?比如我經常使用的mplayer。

使用mplayer:mplayer http://mr3.douban.com/201212101049/fbc67748d2c7791b86653220b2ccbd08/view/song/small/p1472407.mp3,一條命令就可以播放在線的音樂。然后,用python的subprocess模塊調用即可。

至此已經可以寫出一個最簡單的douban.fm播放器:

httpConnection = httplib.HTTPConnection('douban.fm')
httpConnection.request('GET', '/j/mine/playlist?type=n&channel=0')
song = json.loads(httpConnection.getresponse().read())['song']
subprocess.call(['mplayer', song[0]['url']])

激動人心的是,這一功能的實現只用了4行代碼。

Ubuntu桌面通知

統一的桌面通知是很有意義的(想想windows下混亂的彈窗吧),從OS X v10.8 “Mountain Lion"開始,Mac開始統一Notification Center,與此同時各linux桌面也在完善各自的通知系統。

ubuntu unity擁有自己的桌面通知接口,打開~/.bashrc,可以發現有這樣一條命令別名:

alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'

在shell中輸入命令:alert "test",可以看到如下效果:

alert是別名,核心命令是notify-send,通過man notify-send,我們可以查看其用法。

ubuntu下播放器開啟notify插件后,每次切歌都會發出一個桌面提示:

這是一個很酷的功能,那么如何實現?

仔細想想的話並不難,圖片可以由song[0]['picture']下載,然后構造命令notify-send -i pictrue_path ['title'] ['artist'] ['albumtitle']即可。其中涉及到圖片文件的下載保存,可以用httplib+文件讀寫來完成,實際中我用的是wget。

用python來實現就是:

picture = 'images/' + song[0]['picture'].split('/')[4]

# 下載專輯封面
if not os.path.exists(picture):
    subprocess.call([
        'wget',
        '-P',
        'images',
        song[0]['picture']])

# 發送桌面通知
subprocess.call([
    'notify-send',
    '-i',
    os.getcwd() + '/' + picture,
    song[0]['title'],
    song[0]['artist'] + '\n' + song[0]['albumtitle']])

獲取圖片名時小小的hack了一下,song[0]['picture'].split('/')[4] 這句用來獲取url中的圖片名,當然,這並不是一個很好的方法。

小結

最后,結合前面的播放代碼,已經算是基本完成了,雖然沒有實現全局熱鍵控制、登錄,但已經可以使用了。

完整的代碼:

 1 #!/usr/bin/python
 2 # coding: utf-8
 3 
 4 import httplib
 5 import json
 6 import os
 7 import sys
 8 import subprocess
 9 import time
10 
11 reload(sys)
12 sys.setdefaultencoding('utf-8')
13 
14 while True:
15     # 獲取播放列表
16     httpConnection = httplib.HTTPConnection('douban.fm')
17     httpConnection.request('GET', '/j/mine/playlist?type=n&channel=0')
18     song = json.loads(httpConnection.getresponse().read())['song']
19 
20     picture = 'images/' + song[0]['picture'].split('/')[4]
21 
22     # 下載專輯封面
23     if not os.path.exists(picture):
24         subprocess.call([
25             'wget',
26             '-P',
27             'images',
28             song[0]['picture']])
29 
30     # 發送桌面通知
31     subprocess.call([
32         'notify-send',
33         '-i',
34         os.getcwd() + '/' + picture,
35         song[0]['title'],
36         song[0]['artist'] + '\n' + song[0]['albumtitle']])
37 
38     # 播放
39     player = subprocess.Popen(['mplayer', song[0]['url']])
40     time.sleep(song[0]['length'])
41     player.kill()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM