fuo-qqmusic 1.0.2__tar.gz → 1.0.4__tar.gz
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.
Potentially problematic release.
This version of fuo-qqmusic might be problematic. Click here for more details.
- {fuo_qqmusic-1.0.2 → fuo_qqmusic-1.0.4}/PKG-INFO +1 -1
- {fuo_qqmusic-1.0.2 → fuo_qqmusic-1.0.4}/README.md +7 -0
- {fuo_qqmusic-1.0.2 → fuo_qqmusic-1.0.4}/fuo_qqmusic/api.py +41 -5
- {fuo_qqmusic-1.0.2 → fuo_qqmusic-1.0.4}/fuo_qqmusic/provider.py +61 -1
- {fuo_qqmusic-1.0.2 → fuo_qqmusic-1.0.4}/fuo_qqmusic.egg-info/PKG-INFO +1 -1
- {fuo_qqmusic-1.0.2 → fuo_qqmusic-1.0.4}/fuo_qqmusic.egg-info/requires.txt +1 -1
- {fuo_qqmusic-1.0.2 → fuo_qqmusic-1.0.4}/setup.py +2 -2
- {fuo_qqmusic-1.0.2 → fuo_qqmusic-1.0.4}/fuo_qqmusic/__init__.py +0 -0
- {fuo_qqmusic-1.0.2 → fuo_qqmusic-1.0.4}/fuo_qqmusic/assets/icon.svg +0 -0
- {fuo_qqmusic-1.0.2 → fuo_qqmusic-1.0.4}/fuo_qqmusic/consts.py +0 -0
- {fuo_qqmusic-1.0.2 → fuo_qqmusic-1.0.4}/fuo_qqmusic/excs.py +0 -0
- {fuo_qqmusic-1.0.2 → fuo_qqmusic-1.0.4}/fuo_qqmusic/provider_ui.py +0 -0
- {fuo_qqmusic-1.0.2 → fuo_qqmusic-1.0.4}/fuo_qqmusic/schemas.py +0 -0
- {fuo_qqmusic-1.0.2 → fuo_qqmusic-1.0.4}/fuo_qqmusic.egg-info/SOURCES.txt +0 -0
- {fuo_qqmusic-1.0.2 → fuo_qqmusic-1.0.4}/fuo_qqmusic.egg-info/dependency_links.txt +0 -0
- {fuo_qqmusic-1.0.2 → fuo_qqmusic-1.0.4}/fuo_qqmusic.egg-info/entry_points.txt +0 -0
- {fuo_qqmusic-1.0.2 → fuo_qqmusic-1.0.4}/fuo_qqmusic.egg-info/top_level.txt +0 -0
- {fuo_qqmusic-1.0.2 → fuo_qqmusic-1.0.4}/setup.cfg +0 -0
|
@@ -20,6 +20,13 @@ pip3 install fuo-qqmusic
|
|
|
20
20
|
[操作示例](https://github.com/feeluown/feeluown-qqmusic/issues/6)。
|
|
21
21
|
|
|
22
22
|
## changelog
|
|
23
|
+
### 1.0.4 (2024-05-21)
|
|
24
|
+
- 歌手歌曲排序切换为”按热度排序”
|
|
25
|
+
- 修复推荐歌单接口
|
|
26
|
+
|
|
27
|
+
### 1.0.3 (2024-04-21)
|
|
28
|
+
- 适配 feeluown 4.1.3 的新主页功能
|
|
29
|
+
|
|
23
30
|
### 1.0.2 (2024-03-04)
|
|
24
31
|
- 修复获取歌单封面失败的问题 #21
|
|
25
32
|
- 修复获取歌曲播放链接失败的问题 #20
|
|
@@ -177,6 +177,25 @@ class API(object):
|
|
|
177
177
|
return None
|
|
178
178
|
return data_song
|
|
179
179
|
|
|
180
|
+
def batch_song_details(self, song_ids):
|
|
181
|
+
"""
|
|
182
|
+
song_ids should be a list of int
|
|
183
|
+
"""
|
|
184
|
+
payload = {
|
|
185
|
+
'comm': self.get_wkv17_common_params(),
|
|
186
|
+
'req_0': {
|
|
187
|
+
'module': 'music.trackInfo.UniformRuleCtrl',
|
|
188
|
+
'method': 'CgiGetTrackInfo',
|
|
189
|
+
'param': {
|
|
190
|
+
'ids': song_ids,
|
|
191
|
+
'types': [200]*len(song_ids),
|
|
192
|
+
'source': 'AiNoFree',
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
js = self.rpc(payload)
|
|
197
|
+
return js['req_0']['data']['tracks']
|
|
198
|
+
|
|
180
199
|
def song_similar(self, song_id):
|
|
181
200
|
payload = {
|
|
182
201
|
"simsongs": {
|
|
@@ -228,6 +247,7 @@ class API(object):
|
|
|
228
247
|
'singerid': artist_id,
|
|
229
248
|
'begin': (page - 1) * page_size,
|
|
230
249
|
'num': page_size,
|
|
250
|
+
'order': 1, # 热门/新,不带这个字段就是按歌曲新旧排序
|
|
231
251
|
# 有 newsong 字段时,服务端会返回含有 file 字段的字典
|
|
232
252
|
'newsong': 1
|
|
233
253
|
}},
|
|
@@ -377,24 +397,24 @@ class API(object):
|
|
|
377
397
|
playlist = js['recomPlaylist']
|
|
378
398
|
return playlist['data']['v_hot']
|
|
379
399
|
|
|
380
|
-
def
|
|
400
|
+
def get_recommend_feed(self, page=1):
|
|
401
|
+
# APIs are found in https://y.qq.com/wk_v17/#/recommend
|
|
381
402
|
data = {
|
|
382
403
|
'req_0': {
|
|
383
404
|
'module': 'recommend.RecommendFeedServer',
|
|
384
405
|
'method': 'get_recommend_feed',
|
|
385
406
|
'param': {
|
|
386
407
|
'direction': 0,
|
|
387
|
-
'page':
|
|
408
|
+
'page': page,
|
|
388
409
|
'v_cache': [],
|
|
389
410
|
'v_uniq': [],
|
|
390
411
|
's_num': 0
|
|
391
412
|
}
|
|
392
413
|
},
|
|
414
|
+
'comm': self.get_wkv17_common_params(),
|
|
393
415
|
}
|
|
394
416
|
js = self.rpc(data)
|
|
395
|
-
|
|
396
|
-
for card in js['req_0']['data']['v_shelf'][index]['v_niche'][0]['v_card']]
|
|
397
|
-
return ids
|
|
417
|
+
return js['req_0']['data']
|
|
398
418
|
|
|
399
419
|
def get_lyric_by_songmid(self, songmid):
|
|
400
420
|
url = api_base_url + '/lyric/fcgi-bin/fcg_query_lyric_new.fcg'
|
|
@@ -426,6 +446,22 @@ class API(object):
|
|
|
426
446
|
CodeShouldBe0.check(js)
|
|
427
447
|
return js
|
|
428
448
|
|
|
449
|
+
def get_wkv17_common_params(self):
|
|
450
|
+
return {
|
|
451
|
+
# ct field is important, without this field,
|
|
452
|
+
# the req_0 result is completely different.
|
|
453
|
+
"ct": 20,
|
|
454
|
+
"cv": 1770,
|
|
455
|
+
'g_tk': 5381,
|
|
456
|
+
'uin': self._uin,
|
|
457
|
+
'format': 'json',
|
|
458
|
+
'inCharset': 'utf-8',
|
|
459
|
+
'outCharset': 'utf-8',
|
|
460
|
+
'platform': 'wk_v17',
|
|
461
|
+
'uid': '',
|
|
462
|
+
'guid': '',
|
|
463
|
+
}
|
|
464
|
+
|
|
429
465
|
def get_common_params(self):
|
|
430
466
|
return {
|
|
431
467
|
'loginUin': self._uin,
|
|
@@ -3,6 +3,10 @@ from typing import List, Optional, Protocol
|
|
|
3
3
|
from feeluown.excs import ModelNotFound
|
|
4
4
|
from feeluown.library import (
|
|
5
5
|
AbstractProvider,
|
|
6
|
+
BriefSongModel,
|
|
7
|
+
PlaylistModel,
|
|
8
|
+
Collection,
|
|
9
|
+
CollectionType,
|
|
6
10
|
ProviderV2,
|
|
7
11
|
ProviderFlags as PF,
|
|
8
12
|
SupportsSongGet,
|
|
@@ -17,6 +21,7 @@ from feeluown.library import (
|
|
|
17
21
|
SupportsArtistGet,
|
|
18
22
|
SupportsPlaylistGet,
|
|
19
23
|
SupportsPlaylistSongsReader,
|
|
24
|
+
SupportsRecACollectionOfSongs,
|
|
20
25
|
SimpleSearchResult,
|
|
21
26
|
SearchType,
|
|
22
27
|
ModelType,
|
|
@@ -42,6 +47,7 @@ class Supports(
|
|
|
42
47
|
SupportsArtistGet,
|
|
43
48
|
SupportsPlaylistGet,
|
|
44
49
|
SupportsPlaylistSongsReader,
|
|
50
|
+
SupportsRecACollectionOfSongs,
|
|
45
51
|
Protocol,
|
|
46
52
|
):
|
|
47
53
|
pass
|
|
@@ -234,7 +240,7 @@ class QQProvider(AbstractProvider, ProviderV2):
|
|
|
234
240
|
songs = self._model_cache_get_or_fetch(playlist, "songs")
|
|
235
241
|
return create_reader(songs)
|
|
236
242
|
|
|
237
|
-
def
|
|
243
|
+
def __rec_hot_playlists(self):
|
|
238
244
|
user = self.get_current_user()
|
|
239
245
|
if user is None:
|
|
240
246
|
return []
|
|
@@ -247,6 +253,60 @@ class QQProvider(AbstractProvider, ProviderV2):
|
|
|
247
253
|
pl["logo"] = pl["cover"]
|
|
248
254
|
return [_deserialize(playlist, QQPlaylistSchema) for playlist in playlists]
|
|
249
255
|
|
|
256
|
+
def rec_list_daily_playlists(self):
|
|
257
|
+
# TODO: cache API result
|
|
258
|
+
feed = self.api.get_recommend_feed()
|
|
259
|
+
shelf = None
|
|
260
|
+
for shelf_ in feed['v_shelf']:
|
|
261
|
+
# I guess 10046 means 'song'.
|
|
262
|
+
if shelf_['extra_info'].get('moduleID', '').startswith('playlist'):
|
|
263
|
+
shelf = shelf_
|
|
264
|
+
break
|
|
265
|
+
if shelf is None:
|
|
266
|
+
return []
|
|
267
|
+
playlists = []
|
|
268
|
+
for batch in shelf['v_niche']:
|
|
269
|
+
for card in batch['v_card']:
|
|
270
|
+
print(card['title'], card['jumptype'])
|
|
271
|
+
if card['jumptype'] == 10014: # 10014->playlist
|
|
272
|
+
playlists.append(
|
|
273
|
+
PlaylistModel(identifier=str(card['id']),
|
|
274
|
+
source=SOURCE,
|
|
275
|
+
name=card['title'],
|
|
276
|
+
cover=card['cover'],
|
|
277
|
+
description=card['miscellany']['rcmdtemplate'])
|
|
278
|
+
)
|
|
279
|
+
return playlists
|
|
280
|
+
|
|
281
|
+
def rec_a_collection_of_songs(self):
|
|
282
|
+
# TODO: cache API result
|
|
283
|
+
feed = self.api.get_recommend_feed()
|
|
284
|
+
shelf = None
|
|
285
|
+
for shelf_ in feed['v_shelf']:
|
|
286
|
+
# I guess 10046 means 'song'.
|
|
287
|
+
if int(shelf_['miscellany'].get('jumptype', 0)) == 10046:
|
|
288
|
+
shelf = shelf_
|
|
289
|
+
break
|
|
290
|
+
if shelf is None:
|
|
291
|
+
return Collection(name='',
|
|
292
|
+
type_=CollectionType.only_songs,
|
|
293
|
+
models=[],
|
|
294
|
+
description='')
|
|
295
|
+
title = shelf['title_content'] or shelf['title_template']
|
|
296
|
+
song_ids = []
|
|
297
|
+
for batch in shelf['v_niche']:
|
|
298
|
+
for card in batch['v_card']:
|
|
299
|
+
if card['jumptype'] == 10046:
|
|
300
|
+
song_id = int(card['id'])
|
|
301
|
+
if song_id not in song_ids:
|
|
302
|
+
song_ids.append(song_id)
|
|
303
|
+
|
|
304
|
+
tracks = self.api.batch_song_details(song_ids)
|
|
305
|
+
return Collection(name=title,
|
|
306
|
+
type_=CollectionType.only_songs,
|
|
307
|
+
models=[_deserialize(track, QQSongSchema) for track in tracks],
|
|
308
|
+
description='')
|
|
309
|
+
|
|
250
310
|
def current_user_get_radio_songs(self):
|
|
251
311
|
songs_data = self.api.get_radio_music()
|
|
252
312
|
return [_deserialize(s, QQSongSchema) for s in songs_data]
|
|
@@ -5,7 +5,7 @@ from setuptools import setup
|
|
|
5
5
|
|
|
6
6
|
setup(
|
|
7
7
|
name='fuo_qqmusic',
|
|
8
|
-
version='1.0.
|
|
8
|
+
version='1.0.4',
|
|
9
9
|
description='feeluown qqmusic plugin',
|
|
10
10
|
author='Cosven',
|
|
11
11
|
author_email='yinshaowen241@gmail.com',
|
|
@@ -27,7 +27,7 @@ setup(
|
|
|
27
27
|
'Programming Language :: Python :: 3 :: Only',
|
|
28
28
|
],
|
|
29
29
|
install_requires=[
|
|
30
|
-
'feeluown>=4.
|
|
30
|
+
'feeluown>=4.1.3',
|
|
31
31
|
'requests',
|
|
32
32
|
'marshmallow>=3.0'
|
|
33
33
|
],
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|