ADrive Studio
像 macOS Finder / Windows 资源管理器一样,在 VS Code 侧边栏中浏览阿里云盘(alipan.com)。目录浏览的做法与同目录下的 File Studio(file-studio-plugin)相同,连接阿里云盘的做法与 x-cmd(osclass4/osclass4-adrive-client)相同。
功能
- 活动栏新增「ADrive Studio」视图。未登录时视图里只有一个图标、一句登录提示和「扫码登录」按钮;登录后顶上是一条页签(与 SSH Studio 同款):文件、笔记。当前页签在视图折叠再展开后保持
- 「文件」页是阿里云盘的文件树:
- 备份盘(默认盘,默认展开)
- 资源盘(账号有资源盘且不同于备份盘时才显示)
- 顶层盘的行尾淡淡地写着账号名,文件的行尾写着大小
- 侧边栏只有一个视图(工具栏与文件树之间没有可拖拽的分割线),视图标题栏里不放任何按钮:
- 工具栏一行:第一个带文字的按钮 添加文件夹,在当前选中的目录下新建(选中文件时取其所在目录,未选中时为备份盘的根),新建后展开到新条目并选中
- 后四个只有图标的按钮:刷新(重新读取云端内容并重新取盘列表)、全部折叠、传输(上下箭头,打开传输面板;有正在上传的任务时向上的箭头变绿、有正在下载的时向下的变绿,暂停的不算)、设置(齿轮),悬停显示名称
- 齿轮菜单:最上面是账号的空间用量(「已用 X / 共 Y(N%)」、一条用量条、「剩余 Z」;用到九成以上用量条变红。是备份盘与资源盘合在一起的账号总量——开放平台只给总量,不分盘;打开菜单时查一次,30 秒内再开用查过的);退出登录(行尾附注账号名;未登录时是扫码登录);清理已下载的文件缓存;清除云盘中的修饰文件;「界面语言」是二级菜单,行尾显示当前语言,展开后列出「跟随 VS Code」与六种语言,当前设置打勾,点选即切换
- 界面语言支持中文、English、Deutsch、Français、日本語、한국어,默认跟随 VS Code 的显示语言,选择记录在配置文件里(见下文)。命令面板中的命令标题由 VS Code 按其显示语言渲染,不受此设置影响
- 文件树由插件自己绘制,图标为统一的线条图标(不跟随 VS Code 的文件图标主题)。文件按扩展名显示易于辨认的类型图标并着色:网页
< >(橙)、XML(蓝)、JSON { }(黄)、CSS { }(蓝)、YAML 列表(紫)、Markdown M↓(蓝)、PDF(红)、Word W(蓝)、PowerPoint P(橙)、Excel / CSV 表格(绿)、图片(紫)、音频(绿)、视频(红)、压缩包(黄)、代码 </>(按语言着色)、配置文件、字体;未识别的扩展名用普通文件图标。备份盘根目录下的 .notes 文件夹画成红色——那是「笔记」页的笔记本(见下),一眼认得出来,别当普通目录随手改动;资源盘里、子目录里同名的文件夹不算
- 鼠标放到行上时,行尾出现动作按钮:目录是上传、下载、复制路径;文件是下载、复制路径。顶层的盘只有上传(可以往盘的根传,但不整个下)。复制的是云端路径(如
/backup/photos)
- 图片、视频显示缩略图:云端在列目录时就给了缩略图地址,图片和视频的行图标直接换成缩略图(裁成方的、圆角),鼠标划过树不弹任何浮层。缩略图地址带签名、约 15 分钟有效,过期后会把所在目录重读一次换新地址,仍然取不到就换回类型图标。只加载看得见的那些行(
loading="lazy")
- 目录内容按需读取,展开时才加载;收展状态、选中项和滚动位置在视图折叠再展开后保持
- 单击图片(png / jpg / gif / webp / bmp / ico / avif)在编辑器区的预览面板里直接显示,本地不留副本:图片走云端的下载地址由页面自己加载,原图到位之前先拿缩略图垫着(压一点模糊),点图片在「缩到装得下」与「原始尺寸」之间切换
- 单击视频(mp4 / m4v / webm / mov / ogv)在同一个面板里播:直接放云端的原文件(对象存储支持 Range 请求,所以能边下边播、能拖进度条),缩略图当封面,不自动播也不预加载整个文件。看的是原画,走多少流量就是多少;mkv / avi / wmv / flv 这些容器 Chromium 不认(哪怕里面是 H.264),仍旧按下面那条走
- 预览面板只有一个,再点别的图片 / 视频就换掉里面的内容,焦点始终留在侧边栏,可以连着点着看。下载地址约 15 分钟有效,过期后自动换新的接着看(长视频看到一半也能这样续下去)
- 单击其他文件(含 svg、heic、tiff 这些网页显示不了的图,以及 mkv、avi 这些放不了的视频)即下载到本地缓存(
~/.x1/adrive-studio/cache/),然后在当前 VS Code 窗口中打开。打开的是只读副本(在本次会话里设为只读),改动不会传回云盘。同一版本(file_id 与 content_hash 都没变)第二次打开直接用缓存;超过 50 MB 的文件先弹确认框。单击目录展开 / 折叠
- 键盘:上下键移动,右键展开、左键折叠或跳到父目录,Enter 打开文件或切换目录,Home / End 跳到首尾,Delete(macOS 也可 ⌘⌫)删除,F2 重命名
- 预览面板开着的时候,用键盘在树里上下移动,走到哪张图片 / 哪个视频它就换成哪个(按住方向键连着走时只认停下来的那一个,中间经过的不去要地址)。面板没开就不管——键盘翻目录不会突然弹出面板;移到不能预览的条目上,面板里保持上一个不动
- 右键菜单:在目录上新建文件夹、上传…、下载…,下面一组「视频截图」「视频预览」「图片预览」「重复校验」(见下文);在文件上打开、下载…,视频文件还有「视频截图」;在任意条目上「复制路径」;在顶层盘之外的任意条目上「重命名」「删除」
- 删除前先弹出确认框,确认后移入阿里云盘的回收站(可在阿里云盘里恢复),不做永久删除。命令面板里的「删除」对当前选中项生效
- 清除云盘中的修饰文件:齿轮菜单里的一项,范围是整个云盘(备份盘,账号有资源盘的话也一起),不针对某个目录。先弹确认框说清楚要删哪些,确认后用全盘搜索把
.DS_Store 与 ._ 开头的文件一次找出来(openFile/search,一页 100 条),再并发移入回收站。搜索是为了少发请求:逐目录爬几千个文件夹很容易撞上 429,而 429 会让插件里所有在途请求一起等,看着就像卡死;搜索用不了会自动退回逐目录爬,只是慢些。删除只能一个一个发——开放平台没有批量接口(PDS 的 /v2/batch 只在企业版上,这边几个候选路径全是 404,2026-09-08 实测),所以靠并发提速:实测只读并发 8、写入并发 6 都不会 429,这里用 6,真撞上限流会当场把并发收到 2。这些是 macOS 的 Finder 目录设置与扩展属性(AppleDouble),除了占地方没有别的用处;本插件上传时已经不会带上它们,这个功能是给以前用别的方式传上去的存量文件用的。搜索是「包含」匹配,回来的结果里名字中间带 ._ 的普通文件会被滤掉;目录一概不动——万一真有目录叫 ._something,它和里面的东西都不会被删。中途随时可以取消(已经删掉的不会退回来),真撞上限流时进度里会写明「云端限流,等待 N 秒…」,不是卡死
笔记
「笔记」页把备份盘根目录下的 .notes 当作笔记本(没有就在第一次切到这一页时自动建出来),结构固定两层:
/.notes/<分类>/<笔记>/index.md 正文(markdown)
/.notes/<分类>/<笔记>/image-….png 正文里插的图片,与 index.md 同级,正文里用相对路径引用
/.notes/<分类>/<笔记>/<文件名> 正文里插的附件,保留原来的文件名,正文里是指向它的相对链接
/.notes/<分类>/<笔记>/index.pdf 工具栏上「PDF」生成的 PDF,每生成一次换掉上一份
/.notes/<分类>/conf.yaml 这个分类在树里的显示样式(右键「设置」写的,见下)
视频截图、视频预览、图片预览、重复校验
都在文件树的右键菜单里,作用于右键的那个文件夹(顶层的盘也行):
- 视频截图:给视频截一帧当缩略图。右键文件夹是处理它和所有子文件夹里的视频,右键视频文件就只处理它,别的文件跳过。弹窗里填截取第几秒的画面(默认 120 秒;视频没那么长就截正中间那一帧),以及已有缩略图的要不要重新生成(默认不勾,跳过)。缩略图是 PNG,与视频同名、只换扩展名(
a.mp4 → a.png),长边不超过 800 px,传到视频所在的云端目录;重新生成时按上传的同名规则覆盖(新的传上去、旧的进回收站)。从盘的根往下找时跳过笔记的 .notes。进度在通知里,可以取消,结束时说清楚生成、跳过、失败各几个
- 截帧用本机的 ffmpeg(阿里云盘自己的缩略图有的编码截不出来,比如 AV1,截哪一刻也定不了)。ffmpeg 直接读云端的下载地址,靠 Range 请求只取需要的那几段,不用把整个视频下下来:常见的 MP4 / MKV 每个视频只读几 MB;没有索引的文件(录屏常见的不带索引的 MKV 等)要从头读到截帧的位置,截得越靠后读得越多。AV1 要 ffmpeg 带软件解码器(
libdav1d 或 libaom-av1,Homebrew 的 ffmpeg 自带 dav1d)
- 没装 ffmpeg 会提示怎么装;装在别处的在配置文件里写
ffmpegPath(见下文)
- 视频预览:在编辑器区开一个页签看这个文件夹(不含子文件夹)里的图片:上面是选中的那张大图,下面一排是全部图片(横着滚,名字在图下面);同目录里有同名视频的(扩展名前面那段相同,不分大小写,如
a.png 与 a.mp4),图片右下角标出视频的格式
- 键盘:↑↓ 换图(没在放视频时 ←→ 也换);空格放同名视频、再按空格停下回到图片(再放接着上次的位置);放视频时 ← / → 后退 / 前进 15 秒
- 删除按钮把这张图连同它的同名视频一起移入回收站,不再确认——所以这个按钮只认鼠标点,键盘碰不到它
- 视频直接放云端的原文件,只能放浏览器认识的格式(mp4 / webm / mov),mkv、avi 这些会提示放不了
- 图片预览:在编辑器区开一个页签,像访达的图标视图那样一格一张地铺开这个文件夹(不含子文件夹)里的图片,名字在图下面。浏览时只用云端给的缩略图,不加载原图
- 点一张选中它;方向键移动选中(←→ 前后一张,↑↓ 上下一行)
- 选中后按空格放大看原图(像访达的「快速查看」,这时才去取原图),再按空格(或 Esc、点图片外面)关掉;放大着也能用方向键换图
- 重复校验:在编辑器区开一个页签,找出这个文件夹连同所有子文件夹里内容相同的文件。上面是进度条与状态(已扫几个文件夹、几个文件),可以中途「停止」(扫到的照样列出来)、扫完「重新校验」;下面一组一组地列出重复的文件:组标题写着几个相同、每个多大,每个文件一行写名字、大小、所在文件夹,右边是删除按钮。组按「删掉多余的副本能省多少」从大到小排
- 不下载任何文件:判重用的是列目录时云端就给了的校验码(
content_hash,整个文件的 SHA1)加大小。这个校验码是阿里云盘服务端在文件上传完成时按实际存下的内容算的(秒传的文件是服务端核对过所有权证明、引用已有的同一份),客户端报不了假的。所以只是把目录一层层列一遍(同时列 4 个),文件名、修改时间不同但内容一样的也算重复
- 不参与比较:0 字节的文件(空文件的校验码都一样)、
.DS_Store 与 ._*、没传完的半成品、云端没给校验码的(个数写在总结里);从盘的根往下查时跳过笔记的 .notes
- 删除不再确认,移入回收站(能恢复),文件树跟着更新;一组里只剩一个时它的删除按钮是灰的——删了就一份都不剩了。删到一组只剩一个,这一组就收起来
- 删除重复(扫完、有重复时出现在「重新校验」左边):每组只保留排在第一个的(组里按路径排),其余的一次删掉。一下子删很多,先弹一次确认框写明删几个、能省多少;删的时候同时删 4 个,进度条改成删除的进度,单个的删除按钮都灰掉,删完写明删了几个、省了多少、几个没删成
- 视频预览、图片预览、重复校验的页签都是一个文件夹一个,同一个文件夹再点就调到前面;这个文件夹里有变化(上传了、截了图、在树里删了 / 改名了)会自动重读
上传 / 下载与传输面板
- 上传:鼠标放到目录行上,点行尾的上传按钮(或右键「上传…」),选本地的文件 / 文件夹(macOS 的对话框可以两者同时选,别的平台先问一句选哪种),选定后即作为任务加进上传队列。选了文件夹就连同里面的一切一起传,云端建出同样的目录结构(空目录也建,符号链接跳过);macOS 的修饰文件(
.DS_Store、._*)在遍历时直接跳过,不让它们上去(直接点名选中的照传——那是你要的),一个目录里除了修饰文件什么都没有就当空目录建出来;云端已有同名文件时覆盖(内容一样就原样不动,一个请求都不多发;同名的是个目录则不动它,只把文件传上去)。支持秒传:云端已经有一份同样内容的文件时直接建好,一个字节都不用传。大文件走分片上传(16 MB 起,分片数超过 2000 就加大每片),传得慢导致分片地址过期会自动重新取。支持断点续传:传到一半暂停、断网、关掉 VS Code 都不用从头再来——云端记得收到了哪几片,下次只补剩下的(断点记在 uploads.json,本地文件改动过就作废)
- 下载:点文件或目录行尾的下载按钮(或右键「下载…」),选一个本地文件夹作为下载位置,即作为任务加进下载队列。选了目录就连同里面的一切一起下,本地建出同样的目录结构(先向云端逐层列举,大目录列举得久,通知上可以取消);本地已有同名的会加序号(
名字 (1).txt),不覆盖。支持断点续传:下到一半暂停、断网、关掉 VS Code,下次接着下(.part 文件里已收到的字节就是断点,旁边的 .part.etag 记着那份内容的 ETag,续传前先探一下云端现在的 ETag,对不上——云端文件在中断期间被换过——就从头下)。网络抖动、超时、地址过期会自动重试,每次从 .part 已有的地方接着来。只有明确取消才删掉 .part
- 传输面板:工具栏的传输按钮打开(添加任务时也会自动打开),编辑器区的一个页签,上传、下载两个 tab,各自显示任务:文件名、进度条、进度条右边是当前速度,下面一行是来源 → 去向(上传是本地文件 → 云端路径,下载是云端文件 → 本地路径;两段各自省略,鼠标停上去看完整的),右边是当前在做什么:准备中(查断点、建云端目录、取下载地址)、校验中(算哈希、跟云端比对,大文件这一步要好几秒到几十秒,会写明算到哪儿了,如「校验中 · 3.2 GB / 10.0 GB」,速度那格显示读盘速度)、收尾中(合并分片、回收被覆盖的旧文件),真在收发数据时则显示已传 / 总量。这几步一个字节都还没发出去,进度条不动——原来这段时间界面是空白的,看着像卡死。传完的任务从列表里消失,失败的留着显示原因,可以重试或移除,正在传的可以暂停(进度条变灰,已传的量留着)、继续或取消。取消一个没传完的上传会把云端那个半成品一并收进回收站;暂停则留着,等你继续。列表上方还有整个 tab 的批量按钮:全部暂停(有在传或排队的才出现)、全部继续(有暂停着的才出现)、清除失败、全部取消
- 文件校验:传输面板顶上的切换按钮,管的是上传遇到同名文件时怎么判断两边是不是同一份(是同一份就什么都不做,云端保持原样,
file_id 不变、已有的分享链接和收藏都还在)。两档都先比文件大小——大小不一样必然不是同一份,改动过的文件多半在这一步就分出来了。大小相同时:精确(默认)比整个文件的 SHA1,本地要把文件整个读一遍(约 580 MB/s,2 GB 约 4 秒),这个 SHA1 接着还要拿去建文件(云端认得出这份内容就秒传),并不白算;快速只比修改时间——云端的 updated_at 是那份文件传上去的时刻,本地比它新就当改过,零哈希、零额外请求,代价是大小和时间都没变、内容却变了的文件会被当成同一份,于是该覆盖的没覆盖。设置记录在配置文件的 verify 键里。注意这个开关不影响秒传——秒传是云端的判断,协议要求必须给出整个文件的 SHA1
- 并发数:传输面板顶上两个下拉,分别设上传、下载同时进行的任务数(1–10,默认 1),选完立刻生效,不必重启。调大马上多起几个任务,调小不打断正在传的,等它们传完自然收敛。设置记录在配置文件里(见下文)
登录与授权
做法与 x-cmd 相同:插件不持有阿里云盘的 app 密钥,扫码、换取 / 刷新 token 一律经由授权服务端 http://adrive.osclass.cn/adrive-server(写死在 src/adrive/authClient.ts 里,不是配置项)完成;拿到 access_token 之后的列目录、新建、改名、删除、取下载地址、分片上传才由插件直连 https://openapi.alipan.com(分片本身传到接口返回的对象存储地址)。
- 第一次打开视图时显示登录面板,点扫码登录:插件向授权服务端取二维码,把图片抓下来显示在侧边栏里(抓不到时可点「在浏览器中打开」),用手机阿里云盘 App 扫码并确认,最长等 3 分钟。二维码过期或出错时可点「重试」
- 授权成功后 token 存到
~/.x1/adrive-studio/token.json(权限 rw-------),重启 VS Code 后免扫码。access_token 临过期(2 分钟内)自动用 refresh_token 刷新;刷新失败(refresh_token 也失效)会自动登出并回到登录面板
- 与 x-cmd 的
~/.xcmd/adrive-token.json 各用各的文件:阿里云盘刷新 token 后旧的 refresh_token 会失效,两个程序若共用一份会互相把对方踢下线
- 齿轮菜单里的退出登录只删本地的 token.json,不会撤销授权
- 云端限流(HTTP 429)时按服务端给的 Retry-After 等待后重试,所有在途请求一起等(没有 Retry-After 就指数退避,封顶 20 秒——这是交互式插件,等一分钟跟卡死没区别);5xx 与网络异常有限次重试后报错。开放平台没有批量接口(
/v2/batch 那套是企业版 PDS 的),要快只能靠并发;实测只读并发 8、写入并发 6 都不会触发限流
配置文件
插件不使用 VS Code 的设置项,所有偏好记录在用户目录的 ~/.x1/adrive-studio/conf.yaml 里(与 File Studio 的 ~/.x1/file-studio/conf.yaml、SSH Studio 的 ~/.x1/ssh-studio/conf.yaml 同一套做法)。齿轮菜单里的操作会直接写入该文件,文件里的其他键原样保留;也可以手工编辑,重启 VS Code 后生效。
| 键 |
默认值 |
说明 |
language |
auto |
界面语言:auto(跟随 VS Code)、zh-cn、en、de、fr、ja、ko |
uploadThreads |
1 |
同时进行的上传任务数,1–10。由传输面板顶上的下拉维护 |
downloadThreads |
1 |
同时进行的下载任务数,1–10。由传输面板顶上的下拉维护 |
verify |
exact |
上传遇到同名文件时怎么判断两边是不是同一份:exact 比整个文件的 SHA1,fast 只比修改时间(快,但会漏掉「大小和时间都没变」的改动)。两者都先比文件大小。由传输面板顶上的切换按钮维护;早先版本写的 prefix 会当作 fast |
noteToc |
true |
笔记编辑器左边的目录展开着没有。由目录顶上的收起按钮、工具栏上的目录按钮维护 |
noteTocWidth |
(220) |
笔记编辑器左边的目录有多宽,140–480 的整数(px)。由目录与正文之间的分割线维护,没设置时用默认的 220 |
codeTheme |
default |
笔记里代码块的主题:default(默认主题,Monokai Pro 配色)、serene(宁静深邃)、stripes(清新条纹)、starry(暗夜繁星);认不出的值当 default。由代码块工具条上的主题下拉维护 |
codeWrap |
false |
笔记里的代码块自动换行(关着时长行横向滚动)。由代码块工具条上的自动换行按钮维护 |
codeLanguage |
(纯文本) |
新加的代码块默认用的语言,写 markdown 标注行的那个词(如 java、python、form);空串或不写就是纯文本。由工具栏上的「代码块默认类型」维护 |
noteHeadingNumbers |
true |
笔记的标题前面显示自动编号(1、1.1、1.1.1…)。由「正文 ▾」下拉里的「标题编号」维护 |
pdfBrowser |
(自动找) |
笔记生成 PDF 用的浏览器:Chrome / Edge / Chromium 的可执行文件路径(macOS 上写 /Applications/Google Chrome.app 这样的 .app 也行,~ 开头的会展开)。不写就按平台在常见位置找 Chrome、Edge、Chromium、Brave。只能手工写,改了马上生效(每次生成 PDF 时重新读) |
ffmpegPath |
(自动找) |
视频截图用的 ffmpeg:可执行文件的路径,或它所在的目录(ffprobe 要在同一目录),~ 开头的会展开。不写就在 PATH 与常见位置(Homebrew 的 /opt/homebrew/bin、/usr/local/bin 等)找。只能手工写,改了马上生效 |
noteTheme |
auto |
笔记页的深浅:dark、light,或 auto(跟着 VS Code 的主题)。由工具栏上的「深色 / 浅色」按钮维护(按钮只在深色、浅色之间切;想回到跟着 VS Code,把这一项删掉或写成 auto) |
~/.x1/adrive-studio/ 下的其他文件:
~/.x1/adrive-studio/
├── conf.yaml 偏好(界面语言、上传 / 下载并发数、同名文件的校验方式、笔记目录展开着没有与宽度、代码块主题与换行、标题编号、笔记页深浅、生成 PDF 用的浏览器、视频截图用的 ffmpeg)
├── token.json 阿里云盘授权(access / refresh token、过期时刻与登录会话的标识;几个 VS Code 窗口共用,一个窗口登出、换账号,别的窗口跟着)
├── uploads/ 没传完的上传,一条一个文件(file_id + upload_id),下次接着传;传完即删。早先版本的 uploads.json 头一次用到时迁过来
├── downloads/ 下到一半的文件夹记在这里(本地哪个文件夹是为哪个云端文件夹建的),关了窗口再下同一个文件夹时接着下;整个下完即删
├── cache/ 单击打开文件时下载的只读副本:<driveId>/<fileId>/<content_hash 前 8 位>/<文件名>
└── notes/ 笔记的本地工作副本:<driveId>/<笔记文件夹的 file_id>/ 下是 index.md、正文引用的图片
与 .sync.json(同步状态:上次同步的云端版本、有没有没传的修改)。用 file_id 命名,
笔记改名、换分类都不影响。「清理已下载的文件缓存」不碰它——里面可能有还没传上去的修改
齿轮菜单「清理已下载的文件缓存」可整个清掉
目录结构
src/:扩展代码
extension.ts:激活、命令注册;新建 / 改名 / 删除 / 上传 / 下载 / 打开 / 语言切换 / 清缓存的具体执行
sidebarView.ts:侧边栏唯一的 webview 视图(下发文案、盘列表与目录内容,推送扫码登录的进度,执行页面交回的动作)
transfer.ts:上传 / 下载的任务队列(两个独立的池,各自的并发数),文件夹展开、云端目录按需创建、进度与速度统计
transferView.ts:传输面板(编辑器区的 webview 页签)
mediaView.ts:图片 / 视频预览面板(编辑器区的 webview 页签),并判断哪些格式能直接看
notes.ts:笔记的云端结构(.notes / 分类 / 笔记)与本地工作副本的同步(打开时拉、编辑后传、冲突另存)
notePanel.ts:笔记编辑器(编辑器区的 webview 页签,每篇一个),掌握同步的节奏(停手 5 秒 / ⌘S / 关页签)
notePdf.ts:笔记生成 PDF:找本机的 Chrome / Edge / Chromium,套上笔记页的样式表拼成网页,经 --remote-debugging-pipe 走 DevTools 协议无头打印
prompts.ts:文件页与笔记页共用的确认框与名称校验
thumbnails.ts:视频截图:找本机的 ffmpeg / ffprobe,列出目标里的视频,一个个截帧成同名 PNG 传回视频所在目录
galleryView.ts:视频预览(编辑器区的 webview 页签,每个文件夹一个):图片与同名视频配对、给页面要原图 / 视频的下载地址、删除图片连同同名视频
duplicateView.ts:重复校验(编辑器区的 webview 页签,每个文件夹一个):一层层列目录(并发 4)、按云端校验码 + 大小分组、删除时保护每组的最后一份
imageGridView.ts:图片预览(编辑器区的 webview 页签,每个文件夹一个):网格只用云端缩略图,放大看时才给原图地址
cleanup.ts:清除整个云盘里的 macOS 修饰文件(.DS_Store / ._*):全盘搜索 → 并发移入回收站,搜索不可用时退回逐目录爬;认这类文件的规则(isMetadataFile)由上传那边共用
adrive/authClient.ts:授权服务端的三个端点(取二维码、轮询扫码状态、换取 / 刷新 token),解开 { success, message, data } 信封
adrive/openApi.ts:阿里云盘开放平台接口(云盘信息、列目录、全盘搜索、文件详情、新建文件夹、改名、移入回收站、取下载地址、分片上传的建文件 / 取分片地址 / 列已传分片 / 收尾)与限流 / 重试
adrive/session.ts:token 持久化与自动刷新、扫码登录流程、盘列表
adrive/download.ts:把云端文件下载到本地(缓存副本 / 下载任务)
adrive/upload.ts:把本地文件传到云端(秒传、同名覆盖、分片上传)
adrive/hash.ts:秒传要算的三个值(前 1 KB 的 SHA1、整个文件的 SHA1、拿 access_token 定位的所有权证明)
adrive/uploadState.ts:没传完的上传记在 uploads/ 下(一条一个文件),供下次续传
adrive/downloadState.ts:下到一半的文件夹的记录(downloads/),关了窗口再下同一个文件夹时接着下
adrive/fileLock.ts:跨窗口的独占锁(.part、断点、笔记本地副本都靠它:记着持有者的进程号,进程没了锁就作废)
adrive/cancel.ts:暂停 / 取消一路传到云端请求(AbortSignal)的几个小工具
adrive/types.ts:报文类型
i18n.ts:运行时文案的翻译与语言切换;confFile.ts:读写配置文件 ~/.x1/adrive-studio/conf.yaml;webviewHtml.ts:七个 webview 共用的页面装配(模板 + CSP + nonce)
media/main/:侧边栏页面(HTML / CSS / JS):main.js 是登录面板、页签与「文件」页(工具栏、文件树、右键菜单、齿轮菜单),notes.js 是「笔记」页(两层树、弹窗),后者用的 vscode api、菜单、图标从 main.js 交出的 window.__ad 拿
media/note/:笔记编辑器页面(HTML / CSS / JS):main.js 是编辑器与同步状态(建好编辑器、切换模式后清空撤销历史:编辑器把「整篇换成读进来的内容」也记成了一步,不清的话刚打开就按 ⌘Z 会把正文撤空),tables.js 是表格列宽,outline.js 是左边的目录,blocks.js 是区块左边的按钮、区块菜单、插入菜单与拖动,codeblocks.js 是代码块(作为编辑器插件替换自带的代码块视图,行号与高亮是 ProseMirror 装饰),formblock.js 是 Form(表单)代码块的高亮语法与逐行复制按钮,codeformat.js 是代码块的格式化(各语言的重排缩进;js-beautify / sql-formatter 在 vendor/formatters.js 里按需加载),lock.js 是锁定(ProseMirror 不可编辑 + 拦下改文档的事务),theme.js 是笔记页的深色 / 浅色(与 VS Code 不一致时在 body 上重定义 --vscode-* 变量),numbering.js 是标题编号(节点装饰 + CSS 伪元素),toolbar.js 是工具栏的排法与「正文 ▾」下拉(外观在 style.css 的「工具栏」一节),insert.js 是「插入 ▾」菜单,format.js 是字体、字号、两种颜色与取色器(也给编辑器注册 span 标记),find.js 是查找替换,pdf.js 是工具栏的「PDF」(用编辑器自己的预览渲染器把此刻的正文渲染成 HTML 交给扩展;打印用的网页另带 pdf.css,把整页编辑器的排法改成纸上从上往下排、加分页规矩);这几个从 main.js 交出的 window.__note 拿编辑器,直接对编辑器内部的 ProseMirror 文档下事务;vendor/ 是打包好的 Toast UI Editor(含五种界面语言包与代码高亮用的 Prism)与格式化库,由 scripts/build-editor.js 生成
media/transfer/:传输面板页面(HTML / CSS / JS),两个 tab 的任务列表与并发数下拉
media/preview/:预览面板页面(HTML / CSS / JS),图片是缩略图垫底 + 原图后台加载 + 缩放切换,视频是缩略图当封面 + 浏览器自带播放器
media/gallery/:视频预览页面:上面大图 / 播放器,下面横滚的缩略图条,键盘换图、放 / 停视频、跳 15 秒,删除
media/dupes/:重复校验页面:进度条与状态、表头 + 一组一组的结果、每行的删除按钮
media/images/:图片预览页面:缩略图网格、方向键移动选中、空格放大看原图
l10n/:运行时文案的翻译包,英文原文为 key
package.nls.*.json:命令标题、视图名等静态文案,由 VS Code 按显示语言选用
scripts/check-l10n.js:校验 t() 用到的每条文案在各语言包里都有译文、没有多余 key,以及 package.nls.*.json 的 key 一一对应
scripts/check-webview.js:校验扩展与七个页面对得上——下发的文案 key 与页面用到的一一对应、post / send 的消息类型双向都有人处理、页面用到的 class 在各自的 style.css 里都有定义(页面的脚本是页面目录下所有的 .js,vendor/ 不算)
scripts/check-code-langs.js:校验代码块的语言登记与 build-editor.js 打包的 Prism 语法对得上
scripts/build-editor.js:把 Toast UI Editor(npm 包里的 UMD 版把 prosemirror 当外部依赖,没法直接用 script 标签加载)连同语言包、prosemirror-state 的选区类(区块菜单要用,与编辑器是同一份模块)、Prism 与代码块菜单里的语言用 esbuild 打成 media/note/vendor/ 下的一个 js + 一个 css。产物提交在仓库里,平时不用跑;升级编辑器或增减语言时 npm install && npm run build-editor
开发与调试
npm install
npm run compile # 编译到 out/
npm run watch # 监听源码变化自动编译
npm run check-l10n # 校验翻译文件
npm run check-webview # 校验扩展与页面之间的文案 key / 消息类型 / 样式类
npm run check-code-langs # 校验代码块语言登记与打包的 Prism 语法
npm run build-editor # 重新生成笔记编辑器的 vendor 文件(升级 Toast UI Editor 时才需要)
- 按
F5 启动「Run Extension」在扩展开发宿主中调试。
- 或将本目录符号链接到
~/.vscode/extensions/lupee.adrive-studio-<version>(<version> 与 package.json 里的一致),编译后执行 Developer: Reload Window 即可在日常使用的 VS Code 中加载。
- 依赖的 VS Code 版本 ≥ 1.85(内置 Node 18,全局
fetch 可用;分片上传用的是 Node 自带的 https,插件没有引入 HTTP 库)。
打包
npm run package # 生成 adrive-studio-<version>.vsix