新增爬虫规则创建
新增爬虫规则 时可指定默认的规则内容
This commit is contained in:
@@ -194,4 +194,67 @@ class ProxyController extends BaseController {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建规则文件并填充默认内容
|
||||
* 访问URL: index.php/Proxy/createRuleFile (POST请求)
|
||||
*/
|
||||
public function createRuleFileAction() {
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$relativePath = $_POST['relativePath'] ?? null;
|
||||
$apiName = $_POST['apiName'] ?? null;
|
||||
$customContent = $_POST['customContent'] ?? null;
|
||||
|
||||
$saveAsDefault = !empty($_POST['saveAsDefault']) && $_POST['saveAsDefault'] !== 'false';
|
||||
|
||||
if (!$relativePath || !$apiName) {
|
||||
$this->ajaxReturn(['success' => false, 'message' => '缺少必要的参数']);
|
||||
}
|
||||
|
||||
$targetPath = $this->baseSaveDir . sanitize_path($relativePath);
|
||||
$targetDir = dirname($targetPath);
|
||||
|
||||
if (file_exists($targetPath)) {
|
||||
// $this->ajaxReturn(['success' => false, 'message' => '文件已存在,无法创建']);
|
||||
}
|
||||
|
||||
if (!is_dir($targetDir)) {
|
||||
if (!mkdir($targetDir, 0755, true)) {
|
||||
$this->ajaxReturn(['success' => false, 'message' => '创建目录失败,请检查 /box 目录权限']);
|
||||
}
|
||||
}
|
||||
|
||||
$finalContent = '';
|
||||
if (!empty($customContent)) {
|
||||
$finalContent = $customContent;
|
||||
} else {
|
||||
$templatePath = ROOT_PATH . '/Json/' . $apiName . '.json';
|
||||
if (file_exists($templatePath)) {
|
||||
$finalContent = file_get_contents($templatePath);
|
||||
} else {
|
||||
$this->ajaxReturn([
|
||||
'success' => false,
|
||||
'message' => "默认模板 Json/{$apiName}.json 未找到。请点击“内容”按钮设置默认内容,或在服务器Json目录下手动创建该文件。"
|
||||
]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (file_put_contents($targetPath, $finalContent) === false) {
|
||||
$this->ajaxReturn(['success' => false, 'message' => '规则文件写入失败']);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($saveAsDefault && !empty($customContent)) {
|
||||
$defaultTemplatePath = ROOT_PATH . '/Json/' . $apiName . '.json';
|
||||
$defaultTemplateDir = dirname($defaultTemplatePath);
|
||||
if (!is_dir($defaultTemplateDir)) {
|
||||
mkdir($defaultTemplateDir, 0755, true);
|
||||
}
|
||||
file_put_contents($defaultTemplatePath, $customContent);
|
||||
}
|
||||
|
||||
$this->ajaxReturn(['success' => true, 'message' => '规则文件创建成功']);
|
||||
}
|
||||
}
|
||||
|
||||
+35
-14
@@ -70,21 +70,42 @@
|
||||
|
||||
<script id="add-site-modal-template" type="text/x-handlebars-template">
|
||||
<div id="create-spider-form-modal" class="details-panel create-panel active" style="max-height:none; opacity:1; padding:0; background:none;">
|
||||
<div class="form-group"><label for="new-site-name-modal">规则名称</label><input id="new-site-name-modal" type="text" placeholder="例如:酷云影视"></div>
|
||||
<div class="form-group"><label for="new-site-key-modal">唯一标识</label><input id="new-site-key-modal" type="text" placeholder="例如:ky_m"></div>
|
||||
<div class="form-group" style="grid-column: 1 / -1;"><label for="new-site-ext-modal">规则链接</label><input id="new-site-ext-modal" type="text" placeholder="http://.../rule.json"></div>
|
||||
<div class="form-group"><label for="new-site-api-modal">爬虫接口</label><input id="new-site-api-modal" type="text" value="csp_XYQHiker"></div>
|
||||
<div class="form-group"><label for="new-site-type-modal">类型</label><select id="new-site-type-modal"><option value="1">1 (csp)</option><option value="0">0 (vod)</option><option value="2">2</option><option value="3" selected>3</option></select></div>
|
||||
<div class="form-group"><label for="new-site-jar-modal">Jar文件</label><input id="new-site-jar-modal" type="text" placeholder="例如:./libs/Panda.jar"></div>
|
||||
<div class="form-group checkbox-group">
|
||||
<input type="checkbox" id="new-site-searchable-modal" style="width: auto;" checked>
|
||||
<label>可搜索</label>
|
||||
<input type="checkbox" id="new-site-filterable-modal" style="width: auto;" checked>
|
||||
<label>可筛选</label>
|
||||
<input type="checkbox" id="new-site-quick-modal" style="width: auto;" checked>
|
||||
<label>快速搜索</label>
|
||||
</div>
|
||||
<div class="details-form-grid">
|
||||
<div class="form-group"><label for="new-site-name-modal">规则名称</label><input id="new-site-name-modal" type="text" placeholder="例如:酷云影视"></div>
|
||||
<div class="form-group"><label for="new-site-key-modal">唯一标识</label><input id="new-site-key-modal" type="text" placeholder="例如:ky_m"></div>
|
||||
|
||||
<div class="form-group" style="grid-column: 1 / -1;">
|
||||
<label for="new-site-ext-modal">规则链接</label>
|
||||
<div class="input-with-buttons">
|
||||
<input id="new-site-ext-modal" type="text" placeholder="./some/path/rule.json">
|
||||
<button type="button" id="toggle-custom-content-btn" class="btn btn-sm secondary-btn">内容</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="custom-content-wrapper" style="display: none; grid-column: 1 / -1;">
|
||||
<div class="form-group">
|
||||
<label for="new-site-custom-content-modal">自定义规则内容 (留空则使用默认模板)</label>
|
||||
<textarea id="new-site-custom-content-modal" rows="5"></textarea>
|
||||
</div>
|
||||
<div class="form-group checkbox-group">
|
||||
<input type="checkbox" id="save-as-default-toggle-modal" style="width: auto;">
|
||||
<label for="save-as-default-toggle-modal">将以上内容保存为该接口的默认模板</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group"><label for="new-site-api-modal">爬虫接口</label><input id="new-site-api-modal" type="text" value="csp_XYQHiker"></div>
|
||||
<div class="form-group"><label for="new-site-type-modal">类型</label><select id="new-site-type-modal"><option value="1">1 (csp)</option><option value="0">0 (vod)</option><option value="2">2</option><option value="3" selected>3</option></select></div>
|
||||
<div class="form-group"><label for="new-site-jar-modal">Jar文件</label><input id="new-site-jar-modal" type="text" placeholder="例如:./libs/Panda.jar"></div>
|
||||
|
||||
<div class="form-group checkbox-group">
|
||||
<input type="checkbox" id="new-site-searchable-modal" style="width: auto;" checked>
|
||||
<label>可搜索</label>
|
||||
<input type="checkbox" id="new-site-filterable-modal" style="width: auto;" checked>
|
||||
<label>可筛选</label>
|
||||
<input type="checkbox" id="new-site-quick-modal" style="width: auto;" checked>
|
||||
<label>快速搜索</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
||||
+109
-7
@@ -15,6 +15,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
let downloadStatus = {};
|
||||
let currentEditInfo = {};
|
||||
let rawJsonContent = '';
|
||||
let currentConfigBaseDir = '';
|
||||
const defaultJsonUrl = 'https://raw.githubusercontent.com/liu673cn/box/refs/heads/main/m.json';
|
||||
|
||||
/**
|
||||
@@ -190,6 +191,20 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
showToast('请输入有效的JSON链接地址。', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// --- 核心改动:解析并存储当前配置的基础目录 ---
|
||||
if (url.includes('/box/')) {
|
||||
const pathAfterBox = url.split('/box/')[1];
|
||||
const lastSlashIndex = pathAfterBox.lastIndexOf('/');
|
||||
if (lastSlashIndex !== -1) {
|
||||
currentConfigBaseDir = pathAfterBox.substring(0, lastSlashIndex + 1);
|
||||
} else {
|
||||
currentConfigBaseDir = '';
|
||||
}
|
||||
} else {
|
||||
currentConfigBaseDir = '';
|
||||
}
|
||||
|
||||
loadingDiv.style.display = 'block';
|
||||
rawJsonContent = '';
|
||||
const proxyUrl = `index.php/Proxy/load?target_url=${encodeURIComponent(url)}`;
|
||||
@@ -649,9 +664,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 添加新的爬虫规则 (适配弹窗)
|
||||
* @description 添加新的爬虫规则
|
||||
*/
|
||||
function addSpider() {
|
||||
async function addSpider() {
|
||||
const newSite = {
|
||||
key: document.getElementById('new-site-key-modal').value.trim(),
|
||||
name: document.getElementById('new-site-name-modal').value.trim(),
|
||||
@@ -668,6 +683,40 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
showToast('规则名称和唯一标识不能为空!', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (newSite.ext.startsWith('./') && newSite.ext.endsWith('.json')) {
|
||||
const customContent = document.getElementById('new-site-custom-content-modal').value;
|
||||
const saveAsDefault = document.getElementById('save-as-default-toggle-modal').checked;
|
||||
|
||||
// --- 核心改动:拼接基础目录和相对路径 ---
|
||||
const pathFromInput = newSite.ext.substring(2); // 去掉 './'
|
||||
const finalRelativePath = currentConfigBaseDir + pathFromInput;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('relativePath', finalRelativePath);
|
||||
formData.append('apiName', newSite.api);
|
||||
formData.append('customContent', customContent);
|
||||
formData.append('saveAsDefault', saveAsDefault);
|
||||
|
||||
try {
|
||||
showToast('正在创建规则文件...', 'info');
|
||||
const response = await fetch('index.php/Proxy/createRuleFile', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.message);
|
||||
}
|
||||
showToast(result.message, 'success');
|
||||
|
||||
} catch (error) {
|
||||
showToast(`文件创建失败: ${error.message}`, 'error');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentRulesData.sites) currentRulesData.sites = [];
|
||||
currentRulesData.sites.unshift(newSite);
|
||||
renderSitesTab(currentRulesData.sites);
|
||||
@@ -1118,7 +1167,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
document.getElementById('column-select').addEventListener('change', updateGridColumns);
|
||||
localFileInput.addEventListener('change', loadAndRenderRulesFromFile);
|
||||
|
||||
document.body.addEventListener('click', async (e) => {
|
||||
document.body.addEventListener('click', async (e) => {
|
||||
if (e.target.id === 'add-spider-btn-modal') addSpider();
|
||||
if (e.target.id === 'add-parse-btn-modal') addParse();
|
||||
if (e.target.id === 'add-filter-btn-modal') addFilterRule();
|
||||
@@ -1154,6 +1203,23 @@ document.body.addEventListener('click', async (e) => {
|
||||
applySiteFilter(siteFilterBtn);
|
||||
}
|
||||
|
||||
if (e.target.id === 'toggle-custom-content-btn') {
|
||||
const ruleLinkInput = document.getElementById('new-site-ext-modal');
|
||||
const ruleLinkValue = ruleLinkInput ? ruleLinkInput.value.trim() : '';
|
||||
|
||||
if (ruleLinkValue.startsWith('http://') || ruleLinkValue.startsWith('https://')) {
|
||||
showToast('“内容”功能仅适用于创建本地相对路径规则文件。', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
const wrapper = document.getElementById('custom-content-wrapper');
|
||||
if (wrapper) {
|
||||
const isHidden = wrapper.style.display === 'none';
|
||||
wrapper.style.display = isHidden ? 'block' : 'none';
|
||||
e.target.textContent = isHidden ? '收起' : '内容';
|
||||
}
|
||||
}
|
||||
|
||||
const deleteAllBtn = e.target.closest('.delete-all-btn');
|
||||
if (deleteAllBtn) {
|
||||
const itemType = deleteAllBtn.dataset.itemType;
|
||||
@@ -1194,12 +1260,48 @@ document.body.addEventListener('click', async (e) => {
|
||||
const createNewBtn = e.target.closest('.create-new-btn');
|
||||
if (createNewBtn) {
|
||||
const itemType = createNewBtn.dataset.itemType;
|
||||
if (itemType === 'sites') addSiteModal.open();
|
||||
if (itemType === 'parses') addParseModal.open();
|
||||
if (itemType === 'rules') addFilterModal.open();
|
||||
if (itemType === 'sites') {
|
||||
const apiInput = document.getElementById('new-site-api-modal');
|
||||
const label = document.querySelector('#add-site-modal label[for="save-as-default-toggle-modal"]');
|
||||
if(apiInput && label) {
|
||||
const apiName = apiInput.value.trim();
|
||||
if (apiName) {
|
||||
label.textContent = `将以上内容保存为 ${apiName} 的默认模板`;
|
||||
} else {
|
||||
label.textContent = '将以上内容保存为该接口的默认模板';
|
||||
}
|
||||
}
|
||||
addSiteModal.open();
|
||||
|
||||
} else if (itemType === 'parses') {
|
||||
addParseModal.open();
|
||||
} else if (itemType === 'rules') {
|
||||
addFilterModal.open();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @description 为“新增爬虫规则”弹窗添加动态交互
|
||||
*/
|
||||
const addSiteModalElement = document.getElementById('add-site-modal');
|
||||
if (addSiteModalElement) {
|
||||
// 使用事件委托,监听弹窗内部的输入事件
|
||||
addSiteModalElement.addEventListener('input', (e) => {
|
||||
if (e.target.id === 'new-site-api-modal') {
|
||||
const apiName = e.target.value.trim();
|
||||
const label = addSiteModalElement.querySelector('label[for="save-as-default-toggle-modal"]');
|
||||
if (label) {
|
||||
if (apiName) {
|
||||
label.textContent = `将以上内容保存为 ${apiName} 的默认模板`;
|
||||
} else {
|
||||
label.textContent = '将以上内容保存为该接口的默认模板';
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadAndRenderRulesFromUrl();
|
||||
updateGridColumns();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user