diff --git a/upload.sh b/upload.sh new file mode 100644 index 00000000..725d9462 --- /dev/null +++ b/upload.sh @@ -0,0 +1,317 @@ +#!/bin/bash + +# 默认配置 +# 文件分片大小(1MB = 1048576) +CHUNK_SIZE=1048576 +# 1. 服务端地址,如果使用默认的docker-compose部署,则为: http://ip:7072, 或者 http://ip:7070/api +SERVER_URL=${SERVER_URL:-""} +# 2. 在设置-授权应用中添加一个访问令牌 +ACCESS_TOKEN=${ACCESS_TOKEN:-""} +# 3. 用户账号,不是用户名 +USERNAME=${USERNAME:-""} +# 4. 要上传到那个目录,根目录为"/" +CURRENT_DIRECTORY=${CURRENT_DIRECTORY:-""} + +# 检查必要配置 +check_config() { + local missing_configs=() + + if [ -z "$SERVER_URL" ]; then + missing_configs+=("SERVER_URL") + fi + + if [ -z "$ACCESS_TOKEN" ]; then + missing_configs+=("ACCESS_TOKEN") + fi + + if [ -z "$USERNAME" ]; then + missing_configs+=("USERNAME") + fi + + if [ -z "$CURRENT_DIRECTORY" ]; then + missing_configs+=("CURRENT_DIRECTORY") + fi + + if [ ${#missing_configs[@]} -ne 0 ]; then + echo "错误: 以下必要配置缺失:" + printf '%s\n' "${missing_configs[@]}" + echo + echo "请通过以下方式之一进行配置:" + echo "1. 设置环境变量:" + for config in "${missing_configs[@]}"; do + echo " export $config=" + done + echo + echo "2. 直接修改脚本中的默认值:" + for config in "${missing_configs[@]}"; do + echo " $config=\"\"" + done + exit 1 + fi + + # 验证服务器连接和访问令牌 + local response + response=$(curl -s -w "\n%{http_code}" \ + --connect-timeout 3 \ + --max-time 3 \ + "${SERVER_URL}/api/user/info" \ + --header "access-token: ${ACCESS_TOKEN}") + + local http_code=$(echo "$response" | tail -n1) + local body=$(echo "$response" | sed '$d') + + if [ "$http_code" != "200" ]; then + echo "错误: 服务器连接失败" + echo "请检查 SERVER_URL 是否正确" + exit 1 + fi + + # 检查响应中的 code 字段 + if ! echo "$body" | grep -q '"code":0'; then + echo "请检查 ACCESS_TOKEN 是否正确" + exit 1 + fi +} + +# 检查命令行参数 +if [ $# -ne 1 ]; then + echo "用法: $0 <文件或目录路径>" + exit 1 +fi + +PATH_TO_UPLOAD="$1" + +# 检查路径是否存在 +if [ ! -e "$PATH_TO_UPLOAD" ]; then + echo "错误: 路径不存在 - $PATH_TO_UPLOAD" + exit 1 +fi + +# 检查配置 +check_config + + +# URL编码函数 +url_encode() { + local string="$1" + echo -n "$string" | xxd -p | sed 's/\(..\)/%\1/g' +} + +# 获取文件大小的函数,适配 Linux 和 macOS +get_file_size() { + local file_path="$1" + if [[ "$OSTYPE" == "darwin"* ]]; then + # macOS + stat -f%z "$file_path" + else + # Linux + stat -c%s "$file_path" + fi +} + +# 进度条 +show_progress() { + local progress=$1 + local width=50 + local percent=$((progress * width / 100)) + printf "\r" + printf "上传进度: [" + for ((i=0; i ${CURRENT_DIRECTORY}" + + FILE_PATH="$file_path" + FILE_NAME=$(basename "$file_path") + TOTAL_SIZE=$(get_file_size "$FILE_PATH") + IDENTIFIER="${TOTAL_SIZE}-${FILE_NAME}" + IDENTIFIER=$(echo "$IDENTIFIER" | tr -cd '[:alnum:]-') + + # URL编码相关变量 + local encoded_filename=$(url_encode "$FILE_NAME") + local encoded_directory=$(url_encode "$CURRENT_DIRECTORY") + + if [ $TOTAL_SIZE -le $CHUNK_SIZE ]; then + TOTAL_CHUNKS=1 + upload_chunk "$FILE_PATH" 1 "$TOTAL_SIZE" > /dev/null + if [ $? -ne 0 ]; then + echo "文件上传失败: $FILE_NAME" + continue + fi + else + TOTAL_CHUNKS=$(( ($TOTAL_SIZE + $CHUNK_SIZE - 1) / $CHUNK_SIZE )) + TEMP_DIR=$(mktemp -d) + split -b $CHUNK_SIZE "$FILE_PATH" "$TEMP_DIR/chunk." + + CHUNK_INDEX=1 + for CHUNK_FILE in "$TEMP_DIR"/chunk.*; do + CURRENT_CHUNK_SIZE=$(get_file_size "$CHUNK_FILE") + upload_chunk "$CHUNK_FILE" "$CHUNK_INDEX" "$CURRENT_CHUNK_SIZE" > /dev/null + if [ $? -ne 0 ]; then + echo "分片上传失败: $FILE_NAME" + rm -rf "$TEMP_DIR" + continue 2 + fi + CHUNK_INDEX=$((CHUNK_INDEX + 1)) + done + + rm -rf "$TEMP_DIR" + + # 合并文件时使用编码后的参数 + MERGE_URL="${SERVER_URL}/merge" + MERGE_PARAMS="filename=${encoded_filename}&relativePath=${encoded_filename}&identifier=${IDENTIFIER}¤tDirectory=${encoded_directory}&username=${USERNAME}&totalSize=${TOTAL_SIZE}&isFolder=false" + + MERGE_RESPONSE=$(curl -s -X POST "${MERGE_URL}?${MERGE_PARAMS}" \ + -H "access-token: ${ACCESS_TOKEN}" \ + -H "lang: zh-CN") + + if ! echo "$MERGE_RESPONSE" | grep -q '"code":0'; then + echo "文件合并失败: $FILE_NAME" + echo "错误响应: $MERGE_RESPONSE" + continue + fi + fi + echo "文件上传完成: $FILE_NAME" + done + + CURRENT_DIRECTORY="$original_current_directory" +} + +if [ -d "$PATH_TO_UPLOAD" ]; then + ABSOLUTE_PATH=$(cd "$(dirname "$PATH_TO_UPLOAD")" && pwd) + upload_directory "$PATH_TO_UPLOAD" "$ABSOLUTE_PATH" + echo "文件夹上传完成" +else + FILE_PATH="$PATH_TO_UPLOAD" + FILE_NAME=$(basename "$FILE_PATH") + TOTAL_SIZE=$(get_file_size "$FILE_PATH") + IDENTIFIER="${TOTAL_SIZE}-${FILE_NAME}" + IDENTIFIER=$(echo "$IDENTIFIER" | tr -cd '[:alnum:]-') + + echo "开始上传文件: $FILE_NAME (大小: $TOTAL_SIZE 字节)" + + if [ $TOTAL_SIZE -le $CHUNK_SIZE ]; then + # 小文件直接上传 + upload_chunk "$FILE_PATH" 1 "$TOTAL_SIZE" > /dev/null + if [ $? -ne 0 ]; then + echo "文件上传失败" + exit 1 + fi + else + # 大文件分片上传 + TOTAL_CHUNKS=$(( ($TOTAL_SIZE + $CHUNK_SIZE - 1) / $CHUNK_SIZE )) + TEMP_DIR=$(mktemp -d) + split -b $CHUNK_SIZE "$FILE_PATH" "$TEMP_DIR/chunk." + + echo "开始分片上传..." + CHUNK_INDEX=1 + for CHUNK_FILE in "$TEMP_DIR"/chunk.*; do + CURRENT_CHUNK_SIZE=$(get_file_size "$CHUNK_FILE") + PROGRESS=$((CHUNK_INDEX * 100 / TOTAL_CHUNKS)) + show_progress $PROGRESS + + upload_chunk "$CHUNK_FILE" "$CHUNK_INDEX" "$CURRENT_CHUNK_SIZE" > /dev/null + if [ $? -ne 0 ]; then + echo -e "\n分片上传失败" + rm -rf "$TEMP_DIR" + exit 1 + fi + CHUNK_INDEX=$((CHUNK_INDEX + 1)) + done + + rm -rf "$TEMP_DIR" + echo -e "\n分片上传完成" + + # 合并文件 + echo "开始合并文件..." + + # URL编码文件名和目录 + encoded_filename=$(url_encode "$FILE_NAME") + encoded_directory=$(url_encode "$CURRENT_DIRECTORY") + + MERGE_URL="${SERVER_URL}/merge" + MERGE_PARAMS="filename=${encoded_filename}&relativePath=${encoded_filename}&identifier=${IDENTIFIER}¤tDirectory=${encoded_directory}&username=${USERNAME}&totalSize=${TOTAL_SIZE}&isFolder=false" + + MERGE_RESPONSE=$(curl -s -X POST "${MERGE_URL}?${MERGE_PARAMS}" \ + -H "access-token: ${ACCESS_TOKEN}" \ + -H "lang: zh-CN") + + if ! echo "$MERGE_RESPONSE" | grep -q '"code":0'; then + echo "文件合并失败" + echo "错误响应: $MERGE_RESPONSE" + exit 1 + fi + fi + + echo "文件上传完成" +fi +