video_prep.py 15 KB

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