分享一个从云端下载快照到本地的脚本

本贴最后更新于 271 天前,其中的信息可能已经事过境迁

一个手贱,把我本地的快照全给清空了。

image.png

想了想感觉还是需要下载回来一部分,不然还是有些风险。

但是一个个翻页点击,体感还是太恐怖了。

image.png

看了一下,发现有提供快照相关的 API,所以写了一个脚本批量处理,以下的代码依赖于 RunJs 插件,请放到代码块里面,然后使用插件运行。

"use strict"; const request = globalThis.runJs.api.request; class SnapshotScheduler { constructor() { this.now = new Date(); } isInCurrentWeek(date) { const startOfWeek = new Date(this.now); startOfWeek.setDate(this.now.getDate() - this.now.getDay()); return date >= startOfWeek; } getTimeDifferenceInDays(date) { return Math.floor((this.now.getTime() - date.getTime()) / (1000 * 3600 * 24)); } isSameDay(date1, date2) { return date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth() && date1.getDate() === date2.getDate(); } isHourDifferent(date1, date2) { return date1.getHours() !== date2.getHours(); } shouldDownloadSnapshot(last, current, next) { const currentDate = new Date(current.created); const daysDifference = this.getTimeDifferenceInDays(currentDate); if (this.isInCurrentWeek(currentDate)) { return true; // Download all snapshots from the current week } const lastDate = last ? new Date(last.created) : null; const nextDate = next ? new Date(next.created) : null; if (daysDifference <= 30) { // Every hour, plus start and end of day if (!lastDate || !this.isSameDay(currentDate, lastDate)) { return true; // First snapshot of the day } if (!nextDate || !this.isSameDay(currentDate, nextDate)) { return true; // Last snapshot of the day } return this.isHourDifferent(currentDate, lastDate); } if (daysDifference <= 90) { // First and last snapshot of each day return (!lastDate || !this.isSameDay(currentDate, lastDate)) || (!nextDate || !this.isSameDay(currentDate, nextDate)); } if (daysDifference <= 180) { // Last snapshot of each day return !nextDate || !this.isSameDay(currentDate, nextDate); } if (daysDifference <= 365) { // Every third day, last snapshot if (daysDifference % 3 !== 0) return false; return !nextDate || !this.isSameDay(currentDate, nextDate); } // Over a year: weekly, last snapshot const weekNumber = Math.floor(daysDifference / 7); if (daysDifference % 7 !== 0) return false; return !nextDate || Math.floor(this.getTimeDifferenceInDays(nextDate) / 7) !== weekNumber; } } class SnapshotManager { constructor() { this.scheduler = new SnapshotScheduler(); } async getAllSnapshots(startFrom, endTo, startPage) { let page = startPage !== null && startPage !== void 0 ? startPage : 0; let allSnapshots = []; let continueFetching = true; while (continueFetching) { const snaps = await this.getCloudRepoSnapshots(page); const filteredSnapshots = snaps.snapshots.filter(snapshot => { const snapshotDate = new Date(snapshot.created); return snapshotDate <= startFrom && snapshotDate >= endTo; }); console.debug(`Fetched page ${page + 1}, total snapshots: ${filteredSnapshots.length}: ${snaps.snapshots[0].hCreated} ~ ${snaps.snapshots[snaps.snapshots.length - 1].hCreated}`); allSnapshots = allSnapshots.concat(filteredSnapshots); page++; if (page >= snaps.pageCount || new Date(snaps.snapshots[snaps.snapshots.length - 1].created) < endTo) { continueFetching = false; } } return allSnapshots.sort((a, b) => b.created - a.created); // Sort descending } async downloadSnapshots(startFrom, cutoff, startPage) { console.log("Fetching all snapshots..."); const allSnapshots = await this.getAllSnapshots(startFrom, cutoff, startPage); console.log(`Total snapshots fetched: ${allSnapshots.length}`); let totalDownloaded = 0; for (let i = 0; i < allSnapshots.length; i++) { const currentSnapshot = allSnapshots[i]; const lastSnapshot = i > 0 ? allSnapshots[i - 1] : null; const nextSnapshot = i < allSnapshots.length - 1 ? allSnapshots[i + 1] : null; if (this.scheduler.shouldDownloadSnapshot(lastSnapshot, currentSnapshot, nextSnapshot)) { await this.downloadSnapshot(currentSnapshot); totalDownloaded++; } } return totalDownloaded; } async getCloudRepoSnapshots(page) { const response = await request('/api/repo/getCloudRepoSnapshots', { page: page }); return response; } async downloadSnapshot(snapshot) { const snapshotId = snapshot.id; console.debug(`[${snapshot.hCreated}] Downloaded snapshot ${snapshotId}`); await request('/api/repo/downloadCloudSnapshot', { id: snapshotId, tag: '' }); } } async function runMainWithTiming(startFrom, endTo, startPage) { console.log("Starting snapshot download process..."); console.log(`Start date: ${startFrom.toISOString()}`); console.log(`Cutoff date: ${endTo.toISOString()}`); const startTime = Date.now(); const snapshotManager = new SnapshotManager(); const totalDownloaded = await snapshotManager.downloadSnapshots(startFrom, endTo, startPage); const endTime = Date.now(); const executionTime = (endTime - startTime) / 1000; // Convert to seconds console.log(`Download process completed.`); console.log(`Total snapshots downloaded: ${totalDownloaded}`); console.log(`Total execution time: ${executionTime.toFixed(2)} seconds`); } let startFrom = new Date('2024-09-01'); let endTo = new Date('2023-12-01'); runMainWithTiming(startFrom, endTo, 74);

下载快照的时候,遵循以下策略:

  • 对于当前周的快照,全部下载
  • 对于最近一个月内的快照,确保每小时至少下载一个,并且总是下载每天的第一个和最后一个快照
  • 对于 1-3 个月内的快照,只保留每天的第一个和最后一个快照
  • 对于 3-6 个月内的快照,只保留每天的最后一个快照
  • 对于 6 个月到 1 年内的快照,每三天保留最后一个快照。
  • 对于超过 1 年的快照,每周保留最后一个快照

运行时间还是相当长的,我大概跑了半个小时的样子,主要问题在于为了谨慎期间没有做并行处理,而是在 for loop 里面一个个 await Promise。

最后效果如下,原本 387 页,下载之后保留了 22 页。临近的一段时间,快照保存的都比较密集;而更为久远的时间段,快照的保存就稀疏一些。

image.png

image.png

  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    25992 引用 • 107846 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • Wide

    Wide 是一款基于 Web 的 Go 语言 IDE。通过浏览器就可以进行 Go 开发,并有代码自动完成、查看表达式、编译反馈、Lint、实时结果输出等功能。

    欢迎访问我们运维的实例: https://wide.b3log.org

    30 引用 • 218 回帖 • 640 关注
  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    25992 引用 • 107846 回帖
  • Unity

    Unity 是由 Unity Technologies 开发的一个让开发者可以轻松创建诸如 2D、3D 多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

    25 引用 • 7 回帖 • 119 关注
  • RIP

    愿逝者安息!

    8 引用 • 92 回帖 • 404 关注
  • GitLab

    GitLab 是利用 Ruby 一个开源的版本管理系统,实现一个自托管的 Git 项目仓库,可通过 Web 界面操作公开或私有项目。

    46 引用 • 72 回帖
  • OpenCV
    15 引用 • 36 回帖 • 8 关注
  • Notion

    Notion - The all-in-one workspace for your notes, tasks, wikis, and databases.

    10 引用 • 77 回帖 • 1 关注
  • 阿里云

    阿里云是阿里巴巴集团旗下公司,是全球领先的云计算及人工智能科技公司。提供云服务器、云数据库、云安全等云计算服务,以及大数据、人工智能服务、精准定制基于场景的行业解决方案。

    85 引用 • 324 回帖 • 1 关注
  • 创业

    你比 99% 的人都优秀么?

    82 引用 • 1395 回帖
  • Lute

    Lute 是一款结构化的 Markdown 引擎,支持 Go 和 JavaScript。

    29 引用 • 202 回帖 • 27 关注
  • Mobi.css

    Mobi.css is a lightweight, flexible CSS framework that focus on mobile.

    1 引用 • 6 回帖 • 765 关注
  • GitBook

    GitBook 使您的团队可以轻松编写和维护高质量的文档。 分享知识,提高团队的工作效率,让用户满意。

    3 引用 • 8 回帖 • 2 关注
  • 倾城之链
    23 引用 • 66 回帖 • 170 关注
  • Webswing

    Webswing 是一个能将任何 Swing 应用通过纯 HTML5 运行在浏览器中的 Web 服务器,详细介绍请看 将 Java Swing 应用变成 Web 应用

    1 引用 • 15 回帖 • 645 关注
  • CodeMirror
    2 引用 • 17 回帖 • 167 关注
  • 游戏

    沉迷游戏伤身,强撸灰飞烟灭。

    185 引用 • 825 回帖 • 1 关注
  • 叶归
    12 引用 • 54 回帖 • 21 关注
  • Ruby

    Ruby 是一种开源的面向对象程序设计的服务器端脚本语言,在 20 世纪 90 年代中期由日本的松本行弘(まつもとゆきひろ/Yukihiro Matsumoto)设计并开发。在 Ruby 社区,松本也被称为马茨(Matz)。

    7 引用 • 31 回帖 • 258 关注
  • Git

    Git 是 Linux Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

    211 引用 • 358 回帖
  • App

    App(应用程序,Application 的缩写)一般指手机软件。

    91 引用 • 384 回帖
  • 印象笔记
    3 引用 • 16 回帖 • 1 关注
  • Ngui

    Ngui 是一个 GUI 的排版显示引擎和跨平台的 GUI 应用程序开发框架,基于
    Node.js / OpenGL。目标是在此基础上开发 GUI 应用程序可拥有开发 WEB 应用般简单与速度同时兼顾 Native 应用程序的性能与体验。

    7 引用 • 9 回帖 • 402 关注
  • wolai

    我来 wolai:不仅仅是未来的云端笔记!

    2 引用 • 14 回帖 • 1 关注
  • 代码片段

    代码片段分为 CSS 与 JS 两种代码,添加在 [设置 - 外观 - 代码片段] 中,这些代码会在思源笔记加载时自动执行,用于改善笔记的样式或功能。

    用户在该标签下分享代码片段时需在帖子标题前添加 [css] [js] 用于区分代码片段类型。

    183 引用 • 1295 回帖
  • Sublime

    Sublime Text 是一款可以用来写代码、写文章的文本编辑器。支持代码高亮、自动完成,还支持通过插件进行扩展。

    10 引用 • 5 回帖 • 2 关注
  • AWS
    11 引用 • 28 回帖 • 8 关注
  • Node.js

    Node.js 是一个基于 Chrome JavaScript 运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js 使用事件驱动, 非阻塞 I/O 模型而得以轻量和高效。

    139 引用 • 269 回帖 • 1 关注