fix🐛: 修正b站订阅

This commit is contained in:
HibiKier 2023-09-06 18:53:15 +08:00
parent fb26be821b
commit 1130569a20
8 changed files with 3372 additions and 3235 deletions

View File

@ -331,6 +331,10 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能
## 更新
### 2023/9/6
* 修正b站订阅
### 2023/8/28
* 重构`红包`功能, 允许一个群聊中有多个用户发起的红包,发送`开`等命令会开启群中所有条件允许的红包,新增`红包结算排行`,在红包退回或抢完时统计,在`塞红包`时at可以发送专属红包

View File

@ -70,6 +70,12 @@ __plugin_configs__ = {
"default_value": False,
"type": bool,
},
"DOWNLOAD_DYNAMIC_IMAGE": {
"value": True,
"help": "下载动态中的图片并发送在提醒消息中",
"default_value": True,
"type": bool,
},
}
add_sub = on_command("添加订阅", priority=5, block=True)
@ -255,11 +261,11 @@ async def _():
if sub:
try:
logger.debug(f"Bilibili订阅开始检测{sub.sub_id}")
rst = await get_sub_status(sub.sub_id, sub.sub_type)
await send_sub_msg(rst or "", sub, bot) # type: ignore
rst = await get_sub_status(sub.sub_id, sub.sub_id, sub.sub_type)
await send_sub_msg(rst, sub, bot) # type: ignore
if sub.sub_type == "live":
rst = await get_sub_status(sub.sub_id, "up")
await send_sub_msg(rst or "", sub, bot) # type: ignore
rst += "\n" + await get_sub_status(sub.uid, sub.sub_id, "up")
await send_sub_msg(rst, sub, bot) # type: ignore
except Exception as e:
logger.error(f"B站订阅推送发生错误 sub_id{sub.sub_id}", e=e)
@ -298,4 +304,4 @@ async def send_sub_msg(rst: str, sub: BilibiliSub, bot: Bot):
else:
await bot.send_private_msg(user_id=int(x), message=Message(rst))
except Exception as e:
logger.error(f"B站订阅推送发生错误 sub_id{sub.sub_id}", e=e)
logger.error(f"B站订阅推送发生错误 sub_id: {sub.sub_id}", e=e)

View File

@ -1,22 +1,25 @@
import random
from asyncio.exceptions import TimeoutError
from datetime import datetime
from typing import Optional, Tuple
from typing import Optional, Tuple, Union
# from .utils import get_videos
from bilireq import dynamic
from bilireq.exceptions import ResponseCodeError
from bilireq.grpc.dynamic import grpc_get_user_dynamics
from bilireq.grpc.protos.bilibili.app.dynamic.v2.dynamic_pb2 import DynamicType
from bilireq.live import get_room_info_by_id
from bilireq.user import get_videos
from nonebot.adapters.onebot.v11 import MessageSegment
from nonebot.adapters.onebot.v11 import Message, MessageSegment
from configs.config import Config
from configs.path_config import IMAGE_PATH, TEMP_PATH
from services.log import logger
from utils.browser import get_browser
from utils.http_utils import AsyncHttpx, AsyncPlaywright
from utils.manager import resources_manager
from utils.message_builder import image
from utils.utils import get_bot
from utils.utils import get_bot, get_local_proxy
from .model import BilibiliSub
from .utils import get_meta, get_user_card
@ -27,6 +30,17 @@ DYNAMIC_PATH = IMAGE_PATH / "bilibili_sub" / "dynamic"
DYNAMIC_PATH.mkdir(exist_ok=True, parents=True)
TYPE2MSG = {
0: "发布了新动态",
DynamicType.forward: "转发了一条动态",
DynamicType.word: "发布了新文字动态",
DynamicType.draw: "发布了新图文动态",
DynamicType.av: "发布了新投稿",
DynamicType.article: "发布了新专栏",
DynamicType.music: "发布了新音频",
}
resources_manager.add_temp_dir(DYNAMIC_PATH)
@ -52,6 +66,15 @@ async def add_live_sub(live_id: str, sub_user: str) -> str:
short_id = live_info["short_id"]
title = live_info["title"]
live_status = live_info["live_status"]
try:
user_info = await get_user_card(uid)
except ResponseCodeError:
return f"未找到UpId{uid} 的信息请检查Id是否正确"
uname = user_info["name"]
dynamic_info = await dynamic.get_user_dynamics(int(uid))
dynamic_upload_time = 0
if dynamic_info.get("cards"):
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["dynamic_id"]
if await BilibiliSub.sub_handle(
room_id,
"live",
@ -59,11 +82,9 @@ async def add_live_sub(live_id: str, sub_user: str) -> str:
uid=uid,
live_short_id=short_id,
live_status=live_status,
uname=uname,
dynamic_upload_time=dynamic_upload_time,
):
try:
await _get_up_status(room_id)
except Exception as e:
logger.error(f"获取主播UP信息失败: {live_id} 错误", e=e)
if data := await BilibiliSub.get_or_none(sub_id=room_id):
uname = data.uname
return (
@ -102,11 +123,7 @@ async def add_up_sub(uid: str, sub_user: str) -> str:
"""bilibili_api.user库中User类的get_dynamics改为bilireq.dynamic库的get_user_dynamics方法"""
dynamic_info = await dynamic.get_user_dynamics(int(uid))
if dynamic_info.get("cards"):
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
"""bilibili_api.user库中User类的get_videos改为bilireq.user库的get_videos方法"""
video_info = await get_videos(int(uid))
if video_info["list"].get("vlist"):
latest_video_created = video_info["list"]["vlist"][0]["created"]
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["dynamic_id"]
except Exception as e:
logger.error(f"订阅Up uid: {uid} 错误", e=e)
if await BilibiliSub.sub_handle(
@ -204,7 +221,7 @@ async def get_media_id(keyword: str) -> Optional[dict]:
return {}
async def get_sub_status(id_: str, sub_type: str) -> Optional[str]:
async def get_sub_status(id_: str, sub_id: str, sub_type: str) -> Union[Message, str]:
"""
获取订阅状态
:param id_: 订阅 id
@ -214,7 +231,7 @@ async def get_sub_status(id_: str, sub_type: str) -> Optional[str]:
if sub_type == "live":
return await _get_live_status(id_)
elif sub_type == "up":
return await _get_up_status(id_)
return await _get_up_status(id_, sub_id)
elif sub_type == "season":
return await _get_season_status(id_)
except ResponseCodeError as e:
@ -223,9 +240,10 @@ async def get_sub_status(id_: str, sub_type: str) -> Optional[str]:
except Exception as e:
logger.error(f"获取订阅状态发生预料之外的错误 Id_{id_}", e=e)
# return "发生了预料之外的错误..请稍后再试或联系管理员....."
return ""
async def _get_live_status(id_: str) -> Optional[str]:
async def _get_live_status(id_: str) -> str:
"""
获取直播订阅状态
:param id_: 直播间 id
@ -247,56 +265,94 @@ async def _get_live_status(id_: str) -> Optional[str]:
f"标题:{title}\n"
f"直链https://live.bilibili.com/{room_id}"
)
return None
return ""
async def _get_up_status(id_: str) -> Optional[str]:
"""
获取用户投稿状态
:param id_: 订阅 id
:return:
async def _get_up_status(
id_: str, live_id: Optional[str] = None
) -> Union[Message, str]:
"""获取up动态
参数:
id_: up的id
live_id: 直播间id当订阅直播间时才有.
返回:
Union[Message, str]: 消息
"""
rst = ""
if _user := await BilibiliSub.get_or_none(sub_id=id_):
"""bilibili_api.user库中User类的get_user_info改为bilireq.user库的get_user_info方法"""
user_info = await get_user_card(_user.uid)
uname = user_info["name"]
"""bilibili_api.user库中User类的get_videos改为bilireq.user库的get_videos方法"""
video_info = await get_videos(int(_user.uid))
latest_video_created = 0
video = None
dividing_line = "\n-------------\n"
if _user := await BilibiliSub.get_or_none(sub_id=live_id or id_):
dynamics = None
dynamic = None
uname = ""
try:
dynamics = (
await grpc_get_user_dynamics(int(id_), proxy=get_local_proxy())
).list
except Exception as e:
logger.error("获取动态失败...", target=id_, e=e)
if dynamics:
uname = dynamics[0].modules[0].module_author.author.name
for dyn in dynamics:
if int(dyn.extend.dyn_id_str) > _user.dynamic_upload_time:
dynamic = dyn
break
if not dynamic:
logger.debug(f"{_user.sub_type}:{id_} 未有任何动态, 已跳过....")
return ""
if _user.uname != uname:
await BilibiliSub.sub_handle(id_, uname=uname)
dynamic_img, dynamic_upload_time, link = await get_user_dynamic(
_user.uid, _user
await BilibiliSub.sub_handle(live_id or id_, uname=uname)
dynamic_img, link = await get_user_dynamic(dynamic.extend.dyn_id_str, _user)
if not dynamic_img:
logger.debug(f"{id_} 未发布新动态或截图失败, 已跳过....")
return ""
await BilibiliSub.sub_handle(
live_id or id_, dynamic_upload_time=int(dynamic.extend.dyn_id_str)
)
if video_info["list"].get("vlist"):
video = video_info["list"]["vlist"][0]
latest_video_created = video["created"]
if dynamic_img:
await BilibiliSub.sub_handle(id_, dynamic_upload_time=dynamic_upload_time)
rst += f"{uname} 发布了动态!\n" f"{dynamic_img}\n{link}"
if (
latest_video_created
and _user.latest_video_created
and video
and _user.latest_video_created < latest_video_created
):
rst = rst + dividing_line if rst else rst
await BilibiliSub.sub_handle(id_, latest_video_created=latest_video_created)
rst += (
f'{image(video["pic"])}\n'
f"{uname} 投稿了新视频啦\n"
f'标题:{video["title"]}\n'
f'Bvid{video["bvid"]}\n'
f'直链https://www.bilibili.com/video/{video["bvid"]}'
rst += (
f"{uname} {TYPE2MSG.get(dynamic.card_type, TYPE2MSG[0])}\n"
+ dynamic_img
+ f"\n{link}\n"
)
video_info = ""
if video_list := [
module
for module in dynamic.modules
if str(module.module_dynamic.dyn_archive)
]:
video = video_list[0].module_dynamic.dyn_archive
video_info = (
image(video.cover)
+ f"标题: {video.title}\nBvid: {video.bvid}\n直链: https://www.bilibili.com/video/{video.bvid}"
)
rst = None if rst == dividing_line else rst
rst += video_info + "\n"
download_dynamic_image = Config.get_config(
"bilibili_sub", "DOWNLOAD_DYNAMIC_IMAGE"
)
draw_info = ""
if download_dynamic_image and (
draw_list := [
module.module_dynamic.dyn_draw
for module in dynamic.modules
if str(module.module_dynamic.dyn_draw)
]
):
idx = 0
for draws in draw_list:
for draw in list(draws.items):
path = (
TEMP_PATH
/ f"{_user.uid}_{dynamic.extend.dyn_id_str}_draw_{idx}.jpg"
)
if await AsyncHttpx.download_file(draw.src, path):
draw_info += image(path)
idx += 1
if draw_info:
rst += "动态图片\n" + draw_info + "\n"
return rst
async def _get_season_status(id_: str) -> Optional[str]:
async def _get_season_status(id_: str) -> str:
"""
获取 番剧 更新状态
:param id_: 番剧 id
@ -316,36 +372,30 @@ async def _get_season_status(id_: str) -> Optional[str]:
f"[{title}]更新啦\n"
f"最新集数:{new_ep}"
)
return None
return ""
async def get_user_dynamic(
uid: str, local_user: BilibiliSub
) -> Tuple[Optional[MessageSegment], int, str]:
dynamic_id: str, local_user: BilibiliSub
) -> Tuple[Optional[MessageSegment], str]:
"""
获取用户动态
:param uid: 用户uid
:param dynamic_id: 动态id
:param local_user: 数据库存储的用户数据
:return: 最新动态截图与时间
"""
"""bilibili_api.user库中User类的get_dynamics改为bilireq.dynamic库的get_user_dynamics方法"""
dynamic_info = await dynamic.get_user_dynamics(int(uid))
if dynamic_info.get("cards"):
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
dynamic_id = dynamic_info["cards"][0]["desc"]["dynamic_id"]
if local_user.dynamic_upload_time < dynamic_upload_time:
image = await AsyncPlaywright.screenshot(
f"https://t.bilibili.com/{dynamic_id}",
DYNAMIC_PATH / f"sub_{local_user.sub_id}.png",
".bili-dyn-item__main",
wait_until="networkidle",
)
return (
image,
dynamic_upload_time,
f"https://t.bilibili.com/{dynamic_id}",
)
return None, 0, ""
if local_user.dynamic_upload_time < int(dynamic_id):
image = await AsyncPlaywright.screenshot(
f"https://t.bilibili.com/{dynamic_id}",
DYNAMIC_PATH / f"sub_{local_user.sub_id}.png",
".bili-dyn-item__main",
wait_until="networkidle",
)
return (
image,
f"https://t.bilibili.com/{dynamic_id}",
)
return None, ""
class SubManager:

6357
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -36,7 +36,7 @@ dateparser = "^1.1.0"
cn2an = "^0.5.16"
python-jose = "^3.3.0"
python-multipart = "^0.0.5"
bilireq = "^0.2.3.post0"
bilireq = "^0.2.6"
emoji = "^1.7.0"
wordcloud = "^1.8.1"
rich = "^12.4.3"

View File

@ -13,7 +13,7 @@ from playwright.async_api import BrowserContext, Page
from retrying import retry
from services.log import logger
from utils.user_agent import get_user_agent
from utils.user_agent import get_user_agent, get_user_agent_str
from .browser import get_browser
from .message_builder import image
@ -218,7 +218,7 @@ class AsyncHttpx:
else:
logger.error(f"下载 {url} 下载超时.. Path{path.absolute()}")
except Exception as e:
logger.error(f"下载 {url} 未知错误 {type(e)}{e}.. Path{path.absolute()}")
logger.error(f"下载 {url} 错误 Path{path.absolute()}", e=e)
return False
@classmethod
@ -329,6 +329,7 @@ class AsyncPlaywright:
] = "networkidle",
timeout: Optional[float] = None,
type_: Optional[Literal["jpeg", "png"]] = None,
user_agent: Optional[str] = None,
**kwargs,
) -> Optional[MessageSegment]:
"""
@ -353,7 +354,11 @@ class AsyncPlaywright:
element_list = [element]
else:
element_list = element
async with cls.new_page(viewport=viewport_size) as page:
async with cls.new_page(
viewport=viewport_size,
user_agent=user_agent,
**kwargs,
) as page:
await page.goto(url, timeout=timeout, wait_until=wait_until)
card = page
for e in element_list:

View File

@ -7,7 +7,7 @@ import uuid
from io import BytesIO
from math import ceil
from pathlib import Path
from typing import Awaitable, Callable, List, Literal, Optional, Tuple, Union
from typing import Any, Awaitable, Callable, List, Literal, Optional, Tuple, Union
import cv2
import imagehash
@ -353,16 +353,16 @@ class BuildImage:
:param font_size: 字体大小
"""
font_ = cls.load_font(font, font_size)
return font_.getsize(msg)
return font_.getsize(msg) # type: ignore
def getsize(self, msg: str) -> Tuple[int, int]:
def getsize(self, msg: Any) -> Tuple[int, int]:
"""
说明:
获取文字在该图片 font_size 下所需要的空间
参数:
:param msg: 文字内容
"""
return self.font.getsize(msg)
return self.font.getsize(str(msg)) # type: ignore
async def apoint(
self, pos: Tuple[int, int], fill: Optional[Tuple[int, int, int]] = None

View File

@ -1,6 +1,5 @@
import random
user_agent = [
"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
@ -45,3 +44,7 @@ user_agent = [
def get_user_agent():
return {"User-Agent": random.choice(user_agent)}
def get_user_agent_str():
return random.choice(user_agent)