Compare commits

...

21 Commits

Author SHA1 Message Date
mofeng-git
651f9a4f4e feat: 更新演示站点地址 2025-10-11 15:43:04 +08:00
mofeng-git
7777f5e490 feat: 更新说明文档 2025-10-11 11:21:47 +08:00
mofeng-git
3ab5e2b431 fix: 修复 OEC TURBO 硬件编解码权限问题 2025-10-01 07:42:08 +08:00
mofeng-git
65874c6b43 fix: 修复 docker 版本VNC 服务权限问题 2025-09-30 23:53:35 +08:00
mofeng-git
67b943c151 fix: 修复 dnsmasq 软件包启动问题,解决引入的 DNS 解析 BUG 2025-09-30 23:53:28 +08:00
mofeng-git
593de19df5 fix: 更新网页部分文本 2025-09-30 21:32:35 +08:00
SilentWind
5296e61281
fix 2025-09-30 13:08:03 +08:00
mofeng-git
1729badc55 feat: 一些新功能和修复
1.启用初步 DRM 显示支持
2.预装 gostc 内网穿透
3.修复 systemd.journal 缺失问题
2025-09-29 21:18:41 +08:00
mofeng-git
9373790f37 feat: 更新设备配置和服务依赖
- 在 devices.sh 中启用 rc-local.service,以确保 kvmd 服务的正常运行
- 更新 ustreamer 配置,修正音频设备参数
- 修改 kvmd.service 文件,添加对 rc-local.service 的依赖
2025-09-28 23:43:04 +08:00
mofeng-git
edb9112435 feat: 大幅优化 RKMPP 在 ustreamer 中的编解码性能
feat: 添加 DRM 初步支持

fix: 修复 OEC TURBO 硬件编解码设备权限错误
2025-09-28 15:24:25 +08:00
mofeng-git
0328163a9e fix: 玩客云 sn 读取错误 2025-09-27 16:45:58 +08:00
mofeng-git
0c9d94e1c5 feat: 更新安装脚本以支持 dnsmasq 服务,解决 otgnet 服务所需依赖
- 新增 dnsmasq 包安装
- 启用 dnsmasq 服务并禁用 systemd-resolved
- 添加 IP 转发配置
2025-09-27 10:53:25 +08:00
mofeng-git
d4bd94cb8a feat: 更新网络配置和MAC地址生成逻辑
- 在 install.sh 中为 onecloud 和 onecloud-pro 平台启用基于 SN 的 MAC 地址生成机制
2025-09-27 09:50:34 +08:00
mofeng-git
e7c891353b feat: 新增OEC-Turbo设备支持和完善构建系统
- 新增OEC-Turbo设备构建支持,基于Debian 12 Armbian镜像
- 实现OEC-Turbo专用rootfs准备函数,支持GPT分区结构
- 添加VPU硬件编码支持,启用RK MPP加速
- 实现DTB自动下载和替换功能,避免loop设备冲突
- 修复设备特定配置函数命名机制,支持连字符转下划线
- 优化rc.local文件下载逻辑,允许文件可选不存在
- 完善系统FFmpeg包版本检测,支持bookworm和noble
- 更新GitHub Actions工作流支持OEC-Turbo设备CI构建
2025-09-20 12:49:58 +08:00
mofeng-git
3f8a9e3b2c feat: 新增香橙派 Zero One 设备构建支持
- 在 build_img.sh 中新增 orangepi-zero 构建目标支持
2025-09-20 11:31:57 +08:00
mofeng-git
4d4f528178 feat: 增强构建系统功能和设备兼容性
- 在 common.sh 中新增 download_rc_local 函数,支持自动下载平台特定的 rc.local 文件
- 集成 rc.local 自动下载到 install.sh 的 config_base_files 函数中
- 更新 cumebox2 设备配置,使用较新的 Armbian 镜像版本并增加 900MB 扩展空间
- 更新 octopus-flanet 设备使用最新的 Armbian 25.05.0 镜像
- 在 udev 规则中为 ttyUSB0 设备添加 kvmd-hid 符号链接支持
- 完善文件下载机制,支持 GitHub Actions 环境下的临时文件清理
2025-09-19 20:15:37 +08:00
SilentWind
201c615ce2
Merge pull request #178 from mofeng-git/dev
适配 Onecloud Pro 设备
2025-09-19 15:53:13 +08:00
SilentWind
892d2b6f41
fix: 增加 ATX 初始值 2025-09-14 09:10:40 +08:00
SilentWind
30dd4290ab
Merge pull request #171 from mofeng-git/dev
Dev
2025-08-27 15:12:20 +08:00
SilentWind
6f4cf12c69
Merge pull request #170 from mofeng-git/dev
docs: 添加英文文档和完善中文README文档
2025-08-24 16:09:27 +08:00
SilentWind
c262db4a18
Merge pull request #167 from mofeng-git/dev
合并 Dev  分支开发内容
2025-08-23 11:02:01 +08:00
26 changed files with 460 additions and 82 deletions

View File

@ -15,6 +15,8 @@ on:
- vm
- e900v22c
- octopus-flanet
- orangepi-zero
- oec-turbo
- all
create_release:
description: 'Create GitHub Release'

View File

@ -11,8 +11,8 @@
[![GitHub license](https://img.shields.io/github/license/mofeng-git/One-KVM)](https://github.com/mofeng-git/One-KVM/blob/master/LICENSE)
<p>
<a href="https://one-kvm.mofeng.run">📖 详细文档</a>
<a href="https://kvmd-demo.mofeng.run">🚀 在线演示</a>
<a href="https://docs.one-kvm.cn">📖 详细文档</a>
<a href="https://demo.one-kvm.cn/">🚀 在线演示</a>
<a href="#快速开始">⚡ 快速开始</a>
<a href="#功能介绍">📊 功能介绍</a>
</p>
@ -68,7 +68,7 @@
|:--------:|:-------:|:-----:|:------:|:------:|
| 简体中文 WebUI | ✅ | ❌ | ✅ | ✅ |
| 远程视频流 | MJPEG/H.264 | MJPEG/H.264 | MJPEG/H.264 | MJPEG/H.264 |
| H.264 视频编码 | CPU | GPU | 未知 | GPU |
| H.264 视频编码 | CPU/GPU | GPU | 未知 | GPU |
| 远程音频流 | ✅ | ✅ | ✅ | ✅ |
| 远程鼠键控制 | OTG/CH9329 | OTG/CH9329/Pico/Bluetooth | OTG | OTG |
| VNC 控制 | ✅ | ✅ | ✅ | ✅ |
@ -87,7 +87,7 @@ Docker 版本支持 OTG 或 CH9329 作为虚拟 HID兼容 amd64、arm64、arm
#### 一键脚本部署
```bash
curl -sSL https://one-kvm.mofeng.run/quick_start.sh -o quick_start.sh && bash quick_start.sh
curl -sSL https://docs.one-kvm.cn/quick_start.sh -o quick_start.sh && bash quick_start.sh
```
#### 手动部署
@ -157,6 +157,7 @@ sudo docker run --name kvmd -itd \
- **GitHub Releases** [https://github.com/mofeng-git/One-KVM/releases](https://github.com/mofeng-git/One-KVM/releases)
**其他下载方式:**
- **免登录高速下载:** [http://sd1.files.one-kvm.cn/](http://sd1.files.one-kvm.cn/)(由群友赞助,支持直链,接入 EdgeOne CDN建议使用多线程下载工具下载获取最高速度
- **免登录下载:** [https://pan.huang1111.cn/s/mxkx3T1](https://pan.huang1111.cn/s/mxkx3T1) (由 Huang1111公益计划 提供)
- **百度网盘:** [https://pan.baidu.com/s/166-2Y8PBF4SbHXFkGmFJYg?pwd=o9aj](https://pan.baidu.com/s/166-2Y8PBF4SbHXFkGmFJYg?pwd=o9aj) 提取码o9aj
@ -170,19 +171,7 @@ sudo docker run --name kvmd -itd \
| Virtualbox | Virtualbox-uefi | USB 采集卡、CH9329 | 241004 | ✅ |
| s905l3a 通用包 | E900v22c | USB 采集卡、OTG | 241004 | ✅ |
| 我家云 | Chainedbox | USB 采集卡、OTG | 241004 | ✅ |
| 龙芯久久派 | 2k0300 | USB 采集卡、CH9329 | 241025 | ✅ |
## 🤝 贡献指南
欢迎各种形式的贡献!
### 如何贡献
1. **Fork 本仓库**
2. **创建功能分支:** `git checkout -b feature/AmazingFeature`
3. **提交更改:** `git commit -m 'Add some AmazingFeature'`
4. **推送到分支:** `git push origin feature/AmazingFeature`
5. **提交 Pull Request**
| 龙芯久久派 | 2k0300 | USB 采集卡、CH9329 | 241025 | ❌ |
### 报告问题
@ -280,6 +269,30 @@ sudo docker run --name kvmd -itd \
- 爱发电用户_e3202
- 一语念白
- 云边
- 爱发电用户_5a711
- 爱发电用户_9a706
- T0m9ir1SUKI
- 爱发电用户_56d52
- 爱发电用户_3N6F
- DUSK
- 飘零
- .
- 饭太稀
- 葱
- ......
</details>
@ -296,6 +309,14 @@ sudo docker run --name kvmd -itd \
**文件存储服务:**
- **[Huang1111公益计划](https://pan.huang1111.cn/s/mxkx3T1)** - 提供免登录下载服务
**云服务商**
- **[林枫云](https://www.dkdun.cn)** - 赞助了本项目宁波大带宽服务器
![林枫云](./img/36076FEFF0898A80EBD5756D28F4076C.png)
林枫云主营国内外地域的精品线路业务服务器、高主频游戏服务器和大带宽服务器。
## 📚 其他
### 使用的开源项目

View File

@ -68,8 +68,9 @@ RUN sed -i 's/deb.debian.org/mirrors.tuna.tsinghua.edu.cn/' /etc/apt/sources.lis
;; \
arm64) \
apt-get install -y --no-install-recommends \
v4l-utils libv4l-0 \
libstdc++6 \
v4l-utils libv4l-0 libavutil57 \
libstdc++6 libavcodec59 libavformat59 \
libswscale6 libavfilter8 libavdevice59 \
libva2 libva-drm2 libva-x11-2 \
libvdpau1 ocl-icd-libopencl1 \
;; \
@ -86,6 +87,18 @@ RUN sed -i 's/deb.debian.org/mirrors.tuna.tsinghua.edu.cn/' /etc/apt/sources.lis
fi \
&& curl https://github.com/tsl0922/ttyd/releases/download/1.7.7/ttyd.$ARCH -L -o /usr/local/bin/ttyd \
&& chmod +x /usr/local/bin/ttyd \
&& mkdir -p /tmp/gostc && cd /tmp/gostc \
&& case ${TARGETARCH} in \
amd64) GOSTC_ARCH=amd64_v1 ;; \
arm) GOSTC_ARCH=arm_7 ;; \
arm64) GOSTC_ARCH=arm64_v8.0 ;; \
*) echo "Unsupported architecture for gostc: ${TARGETARCH}" && exit 1 ;; \
esac \
&& curl -L https://github.com/mofeng-git/gostc-open/releases/download/v2.0.8-beta.2/gostc_linux_${GOSTC_ARCH}.tar.gz -o gostc.tar.gz \
&& tar -xzf gostc.tar.gz \
&& mv gostc /usr/bin/ \
&& chmod +x /usr/bin/gostc \
&& cd / && rm -rf /tmp/gostc \
&& adduser kvmd --gecos "" --disabled-password \
&& ln -sf /usr/share/tesseract-ocr/*/tessdata /usr/share/tessdata \
&& mkdir -p /etc/kvmd_backup/override.d \
@ -97,6 +110,8 @@ RUN sed -i 's/deb.debian.org/mirrors.tuna.tsinghua.edu.cn/' /etc/apt/sources.lis
/run/kvmd \
/tmp/kvmd-nginx \
&& touch /run/kvmd/ustreamer.sock \
&& groupadd kvmd-selfauth \
&& usermod -a -G kvmd-selfauth root \
&& apt clean \
&& rm -rf /var/lib/apt/lists/* \
&& rm -rf /tmp/lib /tmp/wheel \

View File

@ -54,16 +54,13 @@ RUN sed -i 's/deb.debian.org/mirrors.tuna.tsinghua.edu.cn/' /etc/apt/sources.lis
mesa-vdpau-drivers \
v4l-utils \
libv4l-dev \
&& if [ ${TARGETARCH} != arm64 ]; then \
apt-get install -y --no-install-recommends \
ffmpeg \
libavcodec-dev \
libavformat-dev \
libavutil-dev \
libswscale-dev \
libavfilter-dev \
libavdevice-dev; \
fi \
ffmpeg \
libavcodec-dev \
libavformat-dev \
libavutil-dev \
libswscale-dev \
libavfilter-dev \
libavdevice-dev \
&& if [ ${TARGETARCH} != arm ] && [ ${TARGETARCH} != arm64 ]; then \
apt-get install -y --no-install-recommends \
vainfo \
@ -148,7 +145,7 @@ RUN git clone --depth=1 https://gitlab.freedesktop.org/libnice/libnice /tmp/libn
# 编译 Rockchip MPP、RGA 和 FFmpeg仅 arm64
RUN if [ ${TARGETARCH} = arm64 ]; then \
git clone -b jellyfin-mpp --depth=1 https://github.com/nyanmisaka/mpp.git /tmp/rkmpp \
git clone --depth=1 https://github.com/rockchip-linux/mpp.git /tmp/rkmpp \
&& mkdir -p /tmp/rkmpp/rkmpp_build && cd /tmp/rkmpp/rkmpp_build \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DBUILD_TEST=OFF .. \
&& make -j$(nproc) \
@ -158,21 +155,17 @@ RUN if [ ${TARGETARCH} = arm64 ]; then \
&& meson setup rkrga rkrga_build --prefix=/usr --libdir=lib --buildtype=release -Dcpp_args=-fpermissive -Dlibdrm=false -Dlibrga_demo=false \
&& meson configure rkrga_build > /dev/null \
&& ninja -C rkrga_build install \
&& git clone --depth=1 https://github.com/nyanmisaka/ffmpeg-rockchip.git /tmp/ffmpeg-rockchip \
&& cd /tmp/ffmpeg-rockchip \
&& ./configure --prefix=/usr --enable-gpl --enable-version3 --enable-libdrm --enable-rkmpp --enable-rkrga \
--enable-libv4l2 --enable-libx264 --enable-shared --disable-programs \
--disable-doc --disable-htmlpages --disable-manpages --disable-network --disable-protocols \
--disable-decoders --disable-debug --disable-alsa \
&& make -j$(nproc) \
&& make install \
&& rm -rf /tmp/rkmpp /tmp/rkrga /tmp/ffmpeg-rockchip; \
&& rm -rf /tmp/rkmpp /tmp/rkrga; \
fi
# 编译 ustreamer
RUN sed --in-place --expression 's|^#include "refcount.h"$|#include "../refcount.h"|g' /usr/include/janus/plugins/plugin.h \
&& git clone --depth=1 https://github.com/mofeng-git/ustreamer /tmp/ustreamer \
&& make -j$(nproc) WITH_PYTHON=1 WITH_JANUS=1 WITH_FFMPEG=1 -C /tmp/ustreamer \
&& if [ ${TARGETARCH} = arm64 ]; then \
make -j$(nproc) WITH_PYTHON=1 WITH_JANUS=1 WITH_FFMPEG=1 WITH_MPP=1 WITH_DRM=1 -C /tmp/ustreamer; \
else \
make -j$(nproc) WITH_PYTHON=1 WITH_JANUS=1 WITH_FFMPEG=1 WITH_DRM=1 -C /tmp/ustreamer; \
fi \
&& /tmp/ustreamer/ustreamer -v \
&& /tmp/ustreamer/ustreamer-dump -v \
&& cp /tmp/ustreamer/python/dist/*.whl /tmp/wheel/
@ -186,9 +179,8 @@ RUN mkdir /tmp/lib \
&& find /usr/lib -name "libsrtp2.so.*" -exec cp {} /tmp/lib/ \; \
&& find /usr/lib -name "libwebsockets.so.*" -exec cp {} /tmp/lib/ \; \
&& if [ ${TARGETARCH} = arm64 ]; then \
find /usr/lib -name "libav*.so.*" -exec cp {} /tmp/lib/ \; \
&& find /usr/lib -name "libsw*.so.*" -exec cp {} /tmp/lib/ \; \
find /usr/lib -name "libsw*.so.*" -exec cp {} /tmp/lib/ \; \
&& find /usr/lib -name "libpostproc.so.*" -exec cp {} /tmp/lib/ \; \
&& find /usr/lib -name "librockchip*" -exec cp {} /tmp/lib/ \; \
&& find /usr/lib -name "librga.so.*" -exec cp {} /tmp/lib/ \; ; \
fi
fi

View File

@ -101,6 +101,20 @@ build_target() {
onecloud_pro_rootfs
local arch="aarch64"
local device_type="gpio-onecloud-pro video1"
local network_type="systemd-networkd"
NEED_PREPARE_DNS=true
;;
orangepi-zero)
orangepizero_rootfs
local arch="armhf"
local device_type=""
local network_type=""
NEED_PREPARE_DNS=true
;;
oec-turbo)
oec_turbo_rootfs
local arch="aarch64"
local device_type="vpu"
local network_type=""
NEED_PREPARE_DNS=true
;;
@ -140,6 +154,12 @@ build_target() {
onecloud-pro)
pack_img "Onecloud-Pro"
;;
orangepi-zero)
pack_img "Orangepi-Zero"
;;
oec-turbo)
pack_img "OEC-Turbo"
;;
*)
echo "错误:未知的打包类型 for '$target'" >&2
;;
@ -158,7 +178,7 @@ build_target() {
# 检查是否提供了目标参数
if [ -z "$1" ]; then
echo "用法: $0 <target|all>"
echo "可用目标: onecloud, cumebox2, chainedbox, vm, e900v22c, octopus-flanet, onecloud-pro"
echo "可用目标: onecloud, cumebox2, chainedbox, vm, e900v22c, octopus-flanet, onecloud-pro, orangepi-zero, oec-turbo"
exit 1
fi
@ -178,6 +198,8 @@ if [ "$1" = "all" ]; then
build_target "e900v22c"
build_target "octopus-flanet"
build_target "onecloud-pro"
build_target "orangepi-zero"
build_target "oec-turbo"
echo "信息:所有目标构建完成。"
else
build_target "$1"

View File

@ -244,6 +244,37 @@ download_file_if_missing() {
return 1
}
# 下载 rc.local 文件
download_rc_local() {
local platform_id="$1"
local rc_local_path="$SRCPATH/image/$platform_id/rc.local"
local relative_path="image/$platform_id/rc.local"
local remote_url="$REMOTE_PREFIX/$relative_path"
echo "信息:检查是否需要下载 rc.local 文件 ($platform_id)..."
# 如果本地文件不存在,尝试下载
if [ ! -f "$rc_local_path" ]; then
echo "信息:本地 rc.local 文件不存在,尝试从远程下载..."
ensure_dir "$(dirname "$rc_local_path")"
if curl -sSL --fail "$remote_url" -o "$rc_local_path"; then
echo "信息:成功下载 rc.local 文件:$remote_url"
# 在 GitHub Actions 环境中记录下载的文件
if is_github_actions; then
echo "$rc_local_path" >> "$DOWNLOADED_FILES_LIST"
fi
return 0
else
echo "信息:远程 rc.local 文件不存在或下载失败:$remote_url"
return 1
fi
else
echo "信息:使用本地 rc.local 文件:$rc_local_path"
return 0
fi
}
# 清理下载的文件(仅在 GitHub Actions 环境中)
cleanup_downloaded_files() {
if is_github_actions && [[ -f "$DOWNLOADED_FILES_LIST" ]]; then

View File

@ -66,9 +66,10 @@ onecloud_rootfs() {
}
cumebox2_rootfs() {
local source_image="$SRCPATH/image/cumebox2/Armbian_25.2.2_Khadas-vim1_bookworm_current_6.12.17_minimal.img"
local source_image="$SRCPATH/image/cumebox2/Armbian_24.8.1_Khadas-vim1_bookworm_current_6.6.47_minimal.img"
local target_image="$TMPDIR/rootfs.img"
local offset=$((8192 * 512))
local add_size_mb=900
echo "信息:准备 Cumebox2 Rootfs..."
ensure_dir "$TMPDIR"
@ -77,7 +78,10 @@ cumebox2_rootfs() {
download_file_if_missing "$source_image" || { echo "错误:下载 Cumebox2 原始镜像失败" >&2; exit 1; }
cp "$source_image" "$target_image" || { echo "错误:复制 Cumebox2 原始镜像失败" >&2; exit 1; }
echo "信息:扩展镜像文件 (${add_size_mb}MB)..."
sudo dd if=/dev/zero bs=1M count="$add_size_mb" >> "$target_image" || { echo "错误:扩展镜像文件失败" >&2; exit 1; }
echo "信息:调整镜像分区大小..."
sudo parted -s "$target_image" resizepart 1 100% || { echo "错误:使用 parted 调整分区大小失败" >&2; exit 1; }
@ -188,7 +192,7 @@ e900v22c_rootfs() {
}
octopus_flanet_rootfs() {
local source_image="$SRCPATH/image/octopus-flanet/Armbian_24.11.0_amlogic_s912_bookworm_6.1.114_server_2024.11.01.img"
local source_image="$SRCPATH/image/octopus-flanet/Armbian_25.05.0_amlogic_s912_bookworm_6.1.129_server_2025.03.02.img"
local target_image="$TMPDIR/rootfs.img"
local boot_offset=$((8192 * 512))
local rootfs_offset=$((1056768 * 512))
@ -262,6 +266,40 @@ onecloud_pro_rootfs() {
echo "信息Octopus-Planet Rootfs 准备完成loop 设备 $LOOPDEV 已就绪。"
}
orangepizero_rootfs() {
local source_image="$SRCPATH/image/orangepi-zero/Armbian_community_25.11.0-trunk.208_Orangepizero_bookworm_current_6.12.47_minimal.img"
local target_image="$TMPDIR/rootfs.img"
local offset=$((8192 * 512))
local add_size_mb=600
echo "信息:准备 Orange Pi Zero Rootfs..."
ensure_dir "$TMPDIR"
echo "信息:下载或使用本地 Orange Pi Zero 原始镜像..."
download_file_if_missing "$source_image" || { echo "错误:下载 Orange Pi Zero 原始镜像失败" >&2; exit 1; }
cp "$source_image" "$target_image" || { echo "错误:复制 Orange Pi Zero 原始镜像失败" >&2; exit 1; }
echo "信息:扩展镜像文件 (${add_size_mb}MB)..."
sudo dd if=/dev/zero bs=1M count="$add_size_mb" >> "$target_image" || { echo "错误:扩展镜像文件失败" >&2; exit 1; }
echo "信息:调整镜像分区大小..."
sudo parted -s "$target_image" resizepart 1 100% || { echo "错误:使用 parted 调整分区大小失败" >&2; exit 1; }
find_loop_device
sudo losetup -P "$LOOPDEV" "$target_image" || { echo "错误:设置 loop 设备失败" >&2; exit 1; }
echo "信息:检查并调整文件系统大小..."
sudo e2fsck -y -f "${LOOPDEV}p1" || { echo "错误:文件系统检查失败" >&2; exit 1; }
sudo resize2fs "${LOOPDEV}p1" || { echo "错误:调整文件系统大小失败" >&2; exit 1; }
# 重新设置 LOOPDEV 为分区
sudo losetup -d "$LOOPDEV"
sudo losetup "$LOOPDEV" "$target_image" -o "$offset" || { echo "错误:重新设置 loop 设备失败" >&2; exit 1; }
echo "信息Orange Pi Zero Rootfs 准备完成。"
}
# --- 特定设备的文件配置函数 ---
config_cumebox2_files() {
@ -286,11 +324,120 @@ config_cumebox2_files() {
config_octopus_flanet_files() {
echo "信息:为 Octopus-Planet 配置特定文件 (model_database.conf)..."
# 自动下载 Octopus-Planet 相关文件(如果不存在)
local config_file="$SRCPATH/image/octopus-flanet/model_database.conf"
download_file_if_missing "$config_file" || echo "警告:下载 Octopus-Planet 配置文件失败"
sudo cp "$config_file" "$ROOTFS/etc/model_database.conf" || echo "警告:复制 model_database.conf 失败"
}
}
config_orangepi_zero_files() {
echo "信息:配置 Orange Pi Zero 特定文件..."
# 清空 modules.conf 文件,避免加载不必要的模块
run_in_chroot "echo 'libcomposite' > /etc/modules-load.d/modules.conf"
echo "信息Orange Pi Zero 特定配置完成。"
}
config_onecloud_pro_files() {
echo "信息:配置 Onecloud Pro 特定文件..."
echo "信息Onecloud Pro 特定配置完成。"
}
config_onecloud_files() {
echo "信息:配置 Onecloud 特定文件..."
# 在 ustreamer 命令中添加 DRM 设备配置
echo "信息:为 Onecloud 添加 DRM 设备支持..."
run_in_chroot "sed -i \"/--device=\\/dev\\/video0/a\\ - \\\"--drm-device=/dev/dri/card1\\\"\" /etc/kvmd/override.yaml"
echo "信息Onecloud 特定配置完成。"
}
oec_turbo_rootfs() {
local source_image="$SRCPATH/image/oec-turbo/Flash_Armbian_25.05.0_rockchip_efused-wxy-oec_bookworm_6.1.99_server_2025.03.20.img"
local target_image="$TMPDIR/rootfs.img"
local rootfs_offset=$((1409024 * 512)) # 根据分区7的起始扇区计算
echo "信息:准备 OEC-Turbo Rootfs (Debian 12)..."
ensure_dir "$TMPDIR"
echo "信息:下载或使用本地 OEC-Turbo 原始镜像..."
download_file_if_missing "$source_image" || { echo "错误:下载 OEC-Turbo 原始镜像失败" >&2; exit 1; }
cp "$source_image" "$target_image" || { echo "错误:复制 OEC-Turbo 原始镜像失败" >&2; exit 1; }
find_loop_device
# 设置 loop 设备指向 rootfs 分区 (分区7)
sudo losetup "$LOOPDEV" "$target_image" -o "$rootfs_offset" || { echo "错误:设置 loop 设备失败" >&2; exit 1; }
echo "信息OEC-Turbo Rootfs 准备完成loop 设备 $LOOPDEV 已就绪。"
}
config_oec_turbo_files() {
echo "信息:配置 OEC-Turbo 特定文件..."
# 替换 override.yaml 中的硬件编码配置,启用 RK MPP 硬件编码
echo "信息:配置 VPU 硬件编码支持..."
run_in_chroot "sed -i 's/--h264-hwenc=disabled/--h264-hwenc=rkmpp/g' /etc/kvmd/override.yaml"
run_in_chroot "cat > /etc/udev/rules.d/99-kvmd-hw-access.rules <<'EOF'
SUBSYSTEM=="dma_heap", KERNEL=="system-uncached", GROUP="render", MODE="0660"
KERNEL=="mpp_service", GROUP="render", MODE="0660"
EOF"
# 配置 rc.local 自启脚本,添加设备权限设置
echo "信息:配置 rc.local 自启脚本..."
run_in_chroot "cat > /etc/rc.local << 'EOF'
#!/bin/bash
usermod -aG render,video kvmd
exit 0
EOF"
run_in_chroot "chmod +x /etc/rc.local"
# 确保 rc-local.service 被启用,以便 kvmd 服务可以依赖它
echo "信息:启用 rc-local.service 服务..."
run_in_chroot "systemctl enable rc-local.service"
# 替换 DTB 文件
replace_oec_turbo_dtb
echo "信息OEC-Turbo 特定配置完成。"
}
replace_oec_turbo_dtb() {
local dtb_source="$SRCPATH/image/oec-turbo/rk3566-onething-oec-box.dtb"
local target_image="$TMPDIR/rootfs.img"
local boot_offset=$((360448 * 512)) # boot 分区6的偏移
local boot_mount="$TMPDIR/oec_boot_mount"
local dtb_target_path="dtb/rockchip/rk3566-onething-oec-box.dtb"
local boot_loopdev=""
echo "信息:替换 OEC-Turbo DTB 文件..."
if [ ! -f "$dtb_source" ]; then
echo "信息:尝试下载 DTB 文件..."
download_file_if_missing "$dtb_source"
fi
echo "信息:为 boot 分区查找独立的 loop 设备..."
# 查找一个新的loop设备用于boot分区
boot_loopdev=$(losetup -f)
ensure_dir "$boot_mount"
losetup -o "$boot_offset" "$boot_loopdev" "$target_image"
mount "$boot_loopdev" "$boot_mount"
# 确保目标目录存在并复制 DTB 文件
mkdir -p "$boot_mount/$(dirname "$dtb_target_path")"
cp "$dtb_source" "$boot_mount/$dtb_target_path"
echo "信息DTB 文件替换成功: $dtb_target_path"
umount "$boot_mount"
losetup -d "$boot_loopdev"
rmdir "$boot_mount"
}

View File

@ -77,6 +77,8 @@ config_base_files() {
sudo cp scripts/kvmd-gencert scripts/kvmd-bootconfig scripts/kvmd-certbot scripts/kvmd-udev-hdmiusb-check scripts/kvmd-udev-restart-pass build/scripts/kvmd-firstrun.sh "$ROOTFS/usr/bin/"
sudo chmod +x "$ROOTFS/usr/bin/kvmd-gencert" "$ROOTFS/usr/bin/kvmd-bootconfig" "$ROOTFS/usr/bin/kvmd-certbot" "$ROOTFS/usr/bin/kvmd-udev-hdmiusb-check" "$ROOTFS/usr/bin/kvmd-udev-restart-pass" "$ROOTFS/usr/bin/kvmd-firstrun.sh"
# 尝试下载或使用本地 rc.local 文件
download_rc_local "$platform_id" || echo "信息rc.local 文件不存在,跳过"
if [ -f "$SRCPATH/image/$platform_id/rc.local" ]; then
echo "信息:复制设备特定的 rc.local 文件..."
sudo cp "$SRCPATH/image/$platform_id/rc.local" "$ROOTFS/etc/"
@ -108,7 +110,7 @@ install_base_packages() {
iptables network-manager curl kmod libmicrohttpd12 libjansson4 libssl3 \\
libsofia-sip-ua0 libglib2.0-0 libopus0 libogg0 libcurl4 libconfig9 \\
python3-pip net-tools libavcodec59 libavformat59 libavutil57 libswscale6 \\
libavfilter8 libavdevice59 v4l-utils libv4l-0 nano unzip && \\
libavfilter8 libavdevice59 v4l-utils libv4l-0 nano unzip dnsmasq python3-systemd && \\
apt clean && \\
rm -rf /var/lib/apt/lists/*
"
@ -119,9 +121,9 @@ configure_network() {
if [ "$network_type" = "systemd-networkd" ]; then
echo "信息:在 chroot 环境中配置 systemd-networkd..."
# 检查是否为onecloud平台如果是则使用随机MAC地址生成机制
if [ "$TARGET_DEVICE_NAME" = "onecloud" ]; then
echo "信息为onecloud平台配置随机MAC地址生成机制..."
# onecloud 与 onecloud-pro 均启用基于 SN 的 MAC 地址生成
if [ "$TARGET_DEVICE_NAME" = "onecloud" ] || [ "$TARGET_DEVICE_NAME" = "onecloud-pro" ]; then
echo "信息:为 ${TARGET_DEVICE_NAME} 平台配置基于 SN 的 MAC 地址生成机制..."
# 复制MAC地址生成脚本
sudo cp "$SCRIPT_DIR/scripts/generate-random-mac.sh" "$ROOTFS/usr/local/bin/"
@ -138,7 +140,7 @@ configure_network() {
systemctl enable systemd-networkd systemd-resolved && \\
systemctl enable kvmd-generate-mac.service
"
echo "信息onecloud随机MAC地址生成机制配置完成"
echo "信息:${TARGET_DEVICE_NAME} 基于 SN 的 MAC 地址生成机制配置完成"
fi
else
echo "信息:使用默认的网络管理器 (NetworkManager)..."
@ -179,6 +181,7 @@ configure_system() {
cat /One-KVM/configs/os/sudoers/v2-hdmiusb >> /etc/sudoers && \\
cat /One-KVM/configs/os/udev/v2-hdmiusb-rpi4.rules > /etc/udev/rules.d/99-kvmd.rules && \\
echo 'libcomposite' >> /etc/modules && \\
echo 'net.ipv4.ip_forward = 1' > /etc/sysctl.d/99-kvmd-extra.conf && \\
mv /usr/local/bin/kvmd* /usr/bin/ || echo '信息:/usr/local/bin/kvmd* 未找到或移动失败,可能已在/usr/bin' && \\
cp -r /One-KVM/configs/os/services/* /etc/systemd/system/ && \\
cp /One-KVM/configs/os/tmpfiles.conf /usr/lib/tmpfiles.d/ && \\
@ -191,8 +194,10 @@ configure_system() {
sed -i 's/8080/80/g' /etc/kvmd/override.yaml && \\
sed -i 's/4430/443/g' /etc/kvmd/override.yaml && \\
chown kvmd -R /var/lib/kvmd/msd/ && \\
systemctl enable kvmd kvmd-otg kvmd-nginx kvmd-vnc kvmd-ipmi kvmd-webterm kvmd-janus kvmd-media && \\
systemctl disable nginx && \\
rm /etc/resolv.conf && \\
printf '%s\\n' 'nameserver 1.1.1.1' 'nameserver 1.0.0.1' > /etc/resolv.conf && \
systemctl enable dnsmasq kvmd kvmd-otg kvmd-nginx kvmd-vnc kvmd-ipmi kvmd-webterm kvmd-janus kvmd-media kvmd-gostc && \\
systemctl disable nginx systemd-resolved && \\
rm -rf /One-KVM
"
}
@ -218,6 +223,54 @@ install_webterm() {
"
}
install_gostc() {
local arch="$1" # armhf, aarch64, x86_64
local gostc_arch="$arch"
local gostc_version="v2.0.8-beta.2"
# 根据架构映射下载文件名
case "$arch" in
armhf) gostc_arch="arm_7" ;;
aarch64) gostc_arch="arm64_v8.0" ;;
x86_64|amd64) gostc_arch="amd64_v1" ;;
*) echo "错误:不支持的架构 $arch"; exit 1 ;;
esac
echo "信息:在 chroot 环境中下载并安装 gostc ($gostc_arch)..."
run_in_chroot "
mkdir -p /tmp/gostc && cd /tmp/gostc && \\
curl -L https://github.com/mofeng-git/gostc-open/releases/download/${gostc_version}/gostc_linux_${gostc_arch}.tar.gz -o gostc.tar.gz && \\
tar -xzf gostc.tar.gz && \\
mv gostc /usr/bin/ && \\
chmod +x /usr/bin/gostc && \\
cd / && rm -rf /tmp/gostc
"
echo "信息:创建 gostc systemd 服务文件..."
run_in_chroot "
cat > /etc/systemd/system/kvmd-gostc.service << 'EOF'
[Unit]
Description=基于FRP开发的内网穿透 客户端/节点
ConditionFileIsExecutable=/usr/bin/gostc
After=network.target
[Service]
StartLimitInterval=5
StartLimitBurst=10
ExecStart=/usr/bin/gostc \"-web-addr\" \"0.0.0.0:18080\"
WorkingDirectory=/usr/bin
Restart=always
RestartSec=10
EnvironmentFile=-/etc/sysconfig/gostc
[Install]
WantedBy=multi-user.target
EOF
"
echo "信息gostc 安装和配置完成"
}
apply_kvmd_tweaks() {
local arch="$1" # armhf, aarch64, x86_64
local device_type="$2" # "gpio" or "video1" or other
@ -280,6 +333,8 @@ apply_kvmd_tweaks() {
fi
fi
echo "信息KVMD 配置调整完成。"
run_in_chroot "apt remove -y --purge systemd-resolved"
}
# --- 整体安装流程 ---
@ -302,9 +357,11 @@ install_and_configure_kvmd() {
config_base_files "$TARGET_DEVICE_NAME" # 使用全局变量传递设备名
# 特定设备的额外文件配置 (如果存在)
if declare -f "config_${TARGET_DEVICE_NAME}_files" > /dev/null; then
echo "信息:执行特定设备的文件配置函数 config_${TARGET_DEVICE_NAME}_files ..."
"config_${TARGET_DEVICE_NAME}_files"
# 将设备名中的连字符转换为下划线以匹配函数名
local device_func_name="${TARGET_DEVICE_NAME//-/_}"
if declare -f "config_${device_func_name}_files" > /dev/null; then
echo "信息:执行特定设备的文件配置函数 config_${device_func_name}_files ..."
"config_${device_func_name}_files"
fi
# 某些镜像可能需要准备DNS和换源
@ -319,6 +376,7 @@ install_and_configure_kvmd() {
configure_network "$network_type"
install_python_deps
configure_kvmd_core
install_gostc "$arch" # 安装 gostc
configure_system
install_webterm "$arch" # 传递原始架构名给ttyd下载
apply_kvmd_tweaks "$arch" "$device_type"

3
build/platform/oec-turbo Normal file
View File

@ -0,0 +1,3 @@
PIKVM_MODEL=v2_model
PIKVM_VIDEO=usb_video
PIKVM_BOARD=oec-turbo

View File

@ -0,0 +1,3 @@
PIKVM_MODEL=v2_model
PIKVM_VIDEO=usb_video
PIKVM_BOARD=orangepi-zero

View File

@ -1,12 +1,45 @@
#!/bin/bash
# 为onecloud平台生成随机MAC地址的一次性脚本
# 此脚本在首次开机时执行,为eth0网卡生成并应用随机MAC地址
# 为玩客云/玩客云Pro 平台生成 MAC 地址的一次性脚本
# 此脚本在首次开机时执行,为 eth0 网卡生成并应用基于 SN 的 MAC 地址,失败时回退到随机 MAC
set -e
NETWORK_CONFIG="/etc/systemd/network/99-eth0.network"
LOCK_FILE="/var/lib/kvmd/.mac-generated"
PLATFORM_FILE="/usr/share/kvmd/platform"
EFUSE_SYSFS_PATH=""
SN_PREFIX=""
SN_EXPECTED_LENGTH=13
# 按平台设置 EFUSE 与 SN 参数;未知平台时按 efuse 路径探测
detect_platform_params() {
local platform=""
if [ -f "$PLATFORM_FILE" ]; then
platform=$(tr -d '\n' < "$PLATFORM_FILE")
fi
case "$platform" in
onecloud)
EFUSE_SYSFS_PATH="/sys/bus/nvmem/devices/meson8b-efuse0/nvmem"
SN_PREFIX="OCP"
;;
onecloud-pro)
EFUSE_SYSFS_PATH="/sys/devices/platform/efuse/efuse0/nvmem"
SN_PREFIX="ODC"
;;
esac
if [ -z "$EFUSE_SYSFS_PATH" ] || [ -z "$SN_PREFIX" ]; then
if [ -e "/sys/devices/platform/efuse/efuse0/nvmem" ]; then
EFUSE_SYSFS_PATH="/sys/devices/platform/efuse/efuse0/nvmem"
SN_PREFIX="ODC"
elif [ -e "/sys/bus/nvmem/devices/meson8b-efuse0/nvmem" ]; then
EFUSE_SYSFS_PATH="/sys/bus/nvmem/devices/meson8b-efuse0/nvmem"
SN_PREFIX="OCP"
fi
fi
}
# 检查是否已经执行过
if [ -f "$LOCK_FILE" ]; then
@ -14,10 +47,29 @@ if [ -f "$LOCK_FILE" ]; then
exit 0
fi
# 生成随机MAC地址 (使用本地管理的MAC地址前缀)
# 生成MAC地址函数
generate_random_mac() {
# 使用本地管理的MAC地址前缀 (第二位设为2、6、A、E中的一个)
# 这样可以避免与真实硬件MAC地址冲突
detect_platform_params
# 尝试根据 SN 生成唯一 MAC 地址
if [ -f "$EFUSE_SYSFS_PATH" ]; then
sn_offset=$(grep --binary-files=text -boP "$SN_PREFIX" "$EFUSE_SYSFS_PATH" | head -n1 | cut -d: -f1)
if [ -n "$sn_offset" ]; then
sn=$(cat "$EFUSE_SYSFS_PATH" | dd bs=1 skip="$sn_offset" count="$SN_EXPECTED_LENGTH" 2>/dev/null)
if [ ${#sn} -eq $SN_EXPECTED_LENGTH ]; then
echo "S/N: $sn" >&2 # 输出到 stderr避免干扰返回值
# 使用 SN 的 SHA-256 哈希生成后 5 字节(避免多余管道)
sn_hash=$(printf %s "$sn" | sha256sum | cut -d' ' -f1)
# 直接用 Bash 子串获取哈希末 10 个字符并插入分隔符
mac_hex=${sn_hash: -10}
mac_suffix=$(printf "%s:%s:%s:%s:%s" "${mac_hex:0:2}" "${mac_hex:2:2}" "${mac_hex:4:2}" "${mac_hex:6:2}" "${mac_hex:8:2}")
printf "02:%s\n" "$mac_suffix"
return 0
fi
fi
fi
# 若 SN 获取失败,回退到随机逻辑
echo "警告: 无法获取 SN回退到随机 MAC 生成" >&2
printf "02:%02x:%02x:%02x:%02x:%02x\n" \
$((RANDOM % 256)) \
$((RANDOM % 256)) \
@ -26,12 +78,18 @@ generate_random_mac() {
$((RANDOM % 256))
}
echo "正在为onecloud生成随机MAC地址..."
echo "正在生成基于 SN 的 MAC 地址..."
# 生成新的MAC地址
NEW_MAC=$(generate_random_mac)
echo "生成的MAC地址: $NEW_MAC"
# 验证 MAC 地址格式
if ! [[ $NEW_MAC =~ ^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$ ]]; then
echo "错误: 生成的 MAC 地址格式无效: $NEW_MAC"
exit 1
fi
# 备份原配置文件
if [ -f "$NETWORK_CONFIG" ]; then
cp "$NETWORK_CONFIG" "${NETWORK_CONFIG}.backup"
@ -58,7 +116,7 @@ echo "MAC地址生成时间: $(date)" > "$LOCK_FILE"
# 禁用此服务,确保只运行一次
systemctl disable kvmd-generate-mac.service
echo "随机MAC地址生成完成: $NEW_MAC"
echo "MAC地址生成完成: $NEW_MAC"
echo "服务已自动禁用,下次开机不会再执行"
exit 0
exit 0

View File

@ -2,6 +2,6 @@ video: {
sink = "kvmd::ustreamer::h264"
}
acap: {
device = "hw:0"
device = "hw:0,0"
tc358743 = "/dev/video0"
}

View File

@ -32,4 +32,4 @@ case $ATX in
*)
echo "No thing."
exit -1
esac
esac

View File

@ -53,6 +53,17 @@ stdout_logfile=/dev/stdout
stdout_logfile_maxbytes = 0
redirect_stderr=true
[program:kvmd-gostc]
command=/usr/bin/gostc -web-addr 0.0.0.0:18080
autostart=true
autorestart=true
startsecs=5
priority=300
stopasgroup=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes = 0
redirect_stderr=true
[program:clean_when_exit]
command=/etc/kvmd/clean_when_exit.sh
autostart=true

View File

@ -6,4 +6,4 @@
#
# NEVER use the same passwords for KVMD, IPMI and VNCAuth users.
admin
admin -> admin:admin

View File

@ -1,6 +1,6 @@
[Unit]
Description=One-KVM - The main daemon
After=network.target network-online.target nss-lookup.target
After=network.target network-online.target nss-lookup.target rc-local.service
[Service]
User=kvmd

View File

@ -4,3 +4,4 @@ KERNEL=="video[0-9]*", SUBSYSTEM=="video4linux", PROGRAM="/usr/bin/kvmd-udev-hdm
KERNEL=="hidg0", GROUP="kvmd", SYMLINK+="kvmd-hid-keyboard"
KERNEL=="hidg1", GROUP="kvmd", SYMLINK+="kvmd-hid-mouse"
KERNEL=="hidg2", GROUP="kvmd", SYMLINK+="kvmd-hid-mouse-alt"
KERNEL=="ttyUSB0", GROUP="kvmd", SYMLINK+="kvmd-hid"

View File

@ -0,0 +1,6 @@
name: GOSTC
description: GOSTC Server
icon: share/svg/gostc.svg
path: extras/gostc
daemon: kvmd-gostc
place: 11

View File

@ -0,0 +1,7 @@
location /extras/gostc {
proxy_pass http://127.0.0.1:18080;
include /etc/kvmd/nginx/loc-proxy.conf;
include /etc/kvmd/nginx/loc-websocket.conf;
include /etc/kvmd/nginx/loc-login.conf;
include /etc/kvmd/nginx/loc-nocache.conf;
}

View File

@ -657,7 +657,7 @@
</div>
</td>
<td>&nbsp;</td>
<td>Writable:
<td i18n="msd-rw-switch">Writable:
</td>
<td align="right">
<div class="switch-box">

View File

@ -103,10 +103,10 @@ function __showKvmdInfo(info) {
if (info.meta !== null && info.meta.server && info.meta.server.host) {
$("kvmd-meta-server-host").innerText = info.meta.server.host;
document.title = `${info.meta.server.host} | PiKVM Index`;
document.title = `${info.meta.server.host} | One-KVM Index`;
} else {
$("kvmd-meta-server-host").innerHTML = "<i>Invalid meta</i>";
document.title = "PiKVM Index";
document.title = "One-KVM Index";
}
}

View File

@ -118,7 +118,7 @@ export function Keyboard(__recordWsEvent) {
}
} else {
if (is_captured) {
title = "Keyboard captured, PiKVM offline";
title = "Keyboard captured, One-KVM offline";
}
}
$("hid-keyboard-led").className = led;

View File

@ -169,7 +169,7 @@ export function Mouse(__getGeometry, __recordWsEvent) {
}
} else {
if (is_captured) {
title = "Mouse captured, PiKVM offline";
title = "Mouse captured, One-KVM offline";
}
}
$("hid-mouse-led").className = led;

View File

@ -46,7 +46,7 @@ export function Streamer() {
var __init__ = function() {
__streamer = new MjpegStreamer(__setActive, __setInactive, __setInfo, __organizeHook);
$("stream-led").title = "No stream from PiKVM";
$("stream-led").title = "No stream from One-KVM";
tools.slider.setParams($("stream-quality-slider"), 5, 100, 5, 80, function(value) {
$("stream-quality-value").innerText = `${value}%`;
@ -289,7 +289,7 @@ export function Streamer() {
var __setInactive = function() {
$("stream-led").className = "led-gray";
$("stream-led").title = "No stream from PiKVM";
$("stream-led").title = "No stream from One-KVM";
};
var __setControlsEnabled = function(enabled) {
@ -317,7 +317,7 @@ export function Streamer() {
if (text.length > 0) {
title += text;
} else {
title += "No stream from PiKVM";
title += "No stream from One-KVM";
}
}
el_grab.innerText = el_info.innerText = title;

View File

@ -166,7 +166,7 @@ export function MediaStreamer(__setActive, __setInactive, __setInfo, __organizeH
var __setupCodec = function(formats) {
__closeDecoder();
if (formats.h264 === undefined) {
let msg = "No H.264 stream available on PiKVM";
let msg = "No H.264 stream available on One-KVM";
__setInfo(false, false, msg);
__logInfo(msg);
return;

1
web/share/svg/gostc.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 30 KiB