fuo-qqmusic 1.0.7__tar.gz → 1.0.8__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.

Files changed (21) hide show
  1. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/PKG-INFO +2 -2
  2. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/README.md +4 -0
  3. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/fuo_qqmusic/api.py +31 -0
  4. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/fuo_qqmusic/provider.py +27 -1
  5. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/fuo_qqmusic/provider_ui.py +3 -2
  6. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/fuo_qqmusic/schemas.py +1 -1
  7. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/fuo_qqmusic.egg-info/PKG-INFO +2 -2
  8. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/fuo_qqmusic.egg-info/requires.txt +1 -1
  9. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/setup.py +2 -2
  10. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/fuo_qqmusic/__init__.py +0 -0
  11. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/fuo_qqmusic/assets/icon.svg +0 -0
  12. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/fuo_qqmusic/consts.py +0 -0
  13. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/fuo_qqmusic/excs.py +0 -0
  14. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/fuo_qqmusic/login.py +0 -0
  15. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/fuo_qqmusic.egg-info/SOURCES.txt +0 -0
  16. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/fuo_qqmusic.egg-info/dependency_links.txt +0 -0
  17. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/fuo_qqmusic.egg-info/entry_points.txt +0 -0
  18. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/fuo_qqmusic.egg-info/top_level.txt +0 -0
  19. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/setup.cfg +0 -0
  20. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/tests/test_api.py +0 -0
  21. {fuo_qqmusic-1.0.7 → fuo_qqmusic-1.0.8}/tests/test_provider.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fuo_qqmusic
3
- Version: 1.0.7
3
+ Version: 1.0.8
4
4
  Summary: feeluown qqmusic plugin
5
5
  Home-page: https://github.com/feeluown/feeluown-qqmusic
6
6
  Author: Cosven
@@ -13,7 +13,7 @@ Classifier: Programming Language :: Python :: 3.7
13
13
  Classifier: Programming Language :: Python :: 3.8
14
14
  Classifier: Programming Language :: Python :: 3.9
15
15
  Classifier: Programming Language :: Python :: 3 :: Only
16
- Requires-Dist: feeluown>=4.1.3
16
+ Requires-Dist: feeluown>=4.1.13
17
17
  Requires-Dist: requests
18
18
  Requires-Dist: marshmallow<4.0.0,>=3.0
19
19
  Dynamic: author
@@ -20,6 +20,10 @@ pip3 install fuo-qqmusic
20
20
  [操作示例](https://github.com/feeluown/feeluown-qqmusic/issues/6)。
21
21
 
22
22
  ## changelog
23
+ ### 1.0.8 (2025-07-03)
24
+ - 增强 web 登录可靠性
25
+ - 歌单支持添加/删除歌曲
26
+
23
27
  ### 1.0.7 (2025-05-31)
24
28
  - 支持音乐黑名单
25
29
 
@@ -287,6 +287,34 @@ class API(object):
287
287
  resp = requests.get(url, params=params)
288
288
  return resp.json()['data']
289
289
 
290
+ def playlist_remove_songs(self, playlist_id, song_id_list):
291
+ payload = {
292
+ 'req_0': {
293
+ 'method': 'DelSonglist',
294
+ 'module': 'music.musicasset.PlaylistDetailWrite',
295
+ 'param': {
296
+ 'dirId': playlist_id, # int
297
+ 'v_songInfo': [{'songId': int(song_id), 'songType': 0} for song_id in song_id_list]
298
+ }
299
+ }
300
+ }
301
+ js = self.rpc(payload)
302
+ return js['req_0']['code'] == 0
303
+
304
+ def playlist_add_songs(self, playlist_id, song_id_list):
305
+ payload = {
306
+ 'req_0': {
307
+ 'method': 'AddSonglist',
308
+ 'module': 'music.musicasset.PlaylistDetailWrite',
309
+ 'param': {
310
+ 'dirId': int(playlist_id), # int
311
+ 'v_songInfo': [{'songId': int(song_id), 'songType': 0} for song_id in song_id_list]
312
+ }
313
+ }
314
+ }
315
+ js = self.rpc(payload)
316
+ return js['req_0']['code'] == 0
317
+
290
318
  def playlist_detail(self, pid, offset=0, limit=50):
291
319
  url = api_base_url + '/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg'
292
320
  params = {
@@ -319,6 +347,7 @@ class API(object):
319
347
  resp = requests.get(url, params=params, headers=self._headers,
320
348
  cookies=self._cookies, timeout=self._timeout)
321
349
  js = resp.json()
350
+ logger.debug(f"user detail response: {js}")
322
351
  if js['code'] != 0:
323
352
  raise CodeShouldBe0(js)
324
353
  return js['data']
@@ -438,6 +467,7 @@ class API(object):
438
467
  def rpc(self, payload):
439
468
  if 'comm' not in payload:
440
469
  payload['comm'] = self.get_common_params()
470
+ logger.debug(f"rpc payload: {payload}")
441
471
  data_str = json.dumps(payload, ensure_ascii=False)
442
472
  params = {
443
473
  '_': int(round(time.time() * 1000)),
@@ -448,6 +478,7 @@ class API(object):
448
478
  resp = requests.get(url, params=params, headers=self._headers,
449
479
  cookies=self._cookies, timeout=self._timeout)
450
480
  js = resp.json()
481
+ logger.debug(f"rpc response json: {js}")
451
482
  CodeShouldBe0.check(js)
452
483
  return js
453
484
 
@@ -4,6 +4,7 @@ from feeluown.excs import ModelNotFound
4
4
  from feeluown.library import (
5
5
  AbstractProvider,
6
6
  BriefSongModel,
7
+ BriefPlaylistModel,
7
8
  PlaylistModel,
8
9
  Collection,
9
10
  CollectionType,
@@ -280,6 +281,22 @@ class QQProvider(AbstractProvider, ProviderV2):
280
281
  data = self.api.playlist_detail(int(identifier), limit=1000)
281
282
  return _deserialize(data, QQPlaylistSchema)
282
283
 
284
+ def playlist_add_song(self, playlist, song):
285
+ # FIXME: 目前 playlist 相关接口用的都是 diss 结构体,而这里需要一个 dirid。
286
+ # 平台方也提供了 dir 相关的接口,我大胆猜测,diss 是一套老接口。
287
+ playlist._cache.pop("songs", None)
288
+ dirid = self._get_dirid_by_playlist_id(playlist.identifier)
289
+ return self.api.playlist_add_songs(dirid, [song.identifier])
290
+
291
+ def playlist_remove_song(self, playlist, song):
292
+ playlist._cache.pop("songs", None)
293
+ dirid = self._get_dirid_by_playlist_id(playlist.identifier)
294
+ return self.api.playlist_remove_songs(dirid, [song.identifier])
295
+
296
+ def _get_dirid_by_playlist_id(self, playlist_id):
297
+ data = self.api.playlist_detail(int(playlist_id), limit=1)
298
+ return data["dirid"]
299
+
283
300
  def playlist_create_songs_rd(self, playlist):
284
301
  songs = self._model_cache_get_or_fetch(playlist, "songs")
285
302
  return create_reader(songs)
@@ -381,7 +398,13 @@ class QQProvider(AbstractProvider, ProviderV2):
381
398
  if user is None:
382
399
  return []
383
400
  playlists = self._model_cache_get_or_fetch(user, "playlists")
384
- return playlists
401
+ fav_pid = self._model_cache_get_or_fetch(user, "fav_pid")
402
+ my_love = BriefPlaylistModel(
403
+ source=SOURCE,
404
+ identifier=str(fav_pid),
405
+ name='我喜欢'
406
+ )
407
+ return [my_love] + playlists
385
408
 
386
409
  def current_user_fav_create_songs_rd(self):
387
410
  user = self.get_current_user()
@@ -415,6 +438,9 @@ class QQProvider(AbstractProvider, ProviderV2):
415
438
  return create_reader([])
416
439
  mid = self._model_cache_get_or_fetch(user, "mid")
417
440
  playlists = self.api.user_favorite_playlists(user.identifier, mid)
441
+ # HACK: 给 playlist 加一个 disstid 字段,这样可以兼容 QQPlaylistSchema
442
+ for playlist in playlists:
443
+ playlist["disstid"] = playlist["dissid"]
418
444
  return [_deserialize(playlist, QQPlaylistSchema) for playlist in playlists]
419
445
 
420
446
  def has_current_user(self):
@@ -39,8 +39,9 @@ class ProviderUI(AbstractProviderUi):
39
39
  #
40
40
  # - keys: ['skey']
41
41
  url = os.getenv('FUO_QQMUSIC_LOGIN_URL', 'https://y.qq.com')
42
- keys = os.getenv('FUO_QQMUSIC_LOGIN_COOKIE_KEYS', 'qqmusic_key').split(',')
43
- self._dialog = LoginDialog(url, keys)
42
+ keys_str = os.getenv('FUO_QQMUSIC_LOGIN_COOKIE_KEYS',
43
+ 'qqmusic_key,wxuin|qqmusic_key,uin')
44
+ self._dialog = LoginDialog(url, [keys.split(',') for keys in keys_str.split('|')])
44
45
  self._dialog.login_succeed.connect(self.on_login_succeed)
45
46
  self._dialog.show()
46
47
  self._dialog.autologin()
@@ -271,7 +271,7 @@ class QQAlbumSchema(Schema):
271
271
 
272
272
 
273
273
  class QQPlaylistSchema(Schema):
274
- identifier = fields.Int(required=True, data_key="dissid")
274
+ identifier = fields.Int(required=True, data_key="disstid")
275
275
  name = fields.Str(required=True, data_key="dissname")
276
276
  cover = fields.Str(required=True, data_key="logo")
277
277
  # songs field maybe null, though it can't be null in model
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fuo_qqmusic
3
- Version: 1.0.7
3
+ Version: 1.0.8
4
4
  Summary: feeluown qqmusic plugin
5
5
  Home-page: https://github.com/feeluown/feeluown-qqmusic
6
6
  Author: Cosven
@@ -13,7 +13,7 @@ Classifier: Programming Language :: Python :: 3.7
13
13
  Classifier: Programming Language :: Python :: 3.8
14
14
  Classifier: Programming Language :: Python :: 3.9
15
15
  Classifier: Programming Language :: Python :: 3 :: Only
16
- Requires-Dist: feeluown>=4.1.3
16
+ Requires-Dist: feeluown>=4.1.13
17
17
  Requires-Dist: requests
18
18
  Requires-Dist: marshmallow<4.0.0,>=3.0
19
19
  Dynamic: author
@@ -1,3 +1,3 @@
1
- feeluown>=4.1.3
1
+ feeluown>=4.1.13
2
2
  requests
3
3
  marshmallow<4.0.0,>=3.0
@@ -5,7 +5,7 @@ from setuptools import setup
5
5
 
6
6
  setup(
7
7
  name='fuo_qqmusic',
8
- version='1.0.7',
8
+ version='1.0.8',
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.1.3',
30
+ 'feeluown>=4.1.13',
31
31
  'requests',
32
32
  'marshmallow>=3.0,<4.0.0'
33
33
  ],
File without changes