video_processor.py 33 KB

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