From 1ff571eb46948d63d52effdabb143bda3fa7afc4 Mon Sep 17 00:00:00 2001 From: honue Date: Fri, 27 Oct 2023 15:12:10 +0800 Subject: [PATCH] =?UTF-8?q?fix=20=E5=AE=9A=E6=97=B6=E6=B8=85=E7=90=86?= =?UTF-8?q?=E5=AA=92=E4=BD=93=E5=BA=93=EF=BC=8C=E5=A2=9E=E5=8A=A0username?= =?UTF-8?q?=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/chain/download.py | 21 +- app/chain/message.py | 5 +- app/chain/subscribe.py | 7 +- app/db/downloadhistory_oper.py | 6 +- app/db/models/downloadhistory.py | 9 +- app/plugins/autoclean/__init__.py | 354 +++++++++++------------ app/plugins/doubansync/__init__.py | 3 +- app/plugins/rsssubscribe/__init__.py | 3 +- database/versions/06abf3e7090b_1_0_11.py | 30 ++ 9 files changed, 240 insertions(+), 198 deletions(-) create mode 100644 database/versions/06abf3e7090b_1_0_11.py diff --git a/app/chain/download.py b/app/chain/download.py index 5f4be2bc..a2146f07 100644 --- a/app/chain/download.py +++ b/app/chain/download.py @@ -170,7 +170,8 @@ class DownloadChain(ChainBase): episodes: Set[int] = None, channel: MessageChannel = None, save_path: str = None, - userid: Union[str, int] = None) -> Optional[str]: + userid: Union[str, int] = None, + username: str = None) -> Optional[str]: """ 下载及发送通知 :param context: 资源上下文 @@ -179,6 +180,7 @@ class DownloadChain(ChainBase): :param channel: 通知渠道 :param save_path: 保存路径 :param userid: 用户ID + :param username: 调用下载的用户名/插件名 """ _torrent = context.torrent_info _media = context.media_info @@ -267,6 +269,7 @@ class DownloadChain(ChainBase): torrent_description=_torrent.description, torrent_site=_torrent.site_name, userid=userid, + username=username, channel=channel.value if channel else None, date=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) ) @@ -321,7 +324,8 @@ class DownloadChain(ChainBase): no_exists: Dict[int, Dict[int, NotExistMediaInfo]] = None, save_path: str = None, channel: MessageChannel = None, - userid: str = None) -> Tuple[List[Context], Dict[int, Dict[int, NotExistMediaInfo]]]: + userid: str = None, + username: str = None) -> Tuple[List[Context], Dict[int, Dict[int, NotExistMediaInfo]]]: """ 根据缺失数据,自动种子列表中组合择优下载 :param contexts: 资源上下文列表 @@ -329,6 +333,7 @@ class DownloadChain(ChainBase): :param save_path: 保存路径 :param channel: 通知渠道 :param userid: 用户ID + :param username: 调用下载的用户名/插件名 :return: 已经下载的资源列表、剩余未下载到的剧集 no_exists[tmdb_id] = {season: NotExistMediaInfo} """ # 已下载的项目 @@ -395,7 +400,7 @@ class DownloadChain(ChainBase): for context in contexts: if context.media_info.type == MediaType.MOVIE: if self.download_single(context, save_path=save_path, - channel=channel, userid=userid): + channel=channel, userid=userid, username=username): # 下载成功 downloaded_list.append(context) @@ -463,12 +468,13 @@ class DownloadChain(ChainBase): torrent_file=content if isinstance(content, Path) else None, save_path=save_path, channel=channel, - userid=userid + userid=userid, + username=username ) else: # 下载 download_id = self.download_single(context, save_path=save_path, - channel=channel, userid=userid) + channel=channel, userid=userid, username=username) if download_id: # 下载成功 @@ -528,7 +534,7 @@ class DownloadChain(ChainBase): if torrent_episodes.issubset(set(need_episodes)): # 下载 download_id = self.download_single(context, save_path=save_path, - channel=channel, userid=userid) + channel=channel, userid=userid, username=username) if download_id: # 下载成功 downloaded_list.append(context) @@ -606,7 +612,8 @@ class DownloadChain(ChainBase): episodes=selected_episodes, save_path=save_path, channel=channel, - userid=userid + userid=userid, + username=username ) if not download_id: continue diff --git a/app/chain/message.py b/app/chain/message.py index a22c4696..d55c3792 100644 --- a/app/chain/message.py +++ b/app/chain/message.py @@ -189,7 +189,7 @@ class MessageChain(ChainBase): # 下载种子 context: Context = cache_list[int(text) - 1] # 下载 - self.downloadchain.download_single(context, userid=userid, channel=channel) + self.downloadchain.download_single(context, userid=userid, channel=channel, username=username) elif text.lower() == "p": # 上一页 @@ -343,7 +343,8 @@ class MessageChain(ChainBase): downloads, lefts = self.downloadchain.batch_download(contexts=cache_list, no_exists=no_exists, channel=channel, - userid=userid) + userid=userid, + username=username) if downloads and not lefts: # 全部下载完成 logger.info(f'{_current_media.title_year} 下载完成') diff --git a/app/chain/subscribe.py b/app/chain/subscribe.py index 95722ee2..3bf96939 100644 --- a/app/chain/subscribe.py +++ b/app/chain/subscribe.py @@ -302,7 +302,7 @@ class SubscribeChain(ChainBase): # 自动下载 downloads, lefts = self.downloadchain.batch_download(contexts=matched_contexts, - no_exists=no_exists) + no_exists=no_exists, username=subscribe.username) # 更新已经下载的集数 if downloads \ and meta.type == MediaType.TV \ @@ -415,7 +415,7 @@ class SubscribeChain(ChainBase): } # 订阅默认过滤规则 return self.systemconfig.get(SystemConfigKey.DefaultFilterRules) or {} - + @staticmethod def check_filter_rule(torrent_info: TorrentInfo, filter_rule: Dict[str, str]) -> bool: """ @@ -621,7 +621,8 @@ class SubscribeChain(ChainBase): logger.info(f'{mediainfo.title_year} 匹配完成,共匹配到{len(_match_context)}个资源') if _match_context: # 批量择优下载 - downloads, lefts = self.downloadchain.batch_download(contexts=_match_context, no_exists=no_exists) + downloads, lefts = self.downloadchain.batch_download(contexts=_match_context, no_exists=no_exists, + username=subscribe.username) # 更新已经下载的集数 if downloads and meta.type == MediaType.TV: self.__update_subscribe_note(subscribe=subscribe, downloads=downloads) diff --git a/app/db/downloadhistory_oper.py b/app/db/downloadhistory_oper.py index de7c1623..3f8fc194 100644 --- a/app/db/downloadhistory_oper.py +++ b/app/db/downloadhistory_oper.py @@ -108,10 +108,10 @@ class DownloadHistoryOper(DbOper): episode=episode, tmdbid=tmdbid) - def list_by_user_date(self, date: str, userid: str = None) -> List[DownloadHistory]: + def list_by_user_date(self, date: str, username: str = None) -> List[DownloadHistory]: """ - 查询某用户某时间之后的下载历史 + 查询某用户某时间之前的下载历史 """ return DownloadHistory.list_by_user_date(db=self._db, date=date, - userid=userid) + username=username) diff --git a/app/db/models/downloadhistory.py b/app/db/models/downloadhistory.py index 58358c03..c3d091d7 100644 --- a/app/db/models/downloadhistory.py +++ b/app/db/models/downloadhistory.py @@ -38,6 +38,8 @@ class DownloadHistory(Base): torrent_site = Column(String) # 下载用户 userid = Column(String) + # 下载用户名/插件名 + username = Column(String) # 下载渠道 channel = Column(String) # 创建时间 @@ -108,13 +110,13 @@ class DownloadHistory(Base): @staticmethod @db_query - def list_by_user_date(db: Session, date: str, userid: str = None): + def list_by_user_date(db: Session, date: str, username: str = None): """ 查询某用户某时间之后的下载历史 """ - if userid: + if username: result = db.query(DownloadHistory).filter(DownloadHistory.date < date, - DownloadHistory.userid == userid).order_by( + DownloadHistory.username == username).order_by( DownloadHistory.id.desc()).all() else: result = db.query(DownloadHistory).filter(DownloadHistory.date < date).order_by( @@ -165,7 +167,6 @@ class DownloadFiles(Base): result = db.query(DownloadFiles).filter(DownloadFiles.savepath == savepath).all() return list(result) - @staticmethod @db_update def delete_by_fullpath(db: Session, fullpath: str): db.query(DownloadFiles).filter(DownloadFiles.fullpath == fullpath, diff --git a/app/plugins/autoclean/__init__.py b/app/plugins/autoclean/__init__.py index aca87d9b..d5e370d0 100644 --- a/app/plugins/autoclean/__init__.py +++ b/app/plugins/autoclean/__init__.py @@ -120,26 +120,26 @@ class AutoClean(_PluginBase): days_ago = current_time - timedelta(days=int(self._cleandate)) clean_date = days_ago.strftime("%Y-%m-%d") - # 查询用户清理日期之后的下载历史 + # 查询用户清理日期之前的下载历史,不填默认清理全部用户的下载 if not self._cleanuser: downloadhis_list = self._downloadhis.list_by_user_date(date=clean_date) - logger.info(f'获取到日期 {clean_date} 之后的下载历史 {len(downloadhis_list)} 条') + logger.info(f'获取到日期 {clean_date} 之前的下载历史 {len(downloadhis_list)} 条') self.__clean_history(date=clean_date, downloadhis_list=downloadhis_list) else: - for userid in str(self._cleanuser).split(","): + for username in str(self._cleanuser).split(","): downloadhis_list = self._downloadhis.list_by_user_date(date=clean_date, - userid=userid) + username=username) logger.info( - f'获取到用户 {userid} 日期 {clean_date} 之后的下载历史 {len(downloadhis_list)} 条') - self.__clean_history(date=clean_date, downloadhis_list=downloadhis_list, userid=userid) + f'获取到用户 {username} 日期 {clean_date} 之前的下载历史 {len(downloadhis_list)} 条') + self.__clean_history(date=clean_date, downloadhis_list=downloadhis_list) - def __clean_history(self, date: str, downloadhis_list: List[DownloadHistory], userid: str = None): + def __clean_history(self, date: str, downloadhis_list: List[DownloadHistory]): """ 清理下载历史、转移记录 """ if not downloadhis_list: - logger.warn(f"未获取到日期 {date} 之后的下载记录,停止运行") + logger.warn(f"未获取到日期 {date} 之前的下载记录,停止运行") return # 读取历史记录 @@ -159,10 +159,10 @@ class AutoClean(_PluginBase): # 输出分组结果 for key, downloadhis_list in downloadhis_grouped_dict.items(): logger.info(f"开始清理 {key}") - + result = [] del_transferhis_cnt = 0 del_media_name = downloadhis_list[0].title - del_media_user = downloadhis_list[0].userid + del_media_user = downloadhis_list[0].username del_media_type = downloadhis_list[0].type del_media_year = downloadhis_list[0].year del_media_season = downloadhis_list[0].seasons @@ -198,28 +198,28 @@ class AutoClean(_PluginBase): # 累加删除数量 del_transferhis_cnt += len(transferhis_list) - # 发送消息 - if self._notify: - self.post_message( - mtype=NotificationType.MediaServer, - title="【定时清理媒体库任务完成】", - text=f"清理媒体名称 {del_media_name}\n" - f"下载媒体用户 {del_media_user}\n" - f"删除历史记录 {del_transferhis_cnt}", - userid=userid) + if del_transferhis_cnt: + # 发送消息 + if self._notify: + self.post_message( + mtype=NotificationType.MediaServer, + title="【定时清理媒体库任务完成】", + text=f"清理媒体名称 {del_media_name}\n" + f"下载媒体用户 {del_media_user}\n" + f"删除历史记录 {del_transferhis_cnt}") - history.append({ - "type": del_media_type, - "title": del_media_name, - "year": del_media_year, - "season": del_media_season, - "episode": del_media_episode, - "image": del_image, - "del_time": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())) - }) + result.append({ + "type": del_media_type, + "title": del_media_name, + "year": del_media_year, + "season": del_media_season, + "episode": del_media_episode, + "image": del_image, + "del_time": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())) + }) # 保存历史 - self.save_data("history", history) + self.save_data("history", result) def get_state(self) -> bool: return self._enabled @@ -236,154 +236,154 @@ class AutoClean(_PluginBase): 拼装插件配置页面,需要返回两块数据:1、页面配置;2、数据结构 """ return [ - { - 'component': 'VForm', - 'content': [ - { - 'component': 'VRow', - 'content': [ - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 4 - }, - 'content': [ - { - 'component': 'VSwitch', - 'props': { - 'model': 'enabled', - 'label': '启用插件', - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 4 - }, - 'content': [ - { - 'component': 'VSwitch', - 'props': { - 'model': 'onlyonce', - 'label': '立即运行一次', - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 4 - }, - 'content': [ - { - 'component': 'VSwitch', - 'props': { - 'model': 'notify', - 'label': '开启通知', - } - } - ] - } - ] - }, - { - 'component': 'VRow', - 'content': [ - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 4 - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'cron', - 'label': '执行周期', - 'placeholder': '0 0 ? ? ?' - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 4 - }, - 'content': [ - { - 'component': 'VSelect', - 'props': { - 'model': 'cleantype', - 'label': '清理方式', - 'items': [ - {'title': '媒体库文件', 'value': 'dest'}, - {'title': '源文件', 'value': 'src'}, - {'title': '所有文件', 'value': 'all'}, - ] - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 4 - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'cleandate', - 'label': '清理媒体日期', - 'placeholder': '清理多少天之前的下载记录(天)' - } - } - ] - } - ] - }, - { - 'component': 'VRow', - 'content': [ - { - 'component': 'VCol', - 'props': { - 'cols': 12, - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'cleanuser', - 'label': '清理下载用户', - 'placeholder': '多个用户,分割' - } - } - ] - } - ] - } - ] - } - ], { - "enabled": False, - "onlyonce": False, - "notify": False, - "cleantype": "dest", - "cron": "", - "cleanuser": "", - "cleandate": 30 - } + { + 'component': 'VForm', + 'content': [ + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'enabled', + 'label': '启用插件', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'onlyonce', + 'label': '立即运行一次', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'notify', + 'label': '开启通知', + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'cron', + 'label': '执行周期', + 'placeholder': '0 0 ? ? ?' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSelect', + 'props': { + 'model': 'cleantype', + 'label': '清理方式', + 'items': [ + {'title': '媒体库文件', 'value': 'dest'}, + {'title': '源文件', 'value': 'src'}, + {'title': '所有文件', 'value': 'all'}, + ] + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'cleandate', + 'label': '清理媒体日期', + 'placeholder': '清理多少天之前的下载记录(天)' + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'cleanuser', + 'label': '清理下载用户名/插件名', + 'placeholder': '多个用户,分割 支持按插件清理下载记录(豆瓣想看、豆瓣榜单、RSS订阅)' + } + } + ] + } + ] + } + ] + } + ], { + "enabled": False, + "onlyonce": False, + "notify": False, + "cleantype": "dest", + "cron": "", + "cleanuser": "", + "cleandate": 30 + } def get_page(self) -> List[dict]: """ diff --git a/app/plugins/doubansync/__init__.py b/app/plugins/doubansync/__init__.py index 12700e4e..fd81174a 100644 --- a/app/plugins/doubansync/__init__.py +++ b/app/plugins/doubansync/__init__.py @@ -506,7 +506,8 @@ class DoubanSync(_PluginBase): action = "subscribe" else: # 自动下载 - downloads, lefts = self.downloadchain.batch_download(contexts=contexts, no_exists=no_exists) + downloads, lefts = self.downloadchain.batch_download(contexts=contexts, no_exists=no_exists, + username="豆瓣想看") if downloads and not lefts: # 全部下载完成 logger.info(f'{mediainfo.title_year} 下载完成') diff --git a/app/plugins/rsssubscribe/__init__.py b/app/plugins/rsssubscribe/__init__.py index 1cfdac67..6f375bec 100644 --- a/app/plugins/rsssubscribe/__init__.py +++ b/app/plugins/rsssubscribe/__init__.py @@ -628,7 +628,8 @@ class RssSubscribe(_PluginBase): media_info=mediainfo, torrent_info=torrentinfo, ), - save_path=self._save_path + save_path=self._save_path, + username="RSS订阅" ) if not result: logger.error(f'{title} 下载失败') diff --git a/database/versions/06abf3e7090b_1_0_11.py b/database/versions/06abf3e7090b_1_0_11.py new file mode 100644 index 00000000..ced8bf0f --- /dev/null +++ b/database/versions/06abf3e7090b_1_0_11.py @@ -0,0 +1,30 @@ +"""1.0.11 + +Revision ID: 06abf3e7090b +Revises: d633ca6cd572 +Create Date: 2023-10-27 12:22:56.213376 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '06abf3e7090b' +down_revision = 'd633ca6cd572' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + try: + with op.batch_alter_table("downloadhistory") as batch_op: + batch_op.add_column(sa.Column('username', sa.String, nullable=True)) + except Exception as e: + pass + # ### end Alembic commands ### + + +def downgrade() -> None: + pass