扫一下就能传 · 手机不用装 App · 文件走家里 Wi-Fi,不出家门

功能详解

每一项能力,写清它是怎么做到的

这一页不讲「我们打算做什么」,只讲现在是怎么做的。 数字都能在源码里查到,机制都能自己验证。 如果某件事还在路上或真机待验证,这里会标明。

本地算,不请求外部

二维码、文件指纹、归档路径,全部在你自己的机器上算出来,不联网。

写磁盘,不写数据库

文件按你指定的目录落盘;设置和去重账本是本地 JSON 文件,可以自己打开看。

出问题会给下一步

错误信息都是人话加「你该怎么办」;不是干巴巴一句「失败」,也不会假装成功。

入口

那个二维码是本地画的

没有第三方二维码服务,也没有「生成二维码」的网络请求。

内容是什么

二维码里是电脑在局域网上的地址,加一点配对用的凭据。 手机扫出来后,浏览器直接访问你电脑上的那个地址 —— 请求没出过你家路由器。

电脑上同时显示网络名和6 位密码, 以及可以切换的地址列表(电脑有多块网卡时,见下文)。

什么时候会变

每次启动应用,配对令牌都会重新生成。 所以上一次扫出来的二维码,重启之后就失效了 —— 这是刻意的:令牌只在本次运行里有用。

如果你开了密码(默认开着),二维码里不带令牌, 扫码之后还是要输那 6 位数字。 这样「设置里写着要密码」和「扫码要输密码」是同一件事。

为什么强调「本地」

很多工具的二维码是发给某个服务生成的。那样做方便,代价是你电脑的局域网地址 被第三方知道了。兔本本快传的二维码在应用里直接渲染, 没有这一步。

手机上

扫完之后,你能选什么

手机打开的是一个网页。它有三个常驻入口, 在支持的浏览器上会多出第四个 —— 这个区别是有意的,下面会讲为什么。

🖼 照片

只列图片。iOS / Android 的系统选择器直接打开相册, 可以多选。适合「把今天拍的发过去」。

🎬 视频

只列视频。同样是系统选择器,可以一次选多个短视频。 大体积的走下面会讲的分块传输。

+ 任意文件

什么都能选:PDF、文档、压缩包、安装包…… 可以一次选多个。这是最早支持的入口,能力最全。

📁 相册文件夹

在支持选整个文件夹的浏览器上才会出现。 iOS Safari 大概率没有这一项 —— 页面会自动检测, 不支持就整块藏起来,不会给你一个点了没反应的按钮。

为什么不是「四个入口」

因为第四个是浏览器能力决定的,不是我们决定的。 所以准确说法是:三个常驻入口,支持选文件夹的浏览器上还会多一个 —— 在你的手机上如果只看到三个,那正是它该有的样子。

同理,accept 只是给系统选择器的提示: 平台可以忽略,也可以给出没要的类型 (iOS 的 Live Photo 会成对给出图片和视频)。 它不是正确性判据,所以漏斗里还有第二道筛子。

落盘

存到哪、叫什么名

这是备份工具最容易出事的地方,所以规则写得很死。

目标文件夹:你在电脑上配

电脑设置里可以把好几个文件夹设成手机可选的落点。 手机上看到的是你给每个文件夹写的备注 (比如「客户合同」「孩子相册」),点选之后才开始传。

手机上也会显示真实路径作为副标 —— 因为两个文件夹可以重名(比如都叫「相册」), 只有真实路径能消歧。这条信息只下发给已认证的会话, 手机上只显示、不回传。

整批备注:目录名的一部分

选完文件可以填一条整批共用的备注, 落盘目录名形如:

<目标文件夹>/2026-10-15-客户合同/

日期是接收当天,备注是你填的那句话。 不填备注就只用日期;备注有非法字符会被清洗掉, 但不会因此拒绝接收。

重名文件:绝不覆盖

  • 规则:同目录下已经有的名字,新来的自动改名。 已有 IMG_0001.jpg ⇒ 新来的变成 IMG_0001 (1).jpg,再传一个就是 IMG_0001 (2).jpg,依次类推。
  • 一个字节都不会被冲掉。 原文件保持原样。这比「问你要不要覆盖」更安全 —— 传输中途你不在电脑前,弹窗等于把事情卡住。
  • 落盘是两阶段的。 先写到同卷的暂存区(名字带 .samesend-tmp 前缀), 校验完成再原子改名发布到最终位置。 中途断电 / 断连不会留下半个文件冒充完整文件。
暂存区 .samesend-tmp/ IMG_0001.jpg.part VID_0042.mp4.part 校验 原子改名 你指定的文件夹 2026-10-15-客户合同/ IMG_0001.jpg IMG_0001 (1).jpg VID_0042.mp4 IMG_0001 (2).jpg
示意图:由 SVG 绘制,非实拍界面。虚线框表示「已有同名文件时自动改名」, 不是覆盖、不是跳过。

手机页

选完文件之后,你在手机上看到什么

这是一个刻意做得很朴素的页面: 不引入任何前端框架、不加载任何外部资源, 在弱网下也能立刻打开。

示意图:由 CSS 绘制,非实拍界面。 ① 目标文件夹两行显示(备注 + 真实路径) ② 整批备注 ③ 四个入口(虚线那个在不支持的浏览器上根本不出现) ④ 时间范围 ⑤ 总结行:共选 / 待传 / 电脑上已有 / 不在所选范围 ⑥ 进度条与状态徽标 —— 「电脑上已有,跳过」与「已送达」视觉可分(虚线 vs 实线), 不把跳过伪装成保存成功。

选完之后

三段漏斗:先把该扔的扔掉,再开始传

选了一千张照片时,直接上传是浪费。 手机页在真正发出去之前会先做三道筛选,每一道都是可以绕过的。

1

大小

按你设的大小上限筛。0 字节的占位文件、明显异常的条目先去掉。

几乎不花时间
2

日期

按文件时间(lastModified,不是拍摄时间) 和你选的范围(今天 / 7 天 / 30 天 / 全部 / 指定某一天)筛。 被筛掉的进「未包含」栏,写明它自己是哪一天,点一下就能捞回来。

几乎不花时间
3

哈希

对大文件算内容指纹,用来问电脑「这个你是不是已经有了」。 只在电脑上开了内容去重时才跑;判据是文件内容,不是文件名。

大文件会花时间

日期筛选的依据是「文件时间」,不是「拍摄时间」

手机浏览器读不到 EXIF,所以这里比的是文件的 lastModified。 而截图、聊天软件保存的图根本没有拍摄时间。

电脑端归档时用的是真的拍摄时间(EXIF / 容器元数据), 所以两边依据不同 —— 「选了某天却一张都没有」是可能的。 页面对此写得很明白,被排除的每一行都会写出它自己是哪一天。

哈希算法按文件大小决定,两条都是线上契约

  • ≤ 64 MiB:完整 sha256
  • > 64 MiB:sha256-sampled-v1 = 头 4 MiB ‖ 尾 4 MiB ‖ uint64LE(长度)

采样是为了让几个 GB 的视频在手机上也算得动。 代价是它不是密码学意义上的全文哈希 —— 我们如实写出来,不把它叫成「精确去重」。

大视频怎么传

分块传输:一次发不动的,拆开发

这是「短视频同步到电脑」这条主线的支撑技术。 小文件走一次性上传,大文件走分块 —— 两条路都是活的。

什么时候分块

文件大于 16 MiB 就走分块路线; 小于这个数的一次性发完,不值得切。

单块大小按文件大小算: clamp(ceil(大小 / 64), 8 MiB, 32 MiB)。 一个 20 MiB 的文件切 3 块(下限 8 MiB); 一个 2 GiB 的视频切 64 块(被 32 MiB 上限夹住)。

怎么续传

每个文件有一个会话,会话 id 就是它的内容指纹。 电脑端把收到的字节按顺序追加到暂存文件里 —— 暂存文件的当前大小就是已确认的偏移。

重连之后手机问一句「你收到哪了」,从那个字节继续发。 发重了会返回 409 并带上真实偏移, 手机据此跳回去,不会把数据写乱。

断点能跨什么、不能跨什么

  • 能跨:网络闪断、切出去接个电话再回来。 只要电脑端应用还开着、暂存文件还在,重连后从已收字节继续。 这一层是已经实现并在进程外跑过验证的。
  • 不能跨:电脑端应用重启。 暂存目录 .samesend-tmp/ 在下次启动会被清掉。 也就是说「昨天传到一半,今天开机接着传」不行。
  • 手机真机上能不能救回息屏中断 —— 未验证。 机制在,但 iOS 息屏会挂起页面、可能让连接半开。 电脑端有一个 60 秒的停滞看门狗兜底, 但真机表现我们没有实测过。这一条是「未验证」,不是「已支持」。

两阶段落盘

块先进暂存文件,全部到齐、校验通过才原子改名发布到最终位置。 中途失败只会留下暂存文件,不会出现半个成品冒充完整文件。

严格顺序

块必须按顺序追加。乱序的请求会被拒,回带真实偏移。 这让「收到了多少」这个问题有唯一答案。

按 4 GiB 级别设计

单文件大小、暂存空间(上限 16 GiB)、并发会话数(上限 32) 都有明确上限。超过时会如实报错,不会假装继续。

传之前先看一眼

点图放大、点视频就地播放

选完之后不用传完才知道选错了 —— 缩略图可以直接点。

图片

能点的缩略图点开就放大图。 体积太大的图不给缩略图(上限 32 MiB), 但「没有缩略图」和「不可点」是两个判据 —— 不给缩略图的条目仍然可以点开看原图。

HEIC 这类浏览器解不开的格式,退成图标,不留下破图。

视频

任意大小的视频都可以点开播放。 播放器是就地展开的,关掉就停。

⚠️ 能不能播取决于手机浏览器支持的编码。 桌面 Chrome 能播不代表 iOS Safari 能播,反之亦然。 这一条我们在真机上没验证过。

缩略图不会把手机搞崩

缩略图按可见性创建与回收:滚出视口就释放 (revokeObjectURL)。 几千张图同时开着位图是能真把手机搞崩的,所以这里做了显式的生命周期管理。

网络与权限

电脑上有几块网卡,要挑对

这是连不上时最常见的原因,界面里因此把地址选择器常驻,不藏进设置。

多网卡

台式机可能同时插着网线和连着 Wi-Fi,笔记本可能还有 VPN / 虚拟网卡。 兔本本快传会把所有局域网地址列出来,让你挑一个。

挑错了手机就连不上 —— 不是应用坏了,是地址对不上。 界面上二维码旁边始终显示当前地址和网络名,方便核对。

第一次要过系统的关

Windows:第一次运行防火墙会问要不要允许, 要勾「专用网络」。 便携版(portable)不写防火墙规则,每次可能都要问一次。

macOS:可能会弹「允许查找本地网络设备」, 点了取消的话手机就永远连不上,而且应用不会报错 —— 二维码照常显示。这是系统的做法,我们在 「第一次怎么用」那一页讲了怎么排查。

相册备份

落到电脑上之后,是怎么分类的

分类规则由你在电脑上配,手机端不用管。

第一层:时间或类型

可以按拍摄时间(按天 / 按年月)分, 也可以按文件类型(照片 / 视频)分, 或者两个维度组合。

第二层:再分一层

第一层选了时间,第二层还可以按类型;反过来也行。 两个维度都保留,只是换顺序。

取不到时间怎么办

没有 EXIF 的文件会回退:文件时间 → 接收时间 → 落进 未知日期/。 界面上会标出这个日期是推测的,不假装它是拍摄时间。

改分类方式不会移动已经传过去的文件

分类规则只对新收到的文件生效。 之前落盘的文件留在原地 —— 悄悄挪动用户磁盘上的东西是不能接受的。