utils.py 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105
  1. import traceback
  2. import requests
  3. import json
  4. import time
  5. import gevent
  6. import pandas as pd
  7. import random
  8. from datetime import datetime
  9. # from db_helper import HologresHelper, RedisHelper, MysqlHelper
  10. from db_helper import RedisHelper, MysqlHelper
  11. from config import set_config
  12. from log import Log
  13. from parameter_update import param_update_risk_rule
  14. from parameter_update import param_update_risk_videos
  15. from parameter_update import param_update_risk_filter_flag
  16. config_ = set_config()
  17. log_ = Log()
  18. HOLIDAY_KV = {
  19. "2023-12-25":"圣诞节",
  20. "2024-01-01":"元旦",
  21. "2024-01-18":"腊八节",
  22. "2024-02-02":"小年",
  23. "2024-02-03":"小年",
  24. "2024-02-09":"除夕",
  25. "2024-02-10":"春节",
  26. "2024-02-14":"情人节",
  27. "2024-02-24":"元宵节",
  28. "2024-03-11":"龙抬头",
  29. "2024-03-08":"妇女节",
  30. "2024-05-01":"劳动节",
  31. "2024-05-12":"母亲节",
  32. "2024-06-01":"儿童节",
  33. "2024-06-10":"端午节",
  34. "2024-06-16":"父亲节",
  35. "2024-07-01":"建党节",
  36. "2024-07-07":"七七事变",
  37. "2024-08-01":"建军节",
  38. "2024-08-10":"七夕节",
  39. "2024-08-18":"中元节",
  40. "2024-09-17":"中秋节",
  41. "2024-09-09":"毛主席逝世",
  42. "2024-10-01":"国庆节",
  43. "2024-10-11":"重阳节",
  44. "2024-11-28":"感恩节",
  45. "2024-12-13":"公祭日",
  46. "2024-12-24":"平安夜",
  47. "2024-12-25":"圣诞节",
  48. "2024-12-26":"毛主席诞辰",
  49. "2024-01-06":"小寒",
  50. "2024-01-20":"大寒",
  51. "2024-02-04":"立春",
  52. "2024-02-19":"雨水",
  53. "2024-03-05":"惊蛰",
  54. "2024-03-20":"春分",
  55. "2024-04-04":"清明",
  56. "2024-04-19":"谷雨",
  57. "2024-05-05":"立夏",
  58. "2024-05-20":"小满",
  59. "2024-06-05":"芒种",
  60. "2024-06-21":"夏至",
  61. "2024-07-06":"小暑",
  62. "2024-07-22":"大暑",
  63. "2024-08-07":"立秋",
  64. "2024-08-22":"处暑",
  65. "2024-09-07":"白露",
  66. "2024-09-22":"秋分",
  67. "2024-10-08":"寒露",
  68. "2024-10-23":"霜降",
  69. "2024-11-07":"立冬",
  70. "2024-11-22":"小雪",
  71. "2024-12-06":"大雪",
  72. "2024-12-21":"冬至",
  73. "2025-01-01":"元旦",
  74. "2025-01-07":"腊八节",
  75. "2025-01-22":"小年",
  76. "2025-01-23":"小年",
  77. "2025-01-28":"除夕",
  78. "2025-01-29":"春节",
  79. "2025-02-14":"情人节",
  80. "2025-02-22":"元宵节",
  81. "2025-03-01":"龙抬头",
  82. "2025-03-08":"妇女节",
  83. "2025-05-01":"劳动节",
  84. "2025-05-11":"母亲节",
  85. "2025-06-01":"儿童节",
  86. "2025-05-31":"端午节",
  87. "2025-06-15":"父亲节",
  88. "2025-07-01":"建党节",
  89. "2054-07-07":"七七事变",
  90. "2025-08-01":"建军节",
  91. "2025-08-29":"七夕节",
  92. "2025-09-06":"中元节",
  93. "2025-10-06":"中秋节",
  94. "2025-09-09":"毛主席逝世",
  95. "2025-10-01":"国庆节",
  96. "2025-10-29":"重阳节",
  97. "2024-11-27":"感恩节",
  98. "2025-12-13":"公祭日",
  99. "2025-12-24":"平安夜",
  100. "2025-12-25":"圣诞节",
  101. "2025-12-26":"毛主席诞辰",
  102. "2025-01-05":"小寒",
  103. "2025-01-20":"大寒",
  104. "2025-02-03":"立春",
  105. "2025-02-18":"雨水",
  106. "2025-03-05":"惊蛰",
  107. "2025-03-20":"春分",
  108. "2025-04-04":"清明",
  109. "2025-04-20":"谷雨",
  110. "2025-05-05":"立夏",
  111. "2025-05-21":"小满",
  112. "2025-06-05":"芒种",
  113. "2025-06-21":"夏至",
  114. "2025-07-07":"小暑",
  115. "2025-07-22":"大暑",
  116. "2025-08-07":"立秋",
  117. "2025-08-23":"处暑",
  118. "2025-09-07":"白露",
  119. "2025-09-23":"秋分",
  120. "2025-10-08":"寒露",
  121. "2025-10-23":"霜降",
  122. "2025-11-07":"立冬",
  123. "2025-11-22":"小雪",
  124. "2025-12-07":"大雪",
  125. "2025-12-21":"冬至",
  126. }
  127. def send_msg_to_feishu(msg_text):
  128. """发送消息到飞书"""
  129. # webhook地址
  130. webhook = 'https://open.feishu.cn/open-apis/bot/v2/hook/8de4de35-30ed-4692-8854-7a154e89b2f2'
  131. # 自定义关键词key_word
  132. key_word = '服务报警'
  133. headers = {'Content-Type': 'application/json'}
  134. payload_message = {
  135. "msg_type": "text",
  136. "content": {
  137. "text": '{}: {}'.format(key_word, msg_text)
  138. }
  139. }
  140. response = requests.request('POST', url=webhook, headers=headers, data=json.dumps(payload_message))
  141. # print(response.text)
  142. def request_post(request_url, request_data, timeout):
  143. """
  144. post 请求 HTTP接口
  145. :param request_url: 接口URL
  146. :param request_data: 请求参数
  147. :param timeout: 超时时间,单位为秒,type-float or tuple(connect_timeout, read_timeout)
  148. :return: res_data json格式
  149. """
  150. try:
  151. headers = {"Connection": "close"}
  152. #print(request_url)
  153. #print(headers)
  154. response = requests.post(url=request_url, json=request_data, timeout=timeout, headers=headers)
  155. #print("response:", response)
  156. if response.status_code == 200:
  157. res_data = json.loads(response.text)
  158. return res_data
  159. else:
  160. return None
  161. except Exception as e:
  162. #print(e)
  163. log_.error('url: {}, exception: {}, traceback: {}'.format(request_url, e, traceback.format_exc()))
  164. return None
  165. def request_post_data(request_url, request_data, timeout):
  166. """
  167. post 请求 HTTP接口
  168. :param request_url: 接口URL
  169. :param request_data: 请求参数
  170. :param timeout: 超时时间,单位为秒,type-float or tuple(connect_timeout, read_timeout)
  171. :return: res_data json格式
  172. """
  173. try:
  174. headers = {'content-type': 'application/json'}
  175. response = requests.post(url=request_url, data=request_data, timeout=timeout, headers=headers)
  176. #print("response:", response)
  177. if response.status_code == 200:
  178. res_data = json.loads(response.text)
  179. return res_data['outputs']
  180. else:
  181. return None
  182. except Exception as e:
  183. #print(e)
  184. log_.error('url: {}, exception: {}, traceback: {}'.format(request_url, e, traceback.format_exc()))
  185. return None
  186. def request_get(request_url, timeout):
  187. """
  188. get 请求 HTTP接口
  189. :param request_url: 接口URL
  190. :param timeout: 超时时间,单位为秒,type-float or tuple(connect_timeout, read_timeout)
  191. :return: res_data json格式
  192. """
  193. try:
  194. response = requests.get(url=request_url, timeout=timeout)
  195. if response.status_code == 200:
  196. res_data = json.loads(response.text)
  197. return res_data
  198. else:
  199. return None
  200. except Exception as e:
  201. log_.error('url: {}, exception: {}, traceback: {}'.format(request_url, e, traceback.format_exc()))
  202. return None
  203. def get_user_has30day_return(mid):
  204. """
  205. 获取用户近30天是否有回流
  206. :param mid: mid
  207. :return: data, type
  208. """
  209. if not mid:
  210. return None
  211. # 获取redis中存储的状态值
  212. user_key = f"{config_.KEY_NAME_PREFIX_USER_HAS30DAY_RETURN}{mid}"
  213. redis_helper = RedisHelper()
  214. data = redis_helper.get_data_from_redis(key_name=user_key)
  215. if data is not None:
  216. return int(data)
  217. else:
  218. request_url = f"{config_.GET_USER_30DayReturnCnt_URL}{mid}"
  219. result = request_get(request_url=request_url, timeout=0.1)
  220. if result is None:
  221. return None
  222. if result['code'] != 0:
  223. return None
  224. data = result['data']
  225. if data is True:
  226. redis_data = 1
  227. else:
  228. redis_data = 0
  229. redis_helper.set_data_to_redis(key_name=user_key, value=redis_data, expire_time=2 * 3600)
  230. return redis_data
  231. def get_videos_remain_view_count(app_type, videos):
  232. """
  233. 获取视频在流量池中的剩余可分发数
  234. :param app_type: 产品标识 type-int
  235. :param videos: 视频信息 (视频id, 流量池标记) type-list,[{'videoId': video_id, 'flowPool': flow_pool}, ...]
  236. :return: data type-list,[(video_id, flow_pool, view_count), ...]
  237. error_flag 错误标记,True为错误
  238. """
  239. error_flag = False
  240. if not videos:
  241. return [], error_flag
  242. request_data = {'appType': app_type, 'videos': videos}
  243. result = request_post(request_url=config_.GET_REMAIN_VIEW_COUNT_URL, request_data=request_data, timeout=(0.1, 1))
  244. if result is None:
  245. error_flag = True
  246. return [], error_flag
  247. if result['code'] != 0:
  248. log_.info('获取视频在流量池中的剩余可分发数失败')
  249. error_flag = True
  250. return [], error_flag
  251. data = [(item['videoId'], item['flowPool'], item['distributeCount']) for item in result['data']]
  252. return data, error_flag
  253. def get_videos_local_distribute_count(video_id, flow_pool):
  254. """
  255. 获取流量池视频本地分发数
  256. :param video_id: video_id
  257. :param flow_pool: 流量池标记
  258. :return: current_count 本地记录的分发数
  259. """
  260. # redis_h = datetime.now().hour
  261. # if datetime.now().minute >= 30:
  262. # redis_h += 0.5
  263. # key_name = config_.LOCAL_DISTRIBUTE_COUNT_PREFIX + str(redis_h)
  264. key_name = f'{config_.LOCAL_DISTRIBUTE_COUNT_PREFIX}{video_id}:{flow_pool}'
  265. redis_helper = RedisHelper()
  266. # video = '{}-{}'.format(video_id, flow_pool)
  267. # current_count = redis_helper.get_score_with_value(key_name=key_name, value=video)
  268. current_count = redis_helper.get_data_from_redis(key_name=key_name)
  269. if current_count is not None:
  270. return int(current_count)
  271. else:
  272. return None
  273. def update_video_w_h_rate(video_id, key_name):
  274. """
  275. 获取横屏视频的宽高比,并存入redis中 (width/height>1)
  276. :param video_id: videoId type-int
  277. :param key_name: redis key
  278. :return: None
  279. """
  280. # 获取数据
  281. sql = "SELECT id, width, height, rotate FROM longvideo.wx_video WHERE id = {};".format(video_id)
  282. mysql_helper = MysqlHelper()
  283. data = mysql_helper.get_data(sql=sql)
  284. if len(data) == 0:
  285. return
  286. # 更新到redis
  287. width, height, rotate = int(data[0][1]), int(data[0][2]), int(data[0][3])
  288. if width == 0 or height == 0:
  289. return
  290. if rotate in (90, 270):
  291. w_h_rate = height / width
  292. else:
  293. w_h_rate = width / height
  294. if w_h_rate > 1:
  295. info_data = {int(video_id): w_h_rate}
  296. else:
  297. return
  298. redis_helper = RedisHelper()
  299. # 写入新数据
  300. if len(info_data) > 0:
  301. redis_helper.add_data_with_zset(key_name=key_name, data=info_data)
  302. class FilterVideos(object):
  303. """视频过滤"""
  304. def __init__(self, request_id, app_type, video_ids, mid='', uid='',
  305. expansion_factor=None,
  306. risk_filter_flag=None,
  307. app_region_filtered=None,
  308. videos_with_risk=None,
  309. force_truncation=None):
  310. """
  311. 初始化
  312. :param request_id: request_id
  313. :param app_type: 产品标识 type-int
  314. :param video_ids: 需过滤的视频列表 type-list
  315. :param mid: mid type-string
  316. :param uid: uid type-string
  317. """
  318. self.request_id = request_id
  319. self.app_type = app_type
  320. self.mid = mid
  321. self.uid = uid
  322. self.video_ids = video_ids
  323. self.expansion_factor = expansion_factor
  324. self.risk_filter_flag = risk_filter_flag
  325. self.app_region_filtered = app_region_filtered
  326. self.videos_with_risk = videos_with_risk
  327. self.force_truncation = force_truncation
  328. def filter_video_status_h(self, video_ids, rule_key, data_key, ab_code, province_code, key_flag=''):
  329. """召回小时级更新的视频状态过滤"""
  330. # 根据Redis缓存中的数据过滤
  331. redis_helper = RedisHelper()
  332. # 获取不符合推荐状态的视频
  333. if ab_code in [code for _, code in config_.AB_CODE['region_rank_by_h'].items()]:
  334. if key_flag == 'region_24h':
  335. key_prefix = f"{config_.REGION_H_VIDEO_FILER_24H}{province_code}."
  336. elif key_flag == 'day_24h':
  337. key_prefix = f"{config_.H_VIDEO_FILER_24H}{province_code}."
  338. else:
  339. key_prefix = f"{config_.REGION_H_VIDEO_FILER}{province_code}."
  340. elif ab_code in [code for _, code in config_.AB_CODE['rank_by_24h'].items()]:
  341. key_prefix = config_.H_VIDEO_FILER_24H
  342. elif key_flag == '24h':
  343. key_prefix = config_.H_VIDEO_FILER_24H
  344. else:
  345. key_prefix = config_.H_VIDEO_FILER
  346. filter_videos_list = redis_helper.get_data_from_set(
  347. key_name=f"{key_prefix}{self.app_type}.{data_key}.{rule_key}"
  348. )
  349. if not filter_videos_list:
  350. return video_ids
  351. filter_videos = [int(video) for video in filter_videos_list]
  352. filtered_videos = [video_id for video_id in video_ids if video_id not in filter_videos]
  353. return filtered_videos
  354. def filter_videos_h(self, rule_key, data_key, ab_code, province_code, key_flag='', pool_type='rov'):
  355. """召回小时级更新的视频过滤"""
  356. # 预曝光过滤
  357. # st_pre = time.time()
  358. filtered_pre_result = self.filter_video_previewed(self.video_ids)
  359. # et_pre = time.time()
  360. # log_.info({
  361. # 'logTimestamp': int(time.time() * 1000),
  362. # 'request_id': self.request_id,
  363. # 'app_type': self.app_type,
  364. # 'mid': self.mid,
  365. # 'uid': self.uid,
  366. # 'operation': 'preview_filter',
  367. # 'request_videos': self.video_ids,
  368. # 'preview_filter_result': filtered_pre_result,
  369. # 'executeTime': (time.time() - st_pre) * 1000
  370. # })
  371. if not filtered_pre_result:
  372. return None
  373. # 视频状态过滤
  374. # st_status = time.time()
  375. filtered_status_result = self.filter_video_status_h(video_ids=filtered_pre_result, rule_key=rule_key,
  376. data_key=data_key, ab_code=ab_code,
  377. province_code=province_code, key_flag=key_flag)
  378. # et_status = time.time()
  379. # log_.info({
  380. # 'logTimestamp': int(time.time() * 1000),
  381. # 'request_id': self.request_id,
  382. # 'app_type': self.app_type,
  383. # 'mid': self.mid,
  384. # 'uid': self.uid,
  385. # 'operation': 'status_filter',
  386. # 'request_videos': filtered_pre_result,
  387. # 'status_filter_result': filtered_status_result,
  388. # 'executeTime': (time.time() - st_status) * 1000
  389. # })
  390. if not filtered_status_result:
  391. return None
  392. # 视频已曝光过滤
  393. st_viewed = time.time()
  394. filtered_viewed_result = self.filter_video_viewed(video_ids=filtered_status_result)
  395. # et_viewed = time.time()
  396. log_.info({
  397. 'logTimestamp': int(time.time() * 1000),
  398. 'pool_type': pool_type,
  399. 'request_id': self.request_id,
  400. 'app_type': self.app_type,
  401. 'mid': self.mid,
  402. 'uid': self.uid,
  403. 'operation': 'view_filter',
  404. 'request_videos': filtered_status_result,
  405. 'view_filter_result': filtered_viewed_result,
  406. 'executeTime': (time.time() - st_viewed) * 1000
  407. })
  408. if not filtered_viewed_result:
  409. return None
  410. else:
  411. return [int(video_id) for video_id in filtered_viewed_result]
  412. def filter_videos(self, pool_type='rov', region_code=None, shield_config=None):
  413. """视频过滤"""
  414. # todo: 添加app和region的风险过滤。
  415. st_viewed = time.time()
  416. videos_filtered = self.filter_videos_with_risk_video(self.video_ids, self.app_type, region_code)
  417. # log_.info({
  418. # 'logTimestamp': int(time.time() * 1000),
  419. # 'pool_type': "zhangbo-filter-pool_type",
  420. # 'request_id': self.request_id,
  421. # 'app_type': self.app_type,
  422. # 'mid': "zhangbo-filter_videos",
  423. # 'uid': self.uid,
  424. # 'operation': 'shield_filter',
  425. # 'request_videos': self.video_ids,
  426. # 'shield_filter_result': videos_filtered,
  427. # 'executeTime': (time.time() - st_viewed) * 1000
  428. # })
  429. # 预曝光过滤
  430. st_pre = time.time()
  431. filtered_pre_result = self.filter_video_previewed(videos_filtered)
  432. # print("filtered_pre:", (time.time()-st_pre)*1000)
  433. # et_pre = time.time()
  434. # log_.info({
  435. # 'logTimestamp': int(time.time() * 1000),
  436. # 'request_id': self.request_id,
  437. # 'app_type': self.app_type,
  438. # 'mid': self.mid,
  439. # 'uid': self.uid,
  440. # 'operation': 'preview_filter',
  441. # 'request_videos': self.video_ids,
  442. # 'preview_filter_result': filtered_pre_result,
  443. # 'executeTime': (time.time() - st_pre) * 1000
  444. # })
  445. if not filtered_pre_result:
  446. return None
  447. # 视频状态过滤采用离线定时过滤方案
  448. # 视频状态过滤
  449. # st_status = time.time()
  450. # filtered_status_result = self.filter_video_status(video_ids=filtered_pre_result)
  451. # et_status = time.time()
  452. # log_.info('filter by video status: result = {}, execute time = {}ms'.format(
  453. # filtered_status_result, (et_status - st_status) * 1000))
  454. # if not filtered_status_result:
  455. # return None
  456. # 视频已曝光过滤
  457. st_viewed = time.time()
  458. filtered_viewed_result = self.filter_video_viewed(video_ids=filtered_pre_result)
  459. # print("filtered_pre:", (time.time() - st_viewed) * 1000)
  460. # et_viewed = time.time()
  461. # log_.info({
  462. # 'logTimestamp': int(time.time() * 1000),
  463. # 'pool_type': pool_type,
  464. # 'request_id': self.request_id,
  465. # 'app_type': self.app_type,
  466. # 'mid': self.mid,
  467. # 'uid': self.uid,
  468. # 'operation': 'view_filter',
  469. # 'request_videos': filtered_pre_result,
  470. # 'view_filter_result': filtered_viewed_result,
  471. # 'executeTime': (time.time() - st_viewed) * 1000
  472. # })
  473. if not filtered_viewed_result:
  474. return None
  475. filtered_viewed_videos = [int(video_id) for video_id in filtered_viewed_result]
  476. return filtered_viewed_videos
  477. # if pool_type == 'flow' or pool_type=='normal':
  478. # # 流量池视频需过滤屏蔽视频
  479. # if region_code is None or shield_config is None:
  480. # return filtered_viewed_videos
  481. # else:
  482. # shield_key_name_list = shield_config.get(region_code, None)
  483. # if shield_key_name_list is not None:
  484. # filtered_shield_video_ids = self.filter_shield_video(
  485. # video_ids=filtered_viewed_videos, shield_key_name_list=shield_key_name_list
  486. # )
  487. # log_.info({
  488. # 'logTimestamp': int(time.time() * 1000),
  489. # 'pool_type': pool_type,
  490. # 'request_id': self.request_id,
  491. # 'app_type': self.app_type,
  492. # 'mid': self.mid,
  493. # 'uid': self.uid,
  494. # 'operation': 'shield_filter',
  495. # 'request_videos': filtered_viewed_videos,
  496. # 'shield_filter_result': filtered_shield_video_ids,
  497. # 'executeTime': (time.time() - st_viewed) * 1000
  498. # })
  499. # # print("filtered_pre flow:", (time.time() - st_viewed) * 1000)
  500. # return filtered_shield_video_ids
  501. # else:
  502. # return filtered_viewed_videos
  503. # else:
  504. # return filtered_viewed_videos
  505. def filter_video_previewed(self, video_ids):
  506. """
  507. 预曝光过滤
  508. :param video_ids: 需过滤的视频列表 type-list
  509. :return: filtered_videos 过滤后的列表 type-list
  510. """
  511. pre_time = time.time()
  512. if not self.mid or self.mid == 'null':
  513. # mid为空时,不做预曝光过滤
  514. return video_ids
  515. # 根据Redis缓存中的数据过滤
  516. redis_helper = RedisHelper()
  517. # key拼接
  518. key_name = f"{config_.PREVIEW_KEY_PREFIX}{self.app_type}:{self.mid}"
  519. #print("key_name:", key_name)
  520. pe_videos_list = redis_helper.get_data_from_set(key_name)
  521. #print("pe_videos_list:", pe_videos_list)
  522. # log_.info('****app_type = {}, mid = {}, uid = {}, pe_videos_list = {}'.format(
  523. # self.app_type, self.mid, self.uid, pe_videos_list))
  524. # log_.info('****app_type = {}, mid = {}, uid = {}, video_ids = {}'.format(
  525. # self.app_type, self.mid, self.uid, video_ids))
  526. if not pe_videos_list:
  527. return video_ids
  528. pe_videos = [int(video) for video in pe_videos_list]
  529. #print("pe_videos:", len(pe_videos))
  530. filtered_videos = [video_id for video_id in video_ids if video_id not in pe_videos]
  531. #print(f"pre res: {filtered_videos}\nexecute_time: {(time.time() - pre_time) * 1000}")
  532. return filtered_videos
  533. # def filter_video_status(self, video_ids):
  534. # """
  535. # 对视频状态进行过滤
  536. # :param video_ids: 视频id列表 type-list
  537. # :return: filtered_videos
  538. # """
  539. # if len(video_ids) == 1:
  540. # sql = "set hg_experimental_enable_shard_pruning=off; " \
  541. # "SELECT video_id " \
  542. # "FROM {} " \
  543. # "WHERE audit_status = 5 " \
  544. # "AND applet_rec_status IN (1, -6) " \
  545. # "AND open_status = 1 " \
  546. # "AND payment_status = 0 " \
  547. # "AND encryption_status != 5 " \
  548. # "AND transcoding_status = 3 " \
  549. # "AND video_id IN ({});".format(config_.VIDEO_STATUS, video_ids[0])
  550. # else:
  551. # sql = "set hg_experimental_enable_shard_pruning=off; " \
  552. # "SELECT video_id " \
  553. # "FROM {} " \
  554. # "WHERE audit_status = 5 " \
  555. # "AND applet_rec_status IN (1, -6) " \
  556. # "AND open_status = 1 " \
  557. # "AND payment_status = 0 " \
  558. # "AND encryption_status != 5 " \
  559. # "AND transcoding_status = 3 " \
  560. # "AND video_id IN {};".format(config_.VIDEO_STATUS, tuple(video_ids))
  561. #
  562. # hologres_helper = HologresHelper()
  563. # data = hologres_helper.get_data(sql=sql)
  564. # filtered_videos = [int(temp[0]) for temp in data]
  565. # return filtered_videos
  566. def filter_video_viewed(self, video_ids, types=(1, 6,)):
  567. """
  568. 调用后端接口过滤用户已观看视频
  569. :param video_ids: 视频id列表 type-list
  570. :param types: 过滤参数 type-tuple, 默认(1, )
  571. 1-已观看 2-视频状态 3-是否进入老年人社区 4-话题状态 5-推荐状态 6-白名单过滤 7-涉政视频过滤
  572. :return: filtered_videos
  573. """
  574. # 获取对应端的过滤参数types
  575. types = config_.FILTER_VIEWED_TYPES_CONFIG.get(self.app_type, None)
  576. if types is None:
  577. types = config_.FILTER_VIEWED_TYPES_CONFIG.get('other')
  578. request_data = {"appType": self.app_type,
  579. "mid": self.mid,
  580. "uid": self.uid,
  581. "types": list(types),
  582. "videoIds": video_ids,
  583. "recommendStatus": [-6]}
  584. # print(request_data)
  585. # 调用http接口
  586. url = config_.VIDEO_FILTER_URL
  587. result = request_post(request_url=config_.VIDEO_FILTER_URL, request_data=request_data, timeout=(0.1, 1))
  588. # print("result:", result)
  589. if result is None:
  590. # print("result is None")
  591. # log_.info('过滤失败,types: {}'.format(types))
  592. return []
  593. if result['code'] != 0:
  594. # log_.info('过滤失败,types: {}'.format(types))
  595. return []
  596. filtered_videos = result['data']
  597. return filtered_videos
  598. def filter_video_viewed_new(self, video_ids):
  599. """
  600. 调用后端接口过滤用户已观看视频
  601. :param video_ids: 视频id列表 type-list
  602. :param types: 过滤参数 type-tuple, 默认(1, )
  603. 1-已观看 2-视频状态 3-是否进入老年人社区 4-话题状态 5-推荐状态 6-白名单过滤 7-涉政视频过滤
  604. :return: filtered_videos
  605. """
  606. # 获取对应端的过滤参数types
  607. st_time = time.time()
  608. types = config_.FILTER_VIEWED_TYPES_CONFIG.get(self.app_type, None)
  609. #print(types)
  610. if types is None:
  611. types = config_.FILTER_VIEWED_TYPES_CONFIG.get('other')
  612. if 6 in types:
  613. types = list(types)
  614. types.remove(6)
  615. #print(types)
  616. request_data = {"appType": self.app_type,
  617. "mid": self.mid,
  618. "uid": self.uid,
  619. "types": list(types),
  620. "videoIds": video_ids}
  621. # 调用http接口
  622. result = request_post(request_url=config_.VIDEO_FILTER_URL, request_data=request_data, timeout=(0.1, 1))
  623. #print(f"view res: {result}\nexecute_time: {(time.time() - st_time) * 1000}")
  624. if result is None:
  625. # log_.info('过滤失败,types: {}'.format(types))
  626. return []
  627. if result['code'] != 0:
  628. # log_.info('过滤失败,types: {}'.format(types))
  629. return []
  630. filtered_videos = result['data']
  631. return filtered_videos
  632. def filter_shield_video(self, video_ids, shield_key_name_list):
  633. """
  634. 过滤屏蔽视频视频
  635. :param video_ids: 需过滤的视频列表 type-list
  636. :param shield_key_name_list: 过滤视频 redis-key
  637. :return: filtered_videos 过滤后的列表 type-list
  638. """
  639. # print("filter_shield_video:", len(filter_shield_video))
  640. if len(video_ids) == 0:
  641. return video_ids
  642. # 根据Redis缓存中的数据过滤
  643. redis_helper = RedisHelper()
  644. for shield_key_name in shield_key_name_list:
  645. video_ids = [
  646. int(video_id) for video_id in video_ids
  647. if not redis_helper.data_exists_with_set(key_name=shield_key_name, value=video_id)
  648. ]
  649. # shield_videos_list = redis_helper.get_data_from_set(key_name=shield_key_name)
  650. # if not shield_videos_list:
  651. # continue
  652. # shield_videos = [int(video) for video in shield_videos_list]
  653. # video_ids = [int(video_id) for video_id in video_ids if int(video_id) not in shield_videos]
  654. # print("video_ids:", len(video_ids))
  655. return video_ids
  656. def new_filter_video(self):
  657. """视频过滤"""
  658. # 1. 预曝光过滤
  659. st_pre = time.time()
  660. #print("new_filter video_ids:", self.video_ids)
  661. filtered_pre_result = self.filter_video_previewed(self.video_ids)
  662. if not filtered_pre_result:
  663. return None
  664. # log_.info({
  665. # 'logTimestamp': int(time.time() * 1000),
  666. # 'request_id': self.request_id,
  667. # 'app_type': self.app_type,
  668. # 'mid': self.mid,
  669. # 'uid': self.uid,
  670. # 'operation': 'preview_filter',
  671. # 'request_videos': self.video_ids,
  672. # 'preview_filter_result': filtered_pre_result,
  673. # 'executeTime': (time.time() - st_pre) * 1000
  674. # })
  675. #2. 视频已曝光过滤
  676. st_viewed = time.time()
  677. #print("---filtered viewed---")
  678. #print("filtered_pre_result:",filtered_pre_result)
  679. filtered_viewed_result = self.filter_video_viewed(video_ids=filtered_pre_result)
  680. if not filtered_viewed_result:
  681. return None
  682. return filtered_viewed_result
  683. def new_flow_video(self, vid_list, flow_vids_set, region_code, shield_config):
  684. flow_video_list = []
  685. normal_video_list = []
  686. for v_id in vid_list:
  687. if v_id in flow_vids_set:
  688. flow_video_list.append(v_id)
  689. else:
  690. normal_video_list.append(v_id)
  691. shield_key_name_list = shield_config.get(region_code, None)
  692. if shield_key_name_list is not None:
  693. filtered_shield_video_ids = self.filter_shield_video(
  694. video_ids=flow_video_list, shield_key_name_list=shield_key_name_list
  695. )
  696. return normal_video_list, filtered_shield_video_ids
  697. else:
  698. return normal_video_list, flow_video_list
  699. def filter_movie_religion_video(self, video_ids):
  700. """过滤白名单视频(影视,宗教)"""
  701. # 影视 + 宗教: rov.filter.movie.{videoId}
  702. # 宗教: rov.filter.religion.{videoId}
  703. st_time = time.time()
  704. if self.app_type not in [config_.APP_TYPE['WAN_NENG_VIDEO'],
  705. config_.APP_TYPE['LAO_HAO_KAN_VIDEO'],
  706. config_.APP_TYPE['ZUI_JING_QI'],
  707. config_.APP_TYPE['H5']]:
  708. # 过滤 影视 + 宗教
  709. keys = [f"rov.filter.movie.{video_id}" for video_id in video_ids]
  710. elif self.app_type in [config_.APP_TYPE['WAN_NENG_VIDEO'],
  711. config_.APP_TYPE['ZUI_JING_QI'],
  712. config_.APP_TYPE['H5']]:
  713. # 过滤 影视 + 宗教
  714. keys = [f"rov.filter.religion.{video_id}" for video_id in video_ids]
  715. else:
  716. #print(f"m_r res: {video_ids}\nexecute_time: {(time.time() - st_time) * 1000}")
  717. return video_ids
  718. redis_helper = RedisHelper(redis_info=config_.REDIS_INFO_FILTER)
  719. filter_videos = []
  720. for i in range(len(keys)//1000 + 1):
  721. video_ids_temp = video_ids[i*1000:(i+1)*1000]
  722. if len(video_ids_temp) == 0:
  723. break
  724. mget_res = redis_helper.mget(keys=keys[i*1000:(i+1)*1000])
  725. filter_videos.extend([int(data) for data in mget_res if data is not None])
  726. if len(filter_videos) > 0:
  727. filtered_videos = set(video_ids) - set(filter_videos)
  728. #print(f"m_r res: {list(filtered_videos)}\nexecute_time: {(time.time() - st_time) * 1000}")
  729. return list(filtered_videos)
  730. else:
  731. #print(f"m_r res: {video_ids}\nexecute_time: {(time.time() - st_time) * 1000}")
  732. return video_ids
  733. def filter_videos_new(self, region_code=None, shield_config=None, flow_set=None):
  734. """视频过滤"""
  735. # 预曝光过滤
  736. st_pre = time.time()
  737. #print("self.video_ids:", len(self.video_ids))
  738. filtered_pre_result = self.filter_video_previewed(self.video_ids)
  739. if not filtered_pre_result:
  740. return None
  741. #print("filtered_pre_result:", len(filtered_pre_result))
  742. #print(filtered_pre_result)
  743. # 视频已曝光过滤/白名单过滤
  744. st_viewed = time.time()
  745. t = [
  746. gevent.spawn(self.filter_video_viewed_new, filtered_pre_result),
  747. gevent.spawn(self.filter_movie_religion_video, filtered_pre_result)]
  748. gevent.joinall(t)
  749. filtered_result_list = [i.get() for i in t]
  750. #print("filtered_result_list1:",filtered_result_list[0])
  751. #print("filtered_result_list2:",filtered_result_list[1])
  752. filtered_viewed_set = set('')
  753. for i in filtered_result_list[0]:
  754. filtered_viewed_set.add(int(i))
  755. filter_video_set =set('')
  756. for j in filtered_result_list[1]:
  757. filter_video_set.add(int(j))
  758. filtered_viewed_result = list(filtered_viewed_set & filter_video_set)
  759. #print(f"view&m_r res: {filtered_viewed_result}\nexecute_time: {(time.time() - st_viewed) * 1000}")
  760. #print("filtered:",len(filtered_viewed_result))
  761. if not filtered_viewed_result:
  762. return None
  763. filtered_viewed_videos = [int(video_id) for video_id in filtered_viewed_result]
  764. #print("result:", filtered_viewed_videos)
  765. if flow_set is None:
  766. return filtered_viewed_videos
  767. else:
  768. # 流量池视频需过滤屏蔽视频
  769. if region_code is None or shield_config is None:
  770. return filtered_viewed_videos
  771. else:
  772. normal_recall_ids = []
  773. left_flow_ids = []
  774. for vid in filtered_viewed_videos:
  775. if vid in flow_set:
  776. left_flow_ids.append(vid)
  777. else:
  778. normal_recall_ids.append(vid)
  779. shield_key_name_list = shield_config.get(region_code, None)
  780. if shield_key_name_list is not None:
  781. filtered_shield_video_ids = self.filter_shield_video(
  782. video_ids=left_flow_ids, shield_key_name_list=shield_key_name_list
  783. )
  784. return normal_recall_ids+filtered_shield_video_ids
  785. else:
  786. return filtered_viewed_videos
  787. def filter_videos_status(self, pool_type='rov', region_code=None, shield_config=None):
  788. """视频过滤"""
  789. # todo: 添加app和region的风险过滤。
  790. st_viewed = time.time()
  791. videos_filtered = self.filter_videos_with_risk_video(self.video_ids, self.app_type, region_code)
  792. # log_.info({
  793. # 'logTimestamp': int(time.time() * 1000),
  794. # 'pool_type': "zhangbo-filter-pool_type",
  795. # 'request_id': self.request_id,
  796. # 'app_type': self.app_type,
  797. # 'mid': "zhangbo-filter_videos_status",
  798. # 'uid': self.uid,
  799. # 'operation': 'shield_filter',
  800. # 'request_videos': self.video_ids,
  801. # 'shield_filter_result': videos_filtered,
  802. # 'executeTime': (time.time() - st_viewed) * 1000
  803. # })
  804. # 预曝光过滤
  805. st_pre = time.time()
  806. filtered_pre_result = self.filter_video_previewed(videos_filtered)
  807. # print("filtered_pre:", (time.time()-st_pre)*1000)
  808. # et_pre = time.time()
  809. # log_.info({
  810. # 'logTimestamp': int(time.time() * 1000),
  811. # 'request_id': self.request_id,
  812. # 'app_type': self.app_type,
  813. # 'mid': self.mid,
  814. # 'uid': self.uid,
  815. # 'operation': 'preview_filter',
  816. # 'request_videos': self.video_ids,
  817. # 'preview_filter_result': filtered_pre_result,
  818. # 'executeTime': (time.time() - st_pre) * 1000
  819. # })
  820. if not filtered_pre_result:
  821. return None
  822. # 视频状态过滤采用离线定时过滤方案
  823. # 视频状态过滤
  824. # st_status = time.time()
  825. # filtered_status_result = self.filter_video_status(video_ids=filtered_pre_result)
  826. # et_status = time.time()
  827. # log_.info('filter by video status: result = {}, execute time = {}ms'.format(
  828. # filtered_status_result, (et_status - st_status) * 1000))
  829. # if not filtered_status_result:
  830. # return None
  831. # 视频已曝光过滤
  832. st_viewed = time.time()
  833. filtered_viewed_result = self.filter_video_viewed_status(video_ids=filtered_pre_result)
  834. # print("filtered_pre:", (time.time() - st_viewed) * 1000)
  835. # et_viewed = time.time()
  836. # log_.info({
  837. # 'logTimestamp': int(time.time() * 1000),
  838. # 'pool_type': pool_type,
  839. # 'request_id': self.request_id,
  840. # 'app_type': self.app_type,
  841. # 'mid': self.mid,
  842. # 'uid': self.uid,
  843. # 'operation': 'view_filter',
  844. # 'request_videos': filtered_pre_result,
  845. # 'view_filter_result': filtered_viewed_result,
  846. # 'executeTime': (time.time() - st_viewed) * 1000
  847. # })
  848. if not filtered_viewed_result:
  849. return None
  850. filtered_viewed_videos = [int(video_id) for video_id in filtered_viewed_result]
  851. return filtered_viewed_videos
  852. # if pool_type == 'flow' or pool_type=='normal':
  853. # # 流量池视频需过滤屏蔽视频
  854. # if region_code is None or shield_config is None:
  855. # return filtered_viewed_videos
  856. # else:
  857. # shield_key_name_list = shield_config.get(region_code, None)
  858. # if shield_key_name_list is not None:
  859. # filtered_shield_video_ids = self.filter_shield_video(
  860. # video_ids=filtered_viewed_videos, shield_key_name_list=shield_key_name_list
  861. # )
  862. # log_.info({
  863. # 'logTimestamp': int(time.time() * 1000),
  864. # 'pool_type': pool_type,
  865. # 'request_id': self.request_id,
  866. # 'app_type': self.app_type,
  867. # 'mid': self.mid,
  868. # 'uid': self.uid,
  869. # 'operation': 'shield_filter',
  870. # 'request_videos': filtered_viewed_videos,
  871. # 'shield_filter_result': filtered_shield_video_ids,
  872. # 'executeTime': (time.time() - st_viewed) * 1000
  873. # })
  874. # # print("filtered_pre flow:", (time.time() - st_viewed) * 1000)
  875. # return filtered_shield_video_ids
  876. # else:
  877. # return filtered_viewed_videos
  878. # else:
  879. # return filtered_viewed_videos
  880. def filter_video_viewed_status(self, video_ids, types=(1, 6,)):
  881. """
  882. 调用后端接口过滤用户已观看视频
  883. :param video_ids: 视频id列表 type-list
  884. :param types: 过滤参数 type-tuple, 默认(1, )
  885. 1-已观看 2-视频状态 3-是否进入老年人社区 4-话题状态 5-推荐状态 6-白名单过滤 7-涉政视频过滤
  886. :return: filtered_videos
  887. """
  888. # 获取对应端的过滤参数types
  889. types = config_.FILTER_VIEWED_TYPES_CONFIG.get(self.app_type, None)
  890. if types is None:
  891. types = config_.FILTER_VIEWED_TYPES_CONFIG.get('other')
  892. types = list(types)
  893. types.append(2)
  894. request_data = {"appType": self.app_type,
  895. "mid": self.mid,
  896. "uid": self.uid,
  897. "types": types,
  898. "videoIds": video_ids,
  899. "recommendStatus": [-6]}
  900. # print(request_data)
  901. # 调用http接口
  902. result = request_post(request_url=config_.VIDEO_FILTER_URL, request_data=request_data, timeout=(0.1, 1))
  903. # print("result:", result)
  904. if result is None:
  905. # print("result is None")
  906. # log_.info('过滤失败,types: {}'.format(types))
  907. return []
  908. if result['code'] != 0:
  909. # log_.info('过滤失败,types: {}'.format(types))
  910. return []
  911. filtered_videos = result['data']
  912. return filtered_videos
  913. def filter_videos_with_risk_video(self, video_ids, app_type, region_code):
  914. # 0 用一个开关控制,是否过滤生效。 便于回滚功能。
  915. risk_filter_flag = self.risk_filter_flag
  916. if not risk_filter_flag:
  917. return self.truncation(video_ids)
  918. # 1 判断是否过滤,不展示的app+区域列表,-1必须过滤
  919. app_region_filtered = self.app_region_filtered
  920. if app_type in app_region_filtered.keys():
  921. if_filtered = False
  922. if region_code in app_region_filtered[app_type]:
  923. if_filtered = True
  924. else:
  925. if_filtered = True
  926. if not if_filtered:
  927. return self.truncation(video_ids)
  928. # 2 确认过滤,获取风险video列表param_update_risk_videos
  929. videos_with_risk = self.videos_with_risk
  930. # 3 过滤 返回结果
  931. video_ids_new = [i for i in video_ids if i not in videos_with_risk]
  932. # print(risk_filter_flag)
  933. # print(app_region_filtered)
  934. # print(video_ids)
  935. # print(app_type)
  936. # print(region_code)
  937. # print(videos_with_risk)
  938. # print(video_ids_new)
  939. # print(len(video_ids))
  940. # print(len(video_ids_new))
  941. return self.truncation(video_ids_new)
  942. def truncation(self, video_ids):
  943. if self.force_truncation is None:
  944. return video_ids
  945. else:
  946. return video_ids[:min(self.force_truncation, len(video_ids))]
  947. def filter_videos_for_group(self, region_code=None, videos=None, video_tag_dict=None, tags_rule=None, tags_filter_flag=None):
  948. """视频过滤"""
  949. videos_filtered = self.filter_videos_with_risk_video(videos, self.app_type, region_code)
  950. filtered_pre_result = self.filter_video_previewed(videos_filtered)
  951. if not filtered_pre_result:
  952. return None
  953. filtered_viewed_result = self.filter_video_viewed_status(video_ids=filtered_pre_result)
  954. if not filtered_viewed_result:
  955. return None
  956. if tags_filter_flag:
  957. result = self.filter_videos_with_tags_rule([int(video_id) for video_id in filtered_viewed_result],
  958. video_tag_dict, tags_rule)
  959. result = [int(video_id) for video_id in result]
  960. else:
  961. result = [int(video_id) for video_id in filtered_viewed_result]
  962. return result
  963. def filter_videos_with_tags_rule(self, video_ids: list, video_tag_dict: dict, tags_rule: dict):
  964. # 1 获取当日节日信息和小时数字
  965. hour = datetime.now().hour
  966. date = datetime.strftime(datetime.today(), '%Y-%m-%d')
  967. holiday_cn = HOLIDAY_KV[date] if date in HOLIDAY_KV.keys() else ""
  968. # 2 确认命中规则: 先处理天级别,后处理年级别
  969. tag_days = ["早上好", "中午好", "下午好", "晚上好", "晚安"]
  970. filter_tags = []
  971. for tag_day in tag_days:
  972. rules = tags_rule[tag_day] if tag_day in tags_rule.keys() else {}
  973. start = rules["start"] if "start" in rules.keys() else 0
  974. end = rules["end"] if "end" in rules.keys() else 23
  975. if hour < start or hour > end:
  976. filter_tags.append(tag_day)
  977. if len(holiday_cn) != 0:
  978. rules = tags_rule[holiday_cn] if holiday_cn in tags_rule.keys() else {}
  979. start = rules["start"] if "start" in rules.keys() else 0
  980. end = rules["end"] if "end" in rules.keys() else 9
  981. if hour < start or hour > end:
  982. filter_tags.append(holiday_cn)
  983. if len(filter_tags) == 0:
  984. return video_ids
  985. # 3 获取视频的tag 进行过滤
  986. video_id_result = []
  987. for _, id in enumerate(video_ids):
  988. tags = video_tag_dict[id]
  989. if_filter_video = set(filter_tags) & set(tags)
  990. if len(if_filter_video) > 0:
  991. pass
  992. else:
  993. video_id_result.append(id)
  994. return video_id_result
  995. if __name__ == '__main__':
  996. pass
  997. # video_ids = [17736990, 17734880, 17734759, 17726977]
  998. # video_tag_dict = {17734880: ['国庆节'], 17726977: ['圣诞节'], 17736990: ['早上好'], 17734759: ['晚上好']}
  999. # tags_rule = {'早上好': {'start': 0, 'end': 9}, '中午好': {'start': 11, 'end': 13}, '冬至': {'start': 0, 'end': 9}, '祝福': {'start': 0, 'end': 23}}
  1000. # f = FilterVideos("request_id", "app_type", video_ids)
  1001. # f.filter_videos_with_tags_rule(video_ids, video_tag_dict, tags_rule)
  1002. user = [
  1003. ('weixin_openid_o0w175fDc8pNnywrYN49E341tKfI', ''),
  1004. ('weixin_openid_o0w175YwC3hStzcR5DAQdbgzdMeI', ''),
  1005. ('weixin_openid_o0w175ftZDl6VJVDx9la3WVPh7mU', '15900461'),
  1006. ('weixin_openid_o0w175SPqpCVRcp7x1XvnX4qpIvI', '19659040'),
  1007. ('weixin_openid_o0w175cOnguapyWIrDrHkOWl4oFQ', '31210128'),
  1008. ('weixin_openid_o0w175UXYId-o71e1Q3SOheYNteQ', '33099722'),
  1009. ('weixin_openid_o0w175QQ5b42AtOe50bchrFgcttA', ''),
  1010. ('weixin_openid_o0w175bgaPlfLsp3YLDKWqLWtXX8', '35371534'),
  1011. ('weixin_openid_o0w175eRpvbmV6nOhM1VTyyLICWA', '30488803'),
  1012. ('weixin_openid_o0w175TZYvG47pQkOjyJFoxQuqsw', '')
  1013. ]
  1014. # video_df = pd.read_csv('./data/videoids.csv')
  1015. # videoid_list = video_df['videoid'].tolist()
  1016. videoid_list = [17759493, 17759670, 17759750, 177601111, 688346]
  1017. for mid, uid in user:
  1018. video_ids = videoid_list
  1019. start_time = time.time()
  1020. filter_ = FilterVideos(request_id=f'{mid} - {uid}', app_type=0, mid=mid, uid=uid, video_ids=video_ids)
  1021. res = filter_.filter_video_viewed(video_ids)
  1022. print(res)
  1023. # videos = [{'videoId': 9034659, 'flowPool': '3#11#3#1637824188547'}, {'videoId': 9035052, 'flowPool': '3#11#3#1637824172827'}]
  1024. # res = get_videos_remain_view_count(4, videos)
  1025. # print(res)
  1026. # text = '测试 @李倩'
  1027. # send_msg_to_feishu(text)
  1028. # update_video_w_h_rate(video_id=113, key_name='')
  1029. # mid = "weixin_openid_obHDW5c4g3aULfCWh-68LcUSxCB"
  1030. # request_url = f"{config_.GET_USER_30DayReturnCnt_URL}{mid}"
  1031. # res = request_get(request_url=request_url, timeout=100)
  1032. # res = get_user_has30day_return(mid=mid)
  1033. # print(res, type(res))