为资源搜索功能新增了 PanSou 服务器支持,优化了搜索结果的展示与排序方式,调整了系统配置页面的模块顺序

This commit is contained in:
x1ao4 2025-08-26 01:57:34 +08:00
parent a27c76637b
commit 7bf5e7423a
5 changed files with 448 additions and 92 deletions

View File

@ -16,6 +16,10 @@ from flask import (
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger
from sdk.cloudsaver import CloudSaver
try:
from sdk.pansou import PanSou
except Exception:
PanSou = None
from datetime import timedelta, datetime
import subprocess
import requests
@ -511,6 +515,14 @@ def get_data():
}
}
# 初始化搜索来源默认结构
if "source" not in data or not isinstance(data.get("source"), dict):
data["source"] = {}
# CloudSaver 默认字段
data["source"].setdefault("cloudsaver", {"server": "", "username": "", "password": "", "token": ""})
# PanSou 默认字段
data["source"].setdefault("pansou", {"server": "https://so.252035.xyz"})
# 发送webui信息但不发送密码原文
data["webui"] = {
"username": config_data["webui"]["username"],
@ -929,7 +941,14 @@ def get_task_suggestions():
search_query = extract_show_name(query)
try:
cs_data = config_data.get("source", {}).get("cloudsaver", {})
sources_cfg = config_data.get("source", {}) or {}
cs_data = sources_cfg.get("cloudsaver", {})
ps_data = sources_cfg.get("pansou", {})
merged = []
providers = []
# CloudSaver
if (
cs_data.get("server")
and cs_data.get("username")
@ -941,35 +960,76 @@ def get_task_suggestions():
cs_data.get("password", ""),
cs_data.get("token", ""),
)
# 使用处理后的搜索关键词
search = cs.auto_login_search(search_query)
if search.get("success"):
if search.get("new_token"):
cs_data["token"] = search.get("new_token")
Config.write_json(CONFIG_PATH, config_data)
search_results = cs.clean_search_results(search.get("data"))
# 在返回结果中添加实际使用的搜索关键词
return jsonify(
{
"success": True,
"source": "CloudSaver",
"data": search_results
}
)
else:
return jsonify({"success": True, "message": search.get("message")})
else:
base_url = base64.b64decode("aHR0cHM6Ly9zLjkxNzc4OC54eXo=").decode()
# 使用处理后的搜索关键词
url = f"{base_url}/task_suggestions?q={search_query}&d={deep}"
response = requests.get(url)
return jsonify(
{
"success": True,
"source": "网络公开",
"data": response.json()
}
)
if isinstance(search_results, list):
merged.extend(search_results)
providers.append("CloudSaver")
# PanSou
if ps_data and ps_data.get("server") and PanSou is not None:
try:
ps = PanSou(ps_data.get("server"))
result = ps.search(search_query)
if result.get("success") and isinstance(result.get("data"), list):
merged.extend(result.get("data"))
providers.append("PanSou")
except Exception as e:
logging.warning(f"PanSou 搜索失败: {str(e)}")
# 去重按shareurl优先其次taskname
dedup = []
seen = set()
for item in merged:
if not isinstance(item, dict):
continue
key = item.get("shareurl") or item.get("taskname")
if not key:
continue
if key in seen:
continue
seen.add(key)
dedup.append(item)
# 全局时间排序:所有来源的结果混合排序,按时间倒序(最新的在前)
if dedup:
def parse_datetime_for_sort(item):
"""解析时间字段,返回可比较的时间戳"""
# 兼容两个字段名publish_date 和 datetime
datetime_str = item.get("publish_date") or item.get("datetime")
if not datetime_str:
return 0 # 没有时间的排在最后
try:
from datetime import datetime
# 尝试解析格式: 2025-01-01 12:00:00
dt = datetime.strptime(datetime_str, "%Y-%m-%d %H:%M:%S")
return dt.timestamp()
except:
return 0 # 解析失败排在最后
# 按时间倒序排序(最新的在前)
dedup.sort(key=parse_datetime_for_sort, reverse=True)
return jsonify({
"success": True,
"source": ", ".join(providers) if providers else "聚合",
"data": dedup
})
# 若无本地可用来源,回退到公开网络
base_url = base64.b64decode("aHR0cHM6Ly9zLjkxNzc4OC54eXo=").decode()
url = f"{base_url}/task_suggestions?q={search_query}&d={deep}"
response = requests.get(url)
return jsonify({
"success": True,
"source": "网络公开",
"data": response.json()
})
except Exception as e:
return jsonify({"success": True, "message": f"error: {str(e)}"})

View File

@ -124,6 +124,10 @@ class CloudSaver:
content = content.replace('<mark class="highlight">', "")
content = content.replace("</mark>", "")
content = content.strip()
# 获取发布时间 - 采用与原始实现一致的方式
pubdate = item.get("pubDate", "") # 使用 pubDate 字段
if pubdate:
pubdate = self._iso_to_cst(pubdate) # 转换为中国标准时间
# 链接去重
if link.get("link") not in link_array:
link_array.append(link.get("link"))
@ -132,12 +136,33 @@ class CloudSaver:
"shareurl": link.get("link"),
"taskname": title,
"content": content,
"datetime": pubdate, # 使用 datetime 字段名,与原始实现一致
"tags": item.get("tags", []),
"channel": item.get("channel", ""),
"channel_id": item.get("channelId", ""),
"channel": item.get("channelId", ""),
"source": "CloudSaver"
}
)
# 注意:排序逻辑已移至全局,这里不再进行内部排序
# 返回原始顺序的结果,由全局排序函数统一处理
return clean_results
def _iso_to_cst(self, iso_time_str: str) -> str:
"""将 ISO 格式的时间字符串转换为 CST(China Standard Time) 时间并格式化为 %Y-%m-%d %H:%M:%S 格式
Args:
iso_time_str (str): ISO 格式时间字符串
Returns:
str: CST(China Standard Time) 时间字符串
"""
try:
from datetime import datetime, timezone, timedelta
dt = datetime.fromisoformat(iso_time_str)
dt_cst = dt.astimezone(timezone(timedelta(hours=8)))
return dt_cst.strftime("%Y-%m-%d %H:%M:%S") if dt_cst.year >= 1970 else ""
except:
return iso_time_str # 转换失败时返回原始字符串
# 测试示例

188
app/sdk/pansou.py Normal file
View File

@ -0,0 +1,188 @@
import requests
import json
from typing import List, Dict, Any
class PanSou:
"""PanSou 资源搜索客户端"""
def __init__(self, server: str):
self.server = server.rstrip("/") if server else ""
self.session = requests.Session()
# 使用标准请求头
self.session.headers.update({
"Content-Type": "application/json",
"Accept": "application/json",
"User-Agent": "QASX-PanSouClient/1.0"
})
def _request_json(self, url: str, params: dict):
"""发送 GET 请求并解析 JSON 响应"""
try:
resp = self.session.get(url, params=params, timeout=15)
return resp.json()
except Exception as e:
return {"success": False, "message": str(e)}
def search(self, keyword: str):
"""
搜索资源仅返回夸克网盘结果
返回{"success": True, "data": [{taskname, content, shareurl, tags[]}]}
"""
if not self.server:
return {"success": False, "message": "PanSou未配置服务器"}
# 使用已验证的参数kw + cloud_types=quark + res=all
params = {
"kw": keyword,
"cloud_types": "quark", # 单个类型用字符串,多个类型用逗号分隔
"res": "all"
}
# 优先使用 /api/search 路径
url = f"{self.server}/api/search"
result = self._request_json(url, params)
if not result:
return {"success": False, "message": "PanSou请求失败"}
# 解析响应:兼容 {code, message, data: {results, merged_by_type}} 格式
payload = result
if isinstance(result.get("data"), dict):
payload = result["data"]
# 检查错误码
if "code" in result and result.get("code") != 0:
return {"success": False, "message": result.get("message") or "PanSou搜索失败"}
# 解析结果:优先 results然后 merged_by_type
cleaned = []
try:
# 1) results: 主要结果数组,每个结果包含 title 和 links
results = payload.get("results", [])
if isinstance(results, list):
for result_item in results:
if not isinstance(result_item, dict):
continue
# 从 result_item 获取标题、内容和发布日期
title = result_item.get("title", "")
content = result_item.get("content", "")
datetime_str = result_item.get("datetime", "") # 获取发布日期
# 从 links 获取具体链接
links = result_item.get("links", [])
if isinstance(links, list):
for link in links:
if isinstance(link, dict):
url = link.get("url", "")
link_type = link.get("type", "")
if url: # 确保有有效链接
cleaned.append({
"taskname": title,
"content": content,
"shareurl": url,
"tags": [link_type] if link_type else (result_item.get("tags", []) or []),
"publish_date": datetime_str, # 添加发布日期字段
"source": "PanSou" # 添加来源标识
})
# 2) merged_by_type: 兜底解析,使用 note 字段作为标题
if not cleaned:
merged = payload.get("merged_by_type")
if isinstance(merged, dict):
for cloud_type, links in merged.items():
if isinstance(links, list):
for link in links:
if isinstance(link, dict):
# 从 merged_by_type 获取链接信息
url = link.get("url", "")
note = link.get("note", "") # 使用 note 字段作为标题
datetime_str = link.get("datetime", "") # 获取发布日期
if url:
cleaned.append({
"taskname": note,
"content": note, # 如果没有 content使用 note
"shareurl": url,
"tags": [cloud_type] if cloud_type else [],
"publish_date": datetime_str, # 添加发布日期字段
"source": "PanSou" # 添加来源标识
})
# 3) 直接 data 数组兜底
if not cleaned and isinstance(payload, list):
for item in payload:
if isinstance(item, dict):
cleaned.append({
"taskname": item.get("title", ""),
"content": item.get("content", ""),
"shareurl": item.get("url", ""),
"tags": item.get("tags", []) or [],
"publish_date": item.get("datetime", ""), # 添加发布日期字段
"source": "PanSou" # 添加来源标识
})
except Exception as e:
return {"success": False, "message": f"解析PanSou结果失败: {str(e)}"}
# 二次过滤:确保只返回夸克网盘链接
if cleaned:
filtered = []
for item in cleaned:
try:
url = item.get("shareurl", "")
tags = item.get("tags", []) or []
# 检查是否为夸克网盘
is_quark = ("quark" in tags) or ("pan.quark.cn" in url)
if is_quark:
filtered.append(item)
except Exception:
continue
cleaned = filtered
if not cleaned:
return {"success": False, "message": "PanSou搜索无夸克网盘结果"}
# 去重:按 shareurl 去重
seen_urls = set()
unique_results = []
for item in cleaned:
url = item.get("shareurl", "")
if url and url not in seen_urls:
seen_urls.add(url)
unique_results.append(item)
# 按发布日期排序:最新的在前
def parse_datetime(datetime_str):
"""解析日期时间字符串,返回可比较的时间戳"""
if not datetime_str:
return 0 # 没有日期的排在最后
try:
from datetime import datetime, timezone, timedelta
# 尝试解析 ISO 8601 格式: 2025-07-28T20:43:27Z
dt = datetime.fromisoformat(datetime_str.replace('Z', '+00:00'))
return dt.timestamp()
except:
return 0 # 解析失败排在最后
def convert_to_cst(datetime_str):
"""将 ISO 时间转换为中国标准时间 (CST)"""
if not datetime_str:
return ""
try:
from datetime import datetime, timezone, timedelta
dt = datetime.fromisoformat(datetime_str.replace('Z', '+00:00'))
dt_cst = dt.astimezone(timezone(timedelta(hours=8)))
return dt_cst.strftime("%Y-%m-%d %H:%M:%S")
except:
return datetime_str # 转换失败时返回原始字符串
# 转换时间为中国标准时间格式
for item in unique_results:
if item.get("publish_date"):
item["publish_date"] = convert_to_cst(item["publish_date"])
# 注意:排序逻辑已移至全局,这里不再进行内部排序
# 返回原始顺序的结果,由全局排序函数统一处理
return {"success": True, "data": unique_results}

View File

@ -3218,7 +3218,7 @@ div[data-toggle="collapse"] .btn.text-left i.bi-caret-right-fill {
color: inherit;
transition: transform 0.2s;
position: relative;
top: 0.5px; /* 调整箭头垂直对齐,使其与文本居中 */
top: 0; /* 调整箭头垂直对齐,使其与文本居中 */
font-size: 0.95rem; /* 调整箭头大小与文本比例协调 */
margin-right: 4px; /* 添加右侧间距使与文字有适当间距 */
}
@ -6399,3 +6399,42 @@ body .selectable-files tr.selected-file:has([style*="white-space: normal"]) .fil
font-family: inherit;
letter-spacing: normal;
}
/* 仅在“搜索来源”前的最后一个插件折叠时,将间距减少 2px */
div:has(> .collapse:not(.show)):has(+ .row.title[title^="资源搜索"]) {
margin-bottom: -10px !important; /* override inline -8px only for collapsed state */
}
/* 修复系统配置页面性能设置与API接口模块间距问题 */
.row.mb-2.performance-setting-row + .row.title[title^="API接口"] {
margin-top: 0 !important; /* prevent unexpected collapse stacking */
padding-top: 4px !important; /* adds effective +4px spacing */
}
/* --------------- 来源标识样式 --------------- */
.source-badge {
display: inline-block;
margin-left: 1px;
font-size: 14px;
line-height: 1.2;
white-space: nowrap;
vertical-align: baseline;
color: var(--light-text-color);
background-color: transparent;
}
.source-badge::before {
content: "· ";
margin-right: 0px;
color: var(--light-text-color);
}
.source-badge::after {
content: attr(data-publish-date);
margin-left: 2px;
color: var(--light-text-color);
font-size: 14px;
line-height: 1.2;
white-space: nowrap;
vertical-align: baseline;
}

View File

@ -509,7 +509,7 @@
<div class="row title" title="通知推送支持多个渠道查阅Wiki了解详情">
<div class="col">
<h2 style="display: inline-block; font-size: 1.5rem;">通知</h2>
<h2 style="display: inline-block; font-size: 1.5rem;">通知设置</h2>
<span class="badge badge-pill badge-light">
<a href="https://github.com/x1ao4/quark-auto-save-x/wiki/通知推送服务配置" target="_blank"><i class="bi bi-question-circle"></i></a>
</span>
@ -531,7 +531,7 @@
<div class="row title" v-if="Object.keys(getAvailablePlugins(formData.plugins)).length" title="插件配置具体键值由插件定义查阅Wiki了解详情">
<div class="col">
<h2 style="display: inline-block; font-size: 1.5rem;">插件</h2>
<h2 style="display: inline-block; font-size: 1.5rem;">插件设置</h2>
<span class="badge badge-pill badge-light">
<a href="https://github.com/x1ao4/quark-auto-save-x/wiki/插件配置" target="_blank"><i class="bi bi-question-circle"></i></a>
</span>
@ -541,7 +541,7 @@
<div class="form-group row mb-0" style="display:flex; align-items:center;">
<div data-toggle="collapse" :data-target="'#collapse_'+pluginName" aria-expanded="true" :aria-controls="'collapse_'+pluginName">
<div class="btn btn-block text-left">
<i class="bi bi-caret-right-fill"></i> <span v-html="`${pluginName}`"></span>
<i class="bi bi-caret-right-fill"></i> <span v-html="getPluginDisplayName(pluginName)"></span>
</div>
</div>
</div>
@ -582,6 +582,72 @@
</div>
</div>
</div>
<div class="row title" title="资源搜索服务配置用于任务名称智能搜索查阅Wiki了解详情">
<div class="col">
<h2 style="display: inline-block; font-size: 1.5rem;">搜索来源</h2>
<span class="badge badge-pill badge-light">
<a href="https://github.com/x1ao4/quark-auto-save-x/wiki/CloudSaver搜索源" target="_blank"><i class="bi bi-question-circle"></i></a>
</span>
</div>
</div>
<!-- 按插件风格显示为可展开项 -->
<div style="margin-bottom: -8px;">
<!-- CloudSaver -->
<div style="margin-bottom: -8px; margin-top: -8px;">
<div class="form-group row mb-0" style="display:flex; align-items:center;">
<div data-toggle="collapse" data-target="#collapse_source_cloudsaver" aria-expanded="true" aria-controls="collapse_source_cloudsaver">
<div class="btn btn-block text-left">
<i class="bi bi-caret-right-fill"></i> CloudSaver
</div>
</div>
</div>
<div class="collapse" id="collapse_source_cloudsaver" style="margin-left: 26px;">
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text">服务器</span>
</div>
<input type="text" v-model="formData.source.cloudsaver.server" class="form-control" placeholder="资源搜索服务器地址,如 http://172.17.0.1:8008">
</div>
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text">用户名</span>
</div>
<input type="text" v-model="formData.source.cloudsaver.username" class="form-control" placeholder="用户名">
</div>
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text">密码</span>
</div>
<input :type="showCloudSaverPassword ? 'text' : 'password'" v-model="formData.source.cloudsaver.password" class="form-control" placeholder="密码">
<div class="input-group-append">
<button type="button" class="btn btn-outline-secondary" @click="toggleCloudSaverPassword">
<i :class="['bi', showCloudSaverPassword ? 'bi-eye' : 'bi-eye-slash']"></i>
</button>
</div>
</div>
</div>
</div>
<!-- PanSou -->
<div style="margin-bottom: -9.5px;">
<div class="form-group row mb-0" style="display:flex; align-items:center;">
<div data-toggle="collapse" data-target="#collapse_source_pansou" aria-expanded="false" aria-controls="collapse_source_pansou">
<div class="btn btn-block text-left">
<i class="bi bi-caret-right-fill"></i> PanSou
</div>
</div>
</div>
<div class="collapse" id="collapse_source_pansou" style="margin-left: 26px;">
<div class="input-group mb-2" style="margin-bottom: 10.5px !important;">
<div class="input-group-prepend">
<span class="input-group-text">服务器</span>
</div>
<input type="text" v-model="formData.source.pansou.server" class="form-control" placeholder="PanSou 服务器,如 https://so.252035.xyz">
</div>
</div>
</div>
</div>
<div class="row title" title="预定义的正则匹配规则在任务列表中可直接点击使用查阅Wiki了解详情">
<div class="col">
@ -718,59 +784,6 @@
</div>
</div>
<div class="row title" title="API接口用于第三方添加任务等操作查阅Wiki了解详情">
<div class="col">
<h2 style="display: inline-block; font-size: 1.5rem;">API</h2>
<span class="badge badge-pill badge-light">
<a href="https://github.com/x1ao4/quark-auto-save-x/wiki/API接口" target="_blank"><i class="bi bi-question-circle"></i></a>
</span>
</div>
</div>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">Token</span>
</div>
<input type="text" v-model="formData.api_token" class="form-control" style="background-color:white;" disabled>
</div>
<div class="row title" title="资源搜索服务配置用于任务名称智能搜索查阅Wiki了解详情">
<div class="col">
<h2 style="display: inline-block; font-size: 1.5rem;">CloudSaver</h2>
<span class="badge badge-pill badge-light">
<a href="https://github.com/x1ao4/quark-auto-save-x/wiki/CloudSaver搜索源" target="_blank"><i class="bi bi-question-circle"></i></a>
</span>
</div>
</div>
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text">服务器</span>
</div>
<input type="text" v-model="formData.source.cloudsaver.server" class="form-control" placeholder="资源搜索服务器地址,如 http://172.17.0.1:8008">
</div>
<div class="row mb-2">
<div class="col cloudsaver-username-col">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">用户名</span>
</div>
<input type="text" v-model="formData.source.cloudsaver.username" class="form-control" placeholder="用户名">
</div>
</div>
<div class="col cloudsaver-password-col">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">密码</span>
</div>
<input :type="showCloudSaverPassword ? 'text' : 'password'" v-model="formData.source.cloudsaver.password" class="form-control" placeholder="密码">
<div class="input-group-append">
<button type="button" class="btn btn-outline-secondary" @click="toggleCloudSaverPassword">
<i :class="['bi', showCloudSaverPassword ? 'bi-eye' : 'bi-eye-slash']"></i>
</button>
</div>
</div>
</div>
</div>
<div class="row title" title="设置任务列表页面的任务按钮的显示方式刷新Plex媒体库和刷新AList目录按钮仅在配置了对应插件的前提下才支持显示">
<div class="col">
<h2 style="display: inline-block; font-size: 1.5rem;">显示设置</h2>
@ -910,6 +923,20 @@
</div>
</div>
</div>
<div class="row title" title="API接口用于第三方添加任务等操作查阅Wiki了解详情">
<div class="col">
<h2 style="display: inline-block; font-size: 1.5rem;">API</h2>
<span class="badge badge-pill badge-light">
<a href="https://github.com/x1ao4/quark-auto-save-x/wiki/API接口" target="_blank"><i class="bi bi-question-circle"></i></a>
</span>
</div>
</div>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">Token</span>
</div>
<input type="text" v-model="formData.api_token" class="form-control" style="background-color:white;" disabled>
</div>
</div>
@ -999,6 +1026,7 @@
<span v-html="suggestion.verify ? '✅': ''"></span> {{ suggestion.taskname }}
<small class="text-muted">
<a :href="suggestion.shareurl" target="_blank" @click.stop>{{ suggestion.shareurl }}</a>
<span v-if="suggestion.source" class="source-badge" :class="suggestion.source.toLowerCase()" :data-publish-date="(suggestion.publish_date || suggestion.datetime) ? ' · ' + (suggestion.publish_date || suggestion.datetime) : ''">{{ suggestion.source }}</span>
</small>
</div>
</div>
@ -1926,6 +1954,7 @@
<span v-html="suggestion.verify ? '✅': ''"></span> {{ suggestion.taskname }}
<small class="text-muted">
<a :href="suggestion.shareurl" target="_blank" @click.stop>{{ suggestion.shareurl }}</a>
<span v-if="suggestion.source" class="source-badge" :class="suggestion.source.toLowerCase()" :data-publish-date="(suggestion.publish_date || suggestion.datetime) ? ' · ' + (suggestion.publish_date || suggestion.datetime) : ''">{{ suggestion.source }}</span>
</small>
</div>
</div>
@ -2094,6 +2123,14 @@
showCloudSaverPassword: false,
showWebuiPassword: false,
pageWidthMode: 'medium', // 页面宽度模式narrow, medium, wide
pluginDisplayAliases: {
alist: 'AList',
alist_strm: 'AList Strm',
alist_strm_gen: 'AList Strm Gen',
aria2: 'Aria2',
emby: 'Emby',
plex: 'Plex'
},
formData: {
cookie: [],
push_config: {},
@ -2118,6 +2155,9 @@
username: "",
password: "",
token: ""
},
pansou: {
server: "https://so.252035.xyz"
}
},
webui: {
@ -2718,6 +2758,10 @@
document.removeEventListener('click', this.handleOutsideClick);
},
methods: {
// 获取插件展示名称支持别名仅用于WebUI显示
getPluginDisplayName(pluginName) {
return this.pluginDisplayAliases[pluginName] || pluginName;
},
// 设置移动端任务列表展开/收起状态监听
setupMobileTaskListToggle() {
// 监听所有collapse事件
@ -7632,10 +7676,10 @@
// 打开创建任务模态框
$('#createTaskModal').modal('show');
// 如果启用了自动搜索资源且配置了有效的CloudSaver信息,自动触发资源搜索
// 如果启用了自动搜索资源且配置了有效的搜索来源,自动触发资源搜索
this.$nextTick(() => {
if (this.formData.task_settings.auto_search_resources === 'enabled' &&
this.isCloudSaverConfigValid() &&
this.hasAnyValidSearchSource() &&
this.createTask.taskData.taskname) {
this.searchSuggestions(-1, this.createTask.taskData.taskname);
}
@ -7644,13 +7688,13 @@
console.error('创建任务时出错:', error);
}
},
isCloudSaverConfigValid() {
// 检查CloudSaver配置是否有效
const csData = this.formData.source && this.formData.source.cloudsaver;
return csData &&
csData.server &&
csData.username &&
csData.password;
hasAnyValidSearchSource() {
const src = this.formData.source || {};
const cs = src.cloudsaver || {};
const ps = src.pansou || {};
const csValid = cs.server && cs.username && cs.password;
const psValid = ps.server;
return !!(csValid || psValid);
},
smartFillTaskData(item, movieData) {
// 智能填充任务数据