piaoquan.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. import random
  2. import re
  3. import time
  4. import json
  5. import cffi
  6. import requests
  7. from urllib.parse import urlencode, urlparse
  8. from common import 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. return ""
  41. """
  42. 获取视频链接
  43. """
  44. @classmethod
  45. def get_audio_url(cls, task_mark, user_id, title, mark):
  46. url = f"https://admin.piaoquantv.com/manager/video/detail/{user_id}"
  47. payload = {}
  48. headers = {
  49. 'authority': 'admin.piaoquantv.com',
  50. 'accept': 'application/json, text/plain, */*',
  51. 'accept-language': 'zh-CN,zh;q=0.9',
  52. 'cache-control': 'no-cache',
  53. 'cookie': 'SESSION=YjU3MzgwNTMtM2QyYi00YjljLWI3YWUtZTBjNWYwMGQzYWNl',
  54. 'pragma': 'no-cache',
  55. 'referer': f'https://admin.piaoquantv.com/cms/post-detail/{user_id}/detail',
  56. 'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
  57. 'sec-ch-ua-mobile': '?0',
  58. 'sec-ch-ua-platform': '"macOS"',
  59. 'sec-fetch-dest': 'empty',
  60. 'sec-fetch-mode': 'cors',
  61. 'sec-fetch-site': 'same-origin',
  62. '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'
  63. }
  64. response = requests.request("GET", url, headers=headers, data=payload)
  65. data = response.json()
  66. try:
  67. list = []
  68. video_id = data["content"]["id"]
  69. if mark:
  70. status = sqlCollect.is_used(task_mark, video_id, mark, "票圈")
  71. else:
  72. status = True
  73. if status:
  74. if title == '' or title == None:
  75. new_title = data["content"]["title"]
  76. else:
  77. if '/' in title:
  78. titles = [t for t in title.split('/') if t and t != "None"]
  79. else:
  80. titles = [title]
  81. new_title = random.choice(titles)
  82. video_url = data["content"]["transedVideoPath"]
  83. cover = data["content"]["coverImgPath"]
  84. all_data = {"video_id": video_id, "title": new_title, "cover": cover, "video_url": video_url, "rule": "无", "old_title": data["content"]["title"]}
  85. list.append(all_data)
  86. return list
  87. return list
  88. except Exception as e:
  89. return ""
  90. """
  91. 获取用户下的所有视频
  92. """
  93. @classmethod
  94. def get_pq_url(cls, task_mark, user_id, number, mark, channel_id, name):
  95. url = f"https://admin.piaoquantv.com/manager/video/page?uid={user_id}&pageNum=1&pageSize=100"
  96. payload = {}
  97. headers = {
  98. 'accept': 'application/json, text/plain, */*',
  99. 'cookie': 'SESSION=NjRmMGVjNTAtNzJiNi00ODE0LThjYzQtYmZiNTJhMDNiZTcz',
  100. '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'
  101. }
  102. list = []
  103. try:
  104. response = requests.request("GET", url, headers=headers, data=payload)
  105. data = response.json()
  106. content = data["content"]["objs"]
  107. for url in content:
  108. video_id = url["id"]
  109. status = sqlCollect.is_used(video_id, mark, "票圈")
  110. cover = url["coverImgPath"]
  111. video_url = url["transedVideoPath"]
  112. old_title = url["title"]
  113. log_data = f"user:{user_id},,video_id:{video_id},,video_url:{video_url},,original_title:{old_title}"
  114. AliyunLogger.logging(channel_id, name, user_id, video_id, "扫描到一条视频", "2001", log_data)
  115. if status:
  116. AliyunLogger.logging(channel_id, name, user_id, video_id, "该视频已改造过", "2002", log_data)
  117. continue
  118. AliyunLogger.logging(channel_id, name, user_id, video_id, "符合规则等待改造", "2004", log_data)
  119. all_data = {"video_id": video_id, "cover": cover, "video_url": video_url, "rule": "无", "old_title": old_title}
  120. list.append(all_data)
  121. if len(list) == int(number):
  122. return list
  123. return list
  124. except Exception as e:
  125. return list
  126. """
  127. 获取封面
  128. """
  129. @classmethod
  130. def get_cover(cls, uid):
  131. time.sleep(1)
  132. url = "https://admin.piaoquantv.com/manager/video/multiCover/listV2"
  133. payload = json.dumps({
  134. "videoId": uid,
  135. "range": "2h"
  136. })
  137. headers = {
  138. 'accept': 'application/json',
  139. 'accept-language': 'zh-CN,zh;q=0.9',
  140. 'cache-control': 'no-cache',
  141. 'content-type': 'application/json',
  142. 'cookie': 'SESSION=YjU3MzgwNTMtM2QyYi00YjljLWI3YWUtZTBjNWYwMGQzYWNl',
  143. 'origin': 'https://admin.piaoquantv.com',
  144. 'pragma': 'no-cache',
  145. 'priority': 'u=1, i',
  146. 'sec-ch-ua': '"Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"',
  147. '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'
  148. }
  149. response = requests.request("POST", url, headers=headers, data=payload)
  150. data = response.json()
  151. content = data["content"]
  152. if len(content) == 1:
  153. return content[0]["coverUrl"]
  154. max_share_count = 0
  155. selected_cover_url = ""
  156. for item in content:
  157. share_count = item.get("shareWeight")
  158. if share_count is not None and share_count > max_share_count:
  159. max_share_count = share_count
  160. selected_cover_url = item["coverUrl"]
  161. elif share_count == max_share_count and item["createUser"] == "用户":
  162. selected_cover_url = item["coverUrl"]
  163. return selected_cover_url
  164. """
  165. 获取标题
  166. """
  167. @classmethod
  168. def get_title(cls, uid):
  169. url = "https://admin.piaoquantv.com/manager/video/multiTitleV2/listV2"
  170. payload = json.dumps({
  171. "videoId": uid,
  172. "range": "4h"
  173. })
  174. headers = {
  175. 'accept': 'application/json',
  176. 'accept-language': 'zh-CN,zh;q=0.9',
  177. 'cache-control': 'no-cache',
  178. 'content-type': 'application/json',
  179. 'cookie': 'SESSION=YjU3MzgwNTMtM2QyYi00YjljLWI3YWUtZTBjNWYwMGQzYWNl',
  180. 'origin': 'https://admin.piaoquantv.com',
  181. 'pragma': 'no-cache',
  182. 'priority': 'u=1, i',
  183. 'sec-ch-ua': '"Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"',
  184. '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'
  185. }
  186. response = requests.request("POST", url, headers=headers, data=payload)
  187. data = response.json()
  188. content = data["content"]
  189. if len(content) == 1:
  190. return content[0]["title"]
  191. max_share_count = 0
  192. selected_title = ""
  193. for item in content:
  194. share_count = item.get("shareWeight")
  195. if share_count is not None and share_count > max_share_count:
  196. max_share_count = share_count
  197. selected_title = item["title"]
  198. elif share_count == max_share_count and item["createUser"] == "用户":
  199. selected_title = item["title"]
  200. return selected_title
  201. """
  202. 新生成视频上传到对应账号下
  203. """
  204. @classmethod
  205. def insert_piaoquantv(cls, new_video_path, new_title, cover, n_id):
  206. url = "https://vlogapi.piaoquantv.com/longvideoapi/crawler/video/send"
  207. headers = {
  208. 'User-Agent': 'PQSpeed/486 CFNetwork/1410.1 Darwin/22.6.0',
  209. 'cookie': 'JSESSIONID=4DEA2B5173BB9A9E82DB772C0ACDBC9F; JSESSIONID=D02C334150025222A0B824A98B539B78',
  210. 'referer': 'http://appspeed.piaoquantv.com',
  211. 'token': '524a8bc871dbb0f4d4717895083172ab37c02d2f',
  212. 'accept-language': 'zh-CN,zh-Hans;q=0.9',
  213. 'Content-Type': 'application/x-www-form-urlencoded'
  214. }
  215. payload = {
  216. 'deviceToken': '9ef064f2f7869b3fd67d6141f8a899175dddc91240971172f1f2a662ef891408',
  217. 'fileExtensions': 'MP4',
  218. 'loginUid': n_id,
  219. 'networkType': 'Wi-Fi',
  220. 'platform': 'iOS',
  221. 'requestId': 'fb972cbd4f390afcfd3da1869cd7d001',
  222. 'sessionId': '362290597725ce1fa870d7be4f46dcc2',
  223. 'subSessionId': '362290597725ce1fa870d7be4f46dcc2',
  224. 'title': new_title,
  225. 'token': '524a8bc871dbb0f4d4717895083172ab37c02d2f',
  226. 'uid': n_id,
  227. 'versionCode': '486',
  228. 'versionName': '3.4.12',
  229. 'videoFromScene': '1',
  230. 'videoPath': new_video_path,
  231. 'viewStatus': '1'
  232. }
  233. if cover:
  234. payload['coverImgPath'] = cover
  235. encoded_payload = urlencode(payload)
  236. response = requests.request("POST", url, headers=headers, data=encoded_payload)
  237. data = response.json()
  238. code = data["code"]
  239. if code == 0:
  240. new_video_id = data["data"]["id"]
  241. return new_video_id
  242. else:
  243. return ''
  244. """
  245. 单点视频重新获取视频链接
  246. """
  247. @classmethod
  248. def get_dd_video_url(cls, wx_msg):
  249. try:
  250. url = "http://8.217.190.241:8888/api/wei_xin/msg/callback"
  251. # payload = json.loads(wx_msg)
  252. headers = {
  253. 'Content-Type': 'application/json'
  254. }
  255. response = requests.request("POST", url, headers=headers, data=wx_msg.encode())
  256. response = response.json()
  257. url_video = response['video_url']
  258. return url_video
  259. except Exception as e:
  260. print(e)
  261. return url_video
  262. "视频号加密视频解密"
  263. @classmethod
  264. def decrypt_video(cls, data: bytes, decode_key: int, enc_length: int = 131072) -> bytes:
  265. try:
  266. ffi = cffi.FFI()
  267. # lib = ffi.dlopen(r'/Users/tzld/Desktop/video_rewriting/libsph_decrypt.dylib')
  268. lib = ffi.dlopen(r'/root/video_rewriting/libsph_decrypt.so')
  269. ffi.cdef('void decrypt(unsigned char *data, const size_t data_length, const uint32_t key);')
  270. c_data = ffi.new('unsigned char[]', list(data))
  271. lib.decrypt(c_data, enc_length, decode_key)
  272. data = bytes(ffi.buffer(c_data, len(data))[:])
  273. return data
  274. except Exception as e:
  275. return data
  276. """
  277. 单点视频号视频下载
  278. """
  279. @classmethod
  280. def dd_sph_download_video(cls, video_url, video_path_url, video_id, video, channel_id):
  281. new_video = video_path_url + str(video_id) + '.mp4'
  282. if channel_id == '单点视频':
  283. is_encrypted = video.get('is_encrypted', "0")
  284. if video['source'] == "视频号" and int(is_encrypted) == 1:
  285. decode_key = video['decode_key']
  286. if decode_key == None:
  287. return new_video
  288. decode_key = int(video['decode_key'])
  289. data, enc_length = None, 0
  290. for i in range(3):
  291. try:
  292. response = requests.get(url=video_url, timeout=10)
  293. data = response.content
  294. data_length = int(response.headers.get("Content-Range", '0').split('/')[-1])
  295. enc_length = int(response.headers.get('X-enclen', 131072))
  296. if len(data) == data_length:
  297. break
  298. except TimeoutError:
  299. continue
  300. if not data:
  301. v_id = video["video_id"]
  302. sqlCollect.update_shp_dd_vid_4(v_id)
  303. from_user_name = video['from_user_name'] # 来源用户
  304. from_group_name = video['from_group_name'] # 来源群组
  305. source = video['source'] # 渠道
  306. text = (
  307. f"**渠道**: {source}\n"
  308. f"**来源用户**: {from_user_name}\n"
  309. f"**来源群组**: {from_group_name}\n"
  310. f"**原视频链接**: {video['video_url']}\n"
  311. f"**原视频封面**: {video['cover']}\n"
  312. f"**原视频标题**: {video['old_title']}\n"
  313. )
  314. Feishu.finish_bot(text,
  315. "https://open.feishu.cn/open-apis/bot/v2/hook/493b3d4c-5fae-4a9d-980b-1dd86636524e",
  316. "【 视频下载失败 】")
  317. return new_video
  318. video_url = cls.decrypt_video(data=data, decode_key=decode_key, enc_length=enc_length)
  319. with open(f"{new_video}", 'wb') as f:
  320. f.write(video_url)
  321. return new_video
  322. url_video = video_url
  323. for i in range(3):
  324. try:
  325. payload = {}
  326. headers = {}
  327. response = requests.request("GET", url_video, headers=headers, data=payload)
  328. if response.status_code == 200:
  329. with open(f"{new_video}", "wb") as file:
  330. # 将响应内容写入文件
  331. file.write(response.content)
  332. time.sleep(5)
  333. return new_video
  334. else:
  335. if channel_id == '单点视频':
  336. wx_msg = video['wx_msg']
  337. if wx_msg:
  338. url_videos = cls.get_dd_video_url(wx_msg)
  339. if url_videos:
  340. url_video = url_videos
  341. except Exception:
  342. if channel_id == '单点视频':
  343. wx_msg = video['wx_msg']
  344. if wx_msg:
  345. url_videos = cls.get_dd_video_url(wx_msg)
  346. if url_videos:
  347. url_video = url_videos
  348. if i == 3:
  349. return new_video
  350. return new_video
  351. """
  352. 视频号视频下载
  353. """
  354. @classmethod
  355. def sph_download_video(cls, video_url, video_path_url, video_id, video):
  356. new_video = video_path_url + str(video_id) + '.mp4'
  357. decode_key = int(video['decode_key'])
  358. data, enc_length = None, 0
  359. for i in range(3):
  360. try:
  361. response = requests.get(url=video_url, timeout=10)
  362. data = response.content
  363. data_length = int(response.headers.get("Content-Range", '0').split('/')[-1])
  364. enc_length = int(response.headers.get('X-enclen', 131072))
  365. if len(data) == data_length:
  366. break
  367. except TimeoutError:
  368. continue
  369. if not data:
  370. return new_video
  371. video_url = cls.decrypt_video(data=data, decode_key=decode_key, enc_length=enc_length)
  372. for i in range(3):
  373. try:
  374. with open(f"{new_video}", 'wb') as f:
  375. f.write(video_url)
  376. return new_video
  377. except Exception:
  378. if i == 3:
  379. return new_video
  380. """票圈/快手创作者"""
  381. @classmethod
  382. def download_video(cls, video_url, video_path_url, video_id):
  383. video = video_path_url + str(video_id) + '.mp4'
  384. try:
  385. for i in range(3):
  386. payload = {}
  387. headers = {}
  388. response = requests.request("GET", video_url, headers=headers, data=payload)
  389. if response.status_code == 200:
  390. # 以二进制写入模式打开文件
  391. with open(f"{video}", "wb") as file:
  392. # 将响应内容写入文件
  393. file.write(response.content)
  394. time.sleep(5)
  395. return video
  396. return None
  397. except Exception:
  398. return video
  399. """抖音"""
  400. @classmethod
  401. def download_dy_video(cls, video_url, video_path_url, video_id):
  402. video = video_path_url + str(video_id) + '.mp4'
  403. try:
  404. for i in range(3):
  405. payload = {}
  406. headers = {
  407. 'accept': '*/*',
  408. 'accept-encoding': 'identity;q=1, *;q=0',
  409. 'accept-language': 'zh-CN,zh;q=0.9',
  410. 'cache-control': 'no-cache',
  411. 'connection': 'keep-alive',
  412. 'pragma': 'no-cache',
  413. 'range': 'bytes=0-',
  414. 'referer': f'https://www.douyin.com/video/{video_id}',
  415. 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
  416. }
  417. response = requests.request("GET", video_url, headers=headers, data=payload, timeout= 60)
  418. if response.status_code == 206:
  419. # 以二进制写入模式打开文件
  420. with open(f"{video}", "wb") as file:
  421. # 将响应内容写入文件
  422. file.write(response.content)
  423. time.sleep(5)
  424. return video
  425. return video
  426. except Exception as e:
  427. print(e)
  428. return video
  429. """
  430. 票圈站内视频下载
  431. """
  432. @classmethod
  433. def download_video_jpg(cls, video_url, video_path_url, video_id):
  434. video = video_path_url + str(video_id) + '.jpg'
  435. try:
  436. payload = {}
  437. headers = {}
  438. response = requests.request("GET", video_url, headers=headers, data=payload)
  439. if response.status_code == 200:
  440. # 以二进制写入模式打开文件
  441. with open(f"{video}", "wb") as file:
  442. # 将响应内容写入文件
  443. file.write(response.content)
  444. time.sleep(5)
  445. return video
  446. except Exception:
  447. return video
  448. if __name__ == '__main__':
  449. url ='https://v5-dy-o-abtest.zjcdn.com/24958f9e7ef091a31c409c0dd1e83a6f/675fc6bc/video/tos/cn/tos-cn-ve-15/oIB5AwLndiATiANQIziB1TfHED3igPr1AD5Kje/?a=1128&ch=11&cr=3&dr=0&lr=all&cd=0%7C0%7C0%7C3&cv=1&br=515&bt=515&cs=0&ds=6&ft=J33IIDDhNF5VQsYesNousauzXzySY~bbUBvThbLfK&mime_type=video_mp4&qs=0&rc=aTg2M2Y3ZjU1NGg3ZTU8aUBpamVoZ285cjh0djMzNGkzM0AxNjIzYjUuNV4xXmFiLTRiYSMwM2FlMmRjY3BgLS1kLTBzcw%3D%3D&btag=80010e000b0001&cc=46&cquery=105E_103Q_103W_103Y_100b&dy_q=1734326142&feature_id=f0150a16a324336cda5d6dd0b69ed299&l=20241216131541780499AB5185B80CA219&req_cdn_type='
  450. a = PQ.download_dy_video(url,'/Users/z/Downloads/','70100016')
  451. print(a)