mirror of
https://github.com/nianzhibai/91.git
synced 2026-06-15 00:44:30 +08:00
fix admin video batch delete and spider91 form
This commit is contained in:
@@ -152,15 +152,16 @@ export function VideosPage() {
|
||||
if (ids.length === 0) return;
|
||||
setBatchDeleting(true);
|
||||
try {
|
||||
const results = await Promise.allSettled(
|
||||
ids.map((id) => api.deleteVideo(id))
|
||||
);
|
||||
let success = 0;
|
||||
let deletedSources = 0;
|
||||
for (const r of results) {
|
||||
if (r.status !== "fulfilled") continue;
|
||||
success++;
|
||||
if (r.value.deletedSource) deletedSources++;
|
||||
for (const id of ids) {
|
||||
try {
|
||||
const result = await api.deleteVideo(id);
|
||||
success++;
|
||||
if (result.deletedSource) deletedSources++;
|
||||
} catch {
|
||||
// Keep deleting the rest of the selected videos; report aggregate failure below.
|
||||
}
|
||||
}
|
||||
const failed = ids.length - success;
|
||||
if (failed === 0) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useId } from "react";
|
||||
import { ChevronDown } from "lucide-react";
|
||||
import { kindLabel } from "./constants";
|
||||
import * as api from "../api";
|
||||
|
||||
@@ -16,16 +17,21 @@ export function Spider91UploadTargetField({
|
||||
return (
|
||||
<div className="admin-form__row">
|
||||
<label htmlFor={targetId}>视频上传目标</label>
|
||||
<select id={targetId} value={value} onChange={(e) => onChange(e.target.value)}>
|
||||
<option value="">本地保存,不上传</option>
|
||||
{uploadTargets.map((d) => (
|
||||
<option key={d.id} value={d.id}>
|
||||
{kindLabel[d.kind] ?? d.kind} · {d.name || d.id}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<div className="admin-form__help">
|
||||
选择本地保存时,爬取视频只保存在服务器本地;选择 115 网盘、123 云盘、PikPak 或 OneDrive 后,较早的视频会上传到该云盘根目录下的 91 Spider 文件夹。该设置全局生效。
|
||||
<div className="admin-form-select-wrap">
|
||||
<select
|
||||
id={targetId}
|
||||
className="admin-form-select"
|
||||
value={value}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
>
|
||||
<option value="">本地保存,不上传</option>
|
||||
{uploadTargets.map((d) => (
|
||||
<option key={d.id} value={d.id}>
|
||||
{kindLabel[d.kind] ?? d.kind} · {d.name || d.id}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<ChevronDown size={15} className="admin-form-select__icon" aria-hidden="true" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -264,7 +264,7 @@ export function credentialFields(kind: Kind): Array<{
|
||||
key: "proxy",
|
||||
label: "代理地址(可选)",
|
||||
placeholder: "http://127.0.0.1:7890",
|
||||
help: "仅用于 91Spider 的列表/详情请求和视频、封面下载;留空则使用服务器环境变量 HTTP_PROXY / HTTPS_PROXY 或直连。支持 http://、https://、socks5:// 或 socks5h://。",
|
||||
help: "支持 http://、https://、socks5://、socks5h://代理",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@@ -404,6 +404,39 @@
|
||||
color: var(--text-strong);
|
||||
}
|
||||
|
||||
.admin-form-select-wrap {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.admin-form__row .admin-form-select {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
width: 100%;
|
||||
min-height: 40px;
|
||||
padding-right: 36px;
|
||||
line-height: 1.2;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.admin-form__row .admin-form-select::-ms-expand {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.admin-form-select__icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 12px;
|
||||
transform: translateY(-50%);
|
||||
color: var(--text-faint);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.admin-form-select:focus + .admin-form-select__icon {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.admin-form__row--inline {
|
||||
display: flex;
|
||||
gap: var(--space-2);
|
||||
|
||||
@@ -10,10 +10,18 @@ const driveComponentsSource = readFileSync(
|
||||
new URL("../src/admin/drive/DriveComponents.tsx", import.meta.url),
|
||||
"utf8"
|
||||
);
|
||||
const spider91UploadTargetSource = readFileSync(
|
||||
new URL("../src/admin/drive/Spider91UploadTargetField.tsx", import.meta.url),
|
||||
"utf8"
|
||||
);
|
||||
const driveFormSource = readFileSync(
|
||||
new URL("../src/admin/drive/DriveForm.tsx", import.meta.url),
|
||||
"utf8"
|
||||
);
|
||||
const adminCss = readFileSync(
|
||||
new URL("../src/styles/admin.css", import.meta.url),
|
||||
"utf8"
|
||||
);
|
||||
const apiSource = readFileSync(
|
||||
new URL("../src/admin/api.ts", import.meta.url),
|
||||
"utf8"
|
||||
@@ -23,10 +31,7 @@ const constantsSource = readFileSync(
|
||||
"utf8"
|
||||
);
|
||||
|
||||
const combinedSource = drivesPageSource + "\n" + driveFormSource + "\n" + constantsSource + "\n" + readFileSync(
|
||||
new URL("../src/admin/drive/Spider91UploadTargetField.tsx", import.meta.url),
|
||||
"utf8"
|
||||
);
|
||||
const combinedSource = drivesPageSource + "\n" + driveFormSource + "\n" + constantsSource + "\n" + spider91UploadTargetSource;
|
||||
|
||||
function driveTypeOptions() {
|
||||
const match = /const DRIVE_OPTIONS:\s*DriveOption\[]\s*=\s*\[([\s\S]*?)\];/.exec(
|
||||
@@ -49,7 +54,7 @@ function assertDriveTypeOption(value: string, label: string) {
|
||||
test("spider91 drive form does not expose advanced crawler credentials", () => {
|
||||
assert.match(combinedSource, /key: "proxy"/);
|
||||
assert.match(combinedSource, /label: "代理地址(可选)"/);
|
||||
assert.match(combinedSource, /支持 http:\/\/、https:\/\/、socks5:\/\/ 或 socks5h:\/\//);
|
||||
assert.match(combinedSource, /支持 http:\/\/、https:\/\/、socks5:\/\/、socks5h:\/\/代理/);
|
||||
assert.doesNotMatch(combinedSource, /target_new/);
|
||||
assert.doesNotMatch(combinedSource, /crawl_hour/);
|
||||
assert.doesNotMatch(combinedSource, /python_path/);
|
||||
@@ -64,6 +69,18 @@ test("spider91 upload target uses explicit local-save option instead of auto tar
|
||||
);
|
||||
assert.doesNotMatch(combinedSource, /自动:唯一/);
|
||||
assert.doesNotMatch(combinedSource, /自动模式/);
|
||||
assert.doesNotMatch(combinedSource, /较早的视频会上传到该云盘根目录下的 91 Spider 文件夹/);
|
||||
});
|
||||
|
||||
test("spider91 upload target select uses an aligned custom arrow", () => {
|
||||
assert.match(spider91UploadTargetSource, /className="admin-form-select-wrap"/);
|
||||
assert.match(spider91UploadTargetSource, /className="admin-form-select"/);
|
||||
assert.match(spider91UploadTargetSource, /className="admin-form-select__icon"/);
|
||||
assert.match(adminCss, /\.admin-form__row \.admin-form-select\s*\{[^}]*appearance\s*:\s*none/s);
|
||||
assert.match(
|
||||
adminCss,
|
||||
/\.admin-form-select__icon\s*\{[^}]*top\s*:\s*50%[^}]*right\s*:\s*12px[^}]*transform\s*:\s*translateY\(-50%\)/s
|
||||
);
|
||||
});
|
||||
|
||||
test("drive form hides root directory id for localstorage and spider91", () => {
|
||||
|
||||
@@ -11,3 +11,12 @@ test("admin videos page uses responsive page size", () => {
|
||||
assert.match(videosPageSource, /window\.matchMedia\(VIDEOS_MOBILE_QUERY\)/);
|
||||
assert.match(videosPageSource, /api\.listVideos\(\{ driveId, page, size: pageSize, keyword: searchKeyword \}\)/);
|
||||
});
|
||||
|
||||
test("admin videos batch delete runs deletions sequentially", () => {
|
||||
assert.match(videosPageSource, /for \(const id of ids\) \{/);
|
||||
assert.match(videosPageSource, /const result = await api\.deleteVideo\(id\);/);
|
||||
assert.doesNotMatch(
|
||||
videosPageSource,
|
||||
/Promise\.allSettled\(\s*ids\.map\(\(id\) => api\.deleteVideo\(id\)\)\s*\)/
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user