This commit is contained in:
teasiu
2026-04-19 07:27:55 +08:00
parent 734c00f494
commit fe17ca686d
10 changed files with 1572 additions and 1624 deletions

54
build-docker.sh Normal file
View File

@@ -0,0 +1,54 @@
#!/bin/bash
# build-docker.sh - 用 Docker 为三种架构分别打包
# 前提:本机安装了 Docker + QEMU用于跨架构
# 安装 QEMUdocker run --privileged --rm tonistiigi/binfmt --install all
set -euo pipefail
PLATFORMS=("linux/amd64" "linux/arm64" "linux/arm/v7")
ARCH_NAMES=("x86_64" "arm64" "armhf")
echo "开始多架构打包..."
for i in "${!PLATFORMS[@]}"; do
PLATFORM="${PLATFORMS[$i]}"
ARCH_NAME="${ARCH_NAMES[$i]}"
OUTPUT="releases/nas-media-player-${ARCH_NAME}"
echo ""
echo "========================================="
echo " 打包架构: ${PLATFORM}${ARCH_NAME}"
echo "========================================="
docker run --rm \
--platform "${PLATFORM}" \
-v "$(pwd):/workspace" \
-w /workspace \
python:3.11-slim \
bash -c "
set -e
echo '--- 安装系统依赖 ---'
apt-get update -qq && apt-get install -y -q binutils
echo '--- 安装 Python 依赖 ---'
pip install --upgrade pip -q
pip install pyinstaller fastapi 'uvicorn[standard]' aiofiles \
pydantic python-multipart httptools -q
echo '--- 执行打包 ---'
pyinstaller nas-media-player.spec --clean --noconfirm
echo '--- 复制产物 ---'
mkdir -p releases
cp dist/nas-media-player releases/nas-media-player-${ARCH_NAME}
chmod +x releases/nas-media-player-${ARCH_NAME}
echo '产物大小:' \$(du -sh releases/nas-media-player-${ARCH_NAME})
"
echo "${ARCH_NAME} 打包完成 → ${OUTPUT}"
done
echo ""
echo "========================================="
echo "🎉 所有架构打包完成!"
ls -lh releases/
echo "========================================="

69
build.sh Normal file
View File

@@ -0,0 +1,69 @@
#!/bin/bash
# build.sh - 一键打包脚本
# 在对应架构的机器上执行(或用 Docker 交叉编译,见下方说明)
set -euo pipefail
ARCH=$(uname -m)
OUTPUT_NAME="nas-media-player-${ARCH}"
RELEASES_DIR="./releases"
echo "========================================"
echo " NAS Media Player 打包脚本"
echo " 当前架构: ${ARCH}"
echo "========================================"
# 1. 检查 Python 版本(建议 3.9+
python3 --version
# 2. 创建并激活虚拟环境(隔离,避免污染系统)
echo "[1/5] 创建虚拟环境..."
python3 -m venv .venv-build
source .venv-build/bin/activate
# 3. 安装依赖
echo "[2/5] 安装依赖..."
pip install --upgrade pip -q
pip install \
pyinstaller \
fastapi \
uvicorn[standard] \
aiofiles \
pydantic \
python-multipart \
httptools \
-q
# 4. 执行打包
echo "[3/5] 开始打包 (PyInstaller)..."
pyinstaller nas-media-player.spec \
--clean \
--noconfirm
# 5. 检查产物
BINARY="./dist/nas-media-player"
if [ ! -f "${BINARY}" ]; then
echo "❌ 打包失败!未找到 ${BINARY}"
exit 1
fi
# 6. 重命名并归档
mkdir -p "${RELEASES_DIR}"
cp "${BINARY}" "${RELEASES_DIR}/${OUTPUT_NAME}"
chmod +x "${RELEASES_DIR}/${OUTPUT_NAME}"
# 显示文件大小
SIZE=$(du -sh "${RELEASES_DIR}/${OUTPUT_NAME}" | cut -f1)
echo ""
echo "========================================"
echo "✅ 打包成功!"
echo " 产物路径: ${RELEASES_DIR}/${OUTPUT_NAME}"
echo " 文件大小: ${SIZE}"
echo "========================================"
# 7. 快速验证(不启动服务,只检查 --help
echo "[5/5] 验证二进制可执行..."
"${RELEASES_DIR}/${OUTPUT_NAME}" --help 2>/dev/null || true
echo "验证完成(如无错误输出则正常)"
# 清理虚拟环境
deactivate

78
build.yml Normal file
View File

@@ -0,0 +1,78 @@
# .github/workflows/build.yml
# 推送 tag如 v1.0.0)时自动为三种架构打包并发布 Release
name: Build Multi-Arch Binaries
on:
push:
tags:
- 'v*'
workflow_dispatch: # 支持手动触发
jobs:
build:
name: Build ${{ matrix.arch }}
runs-on: ubuntu-latest
strategy:
matrix:
include:
- arch: x86_64
platform: linux/amd64
python-arch: x64
- arch: arm64
platform: linux/arm64
python-arch: arm64
- arch: armhf
platform: linux/arm/v7
python-arch: arm
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Build binary in Docker
run: |
docker run --rm \
--platform ${{ matrix.platform }} \
-v "${{ github.workspace }}:/workspace" \
-w /workspace \
python:3.11-slim \
bash -c "
set -e
apt-get update -qq && apt-get install -y -q binutils
pip install --upgrade pip -q
pip install pyinstaller fastapi 'uvicorn[standard]' aiofiles \
pydantic python-multipart httptools -q
pyinstaller nas-media-player.spec --clean --noconfirm
mkdir -p releases
cp dist/nas-media-player releases/nas-media-player-${{ matrix.arch }}
chmod +x releases/nas-media-player-${{ matrix.arch }}
"
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: nas-media-player-${{ matrix.arch }}
path: releases/nas-media-player-${{ matrix.arch }}
release:
name: Create Release
needs: build
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: releases/
merge-multiple: true
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
files: releases/*
generate_release_notes: true

2077
index.html

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

140
nas-media-player.spec Normal file
View File

@@ -0,0 +1,140 @@
# nas-media-player.spec
# 使用方法pyinstaller nas-media-player.spec
import sys
from pathlib import Path
block_cipher = None
a = Analysis(
['nas-media-player.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[
# uvicorn 核心
'uvicorn',
'uvicorn.main',
'uvicorn.config',
'uvicorn.server',
'uvicorn.loops',
'uvicorn.loops.auto',
'uvicorn.loops.asyncio',
'uvicorn.protocols',
'uvicorn.protocols.http',
'uvicorn.protocols.http.auto',
'uvicorn.protocols.http.h11_impl',
'uvicorn.protocols.http.httptools_impl',
'uvicorn.protocols.websockets',
'uvicorn.protocols.websockets.auto',
'uvicorn.protocols.websockets.websockets_impl',
'uvicorn.protocols.websockets.wsproto_impl',
'uvicorn.lifespan',
'uvicorn.lifespan.off',
'uvicorn.lifespan.on',
'uvicorn.logging',
'uvicorn.middleware',
'uvicorn.middleware.asgi2',
'uvicorn.middleware.message_logger',
'uvicorn.middleware.proxy_headers',
# fastapi / starlette
'fastapi',
'fastapi.routing',
'fastapi.middleware',
'fastapi.middleware.cors',
'fastapi.staticfiles',
'fastapi.responses',
'starlette',
'starlette.routing',
'starlette.middleware',
'starlette.middleware.cors',
'starlette.staticfiles',
'starlette.responses',
'starlette.background',
'starlette.concurrency',
'starlette.datastructures',
'starlette.exceptions',
'starlette.formparsers',
'starlette.requests',
'starlette.types',
'starlette.websockets',
# HTTP 解析库uvicorn 可选依赖,打包时都带上)
'h11',
'httptools',
'anyio',
'anyio._backends._asyncio',
'anyio._backends._trio',
'sniffio',
# aiofiles
'aiofiles',
'aiofiles.os',
'aiofiles.threadpool',
# pydanticfastapi 依赖)
'pydantic',
'pydantic.v1',
'pydantic_core',
# 标准库补充
'multipart',
'python_multipart',
'email.mime.multipart',
'email.mime.text',
# 编码/哈希
'hashlib',
'hmac',
# 其他
'click',
'typing_extensions',
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[
# 排除不需要的大型库,减小体积
'tkinter',
'matplotlib',
'numpy',
'pandas',
'PIL',
'scipy',
'IPython',
'jupyter',
'notebook',
'test',
'unittest',
],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='nas-media-player', # 输出的二进制名
debug=False,
bootloader_ignore_signals=False,
strip=True, # strip 调试符号,减小体积
upx=True, # 若系统有 upx 则进一步压缩
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)

View File

@@ -1,25 +0,0 @@
## 打包二进制制作方法
```
apt update && apt install -y python3 python3-pip python3-dev gcc g++ make libffi-dev libssl-dev patchelf
pip_select.sh
pip3 install fastapi uvicorn aiofiles python-multipart pyinstaller
```
```
pyinstaller --onefile --name=nas-media-player-armhf --distpath=dist --workpath=tmp --clean --exclude-module=tkinter --exclude-module=unittest --exclude-module=sqlite3 nas-media-player.py
pyinstaller --onefile --name=nas-media-player-arm64 --distpath=dist --workpath=tmp --clean --exclude-module=tkinter --exclude-module=unittest --exclude-module=sqlite3 nas-media-player.py
pyinstaller --onefile --name=nas-media-player-x86_64 --distpath=dist --workpath=tmp --clean --exclude-module=tkinter --exclude-module=unittest --exclude-module=sqlite3 nas-media-player.py
~/.local/bin/pyinstaller --onefile --name=nas-media-player-x86_64 --distpath=dist --workpath=tmp --clean --exclude-module=tkinter --exclude-module=unittest --exclude-module=sqlite3 nas-media-player.py
```
```
chmod +x dist/nas-media-player-x86_64
./dist/nas-media-player-x86_64
```

Binary file not shown.

Binary file not shown.

Binary file not shown.