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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b948b63a01860b2f6aedb884f5cbbeeef4dc225c
4
- data.tar.gz: 917f2baa1b99b824bd11643b8ed59050961942ae
3
+ metadata.gz: 3861716d30ebf71c7ca9da1eff05c42655ee5165
4
+ data.tar.gz: 1cf80994a730ed474c4cf8556c764980f14a297a
5
5
  SHA512:
6
- metadata.gz: cd8fd320829d0aed544d034e85288fd10ee4818258d446e2dd71a046ff2f6c4b4af63d84fb6c8817e100582dfeaaab79b7c2f616ecf06d653cb2e0f0adc8c5f1
7
- data.tar.gz: 5af2cdf94f53a63b97165a990d8ff68c124779d299b5c97025bfe8b930727cb28b9f4a5df5fab318913d7c4086c8ad65b9a705fe57bf750232ab8e76ac0478db
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 = Doubanfm::VERSION
8
+ spec.version = DoubanFM::VERSION
9
9
  spec.authors = ["Edgar Wang"]
10
10
  spec.email = ["edgar.xiaoxiangyu@gmail.com"]
11
- spec.description = %q{A Ruby wrapper of douban.fm api. Just a placeholder now!!}
12
- spec.summary = %q{Just a placeholder now!}
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
@@ -1,3 +1,3 @@
1
- module Doubanfm
2
- VERSION = "0.0.2"
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
- module Doubanfm
4
- end
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.2
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-09 00:00:00.000000000 Z
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: A Ruby wrapper of douban.fm api. Just a placeholder now!!
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: Just a placeholder now!
98
+ summary: A cmdline DoubanFM client. Need mpg123 to play songs.
80
99
  test_files: []