自动断qb脚本

自动断qb脚本

Administrator 44 2025-05-22

前言:

通过这个脚本,可以自动识别带宽是否低于设定值(如 300 Mbps),如果是,则自动阻断新的下载任务。

使用 iptables 阻止新连接

  • 脚本使用 iptables 来阻止对 qBittorrent Web UI 端口(默认是 8080)的访问。

  • 这样做的效果是:

    • 新的任务无法添加(因为 Web UI 无法访问)

    • 已有的任务仍然继续下载(不会中断)

自动恢复机制

  • 当带宽恢复正常后,脚本会自动解除 iptables 规则,允许重新配置 qBittorrent。

  • 可选地(通过变量控制)会在恢复后自动重启服务器(用于清理资源或重置状态)。

通知机制

  • 使用 Telegram Bot 和 Email 发送通知,让你及时了解当前带宽状态和系统操作记录。

  • 支持多种消息格式美化,便于阅读。

脚本的“智能判断”逻辑

判断项

描述

两次测速

避免误判,连续两次低于设定带宽才触发动作

状态文件

使用 /tmp/bw_monitor_state 记录当前状态,避免重复执行

仅变化时通知

只有状态发生变化(从高速到低速或反之)才会推送通知

技术亮点总结

功能

实现方式

带宽检测

使用 speedtest-cli 测速

状态持久化

使用临时文件保存状态

自动安装

一键安装依赖(speedtest、mutt、bc、curl 等)

定时任务

使用 cron 定期检查

网络控制

使用 iptables 控制访问

通知系统

Telegram + Email(支持 Markdown 格式)

安装方法:

1)新建目录bw-monitor,然后再在这个目录下新建bw-monitor.sh

2)粘贴脚本文件进去保存

#!/bin/bash
set -euo pipefail

# === 用户配置区 ===
TELEGRAM_BOT_TOKEN="#"
TELEGRAM_CHAT_ID="#"
EMAIL="#"

QBITTORRENT_PORT=8080        # qBittorrent Web UI 端口
NOTIFY_INTERVAL_MINUTES=10
MIN_BANDWIDTH_Mbps=300       # 触发限速的带宽阈值
STATE_FILE="/tmp/bw_monitor_state"
LOG_FILE="/var/log/bw-monitor.log"

# 是否在离开低速模式后重启服务器
REBOOT_AFTER_LEAVE_LOW_SPEED=true

# === 通知开关 ===
TELEGRAM_NOTIFY=true     # 是否启用 Telegram 通知
EMAIL_NOTIFY=true       # 默认关闭邮件通知(可改为 true 启用)

# === 工具路径检查 ===
SPEEDTEST=$(command -v speedtest-cli || command -v speedtest)
MAIL=$(command -v mail || true)

# 获取公网IPv4地址
get_public_ip() {
    local ip
    ip=$(curl -s --ipv4 http://ifconfig.me)
    echo "$ip"
}

# 日志函数
log() {
    echo "$(date '+%Y-%m-%d %T') $1" | tee -a "$LOG_FILE"
}

# === 安装 mutt(如果未安装)===
setup_mutt() {
    if ! command -v mutt &> /dev/null; then
        log "[INSTALL] 安装 mutt..."
        apt update && apt install -y mutt
    fi
}

# === 通知函数 ===
send_telegram() {
    if [[ "$TELEGRAM_NOTIFY" == "true" ]]; then
        local msg="$1"

        # 替换 \n 字符串为真实换行符
        msg=$(echo "$msg" | sed 's/\\n/\n/g')

        # 在每行末尾加两个空格以确保 Telegram Markdown 正确换行
        msg=$(echo "$msg" | sed 's/$/  /')

        curl -s -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendMessage" \
            -d chat_id="$TELEGRAM_CHAT_ID" \
            -d parse_mode="Markdown" \
            -d text="$msg"
    fi
}

send_email() {
    if [[ "$EMAIL_NOTIFY" == "true" && -n "$EMAIL" ]]; then
        local subject="$1"
        local body="$2"

        # 替换 \n 字符串为真实换行符
        body=$(echo "$body" | sed 's/\\n/\n/g')

        setup_mutt

        # 使用 mutt 发送邮件,确保 UTF-8 编码
        echo -e "$body" | mutt -e "set content_type=text/plain; charset=UTF-8" -s "$subject" -- "$EMAIL"
    fi
}

notify_user() {
    local event="$1"
    local bandwidth="$2"
    local server_ip="$3"
    local container="$4"
    local status="$5"
    local mode="$6"

    local time=$(date "+%Y-%m-%d %H:%M:%S")
    local msg_template="🛠️ 事件: $event\n📊 带宽: $bandwidth Mbps\n🖥️ 服务器IP: $server_ip\n🐳 组件: $container\n🕒 时间: $time\n🔗 状态: $status"

    send_telegram "$msg_template"
    send_email "【带宽通知】$mode 流量模式触发" "$msg_template"
}

# === 网络控制函数 ===

block_qb_connection() {
    if ! iptables -C INPUT -p tcp --dport "$QBITTORRENT_PORT" -j DROP 2>/dev/null; then
        iptables -I INPUT 1 -p tcp --dport "$QBITTORRENT_PORT" -j DROP
        log "[ACTION] 已阻止主机上的 qbittorrent 访问(端口: $QBITTORRENT_PORT)"
    fi
}

unblock_qb_connection() {
    if iptables -C INPUT -p tcp --dport "$QBITTORRENT_PORT" -j DROP 2>/dev/null; then
        iptables -D INPUT -p tcp --dport "$QBITTORRENT_PORT" -j DROP
        log "[ACTION] 已解除对主机 qbittorrent 的访问限制(端口: $QBITTORRENT_PORT)"
    else
        log "[INFO] 当前没有针对 qbittorrent 的限制规则"
    fi
}

get_bandwidth_speed() {
    local result
    result=$($SPEEDTEST --simple)
    if [[ $? -eq 0 ]]; then
        local down
        down=$(echo "$result" | grep 'Download' | awk '{print $2}')
        echo "$down"
    else
        log "[ERROR] Speedtest 失败"
        exit 1
    fi
}

# === 主逻辑 ===
main() {
    log "[INFO] 开始带宽检测..."

    # 第一次测速
    bandwidth1=$(get_bandwidth_speed)
    log "[INFO] 第一次下载速度: ${bandwidth1} Mbps"

    # 等待5秒进行第二次测速
    sleep 5
    bandwidth2=$(get_bandwidth_speed)
    log "[INFO] 第二次下载速度: ${bandwidth2} Mbps"

    # 判断是否都低于阈值
    is_low1=$(echo "$bandwidth1 < $MIN_BANDWIDTH_Mbps" | bc -l)
    is_low2=$(echo "$bandwidth2 < $MIN_BANDWIDTH_Mbps" | bc -l)

    if [[ "$is_low1" -eq 1 && "$is_low2" -eq 1 ]]; then
        is_low_bandwidth=true
    elif [[ "$is_low1" -eq 0 && "$is_low2" -eq 0 ]]; then
        is_low_bandwidth=false
    else
        log "[INFO] 两次测速结果不一致,暂不改变状态"
        exit 0
    fi

    last_state=$(cat "$STATE_FILE" 2>/dev/null || echo "")

    notify_message=""
    SERVER_IP=$(get_public_ip)

    if [[ "$is_low_bandwidth" == "true" ]]; then
        if [[ "$last_state" != "low" ]]; then
            log "[ACTION] 连续两次检测到低速带宽,正在阻止 qbittorrent 访问..."
            block_qb_connection
            notify_message="⚠️ 进入低速模式"
            echo "low" > "$STATE_FILE"
            notify_user "$notify_message" "$bandwidth2" "$SERVER_IP" "qbittorrent" "新任务已禁止" "低速"
        else
            log "[INFO] 当前仍处于低速模式,不重复推送。"
        fi
    else
        if [[ "$last_state" == "low" ]]; then
            log "[ACTION] 连续两次检测到高速带宽恢复,解除限制..."
            unblock_qb_connection
            notify_message="✅ 离开低速模式"
            echo "high" > "$STATE_FILE"
            notify_user "$notify_message" "$bandwidth2" "$SERVER_IP" "qbittorrent" "新任务已恢复" "高速"

            # 判断是否需要重启服务器
            if [[ "$REBOOT_AFTER_LEAVE_LOW_SPEED" == "true" ]]; then
                log "[ACTION] 正在重启服务器..."
                reboot
            fi
        else
            log "[INFO] 当前仍处于高速模式,不推送。"
        fi
    fi
}

# === 测试通知 ===
test_notification() {
    log "[INFO] 发送测试通知..."
    local test_ip=$(get_public_ip)
    notify_user "🧪 测试通知" "1000" "$test_ip" "qbittorrent" "通知系统正常" "测试"
}

# === 安装依赖 ===
setup_dependencies() {
    if ! command -v speedtest-cli &> /dev/null && ! command -v speedtest &> /dev/null; then
        log "[INSTALL] 安装 speedtest-cli..."
        apt update && apt install -y python3-pip
        pip3 install speedtest-cli || apt install -y speedtest-cli
    fi
    if ! command -v jq &> /dev/null; then
        log "[INSTALL] 安装 jq..."
        apt update && apt install -y jq
    fi
    if ! command -v mutt &> /dev/null; then
        log "[INSTALL] 安装 mutt..."
        apt update && apt install -y mutt
    fi
    if ! command -v bc &> /dev/null; then
        log "[INSTALL] 安装 bc..."
        apt update && apt install -y bc
    fi
    if ! command -v curl &> /dev/null; then
        log "[INSTALL] 安装 curl..."
        apt install -y curl
    fi
}

# === 安装cron任务 ===
setup_cron() {
    (crontab -l 2>/dev/null | grep -v "bw-monitor"; echo "*/$NOTIFY_INTERVAL_MINUTES * * * * /opt/bw-monitor/bw-monitor.sh") | crontab -
    log "[CRON] 已添加每${NOTIFY_INTERVAL_MINUTES}分钟的检测任务"
}

# === 初始化安装 ===
if [[ "$*" == *"--install"* ]]; then
    log "[SETUP] 正在安装 bw-monitor..."

    setup_dependencies
    mkdir -p /opt/bw-monitor/
    cp "$0" /opt/bw-monitor/bw-monitor.sh
    chmod +x /opt/bw-monitor/bw-monitor.sh
    ln -sf /opt/bw-monitor/bw-monitor.sh /usr/local/bin/bw-monitor
    setup_cron
    test_notification
    log "[SETUP] 安装完成!"
    exit 0
fi

# === 执行主程序 ===
main

3)赋予执行权限 sudo chmod +x /opt/bw-monitor/bw-monitor.sh

4)首次运行安装 sudo /opt/bw-monitor/bw-monitor.sh --install

5)手动运行监控 sudo /opt/bw-monitor/bw-monitor.sh

6)查看定时任务 crontab -l

7)如果定时任务没有安装好,可以手动安装下

sudo crontab -e

*/10 * * * * /opt/bw-monitor/bw-monitor.sh

依次ctrl+O,回车,ctrl+X

8)查看日志:tail -f /var/log/bw-monitor.log或者手动打开日志文件

目录:STATE_FILE="/tmp/bw_monitor_state",LOG_FILE="/var/log/bw-monitor.log"

  • STATE_FILE 用来保存带宽监控的状态(高速或低速),通过读取和写入这个文件来判断当前是否处于限速模式。

  • LOG_FILE 则是记录脚本执行过程中的日志信息。


下方命令调试使用,可忽略

#模拟低速模式(<300 Mbps)
sudo sed -i '/function get_bandwidth_speed/,+5d' /opt/bw-monitor/bw-monitor.sh
sudo sed -i '/main() {/i get_bandwidth_speed() {\n    echo "150"\n}' /opt/bw-monitor/bw-monitor.sh
sudo /opt/bw-monitor/bw-monitor.sh
#模拟高速模式(≥300 Mbps)
sudo sed -i '/function get_bandwidth_speed/,+5d' /opt/bw-monitor/bw-monitor.sh
sudo sed -i '/main() {/i get_bandwidth_speed() {\n    echo "500"\n}' /opt/bw-monitor/bw-monitor.sh
sudo /opt/bw-monitor/bw-monitor.sh
#恢复自动测速模式(使用真实带宽)
sudo sed -i '/function get_bandwidth_speed/,+5d' /opt/bw-monitor/bw-monitor.sh
sudo sed -i '/main() {/i get_bandwidth_speed() {\n    local result\n    result=$($SPEEDTEST --simple)\n    if [[ $? -eq 0 ]]; then\n        local down\n        down=$(echo "$result" | grep '\''Download'\'' | awk '\''{print $2}'\'')\n        echo "$down"\n    else\n        log "[ERROR] Speedtest 失败"\n        exit 1\n    fi\n}' /opt/bw-monitor/bw-monitor.sh
sudo /opt/bw-monitor/bw-monitor.sh

命令无反馈,手动安装依赖

  • 安装 speedtest-cli: sudo apt update && sudo apt install speedtest-cli

  • 安装 jq: sudo apt install jq

  • 安装 mutt: sudo apt install mutt

  • 安装 bc: sudo apt install bc

  • 安装 curl: sudo apt install curl