# -*- encoding: utf-8 -*- """ @File : CronCloudPhotoController.py @Time : 2022/10/24 15:48 @Author : stephen @Email : zhangdongming@asj6.wecom.work @Software: PyCharm """ import datetime import logging import os import time import traceback import cv2 from django.db import transaction from django.views import View from Ansjer.config import PUSH_CLOUD_PHOTO, ACCESS_KEY_ID, SECRET_ACCESS_KEY, REGION_NAME, PUSH_BUCKET from Model.models import UidSetModel, DeviceCloudPhotoInfo, DevicePicturePushInfo from Object.AWS.AmazonS3Util import AmazonS3Util from Object.RedisObject import RedisObject from Object.ResponseObject import ResponseObject from Object.utils import LocalDateTimeUtil from Service.EquipmentInfoService import EquipmentInfoService LOGGER = logging.getLogger('info') UID_KEY = 'ANSJER:UID:SET:INFO' class CronCloudPhotoView(View): def get(self, request, *args, **kwargs): request.encoding = 'utf-8' operation = kwargs.get('operation') return self.validation(request.GET, request, operation) def post(self, request, *args, **kwargs): request.encoding = 'utf-8' operation = kwargs.get('operation') return self.validation(request.POST, request, operation) def validation(self, request_dict, request, operation): response = ResponseObject() if operation == 'get-photo': return self.get_photo(response) elif operation == 'cache-uid-set': return self.cache_photo_uid_set(response) elif operation == 'generate-video': return self.generate_video(response) else: return response.json(404) @classmethod def get_photo(cls, response): """ 定时获取设备消息推送图 """ try: redis = RedisObject().CONN uid_set_cache = redis.lrange(UID_KEY, 0, -1) if not uid_set_cache: return response.json(0) uid_set_cache = list(uid_set_cache) today = datetime.date.today() time_stamp = cls.get_month_stamp() now_time = int(time.time()) s3 = AmazonS3Util(ACCESS_KEY_ID, SECRET_ACCESS_KEY, REGION_NAME) for item in uid_set_cache: try: eq_qs = EquipmentInfoService.get_equipment_info_model(str(today)) item = str(item, encoding="utf-8") eq_qs = eq_qs.filter(event_time__gt=time_stamp, is_st=1, device_uid=item) \ .values('device_uid', 'channel', 'event_time', 'device_nick_name') count = eq_qs.count() page = int(count / 2) if count > 1 else count redis.lrem(UID_KEY, item, 0) if page == 0: continue eq_qs = eq_qs[(page - 1) * 1:page * 1] eq_vo = eq_qs[0] file_path = '{uid}/{channel}/{event_time}.jpeg'.format(uid=eq_vo['device_uid'], channel=eq_vo['channel'], event_time=eq_vo['event_time']) s3.copy_obj(PUSH_BUCKET, PUSH_CLOUD_PHOTO, file_path) push_data = {'type': 0, 'uid': eq_vo['device_uid'], 'channel': eq_vo['channel'], 'event_time': eq_vo['event_time'], 'updated_time': now_time, 'created_time': now_time, 'device_nick_name': eq_vo['device_nick_name']} DevicePicturePushInfo.objects.create(**push_data) except Exception as e: LOGGER.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e))) continue return response.json(0) except Exception as e: print(e) LOGGER.info('--->抽取推送图片异常:{}'.format(traceback.format_exc())) return response.json(177, repr(e)) @classmethod def cache_photo_uid_set(cls, response): """ 缓存uid_set信息 """ try: photo_qs = DeviceCloudPhotoInfo.objects.filter(status=1).values('uid') if not photo_qs.exists(): return response.json(0) redis = RedisObject() for item in photo_qs: uid_set_qs = UidSetModel.objects.filter(uid=item['uid'], detect_status=1) if not uid_set_qs: continue redis.CONN.rpush(UID_KEY, item['uid']) return response.json(0) except Exception as e: print(e) LOGGER.info('--->获取uid_set信息异常:{}'.format(traceback.format_exc())) return response.json(177, repr(e)) @classmethod def generate_video(cls, response): """ 生成视频并存库 """ try: photo_qs = DeviceCloudPhotoInfo.objects.filter(status=1).values('uid', 'user_id') if not photo_qs.exists(): return response.json(0) # 获取当前项目路径 poj_path = os.path.abspath(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))) time_stamp = cls.get_month_stamp() s3 = AmazonS3Util(ACCESS_KEY_ID, SECRET_ACCESS_KEY, REGION_NAME) now_time = int(time.time()) for item in photo_qs: try: with transaction.atomic(): picture_qs = DevicePicturePushInfo.objects.filter(uid=item['uid'], event_time__gt=time_stamp, type=0) \ .values('uid', 'channel', 'event_time', 'device_nick_name') if not picture_qs.exists(): continue device_nickname = picture_qs[0]['device_nick_name'] pic_list = cls.download_push_picture(s3, item['uid'], poj_path, picture_qs) video_path = poj_path + r'\Ansjer\file\video.mp4' # 输出视频的保存路径 cls.picture_synthesis_video(video_path, poj_path, pic_list) # 图片合成视频 video_name = datetime.datetime.now().strftime('%Y%m') data = open(video_path, 'rb') key = '{}/video/{}.mp4'.format(item['uid'], video_name) s3.upload_file_obj(PUSH_CLOUD_PHOTO, key, data) # 将视频资源上传至S3保存 os.remove(video_path) # 上传完成删除本地资源 push_data = {'type': 1, 'uid': item['uid'], 'channel': 1, 'event_time': int(video_name), 'updated_time': now_time, 'created_time': now_time, 'device_nick_name': device_nickname, 'user_id': item['user_id']} DevicePicturePushInfo.objects.create(**push_data) except Exception as e: LOGGER.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e))) continue return response.json(0) except Exception as e: print(e) LOGGER.info('--->图片合成视频异常:{}'.format(traceback.format_exc())) return response.json(177) @staticmethod def download_push_picture(s3, uid, dir_url, picture_qs): """ 下载推送图片,讲下载资源保存到项目本地 @param s3: s3对象 @param uid: 设备uid @param dir_url: 项目文件路径 @param picture_qs: 消息推送图片对象 @return: pic_list 图片文件名集合 """ pic_list = [] for pic in picture_qs: path = dir_url + r'\Ansjer\file\{}.jpeg'.format(pic['event_time']) s3_key = '{}/{}/{}.jpeg'.format(uid, pic['channel'], pic['event_time']) s3.download_object(PUSH_CLOUD_PHOTO, s3_key, path) pic_list.append('{}.jpeg'.format(pic['event_time'])) return pic_list @staticmethod def picture_synthesis_video(video_path, poj_path, pic_list): """ 图片合成视频 @param video_path: 输出视频的保存路径 @param poj_path: 项目路径 @param pic_list: 图片文件名集合 @return: """ if not pic_list: raise Exception('this pic_list is null.') fps = 1 # 帧率 img_path = poj_path + r'\Ansjer\file\{}'.format(pic_list[0]) image = cv2.imread(img_path) size = image.shape w = size[1] # 宽度 h = size[0] # 高度 img_size = (w, h) # 图片尺寸 fourcc = cv2.VideoWriter_fourcc(*"mp4v") video_writer = cv2.VideoWriter(video_path, fourcc, fps, img_size) for item in pic_list: img_path = poj_path + r'\Ansjer\file\{}'.format(item) frame = cv2.imread(img_path) if frame is None: continue frame = cv2.resize(frame, img_size) # 生成视频 图片尺寸和设定尺寸相同 video_writer.write(frame) # 将图片写进视频里 os.remove(img_path) video_writer.release() # 释放资源 @staticmethod def get_month_stamp(): """ 获取当月开始时间戳 """ now_month = LocalDateTimeUtil.get_cur_month_start() start_time = "{} 00:00:00".format(str(now_month)) time_array = time.strptime(start_time, "%Y-%m-%d %H:%M:%S") # 转换为时间戳 return int(time.mktime(time_array))