如何清空有几万个文件的GDrv回收站

上个月用下载器把 p 站上关注的画师的图全部下回了电脑,结果硬盘被塞满了,于是决定用有损选项上传到咕咕 drv 上,上传了几天后发现他跟咕咕相册不同,是在本地转换的,这样就没有上传到意义了,于是就停掉了上传,然后把已上传的文件删掉了。

结果这一折腾就出问题了,把文件删除掉后会移动到回收站,由于我是直接在备份与还原的 app 里点删除云端文件的,结果他跟 1drv 一样把文件遍历一个列表,然后一个一个扔到回收站里,于是回收站里出现了成千上万的散开的文件,而不是一个包含了成千上万文件的文件夹

这时候又引出了另一个问题,GDrv 的清空回收站逻辑是这样的,当你点击清空回收站的时候,他会获取被标记为已删除的文件的文件列表,然后经过组织之后以每次十个的调用形式用一个批量提交 api 去删除文件:

批量删除
批量删除

所以当你的回收站里散开的文件十分多的时候,获取列表的 api 就会超时,因为在超时时间内后端根本统计不完已删除文件的列表,于是你始终都清空不了回收站。

这时候该怎么办呢,我试了一下午,忽然想起搜索是可以搜到已删除文件的,那应该能像 gmail 一样通过条件搜索只显示已删除文件吧,于是爬了下文档,果然是可以的:

https://drive.google.com/drive/search?q=is:trashed

简单但麻烦的方法

这里的搜索 api 有考虑到数量庞大的文件请求超时的问题,是每次二十个这样请求追加到列表里的,这样我就可以手动彻底删除已删除文件了。

点击一个文件,然后往下滚动,直到加载了几百个文件,再按住 shift 点击另一个文件,可以批量选择数百个文件,然后点击右上角的垃圾桶,确认删除,然后慢慢等就行了。

可以按 F12 打开控制台看 XHR 请求,当十来二十秒都没有新的 v2internal 请求后,说明刚才选中的文件已经删光了,这时候可以刷新页面继续获取文件列表然后删除,试过每次 1000 个文件以内一般不会出错。

这次碰到的问题主要是工程师没有考虑到大量文件时 api 超时的问题,不过一般来说也不会让回收站放十几万个文件。

另外咕咕的 api 设计倒是有点意思,他这个批量接口思路跟 GraphQL 应该是类似的,前端对请求聚合,一次过扔给后端,后端对数据聚合,然后一次过扔回来,在节省了请求的前提下还可以兼顾 RESTful 原则。

这个批量接口的 body 其实就是一堆拼接好参数的 URL 和请求类型,返回的数据则是带 api 命名空间的 json,虽然封装一下应该会好看不少,但明显比 GraphQL 一个 json 扔给服务端,然后再拿到一个同样结构的数据难看吧?

不过 GraphQL 我倒是没仔细研究过,只是粗略看过下范例,等啥时候有空再看吧。

顺带一提后来搜了下果然已经有前人踩到这个坑了,还写了个工具自动删除,不过我已经手动删干净了,就不试用了了,这里附上连接:

https://github.com/cfbao/google-drive-trash-cleaner

复杂但省事的方法

过了一段时间,又手贱传了一大堆文件,删除的时候又碰到这问题了,但是几万个文件删起来会累死的,于是找找有没有其他办法。

周末查了大半天,发现咕咕有个脚本平台可以很方便的操作自家的服务,查了下 api 感觉有戏,于是就开始搞了,链接如下:

https://script.google.com/home

进入后点击左上角的新建脚本,然后点击菜单里的资源-高级Google服务,在弹出的新窗口里找到Drive API,把右边的开关打开,然后保存。

最后把以下代码贴到代码框里,然后点击工具栏里的运行按钮即可(三角形那个):

function myFunction() {
	var files = DriveApp.getTrashedFiles()
	while (files.hasNext()) {
		var currentFile = files.next()
		if (currentFile.isTrashed()) {
			Drive.Files.remove(currentFile.getId())
			Logger.log('Deleted file: ' + currentFile.getName())
		}
	}
}
js

跑一次最多可以跑十分钟,一般 10 分钟可以删三四万个文件了,如果没删完就会提示运行超时。

超时后再次运行即可,如果已经删完了,那么脚本几秒钟就可以跑完了。