mplug163 0.1.1 → 0.2.0
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/README.md +3 -4
- data/lib/mplug163/api.rb +58 -97
- data/lib/mplug163/menu.rb +114 -83
- data/lib/mplug163/player.rb +29 -23
- data/lib/mplug163/ui.rb +60 -56
- data/lib/mplug163/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e33bc56dcd83e31ebfdc4f491d5fe3681382a66
|
4
|
+
data.tar.gz: ac87072c527579dd5c70ea215ad09195a58d2d19
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51c848df5edb40fa2b9994c6f36b0240a8a0042be1ec2bb357c413ed799bb38df8e4d6f0e58140969d7f8efdad3c7fd40c06f7f660ad91d05af64155c3e33194
|
7
|
+
data.tar.gz: 768999fd9f74f558310dcae7143200f74e99ffc9a49d3cf4461af5b9efcc9082d5b55932daddf3e6c8f9a1152b083f73feb2a56f05d88cc93e0ed3c642b75804
|
data/README.md
CHANGED
@@ -26,16 +26,15 @@ Sorry, I do not test Mplug163 in Linux. If you try it in Linux and catch some pr
|
|
26
26
|
| h | Back | 后退 |
|
27
27
|
| l | Forward | 前进 |
|
28
28
|
| [ | Prev Song | 上一首歌曲 |
|
29
|
-
| ] | Next Song |
|
29
|
+
| ] | Next Song | 下一首歌曲 |
|
30
30
|
| ' ' | Play / Pause | 播放 / 暂停 |
|
31
31
|
| u | Prev Page | 上一页列表 |
|
32
32
|
| d | Next Page | 下一页列表 |
|
33
33
|
| f | Search | 搜索 |
|
34
34
|
| m | Main Menu | 主菜单 |
|
35
35
|
| p | Present Playlist | 当前播放列表 |
|
36
|
-
|
|
37
|
-
|
|
38
|
-
| s | Star Song | 收藏歌曲 |
|
36
|
+
| s | Star | 收藏歌曲或精选歌单|
|
37
|
+
| t | Playlist | 收藏精选歌单 |
|
39
38
|
| c | Collection | 收藏歌曲列表 |
|
40
39
|
| r | Remove Present Entry | 删除当前曲目 |
|
41
40
|
| q | Quit | 退出 |
|
data/lib/mplug163/api.rb
CHANGED
@@ -23,18 +23,19 @@ class NetEase
|
|
23
23
|
Unirest.timeout @default_timeout
|
24
24
|
end
|
25
25
|
|
26
|
-
def http_request(method, action, query
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
26
|
+
def http_request(method, action, query = nil)
|
27
|
+
connection =
|
28
|
+
if method == 'GET'
|
29
|
+
url = (query.nil? ? action : "#{action}?#{query}")
|
30
|
+
Unirest.get(url, headers: @header)
|
31
|
+
elsif method == 'POST'
|
32
|
+
Unirest.post(action, headers: @header, parameters: query)
|
33
|
+
end
|
33
34
|
|
34
35
|
connection.body
|
35
36
|
end
|
36
37
|
|
37
|
-
#
|
38
|
+
# Log in
|
38
39
|
def login(username, password)
|
39
40
|
action = "http://music.163.com/api/login/"
|
40
41
|
query = {
|
@@ -44,24 +45,20 @@ class NetEase
|
|
44
45
|
}
|
45
46
|
begin
|
46
47
|
return http_request('POST', action, query)
|
47
|
-
rescue
|
48
|
+
rescue => e
|
48
49
|
return {"code" => 501}
|
49
50
|
end
|
50
51
|
end
|
51
52
|
|
52
|
-
#
|
53
|
-
def user_playlists(uid, offset=0, limit=100)
|
53
|
+
# User's playlists
|
54
|
+
def user_playlists(uid, offset = 0, limit = 100)
|
54
55
|
action = "http://music.163.com/api/user/playlist/?offset=#{offset}&limit=#{limit}&uid=#{uid}"
|
55
|
-
|
56
|
-
|
57
|
-
return data['playlist']
|
58
|
-
rescue Exception => e
|
59
|
-
return []
|
60
|
-
end
|
56
|
+
data = http_request('GET', action)
|
57
|
+
data['playlist']
|
61
58
|
end
|
62
59
|
|
63
|
-
#
|
64
|
-
def search(s, stype=1, offset=0,
|
60
|
+
# Search song(1),artist(100),album(10),playlist(1000),user(1002)
|
61
|
+
def search(s, stype = 1, offset = 0, limit = 100)
|
65
62
|
action = "http://music.163.com/api/search/get/web"
|
66
63
|
query = {
|
67
64
|
"s" => s,
|
@@ -73,128 +70,92 @@ class NetEase
|
|
73
70
|
http_request('POST', action, query)
|
74
71
|
end
|
75
72
|
|
76
|
-
#
|
73
|
+
# New albums
|
74
|
+
# http://music.163.com/#/discover/album/
|
77
75
|
def new_albums(offset=0, limit=50)
|
78
76
|
action = "http://music.163.com/api/album/new?area=ALL&offset=#{offset}&total=true&limit=#{limit}"
|
79
|
-
|
80
|
-
|
81
|
-
return data['albums']
|
82
|
-
rescue Exception => e
|
83
|
-
return []
|
84
|
-
end
|
77
|
+
data = http_request('GET', action)
|
78
|
+
data['albums']
|
85
79
|
end
|
86
80
|
|
87
|
-
#
|
81
|
+
# Top playlists
|
82
|
+
# hot||new http://music.163.com/#/discover/playlist/
|
88
83
|
|
89
84
|
# '全部' => '%E5%85%A8%E9%83%A8'
|
90
|
-
def top_playlists(category='%E5%85%A8%E9%83%A8', order='hot', offset=0, limit=
|
85
|
+
def top_playlists(category = '%E5%85%A8%E9%83%A8', order = 'hot', offset = 0, limit = 100)
|
91
86
|
flag = (offset > 0 ? true : false)
|
92
87
|
action = "http://music.163.com/api/playlist/list?cat=#{category}&order=#{order}&offset=#{offset}&total=#{flag}&limit=#{limit}"
|
93
|
-
|
94
|
-
|
95
|
-
return data['playlists']
|
96
|
-
rescue Exception => e
|
97
|
-
return []
|
98
|
-
end
|
88
|
+
data = http_request('GET', action)
|
89
|
+
return data['playlists']
|
99
90
|
end
|
100
91
|
|
101
|
-
#
|
92
|
+
# Playlist's details
|
102
93
|
def playlist_detail(playlist_id)
|
103
94
|
action = "http://music.163.com/api/playlist/detail?id=#{playlist_id}"
|
104
|
-
|
105
|
-
|
106
|
-
return data['result']['tracks']
|
107
|
-
rescue Exception => e
|
108
|
-
return []
|
109
|
-
end
|
95
|
+
data = http_request('GET', action)
|
96
|
+
return data['result']['tracks']
|
110
97
|
end
|
111
98
|
|
112
|
-
#
|
113
|
-
|
99
|
+
# Top artists
|
100
|
+
# http://music.163.com/#/discover/artist/
|
101
|
+
def top_artists(offset = 0, limit = 100)
|
114
102
|
action = "http://music.163.com/api/artist/top?offset=#{offset}&total=false&limit=#{limit}"
|
115
|
-
|
116
|
-
|
117
|
-
return data['artists']
|
118
|
-
rescue Exception => e
|
119
|
-
return []
|
120
|
-
end
|
103
|
+
data = http_request('GET', action)
|
104
|
+
return data['artists']
|
121
105
|
end
|
122
106
|
|
123
|
-
#
|
124
|
-
|
107
|
+
# Top songlist
|
108
|
+
# http://music.163.com/#/discover/toplist 100
|
109
|
+
def top_songlist
|
125
110
|
action = "http://music.163.com/discover/toplist"
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
return songs_detail(songids.uniq)
|
131
|
-
rescue Exception => e
|
132
|
-
return []
|
133
|
-
end
|
111
|
+
connection = http_request('GET', action)
|
112
|
+
songids = connection.scan(/\/song\?id=(\d+)/)
|
113
|
+
return [] if songids == []
|
114
|
+
return songs_detail(songids.uniq)
|
134
115
|
end
|
135
116
|
|
136
|
-
#
|
117
|
+
# Songs to which a artist belongs.
|
137
118
|
def artists(artist_id)
|
138
119
|
action = "http://music.163.com/api/artist/#{artist_id}"
|
139
|
-
|
140
|
-
|
141
|
-
return data['hotSongs']
|
142
|
-
rescue Exception => e
|
143
|
-
return []
|
144
|
-
end
|
120
|
+
data = http_request('GET', action)
|
121
|
+
return data['hotSongs']
|
145
122
|
end
|
146
123
|
|
147
124
|
# album id -> song id set
|
148
125
|
def album(album_id)
|
149
126
|
action = "http://music.163.com/api/album/#{album_id}"
|
150
|
-
|
151
|
-
|
152
|
-
return data['album']['songs']
|
153
|
-
rescue Exception => e
|
154
|
-
return []
|
155
|
-
end
|
127
|
+
data = http_request('GET', action)
|
128
|
+
return data['album']['songs']
|
156
129
|
end
|
157
130
|
|
158
131
|
# song ids -> song urls (details)
|
159
132
|
def songs_detail(ids, offset=0)
|
160
133
|
tmpids = ids[offset, 100]
|
161
134
|
action = "http://music.163.com/api/song/detail?ids=[#{tmpids.join(',')}]"
|
162
|
-
|
163
|
-
|
164
|
-
return data['songs']
|
165
|
-
rescue Exception => e
|
166
|
-
return []
|
167
|
-
end
|
135
|
+
data = http_request('GET', action)
|
136
|
+
return data['songs']
|
168
137
|
end
|
169
138
|
|
170
139
|
# song id -> song url (details)
|
171
140
|
def song_detail(music_id)
|
172
141
|
id = music_id.join(',')
|
173
142
|
action = "http://music.163.com/api/song/detail/?id=#{id}&ids=[#{id}]"
|
174
|
-
|
175
|
-
|
176
|
-
return data['songs']
|
177
|
-
rescue Exception => e
|
178
|
-
return []
|
179
|
-
end
|
143
|
+
data = http_request('GET', action)
|
144
|
+
return data['songs']
|
180
145
|
end
|
181
146
|
|
182
|
-
#
|
183
|
-
def djchannels(stype=0, offset=0, limit=
|
147
|
+
# DJ channels: hot today(0), week(10), history(20), new(30)
|
148
|
+
def djchannels(stype = 0, offset = 0, limit = 50)
|
184
149
|
action = "http://music.163.com/discover/djchannel?type=#{stype}&offset=#{offset}&limit=#{limit}"
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
return channel_detail(channelids.uniq)
|
190
|
-
rescue Exception => e
|
191
|
-
return []
|
192
|
-
end
|
150
|
+
connection = http_request('GET', action)
|
151
|
+
channelids = connection.scan(/\/dj\?id=(\d+)/) || []
|
152
|
+
return [] if channelids.empty?
|
153
|
+
return channel_detail(channelids.uniq)
|
193
154
|
end
|
194
155
|
|
195
156
|
# DJchannel (id, channel_name) ids -> song urls (details)
|
196
|
-
# channels
|
197
|
-
def channel_detail(channelids
|
157
|
+
# channels -> songs
|
158
|
+
def channel_detail(channelids)
|
198
159
|
channels = []
|
199
160
|
|
200
161
|
# ["xxxxxx"] -> "xxxxxx"
|
@@ -204,7 +165,7 @@ class NetEase
|
|
204
165
|
data = http_request('GET', action)
|
205
166
|
channel = dig_info(data['program']['mainSong'], 'channels')
|
206
167
|
channels.push(channel)
|
207
|
-
rescue
|
168
|
+
rescue => e
|
208
169
|
next
|
209
170
|
end
|
210
171
|
end
|
data/lib/mplug163/menu.rb
CHANGED
@@ -14,10 +14,10 @@ SHORTCUT = [
|
|
14
14
|
['f', 'Search ', '搜索'],
|
15
15
|
['m', 'Menu ', '主菜单'],
|
16
16
|
['p', 'Present ', '当前播放列表'],
|
17
|
-
['
|
18
|
-
['
|
19
|
-
['s', 'Star ', '收藏歌曲'],
|
17
|
+
['s', 'Star ', '收藏歌曲或精选歌单或专辑'],
|
18
|
+
['t', 'Playlist ', '收藏精选歌单'],
|
20
19
|
['c', 'Collection ', '收藏歌曲列表'],
|
20
|
+
['a', 'Album ', '收藏专辑'],
|
21
21
|
['r', 'Remove ', '删除当前曲目'],
|
22
22
|
['q', 'Quit ', '退出']
|
23
23
|
]
|
@@ -26,7 +26,7 @@ class Menu
|
|
26
26
|
def initialize
|
27
27
|
@datatype = 'main'
|
28
28
|
@title = '网易云音乐'
|
29
|
-
@datalist =
|
29
|
+
@datalist = %w(排行榜 艺术家 新碟上架 精选歌单 我的歌单 DJ节目 本地收藏 搜索 帮助)
|
30
30
|
@offset = 0
|
31
31
|
@index = 0
|
32
32
|
@present_songs = []
|
@@ -36,10 +36,10 @@ class Menu
|
|
36
36
|
@screen = @ui.screen
|
37
37
|
@step = 10
|
38
38
|
@stack = []
|
39
|
-
@djstack = []
|
40
39
|
@userid = nil
|
41
40
|
@username = nil
|
42
41
|
@collection = []
|
42
|
+
@playlists = []
|
43
43
|
@account = {}
|
44
44
|
|
45
45
|
@wait = 0.1
|
@@ -60,65 +60,69 @@ class Menu
|
|
60
60
|
idx = index = @index
|
61
61
|
step = @step
|
62
62
|
stack = @stack
|
63
|
-
djstack = @djstack
|
64
63
|
key = @screen.getch
|
65
64
|
@screen.refresh
|
66
65
|
|
67
66
|
case key
|
68
67
|
|
69
|
-
#
|
68
|
+
# Quit
|
70
69
|
when 'q'
|
71
70
|
break
|
72
71
|
|
73
|
-
#
|
72
|
+
# Up
|
74
73
|
when 'k'
|
75
74
|
@index = @carousel[@offset, [datalist.size, offset+step].min - 1, idx - 1]
|
76
75
|
|
77
|
-
#
|
76
|
+
# Down
|
78
77
|
when 'j'
|
79
78
|
@index = @carousel[@offset, [datalist.size, offset+step].min - 1, idx + 1]
|
80
79
|
|
81
|
-
#
|
80
|
+
# Previous page
|
82
81
|
when 'u'
|
83
82
|
next if offset == 0
|
84
83
|
@offset = @offset - step
|
85
84
|
@index = (index - step).divmod(step)[0] * step
|
86
85
|
|
87
|
-
#
|
86
|
+
# Next page
|
88
87
|
when 'd'
|
89
88
|
next if offset + step >= datalist.size
|
90
89
|
@offset = @offset + step
|
91
90
|
@index = (index + step).divmod(step)[0] * step
|
92
91
|
|
93
|
-
#
|
92
|
+
# Forward
|
94
93
|
when 'l'
|
95
|
-
next if @datatype == '
|
96
|
-
@
|
97
|
-
|
98
|
-
|
99
|
-
|
94
|
+
next if @datatype == 'help'
|
95
|
+
if @datatype == 'songs' || @datatype == 'djchannels'
|
96
|
+
@player.play(@datatype, datalist, @index, true)
|
97
|
+
sleep @wait
|
98
|
+
else
|
99
|
+
@ui.build_loading
|
100
|
+
dispatch_enter(idx)
|
101
|
+
@index = 0
|
102
|
+
@offset = 0
|
103
|
+
end
|
100
104
|
|
101
|
-
#
|
105
|
+
# Back
|
102
106
|
when 'h'
|
103
107
|
next if @stack.size == 1
|
104
108
|
up = stack.pop
|
105
109
|
@datatype, @title, @datalist, @offset, @index = up[0], up[1], up[2], up[3], up[4]
|
106
110
|
|
107
|
-
#
|
111
|
+
# Search
|
108
112
|
when 'f'
|
109
113
|
search
|
110
114
|
|
111
|
-
#
|
115
|
+
# Next song
|
112
116
|
when ']'
|
113
117
|
@player.next
|
114
118
|
sleep @wait
|
115
119
|
|
116
|
-
#
|
120
|
+
# Previous song
|
117
121
|
when '['
|
118
122
|
@player.prev
|
119
123
|
sleep @wait
|
120
124
|
|
121
|
-
#
|
125
|
+
# Play or pause a song.
|
122
126
|
when ' '
|
123
127
|
if datatype == 'songs'
|
124
128
|
@present_songs = ['songs', title, datalist, offset, index]
|
@@ -128,50 +132,59 @@ class Menu
|
|
128
132
|
@player.play(datatype, datalist, idx)
|
129
133
|
sleep @wait
|
130
134
|
|
131
|
-
#
|
135
|
+
# Load present playlist.
|
132
136
|
when 'p'
|
133
137
|
next if @present_songs.empty?
|
134
138
|
@stack.push([datatype, title, datalist, offset, index])
|
135
139
|
@datatype, @title, @datalist, @offset, @index = @present_songs[0], @present_songs[1], @present_songs[2], @present_songs[3], @present_songs[4]
|
136
140
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
+
|
142
|
+
# Star a song, a playlist or an album.
|
143
|
+
when 's'
|
144
|
+
next if datalist.empty?
|
145
|
+
if datatype == 'songs' || datatype == 'djchannels'
|
146
|
+
@collection.push(datalist[idx]).uniq!
|
147
|
+
elsif datatype == 'playlists'
|
148
|
+
@playlists.push(datalist[idx]).uniq!
|
149
|
+
elsif datatype == 'albums'
|
150
|
+
@albums.push(datalist[idx]).uniq!
|
141
151
|
end
|
142
152
|
|
143
|
-
#
|
144
|
-
when '
|
153
|
+
# Load favorite playlists.
|
154
|
+
when 't'
|
145
155
|
@stack.push([datatype, title, datalist, offset, index])
|
146
|
-
@datatype = '
|
147
|
-
@title = '网易云音乐 >
|
148
|
-
@datalist = @
|
156
|
+
@datatype = 'playlists'
|
157
|
+
@title = '网易云音乐 > 收藏精选歌单'
|
158
|
+
@datalist = @playlists
|
149
159
|
@offset = 0
|
150
160
|
@index = 0
|
151
161
|
|
152
|
-
#
|
153
|
-
when 's'
|
154
|
-
if (datatype == 'songs' || datatype == 'djchannels') && !datalist.empty?
|
155
|
-
@collection.push(datalist[idx]).uniq!
|
156
|
-
end
|
157
|
-
|
158
|
-
# 加载收藏歌曲
|
162
|
+
# Load favorite songs.
|
159
163
|
when 'c'
|
160
164
|
@stack.push([datatype, title, datalist, offset, index])
|
161
165
|
@datatype = 'songs'
|
162
|
-
@title = '网易云音乐 >
|
166
|
+
@title = '网易云音乐 > 收藏歌曲列表'
|
163
167
|
@datalist = @collection
|
164
168
|
@offset = 0
|
165
169
|
@index = 0
|
166
170
|
|
167
|
-
#
|
171
|
+
# Load favorite albums
|
172
|
+
when 'a'
|
173
|
+
@stack.push([datatype, title, datalist, offset, index])
|
174
|
+
@datatype = 'albums'
|
175
|
+
@title = '网易云音乐 > 收藏专辑'
|
176
|
+
@datalist = @albums
|
177
|
+
@offset = 0
|
178
|
+
@index = 0
|
179
|
+
|
180
|
+
# Remove an entry from the present list.
|
168
181
|
when 'r'
|
169
182
|
if (datatype != 'main') && !datalist.empty?
|
170
183
|
@datalist.delete_at(idx)
|
171
184
|
@index = @carousel[@offset, [datalist.size, offset+step].min - 1, idx]
|
172
185
|
end
|
173
186
|
|
174
|
-
#
|
187
|
+
# Main menu.
|
175
188
|
when 'm'
|
176
189
|
if datatype != 'main'
|
177
190
|
@stack.push([datatype, title, datalist, offset, index])
|
@@ -203,7 +216,7 @@ class Menu
|
|
203
216
|
when 'main'
|
204
217
|
choice_channel idx
|
205
218
|
|
206
|
-
#
|
219
|
+
# Hot songs to which a artist belongs.
|
207
220
|
when 'artists'
|
208
221
|
artist_id = datalist[idx]['artist_id']
|
209
222
|
songs = netease.artists(artist_id)
|
@@ -211,7 +224,7 @@ class Menu
|
|
211
224
|
@datalist = netease.dig_info(songs, 'songs')
|
212
225
|
@title += " > #{datalist[idx]['aritsts_name']}"
|
213
226
|
|
214
|
-
#
|
227
|
+
# All songs to which an album belongs.
|
215
228
|
when 'albums'
|
216
229
|
album_id = datalist[idx]['album_id']
|
217
230
|
songs = netease.album(album_id)
|
@@ -219,7 +232,7 @@ class Menu
|
|
219
232
|
@datalist = netease.dig_info(songs, 'songs')
|
220
233
|
@title += " > #{datalist[idx]['albums_name']}"
|
221
234
|
|
222
|
-
#
|
235
|
+
# All songs to which a playlist belongs.
|
223
236
|
when 'playlists'
|
224
237
|
playlist_id = datalist[idx]['playlist_id']
|
225
238
|
songs = netease.playlist_detail(playlist_id)
|
@@ -234,41 +247,39 @@ class Menu
|
|
234
247
|
|
235
248
|
case idx
|
236
249
|
|
237
|
-
#
|
250
|
+
# Top
|
238
251
|
when 0
|
239
252
|
songs = netease.top_songlist
|
240
253
|
@datalist = netease.dig_info(songs, 'songs')
|
241
254
|
@title += ' > 排行榜'
|
242
255
|
@datatype = 'songs'
|
243
256
|
|
244
|
-
#
|
257
|
+
# Artist
|
245
258
|
when 1
|
246
259
|
artists = netease.top_artists
|
247
260
|
@datalist = netease.dig_info(artists, 'artists')
|
248
261
|
@title += ' > 艺术家'
|
249
262
|
@datatype = 'artists'
|
250
263
|
|
251
|
-
#
|
264
|
+
# New album
|
252
265
|
when 2
|
253
266
|
albums = netease.new_albums
|
254
267
|
@datalist = netease.dig_info(albums, 'albums')
|
255
268
|
@title += ' > 新碟上架'
|
256
269
|
@datatype = 'albums'
|
257
270
|
|
258
|
-
#
|
271
|
+
# Playlists
|
259
272
|
when 3
|
260
273
|
playlists = netease.top_playlists
|
261
274
|
@datalist = netease.dig_info(playlists, 'playlists')
|
262
275
|
@title += ' > 精选歌单'
|
263
276
|
@datatype = 'playlists'
|
264
277
|
|
265
|
-
#
|
278
|
+
# My playlist
|
266
279
|
when 4
|
267
|
-
#
|
280
|
+
# Require user's account before fetching his playlists.
|
268
281
|
if !@userid
|
269
|
-
|
270
|
-
user_info = netease.login(@account[0], @account[1])
|
271
|
-
end
|
282
|
+
user_info = netease.login(@account[0], @account[1]) unless @account.empty?
|
272
283
|
|
273
284
|
if @account == {} || user_info['code'] != 200
|
274
285
|
data = @ui.build_login
|
@@ -280,36 +291,28 @@ class Menu
|
|
280
291
|
@userid = user_info['account']['id']
|
281
292
|
end
|
282
293
|
|
283
|
-
#
|
294
|
+
# Fetch this user's all playlists while he logs in successfully.
|
284
295
|
my_playlist = netease.user_playlists(@userid)
|
285
296
|
@datalist = netease.dig_info(my_playlist, 'playlists')
|
286
297
|
@datatype = 'playlists'
|
287
298
|
@title += " > #{@username} 的歌单"
|
288
299
|
|
289
|
-
# DJ
|
300
|
+
# DJ channels
|
290
301
|
when 5
|
291
302
|
@datatype = 'djchannels'
|
292
303
|
@title += ' > DJ节目'
|
293
304
|
@datalist = netease.djchannels
|
294
305
|
|
295
|
-
#
|
306
|
+
# Favorite things.
|
296
307
|
when 6
|
297
|
-
|
298
|
-
@title += ' > 打碟'
|
299
|
-
@datalist = @djstack
|
308
|
+
favorite
|
300
309
|
|
301
|
-
#
|
310
|
+
# Search
|
302
311
|
when 7
|
303
|
-
@datatype = 'songs'
|
304
|
-
@title += ' > 收藏'
|
305
|
-
@datalist = @collection
|
306
|
-
|
307
|
-
# 搜索
|
308
|
-
when 8
|
309
312
|
search
|
310
313
|
|
311
|
-
#
|
312
|
-
when
|
314
|
+
# Help
|
315
|
+
when 8
|
313
316
|
@datatype = 'help'
|
314
317
|
@title += ' > 帮助'
|
315
318
|
@datalist = SHORTCUT
|
@@ -319,11 +322,41 @@ class Menu
|
|
319
322
|
@index = 0
|
320
323
|
end
|
321
324
|
|
325
|
+
def favorite
|
326
|
+
ui = @ui
|
327
|
+
x = ui.build_favorite_menu
|
328
|
+
|
329
|
+
if (1..3).include? x.to_i
|
330
|
+
@stack.push([@datatype, @title, @datalist, @offset, @index])
|
331
|
+
@index = 0
|
332
|
+
@offset = 0
|
333
|
+
end
|
334
|
+
|
335
|
+
case x
|
336
|
+
|
337
|
+
when '1'
|
338
|
+
@datatype = 'songs'
|
339
|
+
@datalist = @collection
|
340
|
+
@title += ' > 收藏歌曲'
|
341
|
+
|
342
|
+
when '2'
|
343
|
+
@datatype = 'playlists'
|
344
|
+
@datalist = @playlists
|
345
|
+
@title += ' > 收藏歌单'
|
346
|
+
|
347
|
+
when '3'
|
348
|
+
@datatype = 'albums'
|
349
|
+
@datalist = @albums
|
350
|
+
@title += ' > 收藏专辑'
|
351
|
+
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
322
355
|
def search
|
323
356
|
ui = @ui
|
324
357
|
x = ui.build_search_menu
|
325
358
|
|
326
|
-
if (1
|
359
|
+
if (1..4).include? x.to_i
|
327
360
|
@stack.push([@datatype, @title, @datalist, @offset, @index])
|
328
361
|
@index = 0
|
329
362
|
@offset = 0
|
@@ -356,30 +389,28 @@ class Menu
|
|
356
389
|
private
|
357
390
|
|
358
391
|
def check_mplug163_dir
|
359
|
-
Dir.mkdir File.expand_path("~/.mplug163") unless Dir.
|
360
|
-
|
392
|
+
Dir.mkdir File.expand_path("~/.mplug163") unless Dir.exist? File.expand_path("~/.mplug163")
|
361
393
|
end
|
362
394
|
|
363
395
|
def read_data
|
364
396
|
check_mplug163_dir
|
365
397
|
user_file = File.expand_path("~/.mplug163/flavor.json")
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
@account = {}
|
374
|
-
end
|
375
|
-
end
|
398
|
+
return unless File.exist? user_file
|
399
|
+
|
400
|
+
data = JSON.parse(File.read(user_file))
|
401
|
+
@account = data['account'] || {}
|
402
|
+
@collection = data['collection'] || []
|
403
|
+
@playlists = data['playlists'] || []
|
404
|
+
@albums = data['albums'] || []
|
376
405
|
end
|
377
406
|
|
378
407
|
def write_data
|
379
408
|
user_file = File.expand_path("~/.mplug163/flavor.json")
|
380
409
|
data = {
|
381
410
|
:account => @account,
|
382
|
-
:collection => @collection
|
411
|
+
:collection => @collection,
|
412
|
+
:playlists => @playlists,
|
413
|
+
:albums => @albums
|
383
414
|
}
|
384
415
|
|
385
416
|
File.open(user_file, 'w') do |f|
|
data/lib/mplug163/player.rb
CHANGED
@@ -19,36 +19,36 @@ class Player
|
|
19
19
|
@pause_flag = false
|
20
20
|
|
21
21
|
item = @songs[@idx]
|
22
|
-
@ui.build_playinfo(item['song_name'], item['artist']
|
22
|
+
@ui.build_playinfo(item['song_name'], item['artist'])
|
23
23
|
|
24
24
|
@thread = Thread.new do
|
25
25
|
@mp3id, stdin, stdout, stderr = Open4::popen4('mpg123', item['mp3_url'])
|
26
26
|
Process::waitpid2 @mp3id
|
27
27
|
|
28
28
|
if @playing_flag
|
29
|
-
@idx = @carousel[0, @songs.size-1, @idx+1]
|
29
|
+
@idx = @carousel[0, @songs.size - 1, @idx + 1]
|
30
30
|
recall
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
def play(datatype, songs, idx)
|
35
|
+
def play(datatype, songs, idx, switch_flag = false)
|
36
36
|
@datatype = datatype
|
37
37
|
|
38
38
|
if datatype == 'songs' || datatype == 'djchannels'
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
39
|
+
|
40
|
+
if !switch_flag
|
41
|
+
@pause_flag ? resume : pause if @songs == songs
|
42
|
+
elsif switch_flag
|
43
|
+
@songs = songs
|
44
|
+
@idx = idx
|
46
45
|
@playing_flag ? switch : recall
|
47
46
|
end
|
47
|
+
|
48
48
|
else
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
|
50
|
+
@pause_flag ? resume : pause if @playing_flag
|
51
|
+
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
@@ -59,41 +59,47 @@ class Player
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def stop
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
62
|
+
return unless @playing_flag
|
63
|
+
return unless @thread
|
64
|
+
return unless @mp3id
|
65
|
+
|
66
|
+
@playing_flag = false
|
67
|
+
# kill this process and thread
|
68
|
+
Process.kill(:SIGKILL, @mp3id)
|
69
|
+
Thread.kill @thread
|
68
70
|
end
|
69
71
|
|
70
72
|
def pause
|
71
73
|
@pause_flag = true
|
72
74
|
# send SIGSTOP to pipe
|
73
75
|
Process.kill(:SIGSTOP, @mp3id)
|
76
|
+
|
74
77
|
item = @songs[@idx]
|
75
|
-
@ui.build_playinfo(item['song_name'], item['artist'],
|
78
|
+
@ui.build_playinfo(item['song_name'], item['artist'], true)
|
76
79
|
end
|
77
80
|
|
78
81
|
def resume
|
79
82
|
@pause_flag = false
|
80
83
|
# send SIGCONT to pipe
|
81
84
|
Process.kill(:SIGCONT, @mp3id)
|
85
|
+
|
82
86
|
item = @songs[@idx]
|
83
|
-
@ui.build_playinfo(item['song_name'], item['artist']
|
87
|
+
@ui.build_playinfo(item['song_name'], item['artist'])
|
84
88
|
end
|
85
89
|
|
86
90
|
def next
|
87
91
|
stop
|
88
92
|
sleep @wait
|
89
|
-
|
93
|
+
|
94
|
+
@idx = @carousel[0, @songs.size - 1, @idx + 1]
|
90
95
|
recall
|
91
96
|
end
|
92
97
|
|
93
98
|
def prev
|
94
99
|
stop
|
95
100
|
sleep @wait
|
96
|
-
|
101
|
+
|
102
|
+
@idx = @carousel[0, @songs.size - 1, @idx - 1]
|
97
103
|
recall
|
98
104
|
end
|
99
105
|
end
|
data/lib/mplug163/ui.rb
CHANGED
@@ -59,7 +59,7 @@ class Ui
|
|
59
59
|
@netease = NetEase.new
|
60
60
|
end
|
61
61
|
|
62
|
-
def build_playinfo(song_name, artist,
|
62
|
+
def build_playinfo(song_name, artist, pause = false)
|
63
63
|
if pause
|
64
64
|
putstr(@screen, PLAYER_STATUS_Y, PLAYER_NOTE_X, '■', Curses.color_pair(3))
|
65
65
|
else
|
@@ -79,6 +79,8 @@ class Ui
|
|
79
79
|
end
|
80
80
|
|
81
81
|
def build_menu(datatype, title, datalist, offset, index, step)
|
82
|
+
title = pretty_format(title, 0, 52)
|
83
|
+
|
82
84
|
clear_to_bottom(@screen, PLAYER_CONTENT_Y, SCREEN_HEIGHT)
|
83
85
|
putstr(@screen, PLAYER_TITLE_Y, PLAYER_X, title, Curses.color_pair(1))
|
84
86
|
|
@@ -87,7 +89,7 @@ class Ui
|
|
87
89
|
else
|
88
90
|
case datatype
|
89
91
|
when 'main'
|
90
|
-
(offset...[datalist.length, offset+step].min).each do |i|
|
92
|
+
(offset...[datalist.length, offset + step].min).each do |i|
|
91
93
|
if i == index
|
92
94
|
line_info = "♩ #{i}. #{datalist[i]}"
|
93
95
|
putstr(@screen, i-offset+PLAYER_CONTENT_Y, PLAYER_POINTER_X, line_info, Curses.color_pair(2))
|
@@ -100,7 +102,7 @@ class Ui
|
|
100
102
|
putstr(@screen, PLAYER_INFO_Y, PLAYER_X, 'Crafted with ❤ by Ripple Yui', Curses.color_pair(3))
|
101
103
|
|
102
104
|
when 'songs'
|
103
|
-
(offset...[datalist.length, offset+step].min).each do |i|
|
105
|
+
(offset...[datalist.length, offset + step].min).each do |i|
|
104
106
|
if i == index
|
105
107
|
info = "♩ #{i}. #{datalist[i]['song_name']} - #{datalist[i]['artist']} - #{datalist[i]['album_name']}"
|
106
108
|
line_info = pretty_format(info, 0, 52)
|
@@ -113,7 +115,7 @@ class Ui
|
|
113
115
|
end
|
114
116
|
|
115
117
|
when 'artists'
|
116
|
-
(offset...[datalist.length, offset+step].min).each do |i|
|
118
|
+
(offset...[datalist.length, offset + step].min).each do |i|
|
117
119
|
if i == index
|
118
120
|
line_info = "♩ #{i}. #{datalist[i]['artists_name']} - #{datalist[i]['artist']} #{datalist[i]['alias']}"
|
119
121
|
putstr(@screen, i-offset+PLAYER_CONTENT_Y, PLAYER_POINTER_X, line_info, Curses.color_pair(2))
|
@@ -124,40 +126,46 @@ class Ui
|
|
124
126
|
end
|
125
127
|
|
126
128
|
when 'albums'
|
127
|
-
(offset...[datalist.length, offset+step].min).each do |i|
|
129
|
+
(offset...[datalist.length, offset + step].min).each do |i|
|
128
130
|
if i == index
|
129
|
-
|
131
|
+
info = "♩ #{i}. #{datalist[i]['albums_name']} - #{datalist[i]['artists_name']}"
|
132
|
+
line_info = pretty_format(info, 0, 52)
|
130
133
|
putstr(@screen, i-offset+PLAYER_CONTENT_Y, PLAYER_POINTER_X, line_info, Curses.color_pair(2))
|
131
134
|
else
|
132
|
-
|
135
|
+
info = "#{i}. #{datalist[i]['albums_name']} - #{datalist[i]['artists_name']}"
|
136
|
+
line_info = pretty_format(info, 0, 50)
|
133
137
|
putstr(@screen, i-offset+PLAYER_CONTENT_Y, PLAYER_X, line_info)
|
134
138
|
end
|
135
139
|
end
|
136
140
|
|
137
141
|
when 'playlists'
|
138
|
-
(offset...[datalist.length, offset+step].min).each do |i|
|
142
|
+
(offset...[datalist.length, offset + step].min).each do |i|
|
139
143
|
if i == index
|
140
|
-
|
144
|
+
info = "♩ #{i}. #{datalist[i]['playlists_name']} - #{datalist[i]['creator_name']}"
|
145
|
+
line_info = pretty_format(info, 0, 52)
|
141
146
|
putstr(@screen, i-offset+PLAYER_CONTENT_Y, PLAYER_POINTER_X, line_info, Curses.color_pair(2))
|
142
147
|
else
|
143
|
-
|
148
|
+
info = "#{i}. #{datalist[i]['playlists_name']} - #{datalist[i]['creator_name']}"
|
149
|
+
line_info = pretty_format(info, 0, 50)
|
144
150
|
putstr(@screen, i-offset+PLAYER_CONTENT_Y, PLAYER_X, line_info)
|
145
151
|
end
|
146
152
|
end
|
147
153
|
|
148
154
|
when 'djchannels'
|
149
|
-
(offset...[datalist.length, offset+step].min).each do |i|
|
155
|
+
(offset...[datalist.length, offset + step].min).each do |i|
|
150
156
|
if i == index
|
151
|
-
|
157
|
+
info = "♩ #{i}. #{datalist[i][0]['song_name']}"
|
158
|
+
line_info = pretty_format(info, 0, 52)
|
152
159
|
putstr(@screen, i-offset+PLAYER_CONTENT_Y, PLAYER_POINTER_X, line_info, Curses.color_pair(2))
|
153
160
|
else
|
154
|
-
|
161
|
+
info = "#{i}. #{datalist[i][0]['song_name']}"
|
162
|
+
line_info = pretty_format(info, 0, 50)
|
155
163
|
putstr(@screen, i-offset+PLAYER_CONTENT_Y, PLAYER_X, line_info)
|
156
164
|
end
|
157
165
|
end
|
158
166
|
|
159
167
|
when 'help'
|
160
|
-
(offset...[datalist.length, offset+step].min).each do |i|
|
168
|
+
(offset...[datalist.length, offset + step].min).each do |i|
|
161
169
|
line_info = "#{i}. #{datalist[i][0]} #{datalist[i][1]} #{datalist[i][2]}"
|
162
170
|
putstr(@screen, i-offset+PLAYER_CONTENT_Y, PLAYER_X, line_info)
|
163
171
|
end
|
@@ -170,62 +178,58 @@ class Ui
|
|
170
178
|
case stype
|
171
179
|
when 'songs'
|
172
180
|
song_name = get_param('搜索歌曲:')
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
if data['result'].include? '
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
song_ids.push data['result']['songs'][i]['id']
|
182
|
-
end
|
183
|
-
songs = @netease.songs_detail(song_ids)
|
181
|
+
data = @netease.search(song_name, stype = 1)
|
182
|
+
song_ids = []
|
183
|
+
if data['result'].include? 'songs'
|
184
|
+
if data['result']['songs'].include? 'mp3Url'
|
185
|
+
songs = data['result']['songs']
|
186
|
+
else
|
187
|
+
(0...data['result']['songs'].size).each do |i|
|
188
|
+
song_ids.push data['result']['songs'][i]['id']
|
184
189
|
end
|
185
|
-
|
190
|
+
songs = @netease.songs_detail(song_ids)
|
186
191
|
end
|
187
|
-
|
188
|
-
return []
|
192
|
+
return @netease.dig_info(songs, 'songs')
|
189
193
|
end
|
190
194
|
|
191
195
|
when 'artists'
|
192
196
|
artist_name = get_param('搜索艺术家:')
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
return @netease.dig_info(artists, 'artists')
|
198
|
-
end
|
199
|
-
rescue Exception => e
|
200
|
-
return []
|
197
|
+
data = @netease.search(artist_name, stype = 100)
|
198
|
+
if data['result'].include? 'artists'
|
199
|
+
artists = data['result']['artists']
|
200
|
+
return @netease.dig_info(artists, 'artists')
|
201
201
|
end
|
202
202
|
|
203
203
|
when 'albums'
|
204
204
|
artist_name = get_param('搜索专辑:')
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
return @netease.dig_info(albums, 'albums')
|
210
|
-
end
|
211
|
-
rescue Exception => e
|
212
|
-
return []
|
205
|
+
data = @netease.search(artist_name, stype = 10)
|
206
|
+
if data['result'].include? 'albums'
|
207
|
+
albums = data['result']['albums']
|
208
|
+
return @netease.dig_info(albums, 'albums')
|
213
209
|
end
|
214
210
|
|
215
211
|
when 'playlists'
|
216
212
|
artist_name = get_param('搜索网易精选集:')
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
return @netease.dig_info(playlists, 'playlists')
|
222
|
-
end
|
223
|
-
rescue Exception => e
|
224
|
-
return []
|
213
|
+
data = @netease.search(artist_name, stype = 1000)
|
214
|
+
if data['result'].include? 'playlists'
|
215
|
+
playlists = data['result']['playlists']
|
216
|
+
return @netease.dig_info(playlists, 'playlists')
|
225
217
|
end
|
218
|
+
|
226
219
|
end
|
227
220
|
end
|
228
221
|
|
222
|
+
def build_favorite_menu
|
223
|
+
clear_to_bottom(@screen, PLAYER_CONTENT_Y, SCREEN_HEIGHT)
|
224
|
+
putstr(@screen, PLAYER_CONTENT_Y, PLAYER_X, '选择收藏条目类型:', Curses.color_pair(1))
|
225
|
+
putstr(@screen, PLAYER_CONTENT_Y + 1, PLAYER_X, '[1] 歌曲')
|
226
|
+
putstr(@screen, PLAYER_CONTENT_Y + 2, PLAYER_X, '[2] 精选歌单')
|
227
|
+
putstr(@screen, PLAYER_CONTENT_Y + 3, PLAYER_X, '[3] 专辑')
|
228
|
+
putstr(@screen, PLAYER_CONTENT_Y + 6, PLAYER_X, '请键入对应数字:', Curses.color_pair(2))
|
229
|
+
@screen.refresh
|
230
|
+
@screen.getch
|
231
|
+
end
|
232
|
+
|
229
233
|
def build_search_menu
|
230
234
|
clear_to_bottom(@screen, PLAYER_CONTENT_Y, SCREEN_HEIGHT)
|
231
235
|
putstr(@screen, PLAYER_CONTENT_Y, PLAYER_X, '选择搜索类型:', Curses.color_pair(1))
|
@@ -235,7 +239,7 @@ class Ui
|
|
235
239
|
putstr(@screen, PLAYER_CONTENT_Y + 4, PLAYER_X, '[4] 网易精选集')
|
236
240
|
putstr(@screen, PLAYER_CONTENT_Y + 6, PLAYER_X, '请键入对应数字:', Curses.color_pair(2))
|
237
241
|
@screen.refresh
|
238
|
-
|
242
|
+
@screen.getch
|
239
243
|
end
|
240
244
|
|
241
245
|
def build_login
|
@@ -259,7 +263,7 @@ class Ui
|
|
259
263
|
putstr(@screen, PLAYER_CONTENT_Y + 3, PLAYER_X, '[2] 稍后再试')
|
260
264
|
putstr(@screen, PLAYER_CONTENT_Y + 5, PLAYER_X, '请键入对应数字:', Curses.color_pair(2))
|
261
265
|
@screen.refresh
|
262
|
-
|
266
|
+
@screen.getch
|
263
267
|
end
|
264
268
|
|
265
269
|
def get_param(prompt_str)
|
@@ -267,7 +271,7 @@ class Ui
|
|
267
271
|
putstr(@screen, PLAYER_CONTENT_Y, PLAYER_X, prompt_str, Curses.color_pair(1))
|
268
272
|
@screen.setpos(PLAYER_CONTENT_Y + 2, PLAYER_X)
|
269
273
|
params = @screen.getstr
|
270
|
-
if params.strip
|
274
|
+
if params.strip.nil?
|
271
275
|
return get_param(prompt_str)
|
272
276
|
else
|
273
277
|
return params
|
@@ -276,7 +280,7 @@ class Ui
|
|
276
280
|
|
277
281
|
private
|
278
282
|
|
279
|
-
def putstr(screen, y, x, string, color=Curses.color_pair(0))
|
283
|
+
def putstr(screen, y, x, string, color = Curses.color_pair(0))
|
280
284
|
screen.setpos(y, x)
|
281
285
|
screen.clrtoeol
|
282
286
|
screen.attrset(color)
|
data/lib/mplug163/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mplug163
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ripple Yui
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-09-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|