video_processor.py 38 KB

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