carry_video.py 22 KB

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