carry_video.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. import html
  2. import json
  3. import os
  4. import random
  5. import re
  6. import time
  7. import uuid
  8. import requests
  9. from datetime import datetime
  10. from urllib.parse import urlparse, parse_qs
  11. from loguru import logger
  12. from common import Oss, Feishu, AliyunLogger
  13. from common.ffmpeg import FFmpeg
  14. from common.gpt4o_help import GPT4o
  15. from common.redis import in_carry_video_data
  16. from common.tag_video import Tag
  17. from common.tts_help import TTS
  18. from data_channel.piaoquan import PQ
  19. class CarryViode:
  20. def get_text_dy_video(self,url):
  21. try:
  22. if "&vid=" not in url:
  23. headers = {
  24. 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;'
  25. 'q=0.8,application/signed-exchange;v=b3;q=0.7',
  26. 'Accept-Language': 'zh-CN,zh;q=0.9',
  27. 'Cache-Control': 'no-cache',
  28. 'Pragma': 'no-cache',
  29. 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) '
  30. 'Chrome/127.0.0.0 Safari/537.36',
  31. }
  32. response = requests.request(url=url, method='GET', headers=headers, allow_redirects=False)
  33. location = response.headers.get('Location', None)
  34. video_id = re.search(r'/video/(\d+)/?', location.split('?')[0] if location else url).group(1)
  35. else:
  36. parsed_url = urlparse(url)
  37. params = parse_qs(parsed_url.query)
  38. video_id = params.get('vid', [None])[0]
  39. url = "http://47.236.68.175:8889/crawler/dou_yin/detail"
  40. payload = json.dumps({
  41. "content_id": str(video_id)
  42. })
  43. headers = {
  44. 'Content-Type': 'application/json'
  45. }
  46. response = requests.request("POST", url, headers=headers, data=payload)
  47. response = response.json()
  48. code = response["code"]
  49. if code == 0:
  50. data = response["data"]["data"]
  51. video_url = data["video_url_list"][0]["video_url"]
  52. original_title = data["title"]
  53. return video_url, original_title
  54. else:
  55. return None, None
  56. except Exception as e:
  57. logger.error(f"[+] 抖音{url}获取视频链接失败,失败信息{e}")
  58. return None, None
  59. def get_text_ks_video(self,url):
  60. try:
  61. headers = {
  62. 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;'
  63. 'q=0.8,application/signed-exchange;v=b3;q=0.7',
  64. 'Accept-Language': 'zh-CN,zh;q=0.9',
  65. 'Cache-Control': 'no-cache',
  66. 'Pragma': 'no-cache',
  67. 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) '
  68. 'Chrome/127.0.0.0 Safari/537.36',
  69. }
  70. response = requests.request(url=url, method='GET', headers=headers, allow_redirects=False)
  71. location = response.headers.get('Location', None)
  72. video_id = re.search(r'/(f|photo|short-video|long-video)/(.*)/?',
  73. location.split('?')[0] if location else url).group(2)
  74. url = "http://47.236.68.175:8889/crawler/kuai_shou/detail"
  75. payload = json.dumps({
  76. "content_id": str(video_id)
  77. })
  78. headers = {
  79. 'Content-Type': 'application/json'
  80. }
  81. response = requests.request("POST", url, headers=headers, data=payload)
  82. response = response.json()
  83. code = response["code"]
  84. if code == 0:
  85. data = response["data"]["data"]
  86. video_url = data["video_url_list"][0]["video_url"]
  87. original_title = data["title"]
  88. return video_url, original_title
  89. else:
  90. return None,None
  91. except Exception as e:
  92. logger.error(f"[+] 快手{url}获取视频链接失败,失败信息{e}")
  93. return None, None
  94. def main(self, data, REDIS_NAME, file_path):
  95. AliyunLogger.logging(data["name"],"效率工具", data["tag_transport_channel"], data["video_url"], "扫描到一条视频", "2001", str(data))
  96. AliyunLogger.logging(data["name"], "效率工具",data["tag_transport_channel"], data["video_url"], "符合规则等待改造", "2004", str(data))
  97. url = data['video_url']
  98. if "&vid=" not in url and data['tag_transport_channel'] != "抖音":
  99. msg = html.unescape(url).split('?')[0]
  100. pattern = re.search(r'https?://[^\s<>"\'\u4e00-\u9fff]+', msg)
  101. if not pattern:
  102. return
  103. url = pattern.group()
  104. host = urlparse(url).netloc
  105. if host in ['v.douyin.com', 'www.douyin.com', 'www.iesdouyin.com']:
  106. url, original_title = self.get_text_dy_video(url=url)
  107. elif host in ['v.kuaishou.com', 'www.kuaishou.com', 'v.m.chenzhongtech.com', 'creater.eozatvmq.com']:
  108. url, original_title = self.get_text_ks_video(url=url)
  109. else:
  110. logger.error(f"[+] {url}该链接不是抖/快 不做处理")
  111. AliyunLogger.logging(data["name"], "效率工具",data["tag_transport_channel"], data["video_url"],
  112. "不是抖/快不做处理", "1001", str(data))
  113. return
  114. if not url:
  115. in_carry_video_data(REDIS_NAME, data)
  116. logger.info(f"[+] {url}没有获取到视频链接,等待重新处理")
  117. AliyunLogger.logging(data["name"], "效率工具",data["tag_transport_channel"], data["video_url"],
  118. "没有获取到视频链接,等待重新处理", "1002", str(data))
  119. return
  120. if data["title_category"] == "AI标题" or data["trailer_share"] == "AI标题":
  121. title = GPT4o.get_ai_title(original_title if data["title_category"] == "原标题" else data["title_category"])
  122. else:
  123. title = original_title if data["title_category"] == "原标题" else data["title_category"]
  124. # video_path = DownLoad.download_video(url, file_path)
  125. video_path = Oss.download_video_oss(url, file_path)
  126. if not video_path:
  127. logger.error(f"[+] {url}下载失败")
  128. AliyunLogger.logging(data["name"],"效率工具", data["tag_transport_channel"], data["video_url"],
  129. "视频下载失败", "3002", str(data))
  130. print("飞书通知")
  131. return
  132. if data["transform_rule"] == '否':
  133. logger.info(f"[+] {REDIS_NAME}的{data}数据开始发送oss")
  134. oss_object_key = Oss.stitching_sync_upload_oss(video_path, str(uuid.uuid4())) # 视频发送OSS
  135. status = oss_object_key.get("status")
  136. if status != 200:
  137. logger.error(f"[+] {REDIS_NAME}的{data}数据发送oss失败")
  138. AliyunLogger.logging(data["name"], "效率工具",data["tag_transport_channel"], data["video_url"],
  139. "改造失败,发送oss失败", "3001", str(data))
  140. return
  141. logger.info(f"[+] {REDIS_NAME}的{data}数据发送oss成功")
  142. oss_object_key = oss_object_key.get("oss_object_key")
  143. elif data["transform_rule"] == "仅改造":
  144. if data["video_clipping"]: # 判断是否需要裁剪
  145. video_path = FFmpeg.video_crop(video_path, file_path)
  146. if data["video_clipping_time"]: # 判断是否需要指定视频时长
  147. video_path = FFmpeg.video_ggduration(video_path, file_path, data["video_clipping_time"])
  148. width, height = FFmpeg.get_w_h_size(video_path)
  149. if width < height: # 判断是否需要修改为竖屏
  150. video_path = FFmpeg.update_video_h_w(video_path, file_path)
  151. if data['trailer_share'] == "AI片尾引导":
  152. pw_srt_text = '老友们,这个视频说的太好了,请你在看完之后,不要私藏,分享给身边的亲人朋友,转发传递这份美好,这不仅是分享一个好视频,更是在传递一份深厚的祝福和好运,愿每个看到这消息的人,都能收获健康长寿和平安,希望您在看完后能够回传给我,并且把这条视频再传给3个群和3个好友,祝愿你我,健健康康,平平安安,因为3个数字代表着健康和平安,这么好的视频,千万不要在你的手里终止了,分享给群友们,他们看到以后一定会感谢你的,感谢分享,感谢传递'
  153. voice = data['trailer_share_audio']
  154. if voice:
  155. if ',' in voice:
  156. voices = voice.split(',')
  157. else:
  158. voices = [voice]
  159. voice = random.choice(voices)
  160. else:
  161. voice = "zhifeng_emo"
  162. pw_url = TTS.get_pw_zm(pw_srt_text, voice)
  163. if not pw_url:
  164. logger.error(f"[+] {REDIS_NAME}的{data}数据片尾获取失败")
  165. AliyunLogger.logging(data["name"],"效率工具", data["tag_transport_channel"], data["video_url"],
  166. "改造失败,片尾获取失败", "3001", str(data))
  167. return
  168. logger.info(f"[+] {REDIS_NAME}的{data}数据片尾获取成功")
  169. pw_srt = TTS.getSrt(pw_url)
  170. pw_mp3_path = TTS.download_mp3(pw_url, file_path)
  171. if not pw_mp3_path or not pw_mp3_path:
  172. logger.error(f"[+] {REDIS_NAME}的{data}数据片尾音频下载失败")
  173. AliyunLogger.logging(data["name"], "效率工具",data["tag_transport_channel"], data["video_url"],
  174. "改造失败,片尾音频下载失败", "3001", str(data))
  175. return
  176. logger.info(f"[+] {REDIS_NAME}的{data}数据片尾音频下载成功")
  177. jpg_path = FFmpeg.video_png(video_path, file_path) # 生成视频最后一帧jpg
  178. if not os.path.isfile(jpg_path) or not jpg_path:
  179. logger.error(f"[+] {REDIS_NAME}的{data}数据片尾获取最后一帧失败")
  180. AliyunLogger.logging(data["name"], "效率工具",data["tag_transport_channel"], data["video_url"],
  181. "改造失败,获取最后一帧失败", "3001", str(data))
  182. return
  183. logger.info(f"[+] {REDIS_NAME}的{data}数据片尾获取最后一帧成功")
  184. pw_path = FFmpeg.pw_video(jpg_path, file_path, pw_mp3_path, pw_srt) # 生成片尾视频
  185. if not os.path.isfile(pw_path) or not pw_path:
  186. logger.error(f"[+] {REDIS_NAME}的{data}数据片尾拼接失败")
  187. AliyunLogger.logging(data["name"], "效率工具",data["tag_transport_channel"], data["video_url"],
  188. "改造失败,片尾拼接失败", "3001", str(data))
  189. return
  190. pw_video_list = [video_path, pw_path]
  191. video_path = FFmpeg.concatenate_videos(pw_video_list, video_path) # 视频与片尾拼接到一起
  192. if not os.path.isfile(video_path) or not video_path:
  193. logger.error(f"[+] {REDIS_NAME}的{data}数据合并拼接失败")
  194. AliyunLogger.logging(data["name"], "效率工具",data["tag_transport_channel"], data["video_url"],
  195. "改造失败,合并拼接失败", "3001", str(data))
  196. return
  197. logger.info(f"[+] {REDIS_NAME}的{data}数据合并拼接成功")
  198. if data["video_share"]:
  199. video_path = FFmpeg.single_video(video_path, file_path, data["video_share"])
  200. if not os.path.isfile(video_path) or not video_path:
  201. logger.error(f"[+] {REDIS_NAME}的{data}数据添加片中字幕失败")
  202. AliyunLogger.logging(data["name"], "效率工具",data["tag_transport_channel"], data["video_url"],
  203. "改造失败,添加片中字幕失败", "3001", str(data))
  204. return
  205. logger.info(f"[+] {REDIS_NAME}的{data}数据添加片中字幕成功")
  206. logger.info(f"[+] {REDIS_NAME}的{data}数据开始发送oss")
  207. oss_object_key = Oss.stitching_sync_upload_oss(video_path, str(uuid.uuid4())) # 视频发送OSS
  208. status = oss_object_key.get("status")
  209. if status != 200:
  210. logger.error(f"[+] {REDIS_NAME}的{data}数据发送oss失败")
  211. AliyunLogger.logging(data["name"],"效率工具", data["tag_transport_channel"], data["video_url"],
  212. "改造失败,发送oss失败", "3001", str(data))
  213. return
  214. logger.info(f"[+] {REDIS_NAME}的{data}数据发送oss成功")
  215. oss_object_key = oss_object_key.get("oss_object_key")
  216. logger.info(f"[+] {REDIS_NAME}的{data}开始写入票圈")
  217. n_ids = data["pq_ids"]
  218. if ',' in n_ids:
  219. n_id_list = n_ids.split(',')
  220. else:
  221. n_id_list = [n_ids]
  222. pq_list = []
  223. for n_id in n_id_list:
  224. code = PQ.insert_piaoquantv(oss_object_key, title, n_id)
  225. if not code:
  226. logger.error(f"[+] {REDIS_NAME}的{data}写入票圈后台失败")
  227. AliyunLogger.logging(data["name"], "效率工具",data["tag_transport_channel"], data["video_url"],
  228. "改造失败,写入票圈后台失败", "3001", str(data))
  229. continue
  230. pq_list.append(code)
  231. logger.info(f"[+] {REDIS_NAME}的{data}写入票圈成功,返回视频id{code}")
  232. if data["transform_rule"] == '否':
  233. tag_s = "搬运"
  234. else:
  235. tag_s = "搬运改造"
  236. tags = ','.join(filter(None, [
  237. data['pq_label'],
  238. data['channel_mark'],
  239. data['tag_transport_channel'],
  240. data['tag_transport_scene'],
  241. data['tag_transport_keyword'],
  242. data['tag'],
  243. tag_s
  244. ]))
  245. tag_status = Tag.video_tag(code, str(tags))
  246. if tag_status == 0:
  247. logger.info(f"[+] {REDIS_NAME}的{data}写入标签成功,后台视频ID为{code}")
  248. try:
  249. current_time = datetime.now()
  250. formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S")
  251. values = [
  252. [
  253. str(code),
  254. str(n_id),
  255. formatted_time,
  256. data["channel_mark"],
  257. data["name"],
  258. data["pq_ids"],
  259. data["pq_label"],
  260. data["activate_data"],
  261. data["video_url"],
  262. data["title_category"],
  263. data["tag_transport_channel"],
  264. data["tag_transport_scene"],
  265. data["tag_transport_keyword"],
  266. data["tag"],
  267. data["transform_rule"],
  268. data["video_share"],
  269. data["trailer_share"],
  270. data["trailer_share_audio"],
  271. data["video_clipping"],
  272. data["video_clipping_time"],
  273. data["title_transform"],
  274. ]
  275. ]
  276. name_to_sheet = {
  277. "范军": "276ffc",
  278. "鲁涛": "QqrKRY",
  279. "余海涛": "dTzUlI",
  280. "罗情": "8JPv9g",
  281. "刘诗雨": "HqwG0o",
  282. "张峰": "vtWvle",
  283. "周仙琴": "MWUqWt"
  284. }
  285. name = re.sub(r"\s+", "", data.get("name", ""))
  286. sheet = name_to_sheet.get(name)
  287. Feishu.insert_columns("R4dLsce8Jhz9oCtDMr9ccpFHnbI", sheet, "ROWS", 1, 2)
  288. time.sleep(0.5)
  289. Feishu.update_values("R4dLsce8Jhz9oCtDMr9ccpFHnbI", sheet, "A2:Z2", values)
  290. logger.info(f"[+] {REDIS_NAME}的{data}写入飞书成功")
  291. except Exception as e:
  292. logger.error(f"[+] {REDIS_NAME}的{data}写入飞书失败{e}")
  293. pass
  294. AliyunLogger.logging(data["name"], "效率工具",data["tag_transport_channel"], data["video_url"],
  295. "改造成功", "1000", str(data),str(pq_list))
  296. return