mirror of
https://github.com/olcubo/obsidian-cubox.git
synced 2026-07-22 05:43:25 +00:00
278 lines
No EOL
8 KiB
TypeScript
278 lines
No EOL
8 KiB
TypeScript
import { Notice } from 'obsidian';
|
|
import { formatISODateTime } from './utils';
|
|
|
|
export interface CuboxArticle {
|
|
cardId: string;
|
|
id: string; // 兼容原有接口
|
|
title: string;
|
|
description: string;
|
|
url: string;
|
|
domain: string;
|
|
contentId: string;
|
|
coverKey: string;
|
|
isArchived: boolean;
|
|
hasStar: boolean;
|
|
createTime: string;
|
|
updateTime: string;
|
|
content?: string;
|
|
highlights?: CuboxHighlight[];
|
|
tags?: string[];
|
|
folder?: string;
|
|
type?: string;
|
|
}
|
|
|
|
export interface CuboxHighlight {
|
|
id: string;
|
|
text: string;
|
|
note?: string;
|
|
color?: string;
|
|
createDate: string;
|
|
}
|
|
|
|
export interface CuboxApiOptions {
|
|
domain: string;
|
|
apiKey: string;
|
|
}
|
|
|
|
export interface CuboxFolder {
|
|
id: string;
|
|
name: string;
|
|
nested_name: string;
|
|
uncategorized: boolean;
|
|
}
|
|
|
|
export interface CuboxTag {
|
|
id: string;
|
|
name: string;
|
|
nested_name: string;
|
|
parent_id: string | null;
|
|
}
|
|
|
|
interface ListResponse {
|
|
code: number;
|
|
message: string;
|
|
data: {
|
|
list: CuboxArticle[];
|
|
};
|
|
}
|
|
|
|
interface ContentResponse {
|
|
code: number;
|
|
message: string;
|
|
data: string;
|
|
}
|
|
|
|
interface FoldersResponse {
|
|
code: number;
|
|
message: string;
|
|
data: CuboxFolder[];
|
|
}
|
|
|
|
interface TagsResponse {
|
|
code: number;
|
|
message: string;
|
|
data: CuboxTag[];
|
|
}
|
|
|
|
export class CuboxApi {
|
|
private endpoint: string;
|
|
private apiKey: string;
|
|
|
|
constructor(options: CuboxApiOptions) {
|
|
this.endpoint = 'https://test.cubox.pro'//`https://${options.domain}`;
|
|
this.apiKey = options.apiKey;
|
|
}
|
|
|
|
/**
|
|
* 更新 API Key
|
|
*/
|
|
updateApiKey(apiKey: string): void {
|
|
this.apiKey = apiKey;
|
|
}
|
|
|
|
/**
|
|
* 同时更新域名和 API Key
|
|
*/
|
|
updateConfig(options: CuboxApiOptions): void {
|
|
this.endpoint = 'https://test.cubox.pro'// `https://${options.domain}`;
|
|
this.apiKey = options.apiKey;
|
|
}
|
|
|
|
/**
|
|
* 测试 API 连接是否有效
|
|
*/
|
|
async testConnection(): Promise<boolean> {
|
|
try {
|
|
// 尝试获取一篇文章来测试连接
|
|
const result = await this.getArticles({ lastCardId: null, pageSize: 1 });
|
|
new Notice('测试 Cubox 连接成功');
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Cubox API 连接测试失败:', error);
|
|
new Notice('Cubox API 连接失败,请检查域名和 API Key');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private async request(path: string, options: RequestInit = {}) {
|
|
const url = `${this.endpoint}${path}`;
|
|
const headers = {
|
|
'Authorization': `Bearer ${this.apiKey}`,
|
|
'Content-Type': 'application/json',
|
|
};
|
|
|
|
const response = await fetch(url, {
|
|
...options,
|
|
headers: {
|
|
...headers,
|
|
...options.headers,
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`API request failed: ${response.statusText}`);
|
|
}
|
|
|
|
return response.json();
|
|
}
|
|
|
|
/**
|
|
* 获取文章列表
|
|
* @param params 请求参数
|
|
*/
|
|
async getArticles(
|
|
params: {
|
|
lastCardId: string | null;
|
|
pageSize?: number;
|
|
folderFilter?: string[];
|
|
typeFilter?: string[];
|
|
statusFilter?: string[];
|
|
tagsFilter?: string[];
|
|
} = { lastCardId: null }
|
|
): Promise<{ articles: CuboxArticle[], hasMore: boolean, lastCardId: string | null }> {
|
|
try {
|
|
const searchParams = new URLSearchParams();
|
|
const pageSize = params.pageSize || 50;
|
|
|
|
if (params.lastCardId !== null && params.lastCardId.length > 0) {
|
|
searchParams.append('lastCardId', params.lastCardId);
|
|
}
|
|
searchParams.append('pageSize', pageSize.toString());
|
|
|
|
// 添加文件夹过滤
|
|
if (params.folderFilter && params.folderFilter.length > 0) {
|
|
params.folderFilter.forEach(folder => {
|
|
searchParams.append('folderId', folder);
|
|
});
|
|
}
|
|
|
|
// 添加类型过滤
|
|
if (params.typeFilter && params.typeFilter.length > 0) {
|
|
params.typeFilter.forEach(type => {
|
|
searchParams.append('type', type);
|
|
});
|
|
}
|
|
|
|
// 添加状态过滤
|
|
if (params.statusFilter && params.statusFilter.length > 0) {
|
|
// 如果包含 'all',则不添加状态过滤
|
|
if (!params.statusFilter.includes('all')) {
|
|
if (params.statusFilter.includes('read')) searchParams.append('isRead', 'true');
|
|
if (params.statusFilter.includes('starred')) searchParams.append('isStarred', 'true');
|
|
if (params.statusFilter.includes('archived')) searchParams.append('isArchived', 'true');
|
|
if (params.statusFilter.includes('annotated')) searchParams.append('isAnnotated', 'true');
|
|
}
|
|
}
|
|
|
|
// 添加标签过滤
|
|
if (params.tagsFilter && params.tagsFilter.length > 0) {
|
|
params.tagsFilter.forEach(tag => {
|
|
// 如果是空字符串,表示"No Tags"
|
|
searchParams.append('tagId', tag);
|
|
});
|
|
}
|
|
|
|
const path = `/c/api/third-party/card/list?${searchParams.toString()}`;
|
|
const response = await this.request(path) as ListResponse;
|
|
|
|
const articles = response.data.list;
|
|
const hasMore = articles.length >= pageSize;
|
|
const lastCardId = articles.length > 0 ? articles[articles.length - 1].cardId : null;
|
|
|
|
return {
|
|
articles,
|
|
hasMore,
|
|
lastCardId
|
|
};
|
|
} catch (error) {
|
|
console.error('获取文章列表失败:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取文章详情,包括内容
|
|
* @param articleId 文章ID
|
|
*/
|
|
async getArticleDetail(articleId: string): Promise<string | null> {
|
|
try {
|
|
const path = `/c/api/third-party/card/content?cardId=${articleId}`;
|
|
const response = await this.request(path) as ContentResponse;
|
|
|
|
// 直接返回文章内容
|
|
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 [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取用户的文件夹列表
|
|
*/
|
|
async getFolders(): Promise<CuboxFolder[]> {
|
|
try {
|
|
const path = '/c/api/third-party/group/list';
|
|
const response = await this.request(path) as FoldersResponse;
|
|
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error('获取 Cubox 文件夹列表失败:', error);
|
|
new Notice('获取 Cubox 文件夹列表失败');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取用户的标签列表
|
|
*/
|
|
async getTags(): Promise<CuboxTag[]> {
|
|
try {
|
|
const path = '/c/api/third-party/tag/list';
|
|
const response = await this.request(path) as TagsResponse;
|
|
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error('获取 Cubox 标签列表失败:', error);
|
|
new Notice('获取 Cubox 标签列表失败');
|
|
throw error;
|
|
}
|
|
}
|
|
} |