diff --git a/docker/stash/Dockerfile b/docker/stash/Dockerfile new file mode 100644 index 0000000..ef87ce5 --- /dev/null +++ b/docker/stash/Dockerfile @@ -0,0 +1,39 @@ +# 使用 Ubuntu 最新的 x86_64 版本 +FROM --platform=linux/x86_64 stashapp/stash:latest + +# 设置时区,避免交互式输入 +ENV DEBIAN_FRONTEND=noninteractive + +# 更新软件包和安装常用工具 +RUN apk update && apk add --no-cache \ + git \ + yt-dlp \ + curl \ + wget \ + vim \ + bash \ + python3 \ + py3-pip \ + && rm -rf /var/cache/apk/* + +# 创建工作目录 +WORKDIR /app + +# 将 requirements.txt 复制到工作目录 +COPY requirements.txt . + +# 安装项目依赖 +RUN pip3 install -r requirements.txt --break-system-packages + +# 设置 Git 配置 +RUN git config --global user.name "oscar" && \ + git config --global user.email "oscar@easyprompt8.com" && \ + git config --global credential.helper store + +# 复制 FutuOpenD 安装包(假设你事先下载了 FutuOpenD) +# 如果你希望 Docker 自动下载,可以在 ENTRYPOINT 里手动执行 +# COPY FutuOpenD.tar.gz /root/ +# RUN tar -xzf /root/FutuOpenD.tar.gz -C /root/ && rm /root/FutuOpenD.tar.gz + +# 启动时进入 bash 交互模式 +CMD ["/bin/bash"] \ No newline at end of file diff --git a/docker/stash/docker-compose.yml b/docker/stash/docker-compose.yml new file mode 100644 index 0000000..ebebe2a --- /dev/null +++ b/docker/stash/docker-compose.yml @@ -0,0 +1,48 @@ +--- +services: + stash: + image: mystash:latest # 指定了镜像名 + build: + context: . + dockerfile: Dockerfile + container_name: newstash + platform: linux/x86_64 + restart: unless-stopped + ports: + - "8888:9999" + environment: + HTTP_PROXY: "http://192.168.2.20:7890" + HTTPS_PROXY: "http://192.168.2.20:7890" + STASH_STASH: /root/stash/data/ + STASH_GENERATED: /root/stash/generated/ + STASH_METADATA: /root/stash/metadata/ + STASH_CACHE: /root/stash/cache/ + STASH_DATA: /root/stash/data/ + STASH_DB: /root/stash/sqlite/ + STASH_PORT: 9999 + TZ: "Asia/Shanghai" + volumes: + # 应用的目录 + - /etc/localtime:/etc/localtime:ro + - ~/dockers/stash/config:/root/.stash + - ~/dockers/stash/data:/root/stash/data + - ~/dockers/stash/sqlite:/root/stash/sqlite + - ~/dockers/stash/metadata:/root/stash/metadata + - ~/dockers/stash/cache:/root/stash/cache + - ~/dockers/stash/blobs:/root/stash/blobs + - ~/dockers/stash/generated:/root/stash/generated + + - ~/Documents/codes/common:/root/projects # 挂载git工程目录 + # mkdir -p ~/dockers/stash/{hostdir,config} + - ~/dockers/stash/hostdir:/root/hostdir # 挂载一个通用的主机目录 + - ~/dockers/sharedata:/root/sharedata # 挂载一个docker之间共享的目录 + + - ~/dockers/stash/.ssh:/root/.ssh # 允许 SSH 访问 git 仓库 + # touch ~/dockers/stash/.gitconfig + - ~/dockers/stash/.gitconfig:/root/.gitconfig # 共享 Git 配置文件 + networks: + - devops + +networks: + devops: + external: true \ No newline at end of file diff --git a/docker/stash/requirements.txt b/docker/stash/requirements.txt new file mode 100644 index 0000000..b534308 --- /dev/null +++ b/docker/stash/requirements.txt @@ -0,0 +1,7 @@ +# 绕过cloudflare限制的包 +cloudscraper + +requests +beautifulsoup4 +lxml +pymysql diff --git a/tools/sqlite_backup.sh b/tools/sqlite_backup.sh new file mode 100755 index 0000000..29dc8e9 --- /dev/null +++ b/tools/sqlite_backup.sh @@ -0,0 +1,150 @@ +#!/bin/bash + +# 解析命令行参数 +mod="" +while [[ $# -gt 0 ]]; do + case "$1" in + mod=*) + mod="${1#mod=}" + ;; + *) + echo "未知参数: $1" + exit 1 + ;; + esac + shift +done + +# 根据 mod 参数设置 base_dir +if [ "$mod" = "host" ]; then + base_dir="~/dockers/sharedata" +elif [ "$mod" = "docker" ]; then + base_dir="~/sharedata" +else + echo "无效的 mod 参数值,必须为 host 或 docker" + exit 1 +fi + +# 扩展波浪号为用户主目录 +base_dir=$(eval echo "$base_dir") + +# 源目录和目标目录 +src_dir="$base_dir/sqlite" +dst_dir="$base_dir/backup_sqlite" + +# 确保目标目录存在 +if [ ! -d "$dst_dir" ]; then + mkdir -p "$dst_dir" +fi + +# 获取当前时间,格式为 yyyymmdd_hhMMss +timestamp=$(date +%Y%m%d_%H%M%S) + +# 遍历源目录下的所有 .db 文件 +for db_file in "$src_dir"/*.db; do + if [ -f "$db_file" ]; then + # 获取文件名(不包含路径) + file_name=$(basename "$db_file") + # 生成备份文件名 + backup_file="$dst_dir/${file_name%.*}_$timestamp.db" + # 备份文件 + cp "$db_file" "$backup_file" + if [ $? -eq 0 ]; then + echo "备份 $file_name 成功,备份文件为 $backup_file" + # 计算备份文件的 md5 值 + backup_md5=$(md5sum "$backup_file" | awk '{print $1}') + backup_md5_file="$dst_dir/${file_name%.*}_$timestamp.md5" + echo "$backup_md5" > "$backup_md5_file" + if [ $? -eq 0 ]; then + echo "生成 $backup_file 的 md5 文件成功" + else + echo "生成 $backup_file 的 md5 文件失败" + fi + + # 压缩备份文件为 tar.gz + tar_file="$dst_dir/${file_name%.*}_$timestamp.db.tar.gz" + backup_dir=$(dirname "$backup_file") + backup_base=$(basename "$backup_file") + (cd "$backup_dir" && tar -czf "$tar_file" "$backup_base") + if [ $? -eq 0 ]; then + echo "压缩 $backup_file 为 $tar_file 成功" + # 计算压缩文件的 md5 值 + tar_md5=$(md5sum "$tar_file" | awk '{print $1}') + tar_md5_file="$dst_dir/${file_name%.*}_$timestamp.tar.gz.md5" + echo "$tar_md5" > "$tar_md5_file" + if [ $? -eq 0 ]; then + echo "生成 $tar_file 的 md5 文件成功" + else + echo "生成 $tar_file 的 md5 文件失败" + fi + + # 合并两个 MD5 文件 + combined_md5_file="$dst_dir/${file_name%.*}_$timestamp.combined.md5" + echo "$backup_md5 ${file_name%.*}_$timestamp.db" > "$combined_md5_file" + echo "$tar_md5 ${file_name%.*}_$timestamp.db.tar.gz" >> "$combined_md5_file" + if [ $? -eq 0 ]; then + echo "合并 MD5 文件成功,合并后的文件为 $combined_md5_file" + else + echo "合并 MD5 文件失败" + fi + + # 删除未压缩的备份文件和单独的 MD5 文件 + rm "$backup_file" + if [ $? -eq 0 ]; then + echo "删除未压缩的备份文件 $backup_file 成功" + else + echo "删除未压缩的备份文件 $backup_file 失败" + fi + rm "$backup_md5_file" + if [ $? -eq 0 ]; then + echo "删除未压缩备份文件的 MD5 文件 $backup_md5_file 成功" + else + echo "删除未压缩备份文件的 MD5 文件 $backup_md5_file 失败" + fi + rm "$tar_md5_file" + if [ $? -eq 0 ]; then + echo "删除压缩备份文件的 MD5 文件 $tar_md5_file 成功" + else + echo "删除压缩备份文件的 MD5 文件 $tar_md5_file 失败" + fi + else + echo "压缩 $backup_file 为 $tar_file 失败" + fi + else + echo "备份 $file_name 失败" + fi + fi +done + +# 扫描备份目录,清理旧备份 +for base_name in $(ls "$src_dir"/*.db | xargs -n1 basename | sed 's/\.db$//'); do + # 查找该数据库文件的所有备份文件 + backup_files=("$dst_dir/${base_name}"_*.db.tar.gz) + combined_md5_files=("$dst_dir/${base_name}"_*.combined.md5) + # 按时间戳降序排序 + IFS=$'\n' sorted_backup_files=($(sort -r <<<"${backup_files[*]}")) + sorted_combined_md5_files=($(sort -r <<<"${combined_md5_files[*]}")) + unset IFS + # 保留最近的两个备份,删除其余的 + num_backups=${#sorted_backup_files[@]} + num_combined_md5_files=${#sorted_combined_md5_files[@]} + if [ $num_backups -gt 2 ]; then + for ((i = 2; i < num_backups; i++)); do + backup_to_delete="${sorted_backup_files[$i]}" + combined_md5_to_delete="${sorted_combined_md5_files[$i]}" + rm "$backup_to_delete" + if [ $? -eq 0 ]; then + echo "删除旧压缩备份文件 $backup_to_delete 成功" + else + echo "删除旧压缩备份文件 $backup_to_delete 失败" + fi + rm "$combined_md5_to_delete" + if [ $? -eq 0 ]; then + echo "删除旧合并 MD5 文件 $combined_md5_to_delete 成功" + else + echo "删除旧合并 MD5 文件 $combined_md5_to_delete 失败" + fi + done + fi +done + \ No newline at end of file