Evilmass commited on
Commit
65d3d39
·
1 Parent(s): 5448935
.gitignore ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # cache
2
+ __pycache__/
3
+ sync.ffs_db
4
+ *.pyc
5
+
6
+ # file
7
+ cookie/
8
+ !cookie/.gitkeep
9
+ log/
10
+ !log/.gitkeep
11
+
12
+ # dev
13
+ config/settings_dev.py
14
+
15
+ # test
16
+ test.py
Dockerfile ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # build cache
2
+ FROM python:3.9-slim-bullseye as builder
3
+
4
+ WORKDIR /tmp
5
+
6
+ # depends
7
+ RUN apt-get update -y
8
+
9
+ # pip
10
+ COPY ./requirements.txt /tmp/requirements.txt
11
+ RUN pip install -r /tmp/requirements.txt
12
+
13
+ # playwright
14
+ RUN playwright install-deps
15
+
16
+ # Set up a new user named "user" with user ID 1000
17
+ RUN useradd -m -u 1000 user
18
+
19
+ # Switch to the "user" user
20
+ USER user
21
+
22
+ # Set home to the user's home directory
23
+ ENV HOME=/home/user \
24
+ PATH=/home/user/.local/bin:$PATH
25
+
26
+ # Set the working directory to the user's home directory
27
+ WORKDIR $HOME/app
28
+
29
+ RUN mkdir $HOME/app/cookie $HOME/app/log $HOME/app/_playwright $HOME/app/config
30
+
31
+ # Try and run pip command after setting the user with `USER user` to avoid permission issues with Python
32
+ RUN playwright install chromium firefox
33
+
34
+ # use cache build
35
+ FROM builder
36
+
37
+ # Copy the current directory contents into the container at $HOME/app setting the owner to the user
38
+ COPY --chown=user . $HOME/app
39
+
40
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
__init__.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 全局变量 DIR_PATH 不能在其他地方用同一个命名,会被替换
2
+ import sys
3
+ from os.path import abspath, dirname
4
+
5
+
6
+ DEBUG = False
7
+ if DEBUG:
8
+ DIR_PATH = abspath(dirname(__file__))
9
+ sys.path.append(DIR_PATH)
10
+ from config.settings_dev import *
11
+ else:
12
+ DIR_PATH = "/home/user/app"
13
+ sys.path.append(DIR_PATH)
14
+ from config.settings_prod import *
_playwright/[no_use]aliyundrive.py ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding:utf-8
2
+ import sys
3
+ import asyncio
4
+
5
+ from os.path import abspath, dirname, join
6
+ from playwright.async_api import async_playwright
7
+
8
+ sys.path.append(join(dirname(abspath(__file__)), "../"))
9
+
10
+ from utils import push_msg
11
+ from __init__ import (
12
+ browser_headless,
13
+ browser_proxy,
14
+ aliyundrive_url,
15
+ aliyundrive_cookie_file,
16
+ aliyundrive_title,
17
+ aliyundrive_logger,
18
+ )
19
+
20
+
21
+ # 判断登录状态
22
+ async def is_login(page):
23
+ await page.goto(aliyundrive_url)
24
+ # page.locator("li").filter(has_text="回收站").get_by_role("img").click()
25
+ if page.get_by_text("回收站").is_visible(): # 加 await 就会在页面加载完成前跳过
26
+ aliyundrive_logger.info("登录成功")
27
+ return True
28
+ else:
29
+ stderr = "Cookie 过期"
30
+ aliyundrive_logger.error(stderr)
31
+ push_msg(aliyundrive_title, stderr)
32
+ return False
33
+
34
+
35
+ # 签到
36
+ async def sign(page):
37
+ msg = []
38
+
39
+ if not await is_login(page):
40
+ return "aliyundrive_not_login"
41
+
42
+ # await page.pause()
43
+
44
+ if page.get_by_text("待领取").is_visible():
45
+ sign_res = "今日已签到"
46
+ aliyundrive_logger.info(sign_res)
47
+ msg.append(sign_res)
48
+ # 领取奖励
49
+ await page.get_by_text("待领取").click()
50
+ reward_res = "今日领取奖励成功"
51
+ aliyundrive_logger.info(reward_res)
52
+ elif page.get_by_text("待签到").is_visible():
53
+ await page.get_by_text("待签到").click()
54
+ sign_res = "签到成功"
55
+ aliyundrive_logger.info(sign_res)
56
+ msg.append(sign_res)
57
+ else:
58
+ reward_res = "今日奖励已领取"
59
+ aliyundrive_logger.info(reward_res)
60
+ return "\n".join(msg)
61
+
62
+
63
+ async def main():
64
+ async with async_playwright() as playwright:
65
+ browser = await playwright.chromium.launch(headless=browser_headless)
66
+ context = await browser.new_context(storage_state=aliyundrive_cookie_file)
67
+ page = await context.new_page()
68
+ task = asyncio.create_task(sign(page))
69
+ await asyncio.gather(task)
70
+ # 退出
71
+ await page.close()
72
+ await browser.close()
73
+ # 推送
74
+ result = task.result()
75
+ push_msg(aliyundrive_title, "\n".join([result]))
76
+
77
+
78
+ if __name__ == "__main__":
79
+ asyncio.run(main())
_playwright/bilibili.py ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding:utf-8
2
+ import sys
3
+ import asyncio
4
+
5
+ from datetime import datetime
6
+ from os.path import abspath, dirname, join
7
+ from playwright.async_api import async_playwright
8
+
9
+ sys.path.append(join(dirname(abspath(__file__)), "../"))
10
+ from utils import push_msg, get_bilibili_live_rooms_from_pi
11
+ from __init__ import (
12
+ browser_headless,
13
+ browser_proxy,
14
+ bilibili_url,
15
+ bilibili_sign_url,
16
+ bilibili_live_url,
17
+ bilibili_cookie_file,
18
+ bilibili_title,
19
+ bilibili_logger,
20
+ )
21
+
22
+ bilibili_live_rooms = get_bilibili_live_rooms_from_pi()
23
+
24
+
25
+ # 判断登录状态
26
+ async def is_login(page):
27
+ await page.goto(bilibili_url)
28
+ if await page.get_by_text("修改资料").is_visible(timeout=2000):
29
+ bilibili_logger.info("登录成功")
30
+ return True
31
+ else:
32
+ stderr = "Cookie 过期"
33
+ bilibili_logger.error(stderr)
34
+ push_msg(bilibili_title, stderr)
35
+ return False
36
+
37
+
38
+ # 签到
39
+ async def sign(page):
40
+ msg = []
41
+
42
+ if not await is_login(page):
43
+ return "bilibili_not_login"
44
+
45
+ await page.goto(bilibili_sign_url)
46
+ if await page.get_by_text("无法重复签到").is_visible():
47
+ sign_res = f"签到时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n签到状态:今日已签到"
48
+ bilibili_logger.info(sign_res)
49
+ msg.append(sign_res)
50
+ elif await page.get_by_text('"code":0').is_visible():
51
+ sign_res = f"签到时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n签到状态:签到成功"
52
+ bilibili_logger.info(sign_res)
53
+ msg.append(sign_res)
54
+ else:
55
+ sign_res = f"签到失败"
56
+ bilibili_logger.error(sign_res)
57
+ push_msg(bilibili_title, sign_res)
58
+ msg.append(sign_res)
59
+
60
+ return "\n".join(msg)
61
+
62
+
63
+ # 直播间打卡
64
+ async def live(page):
65
+ msg = []
66
+
67
+ if not await is_login(page):
68
+ return "bilibili_not_login"
69
+
70
+ for room_id in list(bilibili_live_rooms.keys()):
71
+ await page.goto(f"{bilibili_live_url}/{str(room_id)}")
72
+ # 输入框选择 xpath 绝对定位
73
+ input_box = await page.locator(
74
+ "xpath=/html/body/div[3]/main/div[1]/section[1]/div[3]/div[12]/div/div[2]/div[2]/textarea",
75
+ )
76
+ # 输入内容
77
+ await input_box.fill("1")
78
+ # 发送按钮
79
+ send_button = await page.locator(
80
+ "xpath=/html/body/div[3]/main/div[1]/section[1]/div[3]/div[12]/div/div[3]/div/button/span"
81
+ )
82
+ if await send_button.is_visible():
83
+ # 点击发送按钮
84
+ await send_button.click()
85
+ room_msg = (
86
+ f"直播间:【{bilibili_live_rooms[room_id]}】打卡成功,打卡时间:【{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}】"
87
+ )
88
+ bilibili_logger.info(room_msg)
89
+ else:
90
+ room_msg = (
91
+ f"直播间:【{bilibili_live_rooms[room_id]}】打卡失败,打卡时间:【{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}】"
92
+ )
93
+ bilibili_logger.error(room_msg)
94
+ msg.append(room_msg)
95
+
96
+ return "\n".join(msg)
97
+
98
+
99
+ async def bilibili_sign():
100
+ async with async_playwright() as playwright:
101
+ browser = await playwright.firefox.launch(headless=browser_headless)
102
+ context = await browser.new_context(storage_state=bilibili_cookie_file)
103
+ # 签到
104
+ sign_page = await context.new_page()
105
+ sign_task = asyncio.create_task(sign(sign_page))
106
+ await asyncio.gather(sign_task)
107
+ await sign_page.close()
108
+ # 直播间打卡
109
+ live_page = await context.new_page()
110
+ live_task = asyncio.create_task(live(live_page))
111
+ await asyncio.gather(live_task)
112
+ await live_page.close()
113
+ # 退出
114
+ await browser.close()
115
+ # 推送
116
+ sign_result = sign_task.result()
117
+ live_result = live_task.result()
118
+ # ""分割两个服务的消息
119
+ push_msg(bilibili_title, "\n".join([sign_result, "", live_result]))
120
+
121
+
122
+ if __name__ == "__main__":
123
+ asyncio.run(bilibili_sign())
_playwright/tsdm.py ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding:utf-8
2
+ import sys
3
+ import random
4
+ import asyncio
5
+
6
+ from os.path import abspath, dirname, join
7
+ from playwright.async_api import async_playwright
8
+
9
+ sys.path.append(join(dirname(abspath(__file__)), "../"))
10
+
11
+ from utils import push_msg
12
+ from __init__ import (
13
+ browser_headless,
14
+ browser_proxy,
15
+ tsdm_url,
16
+ tsdm_sign_url,
17
+ tsdm_cliwork_url,
18
+ tsdm_plugin_id,
19
+ tsdm_minds,
20
+ tsdm_cookie_file,
21
+ tsdm_title,
22
+ tsdm_logger,
23
+ )
24
+
25
+
26
+ # 判断登录状态
27
+ async def is_login(page):
28
+ await page.goto(tsdm_url)
29
+ if await page.get_by_text("用户组").is_visible():
30
+ tsdm_logger.info("登录成功")
31
+ return True
32
+ else:
33
+ stderr = "Cookie 过期"
34
+ tsdm_logger.error(stderr)
35
+ push_msg(tsdm_title, stderr)
36
+ return False
37
+
38
+
39
+ # 签到
40
+ async def sign(page):
41
+ msg = []
42
+
43
+ if not await is_login(page):
44
+ return "tsdm_not_login"
45
+
46
+ # 签到
47
+ await page.goto(tsdm_sign_url)
48
+ if await page.get_by_text("今天已签到").is_visible():
49
+ sign_res = "今天已签到"
50
+ tsdm_logger.info(sign_res)
51
+ msg.append(sign_res)
52
+ else:
53
+ mind = random.choice(list(tsdm_minds.values()))
54
+ tsdm_logger.info(f"签到心情选择:{mind}")
55
+ await page.locator(
56
+ "#ct > div > div.bm.mtn > div.bm_c > form > select"
57
+ ).select_option(label=mind)
58
+ await page.get_by_label("不想填写").check()
59
+ await page.get_by_text("点我签到!").click()
60
+ sign_res = "签到成功"
61
+ tsdm_logger.info(sign_res)
62
+ msg.append(sign_res)
63
+
64
+ return "\n".join(msg)
65
+
66
+
67
+ async def cliwork(page):
68
+ msg = []
69
+
70
+ if not await is_login(page):
71
+ return "tsdm_not_login"
72
+
73
+ # 打工
74
+ await page.goto(tsdm_url) # 切换回电脑版
75
+ await page.goto(tsdm_cliwork_url)
76
+ if await page.get_by_text("您需要等待").is_visible():
77
+ has_work = "今天已打工"
78
+ tsdm_logger.info(has_work)
79
+ msg.append(has_work)
80
+ else:
81
+ for pid in tsdm_plugin_id:
82
+ await page.locator(f"#np_advid{pid} > a > img").click()
83
+ await page.bring_to_front() # 回到第一个标签
84
+ await page.locator("#workstart").click() # 领取奖励
85
+ work_res = "打工成功"
86
+ tsdm_logger.info(work_res)
87
+ msg.append(work_res)
88
+
89
+ return "\n".join(msg)
90
+
91
+
92
+ async def tsdm_sign():
93
+ async with async_playwright() as playwright:
94
+ browser = await playwright.chromium.launch(headless=browser_headless)
95
+ context = await browser.new_context(storage_state=tsdm_cookie_file)
96
+ # 签到
97
+ sign_page = await context.new_page()
98
+ sign_task = asyncio.create_task(sign(sign_page))
99
+ await asyncio.gather(sign_task)
100
+ await sign_page.close()
101
+ # 打工
102
+ cliwork_page = await context.new_page()
103
+ cliwork_task = asyncio.create_task(cliwork(cliwork_page))
104
+ await asyncio.gather(cliwork_task)
105
+ await cliwork_page.close()
106
+ # 退出
107
+ await browser.close()
108
+ # 推送
109
+ sign_result = sign_task.result()
110
+ cliwork_result = cliwork_task.result()
111
+ # ""分割两个服务的消息
112
+ push_msg(tsdm_title, "\n".join([sign_result, "", cliwork_result]))
113
+
114
+
115
+ if __name__ == "__main__":
116
+ asyncio.run(tsdm_sign())
_playwright/v2ex.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding:utf-8
2
+ import sys
3
+ import asyncio
4
+
5
+ from os.path import abspath, dirname, join
6
+ from playwright.async_api import async_playwright
7
+
8
+ sys.path.append(join(dirname(abspath(__file__)), "../"))
9
+
10
+ from utils import push_msg
11
+ from __init__ import (
12
+ browser_headless,
13
+ browser_proxy,
14
+ v2ex_url,
15
+ v2ex_sign_url,
16
+ v2ex_cookie_file,
17
+ v2ex_title,
18
+ v2ex_logger,
19
+ )
20
+
21
+
22
+ # 判断登录状态
23
+ async def is_login(page):
24
+ await page.goto(v2ex_url)
25
+ if await page.get_by_text("记事本").is_visible():
26
+ v2ex_logger.info("登录成功")
27
+ return True
28
+ else:
29
+ stderr = "Cookie 过期"
30
+ v2ex_logger.error(stderr)
31
+ push_msg(v2ex_title, stderr)
32
+ return False
33
+
34
+
35
+ # 签到
36
+ async def sign(page):
37
+ msg = []
38
+
39
+ if not await is_login(page):
40
+ return "v2ex_not_login"
41
+
42
+ await page.goto(v2ex_sign_url)
43
+ if await page.get_by_text("每日登录奖励已领取").is_visible():
44
+ sign_res = "今日铜币已领取"
45
+ v2ex_logger.info(sign_res)
46
+ msg.append(sign_res)
47
+ else:
48
+ await page.get_by_text("领取 X 铜币").click()
49
+ sign_res = "领取铜币成功"
50
+ v2ex_logger.info(sign_res)
51
+ msg.append(sign_res)
52
+
53
+ return "\n".join(msg)
54
+
55
+
56
+ async def v2ex_sign():
57
+ async with async_playwright() as playwright:
58
+ browser = await playwright.chromium.launch(headless=browser_headless)
59
+ context = await browser.new_context(storage_state=v2ex_cookie_file)
60
+ sign_page = await context.new_page()
61
+ sign_task = asyncio.create_task(sign(sign_page))
62
+ await asyncio.gather(sign_task)
63
+ await sign_page.close()
64
+ # 退出
65
+ await browser.close()
66
+ # 推送
67
+ sign_result = sign_task.result()
68
+ push_msg(v2ex_title, "\n".join([sign_result]))
69
+
70
+
71
+ if __name__ == "__main__":
72
+ asyncio.run(v2ex_sign())
_playwright/vits.py ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding:utf-8
2
+ import sys
3
+ import asyncio
4
+
5
+ from os.path import abspath, dirname, join
6
+ from playwright.async_api import async_playwright
7
+
8
+ sys.path.append(join(dirname(abspath(__file__)), "../"))
9
+
10
+ from utils import push_msg
11
+ from __init__ import (
12
+ browser_headless,
13
+ browser_proxy,
14
+ vits_url,
15
+ vits_cookie_file,
16
+ vits_title,
17
+ vits_logger,
18
+ )
19
+
20
+
21
+ # 判断登录状态
22
+ async def is_login(page):
23
+ await page.goto(vits_url)
24
+ if await page.get_by_text("Pause Space").is_visible():
25
+ vits_logger.info("登录成功")
26
+ return True
27
+ else:
28
+ stderr = "Cookie 过期"
29
+ vits_logger.error(stderr)
30
+ push_msg(vits_title, stderr)
31
+ return False
32
+
33
+
34
+ # 签到
35
+ async def sign(page):
36
+ if not await is_login(page):
37
+ return "vits_not_login"
38
+
39
+ if await page.get_by_role("button", name="Restart space").is_visible():
40
+ await page.get_by_role("button", name="Restart space").click()
41
+ sign_res = "restart vits server success"
42
+ vits_logger.info(sign_res)
43
+ else:
44
+ sign_res = "restart vits server failed"
45
+ vits_logger.error(sign_res)
46
+
47
+ return sign_res
48
+
49
+
50
+ async def vits_sign():
51
+ async with async_playwright() as playwright:
52
+ browser = await playwright.chromium.launch(headless=browser_headless)
53
+ context = await browser.new_context(storage_state=vits_cookie_file)
54
+ sign_page = await context.new_page()
55
+ sign_task = asyncio.create_task(sign(sign_page))
56
+ await asyncio.gather(sign_task)
57
+ await sign_page.close()
58
+ # 退出
59
+ await browser.close()
60
+ # 推送
61
+ sign_result = sign_task.result()
62
+ push_msg(vits_title, sign_result)
63
+
64
+
65
+ if __name__ == "__main__":
66
+ asyncio.run(vits_sign())
_playwright/wuaipojie.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding:utf-8
2
+ import sys
3
+ import asyncio
4
+
5
+ from os.path import abspath, dirname, join
6
+ from playwright.async_api import async_playwright
7
+
8
+ sys.path.append(join(dirname(abspath(__file__)), "../"))
9
+
10
+ from utils import push_msg
11
+ from __init__ import (
12
+ browser_headless,
13
+ browser_proxy,
14
+ wuaipojie_url,
15
+ wuaipojie_sign_url,
16
+ wuaipojie_cookie_file,
17
+ wuaipojie_title,
18
+ wuaipojie_logger,
19
+ )
20
+
21
+
22
+ async def sign(page):
23
+ await page.goto(wuaipojie_url)
24
+
25
+ # 判断登录状态
26
+ if await page.get_by_text("提醒").is_enabled():
27
+ wuaipojie_logger.info("登录成功")
28
+ else:
29
+ msg = "Cookie 过期"
30
+ wuaipojie_logger.error(msg)
31
+ return
32
+
33
+ # 签到
34
+ if await page.get_by_text("请下期再来").is_enabled():
35
+ msg = "今天已签到"
36
+ wuaipojie_logger.info(msg)
37
+ else:
38
+ await page.goto(wuaipojie_sign_url)
39
+ msg = "签到成功"
40
+ wuaipojie_logger.info(msg)
41
+ return msg
42
+
43
+
44
+ async def wuaipojie_sign():
45
+ async with async_playwright() as playwright:
46
+ browser = await playwright.chromium.launch(headless=browser_headless)
47
+ context = await browser.new_context(storage_state=wuaipojie_cookie_file)
48
+ sign_page = await context.new_page()
49
+ sign_task = asyncio.create_task(sign(sign_page))
50
+ await asyncio.gather(sign_task)
51
+ await sign_page.close()
52
+ # 退出
53
+ await browser.close()
54
+ # 推送
55
+ sign_result = sign_task.result()
56
+ push_msg(wuaipojie_title, "\n".join([sign_result]))
57
+
58
+
59
+ if __name__ == "__main__":
60
+ asyncio.run(wuaipojie_sign())
_requests/[no_use]restart_vits_server.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding:utf-8
2
+
3
+ import os
4
+ import re
5
+ import requests
6
+
7
+ from os.path import abspath, dirname, join
8
+
9
+ # conf
10
+ title = "Huggingface"
11
+ session = requests.Session()
12
+
13
+ # from utils import push_msg
14
+
15
+
16
+ def restart_vits_server():
17
+ headers = {
18
+ "authority": "huggingface.co",
19
+ "origin": "https://huggingface.co",
20
+ "referer": "https://huggingface.co/login",
21
+ "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36",
22
+ }
23
+ data = {
24
+ "username": os.environ.get("hf_username"),
25
+ "password": os.environ.get("hf_password"),
26
+ }
27
+ session.post("https://huggingface.co/login", headers=headers, data=data)
28
+ rsp = session.get(
29
+ "https://huggingface.co/spaces/evi0mo/vits-fastapi-server/settings"
30
+ )
31
+ csrf = re.findall(r"name=\"csrf\" value=\"(.*?)\">", rsp.text)[0]
32
+
33
+ res = "init"
34
+ restart_headers = {
35
+ "authority": "huggingface.co",
36
+ "origin": "https://huggingface.co",
37
+ "referer": "https://huggingface.co/spaces/evi0mo/vits-fastapi-server/settings",
38
+ "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36",
39
+ }
40
+
41
+ restart_data = {"csrf": csrf}
42
+ session.post(
43
+ "https://huggingface.co/spaces/evi0mo/vits-fastapi-server/restart?factory=false",
44
+ headers=restart_headers,
45
+ data=restart_data,
46
+ )
47
+ # check
48
+ check = session.get(
49
+ "https://huggingface.co/api/spaces/evi0mo/vits-fastapi-server/runtime"
50
+ )
51
+ if check.json()["stage"] == "RUNNING_BUILDING":
52
+ res = "success"
53
+ vits_logger.info(res)
54
+ else:
55
+ res = "failed"
56
+ vits_logger.error(res)
57
+
58
+ # push_msg(title, res)
59
+
60
+
61
+ if __name__ == "__main__":
62
+ restart_vits_server()
_requests/aliyundrive.py ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 接口参考:https://github.com/Anonym-w/autoSigninAliyun/blob/main/autoSignin.js
2
+ import sys
3
+ import requests
4
+
5
+ from os.path import abspath, dirname, join
6
+
7
+ # conf
8
+ sys.path.append(join(dirname(abspath(__file__)), "../"))
9
+ from utils import (
10
+ push_msg,
11
+ get_aliyundrive_refresh_token,
12
+ update_aliyundrive_access_token,
13
+ )
14
+ from __init__ import (
15
+ aliyundrive_nickname_url,
16
+ aliyundrive_signin_url,
17
+ aliyundrive_access_token_url,
18
+ aliyundrive_reward_url,
19
+ aliyundrive_title,
20
+ aliyundrive_logger,
21
+ )
22
+
23
+ # session
24
+ headers = {"message-Type": "application/json"}
25
+ session = requests.Session()
26
+ query_body = {}
27
+
28
+
29
+ def get_refresh_token():
30
+ # local storage only work in browser
31
+ return False
32
+
33
+
34
+ def validate_access_token():
35
+ # token只有三小时有效期,所以定时任务刷新间隔为三小时
36
+ # 从树莓派获取 refresh_token
37
+ refresh_token = get_aliyundrive_refresh_token()
38
+ # 查询结构体
39
+ query_body.update({"grant_type": "refresh_token", "refresh_token": refresh_token})
40
+ # validate
41
+ resp = session.post(aliyundrive_access_token_url, headers=headers, json=query_body)
42
+ if resp.status_code != 200:
43
+ msg = "阿里云 access_token 失效"
44
+ aliyundrive_logger.error(msg)
45
+ push_msg(aliyundrive_title, msg)
46
+ else:
47
+ aliyundrive_logger.info("阿里云 access_token 有效")
48
+ new_access_token = resp.json()["access_token"]
49
+ update_aliyundrive_access_token(new_access_token)
50
+ headers["Authorization"] = f"Bearer {new_access_token}"
51
+ return new_access_token
52
+ return False
53
+
54
+
55
+ def get_aliyun_nickname():
56
+ nickname = False
57
+ # 获取用户名
58
+ user_res = session.post(aliyundrive_nickname_url, headers=headers, json=query_body)
59
+ if user_res.status_code == 200:
60
+ msg = f"获取用户名成功,stdout:{user_res.json()}"
61
+ nickname = user_res.json()["nick_name"]
62
+ else:
63
+ msg = f"获取用户名失败,stderr:{user_res.json()}"
64
+ aliyundrive_logger.error(msg)
65
+ push_msg(title=aliyundrive_title, message=msg)
66
+ return nickname
67
+
68
+
69
+ def sign():
70
+ # 签到
71
+ sign_res = session.post(aliyundrive_signin_url, headers=headers, json=query_body)
72
+ if sign_res.status_code != 200:
73
+ sign_msg = f"阿里云盘签到失败,stderr:{sign_res.json()}"
74
+ aliyundrive_logger.error(sign_msg)
75
+ push_msg(title=aliyundrive_title, message=sign_msg)
76
+ else:
77
+ sign_msg = f"阿里云盘签到成功"
78
+ aliyundrive_logger.info(sign_msg)
79
+ sign_jsondata = sign_res.json()
80
+ # 已签到天数
81
+ signin_count = sign_jsondata["result"]["signInCount"]
82
+ # 当天签到信息,数组下标 -1
83
+ current_sign_info = sign_jsondata["result"]["signInLogs"][signin_count - 1]
84
+ # 当天签到获得的奖励信息
85
+ reward_name = current_sign_info["reward"]["name"]
86
+ reward_description = current_sign_info["reward"]["description"]
87
+ curent_reward = f"{reward_name}{reward_description}"
88
+ # 是否已领取奖励,bool
89
+ is_reward = current_sign_info["isReward"]
90
+ return is_reward, signin_count, curent_reward
91
+ return False
92
+
93
+
94
+ # 领取奖励
95
+ def get_reward(signin_count):
96
+ query_body.update({"signInDay": signin_count})
97
+ reward_res = session.post(aliyundrive_reward_url, headers=headers, json=query_body)
98
+ if reward_res.status_code == 200:
99
+ aliyundrive_logger.info("领取奖励成功")
100
+ else:
101
+ reward_msg = f"领取奖励失败,stderr:{reward_res.json()}"
102
+ aliyundrive_logger.error(reward_msg)
103
+ push_msg(title=aliyundrive_title, message=reward_msg)
104
+ return reward_msg
105
+ return False
106
+
107
+
108
+ def aliyundrive_sign():
109
+ validate_access_token()
110
+ nickname = get_aliyun_nickname()
111
+ is_reward, signin_count, curent_reward = sign()
112
+ if not is_reward:
113
+ get_reward(signin_count)
114
+ message = f"{nickname} 签到成功,本月累计签到 {signin_count} 天\n本次签到获得:{curent_reward}"
115
+ aliyundrive_logger.info(message)
116
+ push_msg(title=aliyundrive_title, message=message)
117
+ return message
118
+
119
+
120
+ if __name__ == "__main__":
121
+ aliyundrive_sign()
api.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ https://github.com/agronholm/apscheduler/blob/3.x/examples/schedulers/asyncio_.py
3
+ """
4
+ import asyncio
5
+ from collections.abc import Callable, Iterable, Mapping
6
+ import threading
7
+ from typing import Any
8
+ import pytz
9
+
10
+ from datetime import datetime
11
+ from apscheduler.schedulers.background import BackgroundScheduler
12
+ from apscheduler.schedulers.asyncio import AsyncIOScheduler
13
+ from loguru import logger
14
+
15
+ from _playwright.bilibili import bilibili_sign
16
+ from _playwright.v2ex import v2ex_sign
17
+ from _playwright.vits import vits_sign
18
+ from _playwright.tsdm import tsdm_sign
19
+ from _playwright.wuaipojie import wuaipojie_sign
20
+ from _requests.aliyundrive import aliyundrive_sign
21
+ from utils import get_cookie_from_pi
22
+
23
+
24
+ def tick():
25
+ logger.debug(f"Tick! The time is: {datetime.now():%Y-%m-%d %H:%M:%S}")
26
+
27
+
28
+ def run_scheduler(loop):
29
+ asyncio.set_event_loop(loop)
30
+ # pi
31
+ get_cookie_from_pi()
32
+ # add task
33
+ sign_scheduler = AsyncIOScheduler()
34
+ sign_scheduler.configure(timezone=pytz.timezone("Asia/Shanghai"))
35
+ sign_scheduler.add_job(tick, "cron", hour="*/1")
36
+ sign_scheduler.add_job(bilibili_sign, "cron", hour=5, minute=1, second=0)
37
+ sign_scheduler.add_job(v2ex_sign, "cron", hour=5, minute=2, second=0)
38
+ sign_scheduler.add_job(tsdm_sign, "cron", hour=5, minute=3, second=0)
39
+ sign_scheduler.add_job(wuaipojie_sign, "cron", hour=5, minute=4, second=0)
40
+ sign_scheduler.add_job(vits_sign, "cron", hour=5, minute=5, second=0)
41
+ sign_scheduler.add_job(aliyundrive_sign, "cron", hour="*/2")
42
+ sign_scheduler.start()
43
+ try:
44
+ asyncio.get_event_loop().run_forever()
45
+ except (KeyboardInterrupt, SystemExit):
46
+ pass
47
+
48
+
49
+ def start_daemon_scheduler(loop):
50
+ t = threading.Thread(target=run_scheduler, args=(loop,), name="schedule", daemon=True)
51
+ t.start()
52
+
53
+
54
+ async def kill_daemon_scheduler():
55
+ loop = asyncio._get_running_loop()
56
+ loop.stop()
57
+
58
+
59
+ if __name__ == "__main__":
60
+ schedule_loop = asyncio.new_event_loop()
61
+ start_daemon_scheduler(schedule_loop)
62
+ import time
63
+
64
+ time.sleep(3)
65
+ asyncio.run_coroutine_threadsafe(kill_daemon_scheduler(), loop=schedule_loop)
app.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding: utf-8
2
+ import asyncio
3
+ import os
4
+ import requests
5
+
6
+ from os.path import join
7
+ from uvicorn import run
8
+ from fastapi import FastAPI
9
+ from fastapi.responses import Response
10
+ from loguru import logger
11
+
12
+ from __init__ import DIR_PATH, api_token
13
+ from utils import push_msg
14
+ from api import start_daemon_scheduler, kill_daemon_scheduler
15
+
16
+ schedule_loop = asyncio.new_event_loop()
17
+
18
+ app = FastAPI()
19
+
20
+
21
+ @app.get("/")
22
+ def home():
23
+ html_content = open("index.html").read()
24
+ return Response(content=html_content, status_code=200)
25
+
26
+
27
+ # 开启定时任务
28
+ @app.get("/run")
29
+ def do_run(token: str):
30
+ if token != api_token:
31
+ return {"code": 422}
32
+
33
+ start_daemon_scheduler(schedule_loop)
34
+ res = {"code": 0, "data": "start scheduler"}
35
+ return res
36
+
37
+
38
+ # 开启定时任务
39
+ @app.get("/kill")
40
+ def do_kill(token: str):
41
+ if token != api_token:
42
+ return {"code": 422}
43
+
44
+ asyncio.run_coroutine_threadsafe(kill_daemon_scheduler(), loop=schedule_loop)
45
+ res = {"code": 0, "data": "kill scheduler"}
46
+ return res
47
+
48
+
49
+ # 查询日志
50
+ @app.get("/log")
51
+ async def do_log(token: str, name: str):
52
+ if token != api_token:
53
+ return {"code": 422}
54
+
55
+ log_file = join(DIR_PATH, f"log/{name}.log")
56
+ with open(log_file, "r", encoding="utf-8") as f:
57
+ data = f.read()
58
+
59
+ res = {"code": 200, "data": data}
60
+ return res
61
+
62
+
63
+ # 列出当前目录所有文件
64
+ @app.get("/path")
65
+ def do_path(token: str):
66
+ if token != api_token:
67
+ return {"code": 422}
68
+
69
+ data = []
70
+ for root, _, files in os.walk(DIR_PATH):
71
+ for file in files:
72
+ data.append(join(root, file))
73
+ res = {"code": 0, "data": data}
74
+ return res
75
+
76
+
77
+ # 测试连通性
78
+ @app.get("/ip")
79
+ def do_ip(token: str):
80
+ if token != api_token:
81
+ return {"code": 422}
82
+
83
+ ip = requests.get("https://checkip.amazonaws.com").text.strip()
84
+ logger.debug(f"checking ip: {ip}")
85
+ res = {"code": 0, "ip": ip}
86
+ return res
87
+
88
+
89
+ # 测试推送消息
90
+ @app.get("/push")
91
+ def do_push(token: str):
92
+ if token != api_token:
93
+ return {"code": 422}
94
+
95
+ data = push_msg("send from huggingface docker", "hello world")
96
+ return {"code": 0, "data": data}
97
+
98
+
99
+ if __name__ == "__main__":
100
+ run("app:app", host="0.0.0.0", port=8000, reload=True)
config/settings_prod.py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding: utf-8
2
+ import os
3
+ import sys
4
+ from os.path import join
5
+
6
+ # 添加根目录引用
7
+ # 不要用同一个 DIR_PATH 命名,会影响 __init__ 中的全局变量
8
+ PROD_PATH = "/home/user/app"
9
+ sys.path.append(PROD_PATH)
10
+
11
+ from option_logger import register_logger
12
+
13
+ # playwright
14
+ browser_headless = True
15
+ browser_proxy = {"server": None}
16
+ user_agent = (
17
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
18
+ )
19
+ ignore_https_errors = True
20
+
21
+ # api
22
+ api_token = os.environ.get("token")
23
+
24
+ # gotify
25
+ gotify_host = os.environ.get("gotify_host")
26
+ gotify_port = os.environ.get("gotify_port")
27
+ gotify_token = os.environ.get("gotify_token")
28
+
29
+ # mysql
30
+ mysql_option = {
31
+ "HOST": os.environ.get("DB_HOST"),
32
+ "PORT": int(os.environ.get("DB_PORT")),
33
+ "USERNAME": os.environ.get("DB_USERNAME"),
34
+ "PASSWORD": os.environ.get("DB_PASSWORD"),
35
+ "DATABASE": os.environ.get("DB_DATABASE"),
36
+ }
37
+
38
+ # for fastapi
39
+ logfile_mapping = {
40
+ "vits": join(PROD_PATH, "log/vits.log"),
41
+ "bilibili": join(PROD_PATH, "log/bilibili.log"),
42
+ "v2ex": join(PROD_PATH, "log/v2ex.log"),
43
+ "tsdm": join(PROD_PATH, "log/tsdm.log"),
44
+ "wuaipojie": join(PROD_PATH, "log/wuaipojie.log"),
45
+ "aliyundrive": join(PROD_PATH, "log/aliyundrive.log"),
46
+ }
47
+
48
+ # vits
49
+ vits_title = "vits server"
50
+ vits_url = "https://huggingface.co/spaces/evi0mo/vits-fastapi-server/settings"
51
+ vits_logger = register_logger("vits", logfile_mapping["vits"])
52
+ vits_cookie_file = join(PROD_PATH, "cookie/vits.json")
53
+ hf_username = os.environ.get("hf_username")
54
+ hf_password = os.environ.get("hf_password")
55
+
56
+ # wuaipojie
57
+ wuaipojie_title = "wuaipojie"
58
+ wuaipojie_logger = register_logger("wuaipojie", logfile_mapping["wuaipojie"])
59
+ wuaipojie_cookie_file = join(PROD_PATH, "cookie/wuaipojie.json")
60
+ wuaipojie_url = "https://www.52pojie.cn/home.php?mod=task&do=apply&id=2"
61
+ wuaipojie_sign_url = "https://www.52pojie.cn/home.php?mod=task&do=draw&id=2"
62
+
63
+ # v2ex
64
+ v2ex_title = "V2EX"
65
+ v2ex_logger = register_logger("v2ex", logfile_mapping["v2ex"])
66
+ v2ex_cookie_file = join(PROD_PATH, "cookie/v2ex.json")
67
+ v2ex_url = "https://v2ex.com"
68
+ v2ex_sign_url = "https://v2ex.com/mission/daily"
69
+
70
+ # bilibili
71
+ bilibili_title = "Bilibili"
72
+ bilibili_logger = register_logger("bilibili", logfile_mapping["bilibili"])
73
+ bilibili_cookie_file = join(PROD_PATH, "cookie/bilibili.json")
74
+ bilibili_url = "https://account.bilibili.com/account/home"
75
+ bilibili_sign_url = "https://api.live.bilibili.com/xlive/web-ucenter/v1/sign/DoSign" # 签到地址
76
+ bilibili_live_url = "https://live.bilibili.com" # 直播间地址
77
+ bilibili_live_rooms = os.environ.get("bilibili_live_rooms")
78
+
79
+ # tsdm
80
+ tsdm_title = "天使动漫"
81
+ tsdm_logger = register_logger("tsdm", logfile_mapping["tsdm"])
82
+ tsdm_cookie_file = join(PROD_PATH, "cookie/tsdm.json")
83
+ tsdm_url = "https://www.tsdm39.com/forum.php?mobile=no" # 首页
84
+ tsdm_sign_url = "https://www.tsdm39.com/plugin.php?id=dsu_paulsign:sign&mobile=yes&simpletype=yes" # 手机精简版签到地址
85
+ tsdm_cliwork_url = "https://www.tsdm39.com/plugin.php?id=np_cliworkdz:work" # 打工地址
86
+ tsdm_plugin_id = [1, 2, 4, 6, 7, 9] # 打工插件 id
87
+ tsdm_minds = {
88
+ "kx": "开心",
89
+ "ng": "难过",
90
+ "ym": "郁闷",
91
+ "wl": "无聊",
92
+ "nu": "怒",
93
+ "ch": "擦汗",
94
+ "fd": "奋斗",
95
+ "yl": "慵懒",
96
+ "shuai": "衰",
97
+ } # 心情
98
+
99
+ # aliyundrive
100
+ aliyundrive_title = "阿里云盘"
101
+ aliyundrive_logger = register_logger("aliyundrive", logfile_mapping["aliyundrive"])
102
+ aliyundrive_refresh_token = os.environ.get("aliyundrive_refresh_token")
103
+ aliyundrive_cookie_file = join(PROD_PATH, "cookie/aliyundrive.json")
104
+ aliyundrive_url = "https://www.aliyundrive.com/drive"
105
+ aliyundrive_nickname_url = "https://api.aliyundrive.com/adrive/v2/user/get"
106
+ aliyundrive_access_token_url = "https://auth.aliyundrive.com/v2/account/token"
107
+ aliyundrive_signin_url = "https://member.aliyundrive.com/v1/activity/sign_in_list"
108
+ aliyundrive_reward_url = "https://member.aliyundrive.com/v1/activity/sign_in_reward"
index.html ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <html>
2
+ <!-- Title -->
3
+
4
+ <head>
5
+ <title>FastAPI Hello World</title>
6
+ </head>
7
+
8
+ <!-- Stylesheet -->
9
+ <style>
10
+ body {
11
+ font-family: Arial, Helvetica, sans-serif;
12
+ font-size: 16px;
13
+ line-height: 1.5;
14
+ margin: 0;
15
+ padding: 0;
16
+ }
17
+
18
+ h1 {
19
+ font-size: 2em;
20
+ margin: 0;
21
+ padding: 0;
22
+ /* Center */
23
+ text-align: center;
24
+ }
25
+
26
+ h3 {
27
+ margin: 0;
28
+ padding: 0;
29
+ /* Center */
30
+ text-align: center;
31
+ }
32
+ </style>
33
+
34
+ <!-- Body -->
35
+
36
+ <body>
37
+ <h1>FastAPI Hello World Example</h1>
38
+
39
+ <h3>
40
+ This is a simple example of a FastAPI Hello World application using Docker. See the links below for more
41
+ information.
42
+ </h3>
43
+ <!-- List of different relevant links and descriptions about them -->
44
+
45
+ <div style="margin: 0 auto; width: 50%;">
46
+
47
+ <ul>
48
+ <!-- Link to self /docs -->
49
+ <li>
50
+ <a href="/docs">This API's Interactive Swaggar Docs</a> - Try the API out here!
51
+ </li>
52
+ </ul>
53
+ </div>
54
+
55
+ </body>
56
+
57
+ </html>
option_logger.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from loguru import logger
2
+
3
+
4
+ # 根据名称注册多个 logger
5
+ def register_logger(bind_name, file_path):
6
+ logger.add(
7
+ file_path,
8
+ format="{time:YYYY-MM-DD HH:mm:ss} {level} {message}",
9
+ filter=lambda record: record["extra"].get("name") == bind_name,
10
+ )
11
+ new_logger = logger.bind(name=bind_name)
12
+ return new_logger
option_mysql.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pymysql
2
+
3
+
4
+ class OptionMysql(object):
5
+ def __init__(self, options):
6
+ host = options["HOST"]
7
+ user = options["USERNAME"]
8
+ password = options["PASSWORD"]
9
+ database = options["DATABASE"]
10
+ port = options["PORT"]
11
+ charset = "utf8"
12
+ # 连接数据库
13
+ self.conn = pymysql.connect(
14
+ host=host,
15
+ port=port,
16
+ user=user,
17
+ password=password,
18
+ database=database,
19
+ charset=charset,
20
+ )
21
+ # 创建游标
22
+ self.cur = self.conn.cursor()
23
+ self.dict_cur = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
24
+
25
+ def __exit__(self):
26
+ self.cur.close()
27
+ self.dict_cur.close()
28
+ self.conn.close()
29
+
30
+ def get_dict_data(self, sql, params=[]):
31
+ """查询,返回字典类型"""
32
+ try:
33
+ if params:
34
+ self.dict_cur.execute(sql, params)
35
+ else:
36
+ self.dict_cur.execute(sql)
37
+ data = self.dict_cur.fetchall()
38
+ return data
39
+ except Exception as e:
40
+ self.conn.rollback()
41
+ raise e
42
+
43
+ def update_data(self, sql, params=[]):
44
+ """更新"""
45
+ try:
46
+ if not params:
47
+ self.cur.execute(sql)
48
+ else:
49
+ self.cur.execute(sql, params)
50
+ self.conn.commit()
51
+ except Exception as e:
52
+ self.conn.rollback()
53
+ raise e
54
+ return True
requirements.txt ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ apscheduler
2
+ psutil
3
+ gotify
4
+ loguru
5
+ playwright
6
+ playwright-stealth
7
+ requests
8
+ tld
9
+ uvicorn
10
+ fastapi
11
+ pytz
12
+ pymysql
13
+ #ddddocr
14
+ #Pillow
15
+ #selenium
utils.py ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding:utf-8
2
+ import os
3
+ import sys
4
+ import socket
5
+ import asyncio
6
+ import psutil
7
+ import requests
8
+
9
+ from os.path import join
10
+ from tld import get_tld
11
+ from loguru import logger
12
+ from playwright.async_api import async_playwright, Page
13
+ from playwright_stealth import stealth_async
14
+
15
+ from option_mysql import OptionMysql
16
+ from __init__ import (
17
+ gotify_host,
18
+ gotify_port,
19
+ gotify_token,
20
+ mysql_option,
21
+ DIR_PATH,
22
+ DEBUG,
23
+ browser_headless,
24
+ browser_proxy,
25
+ ignore_https_errors,
26
+ user_agent,
27
+ aliyundrive_access_token_url,
28
+ )
29
+
30
+
31
+ # webdriver
32
+ async def init_page(storage_state=None, browser_type: str = "chromium") -> Page:
33
+ if browser_type not in ("chromium", "firefox", "webkit"):
34
+ raise TypeError("unspported browser")
35
+
36
+ async with async_playwright() as p:
37
+ if browser_type == "chromium":
38
+ browser = await p.chromium.launch(headless=browser_headless)
39
+ elif browser_type == "firefox":
40
+ browser = await p.firefox.launch(headless=browser_headless)
41
+ else:
42
+ logger.error("初始化浏览器失败")
43
+ exit(-1)
44
+
45
+ context = await browser.new_context(
46
+ proxy=browser_proxy,
47
+ ignore_https_errors=ignore_https_errors,
48
+ user_agent=user_agent,
49
+ )
50
+ # 从文件读取 Cookie
51
+ context = await browser.new_context(storage_state=storage_state)
52
+ page = await context.new_page()
53
+ # 隐藏 webdriver 特征
54
+ await stealth_async(page)
55
+ # await page.pause() # async 跳出上下文就会 playwright._impl._api_types.Error: Connection closed
56
+ await goto_github(page)
57
+ await dump_cookie(page) # 创建函数:一个 browser 对应一个 context、page,在 with 内完成多个任务
58
+ await browser.close()
59
+
60
+
61
+ async def goto_github(page):
62
+ await page.goto("https://github.com")
63
+
64
+
65
+ async def dump_cookie(page):
66
+ # url = "https://www.52pojie.cn/home.php"
67
+ # url = "https://v2ex.com"
68
+ # url = "https://www.bilibili.com"
69
+ # url = "https://www.tsdm39.com/forum.php?mobile=no"
70
+ # url = "https://www.aliyundrive.com/drive"
71
+ url = "https://huggingface.co/login"
72
+ save_cookie = join(DIR_PATH, f"{get_domain(url)}.json")
73
+ await page.goto(url)
74
+ logger.debug(DIR_PATH)
75
+ await page.screenshot(
76
+ path=join(DIR_PATH, "screenshot.png"),
77
+ full_page=True,
78
+ ) # 截图
79
+ while input("input c to continue: ") != "c": # 阻塞等待填写登录信息
80
+ continue
81
+ await page.context.storage_state(path=save_cookie) # 保存 Cookie 到文件
82
+
83
+
84
+ # 获取容器内 IP
85
+ def get_local_ip():
86
+ net_card_info = []
87
+ info = psutil.net_if_addrs()
88
+ for k, v in info.items():
89
+ for item in v:
90
+ if item[0] == 2 and not item[1] == "127.0.0.1":
91
+ net_card_info.append(item[1])
92
+ local_ip = net_card_info[0]
93
+ return local_ip
94
+
95
+
96
+ # 从 url 获取域名
97
+ def get_domain(url: str) -> str:
98
+ result = get_tld(url, as_object=True)
99
+ domain = result.domain
100
+ return domain
101
+
102
+
103
+ # 从域名获取 IP
104
+ def get_domain_ip(host: str) -> str:
105
+ domain_ip = socket.gethostbyname(host)
106
+ return domain_ip
107
+
108
+
109
+ # gotify 推送
110
+ def push_msg(title, message):
111
+ gotify_ip = get_domain_ip(gotify_host)
112
+ url = f"http://{gotify_ip}:{gotify_port}/message?token={gotify_token}"
113
+ data = {"title": title, "message": message, "priority": 10}
114
+ with requests.post(url, json=data) as resp:
115
+ return resp.json()
116
+
117
+
118
+ def get_bilibili_live_rooms_from_pi() -> dict:
119
+ logger.info("getting bilibili_live_rooms from pi")
120
+ bilibili_live_rooms = {}
121
+ mysql = OptionMysql(mysql_option)
122
+ sql = f"SELECT room_id, username FROM live_rooms"
123
+ data = mysql.get_dict_data(sql)
124
+ if data:
125
+ for d in data:
126
+ bilibili_live_rooms[d["room_id"]] = d["username"]
127
+ return bilibili_live_rooms
128
+
129
+
130
+ def get_cookie_from_pi() -> dict:
131
+ logger.info("getting cookie from pi")
132
+ mysql = OptionMysql(mysql_option)
133
+ sql = f"SELECT cookie_name, cookie_value FROM cookie"
134
+ data = mysql.get_dict_data(sql)
135
+ for d in data:
136
+ log_file = join(DIR_PATH, f"cookie/{d['cookie_name']}.json")
137
+ with open(log_file, "w") as lf:
138
+ lf.write(d["cookie_value"])
139
+ return data[0]["cookie_name"]
140
+
141
+
142
+ def get_aliyundrive_refresh_token():
143
+ mysql = OptionMysql(mysql_option)
144
+ sql = f"SELECT token FROM aliyundrive WHERE id=1"
145
+ data = mysql.get_dict_data(sql)
146
+ if data:
147
+ logger.info("获取阿里云盘 refresh_token 成功")
148
+ return data[0]["token"]
149
+ return False
150
+
151
+
152
+ def update_aliyundrive_access_token(access_token):
153
+ mysql = OptionMysql(mysql_option)
154
+ sql = f"UPDATE aliyundrive SET token=%s WHERE id=2"
155
+ data = mysql.update_data(sql, [access_token])
156
+ if data:
157
+ logger.info("update aliyundrive access token")
158
+ return True
159
+ return False
160
+
161
+
162
+ def get_log(log_file: str) -> str:
163
+ with open(log_file, "r", encoding="utf-8") as f:
164
+ data = f.read()
165
+ return data
166
+
167
+
168
+ if __name__ == "__main__":
169
+ logger.debug(f"DEBUG Mode: {DEBUG}")
170
+ logger.debug(f"DIR_PATH: {DIR_PATH}")
171
+ # asyncio.run(init_page())
172
+ # logger.debug(f"get_domain_ip: {get_domain_ip(gotify_host)}")
173
+ # logger.debug(f'get_domain: {get_domain("https://github.com")}')
174
+ # logger.debug(f"list_path: {list_path()}")
175
+ # logger.debug(f'push_msg: {push_msg("utils.py", "hello world")}')
176
+ # logger.debug(f"get_aliyun_token_from_pi(): {get_aliyun_token_from_pi()}")
177
+ # logger.debug(f"get_bilibili_live_rooms_from_pi(): {get_bilibili_live_rooms_from_pi()}")
178
+ # logger.debug(f"get_cookie_from_pi(): {get_cookie_from_pi()}")
179
+ # logger.debug(f'get_cron_log(): {get_cron_log("log/tsdm.log")}')
180
+ # logger.debug(f"get_aliyundrive_access_token: {get_aliyundrive_access_token()}")
181
+ # logger.debug(f"update_aliyundrive_access_token: {update_aliyundrive_access_token('123')}")