Skip to content

Commit

Permalink
Version 1.6.8.3
Browse files Browse the repository at this point in the history
pyncm : `Session` now supports context manager protocol (#22)
This allows us to switch up multiple sessions at once, allowing for multiple accounts to be simultaneously accessed.
README : Documented new features
  • Loading branch information
mos9527 committed Oct 26, 2022
1 parent 7c277b4 commit 6cafa0d
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 11 deletions.
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,18 @@
>>> apis.track.GetTrackComments(29732235)
{'isMusician': False, 'userId': -1, 'topComments': [], 'moreHot': True, 'hotComments': [{'user': {'locationInfo': None, 'liveIn ...
```

- 多 Session 示例
```python
LoginViaEmail(...)
# 利用全局 Session 完成该 API Call
session = CreateNewSession() # 建立新的 Session
with session: # 进入该 Session, 在 `with` 内的 API 将由该 Session 完成
LoginViaCellPhone(...)
result = GetTrackAudio(...)
# 离开 Session. 此后 API 将继续由全局 Session 管理
GetTrackComments(...)
```
详见 [Session 说明](https://github.com/mos9527/pyncm/blob/master/pyncm/__init__.py#L52)
## API 说明
大部分 API 函数已经详细注释,可读性较高。推荐参阅 [API 源码](https://github.com/mos9527/pyncm/tree/master/pyncm) 获得支持

Expand Down
51 changes: 41 additions & 10 deletions pyncm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,33 +32,48 @@
# 注意事项
- (PR#11) 海外用户可能经历 460 "Cheating" 问题,可通过添加以下 Header 解决: `X-Real-IP = 118.88.88.88`
"""
from threading import current_thread
from typing import Text, Union
from time import time
from .utils.crypto import EapiEncrypt, EapiDecrypt, HexCompose
import requests, logging, json
logger = logging.getLogger("pyncm.api")

__version__ = "1.6.8.2.2"
__version__ = "1.6.8.3"

DEVICE_ID_DEFAULT = "pyncm!"
# This sometimes fails with some strings, for no particular reason. Though `pyncm!` seem to work everytime..?
# Though with this, all pyncm users would then be sharing the same device Id.
# Don't think that would be of any issue though...
"""默认 deviceID"""
SESSION_STACK = dict()

class Session(requests.Session):
"""# Session
实现网易云音乐登录态 / API请求管理
实现网易云音乐登录态 / API 请求管理
- HTTP方面,`Session`的配置方法和 `requests.Session` 完全一致,如配置 Headers::
- HTTP方面,`Session`的配置方法和 `requests.Session` 完全一致,如配置 Headers:
GetCurrentSession().headers['X-Real-IP'] = '1.1.1.1'
- 该 Session 其他参数也可被修改::
- 该 Session 其他参数也可被修改:
GetCurrentSession().force_http = True # 优先 HTTP
获取其他具体信息请参考该文档注释
- Session 对象本身可作为 Context Manager 使用:
```python
# 利用全局 Session 完成该 API Call
LoginViaEmail(...)
session = CreateNewSession() # 建立新的 Session
with session: # 进入该 Session, 在 `with` 内的 API 将由该 Session 完成
LoginViaCellPhone(...)
# 离开 Session. 此后 API 将继续由全局 Session 管理
```
注:Session 各*线程*独立,各线程利用 `with` 设置的 Sesison 不互相影响
获取其他具体信息请参考该文档注释
"""
HOST = "music.163.com"
"""网易云音乐 API 服务器域名,可直接改为代理服务器之域名"""
Expand All @@ -70,6 +85,16 @@ class Session(requests.Session):
"""曾经的 Linux 客户端 UA,不推荐更改"""
force_http = False
"""优先使用 HTTP 作 API 请求协议"""

def __enter__(self):
SESSION_STACK.setdefault(current_thread(),list())
SESSION_STACK[current_thread()].append(self)
return super().__enter__()

def __exit__(self, *args) -> None:
SESSION_STACK[current_thread()].pop()
return super().__exit__(*args)

def __init__(self, *a, **k):
super().__init__(*a, **k)
self.headers = {
Expand Down Expand Up @@ -185,19 +210,21 @@ def load(self, dumped):
for k, v in dumped.items():
self._session_info[k][1](self, v)
return True

# endregion

# endregion

class SessionManager:
"""PyNCM Session 单例储存对象"""
def __init__(self) -> None:
self.session = Session()

def get(self):
if SESSION_STACK.get(current_thread(),None):
return SESSION_STACK[current_thread()][-1]
return self.session

def set(self, session):
if SESSION_STACK.get(current_thread(),None):
raise Exception("Current Session is in `with` block, which cannot be reassigned.")
self.session = session

# region Session serialization
Expand Down Expand Up @@ -237,8 +264,7 @@ def parse(dump : str) -> Session:
return session
else:
return SessionManager.parse_legacy(dump)

# endregion
# endregion

sessionManager = SessionManager()

Expand All @@ -257,6 +283,11 @@ def SetNewSession():
sessionManager.set(Session())


def CreateNewSession() -> Session:
"""创建新 Session 实例"""
return Session()


def LoadSessionFromString(dump: str) -> Session:
"""从 `str` 加载 Session / 登录态"""
session = SessionManager.parse(dump)
Expand Down

0 comments on commit 6cafa0d

Please sign in to comment.