Skip to content

Commit

Permalink
Merge pull request #1 from cc004/main
Browse files Browse the repository at this point in the history
[pull] main from cc004:main
  • Loading branch information
666dechaoge authored Aug 9, 2024
2 parents 208ec40 + e28e208 commit f8fe9f0
Show file tree
Hide file tree
Showing 14 changed files with 235 additions and 102 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ py -3.8 httpserver_test.py

使用前请更新Hoshino到最新版,并**更新Hoshino的配置文件`__bot__.py`**

## 渠道服支持

渠道服需要自抓`uid``access_key`,作为用户名和密码。

## Credits
- aiorequests 来自 [HoshinoBot](https://github.com/Ice-Cirno/HoshinoBot)
- 图片绘制改自 [convert2img](https://github.com/SonderXiaoming/convert2img)
Expand Down
35 changes: 0 additions & 35 deletions autopcr/bsdk/bsdkclient.py

This file was deleted.

11 changes: 9 additions & 2 deletions autopcr/constants.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import os

BSDK = '官服'
QSDK = '渠道服'

CHANNEL_OPTION = [BSDK, QSDK]

DEBUG_LOG = False
ERROR_LOG = True
ROOT_DIR = os.path.join(os.path.dirname(__file__), '..')
CACHE_DIR = os.path.join(ROOT_DIR, './cache/')
RESULT_DIR = os.path.join(ROOT_DIR, './result/')
Expand All @@ -26,7 +33,7 @@
'LOCALE': 'CN',
'PLATFORM-OS-VERSION': 'Android OS 5.1.1 / API-22 (LMY48Z/rel.se.infra.20200612.100533)',
'REGION-CODE': '',
'RES-KEY': 'ab00a0a6dd915a052a2ef7fd649083e5',
# 'RES-KEY': 'ab00a0a6dd915a052a2ef7fd649083e5',
'RES-VER': '10002200',
'SHORT-UDID': '0'
}
Expand All @@ -48,7 +55,7 @@
'LOCALE': 'CN',
'PLATFORM-OS-VERSION': 'iOS 17.3',
'REGION-CODE': '',
'RES-KEY': 'ab00a0a6dd915a052a2ef7fd649083e5',
# 'RES-KEY': 'ab00a0a6dd915a052a2ef7fd649083e5',
'RES-VER': '10002200',
'SHORT-UDID': '0'
}
Expand Down
57 changes: 34 additions & 23 deletions autopcr/core/apiclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
from hashlib import md5
from Crypto.Cipher import AES
from base64 import b64encode, b64decode
from traceback import print_exc
from ..constants import DEFAULT_HEADERS, IOS_HEADERS, refresh_headers
from .sdkclient import sdkclient
from ..constants import refresh_headers, DEBUG_LOG, ERROR_LOG

import json
from enum import Enum
Expand Down Expand Up @@ -51,20 +51,16 @@ class NetworkException(Exception):
class apiclient(Container["apiclient"]):
server_time: int = 0
viewer_id: int = 0
servers: list = ['https://l3-prod-all-gs-gzlj.bilibiligame.net/']
servers: list = [] #['https://l3-prod-all-gs-gzlj.bilibiligame.net/']
active_server: int = 0
_requestid: str = ''
_sessionid: str= ''
def __init__(self, account):
def __init__(self, sdk: sdkclient):
super().__init__()
self._headers = {}
platform = account['platform']
if platform == 2:
for key in DEFAULT_HEADERS.keys():
self._headers[key] = DEFAULT_HEADERS[key]
else:
for key in IOS_HEADERS.keys():
self._headers[key] = IOS_HEADERS[key]
self._headers = sdk.header()
self.servers = [
sdk.apiroot
]
self._lck = Lock()

@property
Expand Down Expand Up @@ -134,10 +130,14 @@ async def _request_internal(self, request: Request[TResponse]) -> TResponse:

response1 = apiclient._no_null_key(response0)

# with open('req.log', 'a') as fp:
# fp.write(json.dumps(response0))
# fp.write("\n-------\n")
# fp.write(json.dumps(response1))
if DEBUG_LOG:
with open('req.log', 'a') as fp:
fp.write(f'{self.name} requested {request.__class__.__name__} at /{request.url}\n')
fp.write(json.dumps(self._headers, indent=4, ensure_ascii=False) + '\n')
fp.write(json.dumps(json.loads(request.json(by_alias=True)), indent=4, ensure_ascii=False) + '\n')
fp.write(f'response from {urlroot}\n')
fp.write(json.dumps(dict(resp.headers), indent=4, ensure_ascii=False) + '\n')
fp.write(json.dumps(response0, indent=4, ensure_ascii=False) + '\n')

response: Response[TResponse] = Response[cls].parse_obj(response1)

Expand Down Expand Up @@ -172,13 +172,24 @@ async def _request_internal(self, request: Request[TResponse]) -> TResponse:


if response.data.server_error and "维护" not in response.data.server_error.message:
print(f'pcrclient: /{request.url} api failed {response.data.server_error}')

with open('error.log', 'a') as fp:
fp.write(f'{self.name} requested {request.__class__.__name__} at /{request.url}\n')
fp.write(json.dumps(self._headers, indent=4, ensure_ascii=False) + '\n')
fp.write(json.dumps(json.loads(request.json(by_alias=True)), indent=4, ensure_ascii=False) + '\n')
fp.write(json.dumps(json.loads(response.json(by_alias=True)), indent=4, ensure_ascii=False) + '\n')
print(f'pcrclient: /{request.url} api failed={response.data_headers.result_code} {response.data.server_error}')

if ERROR_LOG:
with open('error.log', 'a') as fp:
fp.write(f'{self.name} requested {request.__class__.__name__} at /{request.url}\n')
fp.write(json.dumps(self._headers, indent=4, ensure_ascii=False) + '\n')
fp.write(json.dumps(json.loads(request.json(by_alias=True)), indent=4, ensure_ascii=False) + '\n')
fp.write(f'response from {urlroot}\n')
fp.write(json.dumps(dict(resp.headers), indent=4, ensure_ascii=False) + '\n')
fp.write(json.dumps(response0, indent=4, ensure_ascii=False) + '\n')

self.active_server = (self.active_server + 1) % len(self.servers)

#with open('error.log', 'a') as fp:
# fp.write(f'{self.name} requested {request.__class__.__name__} at /{request.url}\n')
# fp.write(json.dumps(self._headers, indent=4, ensure_ascii=False) + '\n')
# fp.write(json.dumps(json.loads(request.json(by_alias=True)), indent=4, ensure_ascii=False) + '\n')
# fp.write(json.dumps(json.loads(response.json(by_alias=True)), indent=4, ensure_ascii=False) + '\n')

raise ApiException(response.data.server_error.message,
response.data.server_error.status,
Expand Down
7 changes: 4 additions & 3 deletions autopcr/core/pcrclient.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from ..model.models import *
from .apiclient import apiclient
from .sdkclient import sdkclient
from .sessionmgr import sessionmgr
from .misc import errorhandler
from .datamgr import datamgr
Expand All @@ -8,11 +9,11 @@
import typing

class pcrclient(apiclient):
def __init__(self, platform, *args, **kwargs):
super().__init__(platform)
def __init__(self, sdk: sdkclient, *args, **kwargs):
super().__init__(sdk)
self.keys = {}
self.data = datamgr()
self.session = sessionmgr(platform, *args, **kwargs)
self.session = sessionmgr(sdk, *args, **kwargs)
self.register(errorhandler())
self.register(self.data)
self.register(self.session)
Expand Down
82 changes: 82 additions & 0 deletions autopcr/core/sdkclient.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
from enum import Enum
from typing import Tuple
from abc import abstractmethod
from ..sdk.validator import autoValidator
from ..sdk.bsgamesdk import captch
from copy import deepcopy
from ..constants import DEFAULT_HEADERS, IOS_HEADERS

class platform(Enum):
Android = 0,
IOS = 1

class account:
type: platform
username: str
password: str

def __init__(self, usr: str, pwd: str, type: platform):
self.username = usr
self.password = pwd
self.type = type

async def _defaultLogger(msg):
print(msg)

class sdkclient:

def __init__(self, info: account, captchaVerifier=autoValidator, errlogger=_defaultLogger):
self.captchaVerifier = captchaVerifier
self.errlogger = errlogger
if info.type == platform.Android:
self.platform = '2'
elif info.type == platform.IOS:
self.platform = '1000'
else:
raise ValueError(f"Invalid platform {info.type}")
self._account = info
'''
returns: uid, access_key
'''
@abstractmethod
async def login(self) -> Tuple[str, str]: ...

async def do_captcha(self):
cap = await captch()
return await self.captchaVerifier(self.account, cap['gt'], cap['challenge'], cap['gt_user_id'])

def header(self):
if self._account.type == platform.Android:
headers = deepcopy(DEFAULT_HEADERS)
elif self._account.type == platform.IOS:
headers = deepcopy(IOS_HEADERS)
else:
raise ValueError(f"Invalid platform {self._account.type}")

headers['RES-KEY'] = self.reskey
headers['PLATFORM'] = self.platform
headers['PLATFORM-ID'] = self.platform_id
headers['CHANNEL-ID'] = self.channel

return headers

@property
@abstractmethod
def apiroot(self) -> str: ...

@property
@abstractmethod
def platform_id(self) -> str: ...

@property
def channel(self):
return '1'

@property
def account(self):
return self._account.username

@property
@abstractmethod
def reskey(self) -> str: ...

38 changes: 17 additions & 21 deletions autopcr/core/sessionmgr.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,28 @@
from .base import Component, RequestHandler
from .apiclient import apiclient, ApiException
from ..bsdk.bsdkclient import bsdkclient
from .sdkclient import sdkclient
import json, os, random
from ..model.models import *
from ..constants import CACHE_DIR
import hashlib

class sessionmgr(Component[apiclient]):
def __init__(self, account, *arg, **kwargs):
def __init__(self, sdk: sdkclient, *arg, **kwargs):
super().__init__()
self.cacheDir = os.path.join(CACHE_DIR, 'token')
self.bsdk = bsdkclient(account, *arg, **kwargs)
self._platform = self.bsdk.platform
self._channel = self.bsdk.channel
self._account = account
self.sdk = sdk
self._platform = self.sdk.platform_id
self._channel = self.sdk.channel
self._account: str = sdk.account
self._logged = False
self.auto_relogin = True
self._sdkaccount = None
if not os.path.exists(self.cacheDir):
os.makedirs(self.cacheDir)
self.cacheFile = os.path.join(self.cacheDir, hashlib.md5(account['account'].encode('utf-8')).hexdigest())

def register_to(self, container: apiclient):
container._headers['PLATFORM'] = str(self._account['platform'])
container._headers['PLATFORM-ID'] = str(self._account['platform'])
container._headers['CHANNEL-ID'] = str(self._account['channel'])
return super().register_to(container)
self.cacheFile = os.path.join(self.cacheDir, hashlib.md5(self._account.encode('utf-8')).hexdigest())

async def _bililogin(self):
uid, access_key = await self.bsdk.login()
uid, access_key = await self.sdk.login()
self._sdkaccount = {
'uid': uid,
'access_key': access_key
Expand All @@ -51,9 +45,7 @@ async def _ensure_token(self, next: RequestHandler):
break
else:
for _ in range(5):
from ..bsdk.bsgamesdk import captch
cap=await captch()
captch_done=await self.bsdk.captchaVerifier(self.bsdk.account, cap['gt'], cap['challenge'], cap['gt_user_id'])
captch_done = await self.sdk.do_captcha()
req = ToolSdkLoginRequest(
uid=self._sdkaccount['uid'],
access_key=self._sdkaccount['access_key'],
Expand All @@ -80,17 +72,21 @@ async def _ensure_token(self, next: RequestHandler):
except Exception:
raise
finally:
from ..bsdk.validator import validate_dict, ValidateInfo
validate_dict[self._account['account']] = ValidateInfo(status="ok")
from ..sdk.validator import validate_dict, ValidateInfo
validate_dict[self._account] = ValidateInfo(status="ok")

async def _login(self, next: RequestHandler):
if os.path.exists(self.cacheFile):
with open(self.cacheFile, 'r') as fp:
self._sdkaccount = json.load(fp)
while True:
try:
self._container.servers = [f'http://{server}'.replace('\t', '') for server in (await next.request(SourceIniIndexRequest())).server]
self._container.active_server = 0
current = self._container.servers[self._container.active_server]
self._container.servers = [f'https://{server}'.replace('\t', '') for server in (await next.request(SourceIniIndexRequest())).server]
try:
self._container.active_server = self._container.servers.index(current)
except ValueError:
self._container.active_server = 0
manifest = await next.request(SourceIniGetMaintenanceStatusRequest())
self._container._headers['MANIFEST-VER'] = manifest.required_manifest_ver
if manifest.maintenance_message:
Expand Down
10 changes: 6 additions & 4 deletions autopcr/http_server/httpserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,10 @@ async def update_account(account: Account):
data = await request.get_json()
if 'username' in data:
account.data.username = data['username']
if 'password' in data:
if 'password' in data and data['password'] != '*' * 8:
account.data.password = data['password']
if 'channel' in data:
account.data.channel = data['channel']
return "保存账户信息成功", 200
elif request.method == "DELETE":
account.delete()
Expand Down Expand Up @@ -269,7 +271,7 @@ async def single_result(mgr: Account, order: str):
@HttpServer.wrapaccountmgr(readonly = True)
@HttpServer.wrapaccount(readonly = True)
async def query_validate(mgr: Account):
from ..bsdk.validator import validate_dict, ValidateInfo
from ..sdk.validator import validate_dict, ValidateInfo
if mgr.data.username not in validate_dict:
return ValidateInfo(status="empty").to_dict(), 200
else:
Expand All @@ -280,11 +282,11 @@ async def query_validate(mgr: Account):
@self.api.route('/validate', methods = ['POST'])
async def validate(): # TODO think to check login or not
data = await request.get_json()
from ..bsdk.validator import validate_ok_dict
from ..sdk.validator import validate_ok_dict
if 'id' not in data:
return "incorrect", 403
id = data['id']
from ..bsdk.validator import ValidateInfo
from ..sdk.validator import ValidateInfo
validate_ok_dict[id] = ValidateInfo.from_dict(data)
return "", 200

Expand Down
Loading

0 comments on commit f8fe9f0

Please sign in to comment.