Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

更换抖音图文解析方式 #29

Merged
merged 3 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 92 additions & 61 deletions nonebot-plugin-resolver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

from .config import Config
# noinspection PyUnresolvedReferences
from .constants import COMMON_HEADER, URL_TYPE_CODE_DICT, DOUYIN_VIDEO, GENERAL_REQ_LINK, XHS_REQ_LINK, DY_TOUTIAO_INFO, \
from .constants import COMMON_HEADER, URL_TYPE_CODE_DICT, DOUYIN_VIDEO, DOUYIN_TEMP_API, GENERAL_REQ_LINK, XHS_REQ_LINK, DY_TOUTIAO_INFO, \
BILIBILI_HEADER, NETEASE_API_CN, NETEASE_TEMP_API, VIDEO_MAX_MB, \
WEIBO_SINGLE_INFO, KUGOU_TEMP_API
from .core.acfun import parse_url, download_m3u8_videos, parse_m3u8, merge_ac_file_to_mp4
Expand Down Expand Up @@ -362,68 +362,99 @@ async def dy(bot: Bot, event: Event) -> None:
:return:
"""
# 消息
msg: str = str(event.message).strip()
logger.info(msg)
# 正则匹配
reg = r"(http:|https:)\/\/v.douyin.com\/[A-Za-z\d._?%&+\-=#]*"
dou_url = re.search(reg, msg, re.I)[0]
dou_url_2 = httpx.get(dou_url).headers.get('location')
# logger.error(dou_url_2)
reg2 = r".*(video|note)\/(\d+)\/(.*?)"
# 获取到ID
dou_id = re.search(reg2, dou_url_2, re.I)[2]
# logger.info(dou_id)
# 如果没有设置dy的ck就结束,因为获取不到
msg = str(event.message).strip()
match = re.search(r"(http:|https:)\/\/v.douyin.com\/[A-Za-z\d._?%&+\-=#]*", msg, re.I)
dou_url = match.group(0)
douyin_ck = getattr(global_config, "douyin_ck", "")
if douyin_ck == "":
logger.error(global_config)
await douyin.send(Message(f"{GLOBAL_NICKNAME}识别:抖音,无法获取到管理员设置的抖音ck!"))
if not douyin_ck:
await douyin.finish(Message(f"{GLOBAL_NICKNAME}\n来源:【抖音】\n无法获取管理员设置的抖音ck!"))
return
try: # 首先尝试使用备用 API
douyin_temp_data = httpx.get(DOUYIN_TEMP_API.format(dou_url), headers=COMMON_HEADER, timeout=10).json()
data = douyin_temp_data.get("data", {})
item_id = data.get("jx", {}).get("item_id")
item_type = data.get("jx", {}).get("type")

if not item_id or not item_type:
raise ValueError("备用 API 未返回 item_id 或 type")

if item_type == "图集": # 备用API成功解析图集,直接处理
images = data.get("item", {}).get("images", [])
if images: # 只有在有图片的情况下才发送
author = data.get("author", {}).get("name", "")
title = data.get("item", {}).get("title", "")
await douyin.send(Message(f"{GLOBAL_NICKNAME}\n来源:【抖音】\n作者:{author}\n标题:{title}"))
await send_forward_both(bot, event,
make_node_segment(bot.self_id, [MessageSegment.image(url) for url in images]))
return # 处理完成
else: # 如果没有图片,则尝试使用原始 API
logger.warning("备用 API 返回图集类型但未返回图片数据,尝试使用原始 API") # 记录警告信息
# 注意:这里不需要 raise ValueError,直接进入外部的 except 块即可

elif item_type != "图集": # 如果类型不是图集,也使用原始API
logger.warning(f"备用 API 返回类型为 {item_type},尝试使用原始 API") # 记录警告信息


except (httpx.HTTPError, ValueError, KeyError) as e: # 备用 API 失败或未返回图集数据,尝试使用原始 API
logger.warning(f"备用 API 解析失败或未返回图集数据,尝试使用原始API: {e}")

try: # 使用旧版本处理
dou_url_2 = httpx.get(dou_url).headers.get('location')
# logger.error(dou_url_2)
reg2 = r".*(video|note)\/(\d+)\/(.*?)"
# 获取到ID
dou_id = re.search(reg2, dou_url_2, re.I)[2]
# logger.info(dou_id)
headers = {
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'referer': f'https://www.douyin.com/video/{dou_id}',
'cookie': douyin_ck
} | COMMON_HEADER
api_url = DOUYIN_VIDEO.replace("{}", dou_id)
api_url = generate_x_bogus_url(api_url, headers) # 如果请求失败直接返回
async with aiohttp.ClientSession() as session:
async with session.get(api_url, headers=headers, timeout=10) as response:
detail = await response.json()
if detail is None:
await douyin.send(Message(f"{GLOBAL_NICKNAME}识别:抖音,解析失败!"))
return
# 获取信息
detail = detail['aweme_detail']
# 判断是图片还是视频
url_type_code = detail['aweme_type']
url_type = URL_TYPE_CODE_DICT.get(url_type_code, 'video')
await douyin.send(Message(f"{GLOBAL_NICKNAME}\n来源:【抖音】\n标题:{detail.get('desc')}"))
# 根据类型进行发送
if url_type == 'video':
# 识别播放地址
player_uri = detail.get("video").get("play_addr")['uri']
player_real_addr = DY_TOUTIAO_INFO.replace("{}", player_uri)
# 发送视频
# logger.info(player_addr)
# await douyin.send(Message(MessageSegment.video(player_addr)))
await auto_video_send(event, player_real_addr)
elif url_type == 'image':
# 无水印图片列表/No watermark image list
no_watermark_image_list = []
# 有水印图片列表/With watermark image list
watermark_image_list = []
# 遍历图片列表/Traverse image list
for i in detail['images']:
# 无水印图片列表
# no_watermark_image_list.append(i['url_list'][0])
no_watermark_image_list.append(MessageSegment.image(i['url_list'][0]))
# 有水印图片列表
# watermark_image_list.append(i['download_url_list'][0])
# 异步发送
# logger.info(no_watermark_image_list)
# imgList = await asyncio.gather([])
await send_forward_both(bot, event, make_node_segment(bot.self_id, no_watermark_image_list))


except (aiohttp.ClientError, ValueError, KeyError, AttributeError) as e:
logger.error(f"解析失败: {e}")
await douyin.finish(Message(f"{GLOBAL_NICKNAME}\n来源:【抖音】\n解析失败!"))
return
# API、一些后续要用到的参数
headers = {
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'referer': f'https://www.douyin.com/video/{dou_id}',
'cookie': douyin_ck
} | COMMON_HEADER
api_url = DOUYIN_VIDEO.replace("{}", dou_id)
api_url = generate_x_bogus_url(api_url, headers) # 如果请求失败直接返回
async with aiohttp.ClientSession() as session:
async with session.get(api_url, headers=headers, timeout=10) as response:
detail = await response.json()
if detail is None:
await douyin.send(Message(f"{GLOBAL_NICKNAME}识别:抖音,解析失败!"))
return
# 获取信息
detail = detail['aweme_detail']
# 判断是图片还是视频
url_type_code = detail['aweme_type']
url_type = URL_TYPE_CODE_DICT.get(url_type_code, 'video')
await douyin.send(Message(f"{GLOBAL_NICKNAME}识别:抖音,{detail.get('desc')}"))
# 根据类型进行发送
if url_type == 'video':
# 识别播放地址
player_uri = detail.get("video").get("play_addr")['uri']
player_real_addr = DY_TOUTIAO_INFO.replace("{}", player_uri)
# 发送视频
# logger.info(player_addr)
# await douyin.send(Message(MessageSegment.video(player_addr)))
await auto_video_send(event, player_real_addr)
elif url_type == 'image':
# 无水印图片列表/No watermark image list
no_watermark_image_list = []
# 有水印图片列表/With watermark image list
watermark_image_list = []
# 遍历图片列表/Traverse image list
for i in detail['images']:
# 无水印图片列表
# no_watermark_image_list.append(i['url_list'][0])
no_watermark_image_list.append(MessageSegment.image(i['url_list'][0]))
# 有水印图片列表
# watermark_image_list.append(i['download_url_list'][0])
# 异步发送
# logger.info(no_watermark_image_list)
# imgList = await asyncio.gather([])
await send_forward_both(bot, event, make_node_segment(bot.self_id, no_watermark_image_list))


@tik.handle()
Expand Down
7 changes: 6 additions & 1 deletion nonebot-plugin-resolver/constants/tiktok.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
"""
DOUYIN_VIDEO = "https://www.douyin.com/aweme/v1/web/aweme/detail/?device_platform=webapp&aid=6383&channel=channel_pc_web&aweme_id={}&pc_client_type=1&version_code=190500&version_name=19.5.0&cookie_enabled=true&screen_width=1344&screen_height=756&browser_language=zh-CN&browser_platform=Win32&browser_name=Firefox&browser_version=118.0&browser_online=true&engine_name=Gecko&engine_version=109.0&os_name=Windows&os_version=10&cpu_core_num=16&device_memory=&platform=PC"

"""
dy临时接口
"""
DOUYIN_TEMP_API = "https://api.xingzhige.com/API/douyin/?url={}"

"""
今日头条 DY API
"""
Expand All @@ -26,4 +31,4 @@
"""
tiktok视频信息
"""
TIKTOK_VIDEO = "https://api22-normal-c-alisg.tiktokv.com/aweme/v1/feed/"
TIKTOK_VIDEO = "https://api22-normal-c-alisg.tiktokv.com/aweme/v1/feed/"
Loading