├── requirements.txt ├── .gitignore ├── .github └── workflows │ └── main.yml ├── README.md ├── settings.py └── main.py /requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2023.7.22 2 | chardet==4.0.0 3 | idna==2.10 4 | requests==2.31.0 5 | urllib3==1.26.18 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | __pycache__ 21 | 22 | # Installer logs 23 | pip-log.txt 24 | 25 | # Unit tmp / coverage reports 26 | .coverage 27 | .tox 28 | nosetests.xml 29 | .pytest_cache 30 | 31 | # Translations 32 | *.mo 33 | 34 | # Mr Developer 35 | .mr.developer.cfg 36 | .project 37 | .pydevproject 38 | 39 | # temp file 40 | .DS_Store 41 | *.pkl 42 | 43 | # venv 44 | .venv/ 45 | 46 | # Cookiecutter 47 | output/ 48 | 49 | # vscode 50 | .vscode 51 | 52 | # notebooks 53 | notebooks/ 54 | 55 | # idea 56 | .idea 57 | .python-version 58 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: "Tencent Video Helper" 2 | 3 | on: 4 | schedule: 5 | - cron: "0 1 * * *" # scheduled at 09:00 (UTC+8) everyday 6 | workflow_dispatch: 7 | 8 | env: 9 | RUN_ENV: 'prod' 10 | TZ: 'Asia/Shanghai' 11 | SCKEY: ${{ secrets.SCKEY }} 12 | AUTH_REFRESH_URL: ${{ secrets.AUTH_REFRESH_URL }} 13 | AUTH_REFRESH_COOKIE: ${{ secrets.AUTH_REFRESH_COOKIE }} 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | # if: github.ref == 'refs/heads/master' 19 | 20 | steps: 21 | - name: Checkout master 22 | uses: actions/checkout@v2 23 | with: 24 | fetch-depth: 0 25 | ref: master 26 | 27 | - name: Set up python 28 | uses: actions/setup-python@v2 29 | with: 30 | python-version: 3.8 31 | 32 | - name: Random sleep 33 | if: github.event_name == 'schedule' 34 | run: sleep $(shuf -i 10-300 -n 1) 35 | 36 | - name: Run sign 37 | run: | 38 | python -m pip install --upgrade pip 39 | pip install -r requirements.txt 40 | python3 ./main.py 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

3 | Tencent Video Helper 4 |

5 | 6 | [![GitHub issues](https://img.shields.io/github/issues/PomeloWang/my-actions?style=flat-square)](https://github.com/PomeloWang/my-actions/issues) 7 | [![GitHub contributors](https://img.shields.io/github/contributors/PomeloWang/my-actions?style=flat-square)](https://github.com/PomeloWang/my-actions/graphs/contributors) 8 | ![Tencent Video Helper](https://img.shields.io/github/workflow/status/PomeloWang/my-actions/Tencent%20Video%20Helper?label=status&style=flat-square) 9 |
10 | 11 | > 吹水交流:[130516740](https://qm.qq.com/cgi-bin/qm/qr?k=_M9lYFxkYD7yQQR2btyG3pkZWFys_I-l&authKey=evGDzE2eFVBm46jsHpgcWrokveg70Z9GKl3H45o0oJuia620UGeO27lDPG9gKb/2&noverify=0) 12 | ### 部署 13 | - `AUTH_REFRESH_URL` 腾讯视频官网, 打开浏览器控制台网络搜索`auth_refresh`相关的请求[图片教程](https://cdn.jsdelivr.net/gh/BlueskyClouds/Script/img/2020/11/1/img/v_1.jpg) 14 | - `AUTH_REFRESH_COOKIE` 从上面找到的请求中复制`Cookie`[图片教程](https://cdn.jsdelivr.net/gh/BlueskyClouds/Script/img/2020/11/1/img/v_2.jpg) 15 | - `SCKEY` 详情参考 [SERVER酱官网](http://sc.ftqq.com/3.version) 16 | 17 | 18 | #### 其他 19 | - 如果二次签到失败,尝试手动从手机`app`签到一次。私信任意用户然后发送并点击链接`http://v.qq.com/x/bu/mobile_checkin`, 点击链接后会签到一次。然后次日在观察执行结果 20 | -------------------------------------------------------------------------------- /settings.py: -------------------------------------------------------------------------------- 1 | # settings 2 | import logging 3 | 4 | import os 5 | 6 | __all__ = ['log', 'CONFIG'] 7 | 8 | logging.basicConfig( 9 | level=logging.INFO, 10 | format='%(asctime)s %(levelname)s %(message)s', 11 | datefmt='%Y-%m-%dT%H:%M:%S') 12 | 13 | 14 | log = logger = logging 15 | 16 | 17 | default_user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' \ 18 | 'Chrome/64.0.3282.204 Safari/537.36 ' 19 | 20 | 21 | class _Config: 22 | AUTH_REFRESH_URL = os.environ['AUTH_REFRESH_URL'] 23 | AUTH_REFRESH_COOKIE: dict = os.environ['AUTH_REFRESH_COOKIE'] 24 | HEADERS = { 25 | 'Referer': 'https://v.qq.com', 26 | 'User-Agent': default_user_agent, 27 | 'Cookie': AUTH_REFRESH_COOKIE 28 | } 29 | SIGN_URL = 'https://vip.video.qq.com/fcgi-bin/comm_cgi?name=hierarchical_task_system&cmd=2' 30 | MOBILE_CHECKIN = 'http://v.qq.com/x/bu/mobile_checkin?isDarkMode=0&uiType=REGULAR' 31 | SCKEY = os.environ.get('SCKEY', '') 32 | 33 | 34 | class ProductionConfig(_Config): 35 | LOG_LEVEL = logging.INFO 36 | 37 | 38 | class DevelopmentConfig(_Config): 39 | LOG_LEVEL = logging.DEBUG 40 | 41 | 42 | RUN_ENV = os.environ.get('RUN_ENV', 'dev') 43 | if RUN_ENV == 'dev': 44 | CONFIG = DevelopmentConfig() 45 | else: 46 | CONFIG = ProductionConfig() 47 | 48 | log.basicConfig(level=CONFIG.LOG_LEVEL) 49 | 50 | 51 | MESSGAE_TEMPLATE = ''' 52 | ``` 53 | {today:#^30} 54 | 🔅[{nick}] 55 | 签到积分: {checkin_score} 56 | 签到结果: {message} 57 | 手机签到: {mobile_checkin} 58 | {end:#^30} 59 | ```''' 60 | 61 | CONFIG.MESSGAE_TEMPLATE = MESSGAE_TEMPLATE 62 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import json 3 | import re 4 | import urllib.parse 5 | 6 | import requests 7 | 8 | from settings import * 9 | 10 | request = requests.session() 11 | 12 | today = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') 13 | 14 | 15 | def to_python(json_str: str): 16 | return json.loads(json_str) 17 | 18 | 19 | def to_json(obj): 20 | return json.dumps(obj, indent=4, ensure_ascii=False) 21 | 22 | 23 | def cookie_2_python(cookie): 24 | obj = {} 25 | for header in cookie.split(";"): 26 | param = header.split("=") 27 | obj[param[0].strip()] = param[1] 28 | return obj 29 | 30 | 31 | def cookie_2_param(cookie_obj: dict): 32 | param = "" 33 | for k, v in cookie_obj.items(): 34 | param += "{k}={v}; ".format(**locals()) 35 | return param[:-2] 36 | 37 | 38 | def decode_json_str(s): 39 | pattern = re.compile('{.*}') 40 | return json.loads(pattern.search(s).group()) 41 | 42 | 43 | def decode_urldecode(s): 44 | return urllib.parse.unquote(s) 45 | 46 | 47 | def notify(title, message): 48 | if not CONFIG.SCKEY: 49 | log.info("未配置SCKEY,正在跳过推送") 50 | return 51 | 52 | log.info("准备推送通知...") 53 | urlencode = urllib.parse.urlencode 54 | url = 'https://sctapi.ftqq.com/{}.send?{}&{}'.format(CONFIG.SCKEY, urlencode({'title': title}), urlencode({'desp': message})) 55 | 56 | try: 57 | response = to_python(requests.post(url).text) 58 | # {"code":0,"message":"","data":{"pushid":"1111","readkey":"xxxx","error":"SUCCESS","errno":0}} 59 | log.info('推送结果: {}'.format(response.get('data', {'error': 'no data'}).get('error', ''))) 60 | except Exception as e: 61 | log.error('{}: {}'.format("推送异常", e)) 62 | return log.info('任务结束') 63 | 64 | 65 | 66 | 67 | def main(): 68 | message = { 69 | 'today': today, 70 | 'ret': -1, 71 | 'checkin_score': "-1", 72 | 'mobile_checkin': "失败", 73 | 'end': '' 74 | } 75 | # 主要是判断是否登陆成功以及刷新cookie参数 76 | response = request.get(url=CONFIG.AUTH_REFRESH_URL, headers=CONFIG.HEADERS).text 77 | auth_refresh_obj = decode_json_str(response) 78 | 79 | if (auth_refresh_obj.get('errcode', 9999) != 0) or (not auth_refresh_obj.get('nick', None)): 80 | log.error("刷新cookie参数失败, {msg}".format(**auth_refresh_obj)) 81 | message.update({ 82 | 'ret': auth_refresh_obj.get('errcode', -1), 83 | 'nick': decode_urldecode(auth_refresh_obj.get('nick', "刷新Cookie参数失败, 未获取到用户信息")), 84 | }) 85 | log.error("签到失败", CONFIG.MESSGAE_TEMPLATE.format(**message)) 86 | notify("腾讯视频 签到失败", CONFIG.MESSGAE_TEMPLATE.format(**message)) 87 | exit(-1) 88 | 89 | old_cookie_obj = cookie_2_python(CONFIG.HEADERS['Cookie']) 90 | need_update_fields = { 91 | 'vuserid': 'vqq_vuserid', 92 | 'vusession': 'vqq_vusession', 93 | 'access_token': 'vqq_access_token' 94 | } 95 | 96 | log.info("更新Cookie参数") 97 | # 更新Cookie参数 98 | for k, v in need_update_fields.items(): 99 | old_cookie_obj[v] = auth_refresh_obj[k] 100 | 101 | # 使用更新过的Cookie参数替换CONFIG.HEADERS中的Cookie参数 102 | CONFIG.HEADERS.update({ 103 | 'Cookie': cookie_2_param(old_cookie_obj), 104 | 'Referer': 'https://m.v.qq.com' 105 | }) 106 | log.info("更新Cookie参数成功, 开始签到") 107 | 108 | # QZOutputJson=({ "ret": 0,"checkin_score": 0,"msg":"OK"}); 109 | sign_response = request.get(url=CONFIG.SIGN_URL, headers=CONFIG.HEADERS).text 110 | sign_obj = decode_json_str(sign_response) 111 | 112 | message.update({ 113 | 'ret': sign_obj['ret'], 114 | 'nick': decode_urldecode(auth_refresh_obj['nick']), 115 | 'message': sign_obj['msg'], 116 | 'checkin_score': sign_obj.get('checkin_score', 0) or "👀 今日已签到了哦" 117 | 118 | }) 119 | # TODO 手机签到失败不会重置任务状态 120 | m_checkin_response = request.get(url=CONFIG.MOBILE_CHECKIN, headers=CONFIG.HEADERS).text 121 | 122 | if "page_signin_detail" in m_checkin_response: 123 | message.update({'mobile_checkin': "成功"}) 124 | log.info("签到成功 {}".format(CONFIG.MESSGAE_TEMPLATE.format(**message))) 125 | notify("腾讯视频 签到成功", CONFIG.MESSGAE_TEMPLATE.format(**message)) 126 | 127 | 128 | if __name__ == '__main__': 129 | try: 130 | main() 131 | except Exception as e: 132 | notify("腾讯视频 签到失败", { 133 | "msg": "请前往执行日志查看详情", 134 | "err": str(e) 135 | }) 136 | raise e 137 | --------------------------------------------------------------------------------