video_prep.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. import configparser
  2. import os
  3. import random
  4. import sys
  5. import threading
  6. import time
  7. from datetime import datetime
  8. import concurrent.futures
  9. from common.tts_help import TTS
  10. sys.path.append(os.getcwd())
  11. from common import Material, Feishu, Common, Oss
  12. from common.ffmpeg import FFmpeg
  13. from common.gpt4o_help import GPT4o
  14. from data_channel.douyin import DY
  15. from data_channel.kuaishou import KS
  16. from data_channel.kuaishouchuangzuozhe import KsFeedVideo
  17. from data_channel.piaoquan import PQ
  18. from common.sql_help import sqlCollect
  19. from data_channel.shipinhao import SPH
  20. config = configparser.ConfigParser()
  21. config.read('./config.ini')
  22. class getVideo:
  23. """
  24. 根据标示+任务标示创建目录
  25. """
  26. @classmethod
  27. def create_folders(cls, mark, task_mark):
  28. video_path_url = config['PATHS']['VIDEO_PATH'] + mark + "/" + task_mark + "/"
  29. if not os.path.exists(video_path_url):
  30. os.makedirs(video_path_url)
  31. return video_path_url
  32. """
  33. 随机生成ID
  34. """
  35. @classmethod
  36. def random_id(cls):
  37. now = datetime.now()
  38. rand_num = random.randint(10000, 99999)
  39. oss_id = "{}{}".format(now.strftime("%Y%m%d%H%M%S"), rand_num)
  40. return oss_id
  41. """
  42. 删除文件
  43. """
  44. @classmethod
  45. def remove_files(cls, video_path_url):
  46. if os.path.exists(video_path_url) and os.path.isdir(video_path_url):
  47. for root, dirs, files in os.walk(video_path_url):
  48. for file in files:
  49. file_path = os.path.join(root, file)
  50. os.remove(file_path)
  51. for dir in dirs:
  52. dir_path = os.path.join(root, dir)
  53. os.rmdir(dir_path)
  54. """
  55. 飞书数据处理
  56. """
  57. @classmethod
  58. def video_task(cls, data):
  59. mark = data["mark"]
  60. name = data["name"]
  61. feishu_id = data["feishu_id"]
  62. feishu_sheet = data["feishu_sheet"]
  63. cookie_sheet = data["cookie_sheet"]
  64. pz_sheet = '500Oe0'
  65. pw_sheet = 'DgX7vC'
  66. task_data = Material.get_task_data(feishu_id, feishu_sheet)
  67. if len(task_data) == 0:
  68. Feishu.bot(mark, '机器自动改造消息通知', f'今日任务为空,请关注', name)
  69. return mark
  70. lock = threading.Lock()
  71. def process_task(task):
  72. task_mark = task["task_mark"] # 任务标示
  73. channel_id = str(task["channel_id"])
  74. channel_urls = str(task["channel_url"])
  75. piaoquan_id = str(task["piaoquan_id"])
  76. number = task["number"] # 指定条数
  77. title = task["title"]
  78. video_share = task["video_share"]
  79. video_ending = task["video_ending"]
  80. crop_total = task["crop_total"]
  81. gg_duration_total = task["gg_duration_total"]
  82. video_path_url = cls.create_folders(mark, str(task_mark)) # 创建目录
  83. if video_share and video_share != 'None':
  84. video_share_list = video_share.split('/')
  85. video_share_mark = video_share_list[0]
  86. video_share_name = video_share_list[1]
  87. zm = Material.get_pzsrt_data("summary", pz_sheet, video_share_name) # 获取srt
  88. if zm == '':
  89. Feishu.bot(mark, '机器自动改造消息通知', f'{task_mark}任务下片中标示填写错误,请关注!!!!', name)
  90. if ',' in channel_urls:
  91. channel_url = channel_urls.split(',')
  92. else:
  93. channel_url = [channel_urls]
  94. for url in channel_url:
  95. Common.logger("log").info(f"{task_mark}下的用户:{channel_url}开始获取视频")
  96. if channel_id == "抖音":
  97. data_list = DY.get_dy_url(task_mark, url, number, mark, feishu_id, cookie_sheet, channel_id, name)
  98. elif channel_id == "票圈":
  99. data_list = PQ.get_pq_url(task_mark, url, number, mark)
  100. elif channel_id == "视频号":
  101. data_list = SPH.get_sph_url(task_mark, url, number, mark)
  102. elif channel_id == "快手":
  103. data_list = KS.get_ks_url(task_mark, url, number, mark, feishu_id, cookie_sheet, channel_id, name)
  104. elif channel_id == "快手创作者版":
  105. data_list = KsFeedVideo.get_data(number)
  106. if len(data_list) == 0:
  107. Common.logger("log").info(f"{task_mark}下的视频ID{url} 已经改造过了")
  108. Feishu.bot("快手创作者版", '机器自动改造消息通知', f'本轮没有获取到改造的视频链接', "王雪珂")
  109. cls.remove_files(video_path_url)
  110. continue
  111. if len(data_list) == 0:
  112. Common.logger("log").info(f"{task_mark}下的视频ID{url} 已经改造过了")
  113. Feishu.bot(mark, '机器自动改造消息通知', f'{task_mark}任务下的用户ID{url},没有已经改造的视频了', name)
  114. cls.remove_files(video_path_url)
  115. continue
  116. Common.logger("log").info(f"{task_mark}下的ID{url} 获取视频完成,共{len(data_list)}条")
  117. try:
  118. for video in data_list:
  119. new_title = video['old_title'].strip().replace("\n", "") \
  120. .replace("/", "").replace("\\", "").replace("\r", "") \
  121. .replace(":", "").replace("*", "").replace("?", "") \
  122. .replace("?", "").replace('"', "").replace("<", "") \
  123. .replace(">", "").replace("|", "").replace(" ", "") \
  124. .replace("&NBSP", "").replace(".", "。").replace(" ", "") \
  125. .replace("'", "").replace("#", "").replace("Merge", "")
  126. if title == "原标题":
  127. if new_title == "" or len(new_title) == 0 or new_title == None:
  128. new_title = '⭕分享给大家一个视频!值得细品!'
  129. elif title == "AI标题":
  130. if new_title == "" or len(new_title) == 0 or new_title == None:
  131. new_title = '⭕分享给大家一个视频!值得细品!'
  132. else:
  133. new_title = GPT4o.get_ai_title(new_title)
  134. else:
  135. if '/' in title:
  136. titles = title.split('/')
  137. else:
  138. titles = [title]
  139. new_title = random.choice(titles)
  140. v_id = video["video_id"]
  141. cover = video["cover"]
  142. video_url = video["video_url"]
  143. rule = video['rule']
  144. old_title = video['old_title']
  145. time.sleep(1)
  146. pw_random_id = cls.random_id()
  147. if channel_id == "票圈":
  148. new_video_path = PQ.download_video(video_url, video_path_url, v_id) # 下载视频地址
  149. else:
  150. new_video_path = Oss.download_video_oss(video_url, video_path_url, v_id) # 下载视频地址
  151. Common.logger("log").info(f"{task_mark}下的视频{url},{new_video_path}视频下载成功")
  152. if not os.path.isfile(new_video_path):
  153. Common.logger("log").info(f"{task_mark}下的视频{url},{new_video_path}视频下载失败")
  154. cls.remove_files(video_path_url)
  155. continue
  156. Common.logger("log").info(f"{task_mark}下的视频{url},{new_video_path}视频下载成功")
  157. if crop_total and crop_total != 'None': # 判断是否需要裁剪
  158. new_video_path = FFmpeg.video_crop(new_video_path, video_path_url, pw_random_id)
  159. if gg_duration_total and gg_duration_total != 'None': # 判断是否需要指定视频时长
  160. new_video_path = FFmpeg.video_ggduration(new_video_path, video_path_url, pw_random_id, gg_duration_total)
  161. if video_ending and video_ending != 'None':
  162. if video_ending == "AI片尾引导":
  163. pw_srt_text = GPT4o.get_ai_pw(new_title)
  164. if pw_srt_text:
  165. pw_url = TTS.get_pw_zm(pw_srt_text)
  166. Common.logger("log").info(f"{task_mark}下的视频{url},获取AI片尾音频成功")
  167. if pw_url:
  168. pw_mp3_path = TTS.download_mp3(pw_url, video_path_url, pw_random_id)
  169. pw_url_sec = FFmpeg.get_video_duration(pw_mp3_path) # 获取片尾秒数
  170. Common.logger("log").info(f"{task_mark}下的视频{url},获取AI片尾秒数成功{pw_url_sec}")
  171. pw_srt = TTS.getSrt(pw_url)
  172. Common.logger("log").info(f"{task_mark}下的视频{url},获取AI片尾srt成功")
  173. else:
  174. continue
  175. else:
  176. continue
  177. else:
  178. if ',' in video_ending:
  179. video_ending_list = video_ending.split(',')
  180. else:
  181. video_ending_list = [video_ending]
  182. ending = random.choice(video_ending_list)
  183. pw_list = Material.get_pwsrt_data("summary", pw_sheet, ending) # 获取srt
  184. if pw_list:
  185. pw_id = pw_list["pw_id"]
  186. pw_srt = pw_list["pw_srt"]
  187. pw_url = PQ.get_pw_url(pw_id)
  188. pw_mp3_path = FFmpeg.get_video_mp3(pw_url, video_path_url, pw_random_id)
  189. else:
  190. Feishu.bot(mark, '机器自动改造消息通知', f'{task_mark}任务下片尾标示错误,请关注!!!!', name)
  191. for attempt in range(3):
  192. jpg_path = FFmpeg.video_png(new_video_path, video_path_url, pw_random_id) # 生成视频最后一帧jpg
  193. if os.path.isfile(jpg_path):
  194. Common.logger("log").info(f"{task_mark}下的视频{url},生成视频最后一帧成功")
  195. break
  196. time.sleep(1)
  197. if not os.path.isfile(jpg_path):
  198. Feishu.bot(mark, '机器自动改造消息通知', f'{task_mark}任务用户{url}下的视频{v_id},获取视频最后一帧失败,请关注', name)
  199. cls.remove_files(video_path_url)
  200. continue
  201. for attempt in range(3):
  202. Common.logger("log").info(f"{task_mark}下的视频{url},获取mp3成功")
  203. pw_path = FFmpeg.pw_video(jpg_path, video_path_url, pw_mp3_path, pw_srt, pw_random_id, pw_mp3_path) # 生成片尾视频
  204. if os.path.isfile(pw_path):
  205. Common.logger("log").info(f"{task_mark}下的视频{url},生成片尾视频成功")
  206. break
  207. time.sleep(1)
  208. if not os.path.isfile(pw_path):
  209. Feishu.bot(mark, '机器自动改造消息通知', f'{task_mark}任务用户{url}下的视频{v_id},生成片尾视频失败,请关注',
  210. name)
  211. cls.remove_files(video_path_url)
  212. continue
  213. pw_video_list = [new_video_path, pw_path]
  214. Common.logger("log").info(f"{task_mark}下的视频{url},视频与片尾开始拼接")
  215. video_path = FFmpeg.concatenate_videos(pw_video_list, video_path_url) # 视频与片尾拼接到一起
  216. Common.logger("log").info(f"{task_mark}下的视频{url},视频与片尾拼接成功")
  217. time.sleep(1)
  218. if video_share and video_share != 'None':
  219. new_video_path = FFmpeg.single_video(video_path, video_share_mark, video_path_url, zm)
  220. else:
  221. new_video_path = video_path
  222. else:
  223. if video_share and video_share != 'None':
  224. new_video_path = FFmpeg.single_video(new_video_path, video_share_mark, video_path_url, zm)
  225. time.sleep(1)
  226. oss_id = cls.random_id()
  227. Common.logger("log").info(f"{task_mark}下的视频{url},开始发送oss")
  228. oss_object_key = Oss.stitching_sync_upload_oss(new_video_path, oss_id) # 视频发送OSS
  229. status = oss_object_key.get("status")
  230. if status == 200:
  231. oss_object_key = oss_object_key.get("oss_object_key")
  232. time.sleep(1)
  233. code = PQ.insert_piaoquantv(oss_object_key, new_title, cover, piaoquan_id)
  234. if code:
  235. Common.logger("log").info(f"{task_mark}下的视频ID{v_id}发送成功")
  236. sqlCollect.insert_task(task_mark, v_id, mark, channel_id) # 插入数据库
  237. current_time = datetime.now()
  238. formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S")
  239. sqlCollect.insert_machine_making_data(name, task_mark, channel_id, url, v_id, piaoquan_id, new_title, code, formatted_time, old_title)
  240. if title == "原标题" or title == "AI标题":
  241. values = [[name, task_mark, channel_id, url, str(v_id), piaoquan_id, old_title, title,new_title, str(code), formatted_time, str(rule)]]
  242. else:
  243. values = [[name, task_mark, channel_id, url, str(v_id), piaoquan_id, old_title, "",new_title, str(code), formatted_time, str(rule)]]
  244. # 使用锁保护表格插入操作
  245. with lock:
  246. if name == "王雪珂":
  247. sheet = "vfhHwj"
  248. elif name == "王雪珂-1":
  249. sheet = "61kvW7"
  250. elif name == "鲁涛":
  251. sheet = "FhewlS"
  252. elif name == "范军":
  253. sheet = "B6dCfS"
  254. elif name == "余海涛":
  255. sheet = "mfBrNT"
  256. elif name == "罗情":
  257. sheet = "2J3PwN"
  258. elif name == "王玉婷":
  259. sheet = "bBHFwC"
  260. elif name == "刘诗雨":
  261. sheet = "fBdxIQ"
  262. elif name == "信欣":
  263. sheet = "lPe1eT"
  264. elif name == "快手创作者版品类推荐流":
  265. sheet = "k7l7nQ"
  266. elif name == "抖音品类账号":
  267. sheet = "Bsg5UR"
  268. Feishu.insert_columns("ILb4sa0LahddRktnRipcu2vQnLb", sheet, "ROWS", 1, 2)
  269. time.sleep(0.5)
  270. Feishu.update_values("ILb4sa0LahddRktnRipcu2vQnLb", sheet, "A2:Z2", values)
  271. cls.remove_files(video_path_url)
  272. else:
  273. cls.remove_files(video_path_url)
  274. Common.logger("log").info(f"{task_mark}下的{url}视频{v_id} 视频发送OSS失败 ")
  275. Feishu.bot(mark, '机器自动改造消息通知', f'{task_mark}任务改造完成,请关注', name)
  276. except Exception as e:
  277. cls.remove_files(video_path_url)
  278. Common.logger("warning").warning(f"{name}的{task_mark}任务处理失败:{e}\n")
  279. batch_size = 1
  280. with concurrent.futures.ThreadPoolExecutor(max_workers=batch_size) as executor:
  281. index = 0
  282. while index < len(task_data):
  283. # 计算剩余的任务数量
  284. remaining_tasks = len(task_data) - index
  285. # 当前批次大小为剩余任务数量和批次大小中较小的一个
  286. current_batch_size = min(batch_size, remaining_tasks)
  287. # 获取当前批次的任务
  288. current_batch = task_data[index:index + batch_size]
  289. futures = {executor.submit(process_task, task): task for task in current_batch}
  290. for future in concurrent.futures.as_completed(futures):
  291. task = futures[future]
  292. try:
  293. future.result()
  294. print(f"Task {task['task_mark']} 完成")
  295. except Exception as exc:
  296. print(f"Task {task['task_mark']} 异常信息: {exc}")
  297. # 移动到下一批任务
  298. index += current_batch_size
  299. Feishu.bot(mark, '机器自动改造消息通知', f'你的任务全部完成,请关注!!!!!', name)
  300. return mark