Deroino commited on
Commit
46f6718
·
1 Parent(s): 46de6a9

feat(wechat-channel): add draft upload functionality for video channel

Browse files

- Add isDraft parameter to TencentVideo class to control publishing behavior
- Modify click_publish method to click "保存草稿" instead of "发表" when isDraft is true
- Update post_video_tencent function to accept and pass is_draft parameter
- Add is_draft parameter to /postVideo API endpoint to receive frontend data
- Add "视频号上传草稿" checkbox in frontend that appears only for video channel platform
- Update defaultTabInit to include isDraft property with default value false
- Include isDraft in publishData sent to backend API
- Implement proper URL checking for draft vs publish success confirmation

The new functionality allows users to save WeChat Channel videos as drafts
instead of immediately publishing them when the checkbox is selected.

myUtils/postVideo.py CHANGED
@@ -10,7 +10,7 @@ from utils.constant import TencentZoneTypes
10
  from utils.files_times import generate_schedule_time_next_day
11
 
12
 
13
- def post_video_tencent(title,files,tags,account_file,category=TencentZoneTypes.LIFESTYLE.value,enableTimer=False,videos_per_day = 1, daily_times=None,start_days = 0):
14
  # 生成文件的完整路径
15
  account_file = [Path(BASE_DIR / "cookiesFile" / file) for file in account_file]
16
  files = [Path(BASE_DIR / "videoFile" / file) for file in files]
@@ -25,7 +25,7 @@ def post_video_tencent(title,files,tags,account_file,category=TencentZoneTypes.L
25
  print(f"视频文件名:{file}")
26
  print(f"标题:{title}")
27
  print(f"Hashtag:{tags}")
28
- app = TencentVideo(title, str(file), tags, publish_datetimes[index], cookie, category)
29
  asyncio.run(app.main(), debug=False)
30
 
31
 
 
10
  from utils.files_times import generate_schedule_time_next_day
11
 
12
 
13
+ def post_video_tencent(title,files,tags,account_file,category=TencentZoneTypes.LIFESTYLE.value,enableTimer=False,videos_per_day = 1, daily_times=None,start_days = 0, is_draft=False):
14
  # 生成文件的完整路径
15
  account_file = [Path(BASE_DIR / "cookiesFile" / file) for file in account_file]
16
  files = [Path(BASE_DIR / "videoFile" / file) for file in files]
 
25
  print(f"视频文件名:{file}")
26
  print(f"标题:{title}")
27
  print(f"Hashtag:{tags}")
28
+ app = TencentVideo(title, str(file), tags, publish_datetimes[index], cookie, category, is_draft)
29
  asyncio.run(app.main(), debug=False)
30
 
31
 
sau_backend.py CHANGED
@@ -363,6 +363,7 @@ def postVideo():
363
  productLink = data.get('productLink', '')
364
  productTitle = data.get('productTitle', '')
365
  thumbnail_path = data.get('thumbnail', '')
 
366
 
367
  videos_per_day = data.get('videosPerDay')
368
  daily_times = data.get('dailyTimes')
@@ -376,7 +377,7 @@ def postVideo():
376
  start_days)
377
  case 2:
378
  post_video_tencent(title, file_list, tags, account_list, category, enableTimer, videos_per_day, daily_times,
379
- start_days)
380
  case 3:
381
  post_video_DouYin(title, file_list, tags, account_list, category, enableTimer, videos_per_day, daily_times,
382
  start_days, thumbnail_path, productLink, productTitle)
 
363
  productLink = data.get('productLink', '')
364
  productTitle = data.get('productTitle', '')
365
  thumbnail_path = data.get('thumbnail', '')
366
+ is_draft = data.get('isDraft', False) # 新增参数:是否保存为草稿
367
 
368
  videos_per_day = data.get('videosPerDay')
369
  daily_times = data.get('dailyTimes')
 
377
  start_days)
378
  case 2:
379
  post_video_tencent(title, file_list, tags, account_list, category, enableTimer, videos_per_day, daily_times,
380
+ start_days, is_draft)
381
  case 3:
382
  post_video_DouYin(title, file_list, tags, account_list, category, enableTimer, videos_per_day, daily_times,
383
  start_days, thumbnail_path, productLink, productTitle)
sau_frontend/src/views/PublishCenter.vue CHANGED
@@ -402,6 +402,15 @@
402
  />
403
  </div>
404
 
 
 
 
 
 
 
 
 
 
405
  <!-- 定时发布 -->
406
  <div class="schedule-section">
407
  <h3>定时发布</h3>
@@ -534,7 +543,8 @@ const defaultTabInit = {
534
  dailyTimes: ['10:00'], // 每天发布时间点列表
535
  startDays: 0, // 从今天开始计算的发布天数,0表示明天,1表示后天
536
  publishStatus: null, // 发布状态,包含message和type
537
- publishing: false // 发布状态,用于控制按钮loading效果
 
538
  }
539
 
540
  // helper to create a fresh deep-copied tab from defaultTabInit
@@ -791,7 +801,8 @@ const confirmPublish = async (tab) => {
791
  startDays: tab.scheduleEnabled ? tab.startDays || 0 : 0, // 从今天开始计算的发布天数,0表示明天,1表示后天
792
  category: 0, //表示非原创
793
  productLink: tab.productLink.trim() || '', // 商品链接
794
- productTitle: tab.productTitle.trim() || '' // 商品名称
 
795
  }
796
 
797
  // 调用后端发布API
 
402
  />
403
  </div>
404
 
405
+ <!-- 草稿选项 (仅在视频号可见) -->
406
+ <div v-if="tab.selectedPlatform === 2" class="draft-section">
407
+ <el-checkbox
408
+ v-model="tab.isDraft"
409
+ label="视频号上传草稿"
410
+ class="draft-checkbox"
411
+ />
412
+ </div>
413
+
414
  <!-- 定时发布 -->
415
  <div class="schedule-section">
416
  <h3>定时发布</h3>
 
543
  dailyTimes: ['10:00'], // 每天发布时间点列表
544
  startDays: 0, // 从今天开始计算的发布天数,0表示明天,1表示后天
545
  publishStatus: null, // 发布状态,包含message和type
546
+ publishing: false, // 发布状态,用于控制按钮loading效果
547
+ isDraft: false // 是否保存为草稿,仅视频号平台可见
548
  }
549
 
550
  // helper to create a fresh deep-copied tab from defaultTabInit
 
801
  startDays: tab.scheduleEnabled ? tab.startDays || 0 : 0, // 从今天开始计算的发布天数,0表示明天,1表示后天
802
  category: 0, //表示非原创
803
  productLink: tab.productLink.trim() || '', // 商品链接
804
+ productTitle: tab.productTitle.trim() || '', // 商品名称
805
+ isDraft: tab.isDraft // 是否保存为草稿,仅视频号平台使用
806
  }
807
 
808
  // 调用后端发布API
uploader/tencent_uploader/main.py CHANGED
@@ -82,13 +82,14 @@ async def weixin_setup(account_file, handle=False):
82
 
83
 
84
  class TencentVideo(object):
85
- def __init__(self, title, file_path, tags, publish_date: datetime, account_file, category=None):
86
  self.title = title # 视频标题
87
  self.file_path = file_path
88
  self.tags = tags
89
  self.publish_date = publish_date
90
  self.account_file = account_file
91
  self.category = category
 
92
  self.local_executable_path = LOCAL_CHROME_PATH or None
93
 
94
  async def set_schedule_time_tencent(self, page, publish_date):
@@ -185,21 +186,37 @@ class TencentVideo(object):
185
  async def click_publish(self, page):
186
  while True:
187
  try:
188
- publish_buttion = page.locator('div.form-btns button:has-text("发表")')
189
- if await publish_buttion.count():
190
- await publish_buttion.click()
191
- await page.wait_for_url("https://channels.weixin.qq.com/platform/post/list", timeout=5000)
192
- tencent_logger.success(" [-]视频发布成功")
 
 
 
 
 
 
 
 
 
 
193
  break
194
  except Exception as e:
195
  current_url = page.url
196
- if "https://channels.weixin.qq.com/platform/post/list" in current_url:
197
- tencent_logger.success(" [-]视频发布成功")
198
- break
 
 
199
  else:
200
- tencent_logger.exception(f" [-] Exception: {e}")
201
- tencent_logger.info(" [-] 视频正在发布中...")
202
- await asyncio.sleep(0.5)
 
 
 
 
203
 
204
  async def detect_upload_status(self, page):
205
  while True:
 
82
 
83
 
84
  class TencentVideo(object):
85
+ def __init__(self, title, file_path, tags, publish_date: datetime, account_file, category=None, is_draft=False):
86
  self.title = title # 视频标题
87
  self.file_path = file_path
88
  self.tags = tags
89
  self.publish_date = publish_date
90
  self.account_file = account_file
91
  self.category = category
92
+ self.is_draft = is_draft # 是否保存为草稿
93
  self.local_executable_path = LOCAL_CHROME_PATH or None
94
 
95
  async def set_schedule_time_tencent(self, page, publish_date):
 
186
  async def click_publish(self, page):
187
  while True:
188
  try:
189
+ if self.is_draft:
190
+ # 点击"保存草稿"按钮
191
+ draft_button = page.locator('div.form-btns button:has-text("保存草稿")')
192
+ if await draft_button.count():
193
+ await draft_button.click()
194
+ # 等待跳转到草稿箱页面或确认保存成功
195
+ await page.wait_for_url("**/post/list**", timeout=5000) # 使用通配符匹配包含post/list的URL
196
+ tencent_logger.success(" [-]视频草稿保存成功")
197
+ else:
198
+ # 点击"发表"按钮
199
+ publish_button = page.locator('div.form-btns button:has-text("发表")')
200
+ if await publish_button.count():
201
+ await publish_button.click()
202
+ await page.wait_for_url("https://channels.weixin.qq.com/platform/post/list", timeout=5000)
203
+ tencent_logger.success(" [-]视频发布成功")
204
  break
205
  except Exception as e:
206
  current_url = page.url
207
+ if self.is_draft:
208
+ # 检查是否在草稿相关的页面
209
+ if "post/list" in current_url or "draft" in current_url:
210
+ tencent_logger.success(" [-]视频草稿保存成功")
211
+ break
212
  else:
213
+ # 检查是否在发布列表页面
214
+ if "https://channels.weixin.qq.com/platform/post/list" in current_url:
215
+ tencent_logger.success(" [-]视频发布成功")
216
+ break
217
+ tencent_logger.exception(f" [-] Exception: {e}")
218
+ tencent_logger.info(" [-] 视频正在发布中...")
219
+ await asyncio.sleep(0.5)
220
 
221
  async def detect_upload_status(self, page):
222
  while True: