From 272ce20fa1c93ec0d68e98b18f3c36f601a960dc Mon Sep 17 00:00:00 2001 From: li wei Date: Wed, 5 Jun 2024 18:55:03 +0800 Subject: [PATCH] feat: add dir search --- Dockerfile | 2 +- README.md | 4 +- api/files.go | 6 +- front/src/App.tsx | 76 +++++++++++++- front/src/backend.tsx | 2 +- front/yarn.lock | 225 ++++++++++++++++++++++++++++++++++++++---- server/file.go | 68 +++++++++++++ server/server.go | 1 + 8 files changed, 357 insertions(+), 27 deletions(-) diff --git a/Dockerfile b/Dockerfile index d58f5c0..e538361 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ RUN cd front && yarn install && yarn build FROM golang:1.22 AS go_builder WORKDIR /app COPY . . -COPY --from=node_builder /app/front/dist ./front/ +COPY --from=node_builder /app/front/dist ./front/dist RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o aliyun . # 第三阶段:设置最终的运行环境 diff --git a/README.md b/README.md index 4e95fbd..5267390 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ # 效果展示 ## 设置Token页面 ![token](./img/token.png) +## 获取目录地址(仅支持备份盘) +![dir](./img/dir.png) ## 批量修改页面 ![batch](./img/batch.png) @@ -28,5 +30,5 @@ docker run -d -p 9010:9010 -v /etc/aliyun:/etc/aliyun lwydyby/aliyun_tool ## 参数说明 - 目录地址: 要修改的阿里云盘目录地址,可以通过阿里云盘web端获取到 -- 匹配格式: 用`$`符号标注出集号,比如文件名称为01.mp4,则匹配格式为$01$.mp4,提示: 可以通过填充按钮获取到文件的原名称,可能第一次获取会失败再试一次就好(是个bug但是懒得修了) +- 匹配格式: 用`$`符号标注出集号,比如文件名称为01.mp4,则匹配格式为$01$.mp4,提示: 可以通过填充按钮获取到文件的原名称 - 文件前缀: 修改后的文件名称前缀,比如原文件名称为01.mp4,文件前缀输入庆余年,则修改结果为庆余年E01.mp4 \ No newline at end of file diff --git a/api/files.go b/api/files.go index 401d661..e6d11b1 100644 --- a/api/files.go +++ b/api/files.go @@ -66,7 +66,7 @@ func GetFiles(ctx context.Context, fileId string, driverType string) ([]File, er marker = "" } data := Json{ - "drive_id": getDriveID(driverType), + "drive_id": GetDriveID(driverType), "limit": 200, "marker": marker, "order_by": "created_at", @@ -104,7 +104,7 @@ func Rename(name string, f File) error { return err } -func getDriveID(driveType string) string { +func GetDriveID(driveType string) string { if config.C().DriveType == driveType && config.C().DriveID != "" { return config.C().DriveID } @@ -116,7 +116,7 @@ func getDriveID(driveType string) string { if err != nil { panic(err) } - config.C().DriveID = utils.Json.Get(res, config.C().DriveType+"_drive_id").ToString() + config.C().DriveID = utils.Json.Get(res, driveType+"_drive_id").ToString() config.C().DriveType = driveType config.SaveYaml() return config.C().DriveID diff --git a/front/src/App.tsx b/front/src/App.tsx index 2e9196c..e50189d 100644 --- a/front/src/App.tsx +++ b/front/src/App.tsx @@ -1,24 +1,64 @@ -import {Button, Input, Tabs, Toast} from '@arco-design/mobile-react'; +import {Button, Form, Input, Radio, Tabs, Toast} from '@arco-design/mobile-react'; import '@arco-design/mobile-react/esm/style'; import React, {useState} from "react"; import backend from "./backend.tsx"; const tabData = [ {title: 'token设置'}, + {title: '模糊寻找目录'}, {title: '批量重命名'}, ]; +const rootOption = + [ + {label: '备份盘', value: 'backup'}, + {label: '资源库', value: 'resource',disabled: true}, + ] + function App() { const [token, setToken] = React.useState(''); + const [dir, setDir] = React.useState(''); + const [deviceType, setDeviceType] = React.useState('backup'); const [url, setUrl] = React.useState(''); const [name, setName] = React.useState(''); const [prefix, setPrefix] = React.useState(''); const [tokenLoading, setTokenLoading] = useState(false); const [nameLoading, setNameLoading] = useState(false); const [submitLoading, setSubmitLoading] = useState(false); + const [urlVisbile, setUrlVisbile] = useState(false); + const [dirLoading, setDirLoading] = useState(false); const handleOpenToken = () => { window.open("https://alist.nn.ci/tool/aliyundrive/request.html", "_blank") } + const handleGetDirUrl = async () => { + setDirLoading(true); + try { + const response = await fetch(backend + `/v1/dir`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + dir: dir, + device_type: deviceType, + }), + }); + if (response.ok) { + const data = await response.json(); + setUrl(data.url) + setUrlVisbile(true) + Toast.toast('请求成功'); + // 处理你的数据 + } else { + throw new Error('Something went wrong on api server!'); + } + } catch (error) { + Toast.toast('请求失败,请重试'); + console.error('Error occurred:', error); + } finally { + setDirLoading(false); // 关闭加载状态 + } + } const handleGetName = async () => { setNameLoading(true); try { @@ -128,6 +168,40 @@ function App() { +
+
+ + setDir(value)} + onChange={(_, value) => setDir(value)} + placeholder="请输入目录名称,如果是多级目录则用/分隔,如:剧集/庆余年" + clearable + onClear={() => { + setDir(''); + }} + border="none" + clearShowType='always' + /> + + + { + if (typeof value === 'number') { + setDeviceType(value.toString()); + } else { + setDeviceType(value); + } + }}/> + +
+
+ +
+
+ {urlVisbile &&

目录地址为: {url}

} +
+
=20.0.0", "@types/node@^20.14.1": +"@types/node@^20.14.1": version "20.14.1" resolved "https://bnpm.byted.org/@types/node/-/node-20.14.1.tgz" integrity sha512-T2MzSGEu+ysB/FkWfqmhV3PLyQlowdptmmgD20C6QxsS8Fmv5SjpZ1ayXaEC0S21/h5UJ9iA6W/5vSNU5l00OA== @@ -402,14 +587,14 @@ resolved "https://bnpm.byted.org/@types/prop-types/-/prop-types-15.7.12.tgz" integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== -"@types/react-dom@^18.2.22", "@types/react-dom@>=16.9.0": +"@types/react-dom@^18.2.22": version "18.3.0" resolved "https://bnpm.byted.org/@types/react-dom/-/react-dom-18.3.0.tgz" integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^18.2.66", "@types/react@>=16.9.0": +"@types/react@*", "@types/react@^18.2.66": version "18.3.3" resolved "https://bnpm.byted.org/@types/react/-/react-18.3.3.tgz" integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw== @@ -432,7 +617,7 @@ natural-compare "^1.4.0" ts-api-utils "^1.3.0" -"@typescript-eslint/parser@^7.0.0", "@typescript-eslint/parser@^7.2.0": +"@typescript-eslint/parser@^7.2.0": version "7.11.0" resolved "https://bnpm.byted.org/@typescript-eslint/parser/-/parser-7.11.0.tgz" integrity sha512-yimw99teuaXVWsBcPO1Ais02kwJ1jmNA1KxE7ng0aT7ndr1pT1wqj0OJnsYVGKKlc4QJai86l/025L6z8CljOg== @@ -519,7 +704,7 @@ acorn-jsx@^5.3.2: resolved "https://bnpm.byted.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.9.0: +acorn@^8.9.0: version "8.11.3" resolved "https://bnpm.byted.org/acorn/-/acorn-8.11.3.tgz" integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== @@ -590,7 +775,7 @@ braces@^3.0.3: dependencies: fill-range "^7.1.1" -browserslist@^4.22.2, "browserslist@>= 4.21.0": +browserslist@^4.22.2: version "4.23.0" resolved "https://bnpm.byted.org/browserslist/-/browserslist-4.23.0.tgz" integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== @@ -641,16 +826,16 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@~1.1.4: - version "1.1.4" - resolved "https://bnpm.byted.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - color-name@1.1.3: version "1.1.3" resolved "https://bnpm.byted.org/color-name/-/color-name-1.1.3.tgz" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== +color-name@~1.1.4: + version "1.1.4" + resolved "https://bnpm.byted.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + concat-map@0.0.1: version "0.0.1" resolved "https://bnpm.byted.org/concat-map/-/concat-map-0.0.1.tgz" @@ -800,7 +985,7 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 resolved "https://bnpm.byted.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -"eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", eslint@^8.56.0, eslint@^8.57.0, eslint@>=7: +eslint@^8.57.0: version "8.57.0" resolved "https://bnpm.byted.org/eslint/-/eslint-8.57.0.tgz" integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== @@ -1150,7 +1335,7 @@ keyv@^4.5.3: dependencies: json-buffer "3.0.1" -less@*, less@^4.2.0: +less@^4.2.0: version "4.2.0" resolved "https://bnpm.byted.org/less/-/less-4.2.0.tgz" integrity sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA== @@ -1397,7 +1582,7 @@ queue-microtask@^1.2.2: resolved "https://bnpm.byted.org/queue-microtask/-/queue-microtask-1.2.3.tgz" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -react-dom@^18.2.0, react-dom@>=16.6.0, react-dom@>=16.9.0: +react-dom@^18.2.0: version "18.3.1" resolved "https://bnpm.byted.org/react-dom/-/react-dom-18.3.1.tgz" integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== @@ -1425,7 +1610,7 @@ react-transition-group@>=4.3.0: loose-envify "^1.4.0" prop-types "^15.6.2" -react@^18.2.0, react@^18.3.1, react@>=16.6.0, react@>=16.9.0: +react@^18.2.0: version "18.3.1" resolved "https://bnpm.byted.org/react/-/react-18.3.1.tgz" integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== @@ -1615,7 +1800,7 @@ type-fest@^0.20.2: resolved "https://bnpm.byted.org/type-fest/-/type-fest-0.20.2.tgz" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -typescript@^5.2.2, typescript@>=4.2.0: +typescript@^5.2.2: version "5.4.5" resolved "https://bnpm.byted.org/typescript/-/typescript-5.4.5.tgz" integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== @@ -1640,7 +1825,7 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -"vite@^4.2.0 || ^5.0.0", vite@^5.2.0: +vite@^5.2.0: version "5.2.11" resolved "https://bnpm.byted.org/vite/-/vite-5.2.11.tgz" integrity sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ== diff --git a/server/file.go b/server/file.go index 76b9aa4..541255e 100644 --- a/server/file.go +++ b/server/file.go @@ -160,6 +160,74 @@ func BatchRenameHandler(w http.ResponseWriter, req *http.Request) { w.WriteHeader(http.StatusOK) } +type GetDirRequest struct { + Dir string `json:"dir,omitempty"` + DeviceType string `json:"device_type,omitempty"` +} + +type GetDirResponse struct { + Url string `json:"url"` +} + +func GetDirHandler(w http.ResponseWriter, req *http.Request) { + body, err := io.ReadAll(req.Body) + if err != nil { + http.Error(w, "Error reading request body", http.StatusInternalServerError) + return + } + var request GetDirRequest + err = json.Unmarshal(body, &request) + if err != nil { + http.Error(w, "Error parsing JSON request body", http.StatusBadRequest) + return + } + if request.Dir == "" || request.DeviceType == "" { + http.Error(w, "dir is empty or device_type is empty", http.StatusBadRequest) + return + } + ctx := req.Context() + dirs := strings.Split(request.Dir, "/") + fileId := "root" + for i := range dirs { + files, err := api.GetFiles(ctx, fileId, request.DeviceType) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + hasFound := false + for j := range files { + if files[i].Type == "file" { + continue + } + if files[j].Name == dirs[i] { + fileId = files[j].FileId + hasFound = true + break + } + } + if !hasFound { + http.Error(w, "dir not found", http.StatusBadRequest) + return + } + } + resp := GetDirResponse{ + Url: fmt.Sprintf("%s/%s", request.DeviceType, fileId), + } + responseData, err := json.Marshal(resp) + if err != nil { + http.Error(w, "Error generating JSON response", http.StatusInternalServerError) + return + } + + // 设置响应头为JSON格式 + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, err = w.Write(responseData) + if err != nil { + fmt.Println(err) + } +} + func getDeviceTypeAndFileID(path string) (string, string) { filePaths := strings.Split(path, "/") return filePaths[len(filePaths)-2], filePaths[len(filePaths)-1] diff --git a/server/server.go b/server/server.go index 45ebd00..e697843 100644 --- a/server/server.go +++ b/server/server.go @@ -39,6 +39,7 @@ func (s *SimpleServer) buildHTTPHandler() http.Handler { r.Path("/v1/token").Methods(http.MethodPost).Handler(CorsMiddleware(transHandler(SubmitTokenHandler))) r.Path("/v1/name").Methods(http.MethodPost).Handler(CorsMiddleware(transHandler(GetFileHandler))) r.Path("/v1/batch").Methods(http.MethodPost).Handler(CorsMiddleware(transHandler(BatchRenameHandler))) + r.Path("/v1/dir").Methods(http.MethodPost).Handler(CorsMiddleware(transHandler(GetDirHandler))) r.PathPrefix("/").Handler(CorsMiddleware(http.StripPrefix("/", staticHandler))) return r }