video_processor.py 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. import configparser
  2. import json
  3. import os
  4. import random
  5. import re
  6. import shutil
  7. import time
  8. from datetime import datetime
  9. from common.odps_data import OdpsDataCount
  10. from common.redis import get_data, get_first_value_with_prefix, increment_key
  11. from common.tag_video import Tag
  12. from common.tts_help import TTS
  13. from common import Material, Feishu, Common, Oss, AliyunLogger
  14. from common.ffmpeg import FFmpeg
  15. from common.gpt4o_help import GPT4o
  16. from data_channel.douyin import DY
  17. from data_channel.dy_keyword import DyKeyword
  18. from data_channel.dy_ls import DYLS
  19. from data_channel.ks_keyword import KsKeyword
  20. from data_channel.ks_ls import KSLS
  21. from data_channel.kuaishou import KS
  22. from data_channel.kuaishouchuangzuozhe import KsFeedVideo
  23. from data_channel.piaoquan import PQ
  24. from common.sql_help import sqlCollect
  25. from data_channel.shipinhao import SPH
  26. # 读取配置文件
  27. from data_channel.shipinhaodandian import SPHDD
  28. from data_channel.sph_keyword import SphKeyword
  29. from data_channel.sph_ls import SPHLS
  30. config = configparser.ConfigParser()
  31. config.read('./config.ini')
  32. class VideoProcessor:
  33. """
  34. 视频处理类,包含创建文件夹、生成随机ID、删除文件和处理视频任务等方法。
  35. """
  36. @classmethod
  37. def create_folders(cls, mark):
  38. """
  39. 根据标示和任务标示创建目录
  40. """
  41. id = cls.random_id()
  42. video_path_url = config['PATHS']['VIDEO_PATH'] + mark + "/" + str(id) + "/"
  43. if not os.path.exists(video_path_url):
  44. os.makedirs(video_path_url)
  45. return video_path_url
  46. @classmethod
  47. def random_id(cls):
  48. """
  49. 随机生成ID
  50. """
  51. now = datetime.now()
  52. rand_num = random.randint(10000, 99999)
  53. return f"{now.strftime('%Y%m%d%H%M%S')}{rand_num}"
  54. @classmethod
  55. def remove_files(cls, mark):
  56. """
  57. 删除指定目录下的所有文件和子目录
  58. """
  59. path = config['PATHS']['VIDEO_PATH'] + mark + "/"
  60. # 删除目录下的所有内容
  61. if os.path.exists(path):
  62. # 遍历目录下的所有文件和子目录
  63. for filename in os.listdir(path):
  64. file_path = os.path.join(path, filename)
  65. try:
  66. if os.path.isfile(file_path) or os.path.islink(file_path):
  67. os.unlink(file_path) # 删除文件或符号链接
  68. elif os.path.isdir(file_path):
  69. shutil.rmtree(file_path) # 删除子目录及其所有内容
  70. except Exception as e:
  71. print(f'Failed to delete {file_path}. Reason: {e}')
  72. @classmethod
  73. def process_task(cls, task, mark, name, feishu_id, cookie_sheet):
  74. """
  75. 处理单个任务
  76. """
  77. task_mark = task["task_mark"]
  78. channel_id = str(task["channel_id"])
  79. url = str(task["channel_url"])
  80. piaoquan_id = str(task["piaoquan_id"])
  81. number = task["number"]
  82. title = task["title"]
  83. video_share = task["video_share"]
  84. video_ending = task["video_ending"]
  85. crop_total = task["crop_total"]
  86. gg_duration_total = task["gg_duration_total"]
  87. voice = task['voice']
  88. if voice:
  89. if ',' in voice:
  90. voices = voice.split(',')
  91. else:
  92. voices = [voice]
  93. voice = random.choice(voices)
  94. else:
  95. voice = "zhifeng_emo"
  96. zm = Material.get_pzsrt_data("summary", "500Oe0", video_share)
  97. Common.logger(mark).info(f"{name}的{task_mark}下{channel_id}的用户:{url}开始获取视频")
  98. new_count = None
  99. if name in ['快手品类账号', '抖音品类账号', '抖音品类账号-1', '视频号品类账号']:
  100. new_count = OdpsDataCount.main(channel_id, name, url)
  101. data_list = cls.get_data_list(
  102. channel_id, task_mark, url,
  103. new_count if new_count is not None else number,
  104. mark, feishu_id, cookie_sheet, name, task
  105. )
  106. if new_count:
  107. sqlCollect.insert_spider_supply_targetcnt(channel_id, name, url, number, new_count, str(len(data_list)))
  108. current_time = datetime.now()
  109. formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S")
  110. values = [
  111. [
  112. name,
  113. channel_id,
  114. url,
  115. str(number),
  116. str(new_count),
  117. str(len(data_list)),
  118. formatted_time
  119. ]
  120. ]
  121. Feishu.insert_columns("Z5xLsdyyxh3abntTTvUc9zw8nYd", "099da8", "ROWS", 1, 2)
  122. time.sleep(0.5)
  123. Feishu.update_values("Z5xLsdyyxh3abntTTvUc9zw8nYd", "099da8", "A2:Z2", values)
  124. if not data_list:
  125. AliyunLogger.logging(channel_id, name, url, "", "无改造视频", "4000")
  126. Common.logger(mark).info(f"{name}的{task_mark}下{channel_id}的视频ID{url} 无改造视频")
  127. text = (
  128. f"**通知类型**: 没有改造的视频\n"
  129. f"**负责人**: {name}\n"
  130. f"**渠道**: {channel_id}\n"
  131. f"**视频主页ID**: {url}\n"
  132. )
  133. Feishu.finish_bot(text, "https://open.feishu.cn/open-apis/bot/v2/hook/e7697dc6-5254-4411-8b59-3cd0742bf703",
  134. "【 机器改造通知 】")
  135. return
  136. Common.logger(mark).info(f"{name}的{task_mark}下的ID{url} 获取视频完成,共{len(data_list)}条")
  137. for video in data_list:
  138. try:
  139. cls.remove_files(mark)
  140. video_path_url = cls.create_folders(mark)
  141. new_title = cls.generate_title(video, title)
  142. v_id = video["video_id"]
  143. cover = video["cover"]
  144. video_url = video["video_url"]
  145. old_title = video['old_title']
  146. rule = video['rule']
  147. # if channel_id == "单点视频":
  148. # redis_video = get_redis_video_data(v_id)
  149. # if redis_video:
  150. # continue
  151. if not old_title:
  152. old_title = '这个视频,分享给我的老友,祝愿您能幸福安康'
  153. text = (
  154. f"**通知类型**: 标题为空,使用兜底标题生成片尾\n"
  155. f"**负责人**: {name}\n"
  156. f"**渠道**: {channel_id}\n"
  157. f"**视频主页ID**: {url}\n"
  158. f"**视频Video_id**: {v_id}\n"
  159. )
  160. Feishu.finish_bot(text,
  161. "https://open.feishu.cn/open-apis/bot/v2/hook/e7697dc6-5254-4411-8b59-3cd0742bf703",
  162. "【 机器改造通知 】")
  163. Common.logger(mark).info(f"{name}的{task_mark}下的视频{url},标题为空,使用兜底标题生成片尾")
  164. time.sleep(1)
  165. pw_random_id = cls.random_id()
  166. Common.logger(mark).info(f"{name}的{task_mark}下的ID{url} 开始下载视频")
  167. new_video_path = cls.download_and_process_video(channel_id, video_url, video_path_url, v_id,
  168. crop_total, gg_duration_total, pw_random_id, new_title, mark, video)
  169. if not os.path.isfile(new_video_path) or new_video_path == None:
  170. AliyunLogger.logging(channel_id, name, url, v_id, "视频下载失败", "3002", f"video_url:{video_url}")
  171. text = (
  172. f"**通知类型**: 视频下载失败\n"
  173. f"**负责人**: {name}\n"
  174. f"**渠道**: {channel_id}\n"
  175. f"**视频主页ID**: {url}\n"
  176. f"**视频Video_id**: {v_id}\n"
  177. )
  178. Feishu.finish_bot(text,
  179. "https://open.feishu.cn/open-apis/bot/v2/hook/e7697dc6-5254-4411-8b59-3cd0742bf703",
  180. "【 机器改造通知 】")
  181. continue
  182. if new_video_path:
  183. if video_ending and video_ending != 'None':
  184. new_video_path = cls.handle_video_ending(new_video_path, video_ending, old_title, pw_random_id, video_path_url, mark, task_mark, url, name, video_share, zm, voice)
  185. if new_video_path == None:
  186. if name == "单点视频":
  187. sqlCollect.update_shp_dd_vid_4(v_id)
  188. from_user_name = video['from_user_name'] # 来源用户
  189. from_group_name = video['from_group_name'] # 来源群组
  190. source = video['source'] # 渠道
  191. text = (
  192. f"**渠道**: {source}\n"
  193. f"**来源用户**: {from_user_name}\n"
  194. f"**来源群组**: {from_group_name}\n"
  195. f"**原视频链接**: {video['video_url']}\n"
  196. f"**原视频封面**: {video['cover']}\n"
  197. f"**原视频标题**: {video['old_title']}\n"
  198. )
  199. Feishu.finish_bot(text,
  200. "https://open.feishu.cn/open-apis/bot/v2/hook/493b3d4c-5fae-4a9d-980b-1dd86636524e",
  201. "【 视频下载失败,跳过该视频 】")
  202. continue
  203. else:
  204. if video_share and video_share != 'None':
  205. new_video_path = FFmpeg.single_video(new_video_path, video_path_url, zm)
  206. # new_video_path = FFmpeg.single_video(new_video_path, video_path_url, zm)
  207. if not os.path.isfile(new_video_path):
  208. log_data = f"user:{url},,video_id:{v_id},,video_url:{video_url},,ai_title:{new_title}"
  209. AliyunLogger.logging(channel_id, name, url, v_id, "视频改造失败", "3001", log_data)
  210. text = (
  211. f"**通知类型**: 视频改造失败\n"
  212. f"**负责人**: {name}\n"
  213. f"**渠道**: {channel_id}\n"
  214. f"**视频主页ID**: {url}\n"
  215. f"**视频Video_id**: {v_id}\n"
  216. )
  217. Feishu.finish_bot(text,
  218. "https://open.feishu.cn/open-apis/bot/v2/hook/e7697dc6-5254-4411-8b59-3cd0742bf703",
  219. "【 机器改造通知 】")
  220. continue
  221. # 上传视频和封面,并更新数据库
  222. code = cls.upload_video_and_thumbnail(new_video_path, cover, v_id, new_title, task_mark, name, piaoquan_id,
  223. video_path_url, mark, channel_id, url, old_title, title, rule)
  224. # 更新已使用的视频号状态
  225. pq_url = f'https://admin.piaoquantv.com/cms/post-detail/{code}/detail' # 站内视频链接
  226. if name == "单点视频":
  227. sphdd_status = sqlCollect.update_shp_dd_vid(v_id)
  228. if sphdd_status == 1:
  229. Common.logger(mark).info(f"{name}的{task_mark}下的ID{url} 视频修改已使用,状态已修改")
  230. from_user_name = video['from_user_name'] # 来源用户
  231. from_group_name = video['from_group_name'] # 来源群组
  232. source = video['source'] # 渠道
  233. channel_id = source
  234. text = (
  235. f"**站内视频链接**: {pq_url}\n"
  236. f"**渠道**: {source}\n"
  237. f"**来源用户**: {from_user_name}\n"
  238. f"**来源群组**: {from_group_name}\n"
  239. f"**原视频链接**: {video['video_url']}\n"
  240. f"**原视频封面**: {video['cover']}\n"
  241. f"**原视频标题**: {video['old_title']}\n"
  242. )
  243. Feishu.finish_bot(text, "https://open.feishu.cn/open-apis/bot/v2/hook/493b3d4c-5fae-4a9d-980b-1dd86636524e", "【 有一条新的内容改造成功 】")
  244. if channel_id == "快手历史" or channel_id == "抖音历史" or channel_id == "视频号历史":
  245. explain = "历史爆款"
  246. else:
  247. explain = "新供给"
  248. current_time = datetime.now()
  249. formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S")
  250. if name == "品类关键词搜索":
  251. first_category = task["first_category"]
  252. secondary_category = task["secondary_category"]
  253. keyword_principal = task["keyword_name"]
  254. tag_first = f"一级品类_{first_category}"
  255. tag_keyword = f"关键词_{url}"
  256. if channel_id == "抖音搜索":
  257. tag_channel = "来源_抖音关键词"
  258. elif channel_id == "快手搜索":
  259. tag_channel = "来源_快手关键词"
  260. elif channel_id == "视频号搜索":
  261. tag_channel = "来源_视频号关键词"
  262. tag = f"{tag_first},{tag_keyword},{tag_channel}"
  263. tag_status = Tag.video_tag(code, tag)
  264. if tag_status == 0:
  265. Common.logger(mark).info(f"{name}的{task_mark}下的ID{url}下的票圈视频{code},写入标签成功")
  266. log_data = f"user:{url},,video_id:{v_id},,video_url:{video_url},,ai_title:{new_title},,voice:{voice},,first_category:{first_category},,secondary_category:{secondary_category},,keyword_principal:{keyword_principal},,tag:{tag}"
  267. values = [
  268. [
  269. name,
  270. task_mark,
  271. channel_id,
  272. url,
  273. str(v_id),
  274. piaoquan_id,
  275. old_title,
  276. title if title in ["原标题", "AI标题"] else "",
  277. new_title,
  278. str(code),
  279. formatted_time,
  280. str(rule),
  281. explain,
  282. voice,
  283. first_category,
  284. secondary_category,
  285. keyword_principal,
  286. pq_url
  287. ]
  288. ]
  289. else:
  290. log_data = f"user:{url},,video_id:{v_id},,video_url:{video_url},,ai_title:{new_title},,voice:{voice}"
  291. values = [
  292. [
  293. name,
  294. task_mark,
  295. channel_id,
  296. url,
  297. str(v_id),
  298. piaoquan_id,
  299. old_title,
  300. title if title in ["原标题", "AI标题"] else "",
  301. new_title,
  302. str(code),
  303. formatted_time,
  304. str(rule),
  305. explain,
  306. voice
  307. ]
  308. ]
  309. AliyunLogger.logging(channel_id, name, url, v_id, "视频改造成功", "1000", log_data, str(code))
  310. text = (
  311. f"**通知类型**: 视频改造成功\n"
  312. f"**站内视频链接**: {pq_url}\n"
  313. f"**负责人**: {name}\n"
  314. f"**渠道**: {channel_id}\n"
  315. f"**视频主页ID**: {url}\n"
  316. f"**视频Video_id**: {v_id}\n"
  317. f"**使用音频音色**: {voice}\n"
  318. )
  319. Feishu.finish_bot(text,
  320. "https://open.feishu.cn/open-apis/bot/v2/hook/e7697dc6-5254-4411-8b59-3cd0742bf703",
  321. "【 机器改造通知 】")
  322. if values:
  323. if name == "王雪珂":
  324. sheet = "vfhHwj"
  325. elif name == "抖音品类账号-1":
  326. sheet = "61kvW7"
  327. elif name == "鲁涛":
  328. sheet = "FhewlS"
  329. elif name == "范军":
  330. sheet = "B6dCfS"
  331. elif name == "余海涛":
  332. sheet = "mfBrNT"
  333. elif name == "罗情":
  334. sheet = "2J3PwN"
  335. elif name == "王玉婷":
  336. sheet = "bBHFwC"
  337. elif name == "刘诗雨":
  338. sheet = "fBdxIQ"
  339. elif name == "信欣":
  340. sheet = "lPe1eT"
  341. elif name == "快手创作者版品类推荐流":
  342. sheet = "k7l7nQ"
  343. elif name == "抖音品类账号":
  344. sheet = "Bsg5UR"
  345. elif name == "视频号品类账号":
  346. sheet = "b0uLWw"
  347. elif name == "单点视频":
  348. sheet = "ptgCXW"
  349. elif name == "快手品类账号":
  350. sheet = "ibjoMx"
  351. elif name == "品类关键词搜索":
  352. sheet = "Tgpikc"
  353. Feishu.insert_columns("ILb4sa0LahddRktnRipcu2vQnLb", sheet, "ROWS", 1, 2)
  354. time.sleep(0.5)
  355. Feishu.update_values("ILb4sa0LahddRktnRipcu2vQnLb", sheet, "A2:Z2", values)
  356. except Exception as e:
  357. Common.logger(mark).error(f"{name}的{task_mark}任务处理失败:{e}")
  358. continue
  359. @classmethod
  360. def get_data_list(cls, channel_id, task_mark, url, number, mark, feishu_id, cookie_sheet, name, task):
  361. """
  362. 根据渠道ID获取数据列表
  363. """
  364. if channel_id == "抖音":
  365. return DY.get_dy_url(task_mark, url, number, mark, feishu_id, cookie_sheet, channel_id, name)
  366. elif channel_id == "票圈":
  367. return PQ.get_pq_url(task_mark, url, number, mark, channel_id, name)
  368. elif channel_id == "视频号":
  369. return SPH.get_sph_url(task_mark, url, number, mark, channel_id, name)
  370. elif channel_id == "快手":
  371. return KS.get_ks_url(task_mark, url, number, mark, feishu_id, cookie_sheet, channel_id, name)
  372. elif channel_id == "快手创作者版":
  373. return KsFeedVideo.get_data(channel_id, name)
  374. elif channel_id == "单点视频":
  375. return SPHDD.get_sphdd_data(url, channel_id, name)
  376. elif channel_id == "抖音历史":
  377. return DYLS.get_dy_zr_list(task_mark, url, number, mark, channel_id, name)
  378. elif channel_id == "快手历史":
  379. return KSLS.get_ksls_list(task_mark, url, number, mark, channel_id, name)
  380. elif channel_id == "视频号历史":
  381. return SPHLS.get_sphls_data(task_mark, url, number, mark, channel_id, name)
  382. elif channel_id == '抖音搜索':
  383. return DyKeyword.get_key_word(url, task_mark, mark, channel_id, name, task)
  384. elif channel_id == '快手搜索':
  385. return KsKeyword.get_key_word(url, task_mark, mark, channel_id, name, task)
  386. elif channel_id == '视频号搜索':
  387. return SphKeyword.get_key_word(url, task_mark, mark, channel_id, name)
  388. @classmethod
  389. def generate_title(cls, video, title):
  390. """
  391. 生成新标题
  392. """
  393. if video['old_title']:
  394. new_title = video['old_title'].strip().replace("\n", "") \
  395. .replace("/", "").replace("\\", "").replace("\r", "") \
  396. .replace(":", "").replace("*", "").replace("?", "") \
  397. .replace("?", "").replace('"', "").replace("<", "") \
  398. .replace(">", "").replace("|", "").replace(" ", "") \
  399. .replace("&NBSP", "").replace(".", "。").replace(" ", "") \
  400. .replace("'", "").replace("#", "").replace("Merge", "")
  401. else:
  402. return '这个视频,分享给我的老友,祝愿您能幸福安康'
  403. if title == "原标题":
  404. if not new_title:
  405. new_title = '这个视频,分享给我的老友,祝愿您能幸福安康'
  406. elif title == "AI标题":
  407. if not new_title:
  408. new_title = '这个视频,分享给我的老友,祝愿您能幸福安康'
  409. else:
  410. new_title = GPT4o.get_ai_title(new_title)
  411. else:
  412. titles = title.split('/') if '/' in title else [title]
  413. new_title = random.choice(titles)
  414. return new_title
  415. @classmethod
  416. def download_and_process_video(cls, channel_id, video_url, video_path_url, v_id, crop_total, gg_duration_total,
  417. pw_random_id, new_title, mark, video):
  418. """
  419. 下载并处理视频
  420. """
  421. if channel_id == "单点视频":
  422. new_video_path = PQ.dd_sph_download_video(video_url, video_path_url, v_id, video, channel_id)
  423. if new_video_path == None:
  424. return None
  425. Common.logger(mark).info(f"{channel_id}视频下载成功: {new_video_path}")
  426. elif channel_id == "视频号":
  427. new_video_path = PQ.sph_download_video(video_url, video_path_url, v_id, video)
  428. if new_video_path == None:
  429. return None
  430. Common.logger(mark).info(f"{channel_id}视频下载成功: {new_video_path}")
  431. elif channel_id == "票圈" or channel_id == "快手创作者版" or channel_id == '视频号搜索':
  432. new_video_path = PQ.download_video(video_url, video_path_url, v_id)
  433. if new_video_path == None:
  434. return None
  435. Common.logger(mark).info(f"{channel_id}视频下载成功: {new_video_path}")
  436. elif channel_id == "视频号历史":
  437. new_video_path = Oss.download_sph_ls(video_url, video_path_url, v_id)
  438. Common.logger(mark).info(f"{channel_id}视频下载成功: {new_video_path}")
  439. else:
  440. Common.logger(mark).info(f"视频准备下载")
  441. new_video_path = Oss.download_video_oss(video_url, video_path_url, v_id)
  442. Common.logger(mark).info(f"视频下载成功: {new_video_path}")
  443. if os.path.isfile(new_video_path):
  444. if crop_total and crop_total != 'None': # 判断是否需要裁剪
  445. new_video_path = FFmpeg.video_crop(new_video_path, video_path_url, pw_random_id)
  446. if gg_duration_total and gg_duration_total != 'None': # 判断是否需要指定视频时长
  447. new_video_path = FFmpeg.video_ggduration(new_video_path, video_path_url, pw_random_id,
  448. gg_duration_total)
  449. width, height = FFmpeg.get_w_h_size(new_video_path)
  450. if width < height: # 判断是否需要修改为竖屏
  451. new_video_path = FFmpeg.update_video_h_w(new_video_path, video_path_url, pw_random_id)
  452. new_title_re = re.sub(r'[^\w\s\u4e00-\u9fff,。!?]', '', new_title)
  453. if len(new_title_re) > 12:
  454. new_title_re = '\n'.join(
  455. [new_title_re[i:i + 12] for i in range(0, len(new_title_re), 12)])
  456. new_video_path = FFmpeg.add_video_zm(new_video_path, video_path_url, pw_random_id, new_title_re)
  457. return new_video_path
  458. else:
  459. return None
  460. @classmethod
  461. def handle_video_ending(cls, new_video_path, video_ending, old_title, pw_random_id, video_path_url, mark, task_mark, url, name, video_share, zm, voice):
  462. """
  463. 处理视频片尾
  464. """
  465. if video_ending == "AI片尾引导":
  466. pw_srt_text = GPT4o.get_ai_pw(old_title)
  467. if pw_srt_text:
  468. pw_url = TTS.get_pw_zm(pw_srt_text, voice)
  469. if pw_url:
  470. pw_mp3_path = TTS.download_mp3(pw_url, video_path_url, pw_random_id)
  471. # oss_mp3_key = Oss.mp3_upload_oss(pw_mp3_path, pw_random_id)
  472. # oss_mp3_key = oss_mp3_key.get("oss_object_key")
  473. # new_pw_path = f"http://art-crawler.oss-cn-hangzhou.aliyuncs.com/{oss_mp3_key}"
  474. # print(f"mp3地址:{new_pw_path}")
  475. # pw_url_sec = FFmpeg.get_video_duration(pw_mp3_path)
  476. pw_srt = TTS.getSrt(pw_url)
  477. Common.logger(mark).info(f"{name}的{task_mark}下的视频{url},获取AI片尾srt成功")
  478. else:
  479. # Feishu.bot('zhangyong', 'TTS获取失败提示', f'无法获取到片尾音频,及时更换token', "张勇")
  480. Common.logger(mark).info(f"{name}的{task_mark}下的视频{url},获取AI片尾失败")
  481. return None
  482. else:
  483. Common.logger(mark).info(f"{name}的{task_mark}下的视频{url},获取AI片尾失败")
  484. return None
  485. else:
  486. if ',' in video_ending:
  487. video_ending_list = video_ending.split(',')
  488. else:
  489. video_ending_list = [video_ending]
  490. ending = random.choice(video_ending_list)
  491. pw_list = Material.get_pwsrt_data("summary", "DgX7vC", ending) # 获取srt
  492. if pw_list:
  493. pw_id = pw_list["pw_id"]
  494. pw_srt = pw_list["pw_srt"]
  495. pw_url = PQ.get_pw_url(pw_id)
  496. pw_mp3_path = FFmpeg.get_video_mp3(pw_url, video_path_url, pw_random_id)
  497. else:
  498. Feishu.bot(mark, '机器自动改造消息通知', f'{task_mark}任务下片尾标示错误,请关注!!!!', name)
  499. for attempt in range(3):
  500. jpg_path = FFmpeg.video_png(new_video_path, video_path_url, pw_random_id) # 生成视频最后一帧jpg
  501. if os.path.isfile(jpg_path):
  502. Common.logger(mark).info(f"{name}的{task_mark}下的视频{url},生成视频最后一帧成功")
  503. break
  504. time.sleep(1)
  505. for attempt in range(3):
  506. Common.logger(mark).info(f"{name}的{task_mark}下的视频{url},获取mp3成功")
  507. pw_path = FFmpeg.pw_video(jpg_path, video_path_url, pw_mp3_path, pw_srt, pw_random_id,
  508. pw_mp3_path) # 生成片尾视频
  509. if os.path.isfile(pw_path):
  510. Common.logger(mark).info(f"{task_mark}下的视频{url},生成片尾视频成功")
  511. break
  512. time.sleep(1)
  513. pw_video_list = [new_video_path, pw_path]
  514. Common.logger(mark).info(f"{task_mark}下的视频{url},视频与片尾开始拼接")
  515. video_path = FFmpeg.concatenate_videos(pw_video_list, video_path_url) # 视频与片尾拼接到一起
  516. if video_path:
  517. Common.logger(mark).info(f"{name}的{task_mark}下的视频{url},视频与片尾拼接成功")
  518. time.sleep(1)
  519. if video_share and video_share != 'None':
  520. new_video_path = FFmpeg.single_video(video_path, video_path_url, zm)
  521. else:
  522. new_video_path = video_path
  523. return new_video_path
  524. else:
  525. return None
  526. @classmethod
  527. def upload_video_and_thumbnail(cls, new_video_path: str, cover: str, v_id, new_title: str, task_mark: str, name: str, piaoquan_id,
  528. video_path_url: str, mark: str, channel_id: str, url: str, old_title: str, title, rule: str):
  529. """
  530. 上传视频和封面到OSS,并更新数据库
  531. """
  532. try:
  533. oss_id = cls.random_id()
  534. Common.logger(mark).info(f"{name}的{task_mark},开始发送oss")
  535. oss_object_key = Oss.stitching_sync_upload_oss(new_video_path, oss_id) # 视频发送OSS
  536. Common.logger(mark).info(f"{name}的{task_mark},发送oss成功{oss_object_key}")
  537. status = oss_object_key.get("status")
  538. if status == 200:
  539. oss_object_key = oss_object_key.get("oss_object_key")
  540. time.sleep(1)
  541. if channel_id == "快手历史":
  542. jpg = None
  543. else:
  544. if channel_id == "视频号历史":
  545. jpg_path = Oss.download_sph_ls(cover, video_path_url, v_id)
  546. else:
  547. jpg_path = PQ.download_video_jpg(cover, video_path_url, v_id) # 下载视频封面
  548. if os.path.isfile(jpg_path):
  549. oss_jpg_key = Oss.stitching_fm_upload_oss(jpg_path, oss_id) # 封面发送OSS
  550. status = oss_jpg_key.get("status")
  551. if status == 200:
  552. jpg = oss_jpg_key.get("oss_object_key")
  553. else:
  554. jpg = None
  555. else:
  556. jpg = None
  557. code = PQ.insert_piaoquantv(oss_object_key, new_title, jpg, piaoquan_id)
  558. Common.logger(mark).info(f"{name}的{task_mark}下的视频ID{v_id}发送成功")
  559. sqlCollect.insert_task(task_mark, v_id, mark, channel_id) # 插入数据库
  560. current_time = datetime.now()
  561. formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S")
  562. if name == "单点视频":
  563. url = str(rule)
  564. sqlCollect.insert_machine_making_data(name, task_mark, channel_id, url, v_id, piaoquan_id, new_title, code,
  565. formatted_time, old_title, oss_object_key)
  566. return code
  567. except Exception as e:
  568. Common.logger(mark).error(f"{name}的{task_mark}上传视频和封面到OSS,并更新数据库失败:{e}\n")
  569. return
  570. @classmethod
  571. def main(cls, data):
  572. """
  573. 主函数,初始化任务并使用线程池处理任务。
  574. """
  575. mark = data["mark"]
  576. name = data["name"]
  577. feishu_id = data["feishu_id"]
  578. feishu_sheet = data["feishu_sheet"]
  579. cookie_sheet = data["cookie_sheet"]
  580. try:
  581. data = get_data(mark, feishu_id, feishu_sheet)
  582. if not data:
  583. Common.logger("redis").error(f"{mark}任务开始新的一轮\n")
  584. return
  585. task = json.loads(data)
  586. if mark == 'dy-pl-gjc' and task['channel_id'] == '抖音搜索':
  587. mark_count = 'dyss-count'
  588. count = get_first_value_with_prefix(mark_count)
  589. increment_key(mark_count)
  590. if int(count) >= 300:
  591. Common.logger(mark).log(f"抖音搜索接口今日已经上限")
  592. return "抖音搜索上限"
  593. if mark == 'ks-pl-gjc' and task['channel_id'] == '抖音搜索':
  594. mark_count = 'ksss-count'
  595. count = get_first_value_with_prefix(mark_count)
  596. increment_key(mark_count)
  597. if int(count) >= 300:
  598. Common.logger(mark).log(f"快手搜索接口今日已经上限")
  599. return "快手搜索上限"
  600. if mark == 'sph-pl-gjc':
  601. mark_count = 'sphss-count'
  602. count = get_first_value_with_prefix(mark_count)
  603. increment_key(mark_count)
  604. if int(count) >= 300:
  605. Common.logger(mark).log(f"视频号搜索接口今日已经上限")
  606. return "视频号搜索上限"
  607. if mark == 'sph-plzh'and task['channel_id'] == '视频号':
  608. mark_count = 'sph-count'
  609. count = get_first_value_with_prefix(mark_count)
  610. increment_key(mark_count)
  611. if int(count) >= 400:
  612. Common.logger(mark).log(f"视频号获取用户主页今日已经上限")
  613. return "视频号获取用户主页视频上限"
  614. VideoProcessor.process_task(task, mark, name, feishu_id, cookie_sheet)
  615. return mark
  616. except Exception as e:
  617. Common.logger(mark).error(f"任务处理失败: {e}")
  618. return mark
  619. # if __name__ == "__main__":
  620. # main()