Compare commits
10
Commits
c64c9479a9
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35dcc24096 | ||
|
|
4c4de7a5cb | ||
|
|
cb67026821 | ||
|
|
93dcffc983 | ||
|
|
837bd4df76 | ||
|
|
26e1690f84 | ||
|
|
bd88ca76de | ||
|
|
912eebddee | ||
|
|
6cbacab98b | ||
|
|
f7539a33b0 |
+6
-5
@@ -2,7 +2,7 @@ from flask import Flask
|
||||
from flask_cors import CORS
|
||||
from .extensions import db, migrate
|
||||
from .config import DevelopmentConfig, ProductionConfig, TestingConfig
|
||||
from .blueprints import torrent_bp, book_bp, music_bp, file_bp, video_bp, image_bp
|
||||
from .blueprints import torrent_bp, book_bp, music_bp, file_bp, video_bp, image_bp, asmr_bp
|
||||
|
||||
|
||||
def create_app(config_name="development"):
|
||||
@@ -10,14 +10,14 @@ def create_app(config_name="development"):
|
||||
CORS(app)
|
||||
app.config.from_object(DevelopmentConfig)
|
||||
|
||||
match config_name:
|
||||
case 'production':
|
||||
if config_name == 'production':
|
||||
app.config.from_object(ProductionConfig)
|
||||
case 'testing':
|
||||
elif config_name == 'testing':
|
||||
app.config.from_object(TestingConfig)
|
||||
case _:
|
||||
else:
|
||||
app.config.from_object(DevelopmentConfig)
|
||||
|
||||
|
||||
db.init_app(app)
|
||||
migrate.init_app(app, db)
|
||||
|
||||
@@ -27,5 +27,6 @@ def create_app(config_name="development"):
|
||||
app.register_blueprint(file_bp.bp, url_prefix='/api/file')
|
||||
app.register_blueprint(video_bp.bp, url_prefix='/api/video')
|
||||
app.register_blueprint(image_bp.bp, url_prefix='/api/image')
|
||||
app.register_blueprint(asmr_bp.bp, url_prefix='/api/asmr')
|
||||
|
||||
return app
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
from flask import Blueprint, Response, jsonify
|
||||
|
||||
from app.services.asmr_service import AsmrService
|
||||
|
||||
bp = Blueprint("asmr", __name__)
|
||||
|
||||
|
||||
@bp.route("/")
|
||||
def index():
|
||||
asmr_object = AsmrService()
|
||||
return jsonify({"code": 200, "message": asmr_object.get_all()})
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
import os
|
||||
|
||||
IGNORE_DIRS = {
|
||||
"System Volume Information",
|
||||
"$RECYCLE.BIN",
|
||||
@@ -8,7 +9,7 @@ IGNORE_DIRS = {
|
||||
"done_images",
|
||||
"女同"
|
||||
}
|
||||
SPECIAL_PREFIXES = {"T28", "FC2"}
|
||||
SPECIAL_PREFIXES = {"T28", "FC2", "T38"}
|
||||
SEPARATORS = {"♀ ", "♀ ", "+"}
|
||||
SPECIAL_DIRS = {"川村まや", "上原亜衣", "上原志織"}
|
||||
IMAGE_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.webp', '.svg'}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import requests
|
||||
|
||||
class AsmrService:
|
||||
API_URL = "https://www.asmrgay.com/api/fs/list"
|
||||
base_params = {
|
||||
"path": "/asmr/中文音声",
|
||||
"password": "",
|
||||
"per_page": 30,
|
||||
"refresh": False
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def get_all(self):
|
||||
return [self.API_URL]
|
||||
@@ -11,7 +11,7 @@ from app.models import Setting
|
||||
|
||||
class BookService:
|
||||
ALLOWED_CONTENT_TYPES = ['"application/octet-stream"', "application/octet-stream", "text/plain",
|
||||
"application/zip"]
|
||||
"application/zip", "application/vnd.rar"]
|
||||
|
||||
def __init__(self):
|
||||
setting_record = Setting.query.filter_by(name="book_download").first()
|
||||
@@ -51,6 +51,7 @@ class BookService:
|
||||
@staticmethod
|
||||
def legitimate_naming(name: str) -> str:
|
||||
"""将文件名中的非法字符替换为合法字符"""
|
||||
name = name.rstrip(" .")
|
||||
replacements = {":": ":", "<": "《", ">": "》", "/": " ", "\\": " ", "?": "?"}
|
||||
for old, new in replacements.items():
|
||||
name = name.replace(old, new)
|
||||
@@ -64,12 +65,18 @@ class BookService:
|
||||
return target
|
||||
|
||||
def post_page(self, name, url): # 帖子页面
|
||||
print(f"详情页面 {self.setting["baseUrl"]}{url}")
|
||||
response = self.session.get(f"{self.setting["baseUrl"]}{url}")
|
||||
full_url = f"{self.setting['baseUrl']}{url}"
|
||||
try:
|
||||
response = self.session.get(full_url)
|
||||
response.raise_for_status()
|
||||
print(f"详情页面状态码:{str(response.status_code)}")
|
||||
except requests.RequestException as e:
|
||||
yield f"event: error\ndata: 请求帖子详情失败 {url}: {str(e)}\n\n"
|
||||
return
|
||||
print(f"详情页面 {str(response.status_code)} {full_url}")
|
||||
|
||||
soup = BeautifulSoup(response.text, 'lxml')
|
||||
resource_boxs = soup.select('ignore_js_op')
|
||||
|
||||
for i in resource_boxs:
|
||||
download_dir_path = self.download_path / self.setting["targetDate"]
|
||||
self.create_folder(download_dir_path, name)
|
||||
@@ -81,8 +88,7 @@ class BookService:
|
||||
if privilege_level > self.setting["privilegeLevel"]:
|
||||
print("下载失败,权限等级不够")
|
||||
return
|
||||
yield from self.download_file(f"{self.setting["baseUrl"]}{i.select_one(
|
||||
'a')['href']}", name, i.select_one('a').string)
|
||||
yield from self.download_file(f"{self.setting['baseUrl']}{i.select_one('a')['href']}", name, i.select_one('a').string)
|
||||
# yield from self.download_file(f"{self.setting["baseUrl"]}{i.select_one(
|
||||
# 'a')['href']}", name, self.legitimate_naming(i.select_one('a').string))
|
||||
except RetryError as e:
|
||||
@@ -97,10 +103,12 @@ class BookService:
|
||||
print(f'跳转页面了:{file_url}')
|
||||
response = self.session.get(file_url, headers={"referer": file_url}, stream=True)
|
||||
print(f"下载状态码:{response.status_code} {file_url}")
|
||||
response.raise_for_status()
|
||||
print(dir_name + "/" + file_name)
|
||||
content_type = response.headers.get('Content-Type', '')
|
||||
if content_type not in self.ALLOWED_CONTENT_TYPES:
|
||||
yield f"event: mes_error\ndata: {self.setting["targetDate"]} {file_name}\n\n"
|
||||
yield f"event: mes_error\ndata: {self.setting['targetDate']} {file_name}\n\n"
|
||||
print(content_type)
|
||||
print("不是可下载文件")
|
||||
return
|
||||
target_dir = self.download_path / self.setting["targetDate"] / dir_name / file_name
|
||||
@@ -109,7 +117,7 @@ class BookService:
|
||||
for chunk in response.iter_content(chunk_size=1024):
|
||||
if chunk:
|
||||
f.write(chunk)
|
||||
yield f"data: {self.setting["targetDate"]} {file_name}\n\n"
|
||||
yield f"data: {self.setting['targetDate']} {file_name}\n\n"
|
||||
except requests.RequestException as e:
|
||||
yield f"event: error\ndata: {self.setting['targetDate']} {file_name} 网络错误\n\n"
|
||||
raise # 触发 tenacity 重试
|
||||
@@ -122,7 +130,7 @@ class BookService:
|
||||
yield f"data: 不允许下载当天的\n\n"
|
||||
return None
|
||||
# yield f"data: 当前页面 {page}\n\n"
|
||||
url = f"{self.setting["baseUrl"]}forum.php?mod={self.setting["mod"]}&fid={self.setting["fid"]}&page={page}" # 版块页面地址
|
||||
url = f"{self.setting['baseUrl']}forum.php?mod={self.setting['mod']}&fid={self.setting['fid']}&page={page}" # 版块页面地址
|
||||
response = self.session.get(url) # 请求
|
||||
response.raise_for_status()
|
||||
soup = BeautifulSoup(response.text, 'lxml') # 解析
|
||||
@@ -193,6 +201,9 @@ class BookService:
|
||||
else:
|
||||
return element.select_one(".by em span").string
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# 下载
|
||||
# ------------------------------------------------------------
|
||||
def book_download(self):
|
||||
print(os.getenv('aa'))
|
||||
self.create_folder(self.download_path, self.setting["targetDate"]) # 创建文件夹
|
||||
|
||||
@@ -16,7 +16,10 @@ class FileService:
|
||||
return None
|
||||
|
||||
new_path = os.path.join(os.path.dirname(entry.path), new_name)
|
||||
try:
|
||||
os.rename(entry.path, new_path)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
self.result_list.insert(0, new_path)
|
||||
# return new_path
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import os
|
||||
from typing import Optional, Callable, List
|
||||
from typing import Optional, Callable, List, Union
|
||||
|
||||
|
||||
class FolderService:
|
||||
def __init__(
|
||||
self,
|
||||
paths: List[str] | str,
|
||||
paths: Union[List[str], str],
|
||||
ignore_dirs: Optional[set] = None,
|
||||
folder_callback: Optional[Callable] = None,
|
||||
file_callback: Optional[Callable] = None,
|
||||
|
||||
@@ -67,3 +67,9 @@ export function torrent_statistics(): ResponseData {
|
||||
url: "/torrent/statistics",
|
||||
})
|
||||
}
|
||||
|
||||
export function asmr(): ResponseData {
|
||||
return request({
|
||||
url: "/asmr/",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,26 +10,32 @@ const {isCollapse} = storeToRefs(isCollapseStore)
|
||||
<template>
|
||||
<el-aside :width="!isCollapse?'200px':'auto'">
|
||||
<el-scrollbar>
|
||||
<el-menu default-active="2" :collapse="isCollapse" router>
|
||||
<el-menu-item index="1" route="index">
|
||||
<el-menu :default-active="$route.path" :collapse="isCollapse" router>
|
||||
<el-menu-item index="/index" route="index">
|
||||
<el-icon>
|
||||
<Menu/>
|
||||
</el-icon>
|
||||
<span>首页</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="2" route="about">
|
||||
<el-menu-item index="/about" route="about">
|
||||
<el-icon>
|
||||
<Menu/>
|
||||
</el-icon>
|
||||
<span>统计</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="3" disabled>
|
||||
<el-menu-item index="/byte-to-hex" route="byte-to-hex">
|
||||
<el-icon>
|
||||
<Menu/>
|
||||
</el-icon>
|
||||
<span>字节对象转Hex</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="4" disabled>
|
||||
<el-icon>
|
||||
<document/>
|
||||
</el-icon>
|
||||
<span>Navigator Three</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="4">
|
||||
<el-menu-item index="5">
|
||||
<el-icon>
|
||||
<setting/>
|
||||
</el-icon>
|
||||
|
||||
@@ -19,6 +19,11 @@ const router = createRouter({
|
||||
name: 'About',
|
||||
component: () => import('../views/AboutView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'byte-to-hex',
|
||||
name: 'ByteToHex',
|
||||
component: () => import('../views/ByteToHexView.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -23,9 +23,9 @@ interface RequestCache {
|
||||
axios.defaults.headers["Content-Type"] = "application/json; charset=UTF-8"
|
||||
|
||||
const service: AxiosInstance = axios.create({
|
||||
baseURL: "http://192.168.1.32:5000/api/",
|
||||
baseURL: "http://43.159.32.210:5000/api/",
|
||||
// baseURL: "/api",
|
||||
timeout: 10000,
|
||||
timeout: 30000,
|
||||
})
|
||||
|
||||
service.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
||||
|
||||
@@ -0,0 +1,380 @@
|
||||
<template>
|
||||
<el-main>
|
||||
<el-card>
|
||||
|
||||
<h1>🔑 字节对象 → Hex 密钥</h1>
|
||||
<p class="sub">
|
||||
将键为数字索引的 JSON 对象转换为 32 位十六进制字符串(适用于 AES‑128 密钥)
|
||||
</p>
|
||||
|
||||
<label for="jsonInput">输入 JSON 对象</label>
|
||||
<textarea
|
||||
id="jsonInput"
|
||||
v-model="inputText"
|
||||
placeholder='例如:{"0":14,"1":3,"2":121,...}'
|
||||
@keydown.ctrl.enter="performConversion"
|
||||
@keydown.meta.enter="performConversion"
|
||||
></textarea>
|
||||
|
||||
<div class="actions">
|
||||
<button @click="performConversion">🔄 转换</button>
|
||||
<button class="secondary" :disabled="!copyEnabled" @click="copyResult">
|
||||
📋 复制 Hex
|
||||
</button>
|
||||
<span class="copy-feedback" :class="{ show: copyFeedbackVisible }"
|
||||
>已复制!</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="result-area">
|
||||
<div class="result-label">
|
||||
<span>转换结果</span>
|
||||
</div>
|
||||
<div
|
||||
class="result-box"
|
||||
:class="resultClass"
|
||||
v-text="resultText"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<div class="example-hint">
|
||||
💡 点击
|
||||
<button class="link-btn" @click="loadExample">加载示例</button>
|
||||
快速体验
|
||||
</div>
|
||||
</el-card>
|
||||
</el-main>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {ref, onMounted} from 'vue'
|
||||
|
||||
// 示例数据
|
||||
const EXAMPLE_OBJ: Record<string, number> = {
|
||||
'0': 14,
|
||||
'1': 3,
|
||||
'2': 121,
|
||||
'3': 117,
|
||||
'4': 7,
|
||||
'5': 245,
|
||||
'6': 22,
|
||||
'7': 34,
|
||||
'8': 136,
|
||||
'9': 163,
|
||||
'10': 201,
|
||||
'11': 114,
|
||||
'12': 195,
|
||||
'13': 230,
|
||||
'14': 109,
|
||||
'15': 204,
|
||||
}
|
||||
|
||||
// 响应式数据
|
||||
const inputText = ref<string>('')
|
||||
const resultText = ref<string>('等待转换…')
|
||||
const resultClass = ref<string>('') // 用于 success / error
|
||||
const copyFeedbackVisible = ref<boolean>(false)
|
||||
const copyEnabled = ref<boolean>(false)
|
||||
|
||||
// 核心转换函数
|
||||
function convertToHex(obj: Record<string, unknown>): string {
|
||||
// 获取所有键并转为数字排序
|
||||
const keys = Object.keys(obj)
|
||||
.map((k) => Number(k))
|
||||
.sort((a, b) => a - b)
|
||||
|
||||
// 检查是否有非数字键
|
||||
if (keys.some((k) => isNaN(k))) {
|
||||
throw new Error('对象包含非数字键,请确保键为 "0", "1", … 格式')
|
||||
}
|
||||
|
||||
// 检查长度是否为16
|
||||
if (keys.length !== 16) {
|
||||
throw new Error(`期望 16 个字节,实际获得 ${keys.length} 个`)
|
||||
}
|
||||
|
||||
// 按顺序取值并转为两位十六进制
|
||||
const hex = keys
|
||||
.map((key) => {
|
||||
const val = obj[key]
|
||||
if (typeof val !== 'number' || isNaN(val)) {
|
||||
throw new Error(`键 "${key}" 对应的值不是有效数字 (${val})`)
|
||||
}
|
||||
if (val < 0 || val > 255) {
|
||||
throw new Error(`键 "${key}" 的值 ${val} 超出字节范围 (0-255)`)
|
||||
}
|
||||
return val.toString(16).padStart(2, '0')
|
||||
})
|
||||
.join('')
|
||||
|
||||
return hex
|
||||
}
|
||||
|
||||
// 执行转换
|
||||
function performConversion(): void {
|
||||
const raw = inputText.value.trim()
|
||||
if (!raw) {
|
||||
resultText.value = '⚠️ 请输入 JSON 数据'
|
||||
resultClass.value = 'error'
|
||||
copyEnabled.value = false
|
||||
copyFeedbackVisible.value = false
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const obj = JSON.parse(raw)
|
||||
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
|
||||
throw new Error('输入必须是 JSON 对象(不是数组或原始类型)')
|
||||
}
|
||||
const hex = convertToHex(obj)
|
||||
resultText.value = hex
|
||||
resultClass.value = 'success'
|
||||
copyEnabled.value = true
|
||||
copyFeedbackVisible.value = false
|
||||
} catch (err: any) {
|
||||
resultText.value = `❌ 转换失败:${err.message}`
|
||||
resultClass.value = 'error'
|
||||
copyEnabled.value = false
|
||||
copyFeedbackVisible.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 加载示例
|
||||
function loadExample(): void {
|
||||
inputText.value = JSON.stringify(EXAMPLE_OBJ, null, 2)
|
||||
performConversion() // 自动转换
|
||||
}
|
||||
|
||||
// 复制结果
|
||||
function copyResult(): void {
|
||||
const text = resultText.value
|
||||
if (!text || resultClass.value === 'error') return
|
||||
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
navigator.clipboard
|
||||
.writeText(text)
|
||||
.then(() => {
|
||||
copyFeedbackVisible.value = true
|
||||
setTimeout(() => (copyFeedbackVisible.value = false), 2000)
|
||||
})
|
||||
.catch(() => {
|
||||
fallbackCopy(text)
|
||||
})
|
||||
} else {
|
||||
fallbackCopy(text)
|
||||
}
|
||||
}
|
||||
|
||||
function fallbackCopy(text: string): void {
|
||||
const textarea = document.createElement('textarea')
|
||||
textarea.value = text
|
||||
document.body.appendChild(textarea)
|
||||
textarea.select()
|
||||
try {
|
||||
document.execCommand('copy')
|
||||
copyFeedbackVisible.value = true
|
||||
setTimeout(() => (copyFeedbackVisible.value = false), 2000)
|
||||
} catch (_) {
|
||||
alert('复制失败,请手动复制')
|
||||
}
|
||||
document.body.removeChild(textarea)
|
||||
}
|
||||
|
||||
// 组件挂载时加载示例
|
||||
onMounted(() => {
|
||||
loadExample()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 变量(可根据需要调整)
|
||||
$primary: #3b82f6;
|
||||
$primary-hover: #2563eb;
|
||||
$bg: #f6f8fa;
|
||||
$card-bg: #ffffff;
|
||||
$text-dark: #1f2937;
|
||||
$text-gray: #6b7280;
|
||||
$border: #d1d5db;
|
||||
$radius: 16px;
|
||||
|
||||
:deep(.el-card__body) {
|
||||
//height: calc(100vh - 211px + 60px);
|
||||
height: calc(100vh - 141px);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
margin-top: 0;
|
||||
margin-bottom: 8px;
|
||||
color: $text-dark;
|
||||
}
|
||||
|
||||
.sub {
|
||||
color: $text-gray;
|
||||
font-size: 14px;
|
||||
margin-top: -4px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
color: #374151;
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
padding: 12px 14px;
|
||||
outline: 1px solid $border;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
font-family: 'Menlo', 'Cascadia Code', 'Consolas', monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
resize: none;
|
||||
transition: border 0.2s, background 0.2s;
|
||||
background: #fafbfc;
|
||||
|
||||
&:focus {
|
||||
border-color: $primary;
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);
|
||||
background: white;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin: 18px 0 14px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
button {
|
||||
background: $primary;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 24px;
|
||||
border-radius: 8px;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s, transform 0.1s;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
|
||||
&:hover {
|
||||
background: $primary-hover;
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.96);
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
background: #e5e7eb;
|
||||
color: $text-dark;
|
||||
|
||||
&:hover {
|
||||
background: #d1d5db;
|
||||
}
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
|
||||
&:hover {
|
||||
background: #e5e7eb;
|
||||
}
|
||||
}
|
||||
|
||||
&.link-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: $primary;
|
||||
font-weight: 500;
|
||||
padding: 0;
|
||||
font-size: 13px;
|
||||
text-decoration: underline;
|
||||
display: inline;
|
||||
|
||||
&:hover {
|
||||
color: $primary-hover;
|
||||
background: none;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.copy-feedback {
|
||||
font-size: 13px;
|
||||
color: #10b981;
|
||||
margin-left: 12px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
|
||||
&.show {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.result-area {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.result-label {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 4px;
|
||||
|
||||
span {
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
color: #374151;
|
||||
}
|
||||
}
|
||||
|
||||
.result-box {
|
||||
background: #f3f4f6;
|
||||
border-radius: 10px;
|
||||
padding: 14px 16px;
|
||||
font-family: 'Menlo', 'Cascadia Code', 'Consolas', monospace;
|
||||
font-size: 14px;
|
||||
word-break: break-all;
|
||||
min-height: 48px;
|
||||
border: 1px solid #e5e7eb;
|
||||
color: $text-dark;
|
||||
transition: background 0.2s, border-color 0.2s;
|
||||
|
||||
&.error {
|
||||
background: #fee2e2;
|
||||
border-color: #fca5a5;
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
&.success {
|
||||
background: #ecfdf5;
|
||||
border-color: #6ee7b7;
|
||||
}
|
||||
}
|
||||
|
||||
.example-hint {
|
||||
font-size: 13px;
|
||||
color: $text-gray;
|
||||
margin-top: 6px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import {ref, onUnmounted} from "vue";
|
||||
import {
|
||||
asmr,
|
||||
file_rename,
|
||||
music_rename,
|
||||
image_hasTorrent,
|
||||
@@ -38,7 +39,8 @@ const buttons = [
|
||||
{id: 5, title: "判断视频是否有torrent", handle: video_hasTorrent},
|
||||
{id: 6, title: "判断图片是否有torrent", handle: image_hasTorrent},
|
||||
{id: 7, title: "音乐文件重命名", handle: music_rename},
|
||||
{id: 8, title: "种子统计", handle: torrent_statistics}
|
||||
{id: 8, title: "种子统计", handle: torrent_statistics},
|
||||
{id: 9, title: "asmr", handle: asmr}
|
||||
]
|
||||
|
||||
|
||||
@@ -50,7 +52,7 @@ function closeAlert(id: number) {
|
||||
const handleClick = async (btnObj: BtnItem) => {
|
||||
if (btnObj.title === "断开") return
|
||||
if (btnObj.title === "小说下载") {
|
||||
connect("http://192.168.1.32:5000/api/book/download")
|
||||
connect("http://43.159.32.210:5000/api/book/download")
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
@@ -64,7 +66,10 @@ const handleClick = async (btnObj: BtnItem) => {
|
||||
}))
|
||||
messages.value.push({id: Date.now() + messages.value.length, text: '已完成'})
|
||||
messages.value.reverse()
|
||||
} finally {
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user