From 0859aeeb797483f1d8ceeb026bf3fd83be36650d Mon Sep 17 00:00:00 2001 From: solitude Date: Sun, 4 Jan 2026 20:11:56 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=94=BB=E8=B4=A8?= =?UTF-8?q?=E9=80=89=E9=A1=B9=E4=B8=AD=E4=BB=85=E9=9F=B3=E9=A2=91=E5=BD=95?= =?UTF-8?q?=E5=88=B6=E9=80=89=E9=A1=B9AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/media/video_quality_model.py | 1 + locales/en.json | 3 ++- locales/zh_CN.json | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/models/media/video_quality_model.py b/app/models/media/video_quality_model.py index c7191603..ad6cc909 100644 --- a/app/models/media/video_quality_model.py +++ b/app/models/media/video_quality_model.py @@ -4,6 +4,7 @@ class VideoQuality: HD = "HD" SD = "SD" LD = "LD" + AD = "AD" # Audio-only stream @classmethod def get_qualities(cls): diff --git a/locales/en.json b/locales/en.json index c17f237c..67cf14b3 100644 --- a/locales/en.json +++ b/locales/en.json @@ -406,7 +406,8 @@ "UHD": "Ultra HD", "HD": "High Definition", "SD": "Standard Definition", - "LD": "Low Definition" + "LD": "Low Definition", + "AD": "Audio Only" }, "help_dialog": { "shortcut_key_help": "Shortcut Key Help", diff --git a/locales/zh_CN.json b/locales/zh_CN.json index 42b8ca5e..af57c609 100644 --- a/locales/zh_CN.json +++ b/locales/zh_CN.json @@ -406,7 +406,8 @@ "UHD": "超清", "HD": "高清", "SD": "标清", - "LD": "流畅" + "LD": "流畅", + "AD": "音频" }, "help_dialog": { "shortcut_key_help": "快捷键帮助", From 322662304c710ae0c0907ef1811725f88bd75448 Mon Sep 17 00:00:00 2001 From: iso_SER Date: Sun, 4 Jan 2026 22:17:35 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BB=A5=E9=9D=9Esudo?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E8=BF=90=E8=A1=8C=E5=AE=B9=E5=99=A8=E7=9A=84?= =?UTF-8?q?=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加仅音频格式录制选项的功能 --- Dockerfile | 50 ++++++++++++++---- .../components/business/recording_dialog.py | 32 +++++++++++- docker-compose.yml | 51 ++++++++++++------- streamget | 1 + 4 files changed, 107 insertions(+), 27 deletions(-) create mode 160000 streamget diff --git a/Dockerfile b/Dockerfile index 6e86f084..e85e8b1b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,25 +1,40 @@ +# --- 第一阶段: 编译/构建阶段 --- +ARG http_proxy +ARG https_proxy + FROM python:3.12-slim AS builder WORKDIR /app -# Install system dependencies for build RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* -# Install Python dependencies +# 先复制 streamget 目录和 requirements 文件 +COPY streamget/ ./streamget/ COPY requirements-web.txt . + +# 优先从本地安装 streamget +RUN pip install --no-cache-dir ./streamget + +# 然后安装其他依赖(streamget 已安装,会被跳过) RUN pip install --no-cache-dir -r requirements-web.txt +# 复制其他项目文件 COPY . . -RUN mkdir -p /app/logs /app/downloads +# 提示:在这里创建目录其实没用,因为第二阶段是干净的镜像,建议在第二阶段创建 -# Final stage: production image +# --- 第二阶段: 最终生产镜像 --- FROM python:3.12-slim +# 1. 定义构建参数,允许在 docker-compose 中传入宿主机的 UID/GID +ARG PUID=1000 +ARG PGID=1000 + WORKDIR /app +# 2. 安装运行时依赖 RUN apt-get update && apt-get install -y --no-install-recommends \ ffmpeg \ tzdata \ @@ -30,13 +45,30 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* -# Set timezone +# 3. 设置时区 ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo "$TZ" > /etc/timezone -# Copy Python dependencies and project files from the builder stage -COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages -COPY --from=builder /usr/local/bin /usr/local/bin -COPY --from=builder /app/ ./ +# 4. 创建非 root 用户 +# 创建一个名为 appuser 的用户,并赋予指定的 UID 和 GID +RUN groupadd -g ${PGID} appgroup && \ + useradd -u ${PUID} -g appgroup -s /bin/sh -m appuser + +# 5. 从 builder 阶段复制文件,并利用 --chown 直接修改所有权 +# 关键点:将 site-packages 和可执行文件的权限也交给 appuser +COPY --from=builder --chown=appuser:appgroup /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages +COPY --from=builder --chown=appuser:appgroup /usr/local/bin /usr/local/bin +COPY --from=builder --chown=appuser:appgroup /app/ ./ + +# 6. 预创建必要的持久化目录并授权 +# 确保在容器启动前,这些目录的所有者就是 appuser +RUN mkdir -p /app/logs /app/downloads /app/config && \ + chown -R appuser:appgroup /app + +# 7. 切换到非 root 用户运行 +USER appuser + +# 暴露端口(仅作为文档声明,不影响实际映射) +EXPOSE 6006 CMD ["sh", "-c", "python main.py --web --host 0.0.0.0"] \ No newline at end of file diff --git a/app/ui/components/business/recording_dialog.py b/app/ui/components/business/recording_dialog.py index 8916023f..9bd6cf4e 100644 --- a/app/ui/components/business/recording_dialog.py +++ b/app/ui/components/business/recording_dialog.py @@ -50,6 +50,30 @@ async def update_format_options(e): record_format_field.value = record_format_field.options[0].key record_format_field.update() + async def on_quality_change(e): + """当画质选择改变时,如果选择了AD(仅音频),自动切换到音频格式""" + selected_quality = e.control.value + if selected_quality == VideoQuality.AD: + # 切换到音频模式 + media_type_dropdown.value = "audio" + media_type_dropdown.disabled = True # 禁用媒体类型选择 + # 更新格式选项为音频格式 + record_format_field.options = [ft.dropdown.Option(i) for i in AudioFormat.get_formats()] + if record_format_field.value not in AudioFormat.get_formats(): + record_format_field.value = AudioFormat.M4A + else: + # 恢复媒体类型选择的可用性 + media_type_dropdown.disabled = False + # 如果当前是音频模式,切换回视频模式 + if media_type_dropdown.value == "audio": + media_type_dropdown.value = "video" + record_format_field.options = [ft.dropdown.Option(i) for i in VideoFormat.get_formats()] + if record_format_field.value not in VideoFormat.get_formats(): + record_format_field.value = VideoFormat.TS + + media_type_dropdown.update() + record_format_field.update() + url_field = ft.TextField( label=self._["input_live_link"], hint_text=self._["example"] + ":https://www.example.com/xxxxxx", @@ -77,7 +101,12 @@ async def update_format_options(e): on_change=update_format_options ) - if default_record_type == "video": + # 如果初始画质是AD,强制设置为音频模式并禁用媒体类型选择 + if default_record_quality == VideoQuality.AD: + media_type_dropdown.value = "audio" + media_type_dropdown.disabled = True + record_formats = AudioFormat.get_formats() + elif default_record_type == "video": record_formats = VideoFormat.get_formats() else: record_formats = AudioFormat.get_formats() @@ -98,6 +127,7 @@ async def update_format_options(e): filled=False, value=default_record_quality, width=245, + on_change=on_quality_change, ) flv_use_direct_download_dropdown = ft.Dropdown( diff --git a/docker-compose.yml b/docker-compose.yml index e9607889..db00514c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,15 @@ - services: streamcap: - image: ihmily/streamcap + # 1. 使用本地构建,不再直接拉取镜像 + build: + context: . + dockerfile: Dockerfile + args: + - PUID=${CURRENT_UID:-1000} + - PGID=${CURRENT_GID:-1000} + - http_proxy=http://192.168.50.66:7890 + - https_proxy=http://192.168.50.66:7890 + - no_proxy=localhost,127.0.0.1 tty: true ports: - "${PORT:-6006}:${PORT:-6006}" @@ -11,7 +19,7 @@ services: volumes: - ./logs:/app/logs - ./config:/app/config - - ./downloads:/app/downloads + - /media/iso/hdd3/steamcap/:/app/downloads - ./.env:/app/.env healthcheck: test: ["CMD", "sh", "-c", "curl -f http://localhost:${PORT:-6006}/about"] @@ -22,20 +30,29 @@ services: - streamcap-network video_api: - image: ihmily/streamcap - command: python -m app.api.video_stream_service - ports: - - "${VIDEO_API_PORT:-6007}:${VIDEO_API_PORT:-6007}" - environment: - - TZ=${TZ:-Asia/Shanghai} - - CUSTOM_VIDEO_ROOT_DIR=${CUSTOM_VIDEO_ROOT_DIR:-./downloads} - volumes: - - ./downloads:/app/downloads - - ./.env:/app/.env - depends_on: - - streamcap - networks: - - streamcap-network + # 同样使用构建模式,共享同一套构建代码,但运行不同的命令 + build: + context: . + dockerfile: Dockerfile + args: + - PUID=${CURRENT_UID:-1000} + - PGID=${CURRENT_GID:-1000} + - http_proxy=http://192.168.50.66:7890 + - https_proxy=http://192.168.50.66:7890 + - no_proxy=localhost,127.0.0.1 + command: python -m app.api.video_stream_service + ports: + - "${VIDEO_API_PORT:-6007}:${VIDEO_API_PORT:-6007}" + environment: + - TZ=${TZ:-Asia/Shanghai} + - CUSTOM_VIDEO_ROOT_DIR=${CUSTOM_VIDEO_ROOT_DIR:-./downloads} + volumes: + - /media/iso/hdd3/steamcap/:/app/downloads + - ./.env:/app/.env + depends_on: + - streamcap + networks: + - streamcap-network networks: streamcap-network: diff --git a/streamget b/streamget new file mode 160000 index 00000000..41423040 --- /dev/null +++ b/streamget @@ -0,0 +1 @@ +Subproject commit 414230402ece3cae8cdebc0d6853673b637ffc28 From 36dc6687b3f745be9e92e72e7a2190b1e92af9d9 Mon Sep 17 00:00:00 2001 From: iso_SER Date: Mon, 5 Jan 2026 00:59:15 +0800 Subject: [PATCH 3/3] fix dockerignore --- .dockerignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.dockerignore b/.dockerignore index c452a854..47af65ce 100644 --- a/.dockerignore +++ b/.dockerignore @@ -10,6 +10,7 @@ **/docs **/tests **/*.md +!streamget/README.md # Build Artifacts and Cache **/__pycache__