-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathmusic.py
334 lines (293 loc) · 12.8 KB
/
music.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
import re, os, subprocess, random, threading, time, hashlib
import requests
from config import MUSIC_PATH
from speech import baidu_tts
class MusicMiddleware(object):
def __init__(self):
self.music_list = []
self.player_handler = None
self.playing = 0;
self.current_list = []
self.current_index = 0
self.shuffle = False
self.loop = False
self.exit = False
self.load_music()
def handle(self, context):
text = re.compile(r",|\?|\.|、|,|?|。").sub("", context)
print('音乐:', text)
if text in ['播放下一曲', '播放下一个', '播放下个', '播放下一首']: return self.quit_play()
if text in ['播放上一曲', '播放上一个', '播放上个', '播放上一首']:
self.current_index = self.current_index - 2
return self.quit_play()
if text in ['关闭音乐', '关掉音乐', '关音乐']: return self.close_music()
if music.playing == 2:
music.continue_play();
time.sleep(0.5)
if text in ['快进', '向前进']: return self.forward()
if text in ['后退', '向后退']: return self.backward()
if text in ['加大音量', '增加音量', '上调音量', '声音太小了']: return self.inc_volume()
if text in ['减小音量', '减少音量', '降低音量', '声音太大了']: return self.dec_volume()
if text in ['暂停音乐', '暂停播放', '音乐暂停'] and self.playing == 1: return self.pause_play()
if music.playing == 0:
if text in ['随机播放音乐', '随机播放', '随机听歌', '随机音乐']: return self.play_music(shuffle=True)
if text in ['继续播放', '继续播放音乐']: return self.continue_play()
if text in ['播放音乐', '音乐播放', '打开音乐', '音乐走起', '好想听歌', '我要听音乐', '我要听歌', '音乐嗨起来', '嗨起来']: return self.play_music()
search = self.re_searchs(text, [r'我要听(.*?)的(.*)', r'播放(.*?)的(.*)'])
if search: return self.play_music(name=search[1], singer=search[0])
search = self.re_searchs(text, [r'我要听(.*)', r'播放(.*)', r'打开(.*?)音乐', r'打开音乐(.*)'])
if search: return self.play_music(name=search)
search = self.re_searchs(text, [r'循环播放(.*)'])
if search: return self.play_music(name=search, loop=True)
search = self.re_searchs(text, [r'搜索(.*?)歌曲', r'搜索(.*?)音乐', r'查找(.*?)音乐', r'搜索歌曲(.*)', r'搜索音乐(.*)'])
if search: return self.search_music(search)
search = self.re_searchs(text, [r'下载(.*?)歌曲', r'下载(.*?)音乐', r'下载音乐(.*)'])
if search: return self.down_music(search)
return True
def re_searchs(self, text, list):
for key in list:
results = re.findall(key, text, re.M|re.I)
if results and results[0] and len(results) > 1 and results[1]:
return [results[0], results[1]]
if results and results[0]: return results[0]
return False
def pause_play(self):
if self.playing:
self.playing = 2
self.player_handler.stdin.write(b'p')
self.player_handler.stdin.flush()
return False
def continue_play(self):
if self.playing:
self.playing = 1
self.player_handler.stdin.write(b'c')
self.player_handler.stdin.flush()
return False
def inc_volume(self):
if self.playing:
self.player_handler.stdin.write(b'*')
self.player_handler.stdin.flush()
return False
def dec_volume(self):
if self.playing:
self.player_handler.stdin.write(b'/')
self.player_handler.stdin.flush()
return False
def backward(self):
if self.playing:
self.player_handler.stdin.write(b'<-')
self.player_handler.stdin.flush()
return False
def forward(self):
if self.playing:
self.player_handler.stdin.write(b'->')
self.player_handler.stdin.flush()
return False
def play_music(self, name = None, singer = None, shuffle = False, loop = False):
if self.playing: return False
self.exit = False
print(name, singer, shuffle, loop)
self.shuffle = shuffle
self.loop = loop
list = {}; count = 0;
#播放全部
if not name and not singer:
for item in self.music_list:
list[item['name']] = item['file']
else:
if name and singer:
new = "%s-%s"%(singer, name)
for item in self.music_list:
if re.search(new, item['name'], re.M|re.I):
list[item['name']] = item['file']
print('查找到:', item)
else:
if name:
name = re.compile(r"的音乐|音乐").sub("", name)
print('查找name:', name)
for item in self.music_list:
if re.search(name, item['name'], re.M|re.I):
list[item['name']] = item['file']
print('查找到:', item)
if singer:
singer = re.compile(r"的音乐|音乐").sub("", singer)
print('查找singer:', singer)
for item in self.music_list:
if re.search(singer, item['name'], re.M|re.I):
list[item['name']] = item['file']
print('查找到:', item)
if len(list) > 0:
self.current_list.clear()
for item in list:
file = list[item]
self.current_list.append(file)
if shuffle: random.shuffle(self.current_list)
self.current_index = 0
self.play_next()
else:
text = ''
if singer: text = text + singer
if name: text = text + name
self.down_music(text)
return False
def play_next(self):
thread = threading.Thread(target=self.mplayer, name="mplayer")
thread.setDaemon(True)
thread.start()
def mplayer(self):
if (self.current_index < 0 or self.exit): return
if (self.current_index >= len(self.current_list)):
if self.loop:
print('循环播放!')
if self.shuffle: random.shuffle(self.current_list)
self.current_index = 0
return self.play_next()
print('播放结束!')
self.playing = 0
self.current_list.clear()
self.current_index = 0
return
file = self.current_list[self.current_index]
print('播放音乐:', file)
self.player_handler = subprocess.Popen(["mplayer", file], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
self.playing = 1
while True:
if self.exit: break
strout = self.player_handler.stdout.readline()
#print(strout)
if strout == b'Exiting... (End of file)\n' or strout == b'Exiting... (Quit)\n':
self.playing = 0
break
self.current_index = self.current_index + 1
self.play_next()
def quit_play(self):
if self.playing:
self.player_handler.stdin.write(b'q')
self.player_handler.stdin.flush()
return False
def close_music(self):
self.exit = True
self.playing = 0
self.current_list.clear()
self.current_index = 0
self.player_handler.stdin.write(b'q')
self.player_handler.stdin.flush()
time.sleep(0.5)
self.player_handler.kill()
time.sleep(0.5)
subprocess.run("killall mplayer", shell=True)
return False
def add_music(self, name, extension, fullfile):
self.music_list.append({ 'name': name, 'ext': extension, 'file': fullfile })
def load_music_file(self, path):
for i in os.listdir(path):
filepath = os.path.join(path, i)
if os.path.isdir(filepath):
self.load_music_file(filepath)
else:
fullfile = os.path.join(path, i)
filepath, filename = os.path.split(fullfile)
name, extension = os.path.splitext(filename)
if extension in ['.mp3', '.flac', '.wav', '.m4a']:
self.add_music(name, extension, fullfile)
def load_music(self):
if (not os.path.exists(MUSIC_PATH)): os.mkdir(MUSIC_PATH)
self.load_music_file(MUSIC_PATH)
print('共加载', len(self.music_list), '首音乐!')
if len(self.music_list) == 0: self.play_text('您还没有音乐,可以通过搜索和下载指令获得您需要的音乐,如:搜索绿色音乐 和 下载绿色音乐');
else: self.play_text('您有 %s 首音乐,可以通过播放音乐指令播放'%len(self.music_list));
def search_request(self, keyword, top):
params = {"w": keyword, "format": "json", "p": 1, "n": top}
session = requests.Session()
session.headers.update({"referer": "http://m.y.qq.com", "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"})
resp = session.get("http://c.y.qq.com/soso/fcgi-bin/search_for_qq_cp", params=params, timeout=7)
if resp.status_code != requests.codes.ok or not resp.text: return False
list = resp.json().get("data", {}).get("song", {}).get("list", [])
results = []
for item in list:
singers = [s.get("name", "") for s in item.get("singer", "")]
title = item.get("songname", "")
singer = "、".join(singers)
mid = item.get("songmid", "")
size = round(item.get("size128", 0) / 1048576, 2)
if size > 0: results.append({'mid': mid, 'singer': singer, 'title': title, 'size': size})
return results
def play_text(self, text):
if not os.path.exists('tts-wav/'): os.mkdir('tts-wav/')
filename = 'tts-wav/%s.mp3'%hashlib.md5(text.encode()).hexdigest()
if not os.path.exists(filename): baidu_tts(text, filename)
if self.playing == 1 and text: self.pause_play();
time.sleep(0.5)
subprocess.run(["mplayer", filename])
time.sleep(0.5)
if self.playing == 2 and text: self.continue_play();
return False
def search_music(self, keyword, top=3):
list = self.search_request(keyword, top)
if len(list) > 0:
text = '搜索到%s个结果:'%len(list)
for item in list:
text = text + item['singer'] + ',的,' + item['title'] + '、、'
else:
text = '没有搜索到:%s'%keyword
self.play_text(text)
return False
def down_qq_music(self, mid, filename, size):
guid = str(random.randrange(1000000000, 10000000000))
params = { "guid": guid, "loginUin": "3051522991", "format": "json", "platform": "yqq", "cid": "205361747", "uin": "3051522991", "songmid": mid, "needNewCode": 0}
rate_list = [("A000", "ape", 800), ("F000", "flac", 800), ("M800", "mp3", 320), ("C400", "m4a", 128), ("M500", "mp3", 128)]
session = requests.Session()
session.headers.update({"referer": "http://y.qq.com"})
url = ''; ext = '';
for rate in rate_list:
params["filename"] = "%s%s.%s" % (rate[0], mid, rate[1])
resp = session.get("https://c.y.qq.com/base/fcgi-bin/fcg_music_express_mobile3.fcg", params=params, timeout=7)
vkey = resp.json().get("data", {}).get("items", [])[0].get("vkey", "")
if vkey:
url = ("http://dl.stream.qqmusic.qq.com/%s?vkey=%s&guid=%s&uin=3051522991&fromtag=64"%(params["filename"], vkey, guid))
ext = rate[1]
break
if len(url) == 0 or len(ext) == 0: return False
session.headers.update({"referer": "http://m.y.qq.com", "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"})
res = session.get(url)
file = '{}/{}.{}'.format(MUSIC_PATH, filename, ext)
with open(file, 'wb') as f:
f.write(res.content)
fsize = os.path.getsize(file)
if fsize < 10 * 1024:
os.remove(file)
return False
return True
def down_music(self, keyword, top=1):
list = self.search_request(keyword, top)
if len(list) == 0: return self.play_text('没有找到您要的音乐!')
flag = False
for item in list:
filename = '%s-%s'%(item['singer'], item['title'])
text = '%s,的,%s'%(item['singer'], item['title'])
result = self.down_qq_music(item['mid'], filename, item['size'])
if result:
flag = True
self.play_text('%s 下载完成!'%text)
if flag:
self.music_list.clear();
self.load_music()
return False
music = MusicMiddleware()
if __name__ == "__main__":
search = music.re_searchs('播放陈雪凝的绿色', [r'播放(.*?)的(.*)'])
print(search[1], search[0])
#music.search_music("风筝误");
#music.down_music("风筝误");
#music.handle("播放风筝误");
#music.handle("我要听风筝误");
#music.handle("我要听大壮的我们不一样");
#music.handle("播放大壮的音乐");
#music.handle("播放刘德华的音乐");
#music.handle("你好");
#排行榜分类https://c.y.qq.com/v8/fcg-bin/fcg_v8_toplist_opt.fcg?page=index&format=html&tpl=macv4&v8debug=1&jsonCallback=jsonCallback
#最新音乐https://c.y.qq.com/v8/fcg-bin/fcg_v8_toplist_cp.fcg?g_tk=5381&uin=0&format=json&inCharset=utf-8&outCharset=utf-8¬ice=0&platform=h5&needNewCode=1&tpl=3&page=detail&type=top&topid=27&_=1519963122923
#推荐音乐https://c.y.qq.com/v8/fcg-bin/fcg_v8_toplist_cp.fcg?g_tk=5381&uin=0&format=json&inCharset=utf-8&outCharset=utf-8¬ice=0&platform=h5&needNewCode=1&tpl=3&page=detail&type=top&topid=36&_=1520777874472
#歌词https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg?callback=MusicJsonCallback_lrc&pcachetime=1494070301711&songmid=songmid&g_tk=5381&jsonpCallback=MusicJsonCallback_lrc&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8%C2%ACice=0&platform=yqq&needNewCode=0
#网络音乐排行榜https://c.y.qq.com/v8/fcg-bin/fcg_v8_toplist_cp.fcg?g_tk=5381&uin=0&format=json&inCharset=utf-8&outCharset=utf-8¬ice=0&platform=h5&needNewCode=1&tpl=3&page=detail&type=top&topid=28&_=1519963122923
#热词https://c.y.qq.com/splcloud/fcgi-bin/gethotkey.fcg?g_tk=5381&jsonpCallback=hotSearchKeysmod_top_search&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0