fuo-qqmusic 1.0.1__tar.gz → 1.0.3__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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fuo_qqmusic
3
- Version: 1.0.1
3
+ Version: 1.0.3
4
4
  Summary: feeluown qqmusic plugin
5
5
  Home-page: https://github.com/feeluown/feeluown-qqmusic
6
6
  Author: Cosven
@@ -20,6 +20,12 @@ pip3 install fuo-qqmusic
20
20
  [操作示例](https://github.com/feeluown/feeluown-qqmusic/issues/6)。
21
21
 
22
22
  ## changelog
23
+ ### 1.0.3 (2024-04-21)
24
+ - 适配 feeluown 4.1.3 的新主页功能
25
+
26
+ ### 1.0.2 (2024-03-04)
27
+ - 修复获取歌单封面失败的问题 #21
28
+ - 修复获取歌曲播放链接失败的问题 #20
23
29
 
24
30
  ### 1.0 (2024-01-1)
25
31
  - 使用 FeelUOwn 新接口
@@ -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": {
@@ -377,24 +396,24 @@ class API(object):
377
396
  playlist = js['recomPlaylist']
378
397
  return playlist['data']['v_hot']
379
398
 
380
- def get_recommend_playlists_ids(self, index=0):
399
+ def get_recommend_feed(self, page=1):
400
+ # APIs are found in https://y.qq.com/wk_v17/#/recommend
381
401
  data = {
382
402
  'req_0': {
383
403
  'module': 'recommend.RecommendFeedServer',
384
404
  'method': 'get_recommend_feed',
385
405
  'param': {
386
406
  'direction': 0,
387
- 'page': 1,
407
+ 'page': page,
388
408
  'v_cache': [],
389
409
  'v_uniq': [],
390
410
  's_num': 0
391
411
  }
392
412
  },
413
+ 'comm': self.get_wkv17_common_params(),
393
414
  }
394
415
  js = self.rpc(data)
395
- ids = [card['id']
396
- for card in js['req_0']['data']['v_shelf'][index]['v_niche'][0]['v_card']]
397
- return ids
416
+ return js['req_0']['data']
398
417
 
399
418
  def get_lyric_by_songmid(self, songmid):
400
419
  url = api_base_url + '/lyric/fcgi-bin/fcg_query_lyric_new.fcg'
@@ -426,6 +445,22 @@ class API(object):
426
445
  CodeShouldBe0.check(js)
427
446
  return js
428
447
 
448
+ def get_wkv17_common_params(self):
449
+ return {
450
+ # ct field is important, without this field,
451
+ # the req_0 result is completely different.
452
+ "ct": 20,
453
+ "cv": 1770,
454
+ 'g_tk': 5381,
455
+ 'uin': self._uin,
456
+ 'format': 'json',
457
+ 'inCharset': 'utf-8',
458
+ 'outCharset': 'utf-8',
459
+ 'platform': 'wk_v17',
460
+ 'uid': '',
461
+ 'guid': '',
462
+ }
463
+
429
464
  def get_common_params(self):
430
465
  return {
431
466
  'loginUin': self._uin,
@@ -476,13 +511,7 @@ class API(object):
476
511
  },
477
512
  }
478
513
  js = self.rpc(payload)
479
- res_json = []
480
- for track in js['songlist']['data']['tracks']:
481
- track['songid'] = track.pop('id')
482
- track['songmid'] = track.pop('mid')
483
- track['songname'] = track.pop('name')
484
- res_json.append(track)
485
- return res_json
514
+ return js['songlist']['data']['tracks']
486
515
 
487
516
  def get_song_url(self, song_mid):
488
517
  uin = 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
@@ -153,13 +159,13 @@ class QQProvider(AbstractProvider, ProviderV2):
153
159
  :return: when quality is invalid, return None
154
160
  """
155
161
  q_media_mapping = self._song_get_q_media_mapping(song)
156
- quality_suffix = song.cache_get("quality_suffix")
157
- mid = song.cache_get("mid")
158
- media_id = song.cache_get("media_id")
162
+ quality_suffix = self._model_cache_get_or_fetch(song, "quality_suffix")
163
+ mid = self._model_cache_get_or_fetch(song, "mid")
164
+ media_id = self._model_cache_get_or_fetch(song, "media_id")
159
165
  media = q_media_mapping.get(quality)
160
166
  if media is UNFETCHED_MEDIA:
161
167
  for q, t, b, s in quality_suffix:
162
- if quality == q:
168
+ if quality == Quality.Audio(q):
163
169
  url = self.api.get_song_url_v2(mid, media_id, t)
164
170
  if url:
165
171
  media = Media(url, bitrate=b, format=s)
@@ -247,6 +253,35 @@ 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_a_collection_of_songs(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['miscellany'].get('jumptype') == 10046:
263
+ shelf = shelf
264
+ if shelf is None:
265
+ return '', []
266
+ title = shelf['title_content'] or shelf['title_template']
267
+ song_ids = []
268
+ for batch in shelf['v_niche']:
269
+ for card in batch['v_card']:
270
+ if card['jumptype'] == 10046:
271
+ song_id = int(card['id'])
272
+ if song_id not in song_ids:
273
+ song_ids.append(song_id)
274
+
275
+ tracks = self.api.batch_song_details(song_ids)
276
+ return Collection(name=title,
277
+ type_=CollectionType.only_songs,
278
+ models=[_deserialize(track, QQSongSchema) for track in tracks],
279
+ description='')
280
+
281
+ def current_user_get_radio_songs(self):
282
+ songs_data = self.api.get_radio_music()
283
+ return [_deserialize(s, QQSongSchema) for s in songs_data]
284
+
250
285
  def current_user_list_playlists(self):
251
286
  user = self.get_current_user()
252
287
  if user is None:
@@ -226,7 +226,7 @@ class QQAlbumSchema(Schema):
226
226
  class QQPlaylistSchema(Schema):
227
227
  identifier = fields.Int(required=True, data_key="dissid")
228
228
  name = fields.Str(required=True, data_key="dissname")
229
- cover = fields.Url(required=True, data_key="logo")
229
+ cover = fields.Str(required=True, data_key="logo")
230
230
  # songs field maybe null, though it can't be null in model
231
231
  songs = fields.List(
232
232
  fields.Nested(QQSongSchema), data_key="songlist", allow_none=True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fuo-qqmusic
3
- Version: 1.0.1
3
+ Version: 1.0.3
4
4
  Summary: feeluown qqmusic plugin
5
5
  Home-page: https://github.com/feeluown/feeluown-qqmusic
6
6
  Author: Cosven
@@ -1,3 +1,3 @@
1
- feeluown>=4.0a0
1
+ feeluown>=4.1.3
2
2
  requests
3
3
  marshmallow>=3.0
@@ -5,7 +5,7 @@ from setuptools import setup
5
5
 
6
6
  setup(
7
7
  name='fuo_qqmusic',
8
- version='1.0.1',
8
+ version='1.0.3',
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.0a0',
30
+ 'feeluown>=4.1.3',
31
31
  'requests',
32
32
  'marshmallow>=3.0'
33
33
  ],
File without changes