xiami_radio 1.1.0 → 1.1.2

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: f93c045ffdd8ba47df5d6396621207607e4ddb6b
4
- data.tar.gz: bdd9094e9627de4774fe49d3459bb3b510f60c5a
3
+ metadata.gz: 82320db1fc6fa1004688356887db8a53f38683f6
4
+ data.tar.gz: a34ba7934dc3dd9a40da5bb4d0e5c6cf4808a1d9
5
5
  SHA512:
6
- metadata.gz: 8d51e8774338f469d4396d33aabfb93b3f2ed37bb5adcc860e41affae13245785f1c9ab9f46b8d3c778fbe7db3e10bb78b0d851447a888de1a2cd0a976137957
7
- data.tar.gz: d35701ac4c45494d0e2541b8b307b0df193edd247a15713a6c417c243392a8c1fcefd181b07a4af8cba5ce17549d4ad2c4c006a3a116cc40f4673f9e65e93f31
6
+ metadata.gz: f1a0d25276bc5dafd2ffffe19659aa72f342cfedab660373a222ea8132620a3ab7b703016f29c133d2d0e6f7ee763d093b87f6518e8af080167b56b3e8dbe3c1
7
+ data.tar.gz: add1a386b190a5bf46720ffe232e9dd727b3fb65bdd3e3e83ca0cacd6e6a272f87f7a402dad1ab47ede33917d83526d71b826b7187c6f010c93f04bc26db287b
data/README.md CHANGED
@@ -0,0 +1,61 @@
1
+ Xiami_Radio
2
+ ======================================
3
+
4
+ A Xiami radio player by command-line on ruby.
5
+
6
+ 鉴于 V2ex 上有复数个豆瓣的各种版本各种功能的播放工具,我大虾米拿去一比真是冷清得不行。
7
+
8
+ ( **Pia!(o ‵-′)ノಥ_ಥ ** 你丫忒夸张了吧,仔细看看还是有的 )
9
+
10
+ 之前也在 V2 表示会折腾个 Ruby 版的虾米,于是就有了这个 ruby 的 **虾米电台** ,虽然好像已经过了很久了
11
+
12
+ ## Features
13
+
14
+ * 支持用户登录
15
+ * 支持选择电台
16
+ * 支持 320k (无需会员)
17
+ * 支持收藏到虾米音乐库
18
+ * 播放记录上传虾米
19
+ * 附带自动签到脚本一份
20
+
21
+ ## Usage
22
+
23
+ ```
24
+ $ gem install xiami_radio
25
+ ```
26
+
27
+ and then
28
+
29
+ ```
30
+ $ xiaomi_radio
31
+ ```
32
+
33
+ Enjoy yourself ~
34
+
35
+ ## Requirements
36
+
37
+ * Portaudio >= 19
38
+ * Mpg123 >= 1.14
39
+ * Audite
40
+
41
+ ## OSX Install
42
+
43
+ ```
44
+ brew install portaudio
45
+ brew install mpg123
46
+ ```
47
+
48
+
49
+ ## Debian / Ubuntu Install
50
+ ```
51
+ apt-get install libjack0 libjack-dev
52
+ apt-get install libportaudiocpp0 portaudio19-dev libmpg123-dev
53
+ ```
54
+
55
+ ## Audite
56
+
57
+ 使用了 [Audite][1] 作为播放组件
58
+
59
+
60
+
61
+ [1]: https://github.com/georgi/audite
data/bin/xiami_radio CHANGED
@@ -4,7 +4,7 @@
4
4
  require 'xiami_radio'
5
5
  require 'io/console'
6
6
 
7
- user = XiamiRadio::User.new
7
+ user = XiamiRadio::User.instance
8
8
 
9
9
  email = unless user.login?
10
10
  puts 'Plz keep empty if you don\'t want to login'
@@ -35,4 +35,4 @@ radio_option = case gets.chomp[0]
35
35
  {type: (type || 8).to_i, oid: oid.to_i}
36
36
  end
37
37
 
38
- XiamiRadio::Player.play user.radio radio_option
38
+ XiamiRadio::Player.play XiamiRadio::Radio.new(radio_option)
@@ -10,11 +10,10 @@ module XiamiRadio
10
10
  end
11
11
  end
12
12
 
13
- attr_reader :track, :progress, :total, :file
13
+ attr_reader :track, :file
14
14
 
15
15
  def initialize(track)
16
16
  @track = track
17
- @uri = URI @track.location
18
17
  end
19
18
 
20
19
  def filename
@@ -26,30 +25,32 @@ module XiamiRadio
26
25
  end
27
26
 
28
27
  def start
29
- @thread = Thread.start do
30
- Net::HTTP.get_response @uri do |res|
31
- if res.code == '302'
32
- @uri = URI res.header['Location']
33
- start
34
- else
35
- @progress, @total = 0, res.header['Content-Length'].to_i
36
- @file = File.open(filename, 'w')
37
- res.read_body do |chunk|
38
- @file << chunk
39
- @progress += chunk.size
40
- @file.close unless @progress < @total
41
- end
42
- end
43
- end
44
- end
28
+ @thread = Thread.start { request URI(@track.location) }
45
29
  sleep 0.1 until @progress.to_i > 0
46
30
  end
47
31
 
48
32
  def stop
49
33
  @thread&.exit
50
34
  @thread = nil
51
- File.delete(@file)
35
+ File.delete(@file) if @file
52
36
  end
53
37
 
38
+ private
39
+
40
+ def request(uri)
41
+ Net::HTTP.get_response uri do |res|
42
+ if res.code == '302'
43
+ request URI(res.header['Location'])
44
+ else
45
+ @progress, @total = 0, res.header['Content-Length'].to_i
46
+ @file = File.open(filename, 'w')
47
+ res.read_body do |chunk|
48
+ @file << chunk
49
+ @progress += chunk.size
50
+ @file.close unless @progress < @total
51
+ end
52
+ end
53
+ end
54
+ end
54
55
  end
55
56
  end
@@ -4,16 +4,16 @@ module XiamiRadio
4
4
  # There is a player as you saw
5
5
  class Player
6
6
 
7
- attr_reader :track, :next_track, :radio, :user
7
+ attr_reader :track, :next_track, :radio
8
8
 
9
9
  def initialize(radio:, _playlist: nil)
10
- @radio, @user = radio, radio.client.user
10
+ @radio = radio
11
11
  @player = Audite.new
12
- @view = View::Player.new self
12
+ @view = View::Player.new
13
13
 
14
14
  @player.events.on :position_change, &method(:position_change)
15
15
  @player.events.on :complete, &method(:complete)
16
- @view.listen_on
16
+ @view.listen_on self
17
17
  end
18
18
 
19
19
  def play
@@ -25,11 +25,9 @@ module XiamiRadio
25
25
  end
26
26
 
27
27
  def next
28
- if @next_track.nil?
29
- @next_track = @radio.next_track
30
- @player.queue @next_track.file_path
31
- end
32
- @track, @next_track = @next_track, nil
28
+ @track.downloader.stop
29
+ preload! unless preload?
30
+ unperload!
33
31
  @player.request_next_song
34
32
  end
35
33
 
@@ -48,19 +46,31 @@ module XiamiRadio
48
46
  private
49
47
 
50
48
  def position_change(position)
51
- @view.refresh position
52
-
53
- if @next_track.nil? && position / @track.duration > 0.7
54
- Thread.start do
55
- @track.record
56
- @next_track = @radio.next_track
57
- @player.queue @next_track.file_path
58
- end
59
- end
49
+ @view.refresh @track, position unless position > @track.duration
50
+
51
+ Thread.start do
52
+ preload!
53
+ @track.record
54
+ end if !preload? && position / @track.duration > 0.7
60
55
  end
61
56
 
62
57
  def complete
63
- @track, @next_track = @next_track, nil
58
+ @track, @preload_track = @preload_track, nil
59
+ end
60
+
61
+ def preload?
62
+ @preload_flag ||= false
63
+ end
64
+
65
+ def preload!
66
+ @preload_flag = true
67
+ @preload_track = @radio.next_track
68
+ @player.queue @preload_track.file_path
69
+ end
70
+
71
+ def unperload!
72
+ @preload_flag = false
73
+ @track, @preload_track = @preload_track, nil
64
74
  end
65
75
 
66
76
  def self.play(radio)
@@ -6,12 +6,12 @@ module XiamiRadio
6
6
 
7
7
  XIAMI_CAI = {type: 8, oid: 0}.freeze
8
8
 
9
- attr_reader :type, :oid, :client, :nori, :play_queue
9
+ attr_reader :type, :oid, :nori, :play_queue, :client
10
10
 
11
- def initialize(type:, oid:, user: nil)
11
+ def initialize(type:, oid:)
12
12
  @type = type
13
13
  @oid = oid
14
- @client = user&.client || Client.new
14
+ @client = Client.new user: User.instance
15
15
  @nori = Nori.new(:convert_tags_to => -> (tag) { tag.snakecase.to_sym })
16
16
  @play_queue = []
17
17
  end
@@ -6,7 +6,7 @@ module XiamiRadio
6
6
  @info = track
7
7
  @title, @song_id, @album_name, @artist = track.values_at(:title, :song_id, :album_name, :artist)
8
8
  @radio = radio
9
- @client = radio.client
9
+ @client = Client.new user: User.instance
10
10
  end
11
11
 
12
12
  def location(hd: false)
@@ -1,8 +1,10 @@
1
1
  require 'http-cookie'
2
+ require 'singleton'
2
3
 
3
4
  module XiamiRadio
4
5
  # There is a user as you saw
5
6
  class User
7
+ include Singleton
6
8
  attr_reader :nick_name, :level, :user_id, :sign, :is_vip
7
9
  attr_accessor :cookie_jar
8
10
 
@@ -12,10 +14,6 @@ module XiamiRadio
12
14
  get_user_info
13
15
  end
14
16
 
15
- def radio(**args)
16
- XiamiRadio::Radio.new user: self, **args
17
- end
18
-
19
17
  def login?
20
18
  !user_id.to_s.empty?
21
19
  end
@@ -52,12 +50,12 @@ module XiamiRadio
52
50
  cookie_jar.cookies.select { |c| c.name == '_xiamitoken' }.first&.value
53
51
  end
54
52
 
53
+ private
54
+
55
55
  def client
56
56
  @client ||= Client.new user: self
57
57
  end
58
58
 
59
- private
60
-
61
59
  def login_client
62
60
  @l_client ||= Client.new user: self, host: Client::LOGIN_HOST
63
61
  end
@@ -1,5 +1,5 @@
1
1
  module XiamiRadio
2
2
 
3
- VERSION = '1.1.0'
3
+ VERSION = '1.1.2'
4
4
 
5
5
  end
@@ -1,90 +1,92 @@
1
1
  require 'curses'
2
2
 
3
- module XiamiRadio::View
4
- class Player
5
- attr_reader :player
6
-
7
- def initialize(player)
8
- @player = player
9
- Curses.init_screen
10
- Curses.noecho
11
- Curses.stdscr.keypad(true)
12
- Curses.start_color
13
- Curses.use_default_colors
14
- Curses.init_pair(Curses::COLOR_CYAN,Curses::COLOR_CYAN,Curses::COLOR_BLACK)
15
- Curses.init_pair(Curses::COLOR_RED,Curses::COLOR_RED,Curses::COLOR_BLACK)
16
- Curses.clear
17
- end
3
+ module XiamiRadio
4
+ module View
5
+ class Player
6
+ include Curses
7
+
8
+ def initialize
9
+ init_screen
10
+ noecho
11
+ stdscr.keypad true
12
+ curs_set 0
13
+ start_color
14
+ init_pair(COLOR_CYAN, COLOR_CYAN, COLOR_BLACK)
15
+ init_pair(COLOR_RED, COLOR_RED, COLOR_BLACK)
16
+ end
18
17
 
19
- def refresh(position)
20
- Curses.clear
21
- render_title_line player.track
22
- render_progress_line (position / player.track.duration), player.track.downloader.progress
23
- render_info_line player.track, position
24
- render_msg_line
25
- Curses.refresh
26
- end
18
+ alias_method :curses_refresh, :refresh
19
+ def refresh(track, position)
20
+ render_title_line track
21
+ render_progress_line (position / track.duration), track.downloader.progress
22
+ render_info_line track, position
23
+ render_msg_line
24
+ Curses.refresh
25
+ end
27
26
 
28
- def listen_on
29
- Thread.start do
30
- while (key = Curses.getch)
31
- case key
32
- when Curses::KEY_LEFT
33
- player.rewind
34
- when Curses::KEY_RIGHT
35
- player.forward
36
- when Curses::KEY_DOWN
37
- player.next
38
- when 'l'
39
- XiamiRadio::Notice.push player.track.fav
40
- when ' '
41
- player.toggle
42
- else #
27
+ def listen_on(player)
28
+ Thread.start do
29
+ while (key = getch)
30
+ case key
31
+ when KEY_LEFT
32
+ player.rewind
33
+ when KEY_RIGHT
34
+ player.forward
35
+ when KEY_DOWN
36
+ player.next
37
+ when 'l'
38
+ XiamiRadio::Notice.push player.track.fav
39
+ when ' '
40
+ player.toggle
41
+ else #
42
+ end
43
43
  end
44
44
  end
45
45
  end
46
- end
47
46
 
48
- private
47
+ private
49
48
 
50
- def render_title_line(track)
51
- Curses.setpos(0, 0)
52
- Curses.addstr('Now is playing ')
53
- Curses.attron(Curses.color_pair(Curses::COLOR_RED)|Curses::A_NORMAL){
54
- Curses.addstr(" #{track.title} - #{track.artist} ")
55
- }
56
- if @player.user.login?
57
- track.grade? ? Curses.addstr(' 已收藏 ') : Curses.addstr(' 按"L"加入收藏 ')
49
+ def render_title_line(track)
50
+ setpos(0, 0)
51
+ clrtoeol
52
+ addstr('Now is playing ')
53
+ attron(color_pair(COLOR_RED)|A_NORMAL) {
54
+ addstr(" #{track.title} - #{track.artist} ")
55
+ }
56
+ if User.instance.login?
57
+ track.grade? ? addstr(' 已收藏 ') : addstr(' 按"L"加入收藏 ')
58
+ end
58
59
  end
59
- end
60
60
 
61
- def render_progress_line(play_rate, dawnload_rate)
62
- p = (play_rate * Curses.cols).round
63
- d = (dawnload_rate * Curses.cols).round - p
64
- Curses.setpos(1, 0)
65
- Curses.addstr('_' * p + '#' * d + ' ' * (Curses.cols - p - d))
66
- end
61
+ def render_progress_line(play_rate, dawnload_rate)
62
+ p = (play_rate * cols).round
63
+ d = (dawnload_rate * cols).round - p
64
+ setpos(1, 0)
65
+ clrtoeol
66
+ addstr('_' * p + '#' * d + ' ' * (cols - p - d))
67
+ end
67
68
 
68
- def render_info_line(track, position)
69
- Curses.setpos(2, 0)
70
- Curses.addstr("#{track.reason.content}")
71
- Curses.addstr(": #{track.reason.title} ") unless track.reason.title.nil?
72
- Curses.addstr("- #{track.reason.artist} ") unless track.reason.artist.nil?
73
- Curses.addstr(" 播放进度: ")
74
- Curses.attron(Curses.color_pair(Curses::COLOR_CYAN)|Curses::A_NORMAL){
75
- Curses.addstr(" #{sec_2_min position} / #{sec_2_min track.duration} ")
76
- }
77
- end
69
+ def render_info_line(track, position)
70
+ setpos(2, 0)
71
+ clrtoeol
72
+ addstr("#{track.reason.content}")
73
+ addstr(": #{track.reason.title} ") unless track.reason.title.nil?
74
+ addstr("- #{track.reason.artist} ") unless track.reason.artist.nil?
75
+ addstr(" 播放进度: ")
76
+ attron(color_pair(COLOR_CYAN)|A_NORMAL) {
77
+ addstr(" #{sec_2_min position} / #{sec_2_min track.duration} ")
78
+ }
79
+ end
78
80
 
79
- def render_msg_line(msg = XiamiRadio::Notice.shift)
80
- return if msg.nil?
81
- Curses.setpos(3, 0)
82
- Curses.addstr(msg)
83
- end
81
+ def render_msg_line(msg = XiamiRadio::Notice.shift)
82
+ setpos(3, 0)
83
+ clrtoeol
84
+ addstr(msg || '')
85
+ end
84
86
 
85
- def sec_2_min(sec)
86
- Time.at(sec).utc.strftime('%M:%S')
87
+ def sec_2_min(sec)
88
+ Time.at(sec).utc.strftime('%M:%S')
89
+ end
87
90
  end
88
-
89
91
  end
90
92
  end
data/lib/xiami_radio.rb CHANGED
@@ -11,10 +11,25 @@ require 'tmpdir'
11
11
 
12
12
  module XiamiRadio
13
13
  TMP_DIR = File.join(Dir.tmpdir, 'xiami_radio').freeze
14
+ DEBUG = false
14
15
 
15
- def self.mktmpdir
16
- Dir.mkdir TMP_DIR, 0700 unless Dir.exist? TMP_DIR
16
+ Thread.abort_on_exception = true
17
+
18
+ class << self
19
+ def init
20
+ mktmpdir
21
+ stderr = debug? ? STDOUT : File.join(TMP_DIR, '戊')
22
+ $stderr.reopen stderr, 'w'
23
+ end
24
+
25
+ def mktmpdir
26
+ Dir.mkdir TMP_DIR, 0700 unless Dir.exist? TMP_DIR
27
+ end
28
+
29
+ def debug?
30
+ %w(1 true on).include? ENV.fetch('DEBUG', DEBUG)
31
+ end
17
32
  end
18
33
  end
19
34
 
20
- XiamiRadio.mktmpdir
35
+ XiamiRadio.init
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xiami_radio
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Chou
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-19 00:00:00.000000000 Z
11
+ date: 2017-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: audite
@@ -80,7 +80,8 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '9.0'
83
- description: a command-line tool to help you listen Xiami radio via a geek way
83
+ description: A Xiami radio player by command-line on ruby, help you listening to the
84
+ Xiami via a geek way.
84
85
  email:
85
86
  - me@ichou.cn
86
87
  executables:
@@ -124,5 +125,5 @@ rubyforge_project:
124
125
  rubygems_version: 2.6.11
125
126
  signing_key:
126
127
  specification_version: 4
127
- summary: Xiami radio player with command-line on ruby
128
+ summary: a Xiami radio player by command-line on ruby
128
129
  test_files: []