update at 2025-10-08 09:18:20

This commit is contained in:
douboer
2025-10-08 09:18:20 +08:00
parent a49e389fe2
commit 584d4151fc
67 changed files with 5363 additions and 892 deletions

View File

@@ -1,28 +1,17 @@
/*
* Copyright (c) 2024-2025 Sun Booshi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
/**
* 文件batch-publish-modal.ts
* 功能:批量发布模态窗口;支持文件夹 / 多文件选择 + 多平台勾选。
* - 文件列表与过滤
* - 平台选择(公众号 / 小红书)
* - 批量触发发布逻辑
*/
import { App, Modal, Setting, TFile, Notice, ButtonComponent } from 'obsidian';
import { BatchArticleFilter, BatchFilterConfig } from './batch-filter';
import NoteToMpPlugin from './main';
// 小红书功能模块
import { XiaohongshuContentAdapter } from './xiaohongshu/adapter';
import { XiaohongshuAPIManager } from './xiaohongshu/api';
/**
* BatchPublishModal
@@ -55,6 +44,11 @@ export class BatchPublishModal extends Modal {
private resultsContainer: HTMLElement;
private publishButton: ButtonComponent;
// 平台选择相关(新增)
private wechatCheckbox: HTMLInputElement;
private xiaohongshuCheckbox: HTMLInputElement;
private allPlatformsCheckbox: HTMLInputElement;
// 鼠标框选相关
private isSelecting = false;
private selectionStart: { x: number; y: number } | null = null;
@@ -114,6 +108,61 @@ export class BatchPublishModal extends Modal {
buttonContainer.style.borderTop = '1px solid var(--background-modifier-border)';
buttonContainer.style.flexShrink = '0';
// 发布平台选择(新增)
const platformContainer = buttonContainer.createDiv('platform-select-container');
platformContainer.style.marginBottom = '15px';
platformContainer.style.display = 'flex';
platformContainer.style.alignItems = 'center';
platformContainer.style.justifyContent = 'center';
platformContainer.style.gap = '10px';
const platformLabel = platformContainer.createSpan();
platformLabel.innerText = '发布到: ';
const wechatCheckbox = platformContainer.createEl('input', { type: 'checkbox' });
wechatCheckbox.id = 'publish-wechat';
wechatCheckbox.checked = true;
this.wechatCheckbox = wechatCheckbox;
const wechatLabel = platformContainer.createEl('label');
wechatLabel.setAttribute('for', 'publish-wechat');
wechatLabel.innerText = '微信公众号';
wechatLabel.style.marginRight = '15px';
const xiaohongshuCheckbox = platformContainer.createEl('input', { type: 'checkbox' });
xiaohongshuCheckbox.id = 'publish-xiaohongshu';
this.xiaohongshuCheckbox = xiaohongshuCheckbox;
const xiaohongshuLabel = platformContainer.createEl('label');
xiaohongshuLabel.setAttribute('for', 'publish-xiaohongshu');
xiaohongshuLabel.innerText = '小红书';
xiaohongshuLabel.style.marginRight = '15px';
const allPlatformsCheckbox = platformContainer.createEl('input', { type: 'checkbox' });
allPlatformsCheckbox.id = 'publish-all';
this.allPlatformsCheckbox = allPlatformsCheckbox;
const allPlatformsLabel = platformContainer.createEl('label');
allPlatformsLabel.setAttribute('for', 'publish-all');
allPlatformsLabel.innerText = '全部平台';
// 全部平台checkbox的联动逻辑
allPlatformsCheckbox.addEventListener('change', () => {
if (allPlatformsCheckbox.checked) {
wechatCheckbox.checked = true;
xiaohongshuCheckbox.checked = true;
}
});
// 单个平台checkbox的联动逻辑
const updateAllPlatforms = () => {
if (wechatCheckbox.checked && xiaohongshuCheckbox.checked) {
allPlatformsCheckbox.checked = true;
} else {
allPlatformsCheckbox.checked = false;
}
};
wechatCheckbox.addEventListener('change', updateAllPlatforms);
xiaohongshuCheckbox.addEventListener('change', updateAllPlatforms);
new ButtonComponent(buttonContainer)
.setButtonText('应用筛选')
.setCta()
@@ -406,56 +455,135 @@ export class BatchPublishModal extends Modal {
return;
}
// 获取选择的发布平台
const platforms = this.getSelectedPlatforms();
if (platforms.length === 0) {
new Notice('请选择至少一个发布平台');
return;
}
const files = Array.from(this.selectedFiles);
const total = files.length;
const totalTasks = files.length * platforms.length;
let completed = 0;
let failed = 0;
// 显示进度
const notice = new Notice(`开始批量发布 ${total} 篇文章...`, 0);
const notice = new Notice(`开始批量发布 ${files.length} 篇文章到 ${platforms.join('、')}...`, 0);
try {
for (let i = 0; i < files.length; i++) {
const file = files[i];
try {
// 更新进度
notice.setMessage(`正在发布: ${file.basename} (${i + 1}/${total})`);
// 激活预览视图并发布
await this.plugin.activateView();
const preview = this.plugin.getNotePreview();
if (preview) {
await preview.renderMarkdown(file);
await preview.postArticle();
for (const platform of platforms) {
try {
// 更新进度
const taskIndex = i * platforms.length + platforms.indexOf(platform) + 1;
notice.setMessage(`正在发布: ${file.basename}${platform} (${taskIndex}/${totalTasks})`);
if (platform === '微信公众号') {
await this.publishToWechat(file);
} else if (platform === '小红书') {
await this.publishToXiaohongshu(file);
}
completed++;
} else {
throw new Error('无法获取预览视图');
} catch (error) {
console.error(`发布文章 ${file.basename}${platform} 失败:`, error);
failed++;
}
// 避免请求过于频繁
if (i < files.length - 1) {
const taskIndex = i * platforms.length + platforms.indexOf(platform) + 1;
if (taskIndex < totalTasks) {
await new Promise(resolve => setTimeout(resolve, 2000));
}
} catch (error) {
console.error(`发布文章 ${file.basename} 失败:`, error);
failed++;
}
}
// 显示最终结果
notice.hide();
new Notice(`批量发布完成!成功: ${completed} ,失败: ${failed} `);
new Notice(`批量发布完成!成功: ${completed} 个任务,失败: ${failed} 个任务`);
if (completed > 0) {
this.close();
}
} catch (error) {
notice.hide();
new Notice('批量发布过程中出错: ' + error.message);
console.error(error);
new Notice('批量发布过程中发生错误: ' + error.message);
console.error('批量发布错误:', error);
}
}
/**
* 获取选择的发布平台
*/
private getSelectedPlatforms(): string[] {
const platforms: string[] = [];
if (this.wechatCheckbox.checked) {
platforms.push('微信公众号');
}
if (this.xiaohongshuCheckbox.checked) {
platforms.push('小红书');
}
return platforms;
}
/**
* 发布到微信公众号
*/
private async publishToWechat(file: TFile): Promise<void> {
// 激活预览视图并发布
await this.plugin.activateView();
const preview = this.plugin.getNotePreview();
if (preview) {
// 确保预览器处于微信模式
preview.currentPlatform = 'wechat';
await preview.renderMarkdown(file);
await preview.postToWechat();
} else {
throw new Error('无法获取预览视图');
}
}
/**
* 发布到小红书
*/
private async publishToXiaohongshu(file: TFile): Promise<void> {
try {
// 读取文件内容
const fileContent = await this.app.vault.read(file);
// 使用小红书适配器转换内容
const adapter = new XiaohongshuContentAdapter();
const xiaohongshuPost = adapter.adaptMarkdownToXiaohongshu(fileContent, {
addStyle: true,
generateTitle: true
});
// 验证内容
const validation = adapter.validatePost(xiaohongshuPost);
if (!validation.valid) {
throw new Error('内容验证失败: ' + validation.errors.join('; '));
}
// 获取小红书API实例
const api = XiaohongshuAPIManager.getInstance(false);
// 检查登录状态
const isLoggedIn = await api.checkLoginStatus();
if (!isLoggedIn) {
throw new Error('小红书未登录,请在预览界面登录后再试');
}
// 发布内容
const result = await api.createPost(xiaohongshuPost);
if (!result.success) {
throw new Error(result.message);
}
} catch (error) {
throw new Error(`发布到小红书失败: ${error.message}`);
}
}