mirror of
https://github.com/maclean-d/obsidian-limitless-lifelogs.git
synced 2026-07-22 12:20:25 +00:00
Compare commits
No commits in common. "main" and "1.0.1" have entirely different histories.
12 changed files with 48 additions and 2480 deletions
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
|
@ -32,4 +32,4 @@ jobs:
|
|||
gh release create "$tag" \
|
||||
--title="$tag" \
|
||||
--draft \
|
||||
main.js manifest.json
|
||||
main.js manifest.json styles.css
|
||||
2
LICENSE
2
LICENSE
|
|
@ -1,3 +1,5 @@
|
|||
Copyright (C) 2020-2025 by Dynalist Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
10
README.md
10
README.md
|
|
@ -78,16 +78,10 @@ If you encounter any issues:
|
|||
|
||||
## Star History
|
||||
|
||||
<a href="https://www.star-history.com/?repos=Maclean-D%2Fobsidian-limitless-lifelogs&type=date&legend=top-left">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=Maclean-D/obsidian-limitless-lifelogs&type=date&theme=dark&legend=top-left&sealed_token=n0qnDUpZGvp6y_j0NpoDcTvohZJ0tocsgfpskhjAPGqYY0mSleeunkuQ8dm8HcZi5aCR2D_OHiD8q1Bz4pnUHiXo48HcWKIHPHFUgls95HtHhPnjnuwr5lsOOBjrenFeB0jwJjXP3aNhafiFlspD5WjXA1VVf1XqIO6Yktr2CBHPrSLgqq0YJZqhctEe" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=Maclean-D/obsidian-limitless-lifelogs&type=date&legend=top-left&sealed_token=n0qnDUpZGvp6y_j0NpoDcTvohZJ0tocsgfpskhjAPGqYY0mSleeunkuQ8dm8HcZi5aCR2D_OHiD8q1Bz4pnUHiXo48HcWKIHPHFUgls95HtHhPnjnuwr5lsOOBjrenFeB0jwJjXP3aNhafiFlspD5WjXA1VVf1XqIO6Yktr2CBHPrSLgqq0YJZqhctEe" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=Maclean-D/obsidian-limitless-lifelogs&type=date&legend=top-left&sealed_token=n0qnDUpZGvp6y_j0NpoDcTvohZJ0tocsgfpskhjAPGqYY0mSleeunkuQ8dm8HcZi5aCR2D_OHiD8q1Bz4pnUHiXo48HcWKIHPHFUgls95HtHhPnjnuwr5lsOOBjrenFeB0jwJjXP3aNhafiFlspD5WjXA1VVf1XqIO6Yktr2CBHPrSLgqq0YJZqhctEe" />
|
||||
</picture>
|
||||
</a>
|
||||
[](https://star-history.com/#Maclean-D/obsidian-limitless-lifelogs&Date)
|
||||
|
||||
## Contributors
|
||||
|
||||
<a href="https://github.com/Maclean-D/obsidian-limitless-lifelogs/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=Maclean-D/obsidian-limitless-lifelogs" />
|
||||
</a>
|
||||
</a>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 52 KiB |
91
main.ts
91
main.ts
|
|
@ -33,7 +33,7 @@ export default class LimitlessLifelogsPlugin extends Plugin {
|
|||
// Add command for syncing
|
||||
this.addCommand({
|
||||
id: 'sync-limitless-lifelogs',
|
||||
name: 'Sync',
|
||||
name: 'Sync Limitless Lifelogs',
|
||||
callback: async () => {
|
||||
await this.syncLifelogs();
|
||||
}
|
||||
|
|
@ -96,8 +96,8 @@ export default class LimitlessLifelogsPlugin extends Plugin {
|
|||
}
|
||||
|
||||
private async ensureFolderExists(path: string) {
|
||||
const folder = this.app.vault.getFolderByPath(path);
|
||||
if (!folder) {
|
||||
const folderExists = await this.app.vault.adapter.exists(path);
|
||||
if (!folderExists) {
|
||||
await this.app.vault.createFolder(path);
|
||||
}
|
||||
}
|
||||
|
|
@ -105,15 +105,14 @@ export default class LimitlessLifelogsPlugin extends Plugin {
|
|||
private async getLastSyncedDate(): Promise<Date | null> {
|
||||
const folderPath = normalizePath(this.settings.folderPath);
|
||||
try {
|
||||
const files = this.app.vault.getFiles()
|
||||
.filter(file => file.path.startsWith(folderPath + '/'))
|
||||
.filter(file => file.path.endsWith('.md'))
|
||||
.map(file => file.basename)
|
||||
.filter(basename => /^\d{4}-\d{2}-\d{2}$/.test(basename))
|
||||
.map(basename => new Date(basename))
|
||||
const files = await this.app.vault.adapter.list(folderPath);
|
||||
const dates = files.files
|
||||
.map(file => file.split('/').pop()?.replace('.md', ''))
|
||||
.filter(date => date && /^\d{4}-\d{2}-\d{2}$/.test(date))
|
||||
.map(date => new Date(date as string))
|
||||
.sort((a, b) => b.getTime() - a.getTime());
|
||||
|
||||
return files.length > 0 ? files[0] : null;
|
||||
return dates.length > 0 ? dates[0] : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -121,9 +120,7 @@ export default class LimitlessLifelogsPlugin extends Plugin {
|
|||
|
||||
private formatLifelogMarkdown(lifelog: any): string {
|
||||
if (lifelog.markdown) {
|
||||
// Reformat Markdown
|
||||
const reformattedMarkdown = lifelog.markdown.replaceAll('\n\n', '\n');
|
||||
return reformattedMarkdown;
|
||||
return lifelog.markdown;
|
||||
}
|
||||
|
||||
const content: string[] = [];
|
||||
|
|
@ -195,7 +192,7 @@ class LimitlessLifelogsSettingTab extends PluginSettingTab {
|
|||
containerEl.empty();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('API key')
|
||||
.setName('API Key')
|
||||
.setDesc('Your Limitless AI API key')
|
||||
.addText(text => text
|
||||
.setPlaceholder('Enter your API key')
|
||||
|
|
@ -206,7 +203,7 @@ class LimitlessLifelogsSettingTab extends PluginSettingTab {
|
|||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Folder path')
|
||||
.setName('Folder Path')
|
||||
.setDesc('Where to store the lifelog entries')
|
||||
.addText(text => text
|
||||
.setPlaceholder('Folder path')
|
||||
|
|
@ -217,7 +214,7 @@ class LimitlessLifelogsSettingTab extends PluginSettingTab {
|
|||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Start date')
|
||||
.setName('Start Date')
|
||||
.setDesc('Default start date for initial sync (YYYY-MM-DD)')
|
||||
.addText(text => text
|
||||
.setPlaceholder('YYYY-MM-DD')
|
||||
|
|
@ -233,8 +230,6 @@ class LimitlessAPI {
|
|||
private apiKey: string;
|
||||
private baseUrl = 'https://api.limitless.ai';
|
||||
private batchSize = 10;
|
||||
private maxRetries = 5;
|
||||
private retryDelay = 1000; // 1 second
|
||||
|
||||
constructor(apiKey: string) {
|
||||
this.apiKey = apiKey;
|
||||
|
|
@ -263,7 +258,20 @@ class LimitlessAPI {
|
|||
}
|
||||
|
||||
try {
|
||||
const data = await this.makeRequest(`${this.baseUrl}/v1/lifelogs`, params);
|
||||
const response = await requestUrl({
|
||||
url: `${this.baseUrl}/v1/lifelogs?${params.toString()}`,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-API-Key': this.apiKey,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.json) {
|
||||
throw new Error('Invalid response format');
|
||||
}
|
||||
|
||||
const data = response.json;
|
||||
const lifelogs = data.data?.lifelogs || [];
|
||||
allLifelogs.push(...lifelogs);
|
||||
|
||||
|
|
@ -276,49 +284,4 @@ class LimitlessAPI {
|
|||
|
||||
return allLifelogs;
|
||||
}
|
||||
|
||||
private async makeRequest(url: string, params: URLSearchParams): Promise<any> {
|
||||
let retries = 0;
|
||||
while (true) {
|
||||
try {
|
||||
const response = await requestUrl({
|
||||
url: `${url}?${params.toString()}`,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-API-Key': this.apiKey,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.json) {
|
||||
throw new Error('Invalid response format');
|
||||
}
|
||||
|
||||
return response.json;
|
||||
} catch (error) {
|
||||
if (error.status === 429 && retries < this.maxRetries) {
|
||||
let delay = this.retryDelay * Math.pow(2, retries);
|
||||
const retryAfter = error.headers?.['retry-after'];
|
||||
|
||||
if (retryAfter) {
|
||||
const retryAfterSeconds = parseInt(retryAfter, 10);
|
||||
if (!isNaN(retryAfterSeconds)) {
|
||||
delay = retryAfterSeconds * 1000;
|
||||
} else {
|
||||
const retryAfterDate = new Date(retryAfter);
|
||||
const now = new Date();
|
||||
delay = retryAfterDate.getTime() - now.getTime();
|
||||
}
|
||||
}
|
||||
|
||||
new Notice(`Rate limit exceeded. Retrying in ${Math.round(delay / 1000)} seconds...`);
|
||||
await new Promise(resolve => setTimeout(resolve, delay));
|
||||
retries++;
|
||||
} else {
|
||||
console.error('Error making request:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"id": "limitless-lifelogs",
|
||||
"name": "Limitless Lifelogs",
|
||||
"version": "1.0.6",
|
||||
"version": "1.0.1",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "Sync your Limitless AI lifelog entries",
|
||||
"author": "Maclean Dunkin",
|
||||
"description": "Download and sync your Limitless AI lifelog entries into Obsidian markdown files.",
|
||||
"author": "Maclean Dunstan",
|
||||
"authorUrl": "https://github.com/Maclean-D",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2397
package-lock.json
generated
2397
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "obsidian-limitless-lifelogs",
|
||||
"version": "1.0.6",
|
||||
"version": "1.0.0",
|
||||
"description": "Download and sync your Limitless AI lifelog entries into Obsidian markdown files.",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
"version": "node version-bump.mjs && git add manifest.json versions.json"
|
||||
},
|
||||
"keywords": ["obsidian", "plugin", "limitless", "lifelogs"],
|
||||
"author": "Maclean Dunkin",
|
||||
"author": "Your Name",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.6",
|
||||
|
|
|
|||
8
styles.css
Normal file
8
styles.css
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
|
||||
This CSS file will be included with your plugin, and
|
||||
available in the app when your plugin is enabled.
|
||||
|
||||
If your plugin does not need CSS, delete this file.
|
||||
|
||||
*/
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
{
|
||||
"1.0.0": "0.15.0",
|
||||
"1.0.5": "0.15.0",
|
||||
"1.0.6": "0.15.0"
|
||||
}
|
||||
"1.0.0": "0.15.0"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue