mirror of
https://github.com/Cp0204/quark-auto-save.git
synced 2026-01-18 02:40:44 +08:00
Compare commits
4 Commits
70176a46a1
...
6f9b009194
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f9b009194 | ||
|
|
de37c26423 | ||
|
|
e975b2822b | ||
|
|
0a361e974d |
57
app/run.py
57
app/run.py
@ -15,7 +15,9 @@ from flask import (
|
|||||||
)
|
)
|
||||||
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 concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
from sdk.cloudsaver import CloudSaver
|
from sdk.cloudsaver import CloudSaver
|
||||||
|
from sdk.pansou import PanSou
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import subprocess
|
import subprocess
|
||||||
import requests
|
import requests
|
||||||
@ -233,8 +235,16 @@ def get_task_suggestions():
|
|||||||
return jsonify({"success": False, "message": "未登录"})
|
return jsonify({"success": False, "message": "未登录"})
|
||||||
query = request.args.get("q", "").lower()
|
query = request.args.get("q", "").lower()
|
||||||
deep = request.args.get("d", "").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 (
|
if (
|
||||||
cs_data.get("server")
|
cs_data.get("server")
|
||||||
and cs_data.get("username")
|
and cs_data.get("username")
|
||||||
@ -252,18 +262,37 @@ def get_task_suggestions():
|
|||||||
cs_data["token"] = search.get("new_token")
|
cs_data["token"] = search.get("new_token")
|
||||||
Config.write_json(CONFIG_PATH, config_data)
|
Config.write_json(CONFIG_PATH, config_data)
|
||||||
search_results = cs.clean_search_results(search.get("data"))
|
search_results = cs.clean_search_results(search.get("data"))
|
||||||
return jsonify(
|
return search_results
|
||||||
{"success": True, "source": "CloudSaver", "data": search_results}
|
return []
|
||||||
)
|
|
||||||
else:
|
def ps_search():
|
||||||
return jsonify({"success": True, "message": search.get("message")})
|
if (ps_data.get("server")):
|
||||||
else:
|
ps = PanSou(ps_data.get("server"))
|
||||||
base_url = base64.b64decode("aHR0cHM6Ly9zLjkxNzc4OC54eXo=").decode()
|
return ps.search(query)
|
||||||
url = f"{base_url}/task_suggestions?q={query}&d={deep}"
|
return []
|
||||||
response = requests.get(url)
|
|
||||||
return jsonify(
|
try:
|
||||||
{"success": True, "source": "网络公开", "data": response.json()}
|
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:
|
except Exception as e:
|
||||||
return jsonify({"success": True, "message": f"error: {str(e)}"})
|
return jsonify({"success": True, "message": f"error: {str(e)}"})
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
from datetime import datetime, timedelta
|
||||||
import re
|
import re
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
@ -124,6 +125,11 @@ class CloudSaver:
|
|||||||
content = content.replace('<mark class="highlight">', "")
|
content = content.replace('<mark class="highlight">', "")
|
||||||
content = content.replace("</mark>", "")
|
content = content.replace("</mark>", "")
|
||||||
content = content.strip()
|
content = content.strip()
|
||||||
|
# 统一发布时间格式
|
||||||
|
pubdate = item.get("pubDate", "")
|
||||||
|
if pubdate:
|
||||||
|
utc_tm = datetime.fromisoformat(pubdate)
|
||||||
|
pubdate = (utc_tm + timedelta(hours=8)).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
# 链接去重
|
# 链接去重
|
||||||
if link.get("link") not in link_array:
|
if link.get("link") not in link_array:
|
||||||
link_array.append(link.get("link"))
|
link_array.append(link.get("link"))
|
||||||
@ -132,9 +138,11 @@ class CloudSaver:
|
|||||||
"shareurl": link.get("link"),
|
"shareurl": link.get("link"),
|
||||||
"taskname": title,
|
"taskname": title,
|
||||||
"content": content,
|
"content": content,
|
||||||
|
"datetime": pubdate,
|
||||||
"tags": item.get("tags", []),
|
"tags": item.get("tags", []),
|
||||||
"channel": item.get("channel", ""),
|
"channel": item.get("channel", ""),
|
||||||
"channel_id": item.get("channelId", ""),
|
"channel_id": item.get("channelId", ""),
|
||||||
|
"source": "CloudSaver"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return clean_results
|
return clean_results
|
||||||
|
|||||||
96
app/sdk/pansou.py
Normal file
96
app/sdk/pansou.py
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
import re
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
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:
|
||||||
|
utc_tm = datetime.strptime(tm, "%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
tm = (utc_tm + timedelta(hours=8)).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>
|
</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>
|
||||||
|
|
||||||
<div v-if="activeTab === 'tasklist'">
|
<div v-if="activeTab === 'tasklist'">
|
||||||
@ -281,12 +296,14 @@
|
|||||||
<div class="input-group">
|
<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)">
|
<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-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">
|
<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 }}
|
<span v-html="suggestion.verify ? '✅': '❔'"></span> {{ suggestion.taskname }}
|
||||||
<small class="text-muted">
|
<small class="text-muted">
|
||||||
<a :href="suggestion.shareurl" target="_blank" @click.stop>{{ suggestion.shareurl }}</a>
|
<a :href="suggestion.shareurl" target="_blank" @click.stop>{{ suggestion.shareurl }}</a>
|
||||||
</small>
|
</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>
|
</div>
|
||||||
<div class="input-group-append" title="深度搜索">
|
<div class="input-group-append" title="深度搜索">
|
||||||
@ -542,6 +559,9 @@
|
|||||||
username: "",
|
username: "",
|
||||||
password: "",
|
password: "",
|
||||||
token: ""
|
token: ""
|
||||||
|
},
|
||||||
|
pansou: {
|
||||||
|
server: ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -676,6 +696,11 @@
|
|||||||
token: ""
|
token: ""
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (!config_data.source.pansou) {
|
||||||
|
config_data.source.pansou = {
|
||||||
|
server: ""
|
||||||
|
};
|
||||||
|
}
|
||||||
this.formData = config_data;
|
this.formData = config_data;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.configModified = false;
|
this.configModified = false;
|
||||||
@ -930,6 +955,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
searchSuggestions(index, taskname, deep = 1) {
|
searchSuggestions(index, taskname, deep = 1) {
|
||||||
|
taskname = taskname.replace(/\((19|20)\d{2}\)/g, '').trim();
|
||||||
if (taskname.length < 2) {
|
if (taskname.length < 2) {
|
||||||
console.log(`任务名[${taskname}]过短${taskname.length} 不进行搜索`);
|
console.log(`任务名[${taskname}]过短${taskname.length} 不进行搜索`);
|
||||||
return;
|
return;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user