doubanfm 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/doubanfm +13 -0
- data/doubanfm.gemspec +5 -3
- data/lib/doubanfm/constant.rb +50 -0
- data/lib/doubanfm/doubanfm.rb +111 -0
- data/lib/doubanfm/player.rb +84 -0
- data/lib/doubanfm/version.rb +2 -2
- data/lib/doubanfm.rb +3 -3
- metadata +24 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3861716d30ebf71c7ca9da1eff05c42655ee5165
|
4
|
+
data.tar.gz: 1cf80994a730ed474c4cf8556c764980f14a297a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95cbf1b10fe56afae46919d2bde967e83a775051a4faaa2504daefe055fd1e3750e0798c86c20a29400afb0911d84af76f25ba39a2eac803f06a28232e4f59f8
|
7
|
+
data.tar.gz: 5017daacf5e6f2521707c98bf207c027e1973b2dee3c2dc777056969173c76d9c64fcb8540fc1cf6b8274d270b8fc2caa3969bfbffc1b9102b0e4720d07a127e
|
data/bin/doubanfm
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
ROOT_DIR = Pathname.new(__FILE__).dirname.parent
|
5
|
+
$:.push(ROOT_DIR.join('lib'))
|
6
|
+
load ROOT_DIR.join('lib/doubanfm.rb')
|
7
|
+
|
8
|
+
player = DoubanFM::Player.new
|
9
|
+
begin
|
10
|
+
player.start
|
11
|
+
rescue
|
12
|
+
puts 'Bye~'
|
13
|
+
end
|
data/doubanfm.gemspec
CHANGED
@@ -5,11 +5,11 @@ require 'doubanfm/version'
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "doubanfm"
|
8
|
-
spec.version =
|
8
|
+
spec.version = DoubanFM::VERSION
|
9
9
|
spec.authors = ["Edgar Wang"]
|
10
10
|
spec.email = ["edgar.xiaoxiangyu@gmail.com"]
|
11
|
-
spec.description = %q{
|
12
|
-
spec.summary = %q{
|
11
|
+
spec.description = %q{Just another DoubanFM client.}
|
12
|
+
spec.summary = %q{A cmdline DoubanFM client. Need mpg123 to play songs.}
|
13
13
|
spec.homepage = ""
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
@@ -18,6 +18,8 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
+
spec.add_dependency "highline"
|
22
|
+
|
21
23
|
spec.add_development_dependency "bundler", "~> 1.3"
|
22
24
|
spec.add_development_dependency "rake"
|
23
25
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module DoubanFM
|
4
|
+
module Constants
|
5
|
+
# 豆瓣FM的API服务器通过`app_name`和`version`来确定
|
6
|
+
# 客户端的合法性
|
7
|
+
APP_NAME = 'radio_desktop_win'
|
8
|
+
APP_VERSION = 100
|
9
|
+
|
10
|
+
# 此URI用于用户登录
|
11
|
+
# 返回的用户信息是JSON格式的
|
12
|
+
LOGIN_URI = URI('http://www.douban.com/j/app/login')
|
13
|
+
|
14
|
+
# 此URI用于获取所有可用的兆赫(channel)
|
15
|
+
# 返回值为JSON格式
|
16
|
+
CHANNELS_URI = URI('http://www.douban.com/j/app/radio/channels')
|
17
|
+
|
18
|
+
# 我的私人兆赫所对应的ID
|
19
|
+
PERSONAL_CHANNEL_ID = 0
|
20
|
+
|
21
|
+
# 我的红心兆赫所对应的ID
|
22
|
+
RED_HEART_CHANNEL_ID = -3
|
23
|
+
|
24
|
+
# 当前兆赫(channel)未设定时的默认值
|
25
|
+
INVALID_CHANNEL_ID = -1
|
26
|
+
end
|
27
|
+
|
28
|
+
module ActionType
|
29
|
+
# 不再播放
|
30
|
+
BYE = 'b'
|
31
|
+
|
32
|
+
# 标记当前歌曲为喜欢
|
33
|
+
RATE = 'r'
|
34
|
+
|
35
|
+
# 取消当前歌曲的喜欢标记
|
36
|
+
UNRATE = 'u'
|
37
|
+
|
38
|
+
# 当前歌曲播放完毕,但是歌曲队列中还有歌曲
|
39
|
+
FINISH = 'e'
|
40
|
+
|
41
|
+
# 没有歌曲播放,歌曲队列也没有任何歌曲,需要返回新播放列表
|
42
|
+
NEW_PLAYLIST = 'n'
|
43
|
+
|
44
|
+
# 歌曲正在播放,队列中还有歌曲,需要返回新的播放列表
|
45
|
+
NEXT_PLAYLIST = 'p'
|
46
|
+
|
47
|
+
# 跳过当前歌曲
|
48
|
+
SKIP = 's'
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'json'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module DoubanFM
|
6
|
+
class Client
|
7
|
+
include Constants
|
8
|
+
include ActionType
|
9
|
+
|
10
|
+
attr_reader :channels, :current_channel, :current_song
|
11
|
+
|
12
|
+
def initialize(email='', password='')
|
13
|
+
@client = Net::HTTP
|
14
|
+
@current_channel = INVALID_CHANNEL_ID
|
15
|
+
@current_song = nil
|
16
|
+
@user_info = {user_id: '', expire: '', token: ''}
|
17
|
+
|
18
|
+
if !email.empty? && !password.empty?
|
19
|
+
login(email, password)
|
20
|
+
end
|
21
|
+
|
22
|
+
fetch_channels
|
23
|
+
new_playlist
|
24
|
+
end
|
25
|
+
|
26
|
+
def login(email='', password='')
|
27
|
+
resp = @client.post_form(LOGIN_URI,
|
28
|
+
app_name: APP_NAME,
|
29
|
+
version: APP_VERSION,
|
30
|
+
email: email,
|
31
|
+
password: password)
|
32
|
+
@user_info = JSON.parse(
|
33
|
+
resp.body,
|
34
|
+
symbolize_names: true
|
35
|
+
)
|
36
|
+
|
37
|
+
if @user_info[:r] == 1
|
38
|
+
raise @user_info[:err]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def user_logged?
|
43
|
+
if @user_info[:user_id].empty?
|
44
|
+
return false
|
45
|
+
end
|
46
|
+
|
47
|
+
return true
|
48
|
+
end
|
49
|
+
|
50
|
+
def new_playlist
|
51
|
+
fetch_playlist(NEW_PLAYLIST)
|
52
|
+
end
|
53
|
+
|
54
|
+
def next_playlist
|
55
|
+
fetch_playlist(NEXT_PLAYLIST)
|
56
|
+
end
|
57
|
+
|
58
|
+
def next_song
|
59
|
+
if @current_song == @playlist.last
|
60
|
+
next_playlist
|
61
|
+
end
|
62
|
+
|
63
|
+
next_song_pos = @playlist.index(@current_song) + 1
|
64
|
+
@current_song = @playlist[next_song_pos]
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
def fetch_channels
|
69
|
+
@channels = JSON.parse(
|
70
|
+
@client.get(CHANNELS_URI),
|
71
|
+
symbolize_names: true
|
72
|
+
)[:channels]
|
73
|
+
end
|
74
|
+
|
75
|
+
def fetch_playlist(type)
|
76
|
+
if @current_channel == INVALID_CHANNEL_ID
|
77
|
+
channel_id = select_random_channel
|
78
|
+
else
|
79
|
+
channel_id = @current_channel
|
80
|
+
end
|
81
|
+
|
82
|
+
sid = @current_song ? @current_song[:sid] : ''
|
83
|
+
params = {
|
84
|
+
app_name: APP_NAME,
|
85
|
+
version: APP_VERSION,
|
86
|
+
user_id: @user_info[:user_id],
|
87
|
+
expire: @user_info[:expire],
|
88
|
+
token: @user_info[:token],
|
89
|
+
channel: channel_id,
|
90
|
+
sid: sid,
|
91
|
+
type: type
|
92
|
+
}
|
93
|
+
|
94
|
+
fetch_playlist_uri = URI('http://www.douban.com/j/app/radio/people')
|
95
|
+
fetch_playlist_uri.query = URI.encode_www_form(params)
|
96
|
+
@playlist = JSON.parse(
|
97
|
+
@client.get(fetch_playlist_uri),
|
98
|
+
symbolize_names: true
|
99
|
+
)[:song]
|
100
|
+
|
101
|
+
@current_song = @playlist.first
|
102
|
+
end
|
103
|
+
|
104
|
+
def select_random_channel
|
105
|
+
first_channel = user_logged? ? 1 : 0
|
106
|
+
|
107
|
+
which = Random.new.rand(first_channel ... @channels.size)
|
108
|
+
@channels[which][:channel_id]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'highline/import'
|
2
|
+
|
3
|
+
module DoubanFM
|
4
|
+
class Player
|
5
|
+
def initialize
|
6
|
+
@client = Client.new
|
7
|
+
@semaphore = Mutex.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def start
|
11
|
+
loop do
|
12
|
+
cmd = ask("DoubanFM> ", %w{login play skip quit}) do |q|
|
13
|
+
q.readline = true
|
14
|
+
end
|
15
|
+
|
16
|
+
case cmd
|
17
|
+
when 'login'
|
18
|
+
login
|
19
|
+
when 'play'
|
20
|
+
play
|
21
|
+
when 'skip'
|
22
|
+
skip
|
23
|
+
when 'quit'
|
24
|
+
kill_player_thread
|
25
|
+
break
|
26
|
+
else
|
27
|
+
puts 'Nothing to do'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def play
|
33
|
+
Thread.new do
|
34
|
+
player_proc = proc do |waiting|
|
35
|
+
if waiting
|
36
|
+
@client.next_song
|
37
|
+
|
38
|
+
play_current_song do |wait|
|
39
|
+
player_proc.call(wait)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
player_proc.call(true)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def skip
|
48
|
+
@client.next_song
|
49
|
+
kill_player_thread
|
50
|
+
end
|
51
|
+
|
52
|
+
def login
|
53
|
+
return if @client.user_logged?
|
54
|
+
|
55
|
+
email = ask("邮箱: ")
|
56
|
+
password = ask("密码: ") do |q|
|
57
|
+
q.echo = false
|
58
|
+
end
|
59
|
+
|
60
|
+
@client.login(email, password)
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def play_current_song
|
65
|
+
@semaphore.lock
|
66
|
+
|
67
|
+
@waiting = false
|
68
|
+
|
69
|
+
@player_pid = spawn("mpg123 #{@client.current_song[:url]} > /dev/null 2>&1")
|
70
|
+
|
71
|
+
Process.wait
|
72
|
+
@waiting = true
|
73
|
+
|
74
|
+
@semaphore.unlock
|
75
|
+
|
76
|
+
yield @waiting if block_given?
|
77
|
+
end
|
78
|
+
|
79
|
+
def kill_player_thread
|
80
|
+
Process.kill('KILL', @player_pid)
|
81
|
+
Process.kill('KILL', @player_pid + 1)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/lib/doubanfm/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module
|
2
|
-
VERSION = "0.0.
|
1
|
+
module DoubanFM
|
2
|
+
VERSION = "0.0.3"
|
3
3
|
end
|
data/lib/doubanfm.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
1
|
require "doubanfm/version"
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
require "doubanfm/constant"
|
3
|
+
require "doubanfm/doubanfm"
|
4
|
+
require "doubanfm/player"
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: doubanfm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Edgar Wang
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-08-
|
11
|
+
date: 2013-08-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: highline
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,10 +52,11 @@ dependencies:
|
|
38
52
|
- - '>='
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '0'
|
41
|
-
description:
|
55
|
+
description: Just another DoubanFM client.
|
42
56
|
email:
|
43
57
|
- edgar.xiaoxiangyu@gmail.com
|
44
|
-
executables:
|
58
|
+
executables:
|
59
|
+
- doubanfm
|
45
60
|
extensions: []
|
46
61
|
extra_rdoc_files: []
|
47
62
|
files:
|
@@ -50,8 +65,12 @@ files:
|
|
50
65
|
- LICENSE.txt
|
51
66
|
- README.md
|
52
67
|
- Rakefile
|
68
|
+
- bin/doubanfm
|
53
69
|
- doubanfm.gemspec
|
54
70
|
- lib/doubanfm.rb
|
71
|
+
- lib/doubanfm/constant.rb
|
72
|
+
- lib/doubanfm/doubanfm.rb
|
73
|
+
- lib/doubanfm/player.rb
|
55
74
|
- lib/doubanfm/version.rb
|
56
75
|
homepage: ''
|
57
76
|
licenses:
|
@@ -76,5 +95,5 @@ rubyforge_project:
|
|
76
95
|
rubygems_version: 2.0.6
|
77
96
|
signing_key:
|
78
97
|
specification_version: 4
|
79
|
-
summary:
|
98
|
+
summary: A cmdline DoubanFM client. Need mpg123 to play songs.
|
80
99
|
test_files: []
|