video_processor.py 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. import configparser
  2. import json
  3. import os
  4. import random
  5. import shutil
  6. import time
  7. import traceback
  8. from datetime import datetime
  9. from loguru import logger
  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, 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. logger.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. logger.info(f"[+] {name}的{task_mark}下的ID{url} 获取视频完成,没有符合/改造视频")
  112. AliyunLogger.logging(channel_id, name, url, "", "无改造视频", "4000")
  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. logger.info(f"[+] {name}的{task_mark}下的ID{url} 获取视频完成,共{len(data_list)}条")
  123. for video in data_list:
  124. logger.info(f"[+][+][+][+][+][+] {name}的{task_mark}下的ID{url} ,开始改造")
  125. cls.remove_files(mark)
  126. file_path = cls.create_folders(mark)
  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. time.sleep(1)
  145. pw_random_id = cls.random_id()
  146. logger.info(f"[+] {name}的{task_mark}下的ID{url} 开始下载视频")
  147. video_path = cls.download_and_process_video( channel_id, video_url, file_path, v_id, video)
  148. if not os.path.isfile(video_path) or os.path.getsize(video_path) == 0:
  149. if name == "单点视频":
  150. sqlCollect.update_shp_dd_vid_4(v_id)
  151. from_user_name = video['from_user_name'] # 来源用户
  152. from_group_name = video['from_group_name'] # 来源群组
  153. source = video['source'] # 渠道
  154. text = (
  155. f"**渠道**: {source}\n"
  156. f"**来源用户**: {from_user_name}\n"
  157. f"**来源群组**: {from_group_name}\n"
  158. f"**原视频链接**: {video['video_url']}\n"
  159. f"**原视频封面**: {video['cover']}\n"
  160. f"**原视频标题**: {video['old_title']}\n"
  161. )
  162. Feishu.finish_bot(text,
  163. "https://open.feishu.cn/open-apis/bot/v2/hook/493b3d4c-5fae-4a9d-980b-1dd86636524e",
  164. "【 视频下载失败,跳过该视频 】")
  165. text = (
  166. f"**通知类型**: 视频下载失败\n"
  167. f"**负责人**: {name}\n"
  168. f"**渠道**: {channel_id}\n"
  169. f"**视频主页ID**: {url}\n"
  170. f"**视频Video_id**: {v_id}\n"
  171. )
  172. if name == "快手推荐流" or name == "视频号推荐流":
  173. sqlCollect.update_feed_vid_2(v_id)
  174. Feishu.finish_bot(text,
  175. "https://open.feishu.cn/open-apis/bot/v2/hook/493b3d4c-5fae-4a9d-980b-1dd86636524e",
  176. "【 视频下载失败,跳过该视频 】")
  177. AliyunLogger.logging(channel_id, name, url, v_id, "视频下载失败", "3002", f"video_url:{video_url}")
  178. Feishu.finish_bot(text,
  179. "https://open.feishu.cn/open-apis/bot/v2/hook/e7697dc6-5254-4411-8b59-3cd0742bf703",
  180. "【 机器改造通知 】")
  181. continue
  182. width, height = FFmpeg.get_w_h_size(video_path)
  183. if width < height: # 判断是否需要修改为竖屏
  184. video_path = FFmpeg.update_video_h_w(video_path, file_path, pw_random_id)
  185. logger.info(f"[+] {name}的{task_mark}下的ID{url} 开始视频更改分辨率")
  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. logger.error(f"[+] {name}的{task_mark}下的ID{url} 视频更改分辨率失败")
  189. AliyunLogger.logging(channel_id, name, url, v_id, "视频更改分辨率失败", "3002")
  190. continue
  191. if crop_total and crop_total != 'None': # 判断是否需要裁剪
  192. video_path = FFmpeg.video_crop(video_path, file_path, pw_random_id)
  193. if gg_duration_total and gg_duration_total != 'None': # 判断是否需要指定视频时长
  194. video_path = FFmpeg.video_ggduration(video_path, file_path, pw_random_id,gg_duration_total)
  195. if video_ending == "AI片尾引导":
  196. logger.info(f"[+] {name}的{task_mark}下的ID{url} 获取ai片尾")
  197. pw_srt_text = GPT4oMini.get_ai_mini_pw(old_title)
  198. logger.info(f"[+] {name}的{task_mark}下的ID{url} 获取ai片尾音频")
  199. pw_url = TTS.get_pw_zm(pw_srt_text, voice)
  200. pw_mp3_path = TTS.download_mp3(pw_url, file_path, pw_random_id)
  201. logger.info(f"[+] {name}的{task_mark}下的ID{url} 获取ai片尾srt")
  202. pw_srt = TTS.getSrt(pw_url)
  203. if not pw_srt:
  204. logger.error(f"[+] {name}的{task_mark}下的ID{url} 获取ai片尾srt失败")
  205. continue
  206. else:
  207. if ',' in video_ending:
  208. video_ending_list = video_ending.split(',')
  209. else:
  210. video_ending_list = [video_ending]
  211. ending = random.choice(video_ending_list)
  212. pw_list = Material.get_pwsrt_data("summary", "DgX7vC", ending) # 获取srt
  213. pw_id = pw_list["pw_id"]
  214. pw_srt = pw_list["pw_srt"]
  215. pw_url = PQ.get_pw_url(pw_id)
  216. pw_mp3_path = FFmpeg.get_video_mp3(pw_url, file_path, pw_random_id)
  217. if not pw_url:
  218. logger.error(f"[+] {name}的{task_mark}下的ID{url} 获取片尾失败")
  219. AliyunLogger.logging(channel_id, name, url, v_id, "获取片尾失败", "3002")
  220. continue
  221. logger.info(f"[+] {name}的{task_mark}下的ID{url} 开始生成视频最后一帧jpg")
  222. jpg_path = FFmpeg.video_png(video_path, file_path, pw_random_id) # 生成视频最后一帧jpg
  223. if not os.path.exists(jpg_path) or os.path.getsize(jpg_path) == 0:
  224. logger.error(f"[+] {name}的{task_mark}下的ID{url} 片尾获取最后一帧失败")
  225. AliyunLogger.logging(channel_id, name, url, v_id, "片尾获取最后一帧失败", "3002")
  226. continue
  227. logger.info(f"[+] {name}的{task_mark}下的ID{url} 开始生成片尾视频")
  228. pw_path = FFmpeg.pw_video(jpg_path, file_path, pw_srt, pw_random_id, pw_mp3_path) # 生成片尾视频
  229. if not os.path.exists(pw_path) or os.path.getsize(pw_path) == 0:
  230. logger.error(f"[+] {name}的{task_mark}下的ID{url} 生成片尾失败")
  231. AliyunLogger.logging(channel_id, name, url, v_id, "生成片尾失败", "3002")
  232. text = (
  233. f"**通知类型**: 生成片尾失败\n"
  234. f"**负责人**: {name}\n"
  235. f"**渠道**: {channel_id}\n"
  236. f"**视频主页ID**: {url}\n"
  237. f"**视频Video_id**: {v_id}\n"
  238. )
  239. Feishu.finish_bot(text,
  240. "https://open.feishu.cn/open-apis/bot/v2/hook/e7697dc6-5254-4411-8b59-3cd0742bf703",
  241. "【 机器改造通知 】")
  242. continue
  243. logger.info(f"[+] {name}的{task_mark}下的ID{url} 开始视频拼接到一起")
  244. video_path = FFmpeg.h_b_video(video_path, pw_path, file_path)
  245. logger.info(f"[+] {name}的{task_mark}下的ID{url} 开始视频拼接")
  246. video_path = FFmpeg.single_video(video_path, file_path, zm)
  247. if not os.path.exists(video_path) or os.path.getsize(video_path) == 0:
  248. logger.error(f"[+] {name}的{task_mark}下的ID{url} 拼接失败")
  249. AliyunLogger.logging(channel_id, name, url, v_id, "拼接失败", "3002")
  250. text = (
  251. f"**通知类型**: 视频改造失败\n"
  252. f"**负责人**: {name}\n"
  253. f"**渠道**: {channel_id}\n"
  254. f"**视频主页ID**: {url}\n"
  255. f"**视频Video_id**: {v_id}\n"
  256. )
  257. Feishu.finish_bot(text,
  258. "https://open.feishu.cn/open-apis/bot/v2/hook/e7697dc6-5254-4411-8b59-3cd0742bf703",
  259. "【 机器改造通知 】")
  260. continue
  261. # 上传视频和封面,
  262. oss_object_key, jpg = cls.oss_video_path(video_path, cover, v_id, task_mark, name,
  263. file_path, channel_id, url, video)
  264. if not oss_object_key:
  265. continue
  266. new_old_title = cls.generate_title(video, title)
  267. if channel_id == '快手搜索':
  268. new_test_title = cls.generate_test_title(video, title)
  269. title_list = [new_test_title, new_old_title]
  270. else:
  271. title_list = [new_old_title]
  272. is_first = True
  273. for new_title in title_list:
  274. current_time = datetime.now()
  275. formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S")
  276. title_rule = Material.get_title_rule()
  277. if title_rule:
  278. title_rule = title_rule.split(",")
  279. contains_keyword = any(keyword in new_title for keyword in title_rule)
  280. if contains_keyword:
  281. new_title_secure = GPT4oMini.get_ai_mini_title_secure(new_title)
  282. values = [
  283. [ channel_id,
  284. url,
  285. old_title,
  286. new_title,
  287. new_title_secure,
  288. formatted_time
  289. ]
  290. ]
  291. Feishu.insert_columns("U5dXsSlPOhiNNCtEfgqcm1iYnpf", "V36GHT", "ROWS", 1, 2)
  292. time.sleep(0.5)
  293. Feishu.update_values("U5dXsSlPOhiNNCtEfgqcm1iYnpf", "V36GHT", "A2:Z2", values)
  294. new_title = new_title_secure
  295. # 更新数据库
  296. code = cls.upload_video_and_thumbnail(oss_object_key, jpg, v_id, new_title, task_mark, name, piaoquan_id,
  297. mark, channel_id, url, old_title, rule, video)
  298. logger.info(f"[+][+][+][+][+][+] {name}的{task_mark}下的ID{url} 改造成功")
  299. # 更新已使用的视频号状态
  300. pq_url = f'https://admin.piaoquantv.com/cms/post-detail/{code}/detail' # 站内视频链接
  301. if name == "单点视频":
  302. sphdd_status = sqlCollect.update_shp_dd_vid(v_id)
  303. if sphdd_status == 1:
  304. from_user_name = video['from_user_name'] # 来源用户
  305. from_group_name = video['from_group_name'] # 来源群组
  306. source = video['source'] # 渠道
  307. channel_id = source
  308. text = (
  309. f"**站内视频链接**: {pq_url}\n"
  310. f"**渠道**: {source}\n"
  311. f"**来源用户**: {from_user_name}\n"
  312. f"**来源群组**: {from_group_name}\n"
  313. f"**原视频链接**: {video['video_url']}\n"
  314. f"**原视频封面**: {video['cover']}\n"
  315. f"**原视频标题**: {video['old_title']}\n"
  316. )
  317. Feishu.finish_bot(text, "https://open.feishu.cn/open-apis/bot/v2/hook/d2f751a8-5b0a-49ca-a306-1fda142707a9", "【 有一条新的内容改造成功 】")
  318. if name == "快手推荐流" or name == "视频号推荐流":
  319. sqlCollect.update_feed_vid(v_id)
  320. if channel_id == "快手历史" or channel_id == "抖音历史" or channel_id == "视频号历史":
  321. explain = "历史爆款"
  322. else:
  323. explain = "新供给"
  324. if name == "品类关键词搜索":
  325. first_category = task["first_category"]
  326. keyword_principal = task["keyword_name"]
  327. tag_first = f"一级品类_{first_category}"
  328. tag_keyword = f"关键词_{url}"
  329. if channel_id == "抖音搜索":
  330. tag_channel = "来源_抖音关键词"
  331. elif channel_id == "快手搜索":
  332. tag_channel = "来源_快手关键词"
  333. elif channel_id == "视频号搜索":
  334. tag_channel = "来源_视频号关键词"
  335. tag = f"{tag_first},{tag_keyword},{tag_channel}"
  336. tag_status = Tag.video_tag(code, tag)
  337. if tag_status == 0:
  338. logger.info(f"[+] {name}的{task_mark}下的ID{url}下的票圈视频{code},写入标签成功")
  339. secondary_category = task["secondary_category"]
  340. 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}"
  341. values = [
  342. [
  343. name,
  344. task_mark,
  345. channel_id,
  346. url,
  347. str(v_id),
  348. piaoquan_id,
  349. old_title,
  350. title if title in ["原标题", "AI标题"] else "",
  351. new_title,
  352. str(code),
  353. formatted_time,
  354. str(rule),
  355. explain,
  356. voice,
  357. first_category,
  358. secondary_category,
  359. keyword_principal,
  360. pq_url
  361. ]
  362. ]
  363. elif name == "抖音品类账号-1" or name == "抖音品类账号" or name == "视频号品类账号" or name == "快手品类账号":
  364. first_category = task["first_category"]
  365. tag_first = f"一级品类_{first_category}"
  366. if channel_id == "抖音" or channel_id == "抖音历史":
  367. tag_channel = "来源_抖音品类账号"
  368. elif channel_id == "快手" or channel_id == "快手历史":
  369. tag_channel = "来源_快手品类账号"
  370. elif channel_id == "视频号" or channel_id == "视频号历史":
  371. tag_channel = "来源_视频号品类账号"
  372. tag = f"{tag_first},{tag_channel}"
  373. tag_status = Tag.video_tag( code, tag )
  374. if tag_status == 0:
  375. logger.info(f"{name}的{task_mark}下的ID{url}下的票圈视频{code},写入标签成功")
  376. log_data = f"user:{url},,video_id:{v_id},,video_url:{video_url},,ai_title:{new_title},,voice:{voice},,tag:{tag}"
  377. values = [
  378. [
  379. name,
  380. task_mark,
  381. channel_id,
  382. url,
  383. str( v_id ),
  384. piaoquan_id,
  385. old_title,
  386. title if title in ["原标题", "AI标题"] else "",
  387. new_title,
  388. str( code ),
  389. formatted_time,
  390. str( rule ),
  391. explain,
  392. voice,
  393. first_category,
  394. pq_url
  395. ]
  396. ]
  397. else:
  398. log_data = f"user:{url},,video_id:{v_id},,video_url:{video_url},,ai_title:{new_title},,voice:{voice}"
  399. values = [
  400. [
  401. name,
  402. task_mark,
  403. channel_id,
  404. url,
  405. str(v_id),
  406. piaoquan_id,
  407. old_title,
  408. title if title in ["原标题", "AI标题"] else "",
  409. new_title,
  410. str(code),
  411. formatted_time,
  412. str(rule),
  413. explain,
  414. voice
  415. ]
  416. ]
  417. AliyunLogger.logging(channel_id, name, url, v_id, "视频改造成功", "1000", log_data, str(code))
  418. text = (
  419. f"**通知类型**: 视频改造成功\n"
  420. f"**站内视频链接**: {pq_url}\n"
  421. f"**负责人**: {name}\n"
  422. f"**渠道**: {channel_id}\n"
  423. f"**视频主页ID**: {url}\n"
  424. f"**视频Video_id**: {v_id}\n"
  425. f"**使用音频音色**: {voice}\n"
  426. )
  427. Feishu.finish_bot(text,
  428. "https://open.feishu.cn/open-apis/bot/v2/hook/e7697dc6-5254-4411-8b59-3cd0742bf703",
  429. "【 机器改造通知 】")
  430. if len(title_list) > 1 and is_first:
  431. is_first = False
  432. test_title_tag = "lev-供给,rol-机器,#str-改写标题ab实验_46,genMod-搜索"
  433. Tag.video_tag(code, test_title_tag)
  434. if tags:
  435. Tag.video_tag(code, tags)
  436. if values:
  437. if name == "王雪珂":
  438. sheet = "vfhHwj"
  439. elif name == "鲁涛":
  440. sheet = "FhewlS"
  441. elif name == "范军":
  442. sheet = "B6dCfS"
  443. elif name == "余海涛":
  444. sheet = "mfBrNT"
  445. elif name == "罗情":
  446. sheet = "2J3PwN"
  447. elif name == "王玉婷":
  448. sheet = "bBHFwC"
  449. elif name == "刘诗雨":
  450. sheet = "fBdxIQ"
  451. elif name == "信欣":
  452. sheet = "lPe1eT"
  453. elif name == "快手创作者版品类推荐流":
  454. sheet = "k7l7nQ"
  455. elif name == "抖音品类账号":
  456. sheet = "ZixHmf"
  457. elif name == "抖音品类账号-1":
  458. sheet = "61kvW7"
  459. elif name == "视频号品类账号":
  460. sheet = "b0uLWw"
  461. elif name == "单点视频":
  462. sheet = "ptgCXW"
  463. elif name == "快手品类账号":
  464. sheet = "ibjoMx"
  465. elif name == "品类关键词搜索":
  466. sheet = "rBAJT8"
  467. elif name == "快手推荐流":
  468. sheet = "9Ii8lw"
  469. elif name == "视频号推荐流":
  470. sheet = "hMBv7T"
  471. elif name == "快手小程序":
  472. sheet = "GeDT6Q"
  473. elif name == "Top溯源账号":
  474. sheet = "uayZcd"
  475. Feishu.insert_columns("ILb4sa0LahddRktnRipcu2vQnLb", sheet, "ROWS", 1, 2)
  476. time.sleep(0.5)
  477. Feishu.update_values("ILb4sa0LahddRktnRipcu2vQnLb", sheet, "A2:Z2", values)
  478. continue
  479. except Exception as e:
  480. AliyunLogger.logging(channel_id, name, url, v_id, f"改造失败{traceback.format_exc()}", "3001")
  481. logger.error(f"[+] {name}的{task_mark}任务处理失败:{traceback.format_exc()}")
  482. return
  483. @classmethod
  484. def get_data_list(cls, channel_id, task_mark, url, number, mark, feishu_id, cookie_sheet, name, task):
  485. """
  486. 根据渠道ID获取数据列表
  487. """
  488. if channel_id == "抖音":
  489. return DY.get_dy_url(task_mark, url, number, mark, feishu_id, cookie_sheet, channel_id, name)
  490. elif channel_id == "票圈":
  491. return PQ.get_pq_url(task_mark, url, number, mark, channel_id, name)
  492. elif channel_id == "视频号":
  493. return SPH.get_sph_url(task_mark, url, number, mark, channel_id, name)
  494. elif channel_id == "快手":
  495. return KS.get_ks_url(task_mark, url, number, mark, feishu_id, cookie_sheet, channel_id, name)
  496. # elif channel_id == "快手创作者版":
  497. # return KsFeedVideo.get_data(channel_id, name)
  498. elif channel_id == "单点视频":
  499. return SPHDD.get_sphdd_data(url, channel_id, name)
  500. elif channel_id == "抖音历史":
  501. return DYLS.get_dy_zr_list(task_mark, url, number, mark, channel_id, name)
  502. elif channel_id == "快手历史":
  503. return KSLS.get_ksls_list(task_mark, url, number, mark, channel_id, name)
  504. elif channel_id == "视频号历史":
  505. return SPHLS.get_sphls_data(task_mark, url, number, mark, channel_id, name)
  506. elif channel_id == '抖音搜索':
  507. return DyKeyword.get_key_word(url, task_mark, mark, channel_id, name, task)
  508. elif channel_id == '快手搜索':
  509. return KsKeyword.get_key_word(url, task_mark, mark, channel_id, name, task)
  510. elif channel_id == '视频号搜索':
  511. return SphKeyword.get_key_word(url, task_mark, mark, channel_id, name)
  512. elif channel_id == '快手推荐流':
  513. return KSFeed.get_feed_date()
  514. elif channel_id == '视频号推荐流':
  515. return SPHFeed.get_feed_date()
  516. elif channel_id == '快手小程序':
  517. return KSXCX.get_xcx_date(channel_id)
  518. @classmethod
  519. def generate_title(cls, video, title):
  520. """
  521. 生成新标题
  522. """
  523. if video['old_title']:
  524. new_title = video['old_title'].strip().replace("\n", "") \
  525. .replace("/", "").replace("\\", "").replace("\r", "") \
  526. .replace(":", "").replace("*", "").replace("?", "") \
  527. .replace("?", "").replace('"', "").replace("<", "") \
  528. .replace(">", "").replace("|", "").replace(" ", "") \
  529. .replace("&NBSP", "").replace(".", "。").replace(" ", "") \
  530. .replace("'", "").replace("#", "").replace("Merge", "")
  531. else:
  532. return '这个视频,分享给我的老友,祝愿您能幸福安康'
  533. if title == "原标题":
  534. if not new_title:
  535. new_title = '这个视频,分享给我的老友,祝愿您能幸福安康'
  536. elif title == "AI标题":
  537. if not new_title:
  538. new_title = '这个视频,分享给我的老友,祝愿您能幸福安康'
  539. else:
  540. new_title = GPT4oMini.get_ai_mini_title(new_title)
  541. else:
  542. titles = title.split('/') if '/' in title else [title]
  543. new_title = random.choice(titles)
  544. return new_title
  545. @classmethod
  546. def generate_test_title(cls, video, title):
  547. """
  548. 生成新标题
  549. """
  550. if video['old_title']:
  551. new_title = video['old_title'].strip().replace("\n", "") \
  552. .replace("/", "").replace("\\", "").replace("\r", "") \
  553. .replace(":", "").replace("*", "").replace("?", "") \
  554. .replace("?", "").replace('"', "").replace("<", "") \
  555. .replace(">", "").replace("|", "").replace(" ", "") \
  556. .replace("&NBSP", "").replace(".", "。").replace(" ", "") \
  557. .replace("'", "").replace("#", "").replace("Merge", "")
  558. else:
  559. return '这个视频,分享给我的老友,祝愿您能幸福安康'
  560. if title == "原标题":
  561. if not new_title:
  562. new_title = '这个视频,分享给我的老友,祝愿您能幸福安康'
  563. elif title == "AI标题":
  564. if not new_title:
  565. new_title = '这个视频,分享给我的老友,祝愿您能幸福安康'
  566. else:
  567. new_title = GPT4oMini.get_ai_mini_test_title(new_title)
  568. else:
  569. titles = title.split('/') if '/' in title else [title]
  570. new_title = random.choice(titles)
  571. return new_title
  572. @classmethod
  573. def download_and_process_video(cls, channel_id, video_url, video_path_url, v_id, video):
  574. """
  575. 下载并处理视频
  576. """
  577. if channel_id == "单点视频":
  578. new_video_path = PQ.dd_sph_download_video(video_url, video_path_url, v_id, video, channel_id)
  579. elif channel_id == "视频号":
  580. new_video_path = PQ.sph_download_video(video_url, video_path_url, v_id, video)
  581. elif channel_id == "票圈" or channel_id == "快手创作者版" or channel_id == '视频号搜索' or channel_id == "快手推荐流":
  582. new_video_path = PQ.download_video(video_url, video_path_url, v_id)
  583. elif channel_id == "抖音" or channel_id == "抖音历史" or channel_id == "抖音搜索":
  584. new_video_path = PQ.download_dy_video(video_url, video_path_url, v_id)
  585. elif channel_id == "视频号历史":
  586. new_video_path = Oss.download_sph_ls(video_url, video_path_url, v_id)
  587. else:
  588. new_video_path = Oss.download_video_oss(video_url, video_path_url, v_id)
  589. return new_video_path
  590. @classmethod
  591. def oss_video_path(cls, new_video_path: str, cover: str, v_id, task_mark: str, name: str,
  592. video_path_url: str, channel_id: str, url: str, video):
  593. oss_id = cls.random_id()
  594. logger.info(f"[+] {name}的{task_mark}下的ID{url} 开始发送oss")
  595. """
  596. 上传视频和封面到OSS,并更新数据库
  597. """
  598. try:
  599. oss_object_key = Oss.stitching_sync_upload_oss(new_video_path, oss_id) # 视频发送OSS
  600. logger.info(f"[+] {name}的{task_mark}下的ID{url} 发送oss成功{oss_object_key}")
  601. status = oss_object_key.get("status")
  602. if status == 200:
  603. oss_object_key = oss_object_key.get("oss_object_key")
  604. time.sleep(1)
  605. jpg_path = None
  606. if channel_id == "快手历史" or channel_id == "快手" or channel_id == '快手搜索' or channel_id == '视频号':
  607. jpg = None
  608. elif channel_id == "视频号历史":
  609. jpg_path = Oss.download_sph_ls(cover, video_path_url, v_id)
  610. elif channel_id == '单点视频':
  611. if video['source'] != "快手":
  612. jpg_path = PQ.download_video_jpg(cover, video_path_url, v_id) # 下载视频封面
  613. if jpg_path and os.path.isfile(jpg_path):
  614. oss_jpg_key = Oss.stitching_fm_upload_oss(jpg_path, oss_id) # 封面上传OSS
  615. jpg = oss_jpg_key.get("oss_object_key")
  616. else:
  617. jpg = None
  618. return oss_object_key, jpg
  619. return None, None
  620. except Exception as e:
  621. logger.error(f"[+] {name}的{task_mark}上传视频和封面到OSS失败:{traceback.format_exc()}")
  622. AliyunLogger.logging(channel_id, name, url, video["video_id"], "改造失败-上传视频和封面到OSS", "3001")
  623. return None, None
  624. @classmethod
  625. def upload_video_and_thumbnail(cls, oss_object_key: str, jpg: str, v_id, new_title: str, task_mark: str, name: str, piaoquan_id,
  626. mark: str, channel_id: str, url: str, old_title: str, rule: str, video):
  627. """
  628. 上传视频和封面到OSS,并更新数据库
  629. """
  630. try:
  631. code = PQ.insert_piaoquantv(oss_object_key, new_title, jpg, piaoquan_id)
  632. logger.info(f"[+] {name}的{task_mark}下的视频ID{v_id}写入票圈后台成功")
  633. sqlCollect.insert_task(task_mark, v_id, mark, channel_id) # 插入数据库
  634. current_time = datetime.now()
  635. formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S")
  636. if name == "单点视频":
  637. url = str(rule)
  638. sqlCollect.insert_machine_making_data(name, task_mark, channel_id, url, v_id, piaoquan_id, new_title, code,
  639. formatted_time, old_title, oss_object_key)
  640. return code
  641. except Exception as e:
  642. logger.error(f"[+] {name}的{task_mark}更新数据库失败:{traceback.format_exc()}")
  643. AliyunLogger.logging(channel_id, name, url, video["video_id"], "改造失败-上传视频和封面到OSS", "3001")
  644. return
  645. @classmethod
  646. def main(cls, data):
  647. """
  648. 主函数,初始化任务并使用线程池处理任务。
  649. """
  650. mark = data["mark"]
  651. name = data["name"]
  652. feishu_id = data["feishu_id"]
  653. feishu_sheet = data["feishu_sheet"]
  654. cookie_sheet = data["cookie_sheet"]
  655. data = get_data(mark, feishu_id, feishu_sheet)
  656. if not data:
  657. logger.info(f"[+] {name}-{mark}没有获取到数据任务开始新的一轮")
  658. return
  659. task = json.loads(data)
  660. try:
  661. limit_number = task["limit_number"]
  662. if limit_number:
  663. task_mark = task["task_mark"]
  664. makr_count = sqlCollect.get_mark_count(task_mark)
  665. if int(limit_number) <= int(makr_count[0][0]):
  666. AliyunLogger.logging((task["channel_id"]), name, task["channel_url"], '', f"{task_mark}标识任务每日指定条数已足够,指定条数{limit_number},实际生成条数{int(makr_count[0][0])}",
  667. "1111")
  668. logger.info(f"[+] {task_mark}标识任务每日指定条数已足够,指定条数{limit_number},实际生成条数{int(makr_count[0][0])}")
  669. return
  670. if mark == 'dy-pl-gjc' and task['channel_id'] == '抖音搜索':
  671. mark_count = 'dyss-count'
  672. count = get_first_value_with_prefix(mark_count)
  673. increment_key(mark_count)
  674. if int(count) >= 300:
  675. logger.info(f"[+] 抖音搜索上限")
  676. return "抖音搜索上限"
  677. if mark == 'ks-pl-gjc':
  678. mark_count = 'ksss-count'
  679. count = get_first_value_with_prefix(mark_count)
  680. increment_key(mark_count)
  681. if int(count) >= 300:
  682. logger.info(f"[+] 快手搜索上限")
  683. return "快手搜索上限"
  684. if mark == 'sph-pl-gjc':
  685. mark_count = 'ss-sph-count'
  686. count = get_first_value_with_prefix(mark_count)
  687. increment_key(mark_count)
  688. if int(count) >= 300:
  689. logger.info(f"[+] 视频号搜索上限")
  690. time.sleep(10)
  691. return "视频号搜索上限"
  692. if mark == 'sph-plzh'and task['channel_id'] == '视频号':
  693. mark_count = 'sph-count'
  694. count = get_first_value_with_prefix(mark_count)
  695. increment_key(mark_count)
  696. if int(count) >= 400:
  697. logger.info(f"[+] 视频号获取用户主页视频上限")
  698. time.sleep(10)
  699. return "视频号获取用户主页视频上限"
  700. VideoProcessor.process_task(task, mark, name, feishu_id, cookie_sheet)
  701. return mark
  702. except Exception as e:
  703. logger.error(f"[+] {name}用户抓取异常:{traceback.format_exc()}")
  704. AliyunLogger.logging((task["channel_id"]), name, task["channel_url"],'', f"用户抓取异常:{e}", "3001")
  705. return mark
  706. # if __name__ == "__main__":
  707. # main()