feat: bsky hidden nsfw content

This commit is contained in:
xtaodada 2024-10-22 21:04:59 +08:00
parent c2f6c1255c
commit e729d6e93d
Signed by: xtaodada
GPG Key ID: 4CBB3F4FA8C85659
3 changed files with 49 additions and 10 deletions

View File

@ -59,7 +59,7 @@ class Timeline:
)
@staticmethod
def get_media_group(text: str, post: HumanPost) -> list[InputMediaPhoto]:
def get_media_group(text: str, post: HumanPost, has_spoiler: bool) -> list[InputMediaPhoto]:
data = []
images = post.images
for idx, image in enumerate(images):
@ -68,6 +68,7 @@ class Timeline:
image,
caption=text if idx == 0 else None,
parse_mode=ParseMode.HTML,
has_spoiler=has_spoiler,
)
)
return data
@ -89,8 +90,11 @@ class Timeline:
@staticmethod
@flood_wait()
async def send_to_user(reply: "Reply", post: HumanPost):
async def send_to_user(reply: "Reply", post: HumanPost, override_hidden: bool):
text = Timeline.get_post_text(post)
need_spoiler = post.need_spoiler
if need_spoiler and override_hidden:
need_spoiler = False
if post.gif:
return await bot.send_animation(
reply.cid,
@ -98,6 +102,7 @@ class Timeline:
caption=text,
reply_to_message_id=reply.mid,
parse_mode=ParseMode.HTML,
has_spoiler=need_spoiler,
reply_markup=Timeline.get_button(post),
)
elif post.video:
@ -108,6 +113,7 @@ class Timeline:
thumb=post.video_thumbnail,
reply_to_message_id=reply.mid,
parse_mode=ParseMode.HTML,
has_spoiler=need_spoiler,
reply_markup=Timeline.get_button(post),
)
elif not post.images:
@ -126,12 +132,13 @@ class Timeline:
caption=text,
reply_to_message_id=reply.mid,
parse_mode=ParseMode.HTML,
has_spoiler=need_spoiler,
reply_markup=Timeline.get_button(post),
)
else:
await bot.send_media_group(
reply.cid,
Timeline.get_media_group(text, post),
Timeline.get_media_group(text, post, need_spoiler),
reply_to_message_id=reply.mid,
)

View File

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, Union
from typing import TYPE_CHECKING, Optional, Union, List
from datetime import datetime
@ -28,6 +28,7 @@ if TYPE_CHECKING:
TZ = pytz.timezone("Asia/Shanghai")
XRPC_DOMAIN = "bsky.social"
LABELERS = ["did:plc:ar7c4by46qjdydhdevvrndac"]
class HumanAuthor(BaseModel):
@ -113,6 +114,8 @@ class HumanPost(BaseModel, frozen=False):
author: HumanAuthor
labels: List[str]
is_quote: bool = False
is_reply: bool = False
is_repost: bool = False
@ -137,11 +140,33 @@ class HumanPost(BaseModel, frozen=False):
return "回复"
return "发表"
@property
def need_spoiler(self) -> bool:
return any(
label in ["porn", "sexual", "graphic-media", "nudity"]
for label in self.labels
)
@staticmethod
def parse_labels(
post: Union["PostView", "BskyViewRecordRecord"], author: HumanAuthor
) -> List[str]:
labels = []
if not post.labels:
return labels
labelers = LABELERS.copy()
labelers.append(author.did)
for label in post.labels:
if label.src in labelers:
labels.append(label.val)
return labels
@staticmethod
def parse_view(post: Union["PostView", "BskyViewRecordRecord"]) -> "HumanPost":
record = post.value if isinstance(post, BskyViewRecordRecord) else post.record
# author
author = HumanAuthor.parse(post.author)
labels = HumanPost.parse_labels(post, author)
embed = (
(post.embeds[0] if post.embeds else None)
if isinstance(post, BskyViewRecordRecord)
@ -186,6 +211,7 @@ class HumanPost(BaseModel, frozen=False):
repost_count=post.repost_count,
uri=post.uri,
author=author,
labels=labels,
)
@staticmethod

View File

@ -16,7 +16,7 @@ class Reply(BaseModel):
mid: Optional[int] = None
async def process_url(url: str, reply: Reply):
async def process_url(url: str, reply: Reply, override_hidden: bool):
url = urlparse(url)
if url.hostname and url.hostname in ["bsky.app"]:
if url.path.find("profile") < 0:
@ -28,7 +28,7 @@ async def process_url(url: str, reply: Reply):
)[0]
try:
post = await Timeline.fetch_post(author_handle, status_id)
await Timeline.send_to_user(reply, post)
await Timeline.send_to_user(reply, post, override_hidden)
except Exception as e:
print(e)
elif url.path == f"/profile/{author_handle}":
@ -42,7 +42,8 @@ async def process_url(url: str, reply: Reply):
@bot.on_message(filters.incoming & filters.text & filters.regex(r"bsky.app/"))
async def bsky_share(_: Client, message: Message):
if not message.text:
text = message.text
if not text:
return
if (
message.sender_chat
@ -51,8 +52,13 @@ async def bsky_share(_: Client, message: Message):
):
# 过滤绑定频道的转发
return
if text.startswith("~"):
return
override_hidden = False
if "no" in text or "不隐藏" in text:
override_hidden = True
mid = message.id
if message.text.startswith("del") and message.chat.type == ChatType.CHANNEL:
if text.startswith("del") and message.chat.type == ChatType.CHANNEL:
with contextlib.suppress(Exception):
await message.delete()
mid = None
@ -60,10 +66,10 @@ async def bsky_share(_: Client, message: Message):
for num in range(len(message.entities)):
entity = message.entities[num]
if entity.type == MessageEntityType.URL:
url = message.text[entity.offset : entity.offset + entity.length]
url = text[entity.offset : entity.offset + entity.length]
elif entity.type == MessageEntityType.TEXT_LINK:
url = entity.url
else:
continue
await process_url(url, reply)
await process_url(url, reply, override_hidden)
raise ContinuePropagation