mirror of
https://github.com/Cp0204/quark-auto-save.git
synced 2026-01-11 22:50:45 +08:00
✨ 添加 PanSou 资源搜索功能 (#113)
* feat: 添加 PanSou 资源搜索功能 * fix: 修复 PanSou 未配置时搜索报错问题 * perf: 资源搜索结果按时间倒序排序 * fix: 修复缺失 PanSou 配置前端报错问题 * perf: 资源多源搜索结果合并去重
This commit is contained in:
parent
70176a46a1
commit
0a361e974d
57
app/run.py
57
app/run.py
@ -15,7 +15,9 @@ from flask import (
|
||||
)
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from sdk.cloudsaver import CloudSaver
|
||||
from sdk.pansou import PanSou
|
||||
from datetime import timedelta
|
||||
import subprocess
|
||||
import requests
|
||||
@ -233,8 +235,16 @@ def get_task_suggestions():
|
||||
return jsonify({"success": False, "message": "未登录"})
|
||||
query = request.args.get("q", "").lower()
|
||||
deep = request.args.get("d", "").lower()
|
||||
try:
|
||||
cs_data = config_data.get("source", {}).get("cloudsaver", {})
|
||||
cs_data = config_data.get("source", {}).get("cloudsaver", {})
|
||||
ps_data = config_data.get("source", {}).get("pansou", {})
|
||||
|
||||
def net_search():
|
||||
base_url = base64.b64decode("aHR0cHM6Ly9zLjkxNzc4OC54eXo=").decode()
|
||||
url = f"{base_url}/task_suggestions?q={query}&d={deep}"
|
||||
response = requests.get(url)
|
||||
return response.json()
|
||||
|
||||
def cs_search():
|
||||
if (
|
||||
cs_data.get("server")
|
||||
and cs_data.get("username")
|
||||
@ -252,18 +262,37 @@ def get_task_suggestions():
|
||||
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={query}&d={deep}"
|
||||
response = requests.get(url)
|
||||
return jsonify(
|
||||
{"success": True, "source": "网络公开", "data": response.json()}
|
||||
)
|
||||
return search_results
|
||||
return []
|
||||
|
||||
def ps_search():
|
||||
if (ps_data.get("server")):
|
||||
ps = PanSou(ps_data.get("server"))
|
||||
return ps.search(query)
|
||||
return []
|
||||
|
||||
try:
|
||||
search_results = []
|
||||
with ThreadPoolExecutor(max_workers=3) as executor:
|
||||
features = []
|
||||
features.append(executor.submit(net_search))
|
||||
features.append(executor.submit(cs_search))
|
||||
features.append(executor.submit(ps_search))
|
||||
for future in as_completed(features):
|
||||
result = future.result()
|
||||
search_results.extend(result)
|
||||
|
||||
# 按时间排序并去重
|
||||
results = []
|
||||
link_array = []
|
||||
search_results.sort(key=lambda x: x.get("datetime", ""), reverse=True)
|
||||
for item in search_results:
|
||||
url = item.get("shareurl", "")
|
||||
if url != "" and url not in link_array:
|
||||
link_array.append(url)
|
||||
results.append(item)
|
||||
|
||||
return jsonify({"success": True, "data": results})
|
||||
except Exception as e:
|
||||
return jsonify({"success": True, "message": f"error: {str(e)}"})
|
||||
|
||||
|
||||
@ -135,6 +135,7 @@ class CloudSaver:
|
||||
"tags": item.get("tags", []),
|
||||
"channel": item.get("channel", ""),
|
||||
"channel_id": item.get("channelId", ""),
|
||||
"source": "CloudSaver"
|
||||
}
|
||||
)
|
||||
return clean_results
|
||||
|
||||
95
app/sdk/pansou.py
Normal file
95
app/sdk/pansou.py
Normal file
@ -0,0 +1,95 @@
|
||||
import re
|
||||
import datetime
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
class PanSou:
|
||||
"""
|
||||
PanSou 类,用于获取云盘资源
|
||||
"""
|
||||
|
||||
def __init__(self, server):
|
||||
self.server = server
|
||||
self.session = requests.Session()
|
||||
|
||||
def search(self, keyword: str) -> list:
|
||||
"""搜索资源
|
||||
|
||||
Args:
|
||||
keyword (str): 搜索关键字
|
||||
|
||||
Returns:
|
||||
list: 资源列表
|
||||
"""
|
||||
try:
|
||||
url = f"{self.server.rstrip('/')}/api/search"
|
||||
params = {"kw": keyword, "cloud_types": ["quark"], "res": "merge", "refresh": True}
|
||||
response = self.session.get(url, params=params)
|
||||
result = response.json()
|
||||
if result.get("code") == 0:
|
||||
data = result.get("data", {}).get("merged_by_type", {}).get("quark", [])
|
||||
return self.format_search_results(data)
|
||||
return []
|
||||
except Exception as _:
|
||||
return []
|
||||
|
||||
def format_search_results(self, search_results: list) -> list:
|
||||
"""格式化搜索结果
|
||||
|
||||
Args:
|
||||
search_results (list): 搜索结果列表
|
||||
|
||||
Returns:
|
||||
list: 夸克网盘资源列表
|
||||
"""
|
||||
pattern = (
|
||||
r'^(.*?)'
|
||||
r'(?:'
|
||||
r'[【\[]?'
|
||||
r'(?:简介|介绍|描述)'
|
||||
r'[】\]]?'
|
||||
r'[::]?'
|
||||
r')'
|
||||
r'(.*)$'
|
||||
)
|
||||
format_results = []
|
||||
link_array = []
|
||||
for channel in search_results:
|
||||
url = channel.get("url", "")
|
||||
note = channel.get("note", "")
|
||||
tm = channel.get("datetime", "")
|
||||
if tm:
|
||||
tm = datetime.datetime.strptime(tm, "%Y-%m-%dT%H:%M:%SZ").strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
match = re.search(pattern, note)
|
||||
if match:
|
||||
title = match.group(1)
|
||||
content = match.group(2)
|
||||
else:
|
||||
title = note
|
||||
content = ""
|
||||
|
||||
if url != "" and url not in link_array:
|
||||
link_array.append(url)
|
||||
format_results.append({
|
||||
"taskname": title,
|
||||
"content": content,
|
||||
"shareurl": url,
|
||||
"datetime": tm,
|
||||
"source": "PanSou"
|
||||
})
|
||||
|
||||
return format_results
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
server: str = "https://so.252035.xyz"
|
||||
pansou = PanSou(server)
|
||||
results = pansou.search("哪吒")
|
||||
for item in results:
|
||||
print(f"标题: {item['taskname']}")
|
||||
print(f"描述: {item['content']}")
|
||||
print(f"链接: {item['shareurl']}")
|
||||
print(f"时间: {item['datetime']}")
|
||||
print("-" * 50)
|
||||
@ -223,6 +223,21 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row title" title="资源搜索服务配置,用于任务名称智能搜索">
|
||||
<div class="col-10">
|
||||
<h2 style="display: inline-block;"><i class="bi bi-search"></i> PanSou</h2>
|
||||
<span class="badge badge-pill badge-light">
|
||||
<a href="https://github.com/fish2018/pansou" target="_blank">?</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-2 col-form-label">服务器</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" v-model="formData.source.pansou.server" class="form-control" placeholder="资源搜索服务器地址,如 https://so.252035.xyz">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div v-if="activeTab === 'tasklist'">
|
||||
@ -281,12 +296,14 @@
|
||||
<div class="input-group">
|
||||
<input type="text" name="taskname[]" class="form-control" v-model="task.taskname" placeholder="必填" @focus="smart_param.showSuggestions=true;focusTaskname(index, task)" @input="changeTaskname(index, task)">
|
||||
<div class="dropdown-menu show task-suggestions" v-if="smart_param.showSuggestions && smart_param.taskSuggestions.success && smart_param.index === index">
|
||||
<div class="dropdown-item text-muted text-center" style="font-size:12px;">{{ smart_param.taskSuggestions.message ? smart_param.taskSuggestions.message : smart_param.taskSuggestions.data.length ? `以下资源来自 ${smart_param.taskSuggestions.source} 搜索,请自行辨识,如有侵权请联系资源方` : "未搜索到资源" }}</div>
|
||||
<div class="dropdown-item text-muted text-center" style="font-size:12px;">{{ smart_param.taskSuggestions.message ? smart_param.taskSuggestions.message : smart_param.taskSuggestions.data.length ? `以下资源来自网络搜索,请自行辨识,如有侵权请联系资源方` : "未搜索到资源" }}</div>
|
||||
<div v-for="suggestion in smart_param.taskSuggestions.data" :key="suggestion.taskname" class="dropdown-item cursor-pointer" @click.prevent="selectSuggestion(index, suggestion)" style="font-size: 12px;" :title="suggestion.content">
|
||||
<span v-html="suggestion.verify ? '✅': '❔'"></span> {{ suggestion.taskname }}
|
||||
<small class="text-muted">
|
||||
<a :href="suggestion.shareurl" target="_blank" @click.stop>{{ suggestion.shareurl }}</a>
|
||||
</small>
|
||||
<span class="badge bg-transparent border border-success text-success">{{ suggestion.source || "网络公开" }}</span>
|
||||
<span v-if="suggestion.datetime" class="badge bg-transparent border border-dark text-dark">{{ suggestion.datetime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group-append" title="深度搜索">
|
||||
@ -542,6 +559,9 @@
|
||||
username: "",
|
||||
password: "",
|
||||
token: ""
|
||||
},
|
||||
pansou: {
|
||||
server: ""
|
||||
}
|
||||
},
|
||||
},
|
||||
@ -676,6 +696,11 @@
|
||||
token: ""
|
||||
};
|
||||
}
|
||||
if (!config_data.source.pansou) {
|
||||
config_data.source.pansou = {
|
||||
server: ""
|
||||
};
|
||||
}
|
||||
this.formData = config_data;
|
||||
setTimeout(() => {
|
||||
this.configModified = false;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user