From 25c0819dbd35cce7fab3397d89c5562746e4e678 Mon Sep 17 00:00:00 2001 From: Nick007 Date: Fri, 24 Oct 2025 21:04:25 +0800 Subject: [PATCH] feat: introduce qq --- Dockerfile | 29 +++++++++++++++++++++-- README.md | 43 +++++++++++++++++++++++++++++++--- README_en.md | 41 +++++++++++++++++++++++++++++--- root/defaults/menu.xml | 4 ++-- root/scripts/qq/qq-restart.sh | 3 +++ root/scripts/start.sh | 31 +++++++++++++++++++++--- root/wechat.png | Bin 11050 -> 0 bytes 7 files changed, 138 insertions(+), 13 deletions(-) create mode 100755 root/scripts/qq/qq-restart.sh delete mode 100644 root/wechat.png diff --git a/Dockerfile b/Dockerfile index eb19f54..695cb01 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,7 +27,7 @@ RUN apt-get update && \ libgtk-3-0 libnspr4 libnss3 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 \ libxcomposite1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 \ libxss1 libxtst6 libatomic1 libxcomposite1 libxrender1 libxrandr2 libxkbcommon-x11-0 \ - libfontconfig1 libdbus-1-3 libnss3 libx11-xcb1 python3-tk + libfontconfig1 libdbus-1-3 libnss3 libx11-xcb1 python3-tk stalonetray RUN pip install --no-cache-dir python-xlib @@ -51,6 +51,26 @@ RUN case "$TARGETPLATFORM" in \ rm -f wechat.deb && \ echo "✅ WeChat installation completed for $WECHAT_ARCH" +# Install QQ based on target architecture +RUN case "$TARGETPLATFORM" in \ + "linux/amd64") \ + QQ_URL="https://dldir1v6.qq.com/qqfile/qq/QQNT/Linux/QQ_3.2.19_250904_amd64_01.deb"; \ + QQ_ARCH="x86_64" ;; \ + "linux/arm64") \ + QQ_URL="https://dldir1v6.qq.com/qqfile/qq/QQNT/Linux/QQ_3.2.19_250904_arm64_01.deb"; \ + QQ_ARCH="arm64" ;; \ + *) \ + echo "❌ Unsupported platform: $TARGETPLATFORM" >&2; \ + echo "Supported platforms: linux/amd64, linux/arm64" >&2; \ + exit 1 ;; \ + esac && \ + echo "📦 Downloading QQ for $QQ_ARCH architecture..." && \ + curl -fsSL -o qq.deb "$QQ_URL" && \ + echo "🔧 Installing QQ..." && \ + (dpkg -i qq.deb || (apt-get update && apt-get install -f -y && dpkg -i qq.deb)) && \ + rm -f qq.deb && \ + echo "✅ QQ installation completed for $QQ_ARCH" + # Clean up RUN apt-get purge -y --autoremove RUN apt-get autoclean && \ @@ -61,13 +81,18 @@ RUN apt-get autoclean && \ /var/tmp/* \ /tmp/* +# configure openbox dock mode for stalonetray +RUN sed -i '//,/<\/dock>/s/no<\/noStrut>/yes<\/noStrut>/' /etc/xdg/openbox/rc.xml + # set app name ENV TITLE="WeChat-Selkies" ENV TZ="Asia/Shanghai" ENV LC_ALL="zh_CN.UTF-8" +ENV AUTO_START_WECHAT="true" +ENV AUTO_START_QQ="false" # update favicon -COPY /root/wechat.png /usr/share/selkies/www/icon.png +RUN cp /usr/share/icons/hicolor/128x128/apps/wechat.png /usr/share/selkies/www/icon.png # add local files COPY /root / diff --git a/README.md b/README.md index 729f730..f9f1fc5 100644 --- a/README.md +++ b/README.md @@ -45,10 +45,12 @@ ### 快速部署 1. **直接使用已构建的镜像进行快速部署** + GitHub Container Registry镜像: ```bash docker run -it -p 3001:3001 -v ./config:/config ghcr.io/nickrunning/wechat-selkies:latest ``` + Docker Hub镜像: ```bash docker run -it -p 3001:3001 -v ./config:/config nickrunning/wechat-selkies:latest @@ -58,7 +60,40 @@ docker run -it -p 3001:3001 -v ./config:/config nickrunning/wechat-selkies:lates 在浏览器中访问:`https://localhost:3001` 或 `https://<服务器IP>:3001` -### 自定义部署步骤(源码部署) +### docker-compose 部署 +1. **创建项目目录并进入** + ```bash + mkdir wechat-selkies + cd wechat-selkies + ``` +2. **创建 docker-compose.yml 文件** + ```yaml + services: + wechat-selkies: + image: nickrunning/wechat-selkies:latest # or ghcr.io/nickrunning/wechat-selkies:latest + container_name: wechat-selkies + ports: + - "3001:3001" + volumes: + - ./config:/config + devices: + - /dev/dri:/dev/dri # optional, for hardware acceleration + environment: + - PUID=1000 # user ID + - PGID=100 # group ID + - TZ=Asia/Shanghai # timezone + - LC_ALL=zh_CN.UTF-8 # locale + - AUTO_START_WECHAT=true # default is true + - AUTO_START_QQ=false # default is false + # - CUSTOM_USER= # recommended to set a custom user name + # - PASSWORD= # recommended to set a password for selkies web ui + ``` +3. **启动服务** + ```bash + docker-compose up -d + ``` + +### 源码部署 1. **克隆项目** ```bash @@ -83,10 +118,10 @@ docker run -it -p 3001:3001 -v ./config:/config nickrunning/wechat-selkies:lates 本项目支持同时推送到 GitHub Container Registry 和 Docker Hub。如需启用 Docker Hub 推送功能,请在仓库下添加Environment Secrets和Environment Variables: -**必需的Environment Secrets:** +**Environment Secrets:** * DOCKERHUB_USERNAME: 你的 Docker Hub 用户名 * DOCKERHUB_TOKEN: 你的 Docker Hub Access Token -**必需的Environment Variables:** +**Environment Variables:** * ENABLE_DOCKERHUB: 设置为 `true` 来启用 Docker Hub 推送 #### 环境变量配置 @@ -102,6 +137,8 @@ docker run -it -p 3001:3001 -v ./config:/config nickrunning/wechat-selkies:lates | `LC_ALL` | `zh_CN.UTF-8` | 语言环境 | | `CUSTOM_USER` | - | 自定义用户名(推荐设置) | | `PASSWORD` | - | Web UI 访问密码(推荐设置) | +| `AUTO_START_WECHAT` | `true` | 是否自动启动微信客户端 | +| `AUTO_START_QQ` | `false` | 是否自动启动 QQ 客户端 | #### 端口配置 diff --git a/README_en.md b/README_en.md index 576207a..c43267c 100644 --- a/README_en.md +++ b/README_en.md @@ -58,7 +58,40 @@ docker run -it -p 3001:3001 -v ./config:/config nickrunning/wechat-selkies:lates Open in browser: `https://localhost:3001` or `https://:3001` -### Custom Deployment (Source Code Deployment) +### docker-compose Deployment +1. **Create project directory and navigate into it** + ```bash + mkdir wechat-selkies + cd wechat-selkies + ``` +2. **Create `docker-compose.yml` file with the following content** + ```yaml + services: + wechat-selkies: + image: nickrunning/wechat-selkies:latest # or ghcr.io/nickrunning/wechat-selkies:latest + container_name: wechat-selkies + ports: + - "3001:3001" + volumes: + - ./config:/config + devices: + - /dev/dri:/dev/dri # optional, for hardware acceleration + environment: + - PUID=1000 # user ID + - PGID=100 # group ID + - TZ=Asia/Shanghai # timezone + - LC_ALL=zh_CN.UTF-8 # locale + - AUTO_START_WECHAT=true # default is true + - AUTO_START_QQ=false # default is false + # - CUSTOM_USER= # recommended to set a custom user name + # - PASSWORD= # recommended to set a password for selkies web ui + ``` +3. **Start the service** + ```bash + docker-compose up -d + ``` + +### Source Code Deployment 1. **Clone the repository** ```bash @@ -82,11 +115,11 @@ For more custom configurations, please refer to [Selkies Base Images from LinuxS #### Docker Hub Push Configuration This project supports pushing to both GitHub Container Registry and Docker Hub. Docker Hub push is optional and requires manual configuration. Please add the following Environment Secrets and Environment Variables in your repository to enable Docker Hub push functionality: -**Required Environment Secrets:** +**Environment Secrets:** * `DOCKERHUB_USERNAME`: Your Docker Hub username * `DOCKERHUB_TOKEN`: Your Docker Hub Access Token -**Required Environment Variables:** +**Environment Variables:** * `ENABLE_DOCKERHUB`: Set to `true` to enable Docker Hub push #### Environment Variables @@ -102,6 +135,8 @@ Configure the following environment variables in `docker-compose.yml`: | `LC_ALL` | `zh_CN.UTF-8` | Locale setting | | `CUSTOM_USER` | - | Custom username (recommended) | | `PASSWORD` | - | Web UI access password (recommended) | +| `AUTO_START_WECHAT` | `true` | Whether to automatically start the WeChat client | +| `AUTO_START_QQ` | `false` | Whether to automatically start the QQ client | #### Port Configuration diff --git a/root/defaults/menu.xml b/root/defaults/menu.xml index fe9f87f..8bc8504 100644 --- a/root/defaults/menu.xml +++ b/root/defaults/menu.xml @@ -2,7 +2,7 @@ /usr/bin/xterm -/scripts/wechat/wechat-restart.sh -/scripts/wechat/wechat-unminimize.sh +/scripts/wechat/wechat-restart.sh +/scripts/qq/qq-restart.sh diff --git a/root/scripts/qq/qq-restart.sh b/root/scripts/qq/qq-restart.sh new file mode 100755 index 0000000..1ff1e69 --- /dev/null +++ b/root/scripts/qq/qq-restart.sh @@ -0,0 +1,3 @@ +#!/bin/bash +pkill -9 -f /usr/bin/qq 2>/dev/null +nohup /usr/bin/qq --no-sandbox >/dev/null 2>&1 & \ No newline at end of file diff --git a/root/scripts/start.sh b/root/scripts/start.sh index a08f548..a6f914a 100755 --- a/root/scripts/start.sh +++ b/root/scripts/start.sh @@ -1,7 +1,32 @@ #!/bin/bash -# start WeChat application in the background if wechat exists -if [ -f /usr/bin/wechat ]; then nohup /usr/bin/wechat > /dev/null 2>&1 & fi +# configure openbox dock mode for stalonetray +if [ ! -f /config/.config/openbox/rc.xml ] || grep -A20 "" /config/.config/openbox/rc.xml | grep -q "no"; then + mkdir -p /config/.config/openbox + [ ! -f /config/.config/openbox/rc.xml ] && cp /etc/xdg/openbox/rc.xml /config/.config/openbox/ + sed -i '//,/<\/dock>/s/no<\/noStrut>/yes<\/noStrut>/' /config/.config/openbox/rc.xml + openbox --reconfigure +fi +# update openbox menu if differs from default +if [ ! -f /config/.config/openbox/menu.xml ] || ! cmp /defaults/menu.xml /config/.config/openbox/menu.xml; then + mkdir -p /config/.config/openbox + cp /defaults/menu.xml /config/.config/openbox/menu.xml + openbox --reconfigure +fi + +nohup stalonetray --dockapp-mode simple > /dev/null 2>&1 & + +# start WeChat application in the background if exists and auto-start enabled +if [ "$AUTO_START_WECHAT" = "true" ]; then + if [ -f /usr/bin/wechat ]; then nohup /usr/bin/wechat > /dev/null 2>&1 & fi +fi + +# start QQ application in the background if exists and auto-start enabled +if [ "$AUTO_START_QQ" = "true" ]; then + if [ -f /usr/bin/qq ]; then nohup /usr/bin/qq --no-sandbox > /dev/null 2>&1 & fi +fi + +# !deprecated: start window switcher application in the background # start window switcher application in the background -nohup sleep 2 && python /scripts/window_switcher.py > /dev/null 2>&1 & \ No newline at end of file +# nohup sleep 2 && python /scripts/window_switcher.py > /dev/null 2>&1 & diff --git a/root/wechat.png b/root/wechat.png deleted file mode 100644 index f9dd9b746df2eb9c128913199a0cadeea36035a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11050 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 E0SN^zaR2}S