🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

手机投屏 liyuhan7/dsh-phone-mirror

DeepSeek 客户端
liyuhan75 天前有提交已提供中文文档扫描:含敏感能力兼容 / 相关生态

在侧边栏投屏安卓设备并用鼠标键盘直接反控

30.4/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/11/6 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/liyuhan7/dsh-phone-mirror.git

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:仅索引
是什么[目录]—
生态应用
桌面端 / Web 外壳,不以 dsh plugin add 安装
暂无时间戳·判据 →
装得上吗[实装验证]—
本站尚未做安装检查
暂无时间戳·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/06·判据 →
还在维护吗[仓库]✓
活跃:最近一次提交在 5 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 34 处,展示前 33 条)
  • 读取本地文件
    lib/index.js:36
    const WORKLET_SOURCE = readFileSync(new URL('./audio-worklet.js', import.meta.url), 'utf8')
  • 读取本地文件
    lib/index.js:40
    readFileSync(new URL('./engine.js', import.meta.url), 'utf8'),
  • 读取本地文件
    lib/index.js:41
    readFileSync(new URL('./engine-worker.js', import.meta.url), 'utf8')
  • 读取本地文件
    lib/index.js:165
    if (!configuredAdb && !existsSync(BUNDLED_ADB) && !hasAdbOnPath()) {
  • 发起网络请求
    lib/client.bundle.js:196
    fetch(`${state.controlUrl}?kind=reset`, { method: 'POST', cache: 'no-store' }).catch(() => {})
  • 发起网络请求
    lib/client.bundle.js:470
    const response = await fetch(state.streamUrl, { signal: controller.signal, cache: 'no-store' })
  • 发起网络请求
    lib/client.bundle.js:874
    const response = await fetch(`${BASE}${path}`, {
  • 发起网络请求
    lib/client.bundle.js:886
    const response = await fetch(`${BASE}/status`, { method: 'GET' })
  • 发起网络请求
    lib/client.bundle.js:924
    .then(() => fetch(`${BASE}/control?${params.toString()}`, { method: 'POST', cache: 'no-store' }))
  • 发起网络请求
    lib/client.bundle.js:1809
    await fetch(`${BASE}/disconnect`, { method: 'POST', keepalive: true })
  • 写入本地文件
    lib/adb.js:27
    mkdirSync(candidate, { recursive: true })
  • 读取本地文件
    lib/adb.js:52
    try { if (existsSync(join(dir, name))) return true } catch {}
  • 读取本地文件
    lib/adb.js:71
    if (existsSync(BUNDLED_ADB)) return BUNDLED_ADB
  • 写入本地文件
    lib/adb.js:73
    await mkdir(tools, { recursive: true })
  • 读取本地文件
    lib/adb.js:77
    if (!existsSync(zip)) {
  • 请求外部主机dl.google.com
    lib/adb.js:78
    const response = await fetch(`https://dl.google.com/android/repository/${archive}`, { redirect: 'follow', signal: AbortSignal.timeout(timeoutMs) })
  • 发起网络请求
    lib/adb.js:78
    const response = await fetch(`https://dl.google.com/android/repository/${archive}`, { redirect: 'follow', signal: AbortSignal.timeout(timeoutMs) })
  • 写入本地文件
    lib/adb.js:81
    await pipeline(Readable.fromWeb(response.body), createWriteStream(temp))
  • 写入本地文件
    lib/adb.js:82
    await rename(temp, zip)
  • 读取本地文件
    lib/adb.js:84
    const size = await stat(zip).then((info) => info.size).catch(() => 0)
  • 读取本地文件
    lib/adb.js:87
    if (!existsSync(BUNDLED_ADB)) throw new Error(`解压后未找到 ${ADB_NAME}`)
  • 读取本地文件
    lib/adb.js:95
    return existsSync(BUNDLED_ADB) ? BUNDLED_ADB : 'adb'
  • 写入本地文件
    lib/adb.js:113
    try { mkdirSync(this.tempDir, { recursive: true }) } catch {}
  • 执行外部命令来自配置/变量
    lib/adb.js:119
    execFile(this.binary, args, { timeout, windowsHide: true, encoding, maxBuffer, env: this.env }, (error, stdout, stderr) => {
  • 执行外部命令来自配置/变量
    lib/adb.js:214
    execFile(
  • 读取本地文件
    lib/session.js:132
    if (!existsSync(this.serverPath)) {
  • 执行外部命令来自配置/变量
    lib/session.js:172
    this.child = spawn(this.adb.binary, ['-s', this.serial, 'shell', command], {
  • 发起网络请求
    lib/client.js:267
    const response = await fetch(`${BASE}${path}`, {
  • 发起网络请求
    lib/client.js:279
    const response = await fetch(`${BASE}/status`, { method: 'GET' })
  • 发起网络请求
    lib/client.js:317
    .then(() => fetch(`${BASE}/control?${params.toString()}`, { method: 'POST', cache: 'no-store' }))
  • 发起网络请求
    lib/client.js:1202
    await fetch(`${BASE}/disconnect`, { method: 'POST', keepalive: true })
  • 发起网络请求
    lib/engine.js:158
    fetch(`${state.controlUrl}?kind=reset`, { method: 'POST', cache: 'no-store' }).catch(() => {})
  • 发起网络请求
    lib/engine.js:432
    const response = await fetch(state.streamUrl, { signal: controller.signal, cache: 'no-store' })
扫描于 2026/11/6(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
涉及外部主机:dl.google.com

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/schemastery
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

在 DSH 右侧栏投屏并反控安卓手机/平板。scrcpy 内核编 H.264,浏览器 WebCodecs 解码,鼠标键盘直接操作;仅支持 Windows。

README

由 DeepSeek 最新模型翻译生成
dsh-phone-mirror 用智能体干活的时候,手机就在侧边栏:刷视频、回消息、看通知都不用离开电脑,省掉反复拿起放下的步骤。 底层是 scrcpy 5.0.1 加浏览器端 WebCodecs:安卓设备的画面投到 DSH 右侧栏,鼠标键盘直接反控。 页面示例 特性 - 页签常驻右侧栏:在「+」里添加「手机」页签即可投屏,画面按 contain 比例铺满;切换页签保留会话,关闭页签断开并释放设备端进程。 - 鼠标键盘反控:点按、拖拽、滚轮按 scrcpy 控制协议回传;ASCII 字符走按键注入,中文等非 ASCII 文本经设备剪贴板粘贴,组字时面板底部显示拼音。 - 声音一起转发:Opus 48 kHz 立体声,经 AudioWorklet 环形缓冲播放,起播缓冲 80 ms、欠载时自适应到 240 ms;设备不支持时自动改为无声会话。 - 解码在 Worker 线程:拉流、H.264 解码、绘制与音频解码都在 Worker 内完成,DSH 主线程渲染对话或写文件时面板不跟着卡;拿不到 Worker 时退回主线程。 - 起不来时自动降级:scrcpy 失败后用 adb screencap 周期截图(默认 260 ms 一帧),帧率低但几乎任何能 adb 的设备都能出画面。
展开完整文档(README 剩余 1 节)
dsh-phone-mirror

用智能体干活的时候,手机就在侧边栏:刷视频、回消息、看通知都不用离开电脑,省掉反复拿起放下的步骤。

底层是 scrcpy 5.0.1 加浏览器端 WebCodecs:安卓设备的画面投到 DSH 右侧栏,鼠标键盘直接反控。

页面示例

特性

- 页签常驻右侧栏:在「+」里添加「手机」页签即可投屏,画面按 contain 比例铺满;切换页签保留会话,关闭页签断开并释放设备端进程。
- 鼠标键盘反控:点按、拖拽、滚轮按 scrcpy 控制协议回传;ASCII 字符走按键注入,中文等非 ASCII 文本经设备剪贴板粘贴,组字时面板底部显示拼音。
- 声音一起转发:Opus 48 kHz 立体声,经 AudioWorklet 环形缓冲播放,起播缓冲 80 ms、欠载时自适应到 240 ms;设备不支持时自动改为无声会话。
- 解码在 Worker 线程:拉流、H.264 解码、绘制与音频解码都在 Worker 内完成,DSH 主线程渲染对话或写文件时面板不跟着卡;拿不到 Worker 时退回主线程。
- 起不来时自动降级:scrcpy 失败后用 adb screencap 周期截图(默认 260 ms 一帧),帧率低但几乎任何能 adb 的设备都能出画面。
- 一根线到无线:面板底部「转无线」把 USB 调试切到 TCP 并自动连上,拔线后继续投屏;原生 Android 11+ 还能用「配对」走无线调试。

快速开始

环境要求

- Windows(内置 adb 路径固定为 tools/platform-tools/adb.exe)
- DSH >= 0.2.0-rc.1 < 0.3.0
- Node.js 20+(仅首次下载工具与构建时使用)
- 安卓设备已开启「开发者选项 → USB 调试」并完成授权
- 转发声音需要 Android 11+

各品牌开启 USB 调试的入口和额外开关见 docs/debugging.md。

安装

npm 包,预构建安装
dsh plugin --profile <profile> add dsh-phone-mirror
或从仓库安装
dsh plugin --profile <profile> add "github:liyuhan7/dsh-phone-mirror"

adb

首次运行会自动下载 platform-tools(约 8 MB)到插件目录;也可以手动执行:

全局安装后位于 <profile 目录>/node_modules/dsh-phone-mirror
npm run fetch:tools

系统里已有 adb 时可在配置里指定 adbPath 跳过下载。

运行

1. 重启 DSH,右侧栏点「+」添加「手机」页签
2. 顶部下拉选中设备,点「连接」
3. 设备弹出「允许 USB 调试吗?」时勾选「始终允许」
4. 想摆脱数据线:点面板底部「转无线」,提示已切到无线后拔线

预期输出:面板出现设备画面,标题行显示 BKY-W10 · 1048×1600 · 30fps(设备名 · 分辨率 · 实时帧率)。

用法

点按 / 拖拽 / 滚轮 直接操作设备键盘 点击画面接管,Esc 交还焦点全屏 工具栏「全屏」画质 流畅 720 / 标准 1080 / 高清 1600 无线连接 底部「转无线」把 USB 调试切到 TCP 并自动连上底部「配对」填无线调试页上的配对地址与 6 位配对码断开连接 只断电脑与平板之间的无线通道,USB 不受影响

画面发花或全黑时点「重建画面」:丢弃解码器并重新拉流,由设备重发关键帧。

配置

在 profile 的 cordis.patch.yml 里覆盖:

- id: dsh-phone-mirror
config:
maxSize: 1600
maxFps: 60
videoBitRate: 8000000

| 字段 | 默认 | 说明 |
| mode | auto | auto 先试 scrcpy(音频失败后改无声再试),仍失败才降级截图 |
| maxSize | 1280 | 长边像素上限,可被面板的画质档位覆盖 |
| maxFps | 60 | 编码帧率上限 |
| videoBitRate | 8000000 | 编码码率(bps) |
| screencapIntervalMs | 260 | 降级模式的截图间隔 |
| audio | true | 转发设备声音;设备不支持时下次直接无声开场 |
| adbPath | 空 | 自定义 adb 路径,留空用插件自带的 |
| serverJar | 空 | 自定义 scrcpy-server.jar 路径 |

常见问题

adb devices 为空,但手机显示已连接

Windows 把该 USB 接口绑到了厂商驱动(例如华为 HDB)。在设备管理器里手动更新为「Android ADB Interface」,或安装 Google USB Driver 后指定。

dsh plugin 拒绝操作 desktop profile

desktop profile 由 Electron 应用独占托管。直接编辑该 profile 的 package.json,在 dependencies 里加 "dsh-phone-mirror": "link:D:/path/to/dsh-phone-mirror",并把插件名加进 dsh.profile.bundles,然后执行 pnpm install。

没有声音 先看面板上的喇叭按钮:灰色说明这个会话没拿到音频,查 /dsh-phone-mirror/api/status 里的 session.audio 与 session.audioCodec。按钮可用却听不到,检查电脑音量、设备是否静音,以及正在播的 App 是否禁止被捕获。

画面发黑,或帧率只有个位数

付费视频等 DRM 内容走 MediaCodec 的安全通路,只能出黑屏;设备静止时 scrcpy 不产生帧,帧率显示个位数属正常。

许可证

MIT,见 LICENSE;第三方组件见 THIRD-PARTY.md。
预览分享卡片长什么样 ↓liyuhan7/dsh-phone-mirror
分享 · DeepSeek Harness Hub
liyuhan7/dsh-phone-mirror

在侧边栏投屏安卓设备并用鼠标键盘直接反控

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部