mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-06 16:07:01 +08:00
add siteuserdata
This commit is contained in:
@@ -113,8 +113,6 @@ def update_subscribe(
|
|||||||
subscribe = Subscribe.get(db, subscribe_in.id)
|
subscribe = Subscribe.get(db, subscribe_in.id)
|
||||||
if not subscribe:
|
if not subscribe:
|
||||||
return schemas.Response(success=False, message="订阅不存在")
|
return schemas.Response(success=False, message="订阅不存在")
|
||||||
if subscribe_in.sites is not None:
|
|
||||||
subscribe_in.sites = json.dumps(subscribe_in.sites)
|
|
||||||
# 避免更新缺失集数
|
# 避免更新缺失集数
|
||||||
subscribe_dict = subscribe_in.dict()
|
subscribe_dict = subscribe_in.dict()
|
||||||
if not subscribe_in.lack_episode:
|
if not subscribe_in.lack_episode:
|
||||||
|
|||||||
+16
-3
@@ -59,13 +59,26 @@ class SiteChain(ChainBase):
|
|||||||
"yemapt.org": self.__yema_test,
|
"yemapt.org": self.__yema_test,
|
||||||
}
|
}
|
||||||
|
|
||||||
def site_userdata(self, site: CommentedMap) -> Optional[SiteUserData]:
|
def refresh_userdata(self, site: CommentedMap = None) -> Optional[SiteUserData]:
|
||||||
"""
|
"""
|
||||||
获取站点的所有用户数据
|
刷新站点的用户数据
|
||||||
:param site: 站点
|
:param site: 站点
|
||||||
:return: 用户数据
|
:return: 用户数据
|
||||||
"""
|
"""
|
||||||
return self.run_module("site_userdata", site=site)
|
userdata = self.run_module("refresh_userdata", site=site)
|
||||||
|
if userdata:
|
||||||
|
self.siteoper.update_userdata(domain=StringUtils.get_url_domain(site.get("domain")),
|
||||||
|
payload=userdata)
|
||||||
|
return userdata
|
||||||
|
|
||||||
|
def refresh_userdatas(self) -> None:
|
||||||
|
"""
|
||||||
|
刷新所有站点的用户数据
|
||||||
|
"""
|
||||||
|
sites = self.siteshelper.get_indexers()
|
||||||
|
for site in sites:
|
||||||
|
if site.get("is_active"):
|
||||||
|
self.refresh_userdata(site)
|
||||||
|
|
||||||
def is_special_site(self, domain: str) -> bool:
|
def is_special_site(self, domain: str) -> bool:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -487,7 +487,7 @@ class SubscribeChain(ChainBase):
|
|||||||
# 如果交集与原始订阅不一致,更新数据库
|
# 如果交集与原始订阅不一致,更新数据库
|
||||||
if set(intersection_sites) != set(user_sites):
|
if set(intersection_sites) != set(user_sites):
|
||||||
self.subscribeoper.update(subscribe.id, {
|
self.subscribeoper.update(subscribe.id, {
|
||||||
"sites": json.dumps(intersection_sites)
|
"sites": intersection_sites
|
||||||
})
|
})
|
||||||
# 如果交集为空,返回默认站点
|
# 如果交集为空,返回默认站点
|
||||||
return intersection_sites if intersection_sites else default_sites
|
return intersection_sites if intersection_sites else default_sites
|
||||||
@@ -857,7 +857,7 @@ class SubscribeChain(ChainBase):
|
|||||||
note = list(set(note).union(set(episodes)))
|
note = list(set(note).union(set(episodes)))
|
||||||
# 更新订阅
|
# 更新订阅
|
||||||
self.subscribeoper.update(subscribe.id, {
|
self.subscribeoper.update(subscribe.id, {
|
||||||
"note": json.dumps(note)
|
"note": note
|
||||||
})
|
})
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -1140,7 +1140,7 @@ class SubscribeChain(ChainBase):
|
|||||||
continue
|
continue
|
||||||
sites.remove(site_id)
|
sites.remove(site_id)
|
||||||
self.subscribeoper.update(subscribe.id, {
|
self.subscribeoper.update(subscribe.id, {
|
||||||
"sites": json.dumps(sites)
|
"sites": sites
|
||||||
})
|
})
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@@ -101,6 +101,8 @@ class Settings(BaseSettings):
|
|||||||
SUBSCRIBE_SEARCH: bool = False
|
SUBSCRIBE_SEARCH: bool = False
|
||||||
# 搜索多个名称
|
# 搜索多个名称
|
||||||
SEARCH_MULTIPLE_NAME: bool = False
|
SEARCH_MULTIPLE_NAME: bool = False
|
||||||
|
# 站点数据刷新间隔(小时)
|
||||||
|
SITEDATA_REFRESH_INTERVAL: int = 6
|
||||||
# 种子标签
|
# 种子标签
|
||||||
TORRENT_TAG: str = "MOVIEPILOT"
|
TORRENT_TAG: str = "MOVIEPILOT"
|
||||||
# 下载站点字幕
|
# 下载站点字幕
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import json
|
||||||
from typing import Any, Self, List
|
from typing import Any, Self, List
|
||||||
from typing import Tuple, Optional, Generator
|
from typing import Tuple, Optional, Generator
|
||||||
|
|
||||||
@@ -7,6 +8,7 @@ from sqlalchemy.orm import declared_attr
|
|||||||
from sqlalchemy.orm import sessionmaker, Session, scoped_session, as_declarative
|
from sqlalchemy.orm import sessionmaker, Session, scoped_session, as_declarative
|
||||||
|
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
|
from app.utils.object import ObjectUtils
|
||||||
|
|
||||||
# 数据库引擎
|
# 数据库引擎
|
||||||
Engine = create_engine(f"sqlite:///{settings.CONFIG_PATH}/user.db",
|
Engine = create_engine(f"sqlite:///{settings.CONFIG_PATH}/user.db",
|
||||||
@@ -156,6 +158,8 @@ class Base:
|
|||||||
def update(self, db: Session, payload: dict):
|
def update(self, db: Session, payload: dict):
|
||||||
payload = {k: v for k, v in payload.items() if v is not None}
|
payload = {k: v for k, v in payload.items() if v is not None}
|
||||||
for key, value in payload.items():
|
for key, value in payload.items():
|
||||||
|
if ObjectUtils.is_obj(value):
|
||||||
|
value = json.dumps(value)
|
||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
if inspect(self).detached:
|
if inspect(self).detached:
|
||||||
db.add(self)
|
db.add(self)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import json
|
|
||||||
import time
|
import time
|
||||||
from typing import Optional, Union
|
from typing import Optional, Union
|
||||||
|
|
||||||
@@ -53,7 +52,7 @@ class MessageOper(DbOper):
|
|||||||
"userid": userid,
|
"userid": userid,
|
||||||
"action": action,
|
"action": action,
|
||||||
"reg_time": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
|
"reg_time": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
|
||||||
"note": json.dumps(note) if note else ''
|
"note": note
|
||||||
})
|
})
|
||||||
Message(**kwargs).create(self._db)
|
Message(**kwargs).create(self._db)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from sqlalchemy import Column, Integer, String, Sequence
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
from app.db import db_query, Base
|
||||||
|
|
||||||
|
|
||||||
|
class SiteUserData(Base):
|
||||||
|
"""
|
||||||
|
站点数据表
|
||||||
|
"""
|
||||||
|
id = Column(Integer, Sequence('id'), primary_key=True, index=True)
|
||||||
|
# 站点域名
|
||||||
|
domain = Column(String, index=True)
|
||||||
|
# 用户名
|
||||||
|
username = Column(String)
|
||||||
|
# 用户ID
|
||||||
|
userid = Column(Integer)
|
||||||
|
# 用户等级
|
||||||
|
user_level = Column(String)
|
||||||
|
# 加入时间
|
||||||
|
join_at = Column(String)
|
||||||
|
# 积分
|
||||||
|
bonus = Column(Integer, default=0)
|
||||||
|
# 上传量
|
||||||
|
upload = Column(Integer, default=0)
|
||||||
|
# 下载量
|
||||||
|
download = Column(Integer, default=0)
|
||||||
|
# 分享率
|
||||||
|
ratio = Column(Integer, default=0)
|
||||||
|
# 做种数
|
||||||
|
seeding = Column(Integer, default=0)
|
||||||
|
# 下载数
|
||||||
|
leeching = Column(Integer, default=0)
|
||||||
|
# 做种体积
|
||||||
|
seeding_size = Column(Integer, default=0)
|
||||||
|
# 下载体积
|
||||||
|
leeching_size = Column(Integer, default=0)
|
||||||
|
# 做种人数, 种子大小 JSON
|
||||||
|
seeding_info = Column(String)
|
||||||
|
# 未读消息
|
||||||
|
message_unread = Column(Integer, default=0)
|
||||||
|
# 未读消息内容 JSON
|
||||||
|
message_unread_contents = Column(String)
|
||||||
|
# 错误信息
|
||||||
|
err_msg = Column(String)
|
||||||
|
# 更新日期
|
||||||
|
updated_day = Column(String, index=True, default=datetime.now().strftime('%Y-%m-%d'))
|
||||||
|
# 更新时间
|
||||||
|
updated_time = Column(String, default=datetime.now().strftime('%H:%M:%S'))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@db_query
|
||||||
|
def get_by_domain(db: Session, domain: str):
|
||||||
|
return db.query(SiteUserData).filter(SiteUserData.domain == domain).all()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@db_query
|
||||||
|
def get_by_date(db: Session, date: str):
|
||||||
|
return db.query(SiteUserData).filter(SiteUserData.updated_day == date).all()
|
||||||
@@ -18,8 +18,6 @@ class PluginDataOper(DbOper):
|
|||||||
:param key: 数据key
|
:param key: 数据key
|
||||||
:param value: 数据值
|
:param value: 数据值
|
||||||
"""
|
"""
|
||||||
if ObjectUtils.is_obj(value):
|
|
||||||
value = json.dumps(value)
|
|
||||||
plugin = PluginData.get_plugin_data_by_key(self._db, plugin_id, key)
|
plugin = PluginData.get_plugin_data_by_key(self._db, plugin_id, key)
|
||||||
if plugin:
|
if plugin:
|
||||||
plugin.update(self._db, {
|
plugin.update(self._db, {
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
from datetime import datetime
|
||||||
from typing import Tuple, List
|
from typing import Tuple, List
|
||||||
|
|
||||||
from app.db import DbOper
|
from app.db import DbOper
|
||||||
from app.db.models.site import Site
|
from app.db.models.site import Site
|
||||||
|
from app.db.models.siteuserdata import SiteUserData
|
||||||
|
|
||||||
|
|
||||||
class SiteOper(DbOper):
|
class SiteOper(DbOper):
|
||||||
@@ -98,3 +100,30 @@ class SiteOper(DbOper):
|
|||||||
"rss": rss
|
"rss": rss
|
||||||
})
|
})
|
||||||
return True, "更新站点RSS地址成功"
|
return True, "更新站点RSS地址成功"
|
||||||
|
|
||||||
|
def update_userdata(self, domain: str, payload: dict) -> Tuple[bool, str]:
|
||||||
|
"""
|
||||||
|
更新站点用户数据
|
||||||
|
"""
|
||||||
|
site = Site.get_by_domain(self._db, domain)
|
||||||
|
if not site:
|
||||||
|
return False, "站点不存在"
|
||||||
|
payload.update({
|
||||||
|
"domain": domain,
|
||||||
|
"updated_day": datetime.now().strftime('%Y-%m-%d'),
|
||||||
|
"updated_time": datetime.now().strftime('%H:%M:%S')
|
||||||
|
})
|
||||||
|
SiteUserData.update(self._db, payload)
|
||||||
|
return True, "更新站点用户数据成功"
|
||||||
|
|
||||||
|
def get_userdata_by_domain(self, domain: str) -> List[SiteUserData]:
|
||||||
|
"""
|
||||||
|
获取站点用户数据
|
||||||
|
"""
|
||||||
|
return SiteUserData.get_by_domain(self._db, domain)
|
||||||
|
|
||||||
|
def get_userdata_by_date(self, date: str) -> List[SiteUserData]:
|
||||||
|
"""
|
||||||
|
获取站点用户数据
|
||||||
|
"""
|
||||||
|
return SiteUserData.get_by_date(self._db, date)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class SiteStatisticOper(DbOper):
|
|||||||
"seconds": avg_seconds or sta.seconds,
|
"seconds": avg_seconds or sta.seconds,
|
||||||
"lst_state": 0,
|
"lst_state": 0,
|
||||||
"lst_mod_date": lst_date,
|
"lst_mod_date": lst_date,
|
||||||
"note": json.dumps(note) if note else sta.note
|
"note": note or sta.note
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
note = {}
|
note = {}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import json
|
|
||||||
import time
|
import time
|
||||||
from typing import Tuple, List
|
from typing import Tuple, List
|
||||||
|
|
||||||
@@ -21,9 +20,6 @@ class SubscribeOper(DbOper):
|
|||||||
doubanid=mediainfo.douban_id,
|
doubanid=mediainfo.douban_id,
|
||||||
season=kwargs.get('season'))
|
season=kwargs.get('season'))
|
||||||
if not subscribe:
|
if not subscribe:
|
||||||
if kwargs.get("sites") and not isinstance(kwargs.get("sites"), str):
|
|
||||||
kwargs["sites"] = json.dumps(kwargs.get("sites"))
|
|
||||||
|
|
||||||
subscribe = Subscribe(name=mediainfo.title,
|
subscribe = Subscribe(name=mediainfo.title,
|
||||||
year=mediainfo.year,
|
year=mediainfo.year,
|
||||||
type=mediainfo.type.value,
|
type=mediainfo.type.value,
|
||||||
|
|||||||
@@ -207,9 +207,9 @@ class IndexerModule(_ModuleBase):
|
|||||||
"""
|
"""
|
||||||
return self.search_torrents(site=site)
|
return self.search_torrents(site=site)
|
||||||
|
|
||||||
def site_userdata(self, site: CommentedMap) -> Optional[SiteUserData]:
|
def refresh_userdata(self, site: CommentedMap) -> Optional[SiteUserData]:
|
||||||
"""
|
"""
|
||||||
获取站点的所有用户数据
|
刷新站点的用户数据
|
||||||
:param site: 站点
|
:param site: 站点
|
||||||
:return: 用户数据
|
:return: 用户数据
|
||||||
"""
|
"""
|
||||||
@@ -240,6 +240,7 @@ class IndexerModule(_ModuleBase):
|
|||||||
site_obj.parse()
|
site_obj.parse()
|
||||||
logger.debug(f"站点 {site.get('name')} 解析完成")
|
logger.debug(f"站点 {site.get('name')} 解析完成")
|
||||||
return SiteUserData(
|
return SiteUserData(
|
||||||
|
domain=StringUtils.get_url_domain(site.get("url")),
|
||||||
userid=site_obj.userid,
|
userid=site_obj.userid,
|
||||||
username=site_obj.username,
|
username=site_obj.username,
|
||||||
user_level=site_obj.user_level,
|
user_level=site_obj.user_level,
|
||||||
|
|||||||
@@ -166,6 +166,11 @@ class Scheduler(metaclass=Singleton):
|
|||||||
"name": "壁纸缓存",
|
"name": "壁纸缓存",
|
||||||
"func": TmdbChain().get_trending_wallpapers,
|
"func": TmdbChain().get_trending_wallpapers,
|
||||||
"running": False,
|
"running": False,
|
||||||
|
},
|
||||||
|
"sitedata_refresh": {
|
||||||
|
"name": "站点数据刷新",
|
||||||
|
"func": SiteChain().refresh_userdatas,
|
||||||
|
"running": False,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,6 +348,18 @@ class Scheduler(metaclass=Singleton):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 站点数据刷新,每隔30分钟
|
||||||
|
self._scheduler.add_job(
|
||||||
|
self.start,
|
||||||
|
"interval",
|
||||||
|
id="sitedata_refresh",
|
||||||
|
name="站点数据刷新",
|
||||||
|
minutes=settings.SITEDATA_REFRESH_INTERVAL * 60,
|
||||||
|
kwargs={
|
||||||
|
'job_id': 'sitedata_refresh'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
# 注册插件公共服务
|
# 注册插件公共服务
|
||||||
for pid in PluginManager().get_running_plugin_ids():
|
for pid in PluginManager().get_running_plugin_ids():
|
||||||
self.update_plugin_job(pid)
|
self.update_plugin_job(pid)
|
||||||
|
|||||||
+8
-18
@@ -70,6 +70,8 @@ class SiteStatistic(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class SiteUserData(BaseModel):
|
class SiteUserData(BaseModel):
|
||||||
|
# 站点域名
|
||||||
|
domain: Optional[str]
|
||||||
# 用户名
|
# 用户名
|
||||||
username: Optional[str]
|
username: Optional[str]
|
||||||
# 用户ID
|
# 用户ID
|
||||||
@@ -80,32 +82,20 @@ class SiteUserData(BaseModel):
|
|||||||
join_at: Optional[str]
|
join_at: Optional[str]
|
||||||
# 积分
|
# 积分
|
||||||
bonus: Optional[float] = 0.0
|
bonus: Optional[float] = 0.0
|
||||||
# 上传
|
# 上传量
|
||||||
upload: Optional[int] = 0
|
upload: Optional[int] = 0
|
||||||
# 下载
|
# 下载量
|
||||||
download: Optional[int] = 0
|
download: Optional[int] = 0
|
||||||
# 分享率
|
# 分享率
|
||||||
ratio: Optional[float] = 0
|
ratio: Optional[float] = 0
|
||||||
# 做种
|
# 做种数
|
||||||
seeding: Optional[int] = 0
|
seeding: Optional[int] = 0
|
||||||
# 下载
|
# 下载数
|
||||||
leeching: Optional[int] = 0
|
leeching: Optional[int] = 0
|
||||||
# 做种大小
|
# 做种体积
|
||||||
seeding_size: Optional[int] = 0
|
seeding_size: Optional[int] = 0
|
||||||
# 下载大小
|
# 下载体积
|
||||||
leeching_size: Optional[int] = 0
|
leeching_size: Optional[int] = 0
|
||||||
# 上传量
|
|
||||||
uploaded: Optional[int] = 0
|
|
||||||
# 完成量
|
|
||||||
completed: Optional[int] = 0
|
|
||||||
# 未完成量
|
|
||||||
incomplete: Optional[int] = 0
|
|
||||||
# 上传量
|
|
||||||
uploaded_size: Optional[int] = 0
|
|
||||||
# 完成量
|
|
||||||
completed_size: Optional[int] = 0
|
|
||||||
# 未完成量
|
|
||||||
incomplete_size: Optional[int] = 0
|
|
||||||
# 做种人数, 种子大小
|
# 做种人数, 种子大小
|
||||||
seeding_info: Optional[list] = []
|
seeding_info: Optional[list] = []
|
||||||
# 未读消息
|
# 未读消息
|
||||||
|
|||||||
Reference in New Issue
Block a user