Skip to content

Commit

Permalink
revamp
Browse files Browse the repository at this point in the history
  • Loading branch information
Richard Xiong committed Nov 11, 2024
1 parent 582dfc2 commit dba5cc1
Show file tree
Hide file tree
Showing 9 changed files with 738 additions and 310 deletions.
53 changes: 37 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This is an unofficial sync plugin for Obsidian, specifically for Google Drive.

- **This is NOT the [official sync service](https://obsidian.md/sync) provided by Obsidian.**

## !!!Caution!!!
## Caution

**ALWAYS backup your vault before using this plugin.**

Expand All @@ -15,25 +15,44 @@ This is an unofficial sync plugin for Obsidian, specifically for Google Drive.
- Syncing both ways (from Obsidian to Google Drive and back)
- Cross-device support
- Obsidian iOS app support
- Local file prioritization

## New Devices

- If you've already been using this plugin and want to start using it on a new device, then follow these instructions:
1. Open Google Drive and download the entire Obsidian folder to your new device
2. Move the Obsidian folder to the location where you want your vault to be
3. Open Obsidian and set the vault location to the folder you just moved
4. Enable the Google Drive Sync plugin in Obsidian
- If you activate the plugin on a new device without downloading the Obsidian folder from Google Drive, the plugin will start downloading from Google Drive as per a typical sync, which could take an extremely long amount of time depending on the amount of notes in the Google Drive

## Notes

- Do NOT manually upload files into the generated Obsidian Google Drive folder or use some other method of Google Drive sync
- Do **NOT** manually upload files into the generated Obsidian Google Drive folder or use some other method of Google Drive sync
- Our plugin cannot see these files, and it will likely break functionality, potentially causing data loss
- Instead, use this plugin on any device you wish to sync the vault between
- Do NOT manually change files outside of the Obsidian app
- Do **NOT** manually change files outside of the Obsidian app
- Our plugin tracks file changes through the Obsidian API, and if you change files outside of the app, the plugin will not be able to track these changes
- INITIAL activation of this plugin on a vault will DELETE ALL LOCAL FILES IN THE VAULT and REPLACE them with the files on Google Drive
- If you wish to keep those files, move them to another vault and copy them back in after syncing
- If there is no Google Drive vault, the plugin will create one and delete the contents of the local vault
- This is ONLY on the first activation or when the client is behind Google Drive's files
- If you ever encounter the following situation or vise versa, SYNC after you delete/rename it and before you rename/create the file/folder with the exact same path (this error arises from our plugin seeing a file convert into a folder or vise versa) (this doesn't apply for file to file or folder to folder):
- You have a file that has NO file extension already synced (most files have a file extension so you usually don't have to worry about this)
- You delete it/rename it
- You rename/create a folder with the exact same path
- When activating this plugin on a new vault, make sure the vault is empty
- If you have files that you want to sync to Google Drive from before the plugin, move them to another vault, delete them from the current vault, activate the plugin, and copy them back in **THROUGH THE OBSIDIAN APP**
- We suggest only editing Obsidian notes on one device at a time to avoid conflicts and syncing before editing on another device
- Our plugin does have code to handle conflicts, but it might not be perfect or as the user expects, so try to avoid them
- Make sure to sync with an adequate internet connection
- Closing the app or losing connection while syncing could lead to data corruption
- The plugin does NOT have manual conflict resolution
- If you encounter a conflict, the plugin will automatically resolve it with local file prioritization
- This only accesses the Google Drive API to sync files and does not access any other data or store data outside of the user's device
- This only accesses [https://ogd.richardxiong.com](https://ogd.richardxiong.com) to convert refresh tokens into access tokens without a client secret

## Setup

Note: Instructions are also on this plugin's homepage with images at [https://obsidian.richardxiong.com](https://obsidian.richardxiong.com)
Note: Instructions are also on this plugin's homepage with images at [https://ogd.richardxiong.com](https://ogd.richardxiong.com)

1. Visit this plugin's homepage at [https://obsidian.richardxiong.com](https://obsidian.richardxiong.com)
1. Visit this plugin's homepage at [https://ogd.richardxiong.com](https://ogd.richardxiong.com)
2. Click `Sign In` at the top right and log in with your Google account
3. Copy the refresh token that appears after logging in
4. Enable the Google Drive Sync plugin in Obsidian
Expand All @@ -44,11 +63,13 @@ Note: Instructions are also on this plugin's homepage with images at [https://ob

- After setup, the plugin will automatically sync your vault with Google Drive whenever Obsidian is open
- This sync is from Google Drive TO Obsidian, not the other way around (pulling cloud files)
- The plugin prioritizes changes on Google Drive over changes on the local vault, wiping local changes if the Google Drive files are newer
- To sync local changes to Google Drive, click the sync button on the ribbon or run the `Sync to Google Drive` command from the command palette
- While you do not have to sync before you close Obsidian, we suggest doing so to ensure that Google Drive is up to date
- If a device syncs to Google Drive, other devices will delete their local changes the next time they open Obsidian
- Make sure to sync with an adequate internet connection
- Closing the app or losing connection while syncing could lead to data corruption
- The plugin prioritizes unsynced local changes except for local file deletions (cloud file creation/modification will overwrite local deletion)
- You can pull by running the `Pull from Google Drive` command
- To sync local changes to Google Drive, click the sync button on the ribbon or run the `Push to Google Drive` command from the command palette
- While you do not have to sync before you close Obsidian, we suggest doing so to ensure that Google Drive is up to date and no conflicts occur
- This will pull changes before pushing changes to Google Drive
- If you want to set your local vault state to the Google Drive state, run the `Set Local Vault to Google Drive` command
- If you mess with the vault's files outside of the Obsidian interface, try to revert any of the changes you made
- If you can't, disable the plugin, reclone the vault from Google Drive, and reenable the plugin

Privacy Policy: [https://obsidian.richardxiong.com/privacy](https://obsidian.richardxiong.com/privacy)
Privacy Policy: [https://ogd.richardxiong.com/privacy](https://ogd.richardxiong.com/privacy)
80 changes: 53 additions & 27 deletions helpers/drive.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { KyInstance } from "ky";
import ObsidianGoogleDrive from "main";
import { getDriveKy } from "./ky";
import { KyInstance } from "ky";
import * as path from "path";

export interface FileMetadata {
id: string;
Expand Down Expand Up @@ -93,6 +92,8 @@ export const getDriveClient = (t: ObsidianGoogleDrive) => {
getFile: getFile(drive),
idFromPath: idFromPath(drive),
idsFromPaths: idsFromPaths(drive),
getChangesStartToken: getChangesStartToken(drive),
getChanges: getChanges(drive),
batchDelete: batchDelete(drive),
};
};
Expand Down Expand Up @@ -203,11 +204,13 @@ const createFolder =
parent,
description,
properties,
modifiedTime,
}: {
name: string;
description?: string;
parent?: string;
properties?: Record<string, string>;
modifiedTime?: string;
}) => {
if (!parent) {
parent = await getRootFolderId(drive)();
Expand All @@ -221,6 +224,7 @@ const createFolder =
description,
parents: [parent],
properties,
modifiedTime,
},
})
.json<any>();
Expand Down Expand Up @@ -365,33 +369,55 @@ const batchDelete = (drive: KyInstance) => async (ids: string[]) => {
return result;
};

/*
let body = ``;
ids.forEach((id, i) => {
body += `
--batch_boundary_foobarbiz
Content-Type: application/http
Content-ID: ${i}
const getChangesStartToken = (drive: KyInstance) => async () => {
const result = await drive
.get(`drive/v3/changes/startPageToken`)
.json<any>();
if (!result) return;
return result.startPageToken as string;
};

DELETE https://www.googleapis.com/drive/v3/files/${id}
const getChanges = (drive: KyInstance) => async (startToken: string) => {
if (!startToken) return [];

const request = (token: string) =>
drive
.get(
`drive/v3/changes?${new URLSearchParams({
pageToken: token,
pageSize: "1000",
includeRemoved: "true",
}).toString()}`
)
.json<any>();

`;
});
const result = await request(startToken);
if (!result) return;
while (result.nextPageToken) {
const nextPage = await request(result.nextPageToken);
if (!nextPage) return;
result.changes.push(...nextPage.changes);
result.newStartPageToken = nextPage.newStartPageToken;
result.nextPageToken = nextPage.nextPageToken;
}

body += "--batch_boundary_foobarbiz--";
return result as {
kind: string;
removed: boolean;
file: FileMetadata;
fileId: string;
time: string;
}[];
};

const result = await drive
.post(`batch/drive/v3`, {
headers: {
"Content-Type":
"multipart/mixed; boundary=batch_boundary_foobarbiz",
},
body,
})
.json<any>();
if (!result) return;
return result;
*/
export const batchAsyncs = async (
requests: (() => Promise<any>)[],
batchSize = 10
) => {
const results = [];
for (let i = 0; i < requests.length; i += batchSize) {
const batch = requests.slice(i, i + batchSize);
results.push(...(await Promise.all(batch.map((request) => request()))));
}
return results;
};
4 changes: 3 additions & 1 deletion helpers/ky.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const getDriveKy = (t: ObsidianGoogleDrive) => {
export const refreshAccessToken = async (t: ObsidianGoogleDrive) => {
try {
const { expires_in, access_token } = await ky
.post("https://obsidian.richardxiong.com/api/access", {
.post("https://ogd.richardxiong.com/api/access", {
json: { refresh_token: t.settings.refreshToken },
})
.json<any>();
Expand All @@ -47,6 +47,7 @@ export const refreshAccessToken = async (t: ObsidianGoogleDrive) => {
token: access_token,
expiresAt: Date.now() + expires_in * 1000,
};
return t.accessToken;
} catch (e: any) {
t.settings.refreshToken = "";
t.accessToken = {
Expand All @@ -58,5 +59,6 @@ export const refreshAccessToken = async (t: ObsidianGoogleDrive) => {
"Something is wrong with your refresh token, please reset it."
);
await t.saveSettings();
return;
}
};
Loading

0 comments on commit dba5cc1

Please sign in to comment.