Merge branch 'jxxghp:main' into main
This commit is contained in:
@ -352,6 +352,11 @@ class SubscribeChain(ChainBase):
|
|||||||
"""
|
"""
|
||||||
刷新站点最新资源
|
刷新站点最新资源
|
||||||
"""
|
"""
|
||||||
|
# 所有订阅
|
||||||
|
subscribes = self.subscribehelper.list('R')
|
||||||
|
if not subscribes:
|
||||||
|
# 没有订阅不运行
|
||||||
|
return
|
||||||
# 读取缓存
|
# 读取缓存
|
||||||
torrents_cache: Dict[str, List[Context]] = self.load_cache(self._cache_file) or {}
|
torrents_cache: Dict[str, List[Context]] = self.load_cache(self._cache_file) or {}
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@ import re
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional, Union, Dict, Generator
|
from typing import List, Optional, Union, Dict, Generator
|
||||||
|
|
||||||
|
from requests import Response
|
||||||
|
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.schemas import RefreshMediaItem, WebhookEventInfo
|
from app.schemas import RefreshMediaItem, WebhookEventInfo
|
||||||
@ -597,3 +599,17 @@ class Emby(metaclass=Singleton):
|
|||||||
image_type="Backdrop")
|
image_type="Backdrop")
|
||||||
|
|
||||||
return eventItem
|
return eventItem
|
||||||
|
|
||||||
|
def get_data(self, url: str) -> Optional[Response]:
|
||||||
|
"""
|
||||||
|
自定义URL从媒体服务器获取数据,其中{HOST}、{APIKEY}、{USER}会被替换成实际的值
|
||||||
|
:param url: 请求地址
|
||||||
|
"""
|
||||||
|
url = url.replace("{HOST}", self._host)\
|
||||||
|
.replace("{APIKEY}", self._apikey)\
|
||||||
|
.replace("{USER}", self._user)
|
||||||
|
try:
|
||||||
|
return RequestUtils().get_res(url=url)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"连接Emby出错:" + str(e))
|
||||||
|
return None
|
||||||
|
@ -2,6 +2,8 @@ import json
|
|||||||
import re
|
import re
|
||||||
from typing import List, Union, Optional, Dict, Generator
|
from typing import List, Union, Optional, Dict, Generator
|
||||||
|
|
||||||
|
from requests import Response
|
||||||
|
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.schemas import MediaType, WebhookEventInfo
|
from app.schemas import MediaType, WebhookEventInfo
|
||||||
@ -437,3 +439,17 @@ class Jellyfin(metaclass=Singleton):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"连接Users/Items出错:" + str(e))
|
logger.error(f"连接Users/Items出错:" + str(e))
|
||||||
yield {}
|
yield {}
|
||||||
|
|
||||||
|
def get_data(self, url: str) -> Optional[Response]:
|
||||||
|
"""
|
||||||
|
自定义URL从媒体服务器获取数据,其中{HOST}、{APIKEY}、{USER}会被替换成实际的值
|
||||||
|
:param url: 请求地址
|
||||||
|
"""
|
||||||
|
url = url.replace("{HOST}", self._host)\
|
||||||
|
.replace("{APIKEY}", self._apikey)\
|
||||||
|
.replace("{USER}", self._user)
|
||||||
|
try:
|
||||||
|
return RequestUtils().get_res(url=url)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"连接Jellyfin出错:" + str(e))
|
||||||
|
return None
|
||||||
|
@ -106,6 +106,8 @@ class Qbittorrent(metaclass=Singleton):
|
|||||||
:param ids: 种子Hash列表
|
:param ids: 种子Hash列表
|
||||||
:param tag: 标签内容
|
:param tag: 标签内容
|
||||||
"""
|
"""
|
||||||
|
if not self.qbc:
|
||||||
|
return False
|
||||||
try:
|
try:
|
||||||
self.qbc.torrents_delete_tags(torrent_hashes=ids, tags=tag)
|
self.qbc.torrents_delete_tags(torrent_hashes=ids, tags=tag)
|
||||||
return True
|
return True
|
||||||
@ -129,6 +131,8 @@ class Qbittorrent(metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
设置强制作种
|
设置强制作种
|
||||||
"""
|
"""
|
||||||
|
if not self.qbc:
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
self.qbc.torrents_set_force_start(enable=True, torrent_hashes=ids)
|
self.qbc.torrents_set_force_start(enable=True, torrent_hashes=ids)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
@ -266,6 +270,8 @@ class Qbittorrent(metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
获取种子文件清单
|
获取种子文件清单
|
||||||
"""
|
"""
|
||||||
|
if not self.qbc:
|
||||||
|
return None
|
||||||
try:
|
try:
|
||||||
return self.qbc.torrents_files(torrent_hash=tid)
|
return self.qbc.torrents_files(torrent_hash=tid)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
@ -276,6 +282,8 @@ class Qbittorrent(metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
设置下载文件的状态,priority为0为不下载,priority为1为下载
|
设置下载文件的状态,priority为0为不下载,priority为1为下载
|
||||||
"""
|
"""
|
||||||
|
if not self.qbc:
|
||||||
|
return False
|
||||||
if not kwargs.get("torrent_hash") or not kwargs.get("file_ids"):
|
if not kwargs.get("torrent_hash") or not kwargs.get("file_ids"):
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
@ -291,8 +299,29 @@ class Qbittorrent(metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
获取传输信息
|
获取传输信息
|
||||||
"""
|
"""
|
||||||
|
if not self.qbc:
|
||||||
|
return None
|
||||||
try:
|
try:
|
||||||
return self.qbc.transfer_info()
|
return self.qbc.transfer_info()
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"获取传输信息出错:{err}")
|
logger.error(f"获取传输信息出错:{err}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def set_speed_limit(self, download_limit: float = None, upload_limit: float = None) -> bool:
|
||||||
|
"""
|
||||||
|
设置速度限制
|
||||||
|
:param download_limit: 下载速度限制,单位KB/s
|
||||||
|
:param upload_limit: 上传速度限制,单位kB/s
|
||||||
|
"""
|
||||||
|
if not self.qbc:
|
||||||
|
return False
|
||||||
|
download_limit = download_limit * 1024
|
||||||
|
upload_limit = upload_limit * 1024
|
||||||
|
try:
|
||||||
|
if self.qbc.transfer.upload_limit != upload_limit:
|
||||||
|
self.qbc.transfer.upload_limit = upload_limit
|
||||||
|
if self.qbc.transfer.download_limit != download_limit:
|
||||||
|
self.qbc.transfer.download_limit = download_limit
|
||||||
|
except Exception as err:
|
||||||
|
logger.error(f"设置速度限制出错:{err}")
|
||||||
|
return False
|
||||||
|
@ -115,6 +115,8 @@ class Transmission(metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
设置种子标签
|
设置种子标签
|
||||||
"""
|
"""
|
||||||
|
if not self.trc:
|
||||||
|
return False
|
||||||
if not ids or not tags:
|
if not ids or not tags:
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
@ -138,6 +140,8 @@ class Transmission(metaclass=Singleton):
|
|||||||
:param cookie: 站点Cookie用于辅助下载种子
|
:param cookie: 站点Cookie用于辅助下载种子
|
||||||
:return: Torrent
|
:return: Torrent
|
||||||
"""
|
"""
|
||||||
|
if not self.trc:
|
||||||
|
return None
|
||||||
try:
|
try:
|
||||||
return self.trc.add_torrent(torrent=content,
|
return self.trc.add_torrent(torrent=content,
|
||||||
download_dir=download_dir,
|
download_dir=download_dir,
|
||||||
@ -193,6 +197,8 @@ class Transmission(metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
获取种子文件列表
|
获取种子文件列表
|
||||||
"""
|
"""
|
||||||
|
if not self.trc:
|
||||||
|
return None
|
||||||
if not tid:
|
if not tid:
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
@ -209,6 +215,8 @@ class Transmission(metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
设置下载文件的状态
|
设置下载文件的状态
|
||||||
"""
|
"""
|
||||||
|
if not self.trc:
|
||||||
|
return False
|
||||||
try:
|
try:
|
||||||
self.trc.change_torrent(ids=tid, files_wanted=file_ids)
|
self.trc.change_torrent(ids=tid, files_wanted=file_ids)
|
||||||
return True
|
return True
|
||||||
@ -220,8 +228,39 @@ class Transmission(metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
获取传输信息
|
获取传输信息
|
||||||
"""
|
"""
|
||||||
|
if not self.trc:
|
||||||
|
return None
|
||||||
try:
|
try:
|
||||||
return self.trc.session_stats()
|
return self.trc.session_stats()
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"获取传输信息出错:{err}")
|
logger.error(f"获取传输信息出错:{err}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def set_speed_limit(self, download_limit: float = None, upload_limit: float = None):
|
||||||
|
"""
|
||||||
|
设置速度限制
|
||||||
|
:param download_limit: 下载速度限制,单位KB/s
|
||||||
|
:param upload_limit: 上传速度限制,单位kB/s
|
||||||
|
"""
|
||||||
|
if not self.trc:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
session = self.trc.get_session()
|
||||||
|
download_limit_enabled = True if download_limit else False
|
||||||
|
upload_limit_enabled = True if upload_limit else False
|
||||||
|
if download_limit_enabled == session.speed_limit_down_enabled and \
|
||||||
|
upload_limit_enabled == session.speed_limit_up_enabled and \
|
||||||
|
download_limit == session.speed_limit_down and \
|
||||||
|
upload_limit == session.speed_limit_up:
|
||||||
|
return
|
||||||
|
self.trc.set_session(
|
||||||
|
speed_limit_down=download_limit if download_limit != session.speed_limit_down
|
||||||
|
else session.speed_limit_down,
|
||||||
|
speed_limit_up=upload_limit if upload_limit != session.speed_limit_up
|
||||||
|
else session.speed_limit_up,
|
||||||
|
speed_limit_down_enabled=download_limit_enabled,
|
||||||
|
speed_limit_up_enabled=upload_limit_enabled
|
||||||
|
)
|
||||||
|
except Exception as err:
|
||||||
|
logger.error(f"设置速度限制出错:{err}")
|
||||||
|
return False
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import datetime
|
import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from threading import Lock
|
|
||||||
from typing import Optional, Any, List, Dict, Tuple
|
from typing import Optional, Any, List, Dict, Tuple
|
||||||
|
|
||||||
from apscheduler.schedulers.background import BackgroundScheduler
|
from apscheduler.schedulers.background import BackgroundScheduler
|
||||||
from apscheduler.triggers.cron import CronTrigger
|
from apscheduler.triggers.cron import CronTrigger
|
||||||
|
from requests import Response
|
||||||
|
|
||||||
from app.chain.subscribe import SubscribeChain
|
from app.chain.subscribe import SubscribeChain
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
@ -12,12 +12,8 @@ from app.core.context import MediaInfo
|
|||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.modules.emby import Emby
|
from app.modules.emby import Emby
|
||||||
from app.modules.jellyfin import Jellyfin
|
from app.modules.jellyfin import Jellyfin
|
||||||
from app.modules.plex import Plex
|
|
||||||
from app.plugins import _PluginBase
|
from app.plugins import _PluginBase
|
||||||
from app.schemas.types import MediaType
|
from app.schemas.types import MediaType
|
||||||
from app.utils.http import RequestUtils
|
|
||||||
|
|
||||||
lock = Lock()
|
|
||||||
|
|
||||||
|
|
||||||
class BestFilmVersion(_PluginBase):
|
class BestFilmVersion(_PluginBase):
|
||||||
@ -46,14 +42,6 @@ class BestFilmVersion(_PluginBase):
|
|||||||
_scheduler: Optional[BackgroundScheduler] = None
|
_scheduler: Optional[BackgroundScheduler] = None
|
||||||
_cache_path: Optional[Path] = None
|
_cache_path: Optional[Path] = None
|
||||||
subscribechain = None
|
subscribechain = None
|
||||||
jellyfin = None
|
|
||||||
jellyfin_user = None
|
|
||||||
emby = None
|
|
||||||
emby_user = None
|
|
||||||
plex = None
|
|
||||||
plex_user = None
|
|
||||||
service_host = None
|
|
||||||
service_apikey = None
|
|
||||||
|
|
||||||
# 配置属性
|
# 配置属性
|
||||||
_enabled: bool = False
|
_enabled: bool = False
|
||||||
@ -63,25 +51,6 @@ class BestFilmVersion(_PluginBase):
|
|||||||
def init_plugin(self, config: dict = None):
|
def init_plugin(self, config: dict = None):
|
||||||
self._cache_path = settings.TEMP_PATH / "__best_film_version_cache__"
|
self._cache_path = settings.TEMP_PATH / "__best_film_version_cache__"
|
||||||
self.subscribechain = SubscribeChain()
|
self.subscribechain = SubscribeChain()
|
||||||
if settings.MEDIASERVER == 'jellyfin':
|
|
||||||
self.jellyfin = Jellyfin()
|
|
||||||
self.jellyfin_user = self.jellyfin.get_user()
|
|
||||||
self.service_apikey = settings.JELLYFIN_API_KEY
|
|
||||||
self.service_host = settings.JELLYFIN_HOST
|
|
||||||
if settings.MEDIASERVER == 'emby':
|
|
||||||
self.emby = Emby()
|
|
||||||
self.emby_user = self.emby.get_user()
|
|
||||||
self.service_apikey = settings.EMBY_API_KEY
|
|
||||||
self.service_host = settings.EMBY_HOST
|
|
||||||
if settings.MEDIASERVER == 'plex':
|
|
||||||
self.plex = Plex()
|
|
||||||
self.service_apikey = settings.PLEX_TOKEN
|
|
||||||
self.service_host = settings.PLEX_HOST
|
|
||||||
if self.service_host:
|
|
||||||
if not self.service_host.endswith("/"):
|
|
||||||
self.service_host += "/"
|
|
||||||
if not self.service_host.startswith("http"):
|
|
||||||
self.service_host = "http://" + self.service_host
|
|
||||||
|
|
||||||
# 停止现有任务
|
# 停止现有任务
|
||||||
self.stop_service()
|
self.stop_service()
|
||||||
@ -230,7 +199,6 @@ class BestFilmVersion(_PluginBase):
|
|||||||
poster = history.get("poster")
|
poster = history.get("poster")
|
||||||
mtype = history.get("type")
|
mtype = history.get("type")
|
||||||
time_str = history.get("time")
|
time_str = history.get("time")
|
||||||
overview = history.get("overview")
|
|
||||||
tmdbid = history.get("tmdbid")
|
tmdbid = history.get("tmdbid")
|
||||||
contents.append(
|
contents.append(
|
||||||
{
|
{
|
||||||
@ -332,48 +300,48 @@ class BestFilmVersion(_PluginBase):
|
|||||||
# 读取历史记录
|
# 读取历史记录
|
||||||
history = self.get_data('history') or []
|
history = self.get_data('history') or []
|
||||||
|
|
||||||
if self.jellyfin:
|
# 读取收藏
|
||||||
|
if settings.MEDIASERVER == 'jellyfin':
|
||||||
# 根据加入日期 降序排序
|
# 根据加入日期 降序排序
|
||||||
url = f"{self.service_host}Users/{self.jellyfin_user}/Items?SortBy=DateCreated%2CSortName" \
|
url = "{HOST}Users/{USER}/Items?SortBy=DateCreated%2CSortName" \
|
||||||
f"&SortOrder=Descending" \
|
"&SortOrder=Descending" \
|
||||||
f"&Filters=IsFavorite" \
|
"&Filters=IsFavorite" \
|
||||||
f"&Recursive=true" \
|
"&Recursive=true" \
|
||||||
f"&Fields=PrimaryImageAspectRatio%2CBasicSyncInfo" \
|
"&Fields=PrimaryImageAspectRatio%2CBasicSyncInfo" \
|
||||||
f"&CollapseBoxSetItems=false" \
|
"&CollapseBoxSetItems=false" \
|
||||||
f"&ExcludeLocationTypes=Virtual" \
|
"&ExcludeLocationTypes=Virtual" \
|
||||||
f"&EnableTotalRecordCount=false" \
|
"&EnableTotalRecordCount=false" \
|
||||||
f"&Limit=20" \
|
"&Limit=20" \
|
||||||
f"&apikey={self.service_apikey}"
|
"&apikey={APIKEY}"
|
||||||
elif self.emby:
|
resp = self.get_items(Jellyfin().get_data(url))
|
||||||
|
elif settings.MEDIASERVER == 'emby':
|
||||||
# 根据加入日期 降序排序
|
# 根据加入日期 降序排序
|
||||||
url = f"{self.service_host}emby/Users/{self.emby_user}/Items?SortBy=DateCreated%2CSortName" \
|
url = "{HOST}emby/Users/{USER}/Items?SortBy=DateCreated%2CSortName" \
|
||||||
f"&SortOrder=Descending" \
|
"&SortOrder=Descending" \
|
||||||
f"&Filters=IsFavorite" \
|
"&Filters=IsFavorite" \
|
||||||
f"&Recursive=true" \
|
"&Recursive=true" \
|
||||||
f"&Fields=PrimaryImageAspectRatio%2CBasicSyncInfo" \
|
"&Fields=PrimaryImageAspectRatio%2CBasicSyncInfo" \
|
||||||
f"&CollapseBoxSetItems=false" \
|
"&CollapseBoxSetItems=false" \
|
||||||
f"&ExcludeLocationTypes=Virtual" \
|
"&ExcludeLocationTypes=Virtual" \
|
||||||
f"&EnableTotalRecordCount=false" \
|
"&EnableTotalRecordCount=false" \
|
||||||
f"&Limit=20&api_key={self.service_apikey}"
|
"&Limit=20&api_key={APIKEY}"
|
||||||
|
resp = self.get_items(Emby().get_data(url))
|
||||||
else:
|
else:
|
||||||
# TODO plex待开发
|
# TODO plex待开发
|
||||||
return
|
return
|
||||||
|
|
||||||
# 获取收藏数据
|
|
||||||
resp = self.media_simple_filter(url)
|
|
||||||
logger.info(f'BestFilmVersion插件 resp打印 {resp}')
|
|
||||||
|
|
||||||
for data in resp:
|
for data in resp:
|
||||||
# 检查缓存
|
# 检查缓存
|
||||||
if data.get('Name') in caches:
|
if data.get('Name') in caches:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 获取详情
|
# 获取详情
|
||||||
if self.jellyfin:
|
if settings.MEDIASERVER == 'jellyfin':
|
||||||
item_info_resp = self.jellyfin.get_iteminfo(itemid=data.get('Id'))
|
item_info_resp = Jellyfin().get_iteminfo(itemid=data.get('Id'))
|
||||||
elif self.emby:
|
elif settings.MEDIASERVER == 'emby':
|
||||||
item_info_resp = self.emby.get_iteminfo(itemid=data.get('Id'))
|
item_info_resp = Emby().get_iteminfo(itemid=data.get('Id'))
|
||||||
else:
|
else:
|
||||||
|
# TODO plex待开发
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info(f'BestFilmVersion插件 item打印 {item_info_resp}')
|
logger.info(f'BestFilmVersion插件 item打印 {item_info_resp}')
|
||||||
@ -424,14 +392,12 @@ class BestFilmVersion(_PluginBase):
|
|||||||
self._cache_path.write_text("\n".join(caches))
|
self._cache_path.write_text("\n".join(caches))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def media_simple_filter(url):
|
def get_items(resp: Response):
|
||||||
try:
|
try:
|
||||||
resp = RequestUtils().get_res(url=url)
|
|
||||||
if resp:
|
if resp:
|
||||||
return resp.json().get("Items")
|
return resp.json().get("Items") or []
|
||||||
else:
|
else:
|
||||||
logger.error(f"User/Items 未获取到返回数据")
|
|
||||||
return []
|
return []
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"连接User/Items 出错:" + str(e))
|
print(str(e))
|
||||||
return []
|
return []
|
||||||
|
@ -143,7 +143,7 @@ class ChatGPT(_PluginBase):
|
|||||||
return
|
return
|
||||||
response = self.openai.get_response(text=text, userid=userid)
|
response = self.openai.get_response(text=text, userid=userid)
|
||||||
if response:
|
if response:
|
||||||
self.post_message(channel=channel, title=text, userid=userid)
|
self.post_message(channel=channel, title=response, userid=userid)
|
||||||
|
|
||||||
def stop_service(self):
|
def stop_service(self):
|
||||||
"""
|
"""
|
||||||
|
@ -87,8 +87,9 @@ class CloudflareSpeedTest(_PluginBase):
|
|||||||
|
|
||||||
if self._onlyonce:
|
if self._onlyonce:
|
||||||
logger.info(f"Cloudflare CDN优选服务启动,立即运行一次")
|
logger.info(f"Cloudflare CDN优选服务启动,立即运行一次")
|
||||||
self._scheduler.add_job(self.__cloudflareSpeedTest, 'date',
|
self._scheduler.add_job(func=self.__cloudflareSpeedTest, trigger='date',
|
||||||
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3))
|
run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
|
||||||
|
name="Cloudflare优选")
|
||||||
# 关闭一次性开关
|
# 关闭一次性开关
|
||||||
self._onlyonce = False
|
self._onlyonce = False
|
||||||
self.__update_config()
|
self.__update_config()
|
||||||
|
@ -88,13 +88,16 @@ class DoubanRank(_PluginBase):
|
|||||||
if self._cron:
|
if self._cron:
|
||||||
logger.info(f"豆瓣榜单订阅服务启动,周期:{self._cron}")
|
logger.info(f"豆瓣榜单订阅服务启动,周期:{self._cron}")
|
||||||
try:
|
try:
|
||||||
self._scheduler.add_job(self.__refresh_rss,
|
self._scheduler.add_job(func=self.__refresh_rss,
|
||||||
CronTrigger.from_crontab(self._cron))
|
trigger=CronTrigger.from_crontab(self._cron),
|
||||||
|
name="豆瓣榜单订阅")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"豆瓣榜单订阅服务启动失败,错误信息:{str(e)}")
|
logger.error(f"豆瓣榜单订阅服务启动失败,错误信息:{str(e)}")
|
||||||
self.systemmessage.put(f"豆瓣榜单订阅服务启动失败,错误信息:{str(e)}")
|
self.systemmessage.put(f"豆瓣榜单订阅服务启动失败,错误信息:{str(e)}")
|
||||||
else:
|
else:
|
||||||
self._scheduler.add_job(self.__refresh_rss, CronTrigger.from_crontab("0 8 * * *"))
|
self._scheduler.add_job(func=self.__refresh_rss,
|
||||||
|
trigger=CronTrigger.from_crontab("0 8 * * *"),
|
||||||
|
name="豆瓣榜单订阅")
|
||||||
logger.info("豆瓣榜单订阅服务启动,周期:每天 08:00")
|
logger.info("豆瓣榜单订阅服务启动,周期:每天 08:00")
|
||||||
|
|
||||||
if self._scheduler.get_jobs():
|
if self._scheduler.get_jobs():
|
||||||
|
@ -66,15 +66,17 @@ class LibraryScraper(_PluginBase):
|
|||||||
if self._cron:
|
if self._cron:
|
||||||
logger.info(f"媒体库刮削服务启动,周期:{self._cron}")
|
logger.info(f"媒体库刮削服务启动,周期:{self._cron}")
|
||||||
try:
|
try:
|
||||||
self._scheduler.add_job(self.__libraryscraper,
|
self._scheduler.add_job(func=self.__libraryscraper,
|
||||||
CronTrigger.from_crontab(self._cron))
|
trigger=CronTrigger.from_crontab(self._cron),
|
||||||
|
name="媒体库刮削")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"媒体库刮削服务启动失败,原因:{e}")
|
logger.error(f"媒体库刮削服务启动失败,原因:{e}")
|
||||||
self.systemmessage.put(f"媒体库刮削服务启动失败,原因:{e}")
|
self.systemmessage.put(f"媒体库刮削服务启动失败,原因:{e}")
|
||||||
else:
|
else:
|
||||||
logger.info(f"媒体库刮削服务启动,周期:每7天")
|
logger.info(f"媒体库刮削服务启动,周期:每7天")
|
||||||
self._scheduler.add_job(self.__libraryscraper,
|
self._scheduler.add_job(func=self.__libraryscraper,
|
||||||
CronTrigger.from_crontab("0 0 */7 * *"))
|
trigger=CronTrigger.from_crontab("0 0 */7 * *"),
|
||||||
|
name="媒体库刮削")
|
||||||
if self._scheduler.get_jobs():
|
if self._scheduler.get_jobs():
|
||||||
# 启动服务
|
# 启动服务
|
||||||
self._scheduler.print_jobs()
|
self._scheduler.print_jobs()
|
||||||
|
@ -13,9 +13,10 @@ from app.core.event import eventmanager, Event
|
|||||||
from app.db.models.transferhistory import TransferHistory
|
from app.db.models.transferhistory import TransferHistory
|
||||||
from app.db.transferhistory_oper import TransferHistoryOper
|
from app.db.transferhistory_oper import TransferHistoryOper
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
|
from app.modules.emby import Emby
|
||||||
|
from app.modules.jellyfin import Jellyfin
|
||||||
from app.plugins import _PluginBase
|
from app.plugins import _PluginBase
|
||||||
from app.schemas.types import NotificationType, EventType
|
from app.schemas.types import NotificationType, EventType
|
||||||
from app.utils.http import RequestUtils
|
|
||||||
|
|
||||||
|
|
||||||
class MediaSyncDel(_PluginBase):
|
class MediaSyncDel(_PluginBase):
|
||||||
@ -469,18 +470,8 @@ class MediaSyncDel(_PluginBase):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_emby_log(last_time):
|
def parse_emby_log(last_time):
|
||||||
# emby host
|
log_url = "{HOST}System/Logs/embyserver.txt?api_key={APIKEY}"
|
||||||
emby_host = settings.EMBY_HOST
|
log_res = Emby().get_data(log_url)
|
||||||
if emby_host:
|
|
||||||
if not emby_host.endswith("/"):
|
|
||||||
emby_host += "/"
|
|
||||||
if not emby_host.startswith("http"):
|
|
||||||
emby_host = "http://" + emby_host
|
|
||||||
|
|
||||||
# emby 日志url
|
|
||||||
log_url = "%sSystem/Logs/embyserver.txt?api_key=%s" % (emby_host, settings.EMBY_API_KEY)
|
|
||||||
log_res = RequestUtils().get_res(url=log_url)
|
|
||||||
|
|
||||||
if not log_res or log_res.status_code != 200:
|
if not log_res or log_res.status_code != 200:
|
||||||
logger.error("获取emby日志失败,请检查服务器配置")
|
logger.error("获取emby日志失败,请检查服务器配置")
|
||||||
return []
|
return []
|
||||||
@ -551,19 +542,9 @@ class MediaSyncDel(_PluginBase):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_jellyfin_log(last_time):
|
def parse_jellyfin_log(last_time):
|
||||||
# jellyfin host
|
# 根据加入日期 降序排序
|
||||||
jellyfin_host = settings.JELLYFIN_HOST
|
log_url = "{HOST}System/Logs/Log?name=log_%s.log&api_key={APIKEY}" % datetime.date.today().strftime("%Y%m%d")
|
||||||
if jellyfin_host:
|
log_res = Jellyfin().get_data(log_url)
|
||||||
if not jellyfin_host.endswith("/"):
|
|
||||||
jellyfin_host += "/"
|
|
||||||
if not jellyfin_host.startswith("http"):
|
|
||||||
jellyfin_host = "http://" + jellyfin_host
|
|
||||||
|
|
||||||
# jellyfin 日志url
|
|
||||||
log_url = "%sSystem/Logs/Log?name=log_%s.log&api_key=%s" % (
|
|
||||||
jellyfin_host, datetime.date.today().strftime("%Y%m%d"), settings.JELLYFIN_API_KEY)
|
|
||||||
log_res = RequestUtils().get_res(url=log_url)
|
|
||||||
|
|
||||||
if not log_res or log_res.status_code != 200:
|
if not log_res or log_res.status_code != 200:
|
||||||
logger.error("获取jellyfin日志失败,请检查服务器配置")
|
logger.error("获取jellyfin日志失败,请检查服务器配置")
|
||||||
return []
|
return []
|
||||||
|
@ -4,6 +4,8 @@ from apscheduler.schedulers.background import BackgroundScheduler
|
|||||||
|
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
|
from app.modules.qbittorrent import Qbittorrent
|
||||||
|
from app.modules.transmission import Transmission
|
||||||
from app.plugins import _PluginBase
|
from app.plugins import _PluginBase
|
||||||
|
|
||||||
|
|
||||||
@ -31,22 +33,32 @@ class SpeedLimiter(_PluginBase):
|
|||||||
|
|
||||||
# 私有属性
|
# 私有属性
|
||||||
_scheduler = None
|
_scheduler = None
|
||||||
|
_qb = None
|
||||||
|
_tr = None
|
||||||
_enabled: bool = False
|
_enabled: bool = False
|
||||||
_notify: bool = False
|
_notify: bool = False
|
||||||
_bandwidth: int = 0
|
|
||||||
_interval: int = 60
|
_interval: int = 60
|
||||||
|
_downloader: list = []
|
||||||
|
_play_up_speed: float = 0
|
||||||
|
_play_down_speed: float = 0
|
||||||
|
_noplay_up_speed: float = 0
|
||||||
|
_noplay_down_speed: float = 0
|
||||||
|
|
||||||
def init_plugin(self, config: dict = None):
|
def init_plugin(self, config: dict = None):
|
||||||
# 读取配置
|
# 读取配置
|
||||||
if config:
|
if config:
|
||||||
self._enabled = config.get("enabled")
|
self._enabled = config.get("enabled")
|
||||||
self._notify = config.get("notify")
|
self._notify = config.get("notify")
|
||||||
try:
|
self._play_up_speed = float(config.get("play_up_speed")) if config.get("play_up_speed") else 0
|
||||||
# 总带宽
|
self._play_down_speed = float(config.get("play_down_speed")) if config.get("play_down_speed") else 0
|
||||||
self._bandwidth = int(float(config.get("bandwidth") or 0)) * 1000000
|
self._noplay_up_speed = float(config.get("noplay_up_speed")) if config.get("noplay_up_speed") else 0
|
||||||
except Exception as e:
|
self._noplay_down_speed = float(config.get("noplay_down_speed")) if config.get("noplay_down_speed") else 0
|
||||||
logger.error(f"总带宽配置错误:{e}")
|
self._downloader = config.get("downloader") or []
|
||||||
self._bandwidth = 0
|
if self._downloader:
|
||||||
|
if 'qbittorrent' in self._downloader:
|
||||||
|
self._qb = Qbittorrent()
|
||||||
|
if 'transmission' in self._downloader:
|
||||||
|
self._tr = Transmission()
|
||||||
|
|
||||||
# 移出现有任务
|
# 移出现有任务
|
||||||
self.stop_service()
|
self.stop_service()
|
||||||
@ -56,10 +68,11 @@ class SpeedLimiter(_PluginBase):
|
|||||||
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
|
||||||
self._scheduler.add_job(func=self.__check_playing_sessions,
|
self._scheduler.add_job(func=self.__check_playing_sessions,
|
||||||
trigger='interval',
|
trigger='interval',
|
||||||
seconds=self._interval)
|
seconds=self._interval,
|
||||||
|
name="播放限速检查")
|
||||||
self._scheduler.print_jobs()
|
self._scheduler.print_jobs()
|
||||||
self._scheduler.start()
|
self._scheduler.start()
|
||||||
logger.info("播放限速服务启动")
|
logger.info("播放限速检查服务启动")
|
||||||
|
|
||||||
def get_state(self) -> bool:
|
def get_state(self) -> bool:
|
||||||
return self._enabled
|
return self._enabled
|
||||||
@ -72,7 +85,159 @@ class SpeedLimiter(_PluginBase):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
|
||||||
pass
|
return [
|
||||||
|
{
|
||||||
|
'component': 'VForm',
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VRow',
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VCol',
|
||||||
|
'props': {
|
||||||
|
'cols': 12,
|
||||||
|
'md': 6
|
||||||
|
},
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VSwitch',
|
||||||
|
'props': {
|
||||||
|
'model': 'enabled',
|
||||||
|
'label': '启用插件',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'component': 'VCol',
|
||||||
|
'props': {
|
||||||
|
'cols': 12,
|
||||||
|
'md': 6
|
||||||
|
},
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VSwitch',
|
||||||
|
'props': {
|
||||||
|
'model': 'notify',
|
||||||
|
'label': '发送通知',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'component': 'VRow',
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VCol',
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VSelect',
|
||||||
|
'props': {
|
||||||
|
'chips': True,
|
||||||
|
'multiple': True,
|
||||||
|
'model': 'sign_sites',
|
||||||
|
'label': '下载器',
|
||||||
|
'items': [
|
||||||
|
{'title': 'Qbittorrent', 'value': 'qbittorrent'},
|
||||||
|
{'title': 'Transmission', 'value': 'transmission'},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'component': 'VRow',
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VCol',
|
||||||
|
'props': {
|
||||||
|
'cols': 12,
|
||||||
|
'md': 6
|
||||||
|
},
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VTextField',
|
||||||
|
'props': {
|
||||||
|
'model': 'play_up_speed',
|
||||||
|
'label': '播放限速(上传)',
|
||||||
|
'placeholder': 'KB/s'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'component': 'VCol',
|
||||||
|
'props': {
|
||||||
|
'cols': 12,
|
||||||
|
'md': 6
|
||||||
|
},
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VTextField',
|
||||||
|
'props': {
|
||||||
|
'model': 'play_down_speed',
|
||||||
|
'label': '播放限速(下载)',
|
||||||
|
'placeholder': 'KB/s'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'component': 'VRow',
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VCol',
|
||||||
|
'props': {
|
||||||
|
'cols': 12,
|
||||||
|
'md': 6
|
||||||
|
},
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VTextField',
|
||||||
|
'props': {
|
||||||
|
'model': 'noplay_up_speed',
|
||||||
|
'label': '未播放限速(上传)',
|
||||||
|
'placeholder': 'KB/s'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'component': 'VCol',
|
||||||
|
'props': {
|
||||||
|
'cols': 12,
|
||||||
|
'md': 6
|
||||||
|
},
|
||||||
|
'content': [
|
||||||
|
{
|
||||||
|
'component': 'VTextField',
|
||||||
|
'props': {
|
||||||
|
'model': 'noplay_down_speed',
|
||||||
|
'label': '未播放限速(下载)',
|
||||||
|
'placeholder': 'KB/s'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
], {
|
||||||
|
"enabled": False,
|
||||||
|
"notify": True,
|
||||||
|
"downloader": [],
|
||||||
|
"play_up_speed": 0,
|
||||||
|
"play_down_speed": 0,
|
||||||
|
"noplay_up_speed": 0,
|
||||||
|
"noplay_down_speed": 0,
|
||||||
|
}
|
||||||
|
|
||||||
def get_page(self) -> List[dict]:
|
def get_page(self) -> List[dict]:
|
||||||
pass
|
pass
|
||||||
@ -81,6 +246,13 @@ class SpeedLimiter(_PluginBase):
|
|||||||
"""
|
"""
|
||||||
检查播放会话
|
检查播放会话
|
||||||
"""
|
"""
|
||||||
|
if not self._qb and not self._tr:
|
||||||
|
return
|
||||||
|
|
||||||
|
def __set_limiter(self):
|
||||||
|
"""
|
||||||
|
设置限速
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def stop_service(self):
|
def stop_service(self):
|
||||||
|
Reference in New Issue
Block a user