from services.log import logger from services.db_context import db from datetime import datetime from typing import Optional, List class BilibiliSub(db.Model): __tablename__ = "bilibili_sub" id = db.Column(db.Integer(), primary_key=True) sub_id = db.Column(db.Integer(), nullable=False) sub_type = db.Column(db.String(), nullable=False) # 订阅用户 sub_users = db.Column(db.String(), nullable=False) # 直播 live_short_id = db.Column(db.Integer()) live_status = db.Column(db.Integer) # 主播/UP uid = db.Column(db.BigInteger()) uname = db.Column(db.String()) latest_video_created = db.Column(db.BigInteger()) # 视频上传时间 dynamic_upload_time = db.Column(db.BigInteger(), default=0) # 动态发布时间 # 番剧 season_name = db.Column(db.String()) season_id = db.Column(db.Integer()) season_current_episode = db.Column(db.String()) season_update_time = db.Column(db.DateTime()) _idx1 = db.Index("bilibili_sub_idx1", "sub_id", "sub_type", unique=True) @classmethod async def add_bilibili_sub( cls, sub_id: int, sub_type: str, sub_user: str, *, live_short_id: Optional[int] = None, live_status: Optional[int] = None, dynamic_upload_time: Optional[int] = None, uid: Optional[int] = None, uname: Optional[str] = None, latest_video_created: Optional[int] = None, season_name: Optional[str] = None, season_id: Optional[int] = None, season_current_episode: Optional[str] = None, season_update_time: Optional[datetime] = None, ) -> bool: """ 说明: 添加订阅 参数: :param sub_id: 订阅名称,房间号,番剧号等 :param sub_type: 订阅类型 :param sub_user: 订阅此条目的用户 :param live_short_id: 直接短 id :param live_status: 主播开播状态 :param dynamic_upload_time: 主播/UP最新动态时间 :param uid: 主播/UP uid :param uname: 用户名称 :param latest_video_created: 最新视频上传时间 :param season_name: 番剧名称 :param season_id: 番剧 season_id :param season_current_episode: 番剧最新集数 :param season_update_time: 番剧更新时间 """ try: async with db.transaction(): query = ( await cls.query.where(cls.sub_id == sub_id) .with_for_update() .gino.first() ) sub_user = sub_user if sub_user[-1] == "," else f"{sub_user}," if query: if sub_user not in query.sub_users: sub_users = query.sub_users + sub_user await query.update(sub_users=sub_users).apply() else: sub = await cls.create( sub_id=sub_id, sub_type=sub_type, sub_users=sub_user ) await sub.update( live_short_id=live_short_id if live_short_id else sub.live_short_id, live_status=live_status if live_status else sub.live_status, dynamic_upload_time=dynamic_upload_time if dynamic_upload_time else sub.dynamic_upload_time, uid=uid if uid else sub.uid, uname=uname if uname else sub.uname, latest_video_created=latest_video_created if latest_video_created else sub.latest_video_created, season_update_time=season_update_time if season_update_time else sub.season_update_time, season_current_episode=season_current_episode if season_current_episode else sub.season_current_episode, season_id=season_id if season_id else sub.season_id, season_name=season_name if season_name else sub.season_name, ).apply() return True except Exception as e: logger.info(f"bilibili_sub 添加订阅错误 {type(e)}: {e}") return False @classmethod async def delete_bilibili_sub(cls, sub_id: int, sub_user: str) -> bool: """ 说明: 删除订阅 参数: :param sub_id: 订阅名称 :param sub_user: 删除此条目的用户 """ try: async with db.transaction(): query = ( await cls.query.where( (cls.sub_id == sub_id) & (cls.sub_users.contains(sub_user)) ) .with_for_update() .gino.first() ) if not query: return False await query.update( sub_users=query.sub_users.replace(f"{sub_user},", "") ).apply() if not query.sub_users.strip(): await query.delete() return True except Exception as e: logger.info(f"bilibili_sub 删除订阅错误 {type(e)}: {e}") return False @classmethod async def get_sub(cls, sub_id: int) -> Optional["BilibiliSub"]: """ 说明: 获取订阅对象 参数: :param sub_id: 订阅 id """ return await cls.query.where(cls.sub_id == sub_id).gino.first() @classmethod async def get_sub_data(cls, id_: str) -> List["BilibiliSub"]: """ 获取 id_ 订阅的所有内容 :param id_: id """ query = cls.query.where(cls.sub_users.contains(id_)) return await query.gino.all() @classmethod async def update_sub_info( cls, sub_id: int, *, live_short_id: Optional[int] = None, live_status: Optional[int] = None, dynamic_upload_time: Optional[int] = None, uid: Optional[int] = None, uname: Optional[str] = None, latest_video_created: Optional[int] = None, season_name: Optional[str] = None, season_id: Optional[int] = None, season_current_episode: Optional[str] = None, season_update_time: Optional[datetime] = None, ) -> bool: """ 说明: 更新订阅信息 参数: :param sub_id: 订阅名称,房间号,番剧号等 :param live_short_id: 直接短 id :param live_status: 主播开播状态 :param dynamic_upload_time: 主播/UP最新动态时间 :param uid: 主播/UP uid :param uname: 用户名称 :param latest_video_created: 最新视频上传时间 :param season_name: 番剧名称 :param season_id: 番剧 season_id :param season_current_episode: 番剧最新集数 :param season_update_time: 番剧更新时间 """ try: async with db.transaction(): sub = ( await cls.query.where(cls.sub_id == sub_id) .with_for_update() .gino.first() ) if sub: await sub.update( live_short_id=live_short_id if live_short_id is not None else sub.live_short_id, live_status=live_status if live_status is not None else sub.live_status, dynamic_upload_time=dynamic_upload_time if dynamic_upload_time is not None else sub.dynamic_upload_time, uid=uid if uid is not None else sub.uid, uname=uname if uname is not None else sub.uname, latest_video_created=latest_video_created if latest_video_created is not None else sub.latest_video_created, season_update_time=season_update_time if season_update_time is not None else sub.season_update_time, season_current_episode=season_current_episode if season_current_episode is not None else sub.season_current_episode, season_id=season_id if season_id is not None else sub.season_id, season_name=season_name if season_name is not None else sub.season_name, ).apply() return True except Exception as e: logger.info(f"bilibili_sub 更新订阅错误 {type(e)}: {e}") return False @classmethod async def get_all_sub_data( cls, ) -> "List[BilibiliSub], List[BilibiliSub], List[BilibiliSub]": """ 说明: 分类获取所有数据 """ live_data = [] up_data = [] season_data = [] query = await cls.query.gino.all() for x in query: if x.sub_type == "live": live_data.append(x) if x.sub_type == "up": up_data.append(x) if x.sub_type == "season": season_data.append(x) return live_data, up_data, season_data