Skip to content

Commit 57155c1

Browse files
committed
feat(video): add scheduled publishing feature and enhance video data structure
1 parent 09d30da commit 57155c1

File tree

6 files changed

+264
-100
lines changed

6 files changed

+264
-100
lines changed

src/sync/common.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ export interface VideoData {
5757
video: FileData;
5858
tags?: string[];
5959
cover?: FileData;
60+
verticalCover?: FileData;
61+
scheduledPublishTime?: number;
6062
}
6163

6264
export interface PlatformInfo {

src/sync/video/douyin.ts

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
import type { FileData, SyncData, VideoData } from '../common';
22

33
export async function VideoDouyin(data: SyncData) {
4+
/**
5+
* Format date to yyyy-MM-dd HH:mm format
6+
* @param date - Date object to format
7+
* @returns Formatted date string
8+
*/
9+
function formatDate(date: Date): string {
10+
const year = date.getFullYear();
11+
const month = String(date.getMonth() + 1).padStart(2, '0');
12+
const day = String(date.getDate()).padStart(2, '0');
13+
const hours = String(date.getHours()).padStart(2, '0');
14+
const minutes = String(date.getMinutes()).padStart(2, '0');
15+
return `${year}-${month}-${day} ${hours}:${minutes}`;
16+
}
17+
418
function waitForElement(selector: string, timeout = 10000): Promise<Element> {
519
return new Promise((resolve, reject) => {
620
const element = document.querySelector(selector);
@@ -97,7 +111,7 @@ export async function VideoDouyin(data: SyncData) {
97111
}
98112

99113
try {
100-
const { content, video, title, tags, cover } = data.data as VideoData;
114+
const { content, video, title, tags, cover, scheduledPublishTime } = data.data as VideoData;
101115
// 处理视频上传
102116
if (video) {
103117
const response = await fetch(video.url);
@@ -174,19 +188,37 @@ export async function VideoDouyin(data: SyncData) {
174188
await uploadCover(cover);
175189
}
176190

177-
await new Promise((resolve) => setTimeout(resolve, 5000));
178-
179-
// 处理自动发布
180-
const buttons = document.querySelectorAll('button');
181-
const publishButton = Array.from(buttons).find((button) => button.textContent === '发布');
191+
// 处理定时发布
192+
if (scheduledPublishTime) {
193+
await new Promise((resolve) => setTimeout(resolve, 2000));
194+
const labels = document.querySelectorAll('label');
195+
console.log('labels -->', labels);
196+
const scheduledLabel = Array.from(labels).find((label) => label.textContent?.includes('定时发布'));
197+
console.log('scheduledLabel -->', scheduledLabel);
198+
if (scheduledLabel) {
199+
(scheduledLabel as HTMLElement).click();
200+
await new Promise((resolve) => setTimeout(resolve, 500));
201+
202+
const publishTimeInput = document.querySelector('input[format="yyyy-MM-dd HH:mm"]') as HTMLInputElement;
203+
console.log('publishTimeInput -->', publishTimeInput);
204+
if (publishTimeInput) {
205+
publishTimeInput.value = formatDate(new Date(scheduledPublishTime));
206+
publishTimeInput.dispatchEvent(new Event('input', { bubbles: true }));
207+
publishTimeInput.dispatchEvent(new Event('change', { bubbles: true }));
208+
console.log('定时发布时间已设置:', publishTimeInput.value);
209+
}
210+
}
211+
await new Promise((resolve) => setTimeout(resolve, 3000));
212+
// 处理自动发布
213+
const buttons = document.querySelectorAll('button');
214+
const publishButton = Array.from(buttons).find((button) => button.textContent === '发布');
182215

183-
if (publishButton) {
184-
if (data.isAutoPublish) {
216+
if (publishButton) {
185217
console.log('点击发布按钮');
186218
publishButton.click();
219+
} else {
220+
console.log('未找到"发布"按钮');
187221
}
188-
} else {
189-
console.log('未找到"发布"按钮');
190222
}
191223
} catch (error) {
192224
console.error('DouyinVideo 发布过程中出错:', error);

src/sync/video/kuaishou.ts

Lines changed: 47 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import type { SyncData, VideoData } from '../common';
22

33
export async function VideoKuaishou(data: SyncData) {
4-
const { content, video, title, tags = [], cover } = data.data as VideoData;
5-
6-
// function formatDate(date: Date): string {
7-
// const year = date.getFullYear();
8-
// const month = String(date.getMonth() + 1).padStart(2, '0');
9-
// const day = String(date.getDate()).padStart(2, '0');
10-
// const hours = String(date.getHours()).padStart(2, '0');
11-
// const minutes = String(date.getMinutes()).padStart(2, '0');
12-
// const seconds = String(date.getSeconds()).padStart(2, '0');
13-
// return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
14-
// }
4+
const { content, video, title, tags = [], cover, scheduledPublishTime } = data.data as VideoData;
5+
6+
function formatDate(date: Date): string {
7+
const year = date.getFullYear();
8+
const month = String(date.getMonth() + 1).padStart(2, '0');
9+
const day = String(date.getDate()).padStart(2, '0');
10+
const hours = String(date.getHours()).padStart(2, '0');
11+
const minutes = String(date.getMinutes()).padStart(2, '0');
12+
const seconds = String(date.getSeconds()).padStart(2, '0');
13+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
14+
}
1515

1616
// 辅助函数:等待元素出现
1717
function waitForElement(selector: string, timeout = 10000): Promise<Element> {
@@ -209,48 +209,44 @@ export async function VideoKuaishou(data: SyncData) {
209209
}
210210

211211
// 定时发布功能
212-
// if (videoData.publishTime) {
213-
// const labels = document.querySelectorAll('label');
214-
// const scheduledPublishLabel = Array.from(labels).find((el) => el.textContent?.includes('定时发布'));
215-
216-
// if (scheduledPublishLabel) {
217-
// scheduledPublishLabel.click();
218-
// await new Promise((resolve) => setTimeout(resolve, 500));
219-
220-
// const publishTimeInput = document.querySelector('input[placeholder="选择日期时间"]') as HTMLInputElement;
221-
// if (publishTimeInput) {
222-
// const publishDate =
223-
// typeof videoData.publishTime === 'string' ? new Date(videoData.publishTime) : videoData.publishTime;
224-
// publishTimeInput.value = formatDate(publishDate);
225-
// publishTimeInput.dispatchEvent(new Event('input', { bubbles: true }));
226-
// publishTimeInput.dispatchEvent(new Event('change', { bubbles: true }));
227-
// await new Promise((resolve) => setTimeout(resolve, 2000));
228-
229-
// const confirmLis = document.querySelectorAll('li.ant-picker-ok');
230-
// const confirmLi = Array.from(confirmLis).find((el) => el.textContent === '确定');
231-
// if (confirmLi) {
232-
// const confirmButton = confirmLi.querySelector('button');
233-
// if (confirmButton) {
234-
// confirmButton.click();
235-
// }
236-
// }
237-
// }
238-
// }
239-
// }
240-
241-
// 等待内容更新
242-
await new Promise((resolve) => setTimeout(resolve, 5000));
243-
244-
// 发布按钮逻辑
245-
const divElements = document.querySelectorAll('div');
246-
const publishButton = Array.from(divElements).find((el) => el.textContent === '发布') as HTMLElement;
247-
248-
if (publishButton) {
249-
if (data.isAutoPublish) {
212+
if (scheduledPublishTime && scheduledPublishTime > 0) {
213+
const labels = document.querySelectorAll('label');
214+
const scheduledPublishLabel = Array.from(labels).find((el) => el.textContent?.includes('定时发布'));
215+
216+
if (scheduledPublishLabel) {
217+
scheduledPublishLabel.click();
218+
await new Promise((resolve) => setTimeout(resolve, 500));
219+
220+
const publishTimeInput = document.querySelector('input[placeholder="选择日期时间"]') as HTMLInputElement;
221+
if (publishTimeInput) {
222+
const publishDate = new Date(scheduledPublishTime);
223+
publishTimeInput.value = formatDate(publishDate);
224+
publishTimeInput.dispatchEvent(new Event('input', { bubbles: true }));
225+
publishTimeInput.dispatchEvent(new Event('change', { bubbles: true }));
226+
await new Promise((resolve) => setTimeout(resolve, 2000));
227+
228+
const confirmLis = document.querySelectorAll('li.ant-picker-ok');
229+
const confirmLi = Array.from(confirmLis).find((el) => el.textContent === '确定');
230+
if (confirmLi) {
231+
const confirmButton = confirmLi.querySelector('button');
232+
if (confirmButton) {
233+
confirmButton.click();
234+
}
235+
}
236+
}
237+
}
238+
// 等待内容更新
239+
await new Promise((resolve) => setTimeout(resolve, 5000));
240+
241+
// 发布按钮逻辑
242+
const divElements = document.querySelectorAll('div');
243+
const publishButton = Array.from(divElements).find((el) => el.textContent === '发布') as HTMLElement;
244+
245+
if (publishButton) {
250246
console.log('找到发布按钮,准备点击');
251247
publishButton.click();
248+
} else {
249+
console.error('未找到"发布"按钮');
252250
}
253-
} else {
254-
console.error('未找到"发布"按钮');
255251
}
256252
}

src/sync/video/rednote.ts

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { SyncData, VideoData } from '../common';
22

33
export async function VideoRednote(data: SyncData) {
4-
const { content, video, title, tags, cover } = data.data as VideoData;
4+
const { content, video, title, tags, cover, scheduledPublishTime } = data.data as VideoData;
55

66
// 辅助函数:等待元素出现
77
function waitForElement(selector: string, timeout = 10000): Promise<Element> {
@@ -67,6 +67,42 @@ export async function VideoRednote(data: SyncData) {
6767
}
6868
}
6969

70+
/**
71+
* 设置定时发布时间
72+
* @param scheduledPublishTime - 定时发布时间戳(毫秒)
73+
*/
74+
async function setScheduledPublishTime(scheduledPublishTime: number): Promise<void> {
75+
const labels = document.querySelectorAll('label');
76+
console.debug('labels -->', labels);
77+
78+
const scheduledLabel = Array.from(labels).find((label) => label.textContent?.includes('定时发布'));
79+
console.debug('label -->', scheduledLabel);
80+
81+
if (scheduledLabel) {
82+
(scheduledLabel as HTMLElement).click();
83+
await new Promise((resolve) => setTimeout(resolve, 500));
84+
}
85+
86+
const publishTimeInput = document.querySelector('input[placeholder="选择日期和时间"]') as HTMLInputElement;
87+
console.debug('publishTimeInput -->', publishTimeInput);
88+
89+
if (publishTimeInput) {
90+
// 计算时间:添加 8 小时(28800000 毫秒)以调整时区
91+
const adjustedTime = new Date(scheduledPublishTime + 28800000);
92+
const formattedTime = adjustedTime.toISOString().slice(0, 16).replace('T', ' ');
93+
94+
publishTimeInput.focus();
95+
await new Promise((resolve) => setTimeout(resolve, 100));
96+
97+
publishTimeInput.value = formattedTime;
98+
publishTimeInput.dispatchEvent(new Event('input', { bubbles: true }));
99+
publishTimeInput.dispatchEvent(new Event('change', { bubbles: true }));
100+
publishTimeInput.blur();
101+
102+
console.debug('定时发布时间已设置:', formattedTime);
103+
}
104+
}
105+
70106
// 辅助函数:上传封面
71107
async function uploadCover(coverFile: NonNullable<VideoData['cover']>) {
72108
console.debug('tryCover', coverFile);
@@ -200,23 +236,25 @@ export async function VideoRednote(data: SyncData) {
200236
await uploadCover(cover);
201237
}
202238

203-
// 处理发布按钮
204-
const buttons = document.querySelectorAll('button');
205-
const publishButton = Array.from(buttons).find((button) => button.textContent?.includes('发布'));
239+
// 处理定时发布
240+
if (scheduledPublishTime) {
241+
await new Promise((resolve) => setTimeout(resolve, 2000));
242+
await setScheduledPublishTime(scheduledPublishTime);
243+
// 处理发布按钮
244+
const buttons = document.querySelectorAll('button');
245+
const publishButton = Array.from(buttons).find((button) => button.textContent?.includes('发布'));
206246

207-
if (publishButton) {
208-
// 等待按钮可用
209-
while (publishButton.getAttribute('aria-disabled') === 'true') {
210-
await new Promise((resolve) => setTimeout(resolve, 1000));
211-
}
212-
213-
// 如果需要自动发布
214-
if (data.isAutoPublish) {
215-
publishButton.dispatchEvent(new Event('click', { bubbles: true }));
216-
await new Promise((resolve) => setTimeout(resolve, 10000));
217-
window.location.href = 'https://creator.xiaohongshu.com/new/note-manager';
247+
if (publishButton) {
248+
// 等待按钮可用
249+
while (publishButton.getAttribute('aria-disabled') === 'true') {
250+
await new Promise((resolve) => setTimeout(resolve, 1000));
251+
}
252+
253+
if (publishButton) {
254+
publishButton.dispatchEvent(new Event('click', { bubbles: true }));
255+
await new Promise((resolve) => setTimeout(resolve, 10000));
256+
window.location.href = 'https://creator.xiaohongshu.com/new/note-manager';
257+
}
218258
}
219-
} else {
220-
console.error('未找到"发布"按钮');
221259
}
222260
}

0 commit comments

Comments
 (0)