fuo-qqmusic 1.0.6__tar.gz → 1.0.7__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.6 → fuo_qqmusic-1.0.7}/PKG-INFO +2 -2
- {fuo_qqmusic-1.0.6 → fuo_qqmusic-1.0.7}/README.md +3 -0
- {fuo_qqmusic-1.0.6 → fuo_qqmusic-1.0.7}/fuo_qqmusic/api.py +81 -0
- {fuo_qqmusic-1.0.6 → fuo_qqmusic-1.0.7}/fuo_qqmusic/provider.py +39 -0
- {fuo_qqmusic-1.0.6 → fuo_qqmusic-1.0.7}/fuo_qqmusic.egg-info/PKG-INFO +2 -2
- {fuo_qqmusic-1.0.6 → fuo_qqmusic-1.0.7}/fuo_qqmusic.egg-info/SOURCES.txt +1 -0
- {fuo_qqmusic-1.0.6 → fuo_qqmusic-1.0.7}/fuo_qqmusic.egg-info/requires.txt +1 -1
- {fuo_qqmusic-1.0.6 → fuo_qqmusic-1.0.7}/setup.py +2 -2
- fuo_qqmusic-1.0.7/tests/test_api.py +56 -0
- {fuo_qqmusic-1.0.6 → fuo_qqmusic-1.0.7}/fuo_qqmusic/__init__.py +0 -0
- {fuo_qqmusic-1.0.6 → fuo_qqmusic-1.0.7}/fuo_qqmusic/assets/icon.svg +0 -0
- {fuo_qqmusic-1.0.6 → fuo_qqmusic-1.0.7}/fuo_qqmusic/consts.py +0 -0
- {fuo_qqmusic-1.0.6 → fuo_qqmusic-1.0.7}/fuo_qqmusic/excs.py +0 -0
- {fuo_qqmusic-1.0.6 → fuo_qqmusic-1.0.7}/fuo_qqmusic/login.py +0 -0
- {fuo_qqmusic-1.0.6 → fuo_qqmusic-1.0.7}/fuo_qqmusic/provider_ui.py +0 -0
- {fuo_qqmusic-1.0.6 → fuo_qqmusic-1.0.7}/fuo_qqmusic/schemas.py +0 -0
- {fuo_qqmusic-1.0.6 → fuo_qqmusic-1.0.7}/fuo_qqmusic.egg-info/dependency_links.txt +0 -0
- {fuo_qqmusic-1.0.6 → fuo_qqmusic-1.0.7}/fuo_qqmusic.egg-info/entry_points.txt +0 -0
- {fuo_qqmusic-1.0.6 → fuo_qqmusic-1.0.7}/fuo_qqmusic.egg-info/top_level.txt +0 -0
- {fuo_qqmusic-1.0.6 → fuo_qqmusic-1.0.7}/setup.cfg +0 -0
- {fuo_qqmusic-1.0.6 → fuo_qqmusic-1.0.7}/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.
|
|
3
|
+
Version: 1.0.7
|
|
4
4
|
Summary: feeluown qqmusic plugin
|
|
5
5
|
Home-page: https://github.com/feeluown/feeluown-qqmusic
|
|
6
6
|
Author: Cosven
|
|
@@ -15,7 +15,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
15
15
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
16
|
Requires-Dist: feeluown>=4.1.3
|
|
17
17
|
Requires-Dist: requests
|
|
18
|
-
Requires-Dist: marshmallow
|
|
18
|
+
Requires-Dist: marshmallow<4.0.0,>=3.0
|
|
19
19
|
Dynamic: author
|
|
20
20
|
Dynamic: author-email
|
|
21
21
|
Dynamic: classifier
|
|
@@ -8,6 +8,7 @@ import math
|
|
|
8
8
|
import json
|
|
9
9
|
import random
|
|
10
10
|
import time
|
|
11
|
+
from enum import Enum
|
|
11
12
|
|
|
12
13
|
import requests
|
|
13
14
|
from .excs import QQIOError
|
|
@@ -717,5 +718,85 @@ class API(object):
|
|
|
717
718
|
return 'http://isure.stream.qqmusic.qq.com/{}'.format(midurlinfo[0]['purl'])
|
|
718
719
|
return ''
|
|
719
720
|
|
|
721
|
+
class DislikeListType(Enum):
|
|
722
|
+
singer = 2
|
|
723
|
+
song = 3
|
|
724
|
+
_style_unsupported = 4 # TODO: 这是什么?似乎是不喜欢的风格列表,不确定,暂时不支持
|
|
725
|
+
|
|
726
|
+
def get_dislike_list(self, page=1, type_=DislikeListType.song, last_id=0):
|
|
727
|
+
payload = {
|
|
728
|
+
"req_0": {
|
|
729
|
+
"module": "music.feedback.FeedbackBlack",
|
|
730
|
+
"method": "GetDislikeList",
|
|
731
|
+
"param": {
|
|
732
|
+
"Cmd": type_.value,
|
|
733
|
+
"Page": page,
|
|
734
|
+
"SongLastid": last_id if type_ == API.DislikeListType.song else 0,
|
|
735
|
+
"SingersLastid": (
|
|
736
|
+
last_id if type_ == API.DislikeListType.singer else 0
|
|
737
|
+
),
|
|
738
|
+
},
|
|
739
|
+
},
|
|
740
|
+
}
|
|
741
|
+
js = self.rpc(payload)
|
|
742
|
+
if type_ == API.DislikeListType.song:
|
|
743
|
+
return js["req_0"]["data"]["Songs"]
|
|
744
|
+
elif type_ == API.DislikeListType.singer:
|
|
745
|
+
return js["req_0"]["data"]["Singers"]
|
|
746
|
+
else:
|
|
747
|
+
raise QQIOError(f"Unknown dislike list type: {type_}")
|
|
748
|
+
|
|
749
|
+
def add_to_dislike_list(self, items, type_=DislikeListType.song):
|
|
750
|
+
req_param = {
|
|
751
|
+
"Singers": [],
|
|
752
|
+
"Songs": [],
|
|
753
|
+
"Styles": [],
|
|
754
|
+
"OnlyAdd": 1,
|
|
755
|
+
}
|
|
756
|
+
if type_ == API.DislikeListType.song:
|
|
757
|
+
req_param["Songs"] = items
|
|
758
|
+
elif type_ == API.DislikeListType.singer:
|
|
759
|
+
req_param["Singers"] = items
|
|
760
|
+
else:
|
|
761
|
+
raise QQIOError(f"Unknown dislike list type: {type_}")
|
|
762
|
+
|
|
763
|
+
payload = {
|
|
764
|
+
"req_0": {
|
|
765
|
+
"module": "music.feedback.FeedbackBlack",
|
|
766
|
+
"method": "AddDislike",
|
|
767
|
+
"param": req_param,
|
|
768
|
+
},
|
|
769
|
+
}
|
|
770
|
+
js = self.rpc(payload)
|
|
771
|
+
# Response example, {'code': 0, 'data': {'Retcode': 0, 'Msg': '', 'Token': ''}}
|
|
772
|
+
CodeShouldBe0.check(js['req_0'])
|
|
773
|
+
return js['req_0']['data']
|
|
774
|
+
|
|
775
|
+
def remove_from_dislike_list(self, items, type_=DislikeListType.song):
|
|
776
|
+
req_param = {
|
|
777
|
+
"Singers": [],
|
|
778
|
+
"Songs": [],
|
|
779
|
+
"Styles": [],
|
|
780
|
+
"OnlyAdd": 0,
|
|
781
|
+
}
|
|
782
|
+
if type_ == API.DislikeListType.song:
|
|
783
|
+
req_param["Songs"] = items
|
|
784
|
+
elif type_ == API.DislikeListType.singer:
|
|
785
|
+
req_param["Singers"] = items
|
|
786
|
+
else:
|
|
787
|
+
raise QQIOError(f"Unknown dislike list type: {type_}")
|
|
788
|
+
|
|
789
|
+
payload = {
|
|
790
|
+
"req_0": {
|
|
791
|
+
"module": "music.feedback.FeedbackBlack",
|
|
792
|
+
"method": "CancelDislike",
|
|
793
|
+
"param": req_param,
|
|
794
|
+
},
|
|
795
|
+
}
|
|
796
|
+
js = self.rpc(payload)
|
|
797
|
+
CodeShouldBe0.check(js)
|
|
798
|
+
CodeShouldBe0.check(js['req_0'])
|
|
799
|
+
return js['req_0']['data']
|
|
800
|
+
|
|
720
801
|
|
|
721
802
|
api = API()
|
|
@@ -23,12 +23,17 @@ from feeluown.library import (
|
|
|
23
23
|
SupportsPlaylistGet,
|
|
24
24
|
SupportsPlaylistSongsReader,
|
|
25
25
|
SupportsRecACollectionOfSongs,
|
|
26
|
+
SupportsCurrentUserDislikeSongsReader,
|
|
27
|
+
SupportsCurrentUserDislikeAddSong,
|
|
28
|
+
SupportsCurrentUserDislikeRemoveSong,
|
|
29
|
+
SupportsCurrentUserChanged,
|
|
26
30
|
SimpleSearchResult,
|
|
27
31
|
SearchType,
|
|
28
32
|
ModelType,
|
|
29
33
|
UserModel,
|
|
30
34
|
)
|
|
31
35
|
from feeluown.media import Media, Quality
|
|
36
|
+
from feeluown.utils.dispatch import Signal
|
|
32
37
|
from feeluown.utils.reader import create_reader, SequentialReader
|
|
33
38
|
from .api import API
|
|
34
39
|
from .login import read_cookies
|
|
@@ -53,6 +58,9 @@ class Supports(
|
|
|
53
58
|
SupportsPlaylistSongsReader,
|
|
54
59
|
SupportsRecACollectionOfSongs,
|
|
55
60
|
SupportsAlbumSongsReader,
|
|
61
|
+
SupportsCurrentUserDislikeSongsReader,
|
|
62
|
+
SupportsCurrentUserDislikeAddSong,
|
|
63
|
+
SupportsCurrentUserDislikeRemoveSong,
|
|
56
64
|
Protocol,
|
|
57
65
|
):
|
|
58
66
|
pass
|
|
@@ -70,6 +78,7 @@ class QQProvider(AbstractProvider, ProviderV2):
|
|
|
70
78
|
def __init__(self):
|
|
71
79
|
super().__init__()
|
|
72
80
|
self.api = API()
|
|
81
|
+
self.current_user_changed = Signal()
|
|
73
82
|
|
|
74
83
|
def _(self) -> Supports:
|
|
75
84
|
return self
|
|
@@ -89,6 +98,7 @@ class QQProvider(AbstractProvider, ProviderV2):
|
|
|
89
98
|
self.auth(user)
|
|
90
99
|
else:
|
|
91
100
|
logger.info(f'Auto login failed: {err}')
|
|
101
|
+
self.current_user_changed.emit(user)
|
|
92
102
|
|
|
93
103
|
def try_get_user_from_cookies(self, cookies) -> Tuple[Optional[UserModel], str]:
|
|
94
104
|
if not cookies: # is None or empty
|
|
@@ -417,6 +427,35 @@ class QQProvider(AbstractProvider, ProviderV2):
|
|
|
417
427
|
data_songs = self.api.song_similar(int(song.identifier))
|
|
418
428
|
return [_deserialize(data_song, QQSongSchema) for data_song in data_songs]
|
|
419
429
|
|
|
430
|
+
def current_user_dislike_create_songs_rd(self):
|
|
431
|
+
user = self.get_current_user()
|
|
432
|
+
if user is None:
|
|
433
|
+
return create_reader([])
|
|
434
|
+
# FIXME: 如果用户的黑名单歌曲数量较多的话,这样处理则是不够的
|
|
435
|
+
items = self.api.get_dislike_list(1, API.DislikeListType.song, 0)
|
|
436
|
+
songs = []
|
|
437
|
+
for item in items:
|
|
438
|
+
name = item['Name']
|
|
439
|
+
title, artists_name = name.split(' - ')
|
|
440
|
+
song = BriefSongModel(
|
|
441
|
+
source=SOURCE,
|
|
442
|
+
identifier=item['ID'],
|
|
443
|
+
title=title,
|
|
444
|
+
artists_name=artists_name,
|
|
445
|
+
)
|
|
446
|
+
songs.append(song)
|
|
447
|
+
return create_reader(songs)
|
|
448
|
+
|
|
449
|
+
def current_user_dislike_add_song(self, song):
|
|
450
|
+
items = [{'ID': song.identifier}]
|
|
451
|
+
js = self.api.add_to_dislike_list(items, API.DislikeListType.song)
|
|
452
|
+
return js.get('Retcode') == 0
|
|
453
|
+
|
|
454
|
+
def current_user_dislike_remove_song(self, song):
|
|
455
|
+
items = [{'ID': song.identifier}]
|
|
456
|
+
js = self.api.remove_from_dislike_list(items, API.DislikeListType.song)
|
|
457
|
+
return js.get('Retcode') == 0
|
|
458
|
+
|
|
420
459
|
|
|
421
460
|
def _deserialize(data, schema_cls):
|
|
422
461
|
schema = schema_cls()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fuo_qqmusic
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.7
|
|
4
4
|
Summary: feeluown qqmusic plugin
|
|
5
5
|
Home-page: https://github.com/feeluown/feeluown-qqmusic
|
|
6
6
|
Author: Cosven
|
|
@@ -15,7 +15,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
15
15
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
16
|
Requires-Dist: feeluown>=4.1.3
|
|
17
17
|
Requires-Dist: requests
|
|
18
|
-
Requires-Dist: marshmallow
|
|
18
|
+
Requires-Dist: marshmallow<4.0.0,>=3.0
|
|
19
19
|
Dynamic: author
|
|
20
20
|
Dynamic: author-email
|
|
21
21
|
Dynamic: classifier
|
|
@@ -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.7',
|
|
9
9
|
description='feeluown qqmusic plugin',
|
|
10
10
|
author='Cosven',
|
|
11
11
|
author_email='yinshaowen241@gmail.com',
|
|
@@ -29,7 +29,7 @@ setup(
|
|
|
29
29
|
install_requires=[
|
|
30
30
|
'feeluown>=4.1.3',
|
|
31
31
|
'requests',
|
|
32
|
-
'marshmallow>=3.0'
|
|
32
|
+
'marshmallow>=3.0,<4.0.0'
|
|
33
33
|
],
|
|
34
34
|
entry_points={
|
|
35
35
|
'fuo.plugins_v1': [
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from fuo_qqmusic.api import API
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def parse_cookie_to_dict(cookie_str):
|
|
6
|
+
# 初始化结果字典
|
|
7
|
+
result = {}
|
|
8
|
+
|
|
9
|
+
# 按分号分割字符串,得到每个键值对
|
|
10
|
+
pairs = cookie_str.split(";")
|
|
11
|
+
|
|
12
|
+
for pair in pairs:
|
|
13
|
+
# 去除两端空格
|
|
14
|
+
pair = pair.strip()
|
|
15
|
+
|
|
16
|
+
# 按等号分割键和值
|
|
17
|
+
if "=" in pair:
|
|
18
|
+
key, value = pair.split("=", 1)
|
|
19
|
+
key = key.strip()
|
|
20
|
+
value = value.strip()
|
|
21
|
+
|
|
22
|
+
# 如果值为空字符串,则设置为 None
|
|
23
|
+
if value == "":
|
|
24
|
+
value = None
|
|
25
|
+
|
|
26
|
+
# 存入字典
|
|
27
|
+
result[key] = value
|
|
28
|
+
|
|
29
|
+
return result
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
cookie_str = "Your cookie string here"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@pytest.mark.skip(reason="need valid cookies")
|
|
36
|
+
def test_api():
|
|
37
|
+
api = API()
|
|
38
|
+
api.set_cookies(parse_cookie_to_dict(cookie_str))
|
|
39
|
+
# You can also use the following code to load cookies
|
|
40
|
+
# from fuo_qqmusic.provider import provider
|
|
41
|
+
# provider.auto_login()
|
|
42
|
+
# api = provider.api
|
|
43
|
+
items = [
|
|
44
|
+
{
|
|
45
|
+
"ID": "238159921",
|
|
46
|
+
"Name": "无人区-Vacuum Track#ADD8E6- - 米缐p.",
|
|
47
|
+
"IdType": 0,
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
print(api.add_to_dislike_list(items, type_=API.DislikeListType.song))
|
|
51
|
+
print(api.get_dislike_list(type_=API.DislikeListType.song))
|
|
52
|
+
print(api.remove_from_dislike_list(items, type_=API.DislikeListType.song))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
if __name__ == "__main__":
|
|
56
|
+
test_api()
|
|
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
|
|
File without changes
|