├── .github └── workflows │ ├── main.yml │ └── release.yml ├── Dockerfile ├── README.md ├── appreciate.jpg ├── autMan.sh ├── docker-entrypoint.sh ├── install-autMan.sh ├── install.sh ├── middleware.js ├── middleware.php ├── middleware.py ├── middleware.sh ├── plugin └── golang │ └── go.mod ├── plugins └── test.js ├── qrcode2.png ├── qrcode3.jpg ├── qrcode4.jpg └── sendNotify.js /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build and Publish Docker Image 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | matrix: 12 | arch: [amd64] 13 | 14 | steps: 15 | - name: Checkout repository 16 | uses: actions/checkout@v3 17 | 18 | - name: Install jq 19 | run: sudo apt-get update && sudo apt-get install -y jq 20 | 21 | - name: Wait for a few seconds 22 | run: sleep 10 # 等待10秒钟,可以根据需要调整时间 23 | 24 | - name: Debug Info 25 | run: | 26 | echo "GITHUB_REPOSITORY: $GITHUB_REPOSITORY" 27 | echo "GITHUB_REF: $GITHUB_REF" 28 | 29 | - name: Download release .tar.gz 30 | run: | 31 | RELEASE_TAG=${GITHUB_REF#refs/tags/} 32 | echo "RELEASE_TAG: $RELEASE_TAG" 33 | RELEASE_URL=$(curl -s https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/tags/${RELEASE_TAG} | jq -r '.assets[] | select(.name | endswith("_${{ matrix.arch }}.tar.gz")) | .browser_download_url') 34 | echo "Release URL: $RELEASE_URL" 35 | if [ -z "$RELEASE_URL" ]; then 36 | echo "No release asset found for architecture: ${{ matrix.arch }}" 37 | exit 1 38 | fi 39 | curl -L $RELEASE_URL -o release_${{ matrix.arch }}.tar.gz 40 | 41 | - name: Create extraction directory 42 | run: mkdir -p ./app/autMan 43 | 44 | - name: Extract release .tar.gz 45 | run: tar -xzf release_${{ matrix.arch }}.tar.gz -C ./app/autMan --strip-components=1 46 | 47 | - name: Set up Docker Buildx 48 | uses: docker/setup-buildx-action@v2 49 | 50 | - name: Log in to Docker Hub 51 | uses: docker/login-action@v2 52 | with: 53 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 54 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 55 | 56 | - name: Extract version number from Git tag 57 | id: extract_version 58 | run: | 59 | RELEASE_VERSION=${GITHUB_REF#refs/tags/} 60 | echo "RELEASE_VERSION=${RELEASE_VERSION}" >> $GITHUB_ENV 61 | echo "Extracted RELEASE_VERSION: ${RELEASE_VERSION}" 62 | 63 | - name: Build Docker image 64 | run: | 65 | docker build --platform linux/${{ matrix.arch }} -t ${{ secrets.DOCKER_HUB_USERNAME }}/autman:${{ env.RELEASE_VERSION }}-${{ matrix.arch }} -f Dockerfile . 66 | docker tag ${{ secrets.DOCKER_HUB_USERNAME }}/autman:${{ env.RELEASE_VERSION }}-${{ matrix.arch }} ${{ secrets.DOCKER_HUB_USERNAME }}/autman:latest-${{ matrix.arch }} 67 | 68 | - name: Push Docker image 69 | run: | 70 | docker push ${{ secrets.DOCKER_HUB_USERNAME }}/autman:${{ env.RELEASE_VERSION }}-${{ matrix.arch }} 71 | docker push ${{ secrets.DOCKER_HUB_USERNAME }}/autman:latest-${{ matrix.arch }} 72 | 73 | - name: Create and push manifest 74 | if: matrix.arch == 'amd64' 75 | run: | 76 | docker manifest create ${{ secrets.DOCKER_HUB_USERNAME }}/autman:${{ env.RELEASE_VERSION }} \ 77 | ${{ secrets.DOCKER_HUB_USERNAME }}/autman:${{ env.RELEASE_VERSION }}-amd64 \ 78 | ${{ secrets.DOCKER_HUB_USERNAME }}/autman:${{ env.RELEASE_VERSION }}-arm64 79 | docker manifest push ${{ secrets.DOCKER_HUB_USERNAME }}/autman:${{ env.RELEASE_VERSION }} 80 | 81 | docker manifest create ${{ secrets.DOCKER_HUB_USERNAME }}/autman:latest \ 82 | ${{ secrets.DOCKER_HUB_USERNAME }}/autman:latest-amd64 \ 83 | ${{ secrets.DOCKER_HUB_USERNAME }}/autman:latest-arm64 84 | docker manifest push ${{ secrets.DOCKER_HUB_USERNAME }}/autman:latest 85 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Build and Publish Docker Image 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | build: 9 | # 指定使用 arm64 主机 10 | runs-on: [self-hosted, arm64] 11 | 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v3 15 | 16 | - name: Install jq 17 | run: sudo apt-get update && sudo apt-get install -y jq 18 | 19 | - name: Wait for a few seconds 20 | run: sleep 10 # 等待10秒钟,可以根据需要调整时间 21 | 22 | - name: Debug Info 23 | run: | 24 | echo "GITHUB_REPOSITORY: $GITHUB_REPOSITORY" 25 | echo "GITHUB_REF: $GITHUB_REF" 26 | 27 | - name: Download release .tar.gz 28 | run: | 29 | RELEASE_TAG=${GITHUB_REF#refs/tags/} 30 | echo "RELEASE_TAG: $RELEASE_TAG" 31 | RELEASE_URL=$(curl -s https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/tags/${RELEASE_TAG} | jq -r '.assets[] | select(.name | endswith("_arm64.tar.gz")) | .browser_download_url') 32 | echo "Release URL: $RELEASE_URL" 33 | if [ -z "$RELEASE_URL" ]; then 34 | echo "No release asset found for architecture: arm64" 35 | exit 1 36 | fi 37 | curl -L $RELEASE_URL -o release_arm64.tar.gz 38 | 39 | - name: Create extraction directory 40 | run: mkdir -p ./app/autMan 41 | 42 | - name: Extract release .tar.gz 43 | run: tar -xzf release_arm64.tar.gz -C ./app/autMan --strip-components=1 44 | 45 | - name: Set up Docker Buildx 46 | uses: docker/setup-buildx-action@v2 47 | 48 | - name: Log in to Docker Hub 49 | uses: docker/login-action@v2 50 | with: 51 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 52 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 53 | 54 | - name: Extract version number from Git tag 55 | id: extract_version 56 | run: | 57 | RELEASE_VERSION=${GITHUB_REF#refs/tags/} 58 | echo "RELEASE_VERSION=${RELEASE_VERSION}" >> $GITHUB_ENV 59 | echo "Extracted RELEASE_VERSION: ${RELEASE_VERSION}" 60 | 61 | - name: Build Docker image 62 | run: | 63 | docker build --platform linux/arm64 -t ${{ secrets.DOCKER_HUB_USERNAME }}/autman:${{ env.RELEASE_VERSION }}-arm64 -f Dockerfile . 64 | docker tag ${{ secrets.DOCKER_HUB_USERNAME }}/autman:${{ env.RELEASE_VERSION }}-arm64 ${{ secrets.DOCKER_HUB_USERNAME }}/autman:latest-arm64 65 | 66 | - name: Push Docker image 67 | run: | 68 | docker push ${{ secrets.DOCKER_HUB_USERNAME }}/autman:${{ env.RELEASE_VERSION }}-arm64 69 | docker push ${{ secrets.DOCKER_HUB_USERNAME }}/autman:latest-arm64 70 | 71 | - name: Create and push manifest 72 | run: | 73 | docker manifest create ${{ secrets.DOCKER_HUB_USERNAME }}/autman:${{ env.RELEASE_VERSION }} \ 74 | ${{ secrets.DOCKER_HUB_USERNAME }}/autman:${{ env.RELEASE_VERSION }}-arm64 75 | docker manifest push ${{ secrets.DOCKER_HUB_USERNAME }}/autman:${{ env.RELEASE_VERSION }} 76 | 77 | docker manifest create ${{ secrets.DOCKER_HUB_USERNAME }}/autman:latest \ 78 | ${{ secrets.DOCKER_HUB_USERNAME }}/autman:latest-arm64 79 | docker manifest push ${{ secrets.DOCKER_HUB_USERNAME }}/autman:latest 80 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ponycool/alpine-3.16 2 | 3 | WORKDIR /autMan 4 | 5 | # 安装基础库和依赖 6 | RUN mkdir /lib64 \ 7 | && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2 \ 8 | && ln -s /lib/libc.so.6 /usr/lib/libresolv.so.2 \ 9 | && apk add --no-cache libaio libnsl libc6-compat 10 | 11 | # 创建工作目录 12 | RUN mkdir /app 13 | 14 | # 安装各种工具和语言支持 15 | RUN apk update \ 16 | && apk add --no-cache curl jq wget tar ffmpeg python3 py3-pip icu-data-full nodejs npm php php-cli php-fpm php-mysqli php-json php-openssl php-curl go 17 | 18 | # 安装 Python 包 19 | RUN pip3 install --disable-pip-version-check --root-user-action=ignore requests PyExecJS aiohttp bs4 sseclient-py sseclient 20 | 21 | # 安装 Node.js 包 22 | RUN npm install --save axios request require crypto-js global-agent got@11 dotenv base-64 jquery node-rsa fs png-js cheerio MD5 md5 -g 23 | 24 | # 复制入口脚本和解压后的文件 25 | COPY ./docker-entrypoint.sh /bin/ 26 | COPY ./app/autMan /app/ 27 | 28 | # 设置golang环境变量 29 | ENV GO111MODULE=on \ 30 | GOPROXY=https://goproxy.cn \ 31 | NODE_PATH=/usr/local/lib/node_modules 32 | 33 | # 设置权限和安装 Golang 包 34 | RUN chmod a+x /bin/docker-entrypoint.sh \ 35 | && apk add --no-cache git bash ffmpeg \ 36 | && cd /app/autMan/plugin/scripts \ 37 | && go get -u github.com/hdbjlizhe/middleware \ 38 | && go get github.com/buger/jsonparser \ 39 | && go get github.com/gin-gonic/gin \ 40 | && go get github.com/gin-contrib/sse 41 | 42 | ENTRYPOINT ["/bin/docker-entrypoint.sh"] 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 见https://bbs.autman.cn 2 | -------------------------------------------------------------------------------- /appreciate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdbjlizhe/fanli/2136db764a67e743c32733de3ce1f68aea0d11ff/appreciate.jpg -------------------------------------------------------------------------------- /autMan.sh: -------------------------------------------------------------------------------- 1 | #/bin/bash 2 | LOG_FILE="/var/log/autMan.log" 3 | 4 | function log::info() { 5 | # 基础日志 6 | 7 | printf "[%s] \033[32mINFO: \033[0m%s\n" "$(date +'%Y-%m-%d %H:%M:%S')" "$*" | tee -a "$LOG_FILE" 8 | } 9 | 10 | function log::error() { 11 | # 错误日志 12 | 13 | local item 14 | printf "[$(date +'%Y-%m-%d %H:%M:%S')] \033[31mERROR: \033[0m$*\n" | tee -a "$LOG_FILE" 15 | 16 | } 17 | 18 | 19 | function utils::quote() { 20 | # 转义引号 21 | 22 | # shellcheck disable=SC2046 23 | if [ $(echo "$*" | tr -d "\n" | wc -c) -eq 0 ]; then 24 | echo "''" 25 | elif [ $(echo "$*" | tr -d "[a-z][A-Z][0-9]:,.=~_/\n-" | wc -c) -gt 0 ]; then 26 | printf "%s" "$*" | sed -e "1h;2,\$H;\$!d;g" -e "s/'/\'\"\'\"\'/g" | sed -e "1h;2,\$H;\$!d;g" -e "s/^/'/g" -e "s/$/'/g" 27 | else 28 | echo "$*" 29 | fi 30 | } 31 | function check::exit_code() { 32 | # 检查返回码 33 | 34 | local code=${1:-} 35 | local app=${2:-} 36 | local desc=${3:-} 37 | local exit_script=${4:-} 38 | 39 | if [[ "${code}" == "0" ]]; then 40 | log::info "[${app}]" "${desc} succeeded." 41 | else 42 | log::error "[${app}]" "${desc} failed." 43 | [[ "$exit_script" == "exit" ]] && exit "$code" 44 | fi 45 | } 46 | 47 | function command::exec() { 48 | local command="$*" 49 | command="$(utils::quote "$command")" 50 | 51 | # 本地执行 52 | # log::info "[command]" "bash -c $(printf "%s" "${command//${SUDO_PASSWORD:-}/******}")" 53 | # shellcheck disable=SC2094 54 | COMMAND_OUTPUT=$(eval bash -c "${command}" 2>>"$LOG_FILE" | tee -a "$LOG_FILE") 55 | local status=$? 56 | return $status 57 | } 58 | 59 | function install::Debian_Ubuntu(){ 60 | # Debian 安装命令 61 | log::info "[apt]" "apt update and download python" 62 | command::exec "apt update -y && apt install -y wget python3 python3-pip" 63 | check::exit_code "$?" "apt" "apt install python" "exit" 64 | 65 | # if [ ! -f "~/.pip/pip.conf" ]; then 66 | # mkdir -p ~/.pip 67 | # echo "[global]" >> ~/.pip/pip.conf 68 | # echo "index-url = https://pypi.tuna.tsinghua.edu.cn/simple" >> ~/.pip/pip.conf 69 | # fi 70 | 71 | log::info "[pip3]" "pip3 dependency installation" 72 | command::exec "pip3 install requests user_agent PyExecJS aiohttp -i https://pypi.tuna.tsinghua.edu.cn/simple" 73 | check::exit_code "$?" "pip3" "pip3 install" "exit" 74 | 75 | 76 | log::info "[node]" "node install" 77 | command::exec "curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash - && apt install -y nodejs" 78 | check::exit_code "$?" "node" "node install" "exit" 79 | 80 | 81 | log::info "[node]" "node dependency installation" 82 | command::exec "npm install axios request require crypto-js" 83 | check::exit_code "$?" "node" "node dependency install" "exit" 84 | # log::info "[php]" "php install " 85 | # command::exec "apt-get install -y php" 86 | # check::exit_code "$?" "php" "php install" "exit" 87 | } 88 | function install::CentOS_Oracle(){ 89 | log::info "[yum]" "yum update and download python" 90 | command::exec "yum update -y && yum install -y wget python3 python3-pip" 91 | check::exit_code "$?" "yum" "yum install python" "exit" 92 | 93 | # if [ ! -f "~/.pip/pip.conf" ]; then 94 | # mkdir -p ~/.pip 95 | # echo "[global]" >> ~/.pip/pip.conf 96 | # echo "index-url = https://pypi.tuna.tsinghua.edu.cn/simple" >> ~/.pip/pip.conf 97 | # fi 98 | 99 | log::info "[pip3]" "pip3 dependency installation" 100 | command::exec "pip3 install requests user_agent PyExecJS aiohttp -i https://pypi.tuna.tsinghua.edu.cn/simple" 101 | check::exit_code "$?" "pip3" "pip3 install" "exit" 102 | 103 | 104 | log::info "[node]" "node install" 105 | command::exec "curl -fsSL https://rpm.nodesource.com/setup_16.x | sudo -E bash - && yum install -y nodejs" 106 | check::exit_code "$?" "node" "node install" "exit" 107 | 108 | log::info "[node]" "node dependency installation" 109 | command::exec "npm install axios request require crypto-js" 110 | check::exit_code "$?" "node" "node dependency install" "exit" 111 | # log::info "[php]" "php install " 112 | # command::exec "yum install -y php" 113 | # check::exit_code "$?" "php" "php install" "exit" 114 | } 115 | 116 | function install::anuMan(){ 117 | arch=$(uname -m) 118 | if [ "$arch" == "x86_64" ]; then 119 | a=amd64 120 | elif [ "$arch" == "aarch64" ]; then 121 | a=arm64 122 | fi 123 | latest_version=$(curl -s "https://ghproxy.homeboyc.cn/https://api.github.com/repos/hdbjlizhe/fanli/releases/latest" | grep -oP '"tag_name": "\K.*?(?=")') 124 | command::exec "mkdir -p /root/autMan 125 | cd /root/antMan 126 | wget http://gh.301.ee/https://github.com/hdbjlizhe/fanli/releases/download/$latest_version/autMan_$a.tar.gz; 127 | tar -zxvf autMan_$a.tar.gz -C /root/autMan; 128 | rm -rf autMan_$a.tar.gz 129 | chmod 777 /root/autMan/autMan 130 | pkill -9 /root/antMan/antMan 131 | /root/autMan/autMan -d" 132 | check::exit_code "$?" "anuMan install" 133 | 134 | } 135 | function main(){ 136 | echo -e "\033[1;3$((RANDOM%10%8))m 137 | 138 | █████╗ ██╗ ██╗████████╗███╗ ███╗ █████╗ ███╗ ██╗ 139 | ██╔══██╗██║ ██║╚══██╔══╝████╗ ████║██╔══██╗████╗ ██║ 140 | ███████║██║ ██║ ██║ ██╔████╔██║███████║██╔██╗ ██║ 141 | ██╔══██║██║ ██║ ██║ ██║╚██╔╝██║██╔══██║██║╚██╗██║ 142 | ██║ ██║╚██████╔╝ ██║ ██║ ╚═╝ ██║██║ ██║██║ ╚████║ 143 | ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝ \033[0m" 144 | 145 | echo 146 | echo "有问题请带上日志文件联系作者,路径为:$LOG_FILE" 147 | echo 148 | os=$(grep -oP 'NAME=["]?([^"]+)' /etc/os-release | awk -F= '{print $2}' | tr -d '"' | head -1) 149 | if [[ ! "$os" ]]; then 150 | log::error "获取系统信息错误" 151 | exit 152 | else 153 | log::info "获取系统信息" "$os" 154 | fi 155 | log::info "开始安装基础环境" 156 | if [[ $os == *"Debian"* ]] || [[ $os == *"Ubuntu"* ]]; then 157 | install::Debian_Ubuntu 158 | 159 | elif [[ $os == *"CentOS"* ]] || [[ $os==*"Oracle"* ]]; then 160 | install::CentOS_Oracle 161 | fi 162 | 163 | log::info "开始安装AutMan" 164 | install::anuMan 165 | 166 | ps aux | grep autMan | grep -v grep 2>&1 > /dev/null 167 | if [ $? == 0 ];then 168 | log::info "autMan运行成功" 169 | else 170 | log::error "autMan运行失败,请手动运行" 171 | fi 172 | echo 173 | cat << EOF 174 | 安装路径:/root/autMan 175 | 运行命令:/root/autMan/autMan 前台运行 -t 交互运行 -d 后台默认运行 176 | EOF 177 | 178 | } 179 | 180 | main -------------------------------------------------------------------------------- /docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 代码目录 4 | if [ -z $CODE_DIR ]; then 5 | CODE_DIR=/autMan 6 | fi 7 | 8 | # 代码目录不存在则拷贝 9 | if [ ! -f $CODE_DIR/autMan ]; then 10 | echo "autMan 不存在" 11 | cp -n -r /app/autMan/* /autMan 12 | else 13 | echo "autMan 存在" 14 | fi 15 | 16 | # 进入代码目录 17 | chmod 777 $CODE_DIR 18 | cd $CODE_DIR 19 | echo -e "=================== 如果第一次配置机器人,请先配置机器人 ===================" 20 | echo "启动" 21 | chmod 777 autMan 22 | ./autMan -------------------------------------------------------------------------------- /install-autMan.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 获取系统信息 4 | os=$(awk -F= '/^NAME/{print $2}' /etc/os-release) 5 | os=${os//\"/} 6 | 7 | # 判断系统类型并执行相应的安装命令 8 | if [[ $os == *"Debian"* ]] || [[ $os == *"Ubuntu"* ]]; then 9 | # Debian 安装命令 10 | echo "Installing Python 3 and pip on Debian..." 11 | sudo apt update 12 | sudo apt install -y python3 python3-pip 13 | pip3 install requests 14 | 15 | echo "Installing Node.js on Debian..." 16 | curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash - 17 | sudo apt install -y nodejs 18 | sudo npm install axios 19 | 20 | echo "Installing PHP on Debian..." 21 | sudo apt install -y php 22 | 23 | elif [[ $os == *"CentOS"* ]] || [[ $os==*"Oracle"* ]]; then 24 | # CentOS 安装命令 25 | echo "Installing Python 3 and pip on CentOS..." 26 | sudo yum install -y epel-release 27 | sudo yum install -y python3 python3-pip 28 | pip3 install requests 29 | 30 | echo "Installing Node.js on CentOS..." 31 | curl -sL https://rpm.nodesource.com/setup_16.x | sudo bash - 32 | sudo yum install -y nodejs 33 | npm install axios 34 | 35 | echo "Installing PHP on CentOS..." 36 | sudo yum install -y php 37 | 38 | elif [[ $os == *"OpenWrt"* ]]; then 39 | # OpenWrt 安装命令 40 | echo "Installing Python 3 and pip on OpenWrt..." 41 | opkg update 42 | opkg install python3 python3-pip 43 | pip3 install requests 44 | 45 | echo "Installing Node.js on OpenWrt..." 46 | opkg install node 47 | npm install axios 48 | 49 | echo "Installing PHP on OpenWrt..." 50 | opkg install php7 51 | else 52 | echo "Unsupported operating system: $os" 53 | exit 1 54 | fi 55 | 56 | echo "Installation completed." 57 | 58 | # GitHub 59 | repo_owner="hdbjlizhe" 60 | repo_name="fanli" 61 | 62 | # 发送 API 请求获取最新发布信息 63 | response=$(curl -s "https://api.github.com/repos/$repo_owner/$repo_name/releases/latest") 64 | 65 | # 解析 JSON 响应,提取最新版本号 66 | latest_version=$(echo "$response" | grep -oP '"tag_name": "\K.*?(?=")') 67 | 68 | # 输出最新版本号 69 | echo "Latest version of $repo_owner/$repo_name: $latest_version" 70 | if [ ! "$latest_version" ];then 71 | exit; 72 | fi; 73 | 74 | 75 | s=autMan; 76 | a=arm64; 77 | if [[ $(uname -a | grep "x86_64") != "" ]];then 78 | a=amd64; 79 | fi; 80 | echo "创建文件夹$s" 81 | if [ ! -d $s ];then 82 | mkdir $s; 83 | fi; 84 | cd $s; 85 | wget https://github.com/hdbjlizhe/fanli/releases/download/$latest_version/autMan_$a.tar.gz; 86 | tar -zxvf autMan_$a.tar.gz; 87 | rm -rf autMan_$a.tar.gz; 88 | chmod 777 $s; 89 | pkill -9 $s; 90 | $(pwd)/$s -t; 91 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | color(){ 3 | green='\e[1;32m' 4 | res='\e[0m' 5 | yellow='\e[1;33m' 6 | echo -e ${green} 7 | clear 8 | } 9 | 10 | hello(){ 11 | #!/bin/sh 12 | echo "检查系统..." 13 | check_centos=`cat /etc/redhat-release` 14 | check=`uname -a` 15 | os=debian 16 | cpu=arm64; 17 | if [[ $check_centos =~ "CentOS" ]]; 18 | then os="centos" 19 | fi 20 | if [[ $check =~ "ubuntu" ]]; 21 | then os="ubuntu" 22 | fi 23 | if [[ $check =~ "x86_64" ]]; then 24 | cpu="amd64" 25 | fi 26 | echo "当前系统为:" $os 27 | echo "当前架构为:" $cpu 28 | sleep 3s 29 | } 30 | change(){ 31 | if [[ "$os" == "debian" && "$cpu" == "amd64" ]];then 32 | apt-get install wget git tar -y 33 | url=https://dl.golang.com.cn/dl/go/go1.18.linux-amd64.tar.gz 34 | wget $url 35 | tar -C /usr/local -xzf go1.18.linux-amd64.tar.gz 36 | elif [[ "$os" == "centos" && "$cpu" == "amd64" ]];then 37 | yum install wget git openssl openssl-devel gcc make perl tar -y 38 | url=https://dl.golang.com.cn/dl/go/go1.18.linux-amd64.tar.gz 39 | wget $url 40 | tar -C /usr/local -xzf go1.18.linux-amd64.tar.gz 41 | elif [[ $cpu == "arm64" ]];then 42 | apt-get install wget git tar -y 43 | url=https://dl.golang.com.cn/dl/go/go1.18.linux-arm64.tar.gz 44 | wget $url 45 | tar -C /usr/local -xzf go1.18.linux-arm64.tar.gz 46 | else 47 | exit 1 48 | fi 49 | } 50 | 51 | maingo(){ 52 | color 53 | GO111MODULE=on 54 | GOPROXY=https://goproxy.cn 55 | GOROOT=/usr/local/go 56 | GOPATH=/usr/local/go/path 57 | #GOBIN=/root/go/bin 58 | PATH=$PATH:$GOROOT/bin:$GOPATH/bin 59 | export GO111MODULE=on 60 | export GOPROXY=https://goproxy.cn 61 | export GOROOT=/usr/local/go 62 | export GOPATH=/usr/local/go/path 63 | export PATH=$PATH:$GOROOT/bin:$GOPATH/bin 64 | 65 | command='cat /etc/profile|grep $ GOROOT' 66 | if [-n "$command"];then 67 | echo -e ${yellow} 68 | echo -e ${res} 69 | sillyGirl 70 | exit 1 71 | else 72 | hello 73 | change 74 | #mkdir $HOME/go $HOME/go/src 75 | echo "export GOROOT=${GOROOT}">>/etc/profile 76 | echo "export GOPATH=${GOPATH}">>/etc/profile 77 | echo "export GO111MODULE=on" >>/etc/profile 78 | echo "export GOPROXY=https://goproxy.cn" >>/etc/profile 79 | echo "export PATH=${PATH}">>/etc/profile 80 | . $HOME/.profile 81 | echo -e ${green} 82 | sleep 3s 83 | echo "Go安装完成" 84 | echo -e ${res} 85 | sleep 10s 86 | sillyGirl 87 | fi 88 | } 89 | maingo() 90 | -------------------------------------------------------------------------------- /middleware.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | const url = "http://localhost:9999/otto" 3 | /** 4 | * 获取本地服务响应 5 | * @param {string} path 本地服务路由 6 | * @param {number} timeout 超时时间 7 | * @example 8 | */ 9 | async function accessLocalService(path, timeout) { 10 | try { 11 | const response = await Promise.race([ 12 | axios.get(url + path), 13 | new Promise((_, reject) => 14 | setTimeout(() => reject(new Error('Request timeout')), timeout) 15 | ) 16 | ]); 17 | return response.data; 18 | } catch (error) { 19 | console.error('Error fetching response:', error); 20 | throw error; 21 | } 22 | } 23 | 24 | 25 | // 获取发送者ID 26 | function getSenderID() { 27 | console.log(process.argv); 28 | const arg = process.argv[1]; 29 | return arg 30 | } 31 | 32 | // 推送消息 33 | function push(imType, groupCode, userID, title, content) { 34 | return accessLocalService(`/push?imtype=${imType}&groupcode=${groupCode}&userid=${userID}&title=${title}&content=${content}`, 5000,); 35 | } 36 | 37 | // 获取机器人名称 38 | function name() { 39 | return accessLocalService(`/name`, 5000); 40 | } 41 | 42 | // 获取机器id 43 | function machineId() { 44 | return accessLocalService(`/machineId`, 5000); 45 | } 46 | 47 | // 获取机器人版本 48 | function version() { 49 | return accessLocalService(`/version`, 5000); 50 | } 51 | 52 | // 获取数据库数据 53 | function get(key) { 54 | return accessLocalService(`/get?key=${key}`, 5000); 55 | } 56 | 57 | // 设置数据库数据 58 | function set(key, value) { 59 | return accessLocalService(`/set?key=${key}&value=${value}`, 5000); 60 | } 61 | 62 | // 删除数据库数据 63 | function del(key) { 64 | return accessLocalService(`/del?key=${key}`, 5000); 65 | } 66 | 67 | // 获取指定数据库指定的key值 68 | function bucketGet(bucket, key) { 69 | return accessLocalService(`/bucketGet?bucket=${bucket}&key=${key}`, 5000); 70 | } 71 | 72 | // 设置指定数据库指定的key值 73 | function bucketSet(bucket, key, value) { 74 | return accessLocalService(`/bucketSet?bucket=${bucket}&key=${key}&value=${value}`, 5000); 75 | } 76 | 77 | // 删除指定数据库指定key的值 78 | function bucketDel(bucket, key) { 79 | return accessLocalService(`/bucketDel?bucket=${bucket}&key=${key}`, 5000); 80 | } 81 | 82 | // 获取指定数据库所有值为value的keys 83 | function bucketKeys(bucket, value) { 84 | keys = accessLocalService(`/bucketKeys?bucket=${bucket}&value=${value}`, 5000); 85 | return keys.split(","); 86 | } 87 | 88 | // 获取指定数据桶内所有的key集合 89 | function bucketAllKeys(bucket) { 90 | keys = accessLocalService(`/bucketAllKeys?bucket=${bucket}`, 5000); 91 | return keys.split(","); 92 | } 93 | 94 | // 通知管理员 95 | function notifyMasters(content, imtypes) { 96 | return accessLocalService(`/notifyMasters?content=${content}&imtypes=${imtypes}`, 5000); 97 | } 98 | 99 | // 当前系统咖啡码激活状态 100 | function coffee() { 101 | return accessLocalService(`/coffee`, 5000); 102 | } 103 | 104 | // 京东、淘宝、拼多多转链推广 105 | function spread(msg) { 106 | return accessLocalService(`/spread?msg=${msg}`, 5000); 107 | } 108 | 109 | class Sender { 110 | constructor(senderID) { 111 | // 发送者ID,格式:in64时间戳, 112 | this.senderID = senderID; 113 | 114 | // 获取发送者渠道 115 | this.getImtype = function () { 116 | accessLocalService(`/getImtype?senderid=${senderID}`, 5000); 117 | } 118 | 119 | // 获取当前用户id 120 | this.getUserID = function () { 121 | return accessLocalService(`/getUserID?senderid=${senderID}`, 5000); 122 | } 123 | 124 | // 获取当前用户名 125 | this.getUserName = function () { 126 | return accessLocalService(`/getUserName?senderid=${senderID}`, 5000); 127 | } 128 | 129 | // 获取用户头像url 130 | this.getUserAvatarUrl = function () { 131 | return accessLocalService(`/getUserAvatarUrl?senderid=${senderID}`, 5000); 132 | } 133 | 134 | // 获取当前群组id 135 | this.getGroupID = function () { 136 | return accessLocalService(`/getGroupID?senderid=${senderID}`, 5000); 137 | } 138 | 139 | // 获取当前群组名称 140 | this.getGroupName = function () { 141 | return accessLocalService(`/getGroupName?senderid=${senderID}`, 5000); 142 | } 143 | 144 | // 是否管理员 145 | this.isAdmin = function () { 146 | return "true" == accessLocalService(`/isAdmin?senderid=${senderID}`, 5000); 147 | } 148 | 149 | // 获取消息 150 | this.getMessage = function () { 151 | return accessLocalService(`/getMessage?senderid=${senderID}`, 5000); 152 | } 153 | 154 | // 获取消息ID 155 | this.getMessageID = function () { 156 | return accessLocalService(`/getMessageID?senderid=${senderID}`, 5000); 157 | } 158 | 159 | // 撤回消息 160 | this.recallMessage = function (messageid) { 161 | accessLocalService(`/recallMessage?senderid=${senderID}&id=${messageid}`, 5000); 162 | } 163 | 164 | 165 | // 获取匹配的文本参数 166 | this.param = function (index) { 167 | return accessLocalService(`/param?senderid=${senderID}&index=${index}`, 5000); 168 | } 169 | 170 | // 回复文本消息 171 | this.reply = function (text) { 172 | accessLocalService(`/sendText?senderid=${senderID}&text=${text}`, 5000); 173 | } 174 | 175 | // 回复图片消息 176 | this.replyImage = function (imageUrl) { 177 | accessLocalService(`/sendImage?senderid=${senderID}&imageurl=${imageUrl}`, 5000); 178 | } 179 | 180 | // 回复语音消息 181 | this.replyVoice = function (voiceUrl) { 182 | accessLocalService(`/sendVoice?senderid=${senderID}&voiceurl=${voiceUrl}`, 5000); 183 | } 184 | 185 | // 回复视频消息 186 | this.replyVideo = function (videoUrl) { 187 | accessLocalService(`/sendVideo?senderid=${senderID}&videourl=${videoUrl}`, 5000); 188 | } 189 | 190 | //等待用户输入 191 | this.listen = function (timeout) { 192 | accessLocalService(`/listen?senderid=${senderID}&timeout=${timeout}`, timeout); 193 | } 194 | 195 | //等待支付 196 | this.waitPay = function (exitcode,timeout) { 197 | accessLocalService(`/waitPay?senderid=${senderID}&exitcode=${exitcode}&timeout=${timeout}`, timeout); 198 | } 199 | 200 | //是否处于等待支付状态 201 | this.atWaitPay = function () { 202 | return "true" == accessLocalService(`/atWaitPay`, 5000); 203 | } 204 | 205 | //邀请入群 206 | this.groupInviteIn = function (friend,group) { 207 | accessLocalService(`/groupInviteIn?senderid=${senderID}&friend=${friend}&group=${group}`, 5000); 208 | } 209 | 210 | //踢群 211 | this.groupKick = function (userid) { 212 | accessLocalService(`/groupKick?senderid=${senderID}&userid=${userid}`, 5000); 213 | } 214 | 215 | //禁言 216 | this.groupBan = function (userid,timeout) { 217 | accessLocalService(`/groupBan?senderid=${senderID}&userid=${userid}&timeout=${timeout}`, 5000); 218 | } 219 | 220 | //解除禁言 221 | this.groupUnban = function (userid) { 222 | accessLocalService(`/groupUnban?senderid=${senderID}&userid=${userid}`, 5000); 223 | } 224 | 225 | //全员禁言 226 | this.groupWholeBan=function(){ 227 | accessLocalService(`/groupWholeBan?senderid=${senderID}`, 5000); 228 | } 229 | 230 | //解除全员禁言 231 | this.groupWholeUnban=function(){ 232 | accessLocalService(`/groupWholeUnban?senderid=${senderID}`, 5000); 233 | } 234 | 235 | //发送群公告 236 | this.groupNoticeSend=function(notice){ 237 | accessLocalService(`/groupNoticeSend?senderid=${senderID}¬ice=${notice}`, 5000); 238 | } 239 | 240 | //获取当前处理流程的插件名 241 | this.getPluginName = function () { 242 | return accessLocalService(`/getPluginName?senderid=${senderID}`, 5000); 243 | } 244 | 245 | //获取当前处理流程的插件版本 246 | this.getPluginVersion = function () { 247 | return accessLocalService(`/getPluginVersion?senderid=${senderID}`, 5000); 248 | } 249 | 250 | }; 251 | } 252 | 253 | module.exports = { 254 | Sender, 255 | getSenderID: getSenderID, 256 | push: push, 257 | name: name, 258 | machineId: machineId, 259 | version: version, 260 | get: get, 261 | set: set, 262 | del: del, 263 | bucketGet: bucketGet, 264 | bucketSet: bucketSet, 265 | bucketDel: bucketDel, 266 | bucketKeys: bucketKeys, 267 | bucketAllKeys: bucketAllKeys, 268 | notifyMasters: notifyMasters, 269 | coffee: coffee, 270 | spread: spread, 271 | } 272 | -------------------------------------------------------------------------------- /middleware.php: -------------------------------------------------------------------------------- 1 | senderID = $senderid; 117 | } 118 | // 获取发送者类型 119 | public function getImtype(){ 120 | $path="/getImtype?id=".$this->id; 121 | return fetchLocalURL($path, 5); 122 | } 123 | // 获取发送者ID 124 | public function getUserID(){ 125 | $path="/getUserID?senderid=".$this->senderID; 126 | return fetchLocalURL($path, 5); 127 | } 128 | // 获取发送者名称 129 | public function getUserName(){ 130 | $path="/getUserName?senderid=".$this->senderID; 131 | return fetchLocalURL($path, 5); 132 | } 133 | // 获取发送者头像 134 | public function getUserAvatarUrl(){ 135 | $path="/getUserAvatarUrl?senderid=".$this->senderID; 136 | return fetchLocalURL($path, 5); 137 | } 138 | // 获取当前群组ID 139 | public function getGroupID(){ 140 | $path="/getGroupID?senderid=".$this->senderID; 141 | return fetchLocalURL($path, 5); 142 | } 143 | // 获取当前群组名称 144 | public function getGroupName(){ 145 | $path="/getGroupName?senderid=".$this->senderID; 146 | return fetchLocalURL($path, 5); 147 | } 148 | // 是否管理员 149 | public function isAdmin(){ 150 | $path="/isAdmin?senderid=".$this->senderID; 151 | return "true"==fetchLocalURL($path, 5); 152 | } 153 | // 获取消息id 154 | public function getMessageID(){ 155 | $path="/getMessageID?senderid=".$this->senderID; 156 | return fetchLocalURL($path, 5); 157 | } 158 | // 撤回消息 159 | public function recallMessage($messageID){ 160 | $path="/recallMessage?senderid=".$this->senderID."&id=".$messageID; 161 | return fetchLocalURL($path, 5); 162 | } 163 | // 获取匹配的文本参数 164 | public function param($index){ 165 | $path="/param?senderid=".$this->senderID."&index=".$index; 166 | return fetchLocalURL($path, 5); 167 | } 168 | // 回复文本消息 169 | public function reply($text){ 170 | $path="/sendText?senderid=".$this->senderID."&text=".$text; 171 | return fetchLocalURL($path, 5); 172 | } 173 | // 回复图片消息 174 | public function replyImage($imageUrl){ 175 | $path="/sendImage?senderid=".$this->senderID."&imageurl=".$imageUrl; 176 | return fetchLocalURL($path, 5); 177 | } 178 | // 回复语音消息 179 | public function replyVoice($voiceUrl){ 180 | $path="/sendVoice?senderid=".$this->senderID."&voiceurl=".$voiceUrl; 181 | return fetchLocalURL($path, 5); 182 | } 183 | // 回复视频消息 184 | public function replyVideo($videoUrl){ 185 | $path="/sendVideo?senderid=".$this->senderID."&videourl=".$videoUrl; 186 | return fetchLocalURL($path, 5); 187 | } 188 | // 等待用户输入 189 | public function listen($timeout){ 190 | $path="/listen?senderid=".$this->senderID."&timeout=".$timeout; 191 | $response= fetchLocalURL($path, 5); 192 | //返回response的文本部分 193 | echo $response; 194 | return responseText($response); 195 | } 196 | // 等待支付 197 | public function waitPay($exitcode,$timeout){ 198 | $path="/waitPay?senderid=".$this->senderID."&exitcode=".$exitcode."&timeout=".$timeout; 199 | $response= fetchLocalURL($path, 5); 200 | //返回response的文本部分 201 | echo $response; 202 | return responseText($response); 203 | } 204 | // 是否处于等待支付状态 205 | public function atWaitPay(){ 206 | $path="/atWaitPay"; 207 | return "true"==fetchLocalURL($path, 5); 208 | } 209 | // 添加好友至群聊 210 | public function groupInviteIn($friendID,$groupID){ 211 | $path="/groupInviteIn?senderid=".$this->senderID."&friendid=".$friendID."&groupid=".$groupID; 212 | return fetchLocalURL($path, 5); 213 | } 214 | // 从群聊中移除好友 215 | public function groupKick($userid){ 216 | $path="/groupKick?senderid=".$this->senderID."&userid=".$userid; 217 | return fetchLocalURL($path, 5); 218 | } 219 | // 群聊禁言 220 | public function groupBan($userid,$time){ 221 | $path="/groupBan?senderid=".$this->senderID."&userid=".$userid."&time=".$time; 222 | return fetchLocalURL($path, 5); 223 | } 224 | // 群聊解除禁言 225 | public function groupUnban($userid){ 226 | $path="/groupUnban?senderid=".$this->senderID."&userid=".$userid; 227 | return fetchLocalURL($path, 5); 228 | } 229 | // 全员禁言 230 | public function groupWholeBan($time){ 231 | $path="/groupWholeBan?senderid=".$this->senderID."&time=".$time; 232 | return fetchLocalURL($path, 5); 233 | } 234 | 235 | // 全员解除禁言 236 | public function groupWholeUnban(){ 237 | $path="/groupWholeUnban?senderid=".$this->senderID; 238 | return fetchLocalURL($path, 5); 239 | } 240 | 241 | // 发送群公告 242 | public function groupNoticeSend($notice){ 243 | $path="/groupNoticeSend?senderid=".$this->senderID."¬ice=".$notice; 244 | return fetchLocalURL($path, 5); 245 | } 246 | 247 | // 获取当前处理流程的插件名 248 | public function getPluginName(){ 249 | $path="/getPluginName?senderid=".$this->senderID; 250 | return fetchLocalURL($path, 5); 251 | } 252 | // 获取当前处理流程的插件版本 253 | public function getPluginVersion(){ 254 | $path="/getPluginVersion?senderid=".$this->senderID; 255 | return fetchLocalURL($path, 5); 256 | } 257 | } 258 | ?> -------------------------------------------------------------------------------- /middleware.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import sys 3 | 4 | # 本地服务的请求 5 | def get_local_service_response(path,params): 6 | print("网络请求") 7 | url = "http://localhost:9999/otto"+path 8 | response = requests.get(url, params) 9 | print(response.text) 10 | return response 11 | 12 | # 获取发送者ID 13 | def getSenderID(): 14 | return sys.argv[1] 15 | 16 | # 推送消息 17 | def push(imType,groupCode,userID,title,content): 18 | path="/push" 19 | params={ 20 | "imType":imType, 21 | "groupCode":groupCode, 22 | "userID":userID, 23 | "title":title, 24 | "content":content 25 | } 26 | get_local_service_response(path,params) 27 | 28 | # 获取机器人名称 29 | def name(): 30 | path="/name" 31 | params={} 32 | response=get_local_service_response(path,params) 33 | return response.text 34 | 35 | # 获取机器id 36 | def machineId(): 37 | path="/machineId" 38 | params={} 39 | response=get_local_service_response(path,params) 40 | return response.text 41 | 42 | # 获取autMan版本 43 | def version(): 44 | path="/version" 45 | params={} 46 | response=get_local_service_response(path,params) 47 | return response.text 48 | 49 | # 获取数据库数据 50 | def get(key): 51 | path="/get" 52 | params={ 53 | "key":key 54 | } 55 | response=get_local_service_response(path,params) 56 | return response.text 57 | 58 | # 设置数据库数据 59 | def set(key,value): 60 | path="/set" 61 | params={ 62 | "key":key, 63 | "value":value 64 | } 65 | response=get_local_service_response(path,params) 66 | return response.text 67 | 68 | # 删除数据库数据 69 | def delete(key): 70 | path="/delete" 71 | params={ 72 | "key":key 73 | } 74 | response=get_local_service_response(path,params) 75 | return response.text 76 | 77 | # 获取指定数据库指定key的值 78 | def bucketGet(bucket,key): 79 | path="/bucketGet" 80 | params={ 81 | "bucket":bucket, 82 | "key":key 83 | } 84 | response=get_local_service_response(path,params) 85 | return response.text 86 | 87 | # 设置指定数据库指定key的值 88 | def bucketSet(bucket,key,value): 89 | path="/bucketSet" 90 | params={ 91 | "bucket":bucket, 92 | "key":key, 93 | "value":value 94 | } 95 | response=get_local_service_response(path,params) 96 | return response.text 97 | 98 | # 删除指定数据库指定key的值 99 | def bucketDelete(bucket,key): 100 | path="/bucketDelete" 101 | params={ 102 | "bucket":bucket, 103 | "key":key 104 | } 105 | response=get_local_service_response(path,params) 106 | return response.text 107 | 108 | # 获取指定数据库的所有什为value的keys 109 | def bucketKeys(bucket,value): 110 | path="/bucketKeys" 111 | params={ 112 | "bucket":bucket, 113 | "value":value 114 | } 115 | response=get_local_service_response(path,params) 116 | # 使用逗号分隔字符串 117 | return response.text.split(",") 118 | 119 | # 获取指定数据库的所有的key集合 120 | def bucketAllKeys(bucket): 121 | path="/bucketAllKeys" 122 | params={ 123 | "bucket":bucket 124 | } 125 | response=get_local_service_response(path,params) 126 | # 使用逗号分隔字符串 127 | return response.text.split(",") 128 | 129 | # 通知管理员 130 | def notifyMasters(content,imtypes): 131 | path="/notifyMasters" 132 | params={ 133 | "content":content, 134 | "imtypes":",".join(imtypes), 135 | } 136 | get_local_service_response(path,params) 137 | 138 | # 当前系统咖啡码激活状态 139 | def coffee(): 140 | path="/coffee" 141 | params={} 142 | response=get_local_service_response(path,params) 143 | return response.text=="true" 144 | 145 | # 京东、淘宝、拼多多转链推广 146 | def spread(msg): 147 | path="/spread" 148 | params={ 149 | "msg":msg 150 | } 151 | response=get_local_service_response(path,params) 152 | return response.text 153 | 154 | class Sender: 155 | # 类的构造函数 156 | def __init__(self, senderID): 157 | self.senderID = senderID 158 | 159 | # 获取发送者渠道 160 | def getImtype(self): 161 | path="/getImtype" 162 | params={ 163 | "senderid":self.senderID 164 | } 165 | response=get_local_service_response(path,params) 166 | return response.text 167 | 168 | # 获取发送者ID 169 | def getUserID(self): 170 | path="/getUserID" 171 | params={ 172 | "senderid":self.senderID 173 | } 174 | response=get_local_service_response(path,params) 175 | return response.text 176 | 177 | # 获取发送者昵称 178 | def getUserName(self): 179 | path="/getUserName" 180 | params={ 181 | "senderid":self.senderID 182 | } 183 | response=get_local_service_response(path,params) 184 | return response.text 185 | 186 | # 获取发送者头像 187 | def getUserAvatarUrl(self): 188 | path="/getUserAvatarUrl" 189 | params={ 190 | "senderid":self.senderID 191 | } 192 | response=get_local_service_response(path,params) 193 | return response.text 194 | 195 | # 获取发送者群号 196 | def getChatID(self): 197 | path="/getChatID" 198 | params={ 199 | "senderid":self.senderID 200 | } 201 | response=get_local_service_response(path,params) 202 | return response.text 203 | 204 | # 获取发送者群名称 205 | def getChatName(self): 206 | path="/getChatName" 207 | params={ 208 | "senderid":self.senderID 209 | } 210 | response=get_local_service_response(path,params) 211 | return response.text 212 | 213 | # 是否管理员 214 | def isAdmin(self): 215 | path="/isAdmin" 216 | params={ 217 | "senderid":self.senderID 218 | } 219 | response=get_local_service_response(path,params) 220 | return response.text=="true" 221 | 222 | # 获取消息 223 | def getMessage(self): 224 | path="/getMessage" 225 | params={ 226 | "senderid":self.senderID 227 | } 228 | response=get_local_service_response(path,params) 229 | return response.text 230 | 231 | # 获取消息ID 232 | def getMessageID(self): 233 | path="/getMessageID" 234 | params={ 235 | "senderid":self.senderID 236 | } 237 | response=get_local_service_response(path,params) 238 | return response.text 239 | 240 | # 撤回消息 241 | def recallMessage(self,messageid): 242 | path="/recallMessage" 243 | params={ 244 | "senderid":self.senderID, 245 | "messageid":messageid 246 | } 247 | get_local_service_response(path,params) 248 | 249 | # 获取匹配的文本参数 250 | def param(self,i): 251 | path="/param" 252 | params={ 253 | "senderid":self.senderID, 254 | "index":i 255 | } 256 | response=get_local_service_response(path,params) 257 | return response.text 258 | 259 | # 回复文本消息 260 | def reply(self,text): 261 | path="/sendText" 262 | params={ 263 | "senderid":self.senderID, 264 | "text":text 265 | } 266 | get_local_service_response(path,params) 267 | 268 | # 回复图片消息 269 | def replyImage(self,imageUrl): 270 | path="/sendImage" 271 | params={ 272 | "senderid":self.senderID, 273 | "imageurl":imageUrl 274 | } 275 | get_local_service_response(path,params) 276 | 277 | # 回复语音消息 278 | def replyVoice(self,voiceUrl): 279 | path="/sendVoice" 280 | params={ 281 | "senderid":self.senderID, 282 | "voiceurl":voiceUrl 283 | } 284 | get_local_service_response(path,params) 285 | 286 | # 回复视频消息 287 | def replyVideo(self,videoUrl): 288 | path="/sendVideo" 289 | params={ 290 | "senderid":self.senderID, 291 | "videourl":videoUrl 292 | } 293 | get_local_service_response(path,params) 294 | 295 | # 等待用户输入,timeout为超时时间,单位为毫秒 296 | def listen(self,timeout): 297 | path="/listen" 298 | params={ 299 | "senderid":self.senderID, 300 | "timeout":timeout 301 | } 302 | response=get_local_service_response(path,params) 303 | return response.text 304 | 305 | # 修改用户内容重新送往机器人消息处理通道 306 | def breakIn(self,content): 307 | path="/breakIn" 308 | params={ 309 | "senderid":self.senderID, 310 | "content":content 311 | } 312 | get_local_service_response(path,params) 313 | 314 | # 等待支付 315 | def waitPay(self,exitcode,timeout): 316 | path="/waitPay" 317 | params={ 318 | "senderid":self.senderID, 319 | "exitcode":exitcode, 320 | "timeout":timeout # 超时时间,单位为毫秒 321 | } 322 | response=get_local_service_response(path,params) 323 | return response.text 324 | 325 | # 系统是否处于等待支付状态 326 | def atWaitPay(self): 327 | path="/atWaitPay" 328 | params={ 329 | "senderid":self.senderID 330 | } 331 | response=get_local_service_response(path,params) 332 | return response.text=="true" 333 | 334 | # 添加好友至群聊 335 | def groupInviteIn(self,friend,group): 336 | path="/groupInviteIn" 337 | params={ 338 | "senderid":self.senderID, 339 | "friend":friend, 340 | "group":group, 341 | } 342 | get_local_service_response(path,params) 343 | 344 | # 群聊踢人 345 | def groupKick(self,userid): 346 | path="/groupKick" 347 | params={ 348 | "senderid":self.senderID, 349 | "userid":userid, 350 | } 351 | get_local_service_response(path,params) 352 | 353 | # 群聊禁言 354 | def groupBan(self,userid,timeout): 355 | path="/groupBan" 356 | params={ 357 | "senderid":self.senderID, 358 | "userid":userid, 359 | "timeout":timeout, 360 | } 361 | get_local_service_response(path,params) 362 | 363 | # 群聊解除禁言 364 | def groupUnban(self,userid): 365 | path="/groupUnban" 366 | params={ 367 | "senderid":self.senderID, 368 | "userid":userid, 369 | } 370 | get_local_service_response(path,params) 371 | 372 | # 群聊全员禁言 373 | def groupWholeBan(self): 374 | path="/groupWholeBan" 375 | params={ 376 | "senderid":self.senderID, 377 | } 378 | get_local_service_response(path,params) 379 | 380 | # 群聊全员解禁 381 | def groupWholeUnban(self): 382 | path="/groupWholeUnban" 383 | params={ 384 | "senderid":self.senderID, 385 | } 386 | get_local_service_response(path,params) 387 | 388 | # 群聊内发送公告 389 | def groupNoticeSend(self,notice): 390 | path="/groupNoticeSend" 391 | params={ 392 | "senderid":self.senderID, 393 | "notice":notice, 394 | } 395 | get_local_service_response(path,params) 396 | 397 | # 获取当前处理流程的插件名 398 | def getPluginName(self): 399 | path="/getPluginName" 400 | params={ 401 | "senderid":self.senderID, 402 | } 403 | response=get_local_service_response(path,params) 404 | return response.text 405 | 406 | # 获取当前处理流程的插件版本 407 | def getPluginVersion(self): 408 | path="/getPluginVersion" 409 | params={ 410 | "senderid":self.senderID, 411 | } 412 | response=get_local_service_response(path,params) 413 | return response.text 414 | 415 | # 定时指令的相关操作 416 | class Cron: 417 | 418 | # 构造函数 419 | def __init__(self, cronID): 420 | self.cronID = cronID 421 | 422 | # 获取cronID -------------------------------------------------------------------------------- /middleware.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 网络访问请求函数 4 | # 参数: 5 | # $1: URL 6 | # $2: 超时时间(秒) 7 | function make_request() { 8 | local url="http://localhost:9999/otto${1}" 9 | local timeout=$2 10 | 11 | # 发送GET请求,并设置超时时间 12 | if response=$(curl -s -m "$timeout" "$url"); then 13 | echo "$response" 14 | else 15 | echo "请求超时或失败" 16 | fi 17 | } 18 | 19 | 20 | # 推送消息 21 | function push(){ 22 | local imType=$1 23 | local groupcode=$2 24 | local userid=$3 25 | local title=$4 26 | local content=$5 27 | 28 | local url="/push?imType=${imType}&groupcode=${groupcode}&userid=${userid}&title=${title}&content=${content}" 29 | make_request "$url" 5000 30 | } 31 | 32 | # 获取机器人名称 33 | function name(){ 34 | local url="/name" 35 | make_request "$url" 5000 36 | } 37 | 38 | # 获取机器id 39 | function machineId(){ 40 | local url="/machineId" 41 | make_request "$url" 5000 42 | } 43 | 44 | # 获取机器人版本 45 | function version(){ 46 | local url="/version" 47 | make_request "$url" 5000 48 | } 49 | 50 | # 获取数据库数据 51 | function get(){ 52 | local key=$1 53 | local url="/get?key=${key}" 54 | make_request "$url" 5000 55 | } 56 | 57 | # 设置数据库数据 58 | function set(){ 59 | local key=$1 60 | local value=$2 61 | local url="/set?key=${key}&value=${value}" 62 | make_request "$url" 5000 63 | } 64 | 65 | # 删除数据库数据 66 | function del(){ 67 | local key=$1 68 | local url="/del?key=${key}" 69 | make_request "$url" 5000 70 | } 71 | 72 | # 获取指定数据库指定的key值 73 | function bucketGet(){ 74 | local bucket=$1 75 | local key=$2 76 | local url="/bucket/get?bucket=${bucket}&key=${key}" 77 | make_request "$url" 5000 78 | } 79 | 80 | # 设置指定数据库指定的key值 81 | function bucketSet(){ 82 | local bucket=$1 83 | local key=$2 84 | local value=$3 85 | local url="/bucket/set?bucket=${bucket}&key=${key}&value=${value}" 86 | make_request "$url" 5000 87 | } 88 | 89 | # 删除指定数据库指定的key值 90 | function bucketDel(){ 91 | local bucket=$1 92 | local key=$2 93 | local url="/bucket/del?bucket=${bucket}&key=${key}" 94 | make_request "$url" 5000 95 | } 96 | 97 | # 获取指定数据库的所有值为value的keys 98 | function bucketKeys(){ 99 | local bucket=$1 100 | local value=$2 101 | local url="/bucket/keys?bucket=${bucket}&value=${value}" 102 | make_request "$url" 5000 103 | } 104 | 105 | # 获取指定数据库的所有key 106 | function bucketAllKeys(){ 107 | local bucket=$1 108 | local url="/bucketAllKeys?bucket=${bucket}" 109 | make_request "$url" 5000 110 | } 111 | 112 | # 通知管理员 113 | function notifyMasters(){ 114 | local content=$2 115 | local imtypes=$3 116 | local url="/notifyMasters?content=${content}&imtypes=${imtypes}" 117 | make_request "$url" 5000 118 | } 119 | 120 | # 系统授权状态 121 | function coffee(){ 122 | local url="/coffee" 123 | make_request "$url" 5000 124 | } 125 | 126 | # 京东、淘宝、拼多多转链推广 127 | function spread(){ 128 | local msg=$1 129 | local url="/spread?msg=${msg}" 130 | make_request "$url" 5000 131 | } 132 | 133 | declare -A sender 134 | # 设置变量 135 | sender[senderid]="senderid" 136 | # 发送者渠道 137 | sender.getImtype() { 138 | make_request "/getImtype?senderid=${sender[senderid]}" 5000 139 | } 140 | # 获取用户id 141 | sender.getUserID() { 142 | make_request "/getUserID?senderid=${sender[senderid]}" 5000 143 | } 144 | # 获取用户头像地址 145 | sender.getUserAvatarUrl() { 146 | make_request "/getUserAvatarUrl?senderid=${sender[senderid]}" 5000 147 | } 148 | # 获取用户昵称 149 | sender.getUserName() { 150 | make_request "/getUserName?senderid=${sender[senderid]}" 5000 151 | } 152 | # 获取群组id 153 | sender.getGroupID() { 154 | make_request "/getGroupID?senderid=${sender[senderid]}" 5000 155 | } 156 | # 获取群组名称 157 | sender.getGroupName() { 158 | make_request "/getGroupName?senderid=${sender[senderid]}" 5000 159 | } 160 | # 是否为管理员 161 | sender.isAdmin() { 162 | make_request "/isAdmin?senderid=${sender[senderid]}" 5000 163 | } 164 | # 获取消息ID 165 | sender.getMessageID() { 166 | make_request "/getMessageID?senderid=${sender[senderid]}" 5000 167 | } 168 | # 撤回消息 169 | sender.recallMessage() { 170 | local msgid=$1 171 | make_request "/recall?senderid=${sender[senderid]}&msgid=${msgid}" 5000 172 | } 173 | # 获取匹配的文本参数 174 | sender.param() { 175 | local index=$1 176 | make_request "/getMatchedText?senderid=${sender[senderid]}&index=${index}" 5000 177 | } 178 | # 回复消息 179 | sender.reply() { 180 | local text=$1 181 | make_request "/sendText?senderid=${sender[senderid]}&text=${text}" 5000 182 | } 183 | # 回复图片消息 184 | sender.replyImage() { 185 | local imageurl=$1 186 | make_request "/sendImage?senderid=${sender[senderid]}&imageurl=${imageurl}" 5000 187 | } 188 | # 回复语音消息 189 | sender.replyVoice() { 190 | local voiceurl=$1 191 | make_request "/sendVoice?senderid=${sender[senderid]}&voiceurl=${voiceurl}" 5000 192 | } 193 | # 回复视频消息 194 | sender.replyVideo() { 195 | local videourl=$1 196 | make_request "/sendVideo?senderid=${sender[senderid]}&videourl=${videourl}" 5000 197 | } 198 | # 等待用户输入 199 | sender.listen() { 200 | local timeout=$1 201 | make_request "/listen?senderid=${sender[senderid]}&timeout=${timeout}" 5000 202 | } 203 | # 等待用户支付 204 | sender.waitPay() { 205 | local exitcode=$1 206 | local timeout=$2 207 | make_request "/waitPay?senderid=${sender[senderid]}&exitcode=${exitcode}&timeout=${timeout}" 5000 208 | } 209 | # 是否处于等待支付状态 210 | sender.atWaitingPay() { 211 | make_request "/atWaitingPay" 5000 212 | } 213 | # 邀请入群 214 | sender.groupInviteIn() { 215 | local friend=$1 216 | local group=$2 217 | make_request "/groupInviteIn?senderid=${sender[senderid]}&friend=${friend}&group=${group}" 5000 218 | } 219 | 220 | # 踢出群组 221 | sender.groupKick() { 222 | local userid=$1 223 | make_request "/groupKick?senderid=${sender[senderid]}&userid=${userid}" 5000 224 | } 225 | 226 | # 禁言 227 | sender.groupBan() { 228 | local userid=$1 229 | local time=$2 230 | make_request "/groupBan?senderid=${sender[senderid]}&userid=${userid}&time=${time}" 5000 231 | } 232 | 233 | # 解除禁言 234 | sender.groupUnban() { 235 | local userid=$1 236 | make_request "/groupUnban?senderid=${sender[senderid]}&userid=${userid}" 5000 237 | } 238 | 239 | # 全员禁言 240 | sender.groupWholeBan() { 241 | make_request "/groupWholeBan?senderid=${sender[senderid]}&time=${time}" 5000 242 | } 243 | 244 | # 解除全员禁言 245 | sender.groupWholeUnban() { 246 | make_request "/groupWholeUnban?senderid=${sender[senderid]}" 5000 247 | } 248 | 249 | # 发送群公告 250 | sender.groupNoticeSend(){ 251 | notice=$1 252 | make_request "/groupNoticeSend?senderid=${sender[senderid]}¬ice=${notice}" 5000 253 | } 254 | 255 | # 获取当前处理流程的插件名 256 | sender.getPluginName(){ 257 | local url="/getPluginName?senderid=${sender[senderid]}" 258 | make_request "$url" 5000 259 | } 260 | 261 | # 获取当前处理流程的插件版本 262 | sender.getPluginVersion(){ 263 | local url="/getPluginVersion?senderid=${sender[senderid]}" 264 | make_request "$url" 5000 265 | } 266 | 267 | 268 | -------------------------------------------------------------------------------- /plugin/golang/go.mod: -------------------------------------------------------------------------------- 1 | module main 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/hdbjlizhe/middleware v0.0.0-20231209034644-f500a6e9a660 // indirect 7 | ) 8 | -------------------------------------------------------------------------------- /plugins/test.js: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /qrcode2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdbjlizhe/fanli/2136db764a67e743c32733de3ce1f68aea0d11ff/qrcode2.png -------------------------------------------------------------------------------- /qrcode3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdbjlizhe/fanli/2136db764a67e743c32733de3ce1f68aea0d11ff/qrcode3.jpg -------------------------------------------------------------------------------- /qrcode4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdbjlizhe/fanli/2136db764a67e743c32733de3ce1f68aea0d11ff/qrcode4.jpg -------------------------------------------------------------------------------- /sendNotify.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: lxk0301 https://gitee.com/lxk0301 3 | * @Date: 2020-08-19 16:12:40 4 | * @Last Modified by: whyour 5 | * @Last Modified time: 2021-5-1 15:00:54 6 | * sendNotify 推送通知功能 7 | * @param text 通知头 8 | * @param desp 通知体 9 | * @param params 某些推送通知方式点击弹窗可跳转, 例:{ url: 'https://abc.com' } 10 | * @param author 作者仓库等信息 例:`本通知 By:https://github.com/whyour/qinglong` 11 | */ 12 | 13 | const querystring = require('querystring'); 14 | const $ = new Env(); 15 | const timeout = 15000; //超时时间(单位毫秒) 16 | // =======================================gotify通知设置区域============================================== 17 | //gotify_url 填写gotify地址,如https://push.example.de:8080 18 | //gotify_token 填写gotify的消息应用token 19 | //gotify_priority 填写推送消息优先级,默认为0 20 | let GOTIFY_URL = ''; 21 | let GOTIFY_TOKEN = ''; 22 | let GOTIFY_PRIORITY = 0; 23 | // =======================================go-cqhttp通知设置区域=========================================== 24 | //gobot_url 填写请求地址http://127.0.0.1/send_private_msg 25 | //gobot_token 填写在go-cqhttp文件设置的访问密钥 26 | //gobot_qq 填写推送到个人QQ或者QQ群号 27 | //go-cqhttp相关API https://docs.go-cqhttp.org/api 28 | let GOBOT_URL = ''; // 推送到个人QQ: http://127.0.0.1/send_private_msg 群:http://127.0.0.1/send_group_msg 29 | let GOBOT_TOKEN = ''; //访问密钥 30 | let GOBOT_QQ = ''; // 如果GOBOT_URL设置 /send_private_msg 则需要填入 user_id=个人QQ 相反如果是 /send_group_msg 则需要填入 group_id=QQ群 31 | 32 | // =======================================微信server酱通知设置区域=========================================== 33 | //此处填你申请的SCKEY. 34 | //(环境变量名 PUSH_KEY) 35 | let SCKEY = ''; 36 | 37 | // =======================================PushDeer通知设置区域=========================================== 38 | //此处填你申请的PushDeer KEY. 39 | //(环境变量名 DEER_KEY) 40 | let PUSHDEER_KEY = ''; 41 | 42 | // =======================================Synology Chat通知设置区域=========================================== 43 | //此处填你申请的CHAT_URL与CHAT_TOKEN 44 | //(环境变量名 CHAT_URL CHAT_TOKEN) 45 | let CHAT_URL = ''; 46 | let CHAT_TOKEN = ''; 47 | 48 | // =======================================Bark App通知设置区域=========================================== 49 | //此处填你BarkAPP的信息(IP/设备码,例如:https://api.day.app/XXXXXXXX) 50 | let BARK_PUSH = ''; 51 | //BARK app推送图标,自定义推送图标(需iOS15或以上) 52 | let BARK_ICON = 'http://qn.whyour.cn/logo.png'; 53 | //BARK app推送铃声,铃声列表去APP查看复制填写 54 | let BARK_SOUND = ''; 55 | //BARK app推送消息的分组, 默认为"QingLong" 56 | let BARK_GROUP = 'QingLong'; 57 | 58 | // =======================================telegram机器人通知设置区域=========================================== 59 | //此处填你telegram bot 的Token,telegram机器人通知推送必填项.例如:1077xxx4424:AAFjv0FcqxxxxxxgEMGfi22B4yh15R5uw 60 | //(环境变量名 TG_BOT_TOKEN) 61 | let TG_BOT_TOKEN = ''; 62 | //此处填你接收通知消息的telegram用户的id,telegram机器人通知推送必填项.例如:129xxx206 63 | //(环境变量名 TG_USER_ID) 64 | let TG_USER_ID = ''; 65 | //tg推送HTTP代理设置(不懂可忽略,telegram机器人通知推送功能中非必填) 66 | let TG_PROXY_HOST = ''; //例如:127.0.0.1(环境变量名:TG_PROXY_HOST) 67 | let TG_PROXY_PORT = ''; //例如:1080(环境变量名:TG_PROXY_PORT) 68 | let TG_PROXY_AUTH = ''; //tg代理配置认证参数 69 | //Telegram api自建的反向代理地址(不懂可忽略,telegram机器人通知推送功能中非必填),默认tg官方api(环境变量名:TG_API_HOST) 70 | let TG_API_HOST = 'api.telegram.org'; 71 | // =======================================钉钉机器人通知设置区域=========================================== 72 | //此处填你钉钉 bot 的webhook,例如:5a544165465465645d0f31dca676e7bd07415asdasd 73 | //(环境变量名 DD_BOT_TOKEN) 74 | let DD_BOT_TOKEN = ''; 75 | //密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的字符串 76 | let DD_BOT_SECRET = ''; 77 | 78 | // =======================================企业微信机器人通知设置区域=========================================== 79 | //此处填你企业微信机器人的 webhook(详见文档 https://work.weixin.qq.com/api/doc/90000/90136/91770),例如:693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa 80 | //(环境变量名 QYWX_KEY) 81 | let QYWX_KEY = ''; 82 | 83 | // =======================================企业微信应用消息通知设置区域=========================================== 84 | /* 85 | 此处填你企业微信应用消息的值(详见文档 https://work.weixin.qq.com/api/doc/90000/90135/90236) 86 | 环境变量名 QYWX_AM依次填入 corpid,corpsecret,touser(注:多个成员ID使用|隔开),agentid,消息类型(选填,不填默认文本消息类型) 87 | 注意用,号隔开(英文输入法的逗号),例如:wwcff56746d9adwers,B-791548lnzXBE6_BWfxdf3kSTMJr9vFEPKAbh6WERQ,mingcheng,1000001,2COXgjH2UIfERF2zxrtUOKgQ9XklUqMdGSWLBoW_lSDAdafat 88 | 可选推送消息类型(推荐使用图文消息(mpnews)): 89 | - 文本卡片消息: 0 (数字零) 90 | - 文本消息: 1 (数字一) 91 | - 图文消息(mpnews): 素材库图片id, 可查看此教程(http://note.youdao.com/s/HMiudGkb)或者(https://note.youdao.com/ynoteshare1/index.html?id=1a0c8aff284ad28cbd011b29b3ad0191&type=note) 92 | */ 93 | let QYWX_AM = ''; 94 | 95 | // =======================================iGot聚合推送通知设置区域=========================================== 96 | //此处填您iGot的信息(推送key,例如:https://push.hellyw.com/XXXXXXXX) 97 | let IGOT_PUSH_KEY = ''; 98 | 99 | // =======================================push+设置区域======================================= 100 | //官方文档:http://www.pushplus.plus/ 101 | //PUSH_PLUS_TOKEN:微信扫码登录后一对一推送或一对多推送下面的token(您的Token),不提供PUSH_PLUS_USER则默认为一对一推送 102 | //PUSH_PLUS_USER: 一对多推送的“群组编码”(一对多推送下面->您的群组(如无则新建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送) 103 | let PUSH_PLUS_TOKEN = ''; 104 | let PUSH_PLUS_USER = ''; 105 | 106 | // =======================================Cool Push设置区域======================================= 107 | //官方文档:https://cp.xuthus.cc/docs 108 | //QQ_SKEY: Cool Push登录授权后推送消息的调用代码Skey 109 | //QQ_MODE: 推送模式详情请登录获取QQ_SKEY后见https://cp.xuthus.cc/feat 110 | let QQ_SKEY = ''; 111 | let QQ_MODE = ''; 112 | 113 | //==========================云端环境变量的判断与接收========================= 114 | if (process.env.GOTIFY_URL) { 115 | GOTIFY_URL = process.env.GOTIFY_URL; 116 | } 117 | if (process.env.GOTIFY_TOKEN) { 118 | GOTIFY_TOKEN = process.env.GOTIFY_TOKEN; 119 | } 120 | if (process.env.GOTIFY_PRIORITY) { 121 | GOTIFY_PRIORITY = process.env.GOTIFY_PRIORITY; 122 | } 123 | 124 | if (process.env.GOBOT_URL) { 125 | GOBOT_URL = process.env.GOBOT_URL; 126 | } 127 | if (process.env.GOBOT_TOKEN) { 128 | GOBOT_TOKEN = process.env.GOBOT_TOKEN; 129 | } 130 | if (process.env.GOBOT_QQ) { 131 | GOBOT_QQ = process.env.GOBOT_QQ; 132 | } 133 | 134 | if (process.env.PUSH_KEY) { 135 | SCKEY = process.env.PUSH_KEY; 136 | } 137 | 138 | if (process.env.DEER_KEY) { 139 | PUSHDEER_KEY = process.env.DEER_KEY; 140 | } 141 | 142 | if (process.env.CHAT_URL) { 143 | CHAT_URL = process.env.CHAT_URL; 144 | } 145 | 146 | if (process.env.CHAT_TOKEN) { 147 | CHAT_TOKEN = process.env.CHAT_TOKEN; 148 | } 149 | 150 | if (process.env.QQ_SKEY) { 151 | QQ_SKEY = process.env.QQ_SKEY; 152 | } 153 | 154 | if (process.env.QQ_MODE) { 155 | QQ_MODE = process.env.QQ_MODE; 156 | } 157 | 158 | if (process.env.BARK_PUSH) { 159 | if ( 160 | process.env.BARK_PUSH.indexOf('https') > -1 || 161 | process.env.BARK_PUSH.indexOf('http') > -1 162 | ) { 163 | //兼容BARK自建用户 164 | BARK_PUSH = process.env.BARK_PUSH; 165 | } else { 166 | BARK_PUSH = `https://api.day.app/${process.env.BARK_PUSH}`; 167 | } 168 | if (process.env.BARK_ICON) { 169 | BARK_ICON = process.env.BARK_ICON; 170 | } 171 | if (process.env.BARK_SOUND) { 172 | BARK_SOUND = process.env.BARK_SOUND; 173 | } 174 | if (process.env.BARK_GROUP) { 175 | BARK_GROUP = process.env.BARK_GROUP; 176 | } 177 | } else { 178 | if ( 179 | BARK_PUSH && 180 | BARK_PUSH.indexOf('https') === -1 && 181 | BARK_PUSH.indexOf('http') === -1 182 | ) { 183 | //兼容BARK本地用户只填写设备码的情况 184 | BARK_PUSH = `https://api.day.app/${BARK_PUSH}`; 185 | } 186 | } 187 | if (process.env.TG_BOT_TOKEN) { 188 | TG_BOT_TOKEN = process.env.TG_BOT_TOKEN; 189 | } 190 | if (process.env.TG_USER_ID) { 191 | TG_USER_ID = process.env.TG_USER_ID; 192 | } 193 | if (process.env.TG_PROXY_AUTH) TG_PROXY_AUTH = process.env.TG_PROXY_AUTH; 194 | if (process.env.TG_PROXY_HOST) TG_PROXY_HOST = process.env.TG_PROXY_HOST; 195 | if (process.env.TG_PROXY_PORT) TG_PROXY_PORT = process.env.TG_PROXY_PORT; 196 | if (process.env.TG_API_HOST) TG_API_HOST = process.env.TG_API_HOST; 197 | 198 | if (process.env.DD_BOT_TOKEN) { 199 | DD_BOT_TOKEN = process.env.DD_BOT_TOKEN; 200 | if (process.env.DD_BOT_SECRET) { 201 | DD_BOT_SECRET = process.env.DD_BOT_SECRET; 202 | } 203 | } 204 | 205 | if (process.env.QYWX_KEY) { 206 | QYWX_KEY = process.env.QYWX_KEY; 207 | } 208 | 209 | if (process.env.QYWX_AM) { 210 | QYWX_AM = process.env.QYWX_AM; 211 | } 212 | 213 | if (process.env.IGOT_PUSH_KEY) { 214 | IGOT_PUSH_KEY = process.env.IGOT_PUSH_KEY; 215 | } 216 | 217 | if (process.env.PUSH_PLUS_TOKEN) { 218 | PUSH_PLUS_TOKEN = process.env.PUSH_PLUS_TOKEN; 219 | } 220 | if (process.env.PUSH_PLUS_USER) { 221 | PUSH_PLUS_USER = process.env.PUSH_PLUS_USER; 222 | } 223 | //==========================云端环境变量的判断与接收========================= 224 | 225 | /** 226 | * sendNotify 推送通知功能 227 | * @param text 通知头 228 | * @param desp 通知体 229 | * @param params 某些推送通知方式点击弹窗可跳转, 例:{ url: 'https://abc.com' } 230 | * @param author 作者仓库等信息 例:`本通知 By:https://github.com/whyour/qinglong` 231 | * @returns {Promise} 232 | */ 233 | async function sendNotify( 234 | text, 235 | desp, 236 | params = {}, 237 | author = '\n\n本通知 By:https://github.com/whyour/qinglong', 238 | ) { 239 | //提供6种通知 240 | desp += author; //增加作者信息,防止被贩卖等 241 | await Promise.all([ 242 | serverNotify(text, desp), //微信server酱 243 | pushPlusNotify(text, desp), //pushplus(推送加) 244 | ]); 245 | //由于上述两种微信通知需点击进去才能查看到详情,故text(标题内容)携带了账号序号以及昵称信息,方便不点击也可知道是哪个京东哪个活动 246 | text = text.match(/.*?(?=\s?-)/g) ? text.match(/.*?(?=\s?-)/g)[0] : text; 247 | await Promise.all([ 248 | BarkNotify(text, desp, params), //iOS Bark APP 249 | tgBotNotify(text, desp), //telegram 机器人 250 | ddBotNotify(text, desp), //钉钉机器人 251 | qywxBotNotify(text, desp), //企业微信机器人 252 | qywxamNotify(text, desp), //企业微信应用消息推送 253 | iGotNotify(text, desp, params), //iGot 254 | gobotNotify(text, desp), //go-cqhttp 255 | gotifyNotify(text, desp), //gotify 256 | ChatNotify(text, desp), //synolog chat 257 | PushDeerNotify(text, desp), //PushDeer 258 | ]); 259 | } 260 | 261 | function gotifyNotify(text, desp) { 262 | return new Promise((resolve) => { 263 | if (GOTIFY_URL && GOTIFY_TOKEN) { 264 | const options = { 265 | url: `${GOTIFY_URL}/message?token=${GOTIFY_TOKEN}`, 266 | body: `title=${encodeURIComponent(text)}&message=${encodeURIComponent( 267 | desp, 268 | )}&priority=${GOTIFY_PRIORITY}`, 269 | headers: { 270 | 'Content-Type': 'application/x-www-form-urlencoded', 271 | }, 272 | }; 273 | $.post(options, (err, resp, data) => { 274 | try { 275 | if (err) { 276 | console.log('gotify发送通知调用API失败!!\n'); 277 | console.log(err); 278 | } else { 279 | data = JSON.parse(data); 280 | if (data.id) { 281 | console.log('gotify发送通知消息成功🎉\n'); 282 | } else { 283 | console.log(`${data.message}\n`); 284 | } 285 | } 286 | } catch (e) { 287 | $.logErr(e, resp); 288 | } finally { 289 | resolve(); 290 | } 291 | }); 292 | } else { 293 | resolve(); 294 | } 295 | }); 296 | } 297 | 298 | function gobotNotify(text, desp, time = 2100) { 299 | return new Promise((resolve) => { 300 | if (GOBOT_URL) { 301 | const options = { 302 | url: `${GOBOT_URL}?access_token=${GOBOT_TOKEN}&${GOBOT_QQ}`, 303 | json: { message: `${text}\n${desp}` }, 304 | headers: { 305 | 'Content-Type': 'application/json', 306 | }, 307 | timeout, 308 | }; 309 | setTimeout(() => { 310 | $.post(options, (err, resp, data) => { 311 | try { 312 | if (err) { 313 | console.log('发送go-cqhttp通知调用API失败!!\n'); 314 | console.log(err); 315 | } else { 316 | data = JSON.parse(data); 317 | if (data.retcode === 0) { 318 | console.log('go-cqhttp发送通知消息成功🎉\n'); 319 | } else if (data.retcode === 100) { 320 | console.log(`go-cqhttp发送通知消息异常: ${data.errmsg}\n`); 321 | } else { 322 | console.log( 323 | `go-cqhttp发送通知消息异常\n${JSON.stringify(data)}`, 324 | ); 325 | } 326 | } 327 | } catch (e) { 328 | $.logErr(e, resp); 329 | } finally { 330 | resolve(data); 331 | } 332 | }); 333 | }, time); 334 | } else { 335 | resolve(); 336 | } 337 | }); 338 | } 339 | 340 | function serverNotify(text, desp, time = 2100) { 341 | return new Promise((resolve) => { 342 | if (SCKEY) { 343 | //微信server酱推送通知一个\n不会换行,需要两个\n才能换行,故做此替换 344 | desp = desp.replace(/[\n\r]/g, '\n\n'); 345 | const options = { 346 | url: SCKEY.includes('SCT') 347 | ? `https://sctapi.ftqq.com/${SCKEY}.send` 348 | : `https://sc.ftqq.com/${SCKEY}.send`, 349 | body: `text=${text}&desp=${desp}`, 350 | headers: { 351 | 'Content-Type': 'application/x-www-form-urlencoded', 352 | }, 353 | timeout, 354 | }; 355 | setTimeout(() => { 356 | $.post(options, (err, resp, data) => { 357 | try { 358 | if (err) { 359 | console.log('发送通知调用API失败!!\n'); 360 | console.log(err); 361 | } else { 362 | data = JSON.parse(data); 363 | //server酱和Server酱·Turbo版的返回json格式不太一样 364 | if (data.errno === 0 || data.data.errno === 0) { 365 | console.log('server酱发送通知消息成功🎉\n'); 366 | } else if (data.errno === 1024) { 367 | // 一分钟内发送相同的内容会触发 368 | console.log(`server酱发送通知消息异常: ${data.errmsg}\n`); 369 | } else { 370 | console.log( 371 | `server酱发送通知消息异常\n${JSON.stringify(data)}`, 372 | ); 373 | } 374 | } 375 | } catch (e) { 376 | $.logErr(e, resp); 377 | } finally { 378 | resolve(data); 379 | } 380 | }); 381 | }, time); 382 | } else { 383 | resolve(); 384 | } 385 | }); 386 | } 387 | 388 | function PushDeerNotify(text, desp) { 389 | return new Promise((resolve) => { 390 | if (PUSHDEER_KEY) { 391 | // PushDeer 建议对消息内容进行 urlencode 392 | desp = encodeURI(desp); 393 | const options = { 394 | url: `https://api2.pushdeer.com/message/push`, 395 | body: `pushkey=${PUSHDEER_KEY}&text=${text}&desp=${desp}&type=markdown`, 396 | headers: { 397 | 'Content-Type': 'application/x-www-form-urlencoded', 398 | }, 399 | timeout, 400 | }; 401 | $.post( 402 | options, 403 | (err, resp, data) => { 404 | try { 405 | if (err) { 406 | console.log('发送通知调用API失败!!\n'); 407 | console.log(err); 408 | } else { 409 | data = JSON.parse(data); 410 | // 通过返回的result的长度来判断是否成功 411 | if ( 412 | data.content.result.length !== undefined && 413 | data.content.result.length > 0 414 | ) { 415 | console.log('PushDeer发送通知消息成功🎉\n'); 416 | } else { 417 | console.log( 418 | `PushDeer发送通知消息异常\n${JSON.stringify(data)}`, 419 | ); 420 | } 421 | } 422 | } catch (e) { 423 | $.logErr(e, resp); 424 | } finally { 425 | resolve(data); 426 | } 427 | }, 428 | time, 429 | ); 430 | } else { 431 | resolve(); 432 | } 433 | }); 434 | } 435 | 436 | function ChatNotify(text, desp) { 437 | return new Promise((resolve) => { 438 | if (CHAT_URL && CHAT_TOKEN) { 439 | // 对消息内容进行 urlencode 440 | desp = encodeURI(desp); 441 | const options = { 442 | url: `${CHAT_URL}${CHAT_TOKEN}`, 443 | body: `payload={"text":"${text}\n${desp}"}`, 444 | headers: { 445 | 'Content-Type': 'application/x-www-form-urlencoded', 446 | }, 447 | }; 448 | $.post(options, (err, resp, data) => { 449 | try { 450 | if (err) { 451 | console.log('发送通知调用API失败!!\n'); 452 | console.log(err); 453 | } else { 454 | data = JSON.parse(data); 455 | if (data.success) { 456 | console.log('Chat发送通知消息成功🎉\n'); 457 | } else { 458 | console.log(`Chat发送通知消息异常\n${JSON.stringify(data)}`); 459 | } 460 | } 461 | } catch (e) { 462 | $.logErr(e); 463 | } finally { 464 | resolve(data); 465 | } 466 | }); 467 | } else { 468 | resolve(); 469 | } 470 | }); 471 | } 472 | 473 | function CoolPush(text, desp) { 474 | return new Promise((resolve) => { 475 | if (QQ_SKEY) { 476 | let options = { 477 | url: `https://push.xuthus.cc/${QQ_MODE}/${QQ_SKEY}`, 478 | headers: { 479 | 'Content-Type': 'application/json', 480 | }, 481 | }; 482 | 483 | // 已知敏感词 484 | text = text.replace(/京豆/g, '豆豆'); 485 | desp = desp.replace(/京豆/g, ''); 486 | desp = desp.replace(/🐶/g, ''); 487 | desp = desp.replace(/红包/g, 'H包'); 488 | 489 | switch (QQ_MODE) { 490 | case 'email': 491 | options.json = { 492 | t: text, 493 | c: desp, 494 | }; 495 | break; 496 | default: 497 | options.body = `${text}\n\n${desp}`; 498 | } 499 | 500 | let pushMode = function (t) { 501 | switch (t) { 502 | case 'send': 503 | return '个人'; 504 | case 'group': 505 | return 'QQ群'; 506 | case 'wx': 507 | return '微信'; 508 | case 'ww': 509 | return '企业微信'; 510 | case 'email': 511 | return '邮件'; 512 | default: 513 | return '未知方式'; 514 | } 515 | }; 516 | 517 | $.post(options, (err, resp, data) => { 518 | try { 519 | if (err) { 520 | console.log(`发送${pushMode(QQ_MODE)}通知调用API失败!!\n`); 521 | console.log(err); 522 | } else { 523 | data = JSON.parse(data); 524 | if (data.code === 200) { 525 | console.log(`酷推发送${pushMode(QQ_MODE)}通知消息成功🎉\n`); 526 | } else if (data.code === 400) { 527 | console.log( 528 | `QQ酷推(Cool Push)发送${pushMode(QQ_MODE)}推送失败:${ 529 | data.msg 530 | }\n`, 531 | ); 532 | } else if (data.code === 503) { 533 | console.log(`QQ酷推出错,${data.message}:${data.data}\n`); 534 | } else { 535 | console.log(`酷推推送异常: ${JSON.stringify(data)}`); 536 | } 537 | } 538 | } catch (e) { 539 | $.logErr(e, resp); 540 | } finally { 541 | resolve(data); 542 | } 543 | }); 544 | } else { 545 | resolve(); 546 | } 547 | }); 548 | } 549 | 550 | function BarkNotify(text, desp, params = {}) { 551 | return new Promise((resolve) => { 552 | if (BARK_PUSH) { 553 | const options = { 554 | url: `${BARK_PUSH}/${encodeURIComponent(text)}/${encodeURIComponent( 555 | desp, 556 | )}?icon=${BARK_ICON}?sound=${BARK_SOUND}&group=${BARK_GROUP}&${querystring.stringify( 557 | params, 558 | )}`, 559 | headers: { 560 | 'Content-Type': 'application/x-www-form-urlencoded', 561 | }, 562 | timeout, 563 | }; 564 | $.get(options, (err, resp, data) => { 565 | try { 566 | if (err) { 567 | console.log('Bark APP发送通知调用API失败!!\n'); 568 | console.log(err); 569 | } else { 570 | data = JSON.parse(data); 571 | if (data.code === 200) { 572 | console.log('Bark APP发送通知消息成功🎉\n'); 573 | } else { 574 | console.log(`${data.message}\n`); 575 | } 576 | } 577 | } catch (e) { 578 | $.logErr(e, resp); 579 | } finally { 580 | resolve(); 581 | } 582 | }); 583 | } else { 584 | resolve(); 585 | } 586 | }); 587 | } 588 | 589 | function tgBotNotify(text, desp) { 590 | return new Promise((resolve) => { 591 | if (TG_BOT_TOKEN && TG_USER_ID) { 592 | const options = { 593 | url: `https://${TG_API_HOST}/bot${TG_BOT_TOKEN}/sendMessage`, 594 | json: { 595 | chat_id: `${TG_USER_ID}`, 596 | text: `${text}\n\n${desp}`, 597 | disable_web_page_preview: true, 598 | }, 599 | headers: { 600 | 'Content-Type': 'application/json', 601 | }, 602 | timeout, 603 | }; 604 | if (TG_PROXY_HOST && TG_PROXY_PORT) { 605 | const tunnel = require('tunnel'); 606 | const agent = { 607 | https: tunnel.httpsOverHttp({ 608 | proxy: { 609 | host: TG_PROXY_HOST, 610 | port: TG_PROXY_PORT * 1, 611 | proxyAuth: TG_PROXY_AUTH, 612 | }, 613 | }), 614 | }; 615 | Object.assign(options, { agent }); 616 | } 617 | $.post(options, (err, resp, data) => { 618 | try { 619 | if (err) { 620 | console.log('telegram发送通知消息失败!!\n'); 621 | console.log(err); 622 | } else { 623 | data = JSON.parse(data); 624 | if (data.ok) { 625 | console.log('Telegram发送通知消息成功🎉。\n'); 626 | } else if (data.error_code === 400) { 627 | console.log( 628 | '请主动给bot发送一条消息并检查接收用户ID是否正确。\n', 629 | ); 630 | } else if (data.error_code === 401) { 631 | console.log('Telegram bot token 填写错误。\n'); 632 | } 633 | } 634 | } catch (e) { 635 | $.logErr(e, resp); 636 | } finally { 637 | resolve(data); 638 | } 639 | }); 640 | } else { 641 | resolve(); 642 | } 643 | }); 644 | } 645 | function ddBotNotify(text, desp) { 646 | return new Promise((resolve) => { 647 | const options = { 648 | url: `https://oapi.dingtalk.com/robot/send?access_token=${DD_BOT_TOKEN}`, 649 | json: { 650 | msgtype: 'text', 651 | text: { 652 | content: ` ${text}\n\n${desp}`, 653 | }, 654 | }, 655 | headers: { 656 | 'Content-Type': 'application/json', 657 | }, 658 | timeout, 659 | }; 660 | if (DD_BOT_TOKEN && DD_BOT_SECRET) { 661 | const crypto = require('crypto'); 662 | const dateNow = Date.now(); 663 | const hmac = crypto.createHmac('sha256', DD_BOT_SECRET); 664 | hmac.update(`${dateNow}\n${DD_BOT_SECRET}`); 665 | const result = encodeURIComponent(hmac.digest('base64')); 666 | options.url = `${options.url}×tamp=${dateNow}&sign=${result}`; 667 | $.post(options, (err, resp, data) => { 668 | try { 669 | if (err) { 670 | console.log('钉钉发送通知消息失败!!\n'); 671 | console.log(err); 672 | } else { 673 | data = JSON.parse(data); 674 | if (data.errcode === 0) { 675 | console.log('钉钉发送通知消息成功🎉。\n'); 676 | } else { 677 | console.log(`${data.errmsg}\n`); 678 | } 679 | } 680 | } catch (e) { 681 | $.logErr(e, resp); 682 | } finally { 683 | resolve(data); 684 | } 685 | }); 686 | } else if (DD_BOT_TOKEN) { 687 | $.post(options, (err, resp, data) => { 688 | try { 689 | if (err) { 690 | console.log('钉钉发送通知消息失败!!\n'); 691 | console.log(err); 692 | } else { 693 | data = JSON.parse(data); 694 | if (data.errcode === 0) { 695 | console.log('钉钉发送通知消息完成。\n'); 696 | } else { 697 | console.log(`${data.errmsg}\n`); 698 | } 699 | } 700 | } catch (e) { 701 | $.logErr(e, resp); 702 | } finally { 703 | resolve(data); 704 | } 705 | }); 706 | } else { 707 | resolve(); 708 | } 709 | }); 710 | } 711 | 712 | function qywxBotNotify(text, desp) { 713 | return new Promise((resolve) => { 714 | const options = { 715 | url: `https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${QYWX_KEY}`, 716 | json: { 717 | msgtype: 'text', 718 | text: { 719 | content: ` ${text}\n\n${desp}`, 720 | }, 721 | }, 722 | headers: { 723 | 'Content-Type': 'application/json', 724 | }, 725 | timeout, 726 | }; 727 | if (QYWX_KEY) { 728 | $.post(options, (err, resp, data) => { 729 | try { 730 | if (err) { 731 | console.log('企业微信发送通知消息失败!!\n'); 732 | console.log(err); 733 | } else { 734 | data = JSON.parse(data); 735 | if (data.errcode === 0) { 736 | console.log('企业微信发送通知消息成功🎉。\n'); 737 | } else { 738 | console.log(`${data.errmsg}\n`); 739 | } 740 | } 741 | } catch (e) { 742 | $.logErr(e, resp); 743 | } finally { 744 | resolve(data); 745 | } 746 | }); 747 | } else { 748 | resolve(); 749 | } 750 | }); 751 | } 752 | 753 | function ChangeUserId(desp) { 754 | const QYWX_AM_AY = QYWX_AM.split(','); 755 | if (QYWX_AM_AY[2]) { 756 | const userIdTmp = QYWX_AM_AY[2].split('|'); 757 | let userId = ''; 758 | for (let i = 0; i < userIdTmp.length; i++) { 759 | const count = '账号' + (i + 1); 760 | const count2 = '签到号 ' + (i + 1); 761 | if (desp.match(count2)) { 762 | userId = userIdTmp[i]; 763 | } 764 | } 765 | if (!userId) userId = QYWX_AM_AY[2]; 766 | return userId; 767 | } else { 768 | return '@all'; 769 | } 770 | } 771 | 772 | function qywxamNotify(text, desp) { 773 | return new Promise((resolve) => { 774 | if (QYWX_AM) { 775 | const QYWX_AM_AY = QYWX_AM.split(','); 776 | const options_accesstoken = { 777 | url: `https://qyapi.weixin.qq.com/cgi-bin/gettoken`, 778 | json: { 779 | corpid: `${QYWX_AM_AY[0]}`, 780 | corpsecret: `${QYWX_AM_AY[1]}`, 781 | }, 782 | headers: { 783 | 'Content-Type': 'application/json', 784 | }, 785 | timeout, 786 | }; 787 | $.post(options_accesstoken, (err, resp, data) => { 788 | let html = desp.replace(/\n/g, '
'); 789 | let json = JSON.parse(data); 790 | let accesstoken = json.access_token; 791 | let options; 792 | 793 | switch (QYWX_AM_AY[4]) { 794 | case '0': 795 | options = { 796 | msgtype: 'textcard', 797 | textcard: { 798 | title: `${text}`, 799 | description: `${desp}`, 800 | url: 'https://github.com/whyour/qinglong', 801 | btntxt: '更多', 802 | }, 803 | }; 804 | break; 805 | 806 | case '1': 807 | options = { 808 | msgtype: 'text', 809 | text: { 810 | content: `${text}\n\n${desp}`, 811 | }, 812 | }; 813 | break; 814 | 815 | default: 816 | options = { 817 | msgtype: 'mpnews', 818 | mpnews: { 819 | articles: [ 820 | { 821 | title: `${text}`, 822 | thumb_media_id: `${QYWX_AM_AY[4]}`, 823 | author: `智能助手`, 824 | content_source_url: ``, 825 | content: `${html}`, 826 | digest: `${desp}`, 827 | }, 828 | ], 829 | }, 830 | }; 831 | } 832 | if (!QYWX_AM_AY[4]) { 833 | //如不提供第四个参数,则默认进行文本消息类型推送 834 | options = { 835 | msgtype: 'text', 836 | text: { 837 | content: `${text}\n\n${desp}`, 838 | }, 839 | }; 840 | } 841 | options = { 842 | url: `https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=${accesstoken}`, 843 | json: { 844 | touser: `${ChangeUserId(desp)}`, 845 | agentid: `${QYWX_AM_AY[3]}`, 846 | safe: '0', 847 | ...options, 848 | }, 849 | headers: { 850 | 'Content-Type': 'application/json', 851 | }, 852 | }; 853 | 854 | $.post(options, (err, resp, data) => { 855 | try { 856 | if (err) { 857 | console.log( 858 | '成员ID:' + 859 | ChangeUserId(desp) + 860 | '企业微信应用消息发送通知消息失败!!\n', 861 | ); 862 | console.log(err); 863 | } else { 864 | data = JSON.parse(data); 865 | if (data.errcode === 0) { 866 | console.log( 867 | '成员ID:' + 868 | ChangeUserId(desp) + 869 | '企业微信应用消息发送通知消息成功🎉。\n', 870 | ); 871 | } else { 872 | console.log(`${data.errmsg}\n`); 873 | } 874 | } 875 | } catch (e) { 876 | $.logErr(e, resp); 877 | } finally { 878 | resolve(data); 879 | } 880 | }); 881 | }); 882 | } else { 883 | resolve(); 884 | } 885 | }); 886 | } 887 | 888 | function iGotNotify(text, desp, params = {}) { 889 | return new Promise((resolve) => { 890 | if (IGOT_PUSH_KEY) { 891 | // 校验传入的IGOT_PUSH_KEY是否有效 892 | const IGOT_PUSH_KEY_REGX = new RegExp('^[a-zA-Z0-9]{24}$'); 893 | if (!IGOT_PUSH_KEY_REGX.test(IGOT_PUSH_KEY)) { 894 | console.log('您所提供的IGOT_PUSH_KEY无效\n'); 895 | resolve(); 896 | return; 897 | } 898 | const options = { 899 | url: `https://push.hellyw.com/${IGOT_PUSH_KEY.toLowerCase()}`, 900 | body: `title=${text}&content=${desp}&${querystring.stringify(params)}`, 901 | headers: { 902 | 'Content-Type': 'application/x-www-form-urlencoded', 903 | }, 904 | timeout, 905 | }; 906 | $.post(options, (err, resp, data) => { 907 | try { 908 | if (err) { 909 | console.log('发送通知调用API失败!!\n'); 910 | console.log(err); 911 | } else { 912 | if (typeof data === 'string') data = JSON.parse(data); 913 | if (data.ret === 0) { 914 | console.log('iGot发送通知消息成功🎉\n'); 915 | } else { 916 | console.log(`iGot发送通知消息失败:${data.errMsg}\n`); 917 | } 918 | } 919 | } catch (e) { 920 | $.logErr(e, resp); 921 | } finally { 922 | resolve(data); 923 | } 924 | }); 925 | } else { 926 | resolve(); 927 | } 928 | }); 929 | } 930 | 931 | function pushPlusNotify(text, desp) { 932 | return new Promise((resolve) => { 933 | if (PUSH_PLUS_TOKEN) { 934 | desp = desp.replace(/[\n\r]/g, '
'); // 默认为html, 不支持plaintext 935 | const body = { 936 | token: `${PUSH_PLUS_TOKEN}`, 937 | title: `${text}`, 938 | content: `${desp}`, 939 | topic: `${PUSH_PLUS_USER}`, 940 | }; 941 | const options = { 942 | url: `https://www.pushplus.plus/send`, 943 | body: JSON.stringify(body), 944 | headers: { 945 | 'Content-Type': ' application/json', 946 | }, 947 | timeout, 948 | }; 949 | $.post(options, (err, resp, data) => { 950 | try { 951 | if (err) { 952 | console.log( 953 | `push+发送${ 954 | PUSH_PLUS_USER ? '一对多' : '一对一' 955 | }通知消息失败!!\n`, 956 | ); 957 | console.log(err); 958 | } else { 959 | data = JSON.parse(data); 960 | if (data.code === 200) { 961 | console.log( 962 | `push+发送${ 963 | PUSH_PLUS_USER ? '一对多' : '一对一' 964 | }通知消息完成。\n`, 965 | ); 966 | } else { 967 | console.log( 968 | `push+发送${ 969 | PUSH_PLUS_USER ? '一对多' : '一对一' 970 | }通知消息失败:${data.msg}\n`, 971 | ); 972 | } 973 | } 974 | } catch (e) { 975 | $.logErr(e, resp); 976 | } finally { 977 | resolve(data); 978 | } 979 | }); 980 | } else { 981 | resolve(); 982 | } 983 | }); 984 | } 985 | 986 | module.exports = { 987 | sendNotify, 988 | BARK_PUSH, 989 | }; 990 | 991 | // prettier-ignore 992 | function Env(t,s){return new class{constructor(t,s){this.name=t,this.data=null,this.dataFile="box.dat",this.logs=[],this.logSeparator="\n",this.startTime=(new Date).getTime(),Object.assign(this,s),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}getScript(t){return new Promise(s=>{$.get({url:t},(t,e,i)=>s(i))})}runScript(t,s){return new Promise(e=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let o=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");o=o?1*o:20,o=s&&s.timeout?s.timeout:o;const[h,a]=i.split("@"),r={url:`http://${a}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:o},headers:{"X-Key":h,Accept:"*/*"}};$.post(r,(t,s,i)=>e(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),s=this.path.resolve(process.cwd(),this.dataFile),e=this.fs.existsSync(t),i=!e&&this.fs.existsSync(s);if(!e&&!i)return{};{const i=e?t:s;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),s=this.path.resolve(process.cwd(),this.dataFile),e=this.fs.existsSync(t),i=!e&&this.fs.existsSync(s),o=JSON.stringify(this.data);e?this.fs.writeFileSync(t,o):i?this.fs.writeFileSync(s,o):this.fs.writeFileSync(t,o)}}lodash_get(t,s,e){const i=s.replace(/\[(\d+)\]/g,".$1").split(".");let o=t;for(const t of i)if(o=Object(o)[t],void 0===o)return e;return o}lodash_set(t,s,e){return Object(t)!==t?t:(Array.isArray(s)||(s=s.toString().match(/[^.[\]]+/g)||[]),s.slice(0,-1).reduce((t,e,i)=>Object(t[e])===t[e]?t[e]:t[e]=Math.abs(s[i+1])>>0==+s[i+1]?[]:{},t)[s[s.length-1]]=e,t)}getdata(t){let s=this.getval(t);if(/^@/.test(t)){const[,e,i]=/^@(.*?)\.(.*?)$/.exec(t),o=e?this.getval(e):"";if(o)try{const t=JSON.parse(o);s=t?this.lodash_get(t,i,""):s}catch(t){s=""}}return s}setdata(t,s){let e=!1;if(/^@/.test(s)){const[,i,o]=/^@(.*?)\.(.*?)$/.exec(s),h=this.getval(i),a=i?"null"===h?null:h||"{}":"{}";try{const s=JSON.parse(a);this.lodash_set(s,o,t),e=this.setval(JSON.stringify(s),i)}catch(s){const h={};this.lodash_set(h,o,t),e=this.setval(JSON.stringify(h),i)}}else e=$.setval(t,s);return e}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,s){return this.isSurge()||this.isLoon()?$persistentStore.write(t,s):this.isQuanX()?$prefs.setValueForKey(t,s):this.isNode()?(this.data=this.loaddata(),this.data[s]=t,this.writedata(),!0):this.data&&this.data[s]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,s=(()=>{})){t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon()?$httpClient.get(t,(t,e,i)=>{!t&&e&&(e.body=i,e.statusCode=e.status),s(t,e,i)}):this.isQuanX()?$task.fetch(t).then(t=>{const{statusCode:e,statusCode:i,headers:o,body:h}=t;s(null,{status:e,statusCode:i,headers:o,body:h},h)},t=>s(t)):this.isNode()&&(this.initGotEnv(t),this.got(t).on("redirect",(t,s)=>{try{const e=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();this.ckjar.setCookieSync(e,null),s.cookieJar=this.ckjar}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:e,statusCode:i,headers:o,body:h}=t;s(null,{status:e,statusCode:i,headers:o,body:h},h)},t=>s(t)))}post(t,s=(()=>{})){if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),delete t.headers["Content-Length"],this.isSurge()||this.isLoon())$httpClient.post(t,(t,e,i)=>{!t&&e&&(e.body=i,e.statusCode=e.status),s(t,e,i)});else if(this.isQuanX())t.method="POST",$task.fetch(t).then(t=>{const{statusCode:e,statusCode:i,headers:o,body:h}=t;s(null,{status:e,statusCode:i,headers:o,body:h},h)},t=>s(t));else if(this.isNode()){this.initGotEnv(t);const{url:e,...i}=t;this.got.post(e,i).then(t=>{const{statusCode:e,statusCode:i,headers:o,body:h}=t;s(null,{status:e,statusCode:i,headers:o,body:h},h)},t=>s(t))}}time(t){let s={"M+":(new Date).getMonth()+1,"d+":(new Date).getDate(),"H+":(new Date).getHours(),"m+":(new Date).getMinutes(),"s+":(new Date).getSeconds(),"q+":Math.floor(((new Date).getMonth()+3)/3),S:(new Date).getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,((new Date).getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in s)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?s[e]:("00"+s[e]).substr((""+s[e]).length)));return t}msg(s=t,e="",i="",o){const h=t=>!t||!this.isLoon()&&this.isSurge()?t:"string"==typeof t?this.isLoon()?t:this.isQuanX()?{"open-url":t}:void 0:"object"==typeof t&&(t["open-url"]||t["media-url"])?this.isLoon()?t["open-url"]:this.isQuanX()?t:void 0:void 0;$.isMute||(this.isSurge()||this.isLoon()?$notification.post(s,e,i,h(o)):this.isQuanX()&&$notify(s,e,i,h(o))),this.logs.push("","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="),this.logs.push(s),e&&this.logs.push(e),i&&this.logs.push(i)}log(...t){t.length>0?this.logs=[...this.logs,...t]:console.log(this.logs.join(this.logSeparator))}logErr(t,s){const e=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();e?$.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):$.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(s=>setTimeout(s,t))}done(t={}){const s=(new Date).getTime(),e=(s-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${e} \u79d2`),this.log(),(this.isSurge()||this.isQuanX()||this.isLoon())&&$done(t)}}(t,s)} 993 | --------------------------------------------------------------------------------