piaoquan.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. import random
  2. import re
  3. import time
  4. import json
  5. import cffi
  6. import requests
  7. from urllib.parse import urlencode
  8. from common import Common, AliyunLogger, Feishu
  9. from common.sql_help import sqlCollect
  10. class PQ:
  11. """
  12. 获取视频链接
  13. """
  14. @classmethod
  15. def get_pw_url(cls, user_id):
  16. url = f"https://admin.piaoquantv.com/manager/video/detail/{user_id}"
  17. payload = {}
  18. headers = {
  19. 'authority': 'admin.piaoquantv.com',
  20. 'accept': 'application/json, text/plain, */*',
  21. 'accept-language': 'zh-CN,zh;q=0.9',
  22. 'cache-control': 'no-cache',
  23. 'cookie': 'SESSION=YjU3MzgwNTMtM2QyYi00YjljLWI3YWUtZTBjNWYwMGQzYWNl',
  24. 'pragma': 'no-cache',
  25. 'referer': f'https://admin.piaoquantv.com/cms/post-detail/{user_id}/detail',
  26. 'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
  27. 'sec-ch-ua-mobile': '?0',
  28. 'sec-ch-ua-platform': '"macOS"',
  29. 'sec-fetch-dest': 'empty',
  30. 'sec-fetch-mode': 'cors',
  31. 'sec-fetch-site': 'same-origin',
  32. 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
  33. }
  34. response = requests.request("GET", url, headers=headers, data=payload)
  35. data = response.json()
  36. try:
  37. video_url = data["content"]["transedVideoPath"]
  38. return video_url
  39. except Exception as e:
  40. Common.logger("video").warning(f"获取视频链接失败:{e}\n")
  41. return ""
  42. """
  43. 获取视频链接
  44. """
  45. @classmethod
  46. def get_audio_url(cls, task_mark, user_id, title, mark):
  47. url = f"https://admin.piaoquantv.com/manager/video/detail/{user_id}"
  48. payload = {}
  49. headers = {
  50. 'authority': 'admin.piaoquantv.com',
  51. 'accept': 'application/json, text/plain, */*',
  52. 'accept-language': 'zh-CN,zh;q=0.9',
  53. 'cache-control': 'no-cache',
  54. 'cookie': 'SESSION=YjU3MzgwNTMtM2QyYi00YjljLWI3YWUtZTBjNWYwMGQzYWNl',
  55. 'pragma': 'no-cache',
  56. 'referer': f'https://admin.piaoquantv.com/cms/post-detail/{user_id}/detail',
  57. 'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
  58. 'sec-ch-ua-mobile': '?0',
  59. 'sec-ch-ua-platform': '"macOS"',
  60. 'sec-fetch-dest': 'empty',
  61. 'sec-fetch-mode': 'cors',
  62. 'sec-fetch-site': 'same-origin',
  63. 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
  64. }
  65. response = requests.request("GET", url, headers=headers, data=payload)
  66. data = response.json()
  67. try:
  68. list = []
  69. video_id = data["content"]["id"]
  70. if mark:
  71. status = sqlCollect.is_used(task_mark, video_id, mark, "票圈")
  72. else:
  73. status = True
  74. if status:
  75. if title == '' or title == None:
  76. new_title = data["content"]["title"]
  77. else:
  78. if '/' in title:
  79. titles = [t for t in title.split('/') if t and t != "None"]
  80. else:
  81. titles = [title]
  82. new_title = random.choice(titles)
  83. video_url = data["content"]["transedVideoPath"]
  84. cover = data["content"]["coverImgPath"]
  85. all_data = {"video_id": video_id, "title": new_title, "cover": cover, "video_url": video_url, "rule": "无", "old_title": data["content"]["title"]}
  86. list.append(all_data)
  87. return list
  88. return list
  89. except Exception as e:
  90. Common.logger("video").warning(f"获取视频链接失败:{e}\n")
  91. return ""
  92. """
  93. 获取用户下的所有视频
  94. """
  95. @classmethod
  96. def get_pq_url(cls, task_mark, user_id, number, mark, channel_id, name):
  97. url = f"https://admin.piaoquantv.com/manager/video/page?uid={user_id}&pageNum=1&pageSize=100"
  98. payload = {}
  99. headers = {
  100. 'accept': 'application/json, text/plain, */*',
  101. 'cookie': 'SESSION=NjRmMGVjNTAtNzJiNi00ODE0LThjYzQtYmZiNTJhMDNiZTcz',
  102. 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'
  103. }
  104. response = requests.request("GET", url, headers=headers, data=payload)
  105. data = response.json()
  106. try:
  107. content = data["content"]["objs"]
  108. list = []
  109. for url in content:
  110. video_id = url["id"]
  111. status = sqlCollect.is_used(task_mark, video_id, mark, "票圈")
  112. cover = url["coverImgPath"]
  113. video_url = url["transedVideoPath"]
  114. old_title = url["title"]
  115. log_data = f"user:{user_id},,video_id:{video_id},,video_url:{video_url},,original_title:{old_title}"
  116. AliyunLogger.logging(channel_id, name, user_id, video_id, "扫描到一条视频", "2001", log_data)
  117. if status:
  118. AliyunLogger.logging(channel_id, name, user_id, video_id, "该视频已改造过", "2001", log_data)
  119. continue
  120. AliyunLogger.logging(channel_id, name, user_id, video_id, "符合规则等待改造", "2004", log_data)
  121. all_data = {"video_id": video_id, "cover": cover, "video_url": video_url, "rule": "无", "old_title": old_title}
  122. list.append(all_data)
  123. if len(list) == int(number):
  124. Common.logger("pq").info(f"获取视频总数:{len(list)}\n")
  125. return list
  126. Common.logger("pq").info(f"获取票圈视频总数:{len(list)}\n")
  127. return list
  128. except Exception as e:
  129. Common.logger("pq").warning(f"获取音频视频链接失败:{e}\n")
  130. return ""
  131. """
  132. 获取封面
  133. """
  134. @classmethod
  135. def get_cover(cls, uid):
  136. time.sleep(1)
  137. url = "https://admin.piaoquantv.com/manager/video/multiCover/listV2"
  138. payload = json.dumps({
  139. "videoId": uid,
  140. "range": "2h"
  141. })
  142. headers = {
  143. 'accept': 'application/json',
  144. 'accept-language': 'zh-CN,zh;q=0.9',
  145. 'cache-control': 'no-cache',
  146. 'content-type': 'application/json',
  147. 'cookie': 'SESSION=YjU3MzgwNTMtM2QyYi00YjljLWI3YWUtZTBjNWYwMGQzYWNl',
  148. 'origin': 'https://admin.piaoquantv.com',
  149. 'pragma': 'no-cache',
  150. 'priority': 'u=1, i',
  151. 'sec-ch-ua': '"Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"',
  152. 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'
  153. }
  154. response = requests.request("POST", url, headers=headers, data=payload)
  155. data = response.json()
  156. content = data["content"]
  157. if len(content) == 1:
  158. return content[0]["coverUrl"]
  159. max_share_count = 0
  160. selected_cover_url = ""
  161. for item in content:
  162. share_count = item.get("shareWeight")
  163. if share_count is not None and share_count > max_share_count:
  164. max_share_count = share_count
  165. selected_cover_url = item["coverUrl"]
  166. elif share_count == max_share_count and item["createUser"] == "用户":
  167. selected_cover_url = item["coverUrl"]
  168. return selected_cover_url
  169. """
  170. 获取标题
  171. """
  172. @classmethod
  173. def get_title(cls, uid):
  174. url = "https://admin.piaoquantv.com/manager/video/multiTitleV2/listV2"
  175. payload = json.dumps({
  176. "videoId": uid,
  177. "range": "4h"
  178. })
  179. headers = {
  180. 'accept': 'application/json',
  181. 'accept-language': 'zh-CN,zh;q=0.9',
  182. 'cache-control': 'no-cache',
  183. 'content-type': 'application/json',
  184. 'cookie': 'SESSION=YjU3MzgwNTMtM2QyYi00YjljLWI3YWUtZTBjNWYwMGQzYWNl',
  185. 'origin': 'https://admin.piaoquantv.com',
  186. 'pragma': 'no-cache',
  187. 'priority': 'u=1, i',
  188. 'sec-ch-ua': '"Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"',
  189. 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'
  190. }
  191. response = requests.request("POST", url, headers=headers, data=payload)
  192. data = response.json()
  193. content = data["content"]
  194. if len(content) == 1:
  195. return content[0]["title"]
  196. max_share_count = 0
  197. selected_title = ""
  198. for item in content:
  199. share_count = item.get("shareWeight")
  200. if share_count is not None and share_count > max_share_count:
  201. max_share_count = share_count
  202. selected_title = item["title"]
  203. elif share_count == max_share_count and item["createUser"] == "用户":
  204. selected_title = item["title"]
  205. return selected_title
  206. """
  207. 新生成视频上传到对应账号下
  208. """
  209. @classmethod
  210. def insert_piaoquantv(cls, new_video_path, new_title, cover, n_id):
  211. url = "https://vlogapi.piaoquantv.com/longvideoapi/crawler/video/send"
  212. headers = {
  213. 'User-Agent': 'PQSpeed/486 CFNetwork/1410.1 Darwin/22.6.0',
  214. 'cookie': 'JSESSIONID=4DEA2B5173BB9A9E82DB772C0ACDBC9F; JSESSIONID=D02C334150025222A0B824A98B539B78',
  215. 'referer': 'http://appspeed.piaoquantv.com',
  216. 'token': '524a8bc871dbb0f4d4717895083172ab37c02d2f',
  217. 'accept-language': 'zh-CN,zh-Hans;q=0.9',
  218. 'Content-Type': 'application/x-www-form-urlencoded'
  219. }
  220. payload = {
  221. 'deviceToken': '9ef064f2f7869b3fd67d6141f8a899175dddc91240971172f1f2a662ef891408',
  222. 'fileExtensions': 'MP4',
  223. 'loginUid': n_id,
  224. 'networkType': 'Wi-Fi',
  225. 'platform': 'iOS',
  226. 'requestId': 'fb972cbd4f390afcfd3da1869cd7d001',
  227. 'sessionId': '362290597725ce1fa870d7be4f46dcc2',
  228. 'subSessionId': '362290597725ce1fa870d7be4f46dcc2',
  229. 'title': new_title,
  230. 'token': '524a8bc871dbb0f4d4717895083172ab37c02d2f',
  231. 'uid': n_id,
  232. 'versionCode': '486',
  233. 'versionName': '3.4.12',
  234. 'videoFromScene': '1',
  235. 'videoPath': new_video_path,
  236. 'viewStatus': '1'
  237. }
  238. if cover:
  239. payload['coverImgPath'] = cover
  240. encoded_payload = urlencode(payload)
  241. response = requests.request("POST", url, headers=headers, data=encoded_payload)
  242. data = response.json()
  243. code = data["code"]
  244. if code == 0:
  245. new_video_id = data["data"]["id"]
  246. return new_video_id
  247. else:
  248. return ''
  249. """
  250. 单点视频重新获取视频链接
  251. """
  252. @classmethod
  253. def get_dd_video_url(cls, wx_msg):
  254. try:
  255. url = "http://8.217.190.241:8888/api/wei_xin/msg/callback"
  256. # payload = json.loads(wx_msg)
  257. headers = {
  258. 'Content-Type': 'application/json'
  259. }
  260. response = requests.request("POST", url, headers=headers, data=wx_msg.encode())
  261. response = response.json()
  262. url_video = response['video_url']
  263. return url_video
  264. except Exception as e:
  265. print(e)
  266. return None
  267. "视频号加密视频解密"
  268. @classmethod
  269. def decrypt_video(cls, data: bytes, decode_key: int, enc_length: int = 131072) -> bytes:
  270. try:
  271. ffi = cffi.FFI()
  272. # lib = ffi.dlopen(r'/Users/tzld/Desktop/video_rewriting/libsph_decrypt.dylib')
  273. lib = ffi.dlopen(r'/root/video_rewriting/libsph_decrypt.so')
  274. ffi.cdef('void decrypt(unsigned char *data, const size_t data_length, const uint32_t key);')
  275. c_data = ffi.new('unsigned char[]', list(data))
  276. lib.decrypt(c_data, enc_length, decode_key)
  277. data = bytes(ffi.buffer(c_data, len(data))[:])
  278. return data
  279. except Exception as e:
  280. Common.logger("dd-sph").info(f"decrypt_video获取异常,异常信息{e}")
  281. return data
  282. """
  283. 单点视频号视频下载
  284. """
  285. @classmethod
  286. def dd_sph_download_video(cls, video_url, video_path_url, video_id, video, channel_id):
  287. if channel_id == '单点视频':
  288. is_encrypted = video.get('is_encrypted', "0")
  289. if video['source'] == "视频号" and int(is_encrypted) == 1:
  290. decode_key = video['decode_key']
  291. if decode_key == None:
  292. return None
  293. decode_key = int(video['decode_key'])
  294. data, enc_length = None, 0
  295. for i in range(3):
  296. try:
  297. response = requests.get(url=video_url, timeout=10)
  298. data = response.content
  299. data_length = int(response.headers.get("Content-Range", '0').split('/')[-1])
  300. enc_length = int(response.headers.get('X-enclen', 131072))
  301. if len(data) == data_length:
  302. break
  303. except TimeoutError:
  304. continue
  305. if not data:
  306. v_id = video["video_id"]
  307. sqlCollect.update_shp_dd_vid_4(v_id)
  308. from_user_name = video['from_user_name'] # 来源用户
  309. from_group_name = video['from_group_name'] # 来源群组
  310. source = video['source'] # 渠道
  311. text = (
  312. f"**渠道**: {source}\n"
  313. f"**来源用户**: {from_user_name}\n"
  314. f"**来源群组**: {from_group_name}\n"
  315. f"**原视频链接**: {video['video_url']}\n"
  316. f"**原视频封面**: {video['cover']}\n"
  317. f"**原视频标题**: {video['old_title']}\n"
  318. )
  319. Feishu.finish_bot(text,
  320. "https://open.feishu.cn/open-apis/bot/v2/hook/493b3d4c-5fae-4a9d-980b-1dd86636524e",
  321. "【 视频下载失败 】")
  322. return None
  323. video_url = cls.decrypt_video(data=data, decode_key=decode_key, enc_length=enc_length)
  324. url_video = video_url
  325. new_video = video_path_url + str(video_id) + '.mp4'
  326. for i in range(3):
  327. try:
  328. if video['source'] == "视频号" and int(video.get('is_encrypted', "0")) == 1:
  329. with open(f"{new_video}", 'wb') as f:
  330. f.write(url_video)
  331. return new_video
  332. else:
  333. payload = {}
  334. headers = {}
  335. response = requests.request("GET", url_video, headers=headers, data=payload)
  336. if response.status_code == 200:
  337. with open(f"{new_video}", "wb") as file:
  338. # 将响应内容写入文件
  339. file.write(response.content)
  340. time.sleep(5)
  341. return new_video
  342. else:
  343. if channel_id == '单点视频':
  344. wx_msg = video['wx_msg']
  345. if wx_msg:
  346. url_videos = cls.get_dd_video_url(wx_msg)
  347. if url_videos:
  348. url_video = url_videos
  349. except Exception:
  350. if channel_id == '单点视频':
  351. wx_msg = video['wx_msg']
  352. if wx_msg:
  353. url_videos = cls.get_dd_video_url(wx_msg)
  354. if url_videos:
  355. url_video = url_videos
  356. if i == 3:
  357. return None
  358. return None
  359. """
  360. 视频号视频下载
  361. """
  362. @classmethod
  363. def sph_download_video(cls, video_url, video_path_url, video_id, video):
  364. decode_key = int(video['decode_key'])
  365. data, enc_length = None, 0
  366. for i in range(3):
  367. try:
  368. response = requests.get(url=video_url, timeout=10)
  369. data = response.content
  370. data_length = int(response.headers.get("Content-Range", '0').split('/')[-1])
  371. enc_length = int(response.headers.get('X-enclen', 131072))
  372. if len(data) == data_length:
  373. break
  374. except TimeoutError:
  375. continue
  376. if not data:
  377. return None
  378. video_url = cls.decrypt_video(data=data, decode_key=decode_key, enc_length=enc_length)
  379. new_video = video_path_url + str(video_id) + '.mp4'
  380. for i in range(3):
  381. try:
  382. with open(f"{new_video}", 'wb') as f:
  383. f.write(video_url)
  384. return new_video
  385. except Exception:
  386. if i == 3:
  387. return None
  388. """票圈/快手创作者"""
  389. @classmethod
  390. def download_video(cls, video_url, video_path_url, video_id):
  391. try:
  392. for i in range(3):
  393. payload = {}
  394. headers = {}
  395. response = requests.request("GET", video_url, headers=headers, data=payload)
  396. if response.status_code == 200:
  397. # 以二进制写入模式打开文件
  398. video = video_path_url + str(video_id) + '.mp4'
  399. with open(f"{video}", "wb") as file:
  400. # 将响应内容写入文件
  401. file.write(response.content)
  402. time.sleep(5)
  403. return video
  404. return None
  405. except Exception:
  406. return None
  407. """
  408. 票圈站内视频下载
  409. """
  410. @classmethod
  411. def download_video_jpg(cls, video_url, video_path_url, video_id):
  412. try:
  413. payload = {}
  414. headers = {}
  415. response = requests.request("GET", video_url, headers=headers, data=payload)
  416. if response.status_code == 200:
  417. # 以二进制写入模式打开文件
  418. video = video_path_url + str(video_id) + '.jpg'
  419. with open(f"{video}", "wb") as file:
  420. # 将响应内容写入文件
  421. file.write(response.content)
  422. time.sleep(5)
  423. return video
  424. except Exception:
  425. return None
  426. if __name__ == '__main__':
  427. url= 'http://111.51.148.73/ksc1/55LDHcm2DuGHbBbzIDfqMh-vfVhaCuIXZG0szwmCZj9pXLmq7otQhUyGXtBtc13Rb0C49a4FzRU5xfUaRQb6De46IO6hQBVqzjOkFArRDfTC7u9BThi0Bsa2w6PP_6dg7WQYKxU6ZIbYI2tnLfOXU5Ira-DEZuGDQbgpZstADnGtvLMkOiB6DImlhfgdxWIZ.mp4?tag=1-1724839019-sp-0-lgl7lhkrnt-8937a5c247b0f313&provider=self&ocid=341&clientCacheKey=3x3br4x5z5hew32_bF.mp4&tt=bF&di=6f31a709&bp=10001'
  428. video = {"wx_msg": '{"TypeName":"AddMsg","Appid":"wx_GtAew_wmLbsHMbpDe7Hwk","Data":{"MsgId":1176686077,"FromUserName":{"string":"51757111911@chatroom"},"ToUserName":{"string":"wxid_mr9pdsanc99422"},"MsgType":1,"Content":{"string":"wxid_3379403802612:\n6.41 复制打开抖音,看看【Zooey的作品】被一只青蛙问候了?! https://v.douyin.com/ihHknvbV/ w@f.bA YZm:/ 06/05 "},"Status":3,"ImgStatus":1,"ImgBuf":{"iLen":0},"CreateTime":1725343506,"MsgSource":"<msgsource>\n\t<bizflag>0</bizflag>\n\t<pua>1</pua>\n\t<alnode>\n\t\t<cf>3</cf>\n\t\t<inlenlist>86</inlenlist>\n\t</alnode>\n\t<silence>1</silence>\n\t<membercount>4</membercount>\n\t<signature>V1_pVkC6xlw|v1_pVkC6xlw</signature>\n\t<tmp_node>\n\t\t<publisher-id></publisher-id>\n\t</tmp_node>\n</msgsource>\n","NewMsgId":6473116084228305363,"MsgSeq":776685968},"Wxid":"wxid_mr9pdsanc99422"}'}
  429. a = PQ.download_video(url,'/Users/tzld/Desktop/video_rewriting/path','70100016',video,'单点视频')
  430. print(a)