piaoquan.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  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
  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 download_video(cls, video_url, video_path_url, video_id, video, channel_id):
  287. if channel_id == '单点视频':
  288. if video['source'] == "视频号" and int(video['is_encrypted']) == 1:
  289. decode_key = int(video['decode_key'])
  290. response = requests.get(url=video_url)
  291. data = response.content
  292. enc_length = int(response.headers.get('X-enclen', 131072))
  293. video_url = cls.decrypt_video(data=data, decode_key=decode_key, enc_length=enc_length)
  294. url_video = video_url
  295. new_video = video_path_url + str(video_id) + '.mp4'
  296. for i in range(3):
  297. try:
  298. if video['source'] == "视频号" and int(video['is_encrypted']) == 1:
  299. with open(f"{new_video}", 'wb') as f:
  300. f.write(url_video)
  301. return new_video
  302. else:
  303. payload = {}
  304. headers = {}
  305. response = requests.request("GET", url_video, headers=headers, data=payload)
  306. if response.status_code == 200:
  307. with open(f"{new_video}", "wb") as file:
  308. # 将响应内容写入文件
  309. file.write(response.content)
  310. time.sleep(5)
  311. return new_video
  312. else:
  313. if channel_id == '单点视频':
  314. wx_msg = video['wx_msg']
  315. if wx_msg:
  316. url_videos = cls.get_dd_video_url(wx_msg)
  317. if url_videos:
  318. url_video = url_videos
  319. except Exception:
  320. if channel_id == '单点视频':
  321. wx_msg = video['wx_msg']
  322. if wx_msg:
  323. url_videos = cls.get_dd_video_url(wx_msg)
  324. if url_videos:
  325. url_video = url_videos
  326. if i == 3:
  327. return new_video
  328. return new_video
  329. """
  330. 票圈站内视频下载
  331. """
  332. @classmethod
  333. def download_video_jpg(cls, video_url, video_path_url, video_id):
  334. try:
  335. payload = {}
  336. headers = {}
  337. response = requests.request("GET", video_url, headers=headers, data=payload)
  338. if response.status_code == 200:
  339. # 以二进制写入模式打开文件
  340. video = video_path_url + str(video_id) + '.jpg'
  341. with open(f"{video}", "wb") as file:
  342. # 将响应内容写入文件
  343. file.write(response.content)
  344. time.sleep(5)
  345. return video
  346. except Exception:
  347. return None
  348. if __name__ == '__main__':
  349. 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'
  350. 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"}'}
  351. a = PQ.download_video(url,'/Users/tzld/Desktop/video_rewriting/path','70100016',video,'单点视频')
  352. print(a)