diff --git a/config.gen.ini b/config.gen.ini
index d07a9f0..e375433 100644
--- a/config.gen.ini
+++ b/config.gen.ini
@@ -2,9 +2,6 @@
api_id = ID_HERE
api_hash = HASH_HERE
-[plugins]
-root = modules
-
[proxy]
enabled = False
hostname = 127.0.0.1
@@ -19,8 +16,12 @@ lofter_channel = 0
lofter_channel_username = username
splash_channel = 0
splash_channel_username = username
+bilifav_id = 0
+bilifav_channel = 0
+bilifav_channel_username = username
[api]
amap_key = ABCD
bili_cookie = ABCD
bili_auth_user = 777000,111000
+bili_auth_chat = 777000,111000
diff --git a/defs/bilibili_download.py b/defs/bilibili_download.py
index b5b5f1e..e47829d 100644
--- a/defs/bilibili_download.py
+++ b/defs/bilibili_download.py
@@ -217,7 +217,9 @@ async def take_screenshot(info: Dict) -> Optional[BytesIO]:
return None
-async def audio_download(a: Audio, m: Message):
+async def audio_download(
+ a: Audio, m: Message, push_id: int = None
+) -> Optional[Message]:
try:
info = await a.get_info()
download_url_data = await a.get_download_url()
@@ -243,12 +245,12 @@ async def audio_download(a: Audio, m: Message):
text = f"{info['title']}\n\n简介过长,无法显示\n\nhttps://www.bilibili.com/audio/au{a.get_auid()}"
else:
text = f"{info['title']}\n\nhttps://www.bilibili.com/audio/au{a.get_auid()}"
- await bot.send_audio(
- chat_id=m.chat.id,
+ msg = await bot.send_audio(
+ chat_id=push_id or m.chat.id,
audio=media,
caption=text,
parse_mode=ParseMode.HTML,
- reply_to_message_id=m.reply_to_message_id,
+ reply_to_message_id=m.reply_to_message_id if not push_id else None,
thumb=thumb,
title=info.get("title"),
duration=info.get("duration"),
@@ -256,12 +258,17 @@ async def audio_download(a: Audio, m: Message):
)
except BilibiliDownloaderError as e:
await fail_edit(m, e.MSG)
+ return
except Exception as e:
logger.exception("Downloading audio failed")
await fail_edit(m, f"下载/上传失败:{e}")
+ return
+ with contextlib.suppress(Exception):
+ await m.delete()
+ return msg
-async def go_download(v: Video, p_num: int, m: Message):
+async def go_download(v: Video, p_num: int, m: Message, task: bool = True):
video_path = cache_dir / f"{v.get_aid()}_{p_num}.mp4"
safe_remove(video_path)
flv_temp_path = cache_dir / f"{v.get_aid()}_{p_num}_temp.flv"
@@ -298,7 +305,8 @@ async def go_download(v: Video, p_num: int, m: Message):
)
if result != 0:
raise FFmpegError
- bot.loop.create_task(go_upload(v, p_num, m))
+ if task:
+ bot.loop.create_task(go_upload(v, p_num, m))
except BilibiliDownloaderError as e:
await fail_edit(m, e.MSG)
except Exception as e:
@@ -328,7 +336,9 @@ async def go_upload_progress(current: int, total: int, m: Message):
await message_edit(total, current, chunk, chunk_time, m, "上传")
-async def go_upload(v: Video, p_num: int, m: Message):
+async def go_upload(
+ v: Video, p_num: int, m: Message, push_id: int = None
+) -> Optional[Message]:
video_path = cache_dir / f"{v.get_aid()}_{p_num}.mp4"
if not video_path.exists():
await fail_edit(m, "视频文件不存在")
@@ -346,8 +356,8 @@ async def go_upload(v: Video, p_num: int, m: Message):
video_jpg = None
caption = f"https://b23.tv/{v.get_bvid()}"
logger.info(f"Uploading {video_path}")
- await bot.send_video(
- chat_id=m.chat.id,
+ msg = await bot.send_video(
+ chat_id=push_id or m.chat.id,
video=str(video_path),
caption=caption,
parse_mode=ParseMode.HTML,
@@ -358,7 +368,7 @@ async def go_upload(v: Video, p_num: int, m: Message):
supports_streaming=True,
progress=go_upload_progress,
progress_args=(m,),
- reply_to_message_id=m.reply_to_message_id,
+ reply_to_message_id=m.reply_to_message_id if not push_id else None,
)
logger.info(f"Upload {video_path} success")
except BilibiliDownloaderError as e:
@@ -376,3 +386,4 @@ async def go_upload(v: Video, p_num: int, m: Message):
del UPLOAD_MESSAGE_MAP[m.id]
with contextlib.suppress(Exception):
await m.delete()
+ return msg
diff --git a/defs/bilibili_fav.py b/defs/bilibili_fav.py
new file mode 100644
index 0000000..1ec623f
--- /dev/null
+++ b/defs/bilibili_fav.py
@@ -0,0 +1,104 @@
+import time
+from enum import Enum
+from typing import Optional
+
+from bilibili_api.favorite_list import FavoriteList
+from pydantic import BaseModel, ValidationError
+from pyrogram.types import Message
+
+from defs.bilibili import credential, create_video, create_audio
+from defs.bilibili_download import go_download, go_upload, audio_download
+from defs.glover import bilifav_id, bilifav_channel
+from models.models.bilifav import BiliFav
+from models.services.bilifav import BiliFavAction
+from init import logger
+
+fav = FavoriteList(media_id=bilifav_id, credential=credential)
+
+
+class BilibiliFavException(Exception):
+ pass
+
+
+class MediaType(int, Enum):
+ video = 2
+ audio = 12
+
+
+class Media(BaseModel):
+ id: int
+ bvid: str
+ type: MediaType
+ title: str
+ cover: Optional[str]
+ """ 封面 """
+ intro: Optional[str]
+ """ 简介 """
+
+
+async def process_video(data: Media, m: Message):
+ """处理视频"""
+ video = create_video(data.bvid)
+ await go_download(video, 0, m, task=False)
+ msg = await go_upload(video, 0, m, push_id=bilifav_channel)
+ if not msg:
+ raise BilibiliFavException
+ video_db = BiliFav(
+ id=data.id,
+ bv_id=data.bvid.lower(),
+ type=data.type.value,
+ title=data.title,
+ cover=data.cover,
+ message_id=msg.id,
+ file_id=msg.video.file_id,
+ timestamp=int(time.time()),
+ )
+ await BiliFavAction.add_bili_fav(video_db)
+
+
+async def process_audio(data: Media, m: Message):
+ """处理音频"""
+ audio = create_audio(f"au{data.id}")
+ msg = await audio_download(audio, m, push_id=bilifav_channel)
+ if not msg:
+ raise BilibiliFavException
+ audio_db = BiliFav(
+ id=data.id,
+ bv_id=data.bvid.lower(),
+ type=data.type.value,
+ title=data.title,
+ cover=data.cover,
+ message_id=msg.id,
+ file_id=msg.audio.file_id,
+ timestamp=int(time.time()),
+ )
+ await BiliFavAction.add_bili_fav(audio_db)
+
+
+async def check_update(m: Message):
+ """检查收藏夹是否更新"""
+ logger.info("Check bilibili favorite list")
+ try:
+ info = await fav.get_content()
+ except Exception as e:
+ logger.exception("Check bilibili favorite list failed")
+ await m.edit(f"获取收藏夹信息失败:{e}")
+ return
+ for media in info.get("medias", [])[::-1]:
+ try:
+ data = Media(**media)
+ except ValidationError as _:
+ logger.exception("Validate media failed")
+ continue
+ if await BiliFavAction.get_by_bv_id(data.bvid):
+ continue
+ n = await m.reply(f"处理 {data.type.name} {data.bvid} 中...")
+ try:
+ if data.type == MediaType.video:
+ await process_video(data, n)
+ elif data.type == MediaType.audio:
+ await process_audio(data, n)
+ except BilibiliFavException:
+ continue
+ await m.edit("收藏夹数据获取完毕")
+ logger.info("Check bilibili favorite list success")
diff --git a/defs/fragment.py b/defs/fragment.py
index 5d21f15..b919d66 100644
--- a/defs/fragment.py
+++ b/defs/fragment.py
@@ -5,7 +5,7 @@ from typing import Optional
from bs4 import BeautifulSoup
from init import request
-from models.fragment import (
+from models.services.fragment import (
AuctionStatus,
UserName,
TON_TO_USD_RATE,
diff --git a/defs/glover.py b/defs/glover.py
index 50be3b3..ce67615 100644
--- a/defs/glover.py
+++ b/defs/glover.py
@@ -13,9 +13,13 @@ lofter_channel: int = 0
lofter_channel_username: str = ""
splash_channel: int = 0
splash_channel_username: str = ""
+bilifav_id: int = 0
+bilifav_channel: int = 0
+bilifav_channel_username: str = ""
# [api]
amap_key: str = ""
bili_auth_user_str: str = ""
+bili_auth_chat_str: str = ""
config = RawConfigParser()
config.read("config.ini")
api_id = config.getint("pyrogram", "api_id", fallback=api_id)
@@ -30,12 +34,20 @@ splash_channel = config.getint("post", "splash_channel", fallback=splash_channel
splash_channel_username = config.get(
"post", "splash_channel_username", fallback=splash_channel_username
)
+bilifav_id = config.getint("post", "bilifav_id", fallback=bilifav_id)
+bilifav_channel = config.getint("post", "bilifav_channel", fallback=bilifav_channel)
+bilifav_channel_username = config.get(
+ "post", "bilifav_channel_username", fallback=bilifav_channel_username
+)
amap_key = config.get("api", "amap_key", fallback=amap_key)
bili_auth_user_str = config.get("api", "bili_auth_user", fallback=bili_auth_user_str)
+bili_auth_chat_str = config.get("api", "bili_auth_chat", fallback=bili_auth_chat_str)
try:
bili_auth_user: List[int] = list(map(int, bili_auth_user_str.split(",")))
+ bili_auth_chat: List[int] = list(map(int, bili_auth_chat_str.split(",")))
except ValueError:
bili_auth_user: List[int] = []
+ bili_auth_chat: List[int] = []
try:
ipv6 = bool(strtobool(ipv6))
except ValueError:
diff --git a/defs/lofter.py b/defs/lofter.py
index f6019f2..526acf4 100644
--- a/defs/lofter.py
+++ b/defs/lofter.py
@@ -17,7 +17,7 @@ from pyrogram.types import (
)
from defs.glover import lofter_channel_username
-from models.lofter import LofterPost as LofterPostModel
+from models.services.lofter import LofterPost as LofterPostModel
from init import request
diff --git a/defs/post.py b/defs/post.py
index 5267d80..5a69bb4 100644
--- a/defs/post.py
+++ b/defs/post.py
@@ -12,7 +12,7 @@ from pyrogram.types import Message
from defs.glover import lofter_channel
from defs.lofter import lofter_link
-from models.lofter import LofterPost as LofterPostModel
+from models.services.lofter import LofterPost as LofterPostModel
from models.models.lofter import Lofter as LofterModel
from init import request, bot
diff --git a/defs/splash.py b/defs/splash.py
index 48fd461..b3b7338 100644
--- a/defs/splash.py
+++ b/defs/splash.py
@@ -12,7 +12,7 @@ from defs.request import cache_file
from init import bot, request, logger
from models.models.splash import Splash as SplashModel
from models.apis.splash import Splash as SplashApi
-from models.splash import SplashService
+from models.services.splash import SplashService
async def get_splash() -> List[SplashApi]:
diff --git a/models/models/__init__.py b/models/models/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/models/models/bilifav.py b/models/models/bilifav.py
new file mode 100644
index 0000000..9b46a99
--- /dev/null
+++ b/models/models/bilifav.py
@@ -0,0 +1,14 @@
+from sqlmodel import SQLModel, Field
+
+
+class BiliFav(SQLModel, table=True):
+ __table_args__ = dict(mysql_charset="utf8mb4", mysql_collate="utf8mb4_general_ci")
+
+ id: int = Field(primary_key=True)
+ bv_id: str = Field()
+ type: int = Field(default=2)
+ title: str = Field()
+ cover: str = Field()
+ message_id: int = Field(default=0)
+ file_id: str = Field()
+ timestamp: int = Field(default=0)
diff --git a/models/services/__init__.py b/models/services/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/models/services/bilifav.py b/models/services/bilifav.py
new file mode 100644
index 0000000..026f5da
--- /dev/null
+++ b/models/services/bilifav.py
@@ -0,0 +1,42 @@
+from typing import cast, Optional
+
+from sqlalchemy import select
+from sqlmodel.ext.asyncio.session import AsyncSession
+
+from init import sqlite
+from models.models.bilifav import BiliFav
+
+
+class BiliFavAction:
+ @staticmethod
+ async def get_by_id(id_: int) -> Optional[BiliFav]:
+ async with sqlite.session() as session:
+ session = cast(AsyncSession, session)
+ statement = select(BiliFav).where(BiliFav.id == id_)
+ results = await session.exec(statement)
+ return post[0] if (post := results.first()) else None
+
+ @staticmethod
+ async def get_by_bv_id(bv_id: str) -> Optional[BiliFav]:
+ if not bv_id:
+ return None
+ async with sqlite.session() as session:
+ session = cast(AsyncSession, session)
+ statement = select(BiliFav).where(BiliFav.bv_id == bv_id.lower())
+ results = await session.exec(statement)
+ return post[0] if (post := results.first()) else None
+
+ @staticmethod
+ async def add_bili_fav(bili_fav: BiliFav):
+ async with sqlite.session() as session:
+ session = cast(AsyncSession, session)
+ session.add(bili_fav)
+ await session.commit()
+
+ @staticmethod
+ async def update_bili_fav(bili_fav: BiliFav):
+ async with sqlite.session() as session:
+ session = cast(AsyncSession, session)
+ session.add(bili_fav)
+ await session.commit()
+ await session.refresh(bili_fav)
diff --git a/models/fragment.py b/models/services/fragment.py
similarity index 94%
rename from models/fragment.py
rename to models/services/fragment.py
index 9f133a1..84aa78e 100644
--- a/models/fragment.py
+++ b/models/services/fragment.py
@@ -99,7 +99,7 @@ class FragmentSubText(Enum):
class FragmentSub:
@staticmethod
async def subscribe(cid: int, username: str):
- async with sqlite.Session() as session:
+ async with sqlite.session() as session:
session = cast(AsyncSession, session)
data = Fragment(cid=cid, username=username)
session.add(data)
@@ -107,14 +107,14 @@ class FragmentSub:
@staticmethod
async def unsubscribe(data: Fragment):
- async with sqlite.Session() as session:
+ async with sqlite.session() as session:
session = cast(AsyncSession, session)
await session.delete(data)
await session.commit()
@staticmethod
async def get_by_cid_and_username(cid: int, username: str) -> Optional[Fragment]:
- async with sqlite.Session() as session:
+ async with sqlite.session() as session:
session = cast(AsyncSession, session)
statement = (
select(Fragment)
@@ -126,7 +126,7 @@ class FragmentSub:
@staticmethod
async def get_by_cid(cid: int) -> List[Fragment]:
- async with sqlite.Session() as session:
+ async with sqlite.session() as session:
session = cast(AsyncSession, session)
statement = select(Fragment).where(Fragment.cid == cid)
results = await session.exec(statement)
@@ -134,7 +134,7 @@ class FragmentSub:
@staticmethod
async def get_all() -> List[Fragment]:
- async with sqlite.Session() as session:
+ async with sqlite.session() as session:
session = cast(AsyncSession, session)
statement = select(Fragment)
results = await session.exec(statement)
diff --git a/models/lofter.py b/models/services/lofter.py
similarity index 91%
rename from models/lofter.py
rename to models/services/lofter.py
index 9259f0c..9de34e8 100644
--- a/models/lofter.py
+++ b/models/services/lofter.py
@@ -10,7 +10,7 @@ from models.models.lofter import Lofter
class LofterPost:
@staticmethod
async def get_by_post_and_user_id(user_id: str, post_id: str) -> Optional[Lofter]:
- async with sqlite.Session() as session:
+ async with sqlite.session() as session:
session = cast(AsyncSession, session)
if user_id != "0":
check = Lofter.post_id == post_id and Lofter.user_id == user_id
@@ -26,7 +26,7 @@ class LofterPost:
@staticmethod
async def add_post(post: Lofter):
- async with sqlite.Session() as session:
+ async with sqlite.session() as session:
session = cast(AsyncSession, session)
session.add(post)
await session.commit()
diff --git a/models/splash.py b/models/services/splash.py
similarity index 86%
rename from models/splash.py
rename to models/services/splash.py
index e62c0ae..2ee4b4e 100644
--- a/models/splash.py
+++ b/models/services/splash.py
@@ -10,7 +10,7 @@ from models.models.splash import Splash
class SplashService:
@staticmethod
async def get_by_splash_id(splash_id: int) -> Optional[Splash]:
- async with sqlite.Session() as session:
+ async with sqlite.session() as session:
session = cast(AsyncSession, session)
check = Splash.id == splash_id
statement = select(Splash).where(check)
@@ -19,7 +19,7 @@ class SplashService:
@staticmethod
async def get_all_splashes() -> List[Optional[Splash]]:
- async with sqlite.Session() as session:
+ async with sqlite.session() as session:
session = cast(AsyncSession, session)
statement = select(Splash)
results = await session.exec(statement)
@@ -27,14 +27,14 @@ class SplashService:
@staticmethod
async def add_splash(splash: Splash):
- async with sqlite.Session() as session:
+ async with sqlite.session() as session:
session = cast(AsyncSession, session)
session.add(splash)
await session.commit()
@staticmethod
async def update_splash(splash: Splash):
- async with sqlite.Session() as session:
+ async with sqlite.session() as session:
session = cast(AsyncSession, session)
session.add(splash)
await session.commit()
diff --git a/models/sqlite.py b/models/sqlite.py
index 636a371..a7cd592 100644
--- a/models/sqlite.py
+++ b/models/sqlite.py
@@ -1,9 +1,11 @@
from sqlmodel import SQLModel
+from models.models.bilifav import BiliFav
from models.models.lofter import Lofter
from models.models.fragment import Fragment
+from models.models.splash import Splash
-__all__ = ["Lofter", "Fragment", "Sqlite"]
+__all__ = ["BiliFav", "Lofter", "Fragment", "Splash", "Sqlite"]
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy.orm import sessionmaker
@@ -13,15 +15,11 @@ from sqlmodel.ext.asyncio.session import AsyncSession
class Sqlite:
def __init__(self):
self.engine = create_async_engine("sqlite+aiosqlite:///data/data.db")
- self.Session = sessionmaker(bind=self.engine, class_=AsyncSession)
+ self.session = sessionmaker(bind=self.engine, class_=AsyncSession)
async def create_db_and_tables(self):
async with self.engine.begin() as session:
await session.run_sync(SQLModel.metadata.create_all)
- async def get_session(self):
- async with self.Session() as session:
- yield session
-
def stop(self):
- self.Session.close_all()
+ self.session.close_all()
diff --git a/modules/bilibili.py b/modules/bilibili.py
index 423642c..be0d5bb 100644
--- a/modules/bilibili.py
+++ b/modules/bilibili.py
@@ -12,7 +12,7 @@ from defs.bilibili import (
check_and_refresh_credential,
)
from defs.button import gen_button, Button
-from defs.glover import bili_auth_user
+from defs.glover import bili_auth_user, bili_auth_chat
from init import bot
from scheduler import scheduler
@@ -21,7 +21,7 @@ from scheduler import scheduler
filters.incoming
& filters.text
& filters.regex(r"av(\d{1,12})|BV(1[A-Za-z0-9]{2}4.1.7[A-Za-z0-9]{2})|b23.tv")
- & ~(filters.command(["download"]) & filters.user(bili_auth_user))
+ & ~(filters.command(["download", "bilibili_fav"]) & filters.user(bili_auth_user))
)
async def bili_resolve(_: Client, message: Message):
"""
@@ -37,7 +37,9 @@ async def bili_resolve(_: Client, message: Message):
if video_info:
image = await binfo_image_create(video_info)
buttons = [Button(0, "Link", "https://b23.tv/" + video_info["bvid"])]
- if message.from_user and message.from_user.id in bili_auth_user:
+ if (message.from_user and message.from_user.id in bili_auth_user) or (
+ message.chat and message.chat.id in bili_auth_chat
+ ):
buttons.append(Button(1, "Download", "download_" + video_info["bvid"]))
await message.reply_photo(
image,
diff --git a/modules/bilibili_download.py b/modules/bilibili_download.py
index 6a2dc8c..051343b 100644
--- a/modules/bilibili_download.py
+++ b/modules/bilibili_download.py
@@ -5,14 +5,15 @@ from pyrogram.types import Message, CallbackQuery
from defs.bilibili import b23_extract, create_video, create_audio
from defs.bilibili_download import go_download, audio_download
-from defs.glover import bili_auth_user
+from defs.glover import bili_auth_user, bilifav_channel_username, bili_auth_chat
from init import bot
+from models.services.bilifav import BiliFavAction
@bot.on_message(
filters.incoming
& filters.text
- & filters.user(bili_auth_user)
+ & (filters.user(bili_auth_user) | filters.chat(bili_auth_chat))
& filters.command(["download"])
)
async def bili_download_resolve(_: Client, message: Message):
@@ -29,6 +30,13 @@ async def bili_download_resolve(_: Client, message: Message):
p_num = p_.search(message.text)
p_num = int(p_num[0][2:]) if p_num else 0
video = create_video(video_number)
+ if video_db := await BiliFavAction.get_by_bv_id(video.get_bvid()):
+ await message.reply_video(
+ video_db.file_id,
+ caption=f"详细信息:https://t.me/{bilifav_channel_username}/{video_db.message_id}",
+ quote=True,
+ )
+ raise ContinuePropagation
m = await message.reply("开始获取视频数据", quote=True)
bot.loop.create_task(go_download(video, p_num, m))
@@ -51,11 +59,22 @@ async def bili_download_resolve_cb(_: Client, callback_query: CallbackQuery):
if not callback_query.from_user:
await callback_query.answer("请私聊机器人")
return
- if callback_query.from_user.id not in bili_auth_user:
- await callback_query.answer("你没有权限使用此功能")
+ if (
+ callback_query.message.chat.id not in bili_auth_chat
+ and callback_query.from_user.id not in bili_auth_user
+ ):
+ await callback_query.answer("你没有权限")
return
video_number = callback_query.matches[0].group(1)
video = create_video(video_number)
+ if video_db := await BiliFavAction.get_by_bv_id(video.get_bvid()):
+ await callback_query.answer("找到缓存")
+ await callback_query.message.reply_video(
+ video_db.file_id,
+ caption=f"详细信息:https://t.me/{bilifav_channel_username}/{video_db.message_id}",
+ quote=True,
+ )
+ raise ContinuePropagation
m = await callback_query.message.reply("开始获取视频数据", quote=True)
bot.loop.create_task(go_download(video, 0, m))
await callback_query.answer("开始下载")
diff --git a/modules/bilibili_fav.py b/modules/bilibili_fav.py
new file mode 100644
index 0000000..60d94b4
--- /dev/null
+++ b/modules/bilibili_fav.py
@@ -0,0 +1,103 @@
+import re
+import time
+
+from pyrogram import filters, Client, ContinuePropagation
+from pyrogram.types import Message, CallbackQuery
+
+from defs.bilibili import b23_extract, create_video, create_audio
+from defs.bilibili_download import go_download, go_upload, audio_download
+from defs.bilibili_fav import check_update
+from defs.glover import admin, bilifav_channel
+from init import bot, logger
+from models.models.bilifav import BiliFav
+from models.services.bilifav import BiliFavAction
+
+
+async def process_audio(video_number: str, message: Message):
+ id_ = int(video_number[2:])
+ if await BiliFavAction.get_by_id(id_):
+ await message.reply("该音频已经存在")
+ raise ContinuePropagation
+ audio = create_audio(video_number)
+ info = await audio.get_info()
+ m = await message.reply("开始获取音频数据", quote=True)
+ msg = await audio_download(audio, m, push_id=bilifav_channel)
+ if not msg:
+ raise ContinuePropagation
+ audio_db = BiliFav(
+ id=id_,
+ bv_id=info.get("bvid", "").lower(),
+ type=12,
+ title=info.get("title", ""),
+ cover=info.get("cover", ""),
+ message_id=msg.id,
+ file_id=msg.audio.file_id,
+ timestamp=int(time.time()),
+ )
+ await BiliFavAction.add_bili_fav(audio_db)
+
+
+async def process_video(video_number: str, p_num: int, message: Message):
+ video = create_video(video_number)
+ if await BiliFavAction.get_by_bv_id(video.get_bvid()):
+ await message.edit("该视频已经存在")
+ raise ContinuePropagation
+ info = await video.get_info()
+ id_ = info.get("aid", 0)
+ if not id_:
+ await message.edit("未找到视频 AV 号")
+ raise ContinuePropagation
+ m = await message.reply("开始获取视频数据", quote=True)
+ await go_download(video, p_num, m, task=False)
+ msg = await go_upload(video, p_num, m, push_id=bilifav_channel)
+ if not msg:
+ raise ContinuePropagation
+ audio_db = BiliFav(
+ id=id_,
+ bv_id=info.get("bvid", "").lower(),
+ type=2,
+ title=info.get("title", ""),
+ cover=info.get("pic", ""),
+ message_id=msg.id,
+ file_id=msg.video.file_id,
+ timestamp=int(time.time()),
+ )
+ await BiliFavAction.add_bili_fav(audio_db)
+
+
+@bot.on_message(
+ filters.incoming
+ & filters.text
+ & filters.user(admin)
+ & filters.command(["bilibili_fav"])
+)
+async def bilibili_fav_parse(_: Client, message: Message):
+ if len(message.command) <= 1:
+ m = await message.reply("正在获取收藏夹数据", quote=True)
+ await check_update(m)
+ return
+ if "b23.tv" in message.text:
+ message.text = await b23_extract(message.text)
+ p = re.compile(r"av(\d{1,12})|BV(1[A-Za-z0-9]{2}4.1.7[A-Za-z0-9]{2})|au(\d{1,12})")
+ video_number = p.search(message.text)
+ if video_number:
+ video_number = video_number[0]
+ else:
+ await message.reply("未找到视频 BV 号、 AV 或 AU 号")
+ raise ContinuePropagation
+ p_ = re.compile(r"p=(\d{1,3})")
+ p_num = p_.search(message.text)
+ p_num = int(p_num[0][2:]) if p_num else 0
+ m = await message.reply("开始获取数据", quote=True)
+ try:
+ if video_number.startswith("au"):
+ await process_audio(video_number, m)
+ else:
+ await process_video(video_number, p_num, m)
+ except ContinuePropagation:
+ raise ContinuePropagation
+ except Exception as e:
+ logger.exception("Processing bilibili favorite single push failed")
+ await m.edit(f"处理失败: {e}")
+ await m.edit("处理完成")
+ raise ContinuePropagation
diff --git a/modules/fragment.py b/modules/fragment.py
index 4cff253..4d2e8c3 100644
--- a/modules/fragment.py
+++ b/modules/fragment.py
@@ -12,7 +12,7 @@ from pyrogram.types import (
Message,
)
-from models.fragment import FragmentSubText, FragmentSub, AuctionStatus
+from models.services.fragment import FragmentSubText, FragmentSub, AuctionStatus
from defs.fragment import parse_fragment, NotAvailable, parse_sub
from init import bot
from scheduler import scheduler, add_delete_message_job