Spaces:
Running
Running
admin
commited on
Commit
·
863d5cf
1
Parent(s):
a82064e
merge report
Browse files
activate.py
ADDED
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import time
|
3 |
+
import requests
|
4 |
+
import threading
|
5 |
+
from tqdm import tqdm
|
6 |
+
from huggingface_hub import HfApi
|
7 |
+
from smtp import send_email
|
8 |
+
from config import *
|
9 |
+
|
10 |
+
|
11 |
+
def get_space_status(repo_id: str):
|
12 |
+
response: list = requests.get(
|
13 |
+
url=f"{HF_DOMAIN}/api/spaces/semantic-search",
|
14 |
+
params={"q": repo_id},
|
15 |
+
headers=HEADER,
|
16 |
+
timeout=TIMEOUT,
|
17 |
+
).json()
|
18 |
+
|
19 |
+
if not (response and response[0]["id"] == repo_id):
|
20 |
+
return "ERROR"
|
21 |
+
|
22 |
+
return response[0]["runtime"]["stage"]
|
23 |
+
|
24 |
+
|
25 |
+
def get_spaces(username: str):
|
26 |
+
sleepings, errors = [], []
|
27 |
+
try:
|
28 |
+
spaces = HfApi().list_spaces(author=username)
|
29 |
+
for space in spaces:
|
30 |
+
status = get_space_status(space.id)
|
31 |
+
if status == "SLEEPING":
|
32 |
+
space_id = space.id.replace("/", "-").replace("_", "-").lower()
|
33 |
+
if space.sdk == "gradio":
|
34 |
+
sleepings.append(f"https://{space_id}.hf.space")
|
35 |
+
else:
|
36 |
+
sleepings.append(f"https://{space_id}.static.hf.space")
|
37 |
+
|
38 |
+
elif status == "ERROR":
|
39 |
+
errors.append(f"{HF_DOMAIN}/spaces/{space.id}")
|
40 |
+
|
41 |
+
return sleepings, errors
|
42 |
+
|
43 |
+
except Exception as e:
|
44 |
+
print(f"An error occurred in the request: {e}")
|
45 |
+
|
46 |
+
return [], []
|
47 |
+
|
48 |
+
|
49 |
+
def activate_space(url: str):
|
50 |
+
try:
|
51 |
+
response = requests.get(url, headers=HEADER, timeout=TIMEOUT)
|
52 |
+
response.raise_for_status()
|
53 |
+
|
54 |
+
except Exception as e:
|
55 |
+
print(e)
|
56 |
+
|
57 |
+
|
58 |
+
def get_studios(username: str):
|
59 |
+
try:
|
60 |
+
response = requests.put(
|
61 |
+
f"{MS_DOMAIN}/api/v1/studios/{username}/list",
|
62 |
+
data=json.dumps(
|
63 |
+
{
|
64 |
+
"PageNumber": 1,
|
65 |
+
"PageSize": 1000,
|
66 |
+
"Name": "",
|
67 |
+
"SortBy": "gmt_modified",
|
68 |
+
"Order": "desc",
|
69 |
+
}
|
70 |
+
),
|
71 |
+
headers=HEADER,
|
72 |
+
timeout=TIMEOUT,
|
73 |
+
)
|
74 |
+
response.raise_for_status()
|
75 |
+
spaces: list = response.json()["Data"]["Studios"]
|
76 |
+
if spaces:
|
77 |
+
studios, errors = [], []
|
78 |
+
for space in spaces:
|
79 |
+
status = space["Status"]
|
80 |
+
if status == "Expired":
|
81 |
+
studios.append(f"{username}/{space['Name']}")
|
82 |
+
elif status == "Failed":
|
83 |
+
errors.append(f"{MS_DOMAIN}/studios/{username}/{space['Name']}")
|
84 |
+
|
85 |
+
return studios, errors
|
86 |
+
|
87 |
+
except requests.exceptions.Timeout as e:
|
88 |
+
print(f"Timeout: {e}, retrying...")
|
89 |
+
time.sleep(DELAY)
|
90 |
+
return get_studios(username)
|
91 |
+
|
92 |
+
except Exception as e:
|
93 |
+
print(f"Requesting error: {e}")
|
94 |
+
|
95 |
+
return [], []
|
96 |
+
|
97 |
+
|
98 |
+
def activate_studio(repo: str, holding_delay=5):
|
99 |
+
repo_page = f"{MS_DOMAIN}/studios/{repo}"
|
100 |
+
status_api = f"{MS_DOMAIN}/api/v1/studio/{repo}/status"
|
101 |
+
start_expired_api = f"{MS_DOMAIN}/api/v1/studio/{repo}/start_expired"
|
102 |
+
try:
|
103 |
+
response = requests.put(start_expired_api, headers=HEADER, timeout=TIMEOUT)
|
104 |
+
response.raise_for_status()
|
105 |
+
while (
|
106 |
+
requests.get(status_api, headers=HEADER, timeout=TIMEOUT).json()["Data"][
|
107 |
+
"Status"
|
108 |
+
]
|
109 |
+
!= "Running"
|
110 |
+
):
|
111 |
+
requests.get(repo_page, headers=HEADER, timeout=TIMEOUT)
|
112 |
+
time.sleep(holding_delay)
|
113 |
+
|
114 |
+
except requests.exceptions.Timeout as e:
|
115 |
+
print(f"Failed to activate {repo}: {e}, retrying...")
|
116 |
+
activate_studio(repo)
|
117 |
+
|
118 |
+
except Exception as e:
|
119 |
+
print(e)
|
120 |
+
|
121 |
+
|
122 |
+
def activates(users=USERS):
|
123 |
+
spaces, studios, failures = [], [], []
|
124 |
+
usernames = users.split(";")
|
125 |
+
for user in tqdm(usernames, desc="Collecting spaces"):
|
126 |
+
username = user.strip()
|
127 |
+
if username:
|
128 |
+
sleeps, errors = get_spaces(username)
|
129 |
+
spaces += sleeps
|
130 |
+
failures += errors
|
131 |
+
time.sleep(DELAY)
|
132 |
+
|
133 |
+
for space in tqdm(spaces, desc="Activating spaces"):
|
134 |
+
activate_space(space)
|
135 |
+
time.sleep(DELAY)
|
136 |
+
|
137 |
+
for user in tqdm(usernames, desc="Collecting studios"):
|
138 |
+
username = user.strip()
|
139 |
+
if username:
|
140 |
+
sleeps, errors = get_studios(username)
|
141 |
+
studios += sleeps
|
142 |
+
failures += errors
|
143 |
+
time.sleep(DELAY)
|
144 |
+
|
145 |
+
for studio in tqdm(studios, desc="Activating studios"):
|
146 |
+
threading.Thread(target=activate_studio, args=(studio,), daemon=True).start()
|
147 |
+
time.sleep(DELAY)
|
148 |
+
|
149 |
+
print("\n".join(spaces + studios) + "\nActivation complete!")
|
150 |
+
content = ""
|
151 |
+
for failure in failures:
|
152 |
+
errepo: str = failure
|
153 |
+
errepo = errepo.replace(HF_DOMAIN, "").replace(MS_DOMAIN, "")
|
154 |
+
content += f"<br><a href='{failure}'>{errepo[1:]}</a><br>"
|
155 |
+
|
156 |
+
if content:
|
157 |
+
send_email(content)
|
app.py
CHANGED
@@ -1,237 +1,35 @@
|
|
1 |
-
import os
|
2 |
-
import json
|
3 |
import time
|
4 |
-
import requests
|
5 |
import schedule
|
6 |
import threading
|
7 |
import gradio as gr
|
8 |
-
from
|
9 |
-
from
|
10 |
-
from
|
11 |
-
from
|
12 |
-
from tzlocal import get_localzone
|
13 |
|
14 |
-
DELAY = 1
|
15 |
-
TIMEOUT = 15
|
16 |
-
HF_DOMAIN = "https://huggingface.co"
|
17 |
-
MS_DOMAIN = "https://www.modelscope.cn"
|
18 |
-
HEADER = {
|
19 |
-
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537"
|
20 |
-
}
|
21 |
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
return None
|
26 |
-
|
27 |
-
local_tz = get_localzone()
|
28 |
-
aware_local = naive_time.replace(tzinfo=local_tz)
|
29 |
-
return aware_local.astimezone(target_tz).strftime("%Y-%m-%d %H:%M:%S")
|
30 |
-
|
31 |
-
|
32 |
-
def get_space_status(repo_id: str):
|
33 |
-
response: list = requests.get(
|
34 |
-
url=f"{HF_DOMAIN}/api/spaces/semantic-search",
|
35 |
-
params={"q": repo_id},
|
36 |
-
headers=HEADER,
|
37 |
-
timeout=TIMEOUT,
|
38 |
-
).json()
|
39 |
-
|
40 |
-
if not (response and response[0]["id"] == repo_id):
|
41 |
-
return "ERROR"
|
42 |
-
|
43 |
-
return response[0]["runtime"]["stage"]
|
44 |
-
|
45 |
-
|
46 |
-
def get_spaces(username: str):
|
47 |
-
sleepings, errors = [], []
|
48 |
-
try:
|
49 |
-
spaces = HfApi().list_spaces(author=username)
|
50 |
-
for space in spaces:
|
51 |
-
status = get_space_status(space.id)
|
52 |
-
if status == "SLEEPING":
|
53 |
-
space_id = space.id.replace("/", "-").replace("_", "-").lower()
|
54 |
-
if space.sdk == "gradio":
|
55 |
-
sleepings.append(f"https://{space_id}.hf.space")
|
56 |
-
else:
|
57 |
-
sleepings.append(f"https://{space_id}.static.hf.space")
|
58 |
-
|
59 |
-
elif status == "ERROR":
|
60 |
-
errors.append(f"{HF_DOMAIN}/spaces/{space.id}")
|
61 |
-
|
62 |
-
return sleepings, errors
|
63 |
-
|
64 |
-
except Exception as e:
|
65 |
-
print(f"An error occurred in the request: {e}")
|
66 |
-
|
67 |
-
return [], []
|
68 |
-
|
69 |
-
|
70 |
-
def activate_space(url: str):
|
71 |
-
try:
|
72 |
-
response = requests.get(url, headers=HEADER, timeout=TIMEOUT)
|
73 |
-
response.raise_for_status()
|
74 |
-
|
75 |
-
except Exception as e:
|
76 |
-
print(e)
|
77 |
-
|
78 |
-
|
79 |
-
def get_studios(username: str):
|
80 |
-
try:
|
81 |
-
response = requests.put(
|
82 |
-
f"{MS_DOMAIN}/api/v1/studios/{username}/list",
|
83 |
-
data=json.dumps(
|
84 |
-
{
|
85 |
-
"PageNumber": 1,
|
86 |
-
"PageSize": 1000,
|
87 |
-
"Name": "",
|
88 |
-
"SortBy": "gmt_modified",
|
89 |
-
"Order": "desc",
|
90 |
-
}
|
91 |
-
),
|
92 |
-
headers=HEADER,
|
93 |
-
timeout=TIMEOUT,
|
94 |
-
)
|
95 |
-
response.raise_for_status()
|
96 |
-
spaces: list = response.json()["Data"]["Studios"]
|
97 |
-
if spaces:
|
98 |
-
studios, errors = [], []
|
99 |
-
for space in spaces:
|
100 |
-
status = space["Status"]
|
101 |
-
if status == "Expired":
|
102 |
-
studios.append(f"{username}/{space['Name']}")
|
103 |
-
elif status == "Failed":
|
104 |
-
errors.append(f"{MS_DOMAIN}/studios/{username}/{space['Name']}")
|
105 |
-
|
106 |
-
return studios, errors
|
107 |
-
|
108 |
-
except requests.exceptions.Timeout as e:
|
109 |
-
print(f"Timeout: {e}, retrying...")
|
110 |
-
time.sleep(DELAY)
|
111 |
-
return get_studios(username)
|
112 |
-
|
113 |
-
except Exception as e:
|
114 |
-
print(f"Requesting error: {e}")
|
115 |
-
|
116 |
-
return [], []
|
117 |
-
|
118 |
-
|
119 |
-
def activate_studio(repo: str, holding_delay=5):
|
120 |
-
repo_page = f"{MS_DOMAIN}/studios/{repo}"
|
121 |
-
status_api = f"{MS_DOMAIN}/api/v1/studio/{repo}/status"
|
122 |
-
start_expired_api = f"{MS_DOMAIN}/api/v1/studio/{repo}/start_expired"
|
123 |
-
try:
|
124 |
-
response = requests.put(start_expired_api, headers=HEADER, timeout=TIMEOUT)
|
125 |
-
response.raise_for_status()
|
126 |
-
while (
|
127 |
-
requests.get(status_api, headers=HEADER, timeout=TIMEOUT).json()["Data"][
|
128 |
-
"Status"
|
129 |
-
]
|
130 |
-
!= "Running"
|
131 |
-
):
|
132 |
-
requests.get(repo_page, headers=HEADER, timeout=TIMEOUT)
|
133 |
-
time.sleep(holding_delay)
|
134 |
-
|
135 |
-
except requests.exceptions.Timeout as e:
|
136 |
-
print(f"Failed to activate {repo}: {e}, retrying...")
|
137 |
-
activate_studio(repo)
|
138 |
-
|
139 |
-
except Exception as e:
|
140 |
-
print(e)
|
141 |
-
|
142 |
-
|
143 |
-
def send_email(
|
144 |
-
content,
|
145 |
-
title="Runtime error detected",
|
146 |
-
header="Please fix following repo(s):",
|
147 |
-
email=os.getenv("email"),
|
148 |
-
password=os.getenv("smtp"),
|
149 |
-
target=os.getenv("target"),
|
150 |
-
):
|
151 |
-
body = f"""
|
152 |
-
<html>
|
153 |
-
<body>
|
154 |
-
<h2>{header}</h2>
|
155 |
-
{content}
|
156 |
-
</body>
|
157 |
-
</html>
|
158 |
-
"""
|
159 |
-
response = requests.get(
|
160 |
-
"http://api.mmp.cc/api/mail",
|
161 |
-
params={
|
162 |
-
"host": "smtp.163.com",
|
163 |
-
"Port": 25,
|
164 |
-
"key": password, # apikey
|
165 |
-
"email": email, # from
|
166 |
-
"mail": target, # to
|
167 |
-
"title": title, # subject
|
168 |
-
"name": "ksa", # nickname
|
169 |
-
"text": body, # content
|
170 |
-
},
|
171 |
-
)
|
172 |
-
if response.status_code == 200:
|
173 |
-
result: dict = response.json()
|
174 |
-
if result.get("status") == "success":
|
175 |
-
print("Email sent successfully!")
|
176 |
-
else:
|
177 |
-
print(f"Failed to send email: {result.get('message')}")
|
178 |
-
|
179 |
-
else:
|
180 |
-
print(f"Request failed with status code: {response.status_code}")
|
181 |
-
|
182 |
-
|
183 |
-
def activate(users=os.getenv("users")):
|
184 |
-
spaces, studios, failures = [], [], []
|
185 |
-
usernames = users.split(";")
|
186 |
-
for user in tqdm(usernames, desc="Collecting spaces"):
|
187 |
-
username = user.strip()
|
188 |
-
if username:
|
189 |
-
sleeps, errors = get_spaces(username)
|
190 |
-
spaces += sleeps
|
191 |
-
failures += errors
|
192 |
-
time.sleep(DELAY)
|
193 |
-
|
194 |
-
for space in tqdm(spaces, desc="Activating spaces"):
|
195 |
-
activate_space(space)
|
196 |
-
time.sleep(DELAY)
|
197 |
-
|
198 |
-
for user in tqdm(usernames, desc="Collecting studios"):
|
199 |
-
username = user.strip()
|
200 |
-
if username:
|
201 |
-
sleeps, errors = get_studios(username)
|
202 |
-
studios += sleeps
|
203 |
-
failures += errors
|
204 |
-
time.sleep(DELAY)
|
205 |
-
|
206 |
-
for studio in tqdm(studios, desc="Activating studios"):
|
207 |
-
threading.Thread(target=activate_studio, args=(studio,), daemon=True).start()
|
208 |
-
time.sleep(DELAY)
|
209 |
-
|
210 |
-
print("\n".join(spaces + studios) + "\nActivation complete!")
|
211 |
-
content = ""
|
212 |
-
for failure in failures:
|
213 |
-
errepo: str = failure
|
214 |
-
errepo = errepo.replace(HF_DOMAIN, "").replace(MS_DOMAIN, "")
|
215 |
-
content += f"<br><a href='{failure}'>{errepo[1:]}</a><br>"
|
216 |
-
|
217 |
-
if content:
|
218 |
-
send_email(content)
|
219 |
|
220 |
|
221 |
def run_schedule():
|
|
|
|
|
|
|
222 |
while True:
|
223 |
schedule.run_pending()
|
224 |
time.sleep(DELAY)
|
225 |
|
226 |
|
227 |
-
def monitor(period=
|
228 |
-
activate()
|
229 |
print(f"Monitor is on and triggered every {period}h...")
|
230 |
-
schedule.every(int(period)).hours.do(
|
231 |
threading.Thread(target=run_schedule, daemon=True).start()
|
232 |
|
233 |
|
234 |
def tasklist():
|
|
|
235 |
jobs = schedule.get_jobs()
|
236 |
for job in jobs:
|
237 |
last_run = fix_datetime(job.last_run)
|
|
|
|
|
|
|
1 |
import time
|
|
|
2 |
import schedule
|
3 |
import threading
|
4 |
import gradio as gr
|
5 |
+
from activate import activates
|
6 |
+
from report import batch_report
|
7 |
+
from config import *
|
8 |
+
from times import *
|
|
|
9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
+
def trigger():
|
12 |
+
activates()
|
13 |
+
batch_report()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
|
15 |
|
16 |
def run_schedule():
|
17 |
+
global START_TIME
|
18 |
+
START_TIME = datetime.now()
|
19 |
+
trigger()
|
20 |
while True:
|
21 |
schedule.run_pending()
|
22 |
time.sleep(DELAY)
|
23 |
|
24 |
|
25 |
+
def monitor(period=PERIOD):
|
|
|
26 |
print(f"Monitor is on and triggered every {period}h...")
|
27 |
+
schedule.every(int(period)).hours.do(trigger)
|
28 |
threading.Thread(target=run_schedule, daemon=True).start()
|
29 |
|
30 |
|
31 |
def tasklist():
|
32 |
+
print(f"Has been running for {calc_time_diff(START_TIME, datetime.now())}")
|
33 |
jobs = schedule.get_jobs()
|
34 |
for job in jobs:
|
35 |
last_run = fix_datetime(job.last_run)
|
config.py
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
DELAY = 1
|
4 |
+
TIMEOUT = 15
|
5 |
+
START_TIME = None
|
6 |
+
HF_DOMAIN = "https://huggingface.co"
|
7 |
+
MS_DOMAIN = "https://www.modelscope.cn"
|
8 |
+
HEADER = {
|
9 |
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537"
|
10 |
+
}
|
11 |
+
|
12 |
+
REPORT_DELAY = int(os.getenv("delay")) # < 3600 * period / len(traitors)
|
13 |
+
TRAITORS = os.getenv("traitors")
|
14 |
+
COOKIE = os.getenv("cookie")
|
15 |
+
PERIOD = os.getenv("period")
|
16 |
+
EMAIL = os.getenv("email")
|
17 |
+
SMTP = os.getenv("smtp")
|
18 |
+
TAG = os.getenv("target")
|
19 |
+
USERS = os.getenv("users")
|
report.py
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import time
|
2 |
+
import json
|
3 |
+
import random
|
4 |
+
import requests
|
5 |
+
from tqdm import tqdm
|
6 |
+
from smtp import send_email
|
7 |
+
from config import *
|
8 |
+
|
9 |
+
|
10 |
+
def txt2list(url=TRAITORS):
|
11 |
+
try: # 发送 GET 请求获取文件内容
|
12 |
+
response = requests.get(url)
|
13 |
+
response.raise_for_status() # 检查请求是否成功
|
14 |
+
return response.text.splitlines()
|
15 |
+
|
16 |
+
except Exception as e:
|
17 |
+
send_email(f"Failed to request traitors: {e}")
|
18 |
+
return []
|
19 |
+
|
20 |
+
|
21 |
+
def send_report_request(mid, ck=COOKIE, reason="1,2,3", reason_v2="4", retry=False):
|
22 |
+
try:
|
23 |
+
bili_jct = ck.split("bili_jct=")[1].split(";")[0]
|
24 |
+
response = requests.post(
|
25 |
+
"https://space.bilibili.com/ajax/report/add",
|
26 |
+
data={
|
27 |
+
"mid": mid,
|
28 |
+
"reason": reason,
|
29 |
+
"reason_v2": reason_v2,
|
30 |
+
"csrf": bili_jct,
|
31 |
+
},
|
32 |
+
headers={
|
33 |
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0",
|
34 |
+
"Cookie": ck,
|
35 |
+
},
|
36 |
+
)
|
37 |
+
msg = json.loads(response.text)["data"]
|
38 |
+
if msg == "举报成功":
|
39 |
+
print(f"{msg}: {mid}")
|
40 |
+
else:
|
41 |
+
send_email(f"Failed to report {mid}: {msg}")
|
42 |
+
|
43 |
+
except Exception as e:
|
44 |
+
print(f"举报 {mid} 失败:{e}")
|
45 |
+
if not retry:
|
46 |
+
time.sleep(random.uniform(REPORT_DELAY - 2, REPORT_DELAY + 2))
|
47 |
+
send_report_request(mid, retry=True)
|
48 |
+
|
49 |
+
|
50 |
+
def batch_report():
|
51 |
+
targets = txt2list()
|
52 |
+
for mid in tqdm(targets, desc="Reporting UIDs..."):
|
53 |
+
send_report_request(mid.strip())
|
54 |
+
time.sleep(random.uniform(REPORT_DELAY - 2, REPORT_DELAY + 2))
|
smtp.py
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests
|
2 |
+
from config import *
|
3 |
+
|
4 |
+
|
5 |
+
def send_email(
|
6 |
+
content,
|
7 |
+
title="Runtime error detected",
|
8 |
+
header="Please fix following repo(s):",
|
9 |
+
email=EMAIL,
|
10 |
+
password=SMTP,
|
11 |
+
target=TAG,
|
12 |
+
):
|
13 |
+
body = f"""
|
14 |
+
<html>
|
15 |
+
<body>
|
16 |
+
<h2>{header}</h2>
|
17 |
+
{content}
|
18 |
+
</body>
|
19 |
+
</html>
|
20 |
+
"""
|
21 |
+
response = requests.get(
|
22 |
+
"http://api.mmp.cc/api/mail",
|
23 |
+
params={
|
24 |
+
"host": "smtp.163.com",
|
25 |
+
"Port": 25,
|
26 |
+
"key": password, # apikey
|
27 |
+
"email": email, # from
|
28 |
+
"mail": target, # to
|
29 |
+
"title": title, # subject
|
30 |
+
"name": "ksa", # nickname
|
31 |
+
"text": body, # content
|
32 |
+
},
|
33 |
+
)
|
34 |
+
if response.status_code == 200:
|
35 |
+
result: dict = response.json()
|
36 |
+
if result.get("status") == "success":
|
37 |
+
print("Email sent successfully!")
|
38 |
+
else:
|
39 |
+
print(f"Failed to send email: {result.get('message')}")
|
40 |
+
|
41 |
+
else:
|
42 |
+
print(f"Request failed with status code: {response.status_code}")
|
times.py
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from datetime import datetime
|
2 |
+
from zoneinfo import ZoneInfo
|
3 |
+
from tzlocal import get_localzone
|
4 |
+
|
5 |
+
|
6 |
+
def fix_datetime(naive_time: datetime, target_tz=ZoneInfo("Asia/Shanghai")):
|
7 |
+
if not naive_time:
|
8 |
+
return None
|
9 |
+
|
10 |
+
local_tz = get_localzone()
|
11 |
+
aware_local = naive_time.replace(tzinfo=local_tz)
|
12 |
+
return aware_local.astimezone(target_tz).strftime("%Y-%m-%d %H:%M:%S")
|
13 |
+
|
14 |
+
|
15 |
+
def calc_time_diff(time1: datetime, time2: datetime):
|
16 |
+
time_diff = time2 - time1
|
17 |
+
days = time_diff.days
|
18 |
+
hours = time_diff.seconds // 3600
|
19 |
+
minutes = (time_diff.seconds % 3600) // 60
|
20 |
+
seconds = time_diff.seconds % 60
|
21 |
+
return f"{days} d {hours} h {minutes} m {seconds} s"
|