Sync all projects
This commit is contained in:
@@ -0,0 +1,578 @@
|
||||
import re, sys, json, base64
|
||||
from Crypto.Cipher import AES
|
||||
from urllib.parse import quote
|
||||
from Crypto.Util.Padding import unpad
|
||||
from base.spider import Spider
|
||||
|
||||
sys.path.append('..')
|
||||
|
||||
class Spider(Spider):
|
||||
headers = {'User-Agent': 'okhttp/4.12.0'}
|
||||
|
||||
FIXED_CONFIG = {
|
||||
'host': 'http://pgcms.lyyytv.cn',
|
||||
'cmskey': 'wP5btxoc3yv8FoBQENFZumF0EUYr4LTy'
|
||||
}
|
||||
|
||||
def init(self, extend=''):
|
||||
self.host = self.FIXED_CONFIG['host']
|
||||
self.cmskey = self.FIXED_CONFIG.get('cmskey', '')
|
||||
|
||||
# ============ 原来的解析器(虚联、虚移、虚翼使用这个)============
|
||||
self.external_parser = "http://yoyo.ovg.sh/yt/ttjx.php?url="
|
||||
|
||||
# ============ 新增解析器(虚腾、虚果、虚爱、虚酷、虚哔、虚哩使用这个)============
|
||||
self.need_parse_lines = ["藤藤", "茫茫", "小爱", "小优", "小哩"]
|
||||
|
||||
# 新增解析源列表(按优先级排序)
|
||||
self.new_parsers = [
|
||||
"http://nm.4688888.xyz/jiexi.php?data=093207528aec95afa4616e7afb8e2649&url=", # 牛马解析
|
||||
"http://120.46.190.255//jiexi.php?data=f603bb5f52a0cc1db4064599c3cc9abf&url=", # 小白解析
|
||||
"http://8.155.50.80/xiayexk.php?url=", # 夏夜解析
|
||||
"https://qsy.wya6.cn/parse.php?url=", # 无意云解析
|
||||
"http://zhuimi.摸鱼儿.com/moyu/zhuimi?token=uZBC6q6w&url=", # 摸鱼解析
|
||||
"http://yoyo168.zabc.net/getjx.php?host=http://154.222.26.58:7788&key=guodan2004031600&api=6d735c167eeda72b836cf382e4863f3f&v=", # 呦呦解析
|
||||
"https://cachem3u8.2s0.cn:8899/Th_JsonApi.php?url=", #擦车解析
|
||||
"http://mg.itufm.top/mg.php?url=",#芒果解析
|
||||
"https://jx.xmflv.com/?url=", # 虾米嗅探
|
||||
"https://pp1301239612013983305599.tai2tai.sbs/?url=", # 太乙嗅探
|
||||
"https://jx.m3u8.tv/jiexi/?url=" # m3u8解析
|
||||
]
|
||||
|
||||
self.direct_sniff_keys = [
|
||||
"tai2tai.sbs",
|
||||
"xmflv.com",
|
||||
"m3u8.tv"
|
||||
]
|
||||
|
||||
# ============ 域名替换规则 ============
|
||||
self.domain_replace_rules = {
|
||||
}
|
||||
|
||||
# ============ 线路配置开始 ============
|
||||
self.line_name_mapping = {
|
||||
"移动云": "移不动",
|
||||
"天翼云": "天意也",
|
||||
"联通云": "联不通",
|
||||
"蓝奏云": "拦着揍",
|
||||
"腾讯": "藤藤",
|
||||
"芒果": "茫茫",
|
||||
"爱奇艺": "小爱",
|
||||
"优酷": "小优",
|
||||
"BL线路": "小哩"
|
||||
}
|
||||
|
||||
self.line_order = [
|
||||
"移不动", "天意也", "联不通", "拦着揍", "藤藤", "茫茫", "小爱", "小优", "小哩"
|
||||
]
|
||||
|
||||
# ============ 新增:线路特定的headers ============
|
||||
self.line_headers = {
|
||||
"藤藤": { # 腾讯视频
|
||||
'User-Agent': 'okhttp/4.12.0',
|
||||
'Referer': 'https://v.qq.com'
|
||||
},
|
||||
"茫茫": { # 芒果TV
|
||||
'User-Agent': 'okhttp/4.12.0',
|
||||
'Referer': ''
|
||||
},
|
||||
"小爱": { # 爱奇艺
|
||||
'User-Agent': 'okhttp/4.12.0',
|
||||
'Referer': 'https://www.iqiyi.com'
|
||||
},
|
||||
"小优": { # 优酷
|
||||
'User-Agent': 'okhttp/4.12.0',
|
||||
'Referer': 'https://v.youku.com'
|
||||
},
|
||||
"小哩": { # Bilibili需要Referer
|
||||
'User-Agent': 'okhttp/4.12.0',
|
||||
'Referer': 'https://www.bilibili.com'
|
||||
}
|
||||
}
|
||||
|
||||
def homeVideoContent(self):
|
||||
data = self.fetch(f"{self.host}/api.php/app/index_video?token=", headers=self.headers).json()
|
||||
videos = []
|
||||
for item in data['list']:
|
||||
videos.extend(item['vlist'])
|
||||
return {'list': videos}
|
||||
|
||||
def homeContent(self, filter):
|
||||
data = self.fetch(f"{self.host}/api.php/app/nav?token=", headers=self.headers).json()
|
||||
keys = ["class", "area", "lang", "year", "letter", "by", "sort"]
|
||||
filters = {}
|
||||
classes = []
|
||||
|
||||
for item in data['list']:
|
||||
has_non_empty_field = False
|
||||
jsontype_extend = item["type_extend"]
|
||||
classes.append({"type_name": item["type_name"], "type_id": item["type_id"]})
|
||||
|
||||
for key in keys:
|
||||
if key in jsontype_extend and jsontype_extend[key].strip() != "":
|
||||
has_non_empty_field = True
|
||||
break
|
||||
|
||||
if has_non_empty_field:
|
||||
filters[str(item["type_id"])] = []
|
||||
|
||||
for dkey in jsontype_extend:
|
||||
if dkey in keys and jsontype_extend[dkey].strip() != "":
|
||||
values = jsontype_extend[dkey].split(",")
|
||||
value_array = []
|
||||
for value in values:
|
||||
if value.strip() != "":
|
||||
value_array.append({"n": value.strip(), "v": value.strip()})
|
||||
filters[str(item["type_id"])].append({"key": dkey, "name": dkey, "value": value_array})
|
||||
|
||||
return {"class": classes, "filters": filters}
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
params = {
|
||||
'tid': tid,
|
||||
'class': extend.get('class', ''),
|
||||
'area': extend.get('area', ''),
|
||||
'lang': extend.get('lang', ''),
|
||||
'year': extend.get('year', ''),
|
||||
'limit': '18',
|
||||
'pg': pg
|
||||
}
|
||||
data = self.fetch(f"{self.host}/api.php/app/video", params=params, headers=self.headers).json()
|
||||
return data
|
||||
|
||||
def searchContent(self, key, quick, pg="1"):
|
||||
data = self.fetch(f"{self.host}/api.php/app/search?text={key}&pg={pg}", headers=self.headers).json()
|
||||
videos = data['list']
|
||||
for item in data['list']:
|
||||
item.pop('type', None)
|
||||
return {'list': videos, 'page': pg}
|
||||
|
||||
def detailContent(self, ids):
|
||||
data = self.fetch(f"{self.host}/api.php/app/video_detail?id={ids[0]}", headers=self.headers).json()['data']
|
||||
show, paly_urls = [], []
|
||||
|
||||
for i in data['vod_url_with_player']:
|
||||
original_name = i['name'].strip()
|
||||
|
||||
if original_name in self.line_name_mapping and self.line_name_mapping[original_name] == "":
|
||||
continue
|
||||
|
||||
display_name = self.line_name_mapping.get(original_name, original_name)
|
||||
|
||||
urls = i['url'].split('#')
|
||||
urls2 = []
|
||||
for j in urls:
|
||||
if j:
|
||||
if j.startswith('lvdou+'):
|
||||
j = self.lvdou(j)
|
||||
|
||||
j = self.replace_domains(j)
|
||||
|
||||
url = j.split('$', 1)
|
||||
if len(url) == 2:
|
||||
urls2.append(f"{url[0]}${url[1]}")
|
||||
else:
|
||||
urls2.append(j)
|
||||
paly_urls.append('#'.join(urls2))
|
||||
show.append(display_name)
|
||||
|
||||
data.pop('vod_url_with_player')
|
||||
|
||||
sorted_show, sorted_paly_urls = self.sort_play_lines(show, paly_urls)
|
||||
|
||||
data['vod_play_from'] = '$$$'.join(sorted_show)
|
||||
data['vod_play_url'] = '$$$'.join(sorted_paly_urls)
|
||||
return {'list': [data]}
|
||||
|
||||
def playerContent(self, flag, video_id, vipFlags):
|
||||
print(f"=== playerContent 被调用 ===")
|
||||
print(f"线路标识: {flag}")
|
||||
print(f"原始播放地址: {video_id}")
|
||||
|
||||
# 获取该线路特定的headers
|
||||
line_header = self.line_headers.get(flag, self.headers)
|
||||
print(f"使用headers: {line_header}")
|
||||
|
||||
if video_id.startswith('lvdou+'):
|
||||
decrypted_url = self.lvdou(video_id)
|
||||
else:
|
||||
decrypted_url = video_id
|
||||
|
||||
decrypted_url = self.replace_domains(decrypted_url)
|
||||
|
||||
print(f"解密/替换后地址: {decrypted_url}")
|
||||
|
||||
if decrypted_url.endswith('.m3u8') or '.m3u8?' in decrypted_url or '#EXTM3U' in decrypted_url:
|
||||
print(f"✅ 已经是m3u8直链,直连播放")
|
||||
return {
|
||||
'parse': 0,
|
||||
'jx': 0,
|
||||
'url': decrypted_url,
|
||||
'header': line_header
|
||||
}
|
||||
|
||||
if flag in self.need_parse_lines:
|
||||
print(f"线路 {flag} 需要解析")
|
||||
return self._try_parsers(decrypted_url, self.new_parsers, flag)
|
||||
elif re.search(r'(?:www\.iqiyi|v\.qq|v\.youku|www\.mgtv|www\.bilibili)\.com', decrypted_url):
|
||||
print(f"视频网站链接,使用解析器")
|
||||
return self._try_parsers(decrypted_url, self.new_parsers, flag)
|
||||
else:
|
||||
print(f"线路 {flag} 使用external_parser直接解析")
|
||||
return self._parse_external_direct(decrypted_url, flag)
|
||||
|
||||
def replace_domains(self, url):
|
||||
if not url:
|
||||
return url
|
||||
|
||||
for old_domain, new_domain in self.domain_replace_rules.items():
|
||||
if old_domain in url:
|
||||
url = url.replace(old_domain, new_domain)
|
||||
|
||||
return url
|
||||
|
||||
def _parse_external_direct(self, video_url, flag=None):
|
||||
print(f"使用external_parser直接解析")
|
||||
|
||||
# 获取该线路特定的headers
|
||||
line_header = self.line_headers.get(flag, self.headers) if flag else self.headers
|
||||
|
||||
try:
|
||||
parsed_url = f"{self.external_parser}{quote(video_url)}"
|
||||
print(f"解析地址: {parsed_url[:150]}...")
|
||||
|
||||
response = self.fetch(parsed_url, allow_redirects=True, timeout=10, headers=line_header)
|
||||
|
||||
if response.status_code != 200:
|
||||
print(f"解析失败,状态码: {response.status_code}")
|
||||
return {
|
||||
'parse': 1,
|
||||
'jx': 1,
|
||||
'url': video_url,
|
||||
'header': line_header
|
||||
}
|
||||
|
||||
content = response.text
|
||||
|
||||
if content.strip().startswith('{'):
|
||||
try:
|
||||
json_response = response.json()
|
||||
print(f"解析器返回JSON格式")
|
||||
|
||||
possible_fields = ['url', 'm3u8', 'play_url', 'video_url', 'src', 'data']
|
||||
|
||||
for field in possible_fields:
|
||||
if field in json_response:
|
||||
if isinstance(json_response[field], str):
|
||||
video_url_result = json_response[field]
|
||||
print(f"从字段 {field} 提取到地址: {video_url_result[:100]}")
|
||||
video_url_result = self.replace_domains(video_url_result)
|
||||
return {
|
||||
'parse': 0,
|
||||
'jx': 0,
|
||||
'url': video_url_result,
|
||||
'header': line_header
|
||||
}
|
||||
elif isinstance(json_response[field], dict):
|
||||
for sub_field in possible_fields:
|
||||
if sub_field in json_response[field] and isinstance(json_response[field][sub_field], str):
|
||||
video_url_result = json_response[field][sub_field]
|
||||
print(f"从嵌套字段 {field}.{sub_field} 提取到地址: {video_url_result[:100]}")
|
||||
video_url_result = self.replace_domains(video_url_result)
|
||||
return {
|
||||
'parse': 0,
|
||||
'jx': 0,
|
||||
'url': video_url_result,
|
||||
'header': line_header
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"JSON解析失败: {e}")
|
||||
|
||||
if '#EXTM3U' in content:
|
||||
print(f"解析器返回m3u8内容")
|
||||
return {
|
||||
'parse': 0,
|
||||
'jx': 0,
|
||||
'url': parsed_url,
|
||||
'header': line_header
|
||||
}
|
||||
|
||||
m3u8_matches = re.findall(r'https?://[^\s<>"\']+\.(?:m3u8|mp4)[^\s<>"\']*', content)
|
||||
if m3u8_matches:
|
||||
video_url_result = m3u8_matches[0]
|
||||
print(f"从页面提取到视频地址: {video_url_result[:100]}")
|
||||
video_url_result = self.replace_domains(video_url_result)
|
||||
return {
|
||||
'parse': 0,
|
||||
'jx': 0,
|
||||
'url': video_url_result,
|
||||
'header': line_header
|
||||
}
|
||||
|
||||
print(f"未找到视频地址,返回原链让壳子解析")
|
||||
return {
|
||||
'parse': 1,
|
||||
'jx': 1,
|
||||
'url': video_url,
|
||||
'header': line_header
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
print(f"解析器异常: {e}")
|
||||
return {
|
||||
'parse': 1,
|
||||
'jx': 1,
|
||||
'url': video_url,
|
||||
'header': line_header
|
||||
}
|
||||
|
||||
def _try_parsers(self, video_url, parsers, flag=None):
|
||||
"""
|
||||
核心修复:尝试所有解析器,直到找到可用的
|
||||
只有两种情况下才返回:1.找到视频地址 2.所有解析器都试过了
|
||||
"""
|
||||
print(f"尝试 {len(parsers)} 个解析器")
|
||||
|
||||
# 获取该线路特定的headers
|
||||
line_header = self.line_headers.get(flag, self.headers) if flag else self.headers
|
||||
|
||||
# 按优先级尝试所有解析器
|
||||
for i, parser in enumerate(parsers):
|
||||
try:
|
||||
parsed_url = f"{parser}{quote(video_url)}"
|
||||
print(f"\n[{i+1}/{len(parsers)}] 尝试解析器: {parser}")
|
||||
print(f"解析地址: {parsed_url[:100]}...")
|
||||
|
||||
# 检查是否是嗅探解析器
|
||||
is_direct_sniff = any(key in parser for key in self.direct_sniff_keys)
|
||||
|
||||
if is_direct_sniff:
|
||||
# 嗅探解析器:返回给壳子处理
|
||||
print(f"✅ 嗅探解析器,返回给壳子处理 (parse=1)")
|
||||
return {
|
||||
'parse': 1,
|
||||
'url': parsed_url,
|
||||
'header': line_header
|
||||
}
|
||||
|
||||
# 普通解析器:尝试请求获取视频地址
|
||||
print(f"普通解析器,尝试获取视频地址...")
|
||||
response = self.fetch(parsed_url, timeout=10, allow_redirects=True, headers=line_header)
|
||||
|
||||
if response.status_code != 200:
|
||||
print(f"✗ 解析器返回状态码: {response.status_code}")
|
||||
continue # 继续下一个解析器
|
||||
|
||||
content = response.text
|
||||
|
||||
# 检查是否是测试视频
|
||||
if self._is_test_video(content):
|
||||
print(f"✗ 解析器返回测试视频")
|
||||
continue # 继续下一个解析器
|
||||
|
||||
# 1. 检查是否是m3u8内容
|
||||
if '#EXTM3U' in content:
|
||||
print(f"✓ 解析器返回m3u8内容")
|
||||
# 检查是否可以直接播放
|
||||
if re.search(r'\.m3u8', content) or 'video/' in response.headers.get('Content-Type', ''):
|
||||
return {
|
||||
'parse': 0,
|
||||
'jx': 0,
|
||||
'url': parsed_url,
|
||||
'header': line_header
|
||||
}
|
||||
else:
|
||||
# 需要进一步处理
|
||||
return {
|
||||
'parse': 1,
|
||||
'jx': 0,
|
||||
'url': parsed_url,
|
||||
'header': line_header
|
||||
}
|
||||
|
||||
# 2. 检查JSON格式
|
||||
if content.strip().startswith('{'):
|
||||
try:
|
||||
json_data = json.loads(content)
|
||||
video_url_from_json = self._extract_video_url_from_json(json_data)
|
||||
if video_url_from_json:
|
||||
video_url_from_json = self.replace_domains(video_url_from_json)
|
||||
print(f"✓ 从JSON提取到视频地址: {video_url_from_json[:100]}")
|
||||
return {
|
||||
'parse': 0,
|
||||
'jx': 0,
|
||||
'url': video_url_from_json,
|
||||
'header': line_header
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"JSON解析失败: {e}")
|
||||
# JSON解析失败,继续下一个解析器
|
||||
continue
|
||||
|
||||
# 3. 从HTML中提取视频地址
|
||||
video_patterns = [
|
||||
r'src=["\']([^"\']+\.(?:m3u8|mp4)[^"\']*)["\']',
|
||||
r'url["\']?\s*:\s*["\']([^"\']+\.(?:m3u8|mp4)[^"\']*)["\']',
|
||||
r'video["\']?\s*:\s*["\']([^"\']+\.(?:m3u8|mp4)[^"\']*)["\']',
|
||||
r'file["\']?\s*:\s*["\']([^"\']+\.(?:m3u8|mp4)[^"\']*)["\']',
|
||||
]
|
||||
|
||||
for pattern in video_patterns:
|
||||
matches = re.findall(pattern, content, re.IGNORECASE)
|
||||
if matches:
|
||||
for match in matches:
|
||||
if match.startswith('http'):
|
||||
video_url_result = match
|
||||
video_url_result = self.replace_domains(video_url_result)
|
||||
print(f"✓ 从HTML提取到视频地址: {video_url_result[:100]}")
|
||||
return {
|
||||
'parse': 0,
|
||||
'jx': 0,
|
||||
'url': video_url_result,
|
||||
'header': line_header
|
||||
}
|
||||
|
||||
# 4. 直接查找.m3u8或.mp4链接
|
||||
direct_matches = re.findall(r'https?://[^\s<>"\']+\.(?:m3u8|mp4)[^\s<>"\']*', content)
|
||||
if direct_matches:
|
||||
video_url_result = direct_matches[0]
|
||||
video_url_result = self.replace_domains(video_url_result)
|
||||
print(f"✓ 直接提取到视频地址: {video_url_result[:100]}")
|
||||
return {
|
||||
'parse': 0,
|
||||
'jx': 0,
|
||||
'url': video_url_result,
|
||||
'header': line_header
|
||||
}
|
||||
|
||||
# 5. 如果没有找到视频地址,继续尝试下一个解析器
|
||||
print(f"✗ 未找到视频地址,继续尝试下一个解析器")
|
||||
continue # 关键修复:这里用continue而不是return
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 解析器失败: {str(e)[:100]}")
|
||||
continue # 继续下一个解析器
|
||||
|
||||
# 所有解析器都失败,才返回原链让壳子处理
|
||||
print(f"✗ 所有 {len(parsers)} 个解析器都尝试过了,全部失败")
|
||||
print(f"返回原链让壳子处理")
|
||||
return {
|
||||
'parse': 1,
|
||||
'jx': 1,
|
||||
'url': video_url,
|
||||
'header': line_header
|
||||
}
|
||||
|
||||
def _extract_video_url_from_json(self, json_data):
|
||||
if not json_data:
|
||||
return None
|
||||
|
||||
possible_fields = ['url', 'm3u8', 'play_url', 'video_url', 'src', 'link']
|
||||
|
||||
for field in possible_fields:
|
||||
if field in json_data and json_data[field] and isinstance(json_data[field], str):
|
||||
return json_data[field]
|
||||
|
||||
if 'data' in json_data and isinstance(json_data['data'], dict):
|
||||
for field in possible_fields:
|
||||
if field in json_data['data'] and json_data['data'][field] and isinstance(json_data['data'][field], str):
|
||||
return json_data['data'][field]
|
||||
|
||||
return None
|
||||
|
||||
def _is_test_video(self, text):
|
||||
if not text:
|
||||
return False
|
||||
|
||||
text_lower = text.lower()
|
||||
|
||||
test_patterns = [
|
||||
'oplist.wya6.cn',
|
||||
'web.wya6.com',
|
||||
'k0udeyaayccydz.djvod.ndcimgs.com',
|
||||
'pan.baidu.re',
|
||||
'www.panurl.cn',
|
||||
'test.mp4', 'demo.mp4', 'sample.mp4',
|
||||
'short.mp4', 'preview.mp4', 'trailer.mp4',
|
||||
'ad.mp4', '广告.mp4',
|
||||
'/10秒.mp4', '/15秒.mp4', '/30秒.mp4',
|
||||
'/10s.mp4', '/15s.mp4', '/30s.mp4',
|
||||
'error.html', '404.mp4', 'error.mp4',
|
||||
]
|
||||
|
||||
for pattern in test_patterns:
|
||||
if pattern in text_lower:
|
||||
print(f"检测到测试视频特征: {pattern}")
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def lvdou(self, text):
|
||||
key = self.cmskey[:16].encode("utf-8")
|
||||
iv = self.cmskey[-16:].encode("utf-8")
|
||||
original_text = text
|
||||
url_prefix = "lvdou+"
|
||||
|
||||
if original_text.startswith(url_prefix):
|
||||
ciphertext_b64 = original_text[len(url_prefix):]
|
||||
try:
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||
ct_bytes = base64.b64decode(ciphertext_b64)
|
||||
pt_bytes = cipher.decrypt(ct_bytes)
|
||||
return unpad(pt_bytes, AES.block_size).decode('utf-8')
|
||||
except Exception:
|
||||
return original_text
|
||||
else:
|
||||
return original_text
|
||||
|
||||
def sort_play_lines(self, show_list, url_list):
|
||||
if len(show_list) != len(url_list):
|
||||
return show_list, url_list
|
||||
|
||||
original_order = {}
|
||||
for idx, name in enumerate(show_list):
|
||||
original_order[name] = idx
|
||||
|
||||
line_map = {}
|
||||
for name, url in zip(show_list, url_list):
|
||||
line_map[name] = url
|
||||
|
||||
sorted_show = []
|
||||
sorted_urls = []
|
||||
|
||||
for ordered_name in self.line_order:
|
||||
if ordered_name in line_map:
|
||||
sorted_show.append(ordered_name)
|
||||
sorted_urls.append(line_map[ordered_name])
|
||||
line_map.pop(ordered_name)
|
||||
|
||||
remaining_lines = [(name, line_map[name], original_order[name])
|
||||
for name in line_map.keys()]
|
||||
remaining_lines.sort(key=lambda x: x[2])
|
||||
|
||||
for name, url, _ in remaining_lines:
|
||||
sorted_show.append(name)
|
||||
sorted_urls.append(url)
|
||||
|
||||
return sorted_show, sorted_urls
|
||||
|
||||
def getName(self):
|
||||
return "小心儿悠悠(修复版)"
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
return True
|
||||
|
||||
def fetch(self, url, **kwargs):
|
||||
import requests
|
||||
if 'headers' not in kwargs:
|
||||
kwargs['headers'] = self.headers
|
||||
if 'timeout' not in kwargs:
|
||||
kwargs['timeout'] = 10
|
||||
try:
|
||||
return requests.get(url, **kwargs)
|
||||
except Exception as e:
|
||||
print(f"请求失败: {str(e)}")
|
||||
from requests.models import Response
|
||||
response = Response()
|
||||
response.status_code = 500
|
||||
return response
|
||||
Reference in New Issue
Block a user