mirror of
https://github.com/Xtao-Labs/iShotaBot.git
synced 2024-11-25 09:37:34 +00:00
feat: bsky hidden nsfw content
This commit is contained in:
parent
c2f6c1255c
commit
e729d6e93d
13
defs/bsky.py
13
defs/bsky.py
@ -59,7 +59,7 @@ class Timeline:
|
|||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@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 = []
|
data = []
|
||||||
images = post.images
|
images = post.images
|
||||||
for idx, image in enumerate(images):
|
for idx, image in enumerate(images):
|
||||||
@ -68,6 +68,7 @@ class Timeline:
|
|||||||
image,
|
image,
|
||||||
caption=text if idx == 0 else None,
|
caption=text if idx == 0 else None,
|
||||||
parse_mode=ParseMode.HTML,
|
parse_mode=ParseMode.HTML,
|
||||||
|
has_spoiler=has_spoiler,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return data
|
return data
|
||||||
@ -89,8 +90,11 @@ class Timeline:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@flood_wait()
|
@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)
|
text = Timeline.get_post_text(post)
|
||||||
|
need_spoiler = post.need_spoiler
|
||||||
|
if need_spoiler and override_hidden:
|
||||||
|
need_spoiler = False
|
||||||
if post.gif:
|
if post.gif:
|
||||||
return await bot.send_animation(
|
return await bot.send_animation(
|
||||||
reply.cid,
|
reply.cid,
|
||||||
@ -98,6 +102,7 @@ class Timeline:
|
|||||||
caption=text,
|
caption=text,
|
||||||
reply_to_message_id=reply.mid,
|
reply_to_message_id=reply.mid,
|
||||||
parse_mode=ParseMode.HTML,
|
parse_mode=ParseMode.HTML,
|
||||||
|
has_spoiler=need_spoiler,
|
||||||
reply_markup=Timeline.get_button(post),
|
reply_markup=Timeline.get_button(post),
|
||||||
)
|
)
|
||||||
elif post.video:
|
elif post.video:
|
||||||
@ -108,6 +113,7 @@ class Timeline:
|
|||||||
thumb=post.video_thumbnail,
|
thumb=post.video_thumbnail,
|
||||||
reply_to_message_id=reply.mid,
|
reply_to_message_id=reply.mid,
|
||||||
parse_mode=ParseMode.HTML,
|
parse_mode=ParseMode.HTML,
|
||||||
|
has_spoiler=need_spoiler,
|
||||||
reply_markup=Timeline.get_button(post),
|
reply_markup=Timeline.get_button(post),
|
||||||
)
|
)
|
||||||
elif not post.images:
|
elif not post.images:
|
||||||
@ -126,12 +132,13 @@ class Timeline:
|
|||||||
caption=text,
|
caption=text,
|
||||||
reply_to_message_id=reply.mid,
|
reply_to_message_id=reply.mid,
|
||||||
parse_mode=ParseMode.HTML,
|
parse_mode=ParseMode.HTML,
|
||||||
|
has_spoiler=need_spoiler,
|
||||||
reply_markup=Timeline.get_button(post),
|
reply_markup=Timeline.get_button(post),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await bot.send_media_group(
|
await bot.send_media_group(
|
||||||
reply.cid,
|
reply.cid,
|
||||||
Timeline.get_media_group(text, post),
|
Timeline.get_media_group(text, post, need_spoiler),
|
||||||
reply_to_message_id=reply.mid,
|
reply_to_message_id=reply.mid,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import TYPE_CHECKING, Optional, Union
|
from typing import TYPE_CHECKING, Optional, Union, List
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
@ -28,6 +28,7 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
TZ = pytz.timezone("Asia/Shanghai")
|
TZ = pytz.timezone("Asia/Shanghai")
|
||||||
XRPC_DOMAIN = "bsky.social"
|
XRPC_DOMAIN = "bsky.social"
|
||||||
|
LABELERS = ["did:plc:ar7c4by46qjdydhdevvrndac"]
|
||||||
|
|
||||||
|
|
||||||
class HumanAuthor(BaseModel):
|
class HumanAuthor(BaseModel):
|
||||||
@ -113,6 +114,8 @@ class HumanPost(BaseModel, frozen=False):
|
|||||||
|
|
||||||
author: HumanAuthor
|
author: HumanAuthor
|
||||||
|
|
||||||
|
labels: List[str]
|
||||||
|
|
||||||
is_quote: bool = False
|
is_quote: bool = False
|
||||||
is_reply: bool = False
|
is_reply: bool = False
|
||||||
is_repost: bool = False
|
is_repost: bool = False
|
||||||
@ -137,11 +140,33 @@ class HumanPost(BaseModel, frozen=False):
|
|||||||
return "回复"
|
return "回复"
|
||||||
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
|
@staticmethod
|
||||||
def parse_view(post: Union["PostView", "BskyViewRecordRecord"]) -> "HumanPost":
|
def parse_view(post: Union["PostView", "BskyViewRecordRecord"]) -> "HumanPost":
|
||||||
record = post.value if isinstance(post, BskyViewRecordRecord) else post.record
|
record = post.value if isinstance(post, BskyViewRecordRecord) else post.record
|
||||||
# author
|
# author
|
||||||
author = HumanAuthor.parse(post.author)
|
author = HumanAuthor.parse(post.author)
|
||||||
|
labels = HumanPost.parse_labels(post, author)
|
||||||
embed = (
|
embed = (
|
||||||
(post.embeds[0] if post.embeds else None)
|
(post.embeds[0] if post.embeds else None)
|
||||||
if isinstance(post, BskyViewRecordRecord)
|
if isinstance(post, BskyViewRecordRecord)
|
||||||
@ -186,6 +211,7 @@ class HumanPost(BaseModel, frozen=False):
|
|||||||
repost_count=post.repost_count,
|
repost_count=post.repost_count,
|
||||||
uri=post.uri,
|
uri=post.uri,
|
||||||
author=author,
|
author=author,
|
||||||
|
labels=labels,
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -16,7 +16,7 @@ class Reply(BaseModel):
|
|||||||
mid: Optional[int] = None
|
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)
|
url = urlparse(url)
|
||||||
if url.hostname and url.hostname in ["bsky.app"]:
|
if url.hostname and url.hostname in ["bsky.app"]:
|
||||||
if url.path.find("profile") < 0:
|
if url.path.find("profile") < 0:
|
||||||
@ -28,7 +28,7 @@ async def process_url(url: str, reply: Reply):
|
|||||||
)[0]
|
)[0]
|
||||||
try:
|
try:
|
||||||
post = await Timeline.fetch_post(author_handle, status_id)
|
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:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
elif url.path == f"/profile/{author_handle}":
|
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/"))
|
@bot.on_message(filters.incoming & filters.text & filters.regex(r"bsky.app/"))
|
||||||
async def bsky_share(_: Client, message: Message):
|
async def bsky_share(_: Client, message: Message):
|
||||||
if not message.text:
|
text = message.text
|
||||||
|
if not text:
|
||||||
return
|
return
|
||||||
if (
|
if (
|
||||||
message.sender_chat
|
message.sender_chat
|
||||||
@ -51,8 +52,13 @@ async def bsky_share(_: Client, message: Message):
|
|||||||
):
|
):
|
||||||
# 过滤绑定频道的转发
|
# 过滤绑定频道的转发
|
||||||
return
|
return
|
||||||
|
if text.startswith("~"):
|
||||||
|
return
|
||||||
|
override_hidden = False
|
||||||
|
if "no" in text or "不隐藏" in text:
|
||||||
|
override_hidden = True
|
||||||
mid = message.id
|
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):
|
with contextlib.suppress(Exception):
|
||||||
await message.delete()
|
await message.delete()
|
||||||
mid = None
|
mid = None
|
||||||
@ -60,10 +66,10 @@ async def bsky_share(_: Client, message: Message):
|
|||||||
for num in range(len(message.entities)):
|
for num in range(len(message.entities)):
|
||||||
entity = message.entities[num]
|
entity = message.entities[num]
|
||||||
if entity.type == MessageEntityType.URL:
|
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:
|
elif entity.type == MessageEntityType.TEXT_LINK:
|
||||||
url = entity.url
|
url = entity.url
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
await process_url(url, reply)
|
await process_url(url, reply, override_hidden)
|
||||||
raise ContinuePropagation
|
raise ContinuePropagation
|
||||||
|
Loading…
Reference in New Issue
Block a user