11import type { DynamicData , SyncData } from '../common' ;
22
3- // 优先发布图文
3+ /**
4+ * 快手图文动态发布函数
5+ * @description 优先发布图文内容到快手平台
6+ * @param {SyncData } data - 同步数据,包含标题、内容、图片等信息
7+ */
48export async function DynamicKuaishou ( data : SyncData ) {
59 const { title, content, images } = data . data as DynamicData ;
10+
11+ // 检查图片数量
12+ if ( ! images || images . length === 0 ) {
13+ alert ( '发布图文,请至少提供一张图片' ) ;
14+ return ;
15+ }
16+
617 // 辅助函数:等待元素出现
718 function waitForElement ( selector : string , timeout = 10000 ) : Promise < Element > {
819 return new Promise ( ( resolve , reject ) => {
@@ -32,71 +43,8 @@ export async function DynamicKuaishou(data: SyncData) {
3243 } ) ;
3344 }
3445
35- // 辅助函数:通过文本内容查找元素
36- async function findElementByText (
37- selector : string ,
38- text : string ,
39- maxRetries = 5 ,
40- retryInterval = 1000 ,
41- ) : Promise < Element | null > {
42- for ( let i = 0 ; i < maxRetries ; i ++ ) {
43- const elements = document . querySelectorAll ( selector ) ;
44- const element = Array . from ( elements ) . find ( ( element ) => element . textContent ?. includes ( text ) ) ;
45-
46- if ( element ) {
47- return element ;
48- }
49-
50- console . log ( `未找到包含文本 "${ text } " 的元素,尝试次数:${ i + 1 } ` ) ;
51- await new Promise ( ( resolve ) => setTimeout ( resolve , retryInterval ) ) ;
52- }
53-
54- console . error ( `在 ${ maxRetries } 次尝试后未找到包含文本 "${ text } " 的元素` ) ;
55- return null ;
56- }
57-
58- // 辅助函数:上传文件
59- async function uploadImages ( ) {
60- const fileInput = ( await waitForElement (
61- 'input[type="file"][accept="image/png, image/jpg, image/jpeg, image/webp"]' ,
62- ) ) as HTMLInputElement ;
63- if ( ! fileInput ) {
64- console . error ( '未找到文件输入元素' ) ;
65- return ;
66- }
67-
68- const dataTransfer = new DataTransfer ( ) ;
69-
70- console . log ( '开始上传图片' ) ;
71- for ( const fileInfo of images ) {
72- console . log ( `准备上传图片: ${ fileInfo . url } ` ) ;
73- try {
74- const response = await fetch ( fileInfo . url ) ;
75- if ( ! response . ok ) {
76- throw new Error ( `HTTP 错误! 状态: ${ response . status } ` ) ;
77- }
78- const blob = await response . blob ( ) ;
79- const file = new File ( [ blob ] , fileInfo . name , { type : fileInfo . type } ) ;
80- dataTransfer . items . add ( file ) ;
81- } catch ( error ) {
82- console . error ( `上传图片 ${ fileInfo . url } 失败:` , error ) ;
83- }
84- }
85-
86- if ( dataTransfer . files . length > 0 ) {
87- const uploadButton = ( await findElementByText ( 'button' , '上传图片' ) ) as HTMLElement ;
88-
89- // 使用 simulateDragAndDrop 函数模拟拖拽事件
90- simulateDragAndDrop ( uploadButton . parentElement . parentElement , dataTransfer ) ;
91- console . log ( '文件上传操作完成' ) ;
92- } else {
93- console . error ( '没有成功添加任何文件' ) ;
94- }
95- }
96-
9746 // 模拟拖拽事件的函数
9847 function simulateDragAndDrop ( element : HTMLElement , dataTransfer : DataTransfer ) {
99- console . log ( 'simulateDragAndDrop' , dataTransfer ) ;
10048 const events = [
10149 new DragEvent ( 'dragenter' , { bubbles : true } ) ,
10250 new DragEvent ( 'dragover' , { bubbles : true } ) ,
@@ -106,50 +54,82 @@ export async function DynamicKuaishou(data: SyncData) {
10654 Object . defineProperty ( event , 'preventDefault' , { value : ( ) => { } } ) ;
10755 } ) ;
10856 events . forEach ( ( event ) => {
109- console . log ( 'event' , event ) ;
11057 element . dispatchEvent ( event ) ;
11158 } ) ;
11259 }
11360
114- if ( images && images . length > 0 ) {
115- console . log ( '检测到图片,开始上传' ) ;
61+ // 等待文件输入元素
62+ await waitForElement ( 'input[type="file"]' ) ;
63+ await new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) ) ;
11664
117- const imageTab = ( await waitForElement ( 'div#rc-tabs-0-tab-2' ) ) as HTMLElement ;
118- imageTab . click ( ) ;
119- await new Promise ( ( resolve ) => setTimeout ( resolve , 2000 ) ) ;
120- await uploadImages ( ) ;
65+ // 查找并点击上传图片的tab
66+ const uploadTab = document . querySelector ( 'div#rc-tabs-0-tab-2' ) as HTMLElement ;
67+ if ( ! uploadTab ) {
68+ console . error ( '未找到 uploadTab' ) ;
69+ return ;
70+ }
71+ uploadTab . click ( ) ;
72+ await new Promise ( ( resolve ) => setTimeout ( resolve , 2000 ) ) ;
73+
74+ // 创建 DataTransfer 对象并添加文件
75+ const dataTransfer = new DataTransfer ( ) ;
76+ for ( const fileInfo of images ) {
77+ console . log ( 'try upload file' , fileInfo ) ;
78+ try {
79+ const response = await fetch ( fileInfo . url ) ;
80+ if ( ! response . ok ) {
81+ throw new Error ( `HTTP 错误! 状态: ${ response . status } ` ) ;
82+ }
83+ const arrayBuffer = await response . arrayBuffer ( ) ;
84+ const file = new File ( [ arrayBuffer ] , fileInfo . name , { type : fileInfo . type } ) ;
85+ dataTransfer . items . add ( file ) ;
86+ } catch ( error ) {
87+ console . error ( `上传图片 ${ fileInfo . url } 失败:` , error ) ;
88+ }
89+ }
12190
122- await new Promise ( ( resolve ) => setTimeout ( resolve , 5000 ) ) ;
91+ // 查找上传图片按钮
92+ const buttons = document . querySelectorAll ( 'button' ) ;
93+ const uploadButton = Array . from ( buttons ) . find ( ( button ) => button . textContent === '上传图片' ) as HTMLElement ;
12394
124- // 处理作品描述
125- const contentEditor = ( await waitForElement ( 'div#work-description-edit[contenteditable="true"]' ) ) as HTMLDivElement ;
126- if ( contentEditor ) {
127- contentEditor . innerText = `${ title || '' } \n\n${ content } ` ;
128- contentEditor . dispatchEvent ( new Event ( 'input' , { bubbles : true } ) ) ;
129- }
95+ if ( ! uploadButton ) {
96+ console . error ( "未找到'上传图片'按钮" ) ;
97+ return ;
98+ }
13099
131- // 等待内容更新
132- await new Promise ( ( resolve ) => setTimeout ( resolve , 3000 ) ) ;
133-
134- if ( data . isAutoPublish ) {
135- console . log ( '开始自动发布' ) ;
136- const maxAttempts = 3 ;
137- for ( let attempt = 0 ; attempt < maxAttempts ; attempt ++ ) {
138- try {
139- const publishButton = ( await findElementByText ( 'div' , '发布' ) ) as HTMLElement ;
140- publishButton . click ( ) ;
141- console . log ( '发布按钮已点击' ) ;
142- await new Promise ( ( resolve ) => setTimeout ( resolve , 3000 ) ) ;
143- window . location . href = 'https://cp.kuaishou.com/article/manage/video' ;
144- break ; // 成功点击后退出循环
145- } catch ( error ) {
146- console . warn ( `第 ${ attempt + 1 } 次尝试查找发布按钮失败:` , error ) ;
147- if ( attempt === maxAttempts - 1 ) {
148- console . error ( '达到最大尝试次数,无法找到发布按钮' ) ;
149- }
150- await new Promise ( ( resolve ) => setTimeout ( resolve , 2000 ) ) ; // 等待2秒后重试
151- }
152- }
153- }
100+ // 执行拖拽上传
101+ const dropTarget = uploadButton . parentElement ?. parentElement as HTMLElement ;
102+ simulateDragAndDrop ( dropTarget , dataTransfer ) ;
103+ console . log ( '文件上传操作完成' ) ;
104+
105+ // 等待描述输入框出现
106+ await waitForElement ( 'div[placeholder="添加合适的话题和描述,作品能获得更多推荐~"][contenteditable="true"]' ) ;
107+
108+ // 查找描述输入框并粘贴内容
109+ const descriptionInput = document . querySelector (
110+ 'div[placeholder="添加合适的话题和描述,作品能获得更多推荐~"][contenteditable="true"]' ,
111+ ) as HTMLDivElement ;
112+
113+ if ( descriptionInput ) {
114+ descriptionInput . focus ( ) ;
115+
116+ // 拼接标题和内容,如果有标题则用 \n 分隔
117+ const textContent = title ? `${ title } \n${ content } ` : content ;
118+
119+ // 使用 ClipboardEvent 粘贴内容
120+ const pasteEvent = new ClipboardEvent ( 'paste' , {
121+ bubbles : true ,
122+ cancelable : true ,
123+ clipboardData : new DataTransfer ( ) ,
124+ } ) ;
125+ pasteEvent . clipboardData ?. setData ( 'text/plain' , textContent ) ;
126+ descriptionInput . dispatchEvent ( pasteEvent ) ;
127+ }
128+
129+ await new Promise ( ( resolve ) => setTimeout ( resolve , 3000 ) ) ;
130+
131+ // 如果是自动发布,提示需要手动确认
132+ if ( data . isAutoPublish ) {
133+ alert ( '为确保内容符合预期,请手动确认发布' ) ;
154134 }
155135}
0 commit comments