mirror of
https://github.com/olcubo/obsidian-cubox.git
synced 2026-07-22 05:43:25 +00:00
fix api link copy bug
This commit is contained in:
parent
0442c29e9c
commit
e04949e75c
4 changed files with 164 additions and 125 deletions
213
README.md
213
README.md
|
|
@ -1,94 +1,171 @@
|
|||
# Obsidian Sample Plugin
|
||||
# Obsidian Cubox Sync
|
||||
|
||||
This is a sample plugin for Obsidian (https://obsidian.md).
|
||||

|
||||
|
||||
This project uses TypeScript to provide type checking and documentation.
|
||||
The repo depends on the latest plugin API (obsidian.d.ts) in TypeScript Definition format, which contains TSDoc comments describing what it does.
|
||||
> 将 Cubox 中的文章和标注同步到 Obsidian,打造无缝知识管理流程。
|
||||
|
||||
This sample plugin demonstrates some of the basic functionality the plugin API can do.
|
||||
- Adds a ribbon icon, which shows a Notice when clicked.
|
||||
- Adds a command "Open Sample Modal" which opens a Modal.
|
||||
- Adds a plugin setting tab to the settings page.
|
||||
- Registers a global click event and output 'click' to the console.
|
||||
- Registers a global interval which logs 'setInterval' to the console.
|
||||
Obsidian Cubox Sync 是一个强大的 Obsidian 插件,它允许您将 Cubox 中收藏的文章、网页和标注内容自动同步到 Obsidian 笔记中。通过这个插件,您可以将 Cubox 作为信息收集工具,而 Obsidian 作为知识整理和思考工具,构建完整的个人知识管理系统。
|
||||
|
||||
## First time developing plugins?
|
||||
## ✨ 主要功能
|
||||
|
||||
Quick starting guide for new plugin devs:
|
||||
- **自动同步**:定时从 Cubox 同步文章和标注到 Obsidian
|
||||
- **灵活过滤**:支持按文件夹、内容类型、状态和标签过滤同步内容
|
||||
- **自定义模板**:使用 Mustache 模板语法自定义文件名、前置元数据和内容格式
|
||||
- **高亮标注**:将 Cubox 中的高亮内容同步到 Obsidian 笔记中
|
||||
- **增量同步**:智能识别新增和更新的内容,避免重复同步
|
||||
- **手动触发**:支持通过命令或按钮手动触发同步
|
||||
|
||||
- Check if [someone already developed a plugin for what you want](https://obsidian.md/plugins)! There might be an existing plugin similar enough that you can partner up with.
|
||||
- Make a copy of this repo as a template with the "Use this template" button (login to GitHub if you don't see it).
|
||||
- Clone your repo to a local development folder. For convenience, you can place this folder in your `.obsidian/plugins/your-plugin-name` folder.
|
||||
- Install NodeJS, then run `npm i` in the command line under your repo folder.
|
||||
- Run `npm run dev` to compile your plugin from `main.ts` to `main.js`.
|
||||
- Make changes to `main.ts` (or create new `.ts` files). Those changes should be automatically compiled into `main.js`.
|
||||
- Reload Obsidian to load the new version of your plugin.
|
||||
- Enable plugin in settings window.
|
||||
- For updates to the Obsidian API run `npm update` in the command line under your repo folder.
|
||||
## 🚀 安装方法
|
||||
|
||||
## Releasing new releases
|
||||
### 从 Obsidian 社区插件库安装
|
||||
|
||||
- Update your `manifest.json` with your new version number, such as `1.0.1`, and the minimum Obsidian version required for your latest release.
|
||||
- Update your `versions.json` file with `"new-plugin-version": "minimum-obsidian-version"` so older versions of Obsidian can download an older version of your plugin that's compatible.
|
||||
- Create new GitHub release using your new version number as the "Tag version". Use the exact version number, don't include a prefix `v`. See here for an example: https://github.com/obsidianmd/obsidian-sample-plugin/releases
|
||||
- Upload the files `manifest.json`, `main.js`, `styles.css` as binary attachments. Note: The manifest.json file must be in two places, first the root path of your repository and also in the release.
|
||||
- Publish the release.
|
||||
1. 打开 Obsidian 设置
|
||||
2. 进入 "第三方插件" 选项卡
|
||||
3. 关闭 "安全模式"
|
||||
4. 点击 "浏览" 按钮
|
||||
5. 搜索 "Cubox Sync"
|
||||
6. 点击安装
|
||||
|
||||
> You can simplify the version bump process by running `npm version patch`, `npm version minor` or `npm version major` after updating `minAppVersion` manually in `manifest.json`.
|
||||
> The command will bump version in `manifest.json` and `package.json`, and add the entry for the new version to `versions.json`
|
||||
### 手动安装
|
||||
|
||||
## Adding your plugin to the community plugin list
|
||||
1. 下载最新版本的 `main.js`、`manifest.json` 和 `styles.css` 文件
|
||||
2. 在您的 Obsidian 库中创建 `.obsidian/plugins/obsidian-cubox-sync` 文件夹
|
||||
3. 将下载的文件复制到该文件夹中
|
||||
4. 在 Obsidian 设置中启用插件
|
||||
|
||||
- Check the [plugin guidelines](https://docs.obsidian.md/Plugins/Releasing/Plugin+guidelines).
|
||||
- Publish an initial version.
|
||||
- Make sure you have a `README.md` file in the root of your repo.
|
||||
- Make a pull request at https://github.com/obsidianmd/obsidian-releases to add your plugin.
|
||||
## ⚙️ 配置说明
|
||||
|
||||
## How to use
|
||||
### 连接设置
|
||||
|
||||
- Clone this repo.
|
||||
- Make sure your NodeJS is at least v16 (`node --version`).
|
||||
- `npm i` or `yarn` to install dependencies.
|
||||
- `npm run dev` to start compilation in watch mode.
|
||||
1. **Cubox 服务器域名**:选择您使用的 Cubox 服务器域名(cubox.cc 或 cubox.pro)
|
||||
2. **Cubox API 密钥**:输入您的 Cubox API 密钥(可在 Cubox 网页版设置中创建)
|
||||
|
||||
## Manually installing the plugin
|
||||
### 过滤设置
|
||||
|
||||
- Copy over `main.js`, `styles.css`, `manifest.json` to your vault `VaultFolder/.obsidian/plugins/your-plugin-id/`.
|
||||
- **文件夹过滤**:选择要同步的 Cubox 文件夹
|
||||
- **类型过滤**:选择要同步的内容类型(文章、视频、图片等)
|
||||
- **状态过滤**:选择要同步的内容状态(已读、未读等)
|
||||
- **标签过滤**:选择要同步的标签
|
||||
|
||||
## Improve code quality with eslint (optional)
|
||||
- [ESLint](https://eslint.org/) is a tool that analyzes your code to quickly find problems. You can run ESLint against your plugin to find common bugs and ways to improve your code.
|
||||
- To use eslint with this project, make sure to install eslint from terminal:
|
||||
- `npm install -g eslint`
|
||||
- To use eslint to analyze this project use this command:
|
||||
- `eslint main.ts`
|
||||
- eslint will then create a report with suggestions for code improvement by file and line number.
|
||||
- If your source code is in a folder, such as `src`, you can use eslint with this command to analyze all files in that folder:
|
||||
- `eslint .\src\`
|
||||
### 同步设置
|
||||
|
||||
## Funding URL
|
||||
- **同步频率**:设置自动同步的时间间隔(分钟),设为 0 表示仅手动同步
|
||||
- **目标文件夹**:设置同步内容保存到 Obsidian 的哪个文件夹
|
||||
- **文件名模板**:设置生成的笔记文件名格式
|
||||
- **前置元数据**:设置笔记的前置元数据字段
|
||||
- **内容模板**:设置笔记内容的格式
|
||||
- **日期格式**:设置日期时间的显示格式
|
||||
|
||||
You can include funding URLs where people who use your plugin can financially support it.
|
||||
## 🔍 模板变量
|
||||
|
||||
The simple way is to set the `fundingUrl` field to your link in your `manifest.json` file:
|
||||
### 文件名模板变量
|
||||
|
||||
```json
|
||||
{
|
||||
"fundingUrl": "https://buymeacoffee.com"
|
||||
}
|
||||
- `{{title}}` - 文章标题
|
||||
- `{{article_title}}` - 原始文章标题
|
||||
- `{{create_time}}` - 创建时间
|
||||
- `{{update_time}}` - 更新时间
|
||||
- `{{domain}}` - 域名
|
||||
- `{{type}}` - 内容类型
|
||||
|
||||
### 前置元数据变量
|
||||
|
||||
- `title` - 文章标题
|
||||
- `article_title` - 原始文章标题
|
||||
- `tags` - 标签列表
|
||||
- `create_time` - 创建时间
|
||||
- `update_time` - 更新时间
|
||||
- `domain` - 域名
|
||||
- `url` - 原始链接
|
||||
- `cubox_url` - Cubox 链接
|
||||
- `description` - 描述
|
||||
- `words_count` - 字数统计
|
||||
- `type` - 内容类型
|
||||
- `id` - 文章 ID
|
||||
|
||||
### 内容模板变量
|
||||
|
||||
- `{{title}}` - 文章标题
|
||||
- `{{description}}` - 描述
|
||||
- `{{content}}` - 文章内容
|
||||
- `{{content_highlighted}}` - 带高亮的文章内容
|
||||
- `{{highlights.length}}` - 高亮数量
|
||||
- `{{#highlights}}` ... `{{/highlights}}` - 高亮内容循环
|
||||
- `{{text}}` - 高亮文本
|
||||
- `{{note}}` - 高亮笔记
|
||||
- `{{cubox_url}}` - 高亮链接
|
||||
- `{{color}}` - 高亮颜色
|
||||
- `{{create_time}}` - 高亮创建时间
|
||||
|
||||
## 📝 使用示例
|
||||
|
||||
### 基本内容模板示例
|
||||
|
||||
```
|
||||
# {{{title}}}
|
||||
|
||||
{{{description}}}
|
||||
|
||||
[Read in Cubox]({{{cubox_url}}})
|
||||
[Read Original]({{{url}}})
|
||||
|
||||
{{{content}}}
|
||||
|
||||
{{#highlights.length}}
|
||||
## Annotations
|
||||
|
||||
{{#highlights}}
|
||||
> {{{text}}}
|
||||
{{{note}}}
|
||||
[Link️]({{{cubox_url}}})
|
||||
|
||||
{{/highlights}}
|
||||
{{/highlights.length}}
|
||||
```
|
||||
|
||||
If you have multiple URLs, you can also do:
|
||||
### 前置元数据示例
|
||||
|
||||
```json
|
||||
{
|
||||
"fundingUrl": {
|
||||
"Buy Me a Coffee": "https://buymeacoffee.com",
|
||||
"GitHub Sponsor": "https://github.com/sponsors",
|
||||
"Patreon": "https://www.patreon.com/"
|
||||
}
|
||||
}
|
||||
```
|
||||
title,url,tags,create_time,domain
|
||||
```
|
||||
|
||||
## API Documentation
|
||||
或使用别名:
|
||||
|
||||
See https://github.com/obsidianmd/obsidian-api
|
||||
```
|
||||
title,url,tags,create_time::date,domain::source
|
||||
```
|
||||
|
||||
## 🔄 同步流程
|
||||
|
||||
1. 插件会根据设置的频率自动同步,或者您可以手动触发同步
|
||||
2. 同步时会根据过滤条件获取 Cubox 中的文章
|
||||
3. 对于每篇文章,插件会根据模板生成文件名、前置元数据和内容
|
||||
4. 生成的笔记会保存到指定的目标文件夹中
|
||||
5. 同步完成后,状态栏会显示最后同步时间
|
||||
|
||||
## 🛠️ 开发者信息
|
||||
|
||||
### 构建项目
|
||||
|
||||
1. 克隆仓库
|
||||
2. 安装依赖:`npm install`
|
||||
3. 开发模式:`npm run dev`
|
||||
4. 构建生产版本:`npm run build`
|
||||
|
||||
### 主要依赖
|
||||
|
||||
- Mustache:用于模板渲染
|
||||
- Luxon:用于日期时间处理
|
||||
|
||||
## 📄 许可证
|
||||
|
||||
本项目采用 MIT 许可证。详情请参阅 [LICENSE](LICENSE) 文件。
|
||||
|
||||
## 🙏 致谢
|
||||
|
||||
- [Obsidian](https://obsidian.md/) - 知识管理工具
|
||||
- [Cubox](https://cubox.pro/) - 网络内容收藏工具
|
||||
- 所有贡献者和用户
|
||||
|
||||
---
|
||||
|
||||
如有问题或建议,请在 GitHub 仓库中提交 Issue。
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export interface CuboxArticle {
|
|||
update_time: string;
|
||||
word_count: number;
|
||||
content?: string;
|
||||
cubox_url: string;
|
||||
cubox_url: string;
|
||||
highlights?: CuboxHighlight[];
|
||||
tags?: string[];
|
||||
type: string;
|
||||
|
|
@ -177,8 +177,8 @@ export class CuboxApi {
|
|||
body: JSON.stringify(requestBody)
|
||||
}) as ListResponse;
|
||||
|
||||
const articles = response.data;
|
||||
const hasMore = articles.length >= pageSize;
|
||||
const articles = response.data ?? [];
|
||||
const hasMore = articles && articles.length >= pageSize;
|
||||
|
||||
return {
|
||||
articles,
|
||||
|
|
@ -203,24 +203,8 @@ export class CuboxApi {
|
|||
return response.data;
|
||||
} catch (error) {
|
||||
console.error(`获取文章 ${articleId} 详情失败:`, error);
|
||||
new Notice(`获取文章详情失败`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章的高亮内容
|
||||
* @param articleId 文章ID
|
||||
*/
|
||||
async getHighlights(articleId: string): Promise<CuboxHighlight[]> {
|
||||
try {
|
||||
// 这里需要实现获取高亮的API调用
|
||||
// 暂时返回空数组
|
||||
return [];
|
||||
} catch (error) {
|
||||
console.error(`获取文章 ${articleId} 高亮内容失败:`, error);
|
||||
new Notice(`获取高亮内容失败`);
|
||||
return [];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -232,7 +216,7 @@ export class CuboxApi {
|
|||
const path = '/c/api/third-party/group/list';
|
||||
const response = await this.request(path) as FoldersResponse;
|
||||
|
||||
return response.data;
|
||||
return response.data ?? [];
|
||||
} catch (error) {
|
||||
console.error('获取 Cubox 文件夹列表失败:', error);
|
||||
new Notice('获取 Cubox 文件夹列表失败');
|
||||
|
|
@ -248,7 +232,7 @@ export class CuboxApi {
|
|||
const path = '/c/api/third-party/tag/list';
|
||||
const response = await this.request(path) as TagsResponse;
|
||||
|
||||
return response.data;
|
||||
return response.data ?? [];
|
||||
} catch (error) {
|
||||
console.error('获取 Cubox 标签列表失败:', error);
|
||||
new Notice('获取 Cubox 标签列表失败');
|
||||
|
|
|
|||
33
src/main.ts
33
src/main.ts
|
|
@ -51,7 +51,6 @@ interface CuboxSyncSettings {
|
|||
lastSyncCardId: string | null;
|
||||
lastCardUpdateTime: string | null;
|
||||
syncing: boolean;
|
||||
skipExistingFiles: boolean; // 是否跳过已存在的文件
|
||||
}
|
||||
|
||||
const DEFAULT_SETTINGS: CuboxSyncSettings = {
|
||||
|
|
@ -75,7 +74,6 @@ const DEFAULT_SETTINGS: CuboxSyncSettings = {
|
|||
lastSyncCardId: null,
|
||||
lastCardUpdateTime: null,
|
||||
syncing: false,
|
||||
skipExistingFiles: false
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -153,15 +151,17 @@ export default class CuboxSyncPlugin extends Plugin {
|
|||
|
||||
// 如果频率大于0,设置新的定时器
|
||||
if (this.settings.syncFrequency > 0) {
|
||||
const frequency = Math.min(this.settings.syncFrequency, 1440); // 最大24小时
|
||||
|
||||
this.syncIntervalId = window.setInterval(
|
||||
async () => await this.syncCubox(),
|
||||
this.settings.syncFrequency * 60 * 1000
|
||||
frequency * 60 * 1000
|
||||
);
|
||||
this.registerInterval(this.syncIntervalId);
|
||||
}
|
||||
}
|
||||
|
||||
async syncCubox(continueLastSync: boolean = true) {
|
||||
async syncCubox() {
|
||||
// 如果已经在同步中,则跳过
|
||||
if (this.settings.syncing) {
|
||||
new Notice('Sync is in progress, please wait.');
|
||||
|
|
@ -169,7 +169,7 @@ export default class CuboxSyncPlugin extends Plugin {
|
|||
}
|
||||
|
||||
try {
|
||||
// 设置同步状态为 true
|
||||
// 设置同步状态为进行中
|
||||
this.settings.syncing = true;
|
||||
await this.saveSettings();
|
||||
|
||||
|
|
@ -180,8 +180,8 @@ export default class CuboxSyncPlugin extends Plugin {
|
|||
await this.ensureTargetFolder();
|
||||
|
||||
// 如果选择继续上次同步,则使用保存的 lastSyncCardId
|
||||
let lastCardId: string | null = continueLastSync ? this.settings.lastSyncCardId : null;
|
||||
let lastCardUpdateTime: string | null = continueLastSync ? this.settings.lastCardUpdateTime : null;
|
||||
let lastCardId: string | null = this.settings.lastSyncCardId;
|
||||
let lastCardUpdateTime: string | null = this.settings.lastCardUpdateTime;
|
||||
let hasMore = true;
|
||||
let syncCount = 0;
|
||||
let errorCount = 0;
|
||||
|
|
@ -250,7 +250,7 @@ export default class CuboxSyncPlugin extends Plugin {
|
|||
const filePath = `${this.settings.targetFolder}/${filename}.md`;
|
||||
|
||||
// 检查文件是否已存在,如果设置了跳过已存在文件则跳过
|
||||
if (this.settings.skipExistingFiles && await this.app.vault.adapter.exists(filePath)) {
|
||||
if (await this.app.vault.adapter.exists(filePath)) {
|
||||
console.log(`文件已存在,跳过: ${filePath}`);
|
||||
skipCount++;
|
||||
continue;
|
||||
|
|
@ -282,9 +282,11 @@ export default class CuboxSyncPlugin extends Plugin {
|
|||
this.settings.syncing = false;
|
||||
await this.saveSettings();
|
||||
|
||||
// 更新状态栏
|
||||
this.statusBarItem.setText(`上次同步: ${this.formatLastSyncTime()}`);
|
||||
|
||||
const message = `Cubox sync completed: ${syncCount} articles synchronized${skipCount > 0 ? `, ${skipCount} skipped` : ''}${errorCount > 0 ? `, ${errorCount} errors` : ''}`;
|
||||
new Notice(message);
|
||||
this.statusBarItem.setText(`上次同步: ${this.formatLastSyncTime()} (成功)`);
|
||||
} catch (error) {
|
||||
console.error('同步 Cubox 数据失败:', error);
|
||||
new Notice('Cubox sync failed. Please check settings or network.');
|
||||
|
|
@ -402,7 +404,7 @@ class CuboxSyncSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
|
||||
// 更新 Cubox API 配置
|
||||
this.plugin.updateCuboxApiConfig(this.plugin.settings.domain, value);
|
||||
this.plugin.updateCuboxApiConfig(this.plugin.settings.domain, apiKey);
|
||||
});
|
||||
|
||||
// 如果未选择域名,则禁用输入框
|
||||
|
|
@ -574,17 +576,6 @@ class CuboxSyncSettingTab extends PluginSettingTab {
|
|||
// 同步设置部分
|
||||
containerEl.createEl('h3', {text: 'Sync'});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Skip Existing Files')
|
||||
.setDesc('If enabled, files that already exist in the target folder will be skipped during sync.')
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.skipExistingFiles)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.skipExistingFiles = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Sync Interval')
|
||||
.setDesc('Auto sync interval (in minutes). 0 means manual sync. Each item syncs only once. Subsequent updates won\'t be synced, and modifications in Obsidian won\'t affect Cubox. We recommend avoiding frequent updates.')
|
||||
|
|
|
|||
|
|
@ -177,20 +177,7 @@ export class TemplateProcessor {
|
|||
articleView.content_highlighted = this.generateHighlightedContent(article.content, article.highlights);
|
||||
}
|
||||
|
||||
// 3. 调试输出 (可以在生产环境中移除)
|
||||
console.log('ArticleView for template rendering:', JSON.stringify({
|
||||
title: articleView.title,
|
||||
highlights_length: articleView.highlights_length,
|
||||
highlights_count: articleView.highlights.length,
|
||||
has_highlighted_content: 'content_highlighted' in articleView,
|
||||
first_highlight: articleView.highlights.length > 0 ? {
|
||||
text: articleView.highlights[0].text,
|
||||
note: articleView.highlights[0].note,
|
||||
cubox_url: articleView.highlights[0].cubox_url
|
||||
} : null
|
||||
}, null, 2));
|
||||
|
||||
// 4. 使用 Mustache 渲染模板
|
||||
// 3. 使用 Mustache 渲染模板
|
||||
return Mustache.render(template, articleView);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue