mirror of
https://github.com/Xtao-Labs/iShotaBot.git
synced 2024-11-21 22:58:09 +00:00
✨ 支持同步收藏夹到频道
This commit is contained in:
parent
a93093ea80
commit
6a23509ae3
@ -2,9 +2,6 @@
|
|||||||
api_id = ID_HERE
|
api_id = ID_HERE
|
||||||
api_hash = HASH_HERE
|
api_hash = HASH_HERE
|
||||||
|
|
||||||
[plugins]
|
|
||||||
root = modules
|
|
||||||
|
|
||||||
[proxy]
|
[proxy]
|
||||||
enabled = False
|
enabled = False
|
||||||
hostname = 127.0.0.1
|
hostname = 127.0.0.1
|
||||||
@ -19,8 +16,12 @@ lofter_channel = 0
|
|||||||
lofter_channel_username = username
|
lofter_channel_username = username
|
||||||
splash_channel = 0
|
splash_channel = 0
|
||||||
splash_channel_username = username
|
splash_channel_username = username
|
||||||
|
bilifav_id = 0
|
||||||
|
bilifav_channel = 0
|
||||||
|
bilifav_channel_username = username
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
amap_key = ABCD
|
amap_key = ABCD
|
||||||
bili_cookie = ABCD
|
bili_cookie = ABCD
|
||||||
bili_auth_user = 777000,111000
|
bili_auth_user = 777000,111000
|
||||||
|
bili_auth_chat = 777000,111000
|
||||||
|
@ -217,7 +217,9 @@ async def take_screenshot(info: Dict) -> Optional[BytesIO]:
|
|||||||
return None
|
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:
|
try:
|
||||||
info = await a.get_info()
|
info = await a.get_info()
|
||||||
download_url_data = await a.get_download_url()
|
download_url_data = await a.get_download_url()
|
||||||
@ -243,12 +245,12 @@ async def audio_download(a: Audio, m: Message):
|
|||||||
text = f"<b>{info['title']}</b>\n\n简介过长,无法显示\n\nhttps://www.bilibili.com/audio/au{a.get_auid()}"
|
text = f"<b>{info['title']}</b>\n\n简介过长,无法显示\n\nhttps://www.bilibili.com/audio/au{a.get_auid()}"
|
||||||
else:
|
else:
|
||||||
text = f"<b>{info['title']}</b>\n\nhttps://www.bilibili.com/audio/au{a.get_auid()}"
|
text = f"<b>{info['title']}</b>\n\nhttps://www.bilibili.com/audio/au{a.get_auid()}"
|
||||||
await bot.send_audio(
|
msg = await bot.send_audio(
|
||||||
chat_id=m.chat.id,
|
chat_id=push_id or m.chat.id,
|
||||||
audio=media,
|
audio=media,
|
||||||
caption=text,
|
caption=text,
|
||||||
parse_mode=ParseMode.HTML,
|
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,
|
thumb=thumb,
|
||||||
title=info.get("title"),
|
title=info.get("title"),
|
||||||
duration=info.get("duration"),
|
duration=info.get("duration"),
|
||||||
@ -256,12 +258,17 @@ async def audio_download(a: Audio, m: Message):
|
|||||||
)
|
)
|
||||||
except BilibiliDownloaderError as e:
|
except BilibiliDownloaderError as e:
|
||||||
await fail_edit(m, e.MSG)
|
await fail_edit(m, e.MSG)
|
||||||
|
return
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception("Downloading audio failed")
|
logger.exception("Downloading audio failed")
|
||||||
await fail_edit(m, f"下载/上传失败:{e}")
|
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"
|
video_path = cache_dir / f"{v.get_aid()}_{p_num}.mp4"
|
||||||
safe_remove(video_path)
|
safe_remove(video_path)
|
||||||
flv_temp_path = cache_dir / f"{v.get_aid()}_{p_num}_temp.flv"
|
flv_temp_path = cache_dir / f"{v.get_aid()}_{p_num}_temp.flv"
|
||||||
@ -298,6 +305,7 @@ async def go_download(v: Video, p_num: int, m: Message):
|
|||||||
)
|
)
|
||||||
if result != 0:
|
if result != 0:
|
||||||
raise FFmpegError
|
raise FFmpegError
|
||||||
|
if task:
|
||||||
bot.loop.create_task(go_upload(v, p_num, m))
|
bot.loop.create_task(go_upload(v, p_num, m))
|
||||||
except BilibiliDownloaderError as e:
|
except BilibiliDownloaderError as e:
|
||||||
await fail_edit(m, e.MSG)
|
await fail_edit(m, e.MSG)
|
||||||
@ -328,7 +336,9 @@ async def go_upload_progress(current: int, total: int, m: Message):
|
|||||||
await message_edit(total, current, chunk, chunk_time, m, "上传")
|
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"
|
video_path = cache_dir / f"{v.get_aid()}_{p_num}.mp4"
|
||||||
if not video_path.exists():
|
if not video_path.exists():
|
||||||
await fail_edit(m, "视频文件不存在")
|
await fail_edit(m, "视频文件不存在")
|
||||||
@ -346,8 +356,8 @@ async def go_upload(v: Video, p_num: int, m: Message):
|
|||||||
video_jpg = None
|
video_jpg = None
|
||||||
caption = f"https://b23.tv/{v.get_bvid()}"
|
caption = f"https://b23.tv/{v.get_bvid()}"
|
||||||
logger.info(f"Uploading {video_path}")
|
logger.info(f"Uploading {video_path}")
|
||||||
await bot.send_video(
|
msg = await bot.send_video(
|
||||||
chat_id=m.chat.id,
|
chat_id=push_id or m.chat.id,
|
||||||
video=str(video_path),
|
video=str(video_path),
|
||||||
caption=caption,
|
caption=caption,
|
||||||
parse_mode=ParseMode.HTML,
|
parse_mode=ParseMode.HTML,
|
||||||
@ -358,7 +368,7 @@ async def go_upload(v: Video, p_num: int, m: Message):
|
|||||||
supports_streaming=True,
|
supports_streaming=True,
|
||||||
progress=go_upload_progress,
|
progress=go_upload_progress,
|
||||||
progress_args=(m,),
|
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")
|
logger.info(f"Upload {video_path} success")
|
||||||
except BilibiliDownloaderError as e:
|
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]
|
del UPLOAD_MESSAGE_MAP[m.id]
|
||||||
with contextlib.suppress(Exception):
|
with contextlib.suppress(Exception):
|
||||||
await m.delete()
|
await m.delete()
|
||||||
|
return msg
|
||||||
|
104
defs/bilibili_fav.py
Normal file
104
defs/bilibili_fav.py
Normal file
@ -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")
|
@ -5,7 +5,7 @@ from typing import Optional
|
|||||||
|
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from init import request
|
from init import request
|
||||||
from models.fragment import (
|
from models.services.fragment import (
|
||||||
AuctionStatus,
|
AuctionStatus,
|
||||||
UserName,
|
UserName,
|
||||||
TON_TO_USD_RATE,
|
TON_TO_USD_RATE,
|
||||||
|
@ -13,9 +13,13 @@ lofter_channel: int = 0
|
|||||||
lofter_channel_username: str = ""
|
lofter_channel_username: str = ""
|
||||||
splash_channel: int = 0
|
splash_channel: int = 0
|
||||||
splash_channel_username: str = ""
|
splash_channel_username: str = ""
|
||||||
|
bilifav_id: int = 0
|
||||||
|
bilifav_channel: int = 0
|
||||||
|
bilifav_channel_username: str = ""
|
||||||
# [api]
|
# [api]
|
||||||
amap_key: str = ""
|
amap_key: str = ""
|
||||||
bili_auth_user_str: str = ""
|
bili_auth_user_str: str = ""
|
||||||
|
bili_auth_chat_str: str = ""
|
||||||
config = RawConfigParser()
|
config = RawConfigParser()
|
||||||
config.read("config.ini")
|
config.read("config.ini")
|
||||||
api_id = config.getint("pyrogram", "api_id", fallback=api_id)
|
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(
|
splash_channel_username = config.get(
|
||||||
"post", "splash_channel_username", fallback=splash_channel_username
|
"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)
|
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_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:
|
try:
|
||||||
bili_auth_user: List[int] = list(map(int, bili_auth_user_str.split(",")))
|
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:
|
except ValueError:
|
||||||
bili_auth_user: List[int] = []
|
bili_auth_user: List[int] = []
|
||||||
|
bili_auth_chat: List[int] = []
|
||||||
try:
|
try:
|
||||||
ipv6 = bool(strtobool(ipv6))
|
ipv6 = bool(strtobool(ipv6))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -17,7 +17,7 @@ from pyrogram.types import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from defs.glover import lofter_channel_username
|
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
|
from init import request
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ from pyrogram.types import Message
|
|||||||
|
|
||||||
from defs.glover import lofter_channel
|
from defs.glover import lofter_channel
|
||||||
from defs.lofter import lofter_link
|
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 models.models.lofter import Lofter as LofterModel
|
||||||
from init import request, bot
|
from init import request, bot
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ from defs.request import cache_file
|
|||||||
from init import bot, request, logger
|
from init import bot, request, logger
|
||||||
from models.models.splash import Splash as SplashModel
|
from models.models.splash import Splash as SplashModel
|
||||||
from models.apis.splash import Splash as SplashApi
|
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]:
|
async def get_splash() -> List[SplashApi]:
|
||||||
|
0
models/models/__init__.py
Normal file
0
models/models/__init__.py
Normal file
14
models/models/bilifav.py
Normal file
14
models/models/bilifav.py
Normal file
@ -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)
|
0
models/services/__init__.py
Normal file
0
models/services/__init__.py
Normal file
42
models/services/bilifav.py
Normal file
42
models/services/bilifav.py
Normal file
@ -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)
|
@ -99,7 +99,7 @@ class FragmentSubText(Enum):
|
|||||||
class FragmentSub:
|
class FragmentSub:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def subscribe(cid: int, username: str):
|
async def subscribe(cid: int, username: str):
|
||||||
async with sqlite.Session() as session:
|
async with sqlite.session() as session:
|
||||||
session = cast(AsyncSession, session)
|
session = cast(AsyncSession, session)
|
||||||
data = Fragment(cid=cid, username=username)
|
data = Fragment(cid=cid, username=username)
|
||||||
session.add(data)
|
session.add(data)
|
||||||
@ -107,14 +107,14 @@ class FragmentSub:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def unsubscribe(data: Fragment):
|
async def unsubscribe(data: Fragment):
|
||||||
async with sqlite.Session() as session:
|
async with sqlite.session() as session:
|
||||||
session = cast(AsyncSession, session)
|
session = cast(AsyncSession, session)
|
||||||
await session.delete(data)
|
await session.delete(data)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def get_by_cid_and_username(cid: int, username: str) -> Optional[Fragment]:
|
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)
|
session = cast(AsyncSession, session)
|
||||||
statement = (
|
statement = (
|
||||||
select(Fragment)
|
select(Fragment)
|
||||||
@ -126,7 +126,7 @@ class FragmentSub:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def get_by_cid(cid: int) -> List[Fragment]:
|
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)
|
session = cast(AsyncSession, session)
|
||||||
statement = select(Fragment).where(Fragment.cid == cid)
|
statement = select(Fragment).where(Fragment.cid == cid)
|
||||||
results = await session.exec(statement)
|
results = await session.exec(statement)
|
||||||
@ -134,7 +134,7 @@ class FragmentSub:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def get_all() -> List[Fragment]:
|
async def get_all() -> List[Fragment]:
|
||||||
async with sqlite.Session() as session:
|
async with sqlite.session() as session:
|
||||||
session = cast(AsyncSession, session)
|
session = cast(AsyncSession, session)
|
||||||
statement = select(Fragment)
|
statement = select(Fragment)
|
||||||
results = await session.exec(statement)
|
results = await session.exec(statement)
|
@ -10,7 +10,7 @@ from models.models.lofter import Lofter
|
|||||||
class LofterPost:
|
class LofterPost:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def get_by_post_and_user_id(user_id: str, post_id: str) -> Optional[Lofter]:
|
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)
|
session = cast(AsyncSession, session)
|
||||||
if user_id != "0":
|
if user_id != "0":
|
||||||
check = Lofter.post_id == post_id and Lofter.user_id == user_id
|
check = Lofter.post_id == post_id and Lofter.user_id == user_id
|
||||||
@ -26,7 +26,7 @@ class LofterPost:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def add_post(post: Lofter):
|
async def add_post(post: Lofter):
|
||||||
async with sqlite.Session() as session:
|
async with sqlite.session() as session:
|
||||||
session = cast(AsyncSession, session)
|
session = cast(AsyncSession, session)
|
||||||
session.add(post)
|
session.add(post)
|
||||||
await session.commit()
|
await session.commit()
|
@ -10,7 +10,7 @@ from models.models.splash import Splash
|
|||||||
class SplashService:
|
class SplashService:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def get_by_splash_id(splash_id: int) -> Optional[Splash]:
|
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)
|
session = cast(AsyncSession, session)
|
||||||
check = Splash.id == splash_id
|
check = Splash.id == splash_id
|
||||||
statement = select(Splash).where(check)
|
statement = select(Splash).where(check)
|
||||||
@ -19,7 +19,7 @@ class SplashService:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def get_all_splashes() -> List[Optional[Splash]]:
|
async def get_all_splashes() -> List[Optional[Splash]]:
|
||||||
async with sqlite.Session() as session:
|
async with sqlite.session() as session:
|
||||||
session = cast(AsyncSession, session)
|
session = cast(AsyncSession, session)
|
||||||
statement = select(Splash)
|
statement = select(Splash)
|
||||||
results = await session.exec(statement)
|
results = await session.exec(statement)
|
||||||
@ -27,14 +27,14 @@ class SplashService:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def add_splash(splash: Splash):
|
async def add_splash(splash: Splash):
|
||||||
async with sqlite.Session() as session:
|
async with sqlite.session() as session:
|
||||||
session = cast(AsyncSession, session)
|
session = cast(AsyncSession, session)
|
||||||
session.add(splash)
|
session.add(splash)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def update_splash(splash: Splash):
|
async def update_splash(splash: Splash):
|
||||||
async with sqlite.Session() as session:
|
async with sqlite.session() as session:
|
||||||
session = cast(AsyncSession, session)
|
session = cast(AsyncSession, session)
|
||||||
session.add(splash)
|
session.add(splash)
|
||||||
await session.commit()
|
await session.commit()
|
@ -1,9 +1,11 @@
|
|||||||
from sqlmodel import SQLModel
|
from sqlmodel import SQLModel
|
||||||
|
|
||||||
|
from models.models.bilifav import BiliFav
|
||||||
from models.models.lofter import Lofter
|
from models.models.lofter import Lofter
|
||||||
from models.models.fragment import Fragment
|
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.ext.asyncio import create_async_engine
|
||||||
from sqlalchemy.orm import sessionmaker
|
from sqlalchemy.orm import sessionmaker
|
||||||
@ -13,15 +15,11 @@ from sqlmodel.ext.asyncio.session import AsyncSession
|
|||||||
class Sqlite:
|
class Sqlite:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.engine = create_async_engine("sqlite+aiosqlite:///data/data.db")
|
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 def create_db_and_tables(self):
|
||||||
async with self.engine.begin() as session:
|
async with self.engine.begin() as session:
|
||||||
await session.run_sync(SQLModel.metadata.create_all)
|
await session.run_sync(SQLModel.metadata.create_all)
|
||||||
|
|
||||||
async def get_session(self):
|
|
||||||
async with self.Session() as session:
|
|
||||||
yield session
|
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.Session.close_all()
|
self.session.close_all()
|
||||||
|
@ -12,7 +12,7 @@ from defs.bilibili import (
|
|||||||
check_and_refresh_credential,
|
check_and_refresh_credential,
|
||||||
)
|
)
|
||||||
from defs.button import gen_button, Button
|
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 init import bot
|
||||||
from scheduler import scheduler
|
from scheduler import scheduler
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ from scheduler import scheduler
|
|||||||
filters.incoming
|
filters.incoming
|
||||||
& filters.text
|
& 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.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):
|
async def bili_resolve(_: Client, message: Message):
|
||||||
"""
|
"""
|
||||||
@ -37,7 +37,9 @@ async def bili_resolve(_: Client, message: Message):
|
|||||||
if video_info:
|
if video_info:
|
||||||
image = await binfo_image_create(video_info)
|
image = await binfo_image_create(video_info)
|
||||||
buttons = [Button(0, "Link", "https://b23.tv/" + video_info["bvid"])]
|
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"]))
|
buttons.append(Button(1, "Download", "download_" + video_info["bvid"]))
|
||||||
await message.reply_photo(
|
await message.reply_photo(
|
||||||
image,
|
image,
|
||||||
|
@ -5,14 +5,15 @@ from pyrogram.types import Message, CallbackQuery
|
|||||||
|
|
||||||
from defs.bilibili import b23_extract, create_video, create_audio
|
from defs.bilibili import b23_extract, create_video, create_audio
|
||||||
from defs.bilibili_download import go_download, audio_download
|
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 init import bot
|
||||||
|
from models.services.bilifav import BiliFavAction
|
||||||
|
|
||||||
|
|
||||||
@bot.on_message(
|
@bot.on_message(
|
||||||
filters.incoming
|
filters.incoming
|
||||||
& filters.text
|
& filters.text
|
||||||
& filters.user(bili_auth_user)
|
& (filters.user(bili_auth_user) | filters.chat(bili_auth_chat))
|
||||||
& filters.command(["download"])
|
& filters.command(["download"])
|
||||||
)
|
)
|
||||||
async def bili_download_resolve(_: Client, message: Message):
|
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 = p_.search(message.text)
|
||||||
p_num = int(p_num[0][2:]) if p_num else 0
|
p_num = int(p_num[0][2:]) if p_num else 0
|
||||||
video = create_video(video_number)
|
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)
|
m = await message.reply("开始获取视频数据", quote=True)
|
||||||
bot.loop.create_task(go_download(video, p_num, m))
|
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:
|
if not callback_query.from_user:
|
||||||
await callback_query.answer("请私聊机器人")
|
await callback_query.answer("请私聊机器人")
|
||||||
return
|
return
|
||||||
if callback_query.from_user.id not in bili_auth_user:
|
if (
|
||||||
await callback_query.answer("你没有权限使用此功能")
|
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
|
return
|
||||||
video_number = callback_query.matches[0].group(1)
|
video_number = callback_query.matches[0].group(1)
|
||||||
video = create_video(video_number)
|
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)
|
m = await callback_query.message.reply("开始获取视频数据", quote=True)
|
||||||
bot.loop.create_task(go_download(video, 0, m))
|
bot.loop.create_task(go_download(video, 0, m))
|
||||||
await callback_query.answer("开始下载")
|
await callback_query.answer("开始下载")
|
||||||
|
103
modules/bilibili_fav.py
Normal file
103
modules/bilibili_fav.py
Normal file
@ -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
|
@ -12,7 +12,7 @@ from pyrogram.types import (
|
|||||||
Message,
|
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 defs.fragment import parse_fragment, NotAvailable, parse_sub
|
||||||
from init import bot
|
from init import bot
|
||||||
from scheduler import scheduler, add_delete_message_job
|
from scheduler import scheduler, add_delete_message_job
|
||||||
|
Loading…
Reference in New Issue
Block a user