Skip to content

Commit a92f6f1

Browse files
FXFX
authored andcommitted
Add netdisk share monitoring and denser detail meta.
Support direct cloud-drive share sources with optional extract codes, and compact the expanded row meta into a single strip with a clickable source URL.
1 parent 2d418bd commit a92f6f1

9 files changed

Lines changed: 1038 additions & 29 deletions

File tree

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
# 更新追踪(AppUpdate)
22

3-
内网自用:追踪 **GitHub Release 下载附件****单篇文章网盘链接**,网页管理,可选 Telegram 推送。
3+
内网自用:追踪 **GitHub Release 下载附件****单篇文章网盘链接**,以及 **网盘分享页本身的更新**,网页管理,可选 Telegram 推送。
44

55
![更新追踪界面预览](docs/screenshot-main.png)
66

77
## 功能
88

99
- **GitHub 公开仓库**:正式版 + 预发布;按扩展名 / 系统 / 架构别名 / 包含·排除筛选附件
1010
- **单篇文章**:标题变化则整页重抓,提取百度 / 阿里 / 夸克 / 123 / 天翼 / 蓝奏(链接、提取码、标题备注)
11+
- **网盘分享**:直接添加分享链接(可选提取码),监控分享内文件列表变化;支持百度 / 阿里 / 夸克 / 123 / 天翼 / 蓝奏
1112
- 只保留当前最新状态(有变化才推送;首次检查不刷屏)
1213
- 固定间隔检查(默认 6 小时,可在设置里改)+ 立即检查
1314
- 可停用不删除
@@ -50,7 +51,7 @@ docker compose up -d --build
5051
首次打开为空列表。在网页中:
5152

5253
1. **设置**:检查间隔、Telegram Bot Token / Chat ID(可选)、**面板访问密码(可选)**
53-
2. **添加**:GitHub 仓库或文章链接,并配置筛选规则
54+
2. **添加**:GitHub 仓库、文章链接或网盘分享链接,并配置筛选/提取码
5455
3. 添加后会自动检查;也可随时点 **立即检查** 或单项 **检查**
5556

5657
数据目录:`./data`(SQLite:`appupdate.db`,首次运行自动创建)
@@ -104,7 +105,7 @@ uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
104105
## 说明
105106

106107
- 仅支持公开 GitHub 仓库
107-
- 不做自动下载、不自动转存网盘
108+
- 网盘监控只读分享信息,不做自动下载、不自动转存;部分盘商有登录墙/验证码时退化为页面指纹监控
108109
- 默认无密码;可在设置中开启面板密码
109110
- 设计稿与交互原型在 `design-options/``prototype/`,部署不需要,已排除在 Docker 构建之外
110111

app/models.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from pydantic import BaseModel, Field
66

77

8-
SourceType = Literal["github", "article"]
8+
SourceType = Literal["github", "article", "netdisk"]
99

1010

1111
class FilterRule(BaseModel):
@@ -38,6 +38,7 @@ class SourceCreate(BaseModel):
3838
enabled: bool = True
3939
filter_rule: Optional[FilterRule] = Field(default=None, alias="filterRule")
4040
include_prerelease: bool = Field(default=True, alias="includePrerelease")
41+
share_code: str = Field(default="", alias="shareCode")
4142

4243
model_config = {"populate_by_name": True}
4344

@@ -48,6 +49,7 @@ class SourceUpdate(BaseModel):
4849
url: Optional[str] = None
4950
filter_rule: Optional[FilterRule] = Field(default=None, alias="filterRule")
5051
include_prerelease: Optional[bool] = Field(default=None, alias="includePrerelease")
52+
share_code: Optional[str] = Field(default=None, alias="shareCode")
5153

5254
model_config = {"populate_by_name": True}
5355

app/routers/sources.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,21 @@
66

77
from app import db
88
from app.models import SourceCreate, SourceUpdate
9-
from app.services import article_svc, github_svc
9+
from app.services import article_svc, github_svc, netdisk_svc
1010
from app.services.match import ARCH_OPTIONS, EXT_OPTIONS, OS_OPTIONS, describe_rule, normalize_rule
1111

1212
router = APIRouter(prefix="/api/sources", tags=["sources"])
1313

1414

1515
def _public(source: dict[str, Any]) -> dict[str, Any]:
1616
data = {k: v for k, v in source.items() if k not in {"fingerprint", "createdAt", "updatedAt"}}
17-
data["ruleText"] = describe_rule(source.get("filterRule") or {})
17+
rule = source.get("filterRule") or {}
18+
if source.get("type") == "netdisk":
19+
data["ruleText"] = netdisk_svc.describe_netdisk_rule(rule)
20+
data["shareCode"] = str(rule.get("code") or "")
21+
else:
22+
data["ruleText"] = describe_rule(rule)
23+
data["shareCode"] = ""
1824
if not source.get("enabled"):
1925
data["status"] = "off"
2026
return data
@@ -61,6 +67,16 @@ def create(body: SourceCreate) -> dict[str, Any]:
6167
name = github_svc.default_name(url)
6268
filter_rule = normalize_rule(body.filter_rule.model_dump(by_alias=True) if body.filter_rule else {})
6369
include_prerelease = body.include_prerelease
70+
elif body.type == "netdisk":
71+
if not url.startswith("http://") and not url.startswith("https://"):
72+
raise HTTPException(400, "网盘请填写完整 http(s) 分享链接")
73+
if not netdisk_svc.is_netdisk_url(url):
74+
raise HTTPException(400, "暂不支持该网盘,目前支持百度/阿里/夸克/123/天翼/蓝奏")
75+
if not name:
76+
name = netdisk_svc.default_name(url)
77+
code = (body.share_code or "").strip() or netdisk_svc.extract_code(url)
78+
filter_rule = {"code": code}
79+
include_prerelease = True
6480
else:
6581
if not url.startswith("http://") and not url.startswith("https://"):
6682
raise HTTPException(400, "文章请填写完整 http(s) 链接")
@@ -99,12 +115,25 @@ def update(source_id: int, body: SourceUpdate) -> dict[str, Any]:
99115
github_svc.parse_repo(url)
100116
except ValueError as e:
101117
raise HTTPException(400, str(e)) from e
118+
elif src["type"] == "netdisk":
119+
if not url.startswith("http://") and not url.startswith("https://"):
120+
raise HTTPException(400, "网盘请填写完整 http(s) 分享链接")
121+
if not netdisk_svc.is_netdisk_url(url):
122+
raise HTTPException(400, "暂不支持该网盘,目前支持百度/阿里/夸克/123/天翼/蓝奏")
102123
payload["url"] = url
103124
if "enabled" in data:
104125
payload["enabled"] = data["enabled"]
105126
if "include_prerelease" in data:
106127
payload["include_prerelease"] = data["include_prerelease"]
107-
if "filter_rule" in data and data["filter_rule"] is not None:
128+
if src["type"] == "netdisk" and ("share_code" in data or "url" in payload):
129+
current_rule = src.get("filterRule") or {}
130+
code = current_rule.get("code") or ""
131+
if "share_code" in data and data["share_code"] is not None:
132+
code = str(data["share_code"] or "").strip()
133+
elif "url" in payload:
134+
code = netdisk_svc.extract_code(payload["url"], str(code))
135+
payload["filter_rule"] = {"code": code}
136+
elif "filter_rule" in data and data["filter_rule"] is not None:
108137
payload["filter_rule"] = normalize_rule(
109138
body.filter_rule.model_dump(by_alias=True) if body.filter_rule else {}
110139
)

app/services/checker.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from typing import Any, Optional
55

66
from app import db
7-
from app.services import article_svc, github_svc
7+
from app.services import article_svc, github_svc, netdisk_svc
88
from app.services.telegram_notify import format_update_message, send_telegram
99

1010
log = logging.getLogger("appupdate.checker")
@@ -37,6 +37,12 @@ async def check_one(source: dict[str, Any], *, notify: bool = True) -> dict[str,
3737
include_prerelease=bool(source.get("includePrerelease", True)),
3838
filter_rule=source.get("filterRule") or {},
3939
)
40+
elif source["type"] == "netdisk":
41+
rule = source.get("filterRule") or {}
42+
result = await netdisk_svc.fetch_share(
43+
source["url"],
44+
code=str(rule.get("code") or ""),
45+
)
4046
else:
4147
result = await article_svc.fetch_article(source["url"])
4248

0 commit comments

Comments
 (0)