package com.platform.modules.live.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.live.model.v20161101.DescribeLivePullStreamConfigResponse;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.platform.autoconfigure.live.LiveProperties;
import com.platform.common.utils.*;
import com.platform.modules.foreign.entity.SceneForeignEntity;
import com.platform.modules.foreign.entity.SceneStreamForeignEntity;
import com.platform.modules.live.constants.SceneConstants;
import com.platform.modules.live.dao.LiveSceneDao;
import com.platform.modules.live.entity.*;
import com.platform.modules.live.service.*;
import com.platform.modules.live.utils.ForeignProperties;
import com.platform.modules.live.utils.LuceneTypeEnum;
import com.platform.modules.live.utils.TopEnum;
import com.platform.modules.live.vo.*;
import com.platform.modules.plm.util.MateriaFileProperties;
import com.platform.modules.plm.util.MaterialUtils;
import com.platform.modules.sys.entity.SysTenantEntity;
import com.platform.modules.sys.entity.SysUserEntity;
import com.platform.modules.sys.service.SysTenantService;
import com.platform.modules.sys.service.SysUserService;
import com.platform.modules.video.service.RealPathResolver;
import com.platform.plugs.common.rpc.ErrorCode;
import com.platform.plugs.common.rpc.ResponseResult;
import com.platform.plugs.common.rpc.RpcResponse;
import com.platform.plugs.live.LiveClient;
import com.platform.plugs.live.responseEntity.*;
import com.platform.plugs.live.utils.UTCDateFormat;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;

@Service("liveSceneService")
@Transactional
public class LiveSceneServiceImpl extends ServiceImpl<LiveSceneDao, LiveSceneEntity> implements LiveSceneService {

	private final Log log = LogFactory.getLog(LiveSceneServiceImpl.class);

	/**
	 * 日期转换格式
	 */
	private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy年M月d日 H时m分");

	@Autowired
	private LiveSceneLiveInfoService liveSceneLiveInfoService;
	@Autowired
	private LiveSceneCheckService liveSceneCheckService;
	@Autowired
	private LiveCasterService liveCasterService;
	@Autowired
	private LiveSceneLiveInfoExtService liveSceneLiveInfoExtService;
	@Autowired
	private SysUserService sysUserService;
	@Autowired
	private MateriaFileProperties materiaFileProperties;
	@Autowired
	private RealPathResolver realPathResolver;
	@Autowired
	private LiveClient liveClient;
	@Autowired
	private LuceneService luceneService;
	@Autowired
	private LiveSceneCountService liveSceneCountService;
	@Autowired
	private LiveSceneRecordService liveSceneRecordService;
	@Autowired
	private RedisUtils redisUtils;
	@Autowired
	private LiveReportService liveReportService;
	@Autowired
	private ForeignProperties foreignProperties;
	@Autowired
	private LiveChannelService liveChannelService;
	@Autowired
	private LiveSceneChannelService liveSceneChannelService;
	@Autowired
	private LiveMultimediaService liveMultimediaService;
	@Autowired
	private SysTenantService tenantService;
	@Autowired
	private LiveProperties liveProperties;

	@Override
	@Transactional(readOnly = true)
	public Page page(String title, Integer sceneType, String ltype, Integer liveState, Integer pageNo,
			Integer pageSize, Long tenantId) {
		EntityWrapper wrapper = new EntityWrapper<>(new LiveSceneEntity());
		// 标题
		if (StringUtils.isNotBlank(title)) {
			wrapper.like("title", title);
		}
		// 现场类型
		if (null != sceneType) {
			wrapper.eq("scene_type", sceneType);
		}
		if("cycle".equals(ltype)){
			wrapper.eq("delete_flag", 1);
		}else{
			wrapper.eq("delete_flag", 0);
			// 现场状态
			int sstate = SceneConstants.SCENE_DRAFT;
			if ("check".equals(ltype)) {
				sstate = SceneConstants.SCENE_ONE;
			} else if ("prod".equals(ltype)) {
				sstate = SceneConstants.SCENE_PROD;
			} else if ("draft".equals(ltype)) {
				// 除超级管理员，草稿只能查看自己创建的现场
				if (ShiroUtils.getUserId() != Constant.SUPER_ADMIN) {
					wrapper.eq("creator_id", ShiroUtils.getUserId());
				}
			}
			wrapper.eq("scene_state", sstate);
		}

		if (liveState != null) {
			wrapper.eq("live_state", liveState);
		}

		if (null != tenantId){
			wrapper.eq("tenant_id", tenantId);
		}

//		if (null != tenantId){
//			wrapper.eq("tenant_id", tenantId);
//		}
		// 后台列表排序需要和对外数据接口排序一致，变动后需同步调整luceneservice排序
		wrapper.orderBy("is_top", false).orderBy("priority", false).orderBy("live_state", true)
				.orderBy("live_start", false).orderBy("id", false);
		Page<LiveSceneEntity> page = new Page<>(pageNo, pageSize);
		page = this.selectPage(page, wrapper);
		if (null != page && null != page.getRecords() && page.getRecords().size() > 0) {
			Page<SceneEntityVo> retPage = new Page<>();
			retPage.setTotal(page.getTotal());
			retPage.setSize(page.getSize());
			retPage.setCurrent(page.getCurrent());

			List<SceneEntityVo> list = new ArrayList<>();
			SceneEntityVo tmpVo;
			for (LiveSceneEntity entity : page.getRecords()) {
				if (null != entity.getTenantId()){
					if (redisUtils.hexists(Constant.REDIS_SYS_TENANT_ENTITY, entity.getTenantId().toString())){
						entity.setTenantName(redisUtils.hget(Constant.REDIS_SYS_TENANT_ENTITY, entity.getTenantId().toString(), SysTenantEntity.class).getTenantName());
					}else {
						SysTenantEntity tenantEntity = tenantService.selectById(entity.getTenantId());
						if (tenantEntity != null) {
							redisUtils.hset(Constant.REDIS_SYS_TENANT_ENTITY, tenantEntity.getId().toString(), tenantEntity);
							entity.setTenantName(tenantEntity.getTenantName());
						}
					}
				}
				tmpVo = new SceneEntityVo(entity);
				// 创建人姓名
				if (null != entity.getCreatorId()) {
					SysUserEntity user = sysUserService.selectBaseById(Long.valueOf(entity.getCreatorId()));
					if (null != user) {
						tmpVo.setCreatorName(user.getRealname());
					}
				}
				tmpVo.setTitleImageShow(MaterialUtils.getMaterialUrl(entity.getTitleImage(), foreignProperties.getMediaurl()));
				// 查询阅读量
				// 20190305 TROY 优化：成品后获取对外点击量
				if (SceneConstants.SCENE_PROD.equals(entity.getSceneState())) {
					// 查询阅读量
					SceneCountVo sceneCountVo = liveSceneCountService.findRedisById(entity.getId());
					tmpVo.setViewsShow(sceneCountVo == null ? 0 : sceneCountVo.getViewsShow());
				}
				// END

				list.add(tmpVo);
			}
			retPage.setRecords(list);
			return retPage;
		}
		return page;
	}

	@Override
	@Transactional(readOnly = true)
	public PageUtils page(String title, Integer sceneType, Integer userId, String ltype, Integer pageNo,
			Integer pageSize) {
		// 检索记录
		Page<SceneEntityVo> page = new Page<SceneEntityVo>(pageNo, pageSize);
		Map<String, Object> params = new HashMap<String, Object>();
		// 标题
		if (StringUtils.isNotBlank(title)) {
			params.put("title", title);
		}
		// 现场类型
		if (null != sceneType) {
			params.put("sceneType", sceneType);
		}
		// params.put("ltype", ltype);
		params.put("userId", userId);
		params.put("deleteFlag", 0);
		// 现场状态
		int sstate = SceneConstants.SCENE_DRAFT;
		if ("check".equals(ltype)) {
			sstate = SceneConstants.SCENE_ONE;
		} else if ("prod".equals(ltype)) {
			sstate = SceneConstants.SCENE_PROD;
		} else if ("draft".equals(ltype)) {
			// 除超级管理员，草稿只能查看自己创建的现场
			if (ShiroUtils.getUserId() != Constant.SUPER_ADMIN) {
				params.put("creatorId", ShiroUtils.getUserId());
			}
		}
		params.put("ltype", sstate);
		List<SceneEntityVo> pageList = this.baseMapper.queryPageMap(page, params);
		List<SceneEntityVo> list = new ArrayList<SceneEntityVo>();
		if (pageList != null && pageList.size() > 0) {
			for (int i = 0; i < pageList.size(); i++) {
				SceneEntityVo bean = pageList.get(i);
				if (bean == null) {
					continue;
				}
				// 现场类型
				if (null != bean.getSceneType()) {
					bean.setSceneTypeStr(SceneConstants.SceneType.getNameByKey(bean.getSceneType()));
				}
				// 直播状态
				if (null != bean.getLiveState()) {
					bean.setLiveStateStr(SceneConstants.liveStates.get(bean.getLiveState()));
				}
				// 创建时间客户端呈现
				if (null != bean.getCreateDate()) {
					bean.setCreateDateStr(DATE_FORMAT.format(bean.getCreateDate()));
				}
				// 创建时间客户端呈现
				if (null != bean.getLiveStart()) {
					bean.setLiveStartStr(DATE_FORMAT.format(bean.getLiveStart()));
				}
				// 20190305 TROY 优化：成品后获取对外点击量
				if (SceneConstants.SCENE_PROD.equals(bean.getSceneState())) {
					// 查询阅读量
					SceneCountVo sceneCountVo = liveSceneCountService.findRedisById(bean.getId());
					bean.setViewsShow(sceneCountVo == null ? 0 : sceneCountVo.getViewsShow());
				}
				// END
				bean.setTitleImageShow( MaterialUtils.getMaterialUrl(bean.getTitleImage(), foreignProperties.getMediaurl()));
				list.add(bean);
			}
		}
		page.setRecords(list);
		return new PageUtils(page);
	}

	@Override
	public void save(SceneEntityVo liveScene) {
		if (null == liveScene || liveScene.getLiveEnd() == null) {
			throw new NullPointerException();
		}
		Date currDate = new Date();
		liveScene.setCreateDate(currDate);
		LiveSceneEntity entity = new LiveSceneEntity(liveScene);
		entity.init();
		// 保存标题图 20190320Anine:使用素材路径保存titleImage
//		entity.setTitleImage(saveTitleImage(materialFile));
		entity.setTitleImage(liveScene.getTitleImage());
		if (SceneConstants.SCENE_ONE.equals(liveScene.getSendToCheck())) {
			entity.setSceneState(SceneConstants.SCENE_ONE);
			entity.setSubmitDate(currDate);
		}
		entity.setChannelsName((liveScene.getChannelNameList()==null || liveScene.getChannelNameList().size()==0) ? null : StringUtils.join(liveScene.getChannelNameList().toArray(), ","));
		this.baseMapper.insert(entity);

		LiveSceneCountEntity liveSceneCountEntity = new LiveSceneCountEntity();
		liveSceneCountEntity.setSceneId(entity.getId());
		liveSceneCountService.save(liveSceneCountEntity);

		saveSceneChannels(entity, liveScene.getChannelIdList());

		// 生成记者流
		saveSceneReportersStream(entity, liveScene.getUserIdList(), null);
		// 插入check记录
		SysUserEntity userEntity = sysUserService.selectBaseById(ShiroUtils.getUserId());
		createOrUpdateSceneCheck(entity, liveScene.getSendToCheck(), userEntity);
	}

	private String saveMutimedia(MultipartFile file, SceneConstants.MediaType mediaType, Integer creatorId) {
		LiveMultimediaEntity multimediaEntity = new LiveMultimediaEntity();
		multimediaEntity.setMediaType(mediaType.getValue());
		multimediaEntity.setTitle(file.getOriginalFilename());
		Map<String, Object> mediaMap = liveMultimediaService.save(multimediaEntity, file, Long.valueOf(creatorId));
		String fileUrl = (String) mediaMap.get("fileUrl");
		return fileUrl;
	}
	@Override
	public R save(AppSceneEntityVo liveScene, MultipartFile titleFile, MultipartFile videoFile) {

		Date currDate = new Date();
		LiveSceneEntity entity = new LiveSceneEntity(liveScene);
		entity.init();
		entity.setUpdatorId(liveScene.getCreatorId());

		if(entity.getCreateDate() == null)
			entity.setCreateDate(currDate);
		entity.setUpdateDate(entity.getCreateDate());
		if(titleFile != null) {
			entity.setTitleImage(saveMutimedia(titleFile, SceneConstants.MediaType.IMAGE, liveScene.getCreatorId()));
		}
		if(SceneConstants.SceneType.VIDEO.getKey().equals(entity.getSceneType()) && videoFile != null) {
			entity.setVideoUrl(saveMutimedia(videoFile, SceneConstants.MediaType.VIDEO, liveScene.getCreatorId()));
		}
		if (SceneConstants.SCENE_ONE.equals(liveScene.getSendToCheck())) {
			entity.setSceneState(SceneConstants.SCENE_ONE);
			entity.setSubmitDate(currDate);
		}
		entity.setChannelsName((liveScene.getChannelNameList()==null || liveScene.getChannelNameList().size()==0) ? null : StringUtils.join(liveScene.getChannelNameList().toArray(), ","));
		this.baseMapper.insert(entity);

		LiveSceneCountEntity liveSceneCountEntity = new LiveSceneCountEntity();
		liveSceneCountEntity.setSceneId(entity.getId());
		liveSceneCountService.save(liveSceneCountEntity);

		saveSceneChannels(entity, liveScene.getChannelIdList());

		// 生成记者流
		saveSceneReportersStream(entity, liveScene.getUserIdList(), null);
		// 插入check记录
		SysUserEntity userEntity = sysUserService.selectBaseById(Long.valueOf(liveScene.getCreatorId()));
		createOrUpdateSceneCheck(entity, liveScene.getSendToCheck(), userEntity);
		return R.ok("现场保存成功");
	}

	/**
	 * 生成记者流
	 *
	 * @param liveScene
	 */
	private void saveSceneReportersStream(LiveSceneEntity liveScene, List<Integer> reporters, Date liveEnd) {
		if (reporters == null || reporters.size() <= 0) {
			return;
		}
		for (Integer userId : reporters) {
			SysUserEntity user = sysUserService.selectBaseById(Long.valueOf(userId));
			if (user == null) {
				continue;
			}
			LiveSceneLiveInfoEntity infoEntity = new LiveSceneLiveInfoEntity();
			infoEntity.setSceneId(liveScene.getId());
			infoEntity.setUserId(userId);
			infoEntity.setInfoName(user.getRealname());
			infoEntity.setInfoType(SceneConstants.InfoTypeEnum.REPORTER.getType());
			infoEntity.setIsShow(SceneConstants.STREAM_NOT_SHOW);
			infoEntity.setIsDefault(SceneConstants.NOT_DEFAULT);
			infoEntity.setStreamName(DigestUtils.md5Hex(userId.toString()));
			infoEntity.setAppName(liveScene.getSceneSign());
			infoEntity.setPushDomain(liveClient.liveStream().getLiveStream().getPushDomain());
			infoEntity.setLiveDomain(liveClient.liveStream().getLiveStream().getLiveDomain());
			infoEntity.setPushState(SceneConstants.PushEnum.NOT_START.getState());
			infoEntity.setTitleImage(liveScene.getTitleImage());

			//20210426 yang 默认不转文字
			infoEntity.setIsTxt(SceneConstants.STREAM_NOT_TXT);

			liveSceneLiveInfoService.save(infoEntity);

 			// 成品状态现场生成流地址
			// 20190307 TROY 增加现场类型允许直播判断
			if (SceneConstants.SceneType.isAllowLive(liveScene.getSceneType())
					&& SceneConstants.SCENE_PROD.equals(liveScene.getSceneState())) {
				saveOrUpdateInfoExt(infoEntity.getId(), infoEntity.getAppName(), infoEntity.getStreamName(), liveEnd, liveScene.getSceneType(), null,null);
			}
		}
	}

	private void deleteSceneReportersStream(Integer sceneId) {
		if (sceneId == null) {
			return;
		}
		Wrapper wrapper = new EntityWrapper<LiveSceneLiveInfoEntity>().eq("scene_id", sceneId).eq("info_type",
				SceneConstants.InfoTypeEnum.REPORTER.getType());
		liveSceneLiveInfoService.delete(wrapper);
	}

	private void updateSceneReporterStream(LiveSceneEntity sceneEntity, List<Integer> userIdList, Date liveEnd) {
		List<LiveSceneLiveInfoEntity> entityList = liveSceneLiveInfoService
				.selectList(new EntityWrapper<LiveSceneLiveInfoEntity>().eq("scene_id", sceneEntity.getId()));
		List<Integer> oldUserIdList = new ArrayList<>();
		List<Integer> listForAdd = new ArrayList<>();
		if (entityList != null && entityList.size() > 0) {
			// 删除新记者列表中不存在的原记者列表中存在的
			for (LiveSceneLiveInfoEntity infoEntity : entityList) {
				Integer userId = infoEntity.getUserId();
				oldUserIdList.add(userId);
				if (userId != null && (userIdList == null || !userIdList.contains(userId))) {
					liveSceneLiveInfoService.delete(new EntityWrapper<LiveSceneLiveInfoEntity>()
							.eq("scene_id", sceneEntity.getId()).eq("user_id", userId));
					liveSceneLiveInfoExtService
							.delete(new EntityWrapper<LiveSceneLiveInfoExtEntity>().eq("info_id", infoEntity.getId()));
				}
			}
		}
		// 增加原记者列表中不存在的，新记者列表中存在的
		if (userIdList != null && userIdList.size() > 0) {
			for (Integer userId : userIdList) {
				if (oldUserIdList == null || oldUserIdList.size() <= 0 || !oldUserIdList.contains(userId)) {
					listForAdd.add(userId);
				}
			}
		}
		saveSceneReportersStream(sceneEntity, listForAdd, liveEnd);
	}

	/**
	 * 更新check记录
	 *
	 * @param entity
	 */
	private void createOrUpdateSceneCheck(LiveSceneEntity entity, Integer sendToCheck, SysUserEntity user) {
		if (entity == null || entity.getId() == null || user == null) {
			return;
		}
		LiveSceneCheckEntity checkEntity = liveSceneCheckService
				.selectOne(new EntityWrapper<LiveSceneCheckEntity>().eq("scene_id", entity.getId()));
		if (checkEntity == null) {
			checkEntity = new LiveSceneCheckEntity();
			checkEntity.setSceneId(entity.getId());
		}
		checkEntity.setAuditorId(user.getUserId().intValue());
		checkEntity.setAuditorName(user.getRealname());
		checkEntity.setCheckDate(new Date());
		// 新建
		if (checkEntity.getId() == null) {
			if (SceneConstants.SCENE_ONE.equals(sendToCheck)) {
				checkEntity.setCheckInfo("新建现场并送审");
			} else {
				checkEntity.setCheckInfo("新建现场");
			}
			liveSceneCheckService.insert(checkEntity);
		} else {
			// 更新
			if (SceneConstants.SCENE_ONE.equals(sendToCheck)) {
				checkEntity.setCheckInfo("现场送审");
			} else {
				checkEntity.setCheckInfo("更新现场");
			}
			liveSceneCheckService.updateById(checkEntity);
		}
	}

	/**
	 * 保存标题图
	 *
	 * @param materialFile
	 * @return
	 */
	public String saveTitleImage(MultipartFile materialFile) {
		String serverMaterialPath = "";
		if (materialFile != null && !materialFile.isEmpty()) {
			String newMaterialName = FileUtils.createFileName() + "."
					+ FileUtils.getSuffix(materialFile.getOriginalFilename());
			serverMaterialPath = materiaFileProperties.getMediaPath() + "/" + MaterialUtils.getDateDir() + "/"
					+ newMaterialName;
			String newMaterialPath = realPathResolver.get(materiaFileProperties.getMateriaPath() + serverMaterialPath);
			try {
				FileUtils.copy(materialFile.getInputStream(), newMaterialPath);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return serverMaterialPath;
	}

	@Override
	@Transactional(readOnly = true)
	public SceneEntityVo info(Integer id) {
		if (null == id) {
			return null;
		}
		LiveSceneEntity entity = this.baseMapper.queryById(id);
		if (null == entity) {
			return null;
		}
		SceneEntityVo vo = new SceneEntityVo(entity);
		vo.setTitleImageShow( MaterialUtils.getMaterialUrl(entity.getTitleImage(), foreignProperties.getMediaurl()));
		vo.setVideoUrlShow(MaterialUtils.getMaterialUrl(entity.getVideoUrl(), foreignProperties.getMediaurl()));
		// 直播状态
		if (null != entity.getLiveState() && null != entity.getCasterId()) {
			// 如果正在直播，输出直播地址
			LiveCasterEntity casterEntity = liveCasterService.selectById(entity.getCasterId());
			if (null != casterEntity) {
				vo.setCasterId(casterEntity.getCasterId());
			}
		}

		// 获取人员信息
		EntityWrapper<LiveSceneLiveInfoEntity> ew = new EntityWrapper<>();
		ew.eq("scene_id", id);
		// 20190306 TROY 增加记者过滤
		ew.eq("info_type", SceneConstants.InfoTypeEnum.REPORTER.getType());
		// END
		List<LiveSceneLiveInfoEntity> infoEntities = liveSceneLiveInfoService.selectList(ew);
		if (null != infoEntities && infoEntities.size() > 0) {
			List<Integer> userIdList = new ArrayList<>();
			List<String> userNameList = new ArrayList<>();
			for (LiveSceneLiveInfoEntity infoEntity : infoEntities) {
				if (null == infoEntity.getUserId()) {
					continue;
				}
				SysUserEntity userEntity = sysUserService.selectBaseById(Long.valueOf(infoEntity.getUserId()));
				if (userEntity != null) {
					userIdList.add(infoEntity.getUserId());
					userNameList.add(userEntity.getRealname());
				}
			}
			vo.setUserIdList(userIdList);
			vo.setUserNameList(userNameList);
		}

		// 获取栏目信息
		EntityWrapper<LiveSceneChannelEntity> wrapper = new EntityWrapper<LiveSceneChannelEntity>();
		wrapper.eq("scene_id", id);
		List<LiveSceneChannelEntity> channelEntities = liveSceneChannelService.selectList(wrapper);
		if (null != channelEntities && channelEntities.size() > 0) {
			List<Integer> channelIdList = new ArrayList<>();
			List<String> channelNameList = new ArrayList<>();
			for (LiveSceneChannelEntity sceneChannelEntity : channelEntities) {
				if (null == sceneChannelEntity || null == sceneChannelEntity.getChannelId()) {
					continue;
				}
				LiveChannelEntity channelEntity = liveChannelService.selectById(sceneChannelEntity.getChannelId());
				if (channelEntity != null && channelEntity.getId() != null) {
					channelIdList.add(channelEntity.getId());
					channelNameList.add(channelEntity.getName());
				}
			}
			vo.setChannelIdList(channelIdList);
			vo.setChannelNameList(channelNameList);
		}

		if(null != entity.getAuditorId()){
			SysUserEntity user = sysUserService.selectBaseById(Long.valueOf(entity.getAuditorId()));
			if (null != user) {
				vo.setAuditorName(user.getRealname());
			}
		}

		// 创建人姓名
		if (null != entity.getCreatorId()) {
			SysUserEntity user = sysUserService.selectBaseById(Long.valueOf(entity.getCreatorId()));
			if (null != user) {
				vo.setCreatorName(user.getRealname());
			}
		}
		// 查询阅读量
		SceneCountVo sceneCountVo = liveSceneCountService.findRedisById(id);
		vo.setViewsShow(sceneCountVo == null ? 0 : sceneCountVo.getViewsShow());

		// 20190408 TROY 现场详情增加wapurl
		String path;
		if (null == entity.getSceneType()) {
			path = SceneConstants.SceneType.IMAGE.getPath();
		} else {
			path = SceneConstants.SceneType.getPathByKey(entity.getSceneType());
		}
		vo.setWapUrl(foreignProperties.getWapurl() + "/live/" + path + "/detail/" + id);

		return vo;
	}

	@Override
	public String update(SceneEntityVo liveScene, SysUserEntity updator) {
		if (null == liveScene || null == liveScene.getId() || liveScene.getLiveEnd() == null) {
			throw new NullPointerException();
		}
		// 20190221 TROY 更新校验，只读
		LiveSceneEntity dbScene = this.baseMapper.selectById(liveScene.getId());
		if (null == dbScene) {
			throw new NullPointerException();
		}

		LiveSceneEntity entity = new LiveSceneEntity(liveScene);
		entity.setSceneState(dbScene.getSceneState());
		entity.setLiveState(dbScene.getLiveState());
		if (null != updator && null != updator.getUserId()) {
			entity.setUpdatorId(updator.getUserId().intValue());
		}
		Date currDate = new Date();
		entity.setUpdateDate(currDate);
		// 保存标题图 20190320Anine:使用素材路径保存titleImage
//        entity.setTitleImage(liveScene.getTitleImage());
		if (StringUtils.isNotBlank(liveScene.getTitleImage())) {
			entity.setTitleImage(liveScene.getTitleImage());
		} else {
			entity.setTitleImage(dbScene.getTitleImage());
		}
		// 草稿状态的现场送审
		if (SceneConstants.SCENE_DRAFT.equals(entity.getSceneState())
				&& SceneConstants.SCENE_ONE.equals(liveScene.getSendToCheck())) {
			entity.setSceneState(SceneConstants.SCENE_ONE);
			entity.setSubmitDate(currDate);
		}
		//修改直播流
		// 20190613 TROY dbScene原只作为读数据使用，更新时titleImage若未变动赋值为空，导致lucene索引标题图置空
		// 增加空判断条件处理
		if (StringUtils.isNotBlank(entity.getTitleImage())) {
			dbScene.setTitleImage(entity.getTitleImage());
		}
		// END
		updateSceneReporterStream(dbScene, liveScene.getUserIdList(), liveScene.getLiveEnd());
		//修改栏目关系
		updateSceneChannels(dbScene, liveScene.getChannelIdList());
		entity.setChannelsName((liveScene.getChannelNameList()==null || liveScene.getChannelNameList().size()==0) ? null : StringUtils.join(liveScene.getChannelNameList().toArray(), ","));

		// 更新check记录
		createOrUpdateSceneCheck(entity, liveScene.getSendToCheck(), updator);
		// 更新阅读量
		LiveSceneCountEntity countEntity = liveSceneCountService.selectById(entity.getId());
		// 20190306 TROY 增加旧数据兼容判断
		if (null == countEntity) {
			countEntity = new LiveSceneCountEntity();
			countEntity.setSceneId(liveScene.getId());
			countEntity.setViewsShow(liveScene.getViewsShow());
			liveSceneCountService.save(countEntity);
		} else if (SceneConstants.SCENE_PROD.equals(entity.getSceneState()) && liveScene.getViewsShow() != null
				&& !countEntity.getViewsShow().equals(liveScene.getViewsShow())) {
			// 更新数据库
			countEntity.setViewsShow(liveScene.getViewsShow());
			liveSceneCountService.updateById(countEntity);
			// 更新redis
			liveSceneCountService.updateRedisById(entity.getId(), liveScene.getViewsShow());

		}
		// 20190531 TROY 兼容置空
		if (StringUtils.isBlank(entity.getLiveDescHref())) {
			entity.setLiveDescHref(" ");
		}
		this.baseMapper.updateById(entity);

		// 20190423 TONG 暂时手动更新
		this.baseMapper.updateByIdSelective(entity, new String[]{"videoUrl", "liveDesc", "sceneMark"});
		// 20190221 TROY 成品现场更新索引
		boolean isProduct = SceneConstants.SCENE_PROD.equals(dbScene.getSceneState());

		if (isProduct) {
			entity.setChannelsId((liveScene.getChannelIdList()==null || liveScene.getChannelIdList().size()==0) ? null : StringUtils.join(liveScene.getChannelIdList().toArray(), ","));
			entity.setChannelsName((liveScene.getChannelNameList()==null || liveScene.getChannelNameList().size()==0) ? null : StringUtils.join(liveScene.getChannelNameList().toArray(), ","));

			createSceneIndex(entity, dbScene.getCreateDate(), dbScene.getSceneState(), dbScene.getLiveState(),
					StringUtils.isBlank(liveScene.getTitleImage()) ? dbScene.getTitleImage() : liveScene
							.getTitleImage(), null);
			redisUtils.delete(SceneConstants.SCENE_REDIS_PREFIX + liveScene.getId());

			// 20210419_Matt 是否自动开关播设置，若为开启状态，则存入Redis
			if (entity.getIsAutoLive() == null){
				entity.setIsAutoLive(dbScene.getIsAutoLive());
			}
		}

		// 成品现场如果修改结束时间需要更新流地址
		// 20190307 TROY 增加现场类型直播判断
		String str = "";
		if (isProduct && SceneConstants.SceneType.isAllowLive(dbScene.getSceneType())
				&& !liveScene.getLiveEnd().equals(dbScene.getLiveEnd())) {
			List<LiveSceneLiveInfoEntity> infoEntities = liveSceneLiveInfoService
					.selectList(new EntityWrapper<LiveSceneLiveInfoEntity>().eq("scene_id", entity.getId()));

			// 更新现场源地址
			if (infoEntities != null) {
				for (LiveSceneLiveInfoEntity infoEntity : infoEntities) {
					if(infoEntity==null || infoEntity.getId()==null || infoEntity.getPushState().equals(1)){
						if(StringUtils.isNotBlank(str)){
							str += ",";
						}
						str += infoEntity.getInfoName();
						continue;
					}
					LiveStreams streams = liveClient.liveStream().generateStreamUrls(infoEntity.getAppName(),
							infoEntity.getStreamName(), entity.getLiveEnd());
					LiveSceneLiveInfoExtEntity extEntity = liveSceneLiveInfoExtService
							.selectByInfoId(infoEntity.getId());
					if (extEntity != null) {
						extEntity.setPushUrl(streams.getPushStreamUrl());
						extEntity.setPlayUrlRmtp(streams.getLiveStreamUrls()[0]);
						extEntity.setPlayUrlFlv(streams.getLiveStreamUrls()[1]);
						extEntity.setPlayUrlHls(streams.getLiveStreamUrls()[2]);
						liveSceneLiveInfoExtService.updateById(extEntity);
					}

				}
			}
		}
		if(StringUtils.isNotBlank(str)){
			str = "现场修改成功，但流名称为："+str + "正在直播中，直播流的有效期不能进行修改";
		}else{
			str = "现场修改成功";
		}
		return str;
	}

	@Override
	public R update(AppSceneEntityVo liveScene, LiveSceneEntity dbScene, MultipartFile titleFile, MultipartFile videoFile) {

		LiveSceneEntity entity = new LiveSceneEntity(liveScene);
		Date currDate = new Date();
		entity.setLiveState(dbScene.getLiveState());
		if(entity.getUpdateDate() == null)
			entity.setUpdateDate(currDate);
		// 草稿状态的现场送审
		if (SceneConstants.SCENE_DRAFT.equals(entity.getSceneState())
				&& SceneConstants.SCENE_ONE.equals(liveScene.getSendToCheck())) {
			entity.setSceneState(SceneConstants.SCENE_ONE);
			entity.setSubmitDate(currDate);
		}
		//修改直播流
		dbScene.setTitleImage(entity.getTitleImage());
		if(titleFile != null) {
			entity.setTitleImage(saveMutimedia(titleFile, SceneConstants.MediaType.IMAGE, liveScene.getCreatorId()));
		}
		if(SceneConstants.SceneType.VIDEO.getKey().equals(entity.getSceneType()) || videoFile != null) {
			entity.setVideoUrl(saveMutimedia(videoFile, SceneConstants.MediaType.VIDEO, liveScene.getCreatorId()));
		}
		updateSceneReporterStream(dbScene, liveScene.getUserIdList(), liveScene.getLiveEnd());
		//修改栏目关系
		updateSceneChannels(dbScene, liveScene.getChannelIdList());
		entity.setChannelsName((liveScene.getChannelNameList()==null || liveScene.getChannelNameList().size()==0) ? null : StringUtils.join(liveScene.getChannelNameList().toArray(), ","));

		// 更新check记录
		SysUserEntity updator = sysUserService.selectBaseById(Long.valueOf(entity.getUpdatorId()));
		createOrUpdateSceneCheck(entity, liveScene.getSendToCheck(), updator);
		this.baseMapper.updateById(entity);
		// 20190423 TONG 暂时手动更新
		this.baseMapper.updateByIdSelective(entity, new String[]{"videoUrl", "liveDesc", "sceneMark"});

		// 20210419_Matt 是否自动开关播设置，若为开启状态，则存入Redis
		if (entity.getIsAutoLive() == null){
			entity.setIsAutoLive(dbScene.getIsAutoLive());
		}

		return R.ok("现场更新成功");
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void check(Integer id, Integer pass, SysUserEntity user) {
		if (null == id) {
			throw new NullPointerException();
		}
		LiveSceneEntity scene = this.selectById(id);
		if (null == scene) {
			throw new NullPointerException();
		}

		if (SceneConstants.SCENE_PROD.equals(scene.getSceneState())) {
			log.error("LiveScene has been checked");
			return;
		}

		// LiveSceneEntity entity = new LiveSceneEntity(id);
		// 审核信息
		LiveSceneCheckEntity checkEntity = liveSceneCheckService
				.selectOne(new EntityWrapper<LiveSceneCheckEntity>().eq("scene_id", id));
		if (checkEntity == null) {
			checkEntity = new LiveSceneCheckEntity();
			checkEntity.setSceneId(id);
		}
		if (null != user && null != user.getUserId()) {
			checkEntity.setAuditorId(user.getUserId().intValue());
			checkEntity.setAuditorName(user.getRealname());
		}
		Date now = new Date();
		checkEntity.setCheckDate(now);
		checkEntity.setTenantId(scene.getTenantId());
		// 0：不通过
		if (null != pass && pass == 0) {
			scene.setSceneState(SceneConstants.SCENE_DRAFT);
			checkEntity.setCheckInfo("审核不通过");
		} else {
			scene.setSceneState(SceneConstants.SCENE_PROD);
			checkEntity.setCheckInfo("审核通过");
		}
		scene.setAuditDate(new Date());
		scene.setAuditorId(user.getUserId().intValue());
		// 更新现场
		this.updateById(scene);
		if (null == pass || pass == 1) {
			// 20190307 TROY 如果现场类型允许直播，生成直播相关数据
			if (SceneConstants.SceneType.isAllowLive(scene.getSceneType())) {
				// 生成记者流
				List<LiveSceneLiveInfoEntity> infoEntities = liveSceneLiveInfoService
						.selectList(new EntityWrapper<LiveSceneLiveInfoEntity>().eq("scene_id", scene.getId()));
				if (infoEntities != null && infoEntities.size() > 0) {
					for (LiveSceneLiveInfoEntity entity : infoEntities) {
						saveOrUpdateInfoExt(entity.getId(), entity.getAppName(), entity.getStreamName(),
								scene.getLiveEnd(), scene.getSceneType(), scene.getTenantId(),null);
					}
				}

				// 审核通过自动生成现场源
				LiveSceneLiveInfoEntity entity = liveSceneLiveInfoService.selectOne(
						new EntityWrapper<LiveSceneLiveInfoEntity>()
								.eq("scene_id", scene.getId())
								.eq("info_name", "默认现场源")
				);

				if (null == entity){
					LiveSceneLiveInfoEntity liveSceneLiveInfoEntity = new LiveSceneLiveInfoEntity();
					liveSceneLiveInfoEntity.setSceneId(scene.getId());
					liveSceneLiveInfoEntity.setInfoName("默认现场源");
					liveSceneLiveInfoEntity.setInfoType(SceneConstants.InfoTypeEnum.BROADCASTING_ROOM.getType());
					liveSceneLiveInfoEntity.setTitleImage(scene.getTitleImage());
					liveSceneLiveInfoEntity.setIsShow(SceneConstants.STREAM_SHOW);
					liveSceneLiveInfoEntity.setIsDefault(SceneConstants.DEFAULT);
					liveSceneLiveInfoEntity.setTenantId(scene.getTenantId());

					// 20210226_Matt 默认现场源默认转文字为1

					//20210426 yang 默认现场源默认转文字为 0
					liveSceneLiveInfoEntity.setIsTxt(0);

					saveLiveInfoAndEntity(liveSceneLiveInfoEntity, scene.getSceneSign(),
							DigestUtils.md5Hex(scene.getSceneSign()), scene.getLiveEnd(), scene.getSceneType());
				}

				// 添加录制配置
				RpcResponse response = null;
				// TODO 根据现场类型状态进行控制
				if (SceneConstants.SceneType.AUDIO.getKey().equals(scene.getSceneType()) || SceneConstants.SceneType.MERGE.getKey().equals(scene.getSceneType()) || SceneConstants.SceneType.VIDEO.getKey().equals(scene.getSceneType()) || SceneConstants.SceneType.VR.getKey().equals(scene.getSceneType())) {
					if (SceneConstants.SceneType.AUDIO.getKey().equals(scene.getSceneType()))
						response = liveClient.liveRecord().addLiveRecordVodMp3Config(scene.getSceneSign(), "*");
					else
						response = liveClient.liveRecord().addLiveRecordVodMp4Config(scene.getSceneSign(), "*");
					if (response == null || response.getResult() != ResponseResult.SUCCESS) {
						log.error("startLive error , status : " + response.getStatus() + ", msg : " + response.getData());
						throw new RuntimeException("添加录制配置错误");
					}
				}
			}
			// 20200330_Mxy 初始化拖动排序标识
			List<LiveSceneChannelEntity> sceneChannelEntityList = liveSceneChannelService.getBySceneId(scene.getId());
			if (null != sceneChannelEntityList && sceneChannelEntityList.size() > 0){
				sceneChannelEntityList.forEach(list -> list.setDragSort(now.getTime() / 1000));
			}
			// 增加列表索引
			createSceneIndex(scene, null, null, null, null, null);
		}
		liveSceneCheckService.saveOrUpdate(checkEntity);
	}

	private void saveLiveInfoAndEntity(LiveSceneLiveInfoEntity entity, String appName, String streamName,
			Date liveEndDate, Integer sceneType) {

		entity.setAppName(appName);
		entity.setStreamName(streamName);
		entity.setPushDomain(liveClient.liveStream().getLiveStream().getPushDomain());
		entity.setLiveDomain(liveClient.liveStream().getLiveStream().getLiveDomain());
		entity.setPushState(SceneConstants.PushEnum.NOT_START.getState());
		liveSceneLiveInfoService.save(entity);
		// 保存现场源地址
		saveOrUpdateInfoExt(entity.getId(), appName, streamName, liveEndDate, sceneType, entity.getTenantId(),entity.getPullUrl());
	}

	private void saveOrUpdateInfoExt(Integer infoId, String appName, String streamName, Date liveEndDate, Integer sceneType, Long tenantId,String pullUrl) {
		LiveSceneLiveInfoExtEntity infoExtEntity = liveSceneLiveInfoExtService.selectByInfoId(infoId);
		if (infoExtEntity == null) {
			infoExtEntity = new LiveSceneLiveInfoExtEntity();
			infoExtEntity.setInfoId(infoId);
			if (tenantId != null)
				infoExtEntity.setTenantId(tenantId);
		}

		LiveStreams streams = liveClient.liveStream().generateStreamUrls(appName, streamName, liveEndDate);
		String pushUrl = streams.getPushStreamUrl();
		String playUrlRmtp = streams.getLiveStreamUrls()[0];
		String playUrlFlv = streams.getLiveStreamUrls()[1];
		String appendParam = "";
		if(SceneConstants.SceneType.AUDIO.getKey().equals(sceneType)) {//音频
			appendParam = "onlyaudio=1";
			if (pushUrl.indexOf("?") > 0)
				pushUrl += "&";
			else
				pushUrl += "?";
			if (playUrlRmtp.indexOf("?") > 0)
				playUrlRmtp += "&";
			else
				playUrlRmtp += "?";
			if (playUrlFlv.indexOf("?") > 0)
				playUrlFlv += "&";
			else
				playUrlFlv += "?";
		}
		infoExtEntity.setPushUrl(pushUrl + appendParam);
		infoExtEntity.setPlayUrlRmtp(playUrlRmtp + appendParam);
		// 20200512_Mxy 修改http为https协议
		StringBuilder sbUrlFlv = new StringBuilder(playUrlFlv);
//		playUrlFlv = sbUrlFlv.insert(4, "s").toString();
		String playUrlHls = streams.getLiveStreamUrls()[2];
//		if (StringUtils.isNotBlank(streams.getLiveStreamUrls()[2])){
//			StringBuilder sbUrlHls = new StringBuilder(streams.getLiveStreamUrls()[2]);
//			playUrlHls = sbUrlHls.insert(4, "s").toString();
//		}
		infoExtEntity.setPlayUrlFlv(playUrlFlv + appendParam);
		infoExtEntity.setPlayUrlHls(playUrlHls);//仅支持FLV与RTMP格式的播流地址
		infoExtEntity.setPullUrl(pullUrl);

		liveSceneLiveInfoExtService.saveOrUpdate(infoExtEntity);
	}

	/**
	 * 数据流列表
	 *
	 * @return
	 */
	@Override
	@Transactional(readOnly = true)
	public List<LiveInfoVo> streamList(Map<String, Object> params) {
		if (params == null || params.get("sceneId") == null) {
			return null;
		}
		Integer sceneId = Integer.parseInt((String) params.get("sceneId"));
		// 20190310 TROY 增加优先级排序
		List<LiveSceneLiveInfoEntity> list = liveSceneLiveInfoService
				.selectList(new EntityWrapper<LiveSceneLiveInfoEntity>().eq("scene_id", sceneId)
						.orderBy("priority", false).orderBy("id", false));
		if (null == list || list.size() <= 0) {
			return null;
		}
		List<LiveInfoVo> liveInfoList = new ArrayList<>();
		LiveInfoVo infoVo;
		for (LiveSceneLiveInfoEntity info : list) {
			LiveSceneLiveInfoExtEntity extEntity = liveSceneLiveInfoExtService.selectByInfoId(info.getId());
			info.setExtEntity(extEntity);
			infoVo = new LiveInfoVo(info);
			if (null != info.getUserId()) {
				SysUserEntity userEntity = sysUserService.selectBaseById(Long.valueOf(info.getUserId()));
				if (userEntity != null) {
					infoVo.setUserName(userEntity.getRealname());
				}
			}
			// 20200316_Mxy 图片压缩
			infoVo.setTitleImageShow(MaterialUtils.getMaterialUrl(compressImage(info.getTitleImage()), foreignProperties.getMediaurl()));
			// infoVo.setTitleImageShow(MaterialUtils.getMaterialUrl(info.getTitleImage(), foreignProperties.getMediaurl()));
			liveInfoList.add(infoVo);
		}
		return liveInfoList;
	}

	@Override
	public void delete(Integer id) {
		// 20190221 TROY 逻辑删除
		if (null == id) {
			return;
		}
		LiveSceneEntity entity = new LiveSceneEntity();
		entity.setId(id);
		entity.setDeleteFlag(SceneConstants.IS_DELETE);
		entity.setUpdateDate(new Date());
		this.baseMapper.updateById(entity);

		try {
			luceneService.deleteIndex(LuceneTypeEnum.LUCENE_SCENE.getType(), "id", String.valueOf(id));
			redisUtils.delete(SceneConstants.SCENE_REDIS_PREFIX + id);
		} catch (IOException e) {
			e.printStackTrace();
		}

		// this.baseMapper.deleteById(id);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void deleteBatch(Integer[] ids) {
		// 20190221 TROY 逻辑删除
//		LiveSceneEntity entity = new LiveSceneEntity();
//		entity.setDeleteFlag(SceneConstants.IS_DELETE);
//		entity.setUpdateDate(new Date());
//		EntityWrapper<LiveSceneEntity> wrapper = new EntityWrapper<>();
//		wrapper.in("id", ids);
//
//		this.baseMapper.update(entity, wrapper);

		for(Integer id : ids) {
			LiveSceneEntity sceneEntity = this.selectById(id);

			if(sceneEntity != null) {
                sceneEntity.setDeleteFlag(SceneConstants.IS_DELETE);
                sceneEntity.setUpdateDate(new Date());
                this.updateById(sceneEntity);

				List<LiveSceneLiveInfoEntity> liveInfos = liveSceneLiveInfoService.selectLiveInfoByInfoType(sceneEntity.getId(),SceneConstants.InfoTypeEnum.THIRD.getType());
				if(liveInfos!=null && liveInfos.size()>0){
					for(LiveSceneLiveInfoEntity liveInfo : liveInfos){
						try {
							liveClient.livePullStream().DeleteLivePullStreamInfoConfig(liveInfo.getAppName(),liveInfo.getStreamName());
						} catch (ClientException e) {
							e.printStackTrace();
						}
					}
				}

//				liveClient.liveRecord().deleteLiveRecordVodConfig(sceneEntity.getSceneSign(), "*");
//				if(sceneEntity.getCasterId() != null) {
//					redisUtils.delete(SceneConstants.CASTER_LIVETEMPLATEIDS + id);
//					LiveCasterEntity casterEntity = liveCasterService.selectById(sceneEntity.getCasterId());
//					if(casterEntity == null) return;
//					liveClient.liveRecord().deleteLiveRecordVodConfig(casterEntity.getAppName(), casterEntity.getStreamName());
//					if(casterEntity.getIsDelete().equals(SceneConstants.NOT_DELETE))
//						liveClient.liveCaster().deleteCaster(casterEntity.getCasterId());
//				}
			}
		}
		// TODO TROY 暂时用循环删除
		for (Integer id : ids) {
			try {
				luceneService.deleteIndex(LuceneTypeEnum.LUCENE_SCENE.getType(), "id", String.valueOf(id));
				redisUtils.delete(SceneConstants.SCENE_REDIS_PREFIX + id);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		// this.baseMapper.deleteBatchIds(Arrays.asList(ids));
	}

	@Override
	public R createStream(LiveSceneLiveInfoEntity liveInfoEntity) {
		LiveSceneEntity scene = selectById(liveInfoEntity.getSceneId());
		if (scene == null) {
			return R.error("现场不存在");
		}
		String streamName = UUID.randomUUID().toString().replaceAll("-", "");

		if (SceneConstants.InfoTypeEnum.REPORTER.getType().equals(liveInfoEntity.getInfoType())) {
			if (null == liveInfoEntity.getUserId()) {
				return R.error("记者信息不能为空");
			}
			// 20190308 TROY 记者流只能存在一个，防止直播时地址错乱
			boolean exist = liveSceneLiveInfoService.existInfo(liveInfoEntity.getSceneId(), liveInfoEntity.getUserId());
			if (exist) {
				return R.error("现场已存在记者信息，不可重复添加");
			}
			// END
			if (StringUtils.isBlank(liveInfoEntity.getInfoName())) {
				// 获取用名
				SysUserEntity user = sysUserService.selectBaseById(Long.valueOf(liveInfoEntity.getUserId()));
				liveInfoEntity.setInfoName(null != user ? user.getRealname() : "默认记者");
			}
			streamName = DigestUtils.md5Hex(liveInfoEntity.getUserId().toString());
		} else if(SceneConstants.InfoTypeEnum.THIRD.getType().equals(liveInfoEntity.getInfoType())){
			if(StringUtils.isBlank(liveInfoEntity.getPullUrl()) || liveInfoEntity.getPullStart()==null || liveInfoEntity.getPullEnd()==null){
				return R.error("拉流信息不完整");
			}

			try {
				DescribeLivePullStreamConfigResponse response = liveClient.livePullStream().describeLivePullStreamConfig();
				if(response.getLiveAppRecordList()!=null && response.getLiveAppRecordList().size()>=10){
					return R.error("最多支持配置10个拉流。");
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			if(liveInfoEntity.getPullUrl().indexOf("rtmp://")!=0 && liveInfoEntity.getPullUrl().indexOf(".m3u8")<=0 && liveInfoEntity.getPullUrl().indexOf(".flv")<=0){
				return R.error("只支持RTMP、FLV、HLS格式直播地址进行拉流");
			}

			liveInfoEntity.setUserId(null);
			if (StringUtils.isBlank(liveInfoEntity.getInfoName())){
				liveInfoEntity.setInfoName("第三方流");
			}

		    try {
		    	SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
			    TimeZone utcZone = TimeZone.getTimeZone("UTC");
			    sf.setTimeZone(utcZone);
		    	liveClient.livePullStream().addLivePullStreamInfoConfig(scene.getSceneSign(), streamName, liveInfoEntity.getPullUrl(), sf.format(liveInfoEntity.getPullStart()), sf.format(liveInfoEntity.getPullEnd()));
			} catch (Exception e) {
				e.printStackTrace();
			}
			
		}else {
			liveInfoEntity.setUserId(null);
			if (StringUtils.isBlank(liveInfoEntity.getInfoName()))
				liveInfoEntity.setInfoName("默认现场源");
		}

		liveInfoEntity.setAppName(scene.getSceneSign());
//		String titleImage = saveTitleImage(uploadPicName);
//		titleImage = StringUtils.isNotBlank(titleImage) ? titleImage : scene.getTitleImage();
//		liveInfoEntity.setTitleImage(titleImage);
		// 20190309 TROY 根据前端传值处理
		liveInfoEntity.setIsShow(
				null == liveInfoEntity.getIsShow() ? SceneConstants.STREAM_NOT_SHOW : liveInfoEntity.getIsShow());
		// 判断是否设置为默认流
		setDefaultStream(liveInfoEntity);
		saveLiveInfoAndEntity(liveInfoEntity, scene.getSceneSign(), streamName, scene.getLiveEnd(), scene.getSceneType());

		// 20190309 TROY 对外发布流信息更新，更新 正在直播 的现场
		if (SceneConstants.STREAM_SHOW.equals(liveInfoEntity.getIsShow())
				&& SceneConstants.LIVE_STATE_DIRECT.equals(scene.getLiveState())) {
			redisUtils.delete(SceneConstants.SCENE_REDIS_PREFIX + scene.getId());
		}
		// END
		return R.ok();
	}

	@Override
	public R updateStream(LiveSceneLiveInfoEntity liveInfoEntity) {
		if (null == liveInfoEntity.getId()) {
			return R.error("流信息不存在");
		}

		// 流信息
		LiveSceneLiveInfoEntity src = liveSceneLiveInfoService.selectById(liveInfoEntity.getId());
		if (null == src || null == src.getSceneId()) {
			return R.error("流信息错误");
		}
		if(SceneConstants.PushEnum.PUSHING.getState().equals(src.getPushState()) && (src.getInfoType()!=liveInfoEntity.getInfoType() && !src.getInfoType().equals(liveInfoEntity.getInfoType()))){
			return R.error("正在直播的流不能修改流类型");
		}

		// 现场信息
		LiveSceneEntity sceneEntity = selectById(src.getSceneId());
		if (sceneEntity == null) {
			return R.error("流信息无归属现场");
		}
		if (SceneConstants.InfoTypeEnum.REPORTER.getType().equals(liveInfoEntity.getInfoType())) {
			if (null == liveInfoEntity.getUserId()) {
				return R.error("记者信息不能为空");
			}
			// 20190308 TROY 记者流只能存在一个，防止直播时地址错乱
			if (!liveInfoEntity.getUserId().equals(src.getUserId())) {
				boolean exist = liveSceneLiveInfoService.existInfo(liveInfoEntity.getSceneId(),
						liveInfoEntity.getUserId());
				if (exist) {
					return R.error("现场已存在记者信息，不可重复添加");
				}
			}
			// END
			if (StringUtils.isBlank(liveInfoEntity.getInfoName())) {
				// 获取用户名
				SysUserEntity user = sysUserService.selectBaseById(Long.valueOf(liveInfoEntity.getUserId()));
				liveInfoEntity.setInfoName(null != user ? user.getRealname() : "默认记者");
			}
		}else {
			liveInfoEntity.setUserId(null);
			if (StringUtils.isBlank(liveInfoEntity.getInfoName()))
				liveInfoEntity.setInfoName("默认现场源");
		}

		// userId变动，或记者流和直播间流互改
		// TODO 20190309 TROY 逻辑待确定
		boolean adjust = (null == src.getUserId() && null != liveInfoEntity.getUserId())
				|| (null != src.getUserId() && !src.getUserId().equals(liveInfoEntity.getUserId()));
		liveInfoEntity.setStreamName(src.getStreamName());
		if (adjust) {
			if (SceneConstants.InfoTypeEnum.REPORTER.getType() == liveInfoEntity.getInfoType()) {
				liveInfoEntity.setStreamName(DigestUtils.md5Hex(liveInfoEntity.getUserId().toString()));
			} else
				liveInfoEntity.setStreamName(UUID.randomUUID().toString().replaceAll("-", ""));
		}
		
		//第三方流
		boolean flag = false;
		if(SceneConstants.InfoTypeEnum.THIRD.getType().equals(liveInfoEntity.getInfoType())){

			if(StringUtils.isBlank(liveInfoEntity.getPullUrl()) || liveInfoEntity.getPullStart()==null || liveInfoEntity.getPullEnd()==null){
				return R.error("拉流信息不完整");
			}

			try {
				DescribeLivePullStreamConfigResponse response = liveClient.livePullStream().describeLivePullStreamConfig();
				if(response.getLiveAppRecordList()!=null && response.getLiveAppRecordList().size()>=10){
					return R.error("最多支持配置10个拉流。");
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			if(liveInfoEntity.getPullUrl().indexOf("rtmp://")!=0 && liveInfoEntity.getPullUrl().indexOf(".m3u8")<=0 && liveInfoEntity.getPullUrl().indexOf(".flv")<=0){
				return R.error("只支持RTMP、FLV、HLS格式直播地址进行拉流");
			}

			liveInfoEntity.setUserId(null);
			if (StringUtils.isBlank(liveInfoEntity.getInfoName())){
				liveInfoEntity.setInfoName("第三方流");
			}

			LiveSceneLiveInfoExtEntity ext = liveSceneLiveInfoExtService.selectByInfoId(liveInfoEntity.getId());
			if(!liveInfoEntity.getInfoType().equals(src.getInfoType()) || !liveInfoEntity.getPullStart().equals(src.getPullStart()) 
					|| !liveInfoEntity.getPullEnd().equals(src.getPullEnd()) || !liveInfoEntity.getPullUrl().equals(ext.getPullUrl())){
				flag = true;
				try {
					liveClient.livePullStream().DeleteLivePullStreamInfoConfig(src.getAppName(), src.getStreamName());
			    	SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
				    TimeZone utcZone = TimeZone.getTimeZone("UTC");
				    sf.setTimeZone(utcZone);
			    	liveClient.livePullStream().addLivePullStreamInfoConfig(src.getAppName(), liveInfoEntity.getStreamName(), liveInfoEntity.getPullUrl(), sf.format(liveInfoEntity.getPullStart()), sf.format(liveInfoEntity.getPullEnd()));
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			
		} else{
			if(SceneConstants.InfoTypeEnum.THIRD.getType().equals(src.getInfoType())){
				flag = true;
				try {
					liveClient.livePullStream().DeleteLivePullStreamInfoConfig(src.getAppName(), src.getStreamName());
				} catch (ClientException e) {
					e.printStackTrace();
				}
			}
			liveInfoEntity.setPullUrl(null);
			liveInfoEntity.setPullStart(null);
			liveInfoEntity.setPullEnd(null);
		}
		
		
//		liveInfoEntity.setTitleImage(saveTitleImage(uploadPicName));
		// 判断是否设置为默认流
		setDefaultStream(liveInfoEntity);
		liveSceneLiveInfoService.updateById(liveInfoEntity);
		// streamName更改修改ext
		// 20190322 TROY BUG修复
		if (!src.getStreamName().equals(liveInfoEntity.getStreamName()) || flag) {
			// 更新流地址信息
			saveOrUpdateInfoExt(liveInfoEntity.getId(), src.getAppName(), liveInfoEntity.getStreamName(),
					sceneEntity.getLiveEnd(), sceneEntity.getSceneType(), null,liveInfoEntity.getPullUrl());
		}

		// 20190309 TROY 对外发布流信息更新，更新 正在直播 的现场
//		boolean refresh = (liveInfoEntity.getIsShow() == null && src.getIsShow() != null)
//				|| (null != liveInfoEntity.getIsShow() && !liveInfoEntity.getIsShow().equals(src.getIsShow()));
//		if (refresh && SceneConstants.LIVE_STATE_DIRECT.equals(sceneEntity.getLiveState())) {
//			redisUtils.delete(SceneConstants.SCENE_REDIS_PREFIX + sceneEntity.getId());
//		}
		// 20190814 TONG 不管修改哪些字段，对外发布流信息更新，更新 正在直播 的现场
		if (SceneConstants.LIVE_STATE_DIRECT.equals(sceneEntity.getLiveState())) {
			redisUtils.delete(SceneConstants.SCENE_REDIS_PREFIX + sceneEntity.getId());
		}
		// END

		return R.ok();
	}


	private void setDefaultStream(LiveSceneLiveInfoEntity liveInfoEntity) {
		if (liveInfoEntity == null) {
			return;
		}
		// 判断是否设置为默认流
		if (SceneConstants.DEFAULT.equals(liveInfoEntity.getIsDefault())) {
			LiveSceneLiveInfoEntity entity = liveSceneLiveInfoService
					.selectOne(new EntityWrapper<LiveSceneLiveInfoEntity>().eq("is_default", SceneConstants.DEFAULT).eq("scene_id", liveInfoEntity.getSceneId()));
			if (entity != null) {
				entity.setIsDefault(SceneConstants.NOT_DEFAULT);
				liveSceneLiveInfoService.updateById(entity);
			}
			liveInfoEntity.setIsDefault(SceneConstants.DEFAULT);
		}
	}
	@Override
	public R streamPullStart(Integer id){
		if (null == id) {
			return R.error("参数错误");
		}
		LiveSceneLiveInfoEntity infoEntity = liveSceneLiveInfoService.selectById(id);
		return streamPullStartEntity(infoEntity);
	}

	public R streamPullStartEntity(LiveSceneLiveInfoEntity infoEntity) {

		if (null == infoEntity) {
			return R.error("该直播流不存在，不能进行开始拉流操作！");
		}
		if (!SceneConstants.InfoTypeEnum.THIRD.getType().equals(infoEntity.getInfoType())) {
			return R.error("该直播流不是第三方流，不能进行开始拉流操作！");
		}
		if (infoEntity.getPullEnd().before(new Date())) {
			return R.error("该直播流的拉流结束时间超过当前时间，不能进行开始拉流操作！");
		}
		if (infoEntity.getPushState().equals(1)) {
			return R.error("该直播流已经开始拉流，不能进行开始拉流操作！");
		}
		if (infoEntity.getPushState().equals(3) || infoEntity.getPushState().equals(4)) {
			return R.error("该直播流不能进行开始拉流操作！");
		}

		try {
			LiveSceneLiveInfoExtEntity ext = liveSceneLiveInfoExtService.selectByInfoId(infoEntity.getId());
			SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
			TimeZone utcZone = TimeZone.getTimeZone("UTC");
			sf.setTimeZone(utcZone);
			liveClient.livePullStream().DeleteLivePullStreamInfoConfig(infoEntity.getAppName(), infoEntity.getStreamName());
			liveClient.livePullStream().addLivePullStreamInfoConfig(infoEntity.getAppName(), infoEntity.getStreamName(), ext.getPullUrl(), sf.format(new Date()), sf.format(infoEntity.getPullEnd()));
			infoEntity.setPushState(3);
			liveSceneLiveInfoService.updateById(infoEntity);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return R.ok();
	}

	@Override
	public R streamPullEnd(Integer id){
		if (null == id) {
			return R.error("参数错误");
		}
		LiveSceneLiveInfoEntity infoEntity = liveSceneLiveInfoService.selectById(id);
		return streamPullEndEntity(infoEntity);
	}

	public R streamPullEndEntity(LiveSceneLiveInfoEntity infoEntity) {

		if (null == infoEntity) {
			return R.error("该直播流不是第三方流，不能进行停止拉流操作！");
		}
		if (!SceneConstants.InfoTypeEnum.THIRD.getType().equals(infoEntity.getInfoType())) {
			return R.error("该直播流不是第三方流，不能进行停止拉流操作！");
		}
		if (!infoEntity.getPushState().equals(1)) {
			return R.error("该直播流还未开始拉流，不能进行停止拉流操作！");
		}
		if (infoEntity.getPushState().equals(3) || infoEntity.getPushState().equals(4)) {
			return R.error("该直播流不能进行停止拉流操作！");
		}

		try {
			liveClient.livePullStream().DeleteLivePullStreamInfoConfig(infoEntity.getAppName(), infoEntity.getStreamName());
			infoEntity.setPushState(4);
			liveSceneLiveInfoService.updateById(infoEntity);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return R.ok();
	}

	@Override
	@Transactional(readOnly = true)
	public R streamInfo(Integer id) {
		if (null == id) {
			return null;
		}
		LiveSceneLiveInfoEntity infoEntity = liveSceneLiveInfoService.selectById(id);
		if (null == infoEntity) {
			return R.ok();
		}
		LiveSceneLiveInfoExtEntity extEntity = liveSceneLiveInfoExtService.selectByInfoId(infoEntity.getId());
		infoEntity.setExtEntity(extEntity);
		LiveInfoVo liveInfoVo = new LiveInfoVo(infoEntity);
		if (null != infoEntity.getUserId()) {
			SysUserEntity userEntity = sysUserService.selectBaseById(Long.valueOf(infoEntity.getUserId()));
			if (userEntity != null) {
				liveInfoVo.setUserName(userEntity.getRealname());
			}
		}
		// 20200316_Mxy 图片压缩
		liveInfoVo.setTitleImageShow(MaterialUtils.getMaterialUrl(compressImage(infoEntity.getTitleImage()), foreignProperties.getMediaurl()));
		// liveInfoVo.setTitleImageShow(MaterialUtils.getMaterialUrl(infoEntity.getTitleImage(), foreignProperties.getMediaurl()));
		return R.ok().put("liveInfoVo", liveInfoVo);
	}

	@Override
	public R deleteStream(Integer[] infoIds) {
		if (infoIds == null || infoIds.length <= 0) {
			return R.error("参数错误");
		}
		List<Integer> sceneList = new ArrayList<>();
		for (Integer infoId : infoIds) {
			LiveSceneLiveInfoEntity infoEntity = liveSceneLiveInfoService.selectById(infoId);
			if (infoEntity != null) {
				// 删除从表信息
				liveSceneLiveInfoExtService.deleteByMap(new MapUtils().put("info_id", infoId));
				liveSceneLiveInfoService.deleteById(infoId);
				if (SceneConstants.STREAM_SHOW.equals(infoEntity.getIsShow())
						&& !sceneList.contains(infoEntity.getSceneId())) {
					sceneList.add(infoEntity.getSceneId());
				}
				if(SceneConstants.InfoTypeEnum.THIRD.getType().equals(infoEntity.getInfoType())){
					try {
						liveClient.livePullStream().DeleteLivePullStreamInfoConfig(infoEntity.getAppName(),infoEntity.getStreamName());
					} catch (ClientException e) {
						e.printStackTrace();
					}
				}
			}
		}
		// 20190309 TROY 删除已发布流信息，更新现场信息
		for (Integer sceneId : sceneList) {
			redisUtils.delete(SceneConstants.SCENE_REDIS_PREFIX + sceneId);
		}
		return R.ok();
	}

	@Override
	@Transactional(readOnly = true)
	public R reporterList(Integer sceneId) {
		List<SysUserEntity> userEntities = sysUserService.selectByRoleId(2);
		if (userEntities == null || userEntities.size() <= 0) {
			// list返回空列表
			return R.ok().put("list", new ArrayList<>());
		}

		// 20190307 TROY 现场记者流数据过滤
		boolean isFilter = false;
		List<Long> hasUserList = null;
		if (null != sceneId) {
			EntityWrapper<LiveSceneLiveInfoEntity> ew = new EntityWrapper<>();
			ew.eq("info_type", SceneConstants.InfoTypeEnum.REPORTER.getType());
			ew.eq("scene_id", sceneId);
			List<LiveSceneLiveInfoEntity> reporterList = liveSceneLiveInfoService.selectList(ew);
			if (null != reporterList && reporterList.size() > 0) {
				isFilter = true;
				hasUserList = new ArrayList<>();
				for (LiveSceneLiveInfoEntity info : reporterList) {
					if (null != info.getUserId()) {
						hasUserList.add(Long.valueOf(info.getUserId()));
					}
				}
			}
		}

		List<ReporterVo> reporterVos = new ArrayList<>();
		for (SysUserEntity sysUserEntity : userEntities) {
			if (isFilter && hasUserList.contains(sysUserEntity.getUserId())) {
				continue;
			}
			ReporterVo reporterVo = new ReporterVo(sysUserEntity);
			reporterVos.add(reporterVo);
		}
		return R.ok().put("list", reporterVos);
	}

	@Override
	@Transactional(readOnly = true)
	public SceneForeignEntity getForeignScnenInfo(Integer id) {
		if (null == id) {
			return null;
		}
		// 基础信息
		LiveSceneEntity liveScene = this.baseMapper.selectById(id);
		// 20190228 TROY 信息为空、非成品、已删除 不返回
		if (null == liveScene || null == liveScene.getId() || !SceneConstants.SCENE_PROD.equals(liveScene.getSceneState())
				|| liveScene.getDeleteFlag().equals(Integer.valueOf(SceneConstants.IS_DELETE))) {
			return null;
		}
		SceneForeignEntity scnenForeign = new SceneForeignEntity(liveScene);
		// 20190321 TROY 调整资源URL
		if (StringUtils.isNotBlank(scnenForeign.getTitleImage())) {
			scnenForeign.setTitleImage(MaterialUtils.getMaterialUrl(scnenForeign.getTitleImage(), foreignProperties.getMediaurl()));
		}
		if (StringUtils.isNotBlank(scnenForeign.getVideoUrl())) {
			scnenForeign.setVideoUrl(MaterialUtils.getMaterialUrl(scnenForeign.getVideoUrl(), foreignProperties.getMediaurl()));
		}

		// 根据直播状态调整详情信息
		List<SceneStreamForeignEntity> streamList = null;
		if (SceneConstants.LIVE_STATE_DIRECT.equals(liveScene.getLiveState())) {
			// 正在直播中，获取流信息
			streamList = liveSceneLiveInfoService.selectLiveInfoForeign(id);
		} else if (SceneConstants.LIVE_STATE_REVIEW.equals(liveScene.getLiveState())) {
			// 回顾视频，获取回顾视频列表
			streamList = liveSceneRecordService.selectSceneRecordForeign(id);
		}
		if (streamList != null && streamList.size() > 0) {
			scnenForeign.setLiveList(streamList);
		}

		return scnenForeign;
	}

	@Override
	public R broadcast(Integer id, boolean start) {
		if (null == id) {
			throw new NullPointerException();
		}
		LiveSceneEntity entity = this.selectById(id);
		// 若现场不存在或现场未分配导播台
		if (null == entity) {
			return R.error("无法找到该现场");
		}
		// 只有成品现场才能开播
		if (!SceneConstants.SCENE_PROD.equals(entity.getSceneState())) {
			return R.error("非成品现场不可执行开播关播操作");
		}
		if(entity.getCasterId()!=null) {
			return R.error("该现场已申请导播台，请在导播台中执行开播关播操作");
		}
		if(entity.getLiveEnd().before(new Date()) && start){
			return R.error("该现场结束时间已超过当前时间，不可执行开播操作");
		}
		if (start) {
			if (!SceneConstants.LIVE_STATE_NOTICE.equals(entity.getLiveState()) && !SceneConstants.LIVE_STATE_REVIEW.equals(entity.getLiveState()))
				return R.error("非预告/回顾现场无法进行开播操作");

			//TODO 20200221 weiyan 在重新开播时，刷新记者流
			if(SceneConstants.LIVE_STATE_REVIEW.equals(entity.getLiveState()) || SceneConstants.LIVE_STATE_REVIEW==entity.getLiveState()){
//				resetSceneReportersStream(entity, entity.getLiveEnd());
				entity.setCasterId(null);
			}

			entity.setLiveState(SceneConstants.LIVE_STATE_DIRECT);
			entity.setActualLiveStart(new Date());
			// upEntity.setDirectStart(new Date());
		} else {
			if (!SceneConstants.LIVE_STATE_DIRECT.equals(entity.getLiveState())) {
				return R.error("只可关闭正在直播中现场");
			}
			entity.setLiveState(SceneConstants.LIVE_STATE_REVIEW);
			entity.setActualLiveEnd(new Date());
			// 删除自动开关播
			redisUtils.hdel(RedisContants.AUTO_LIVE_SCENE, id.toString());
		}

		this.updateById(entity);
		// 20190321 TROY 开播/停播刷新现场数据
		createSceneIndex(entity, null, null, entity.getLiveState(), null, null);
		redisUtils.delete(SceneConstants.SCENE_REDIS_PREFIX + id);
		return R.ok();
	}

	/**
	 * 播放现场
	 *
	 * @param sceneId
	 * @return
	 */
	@Override
	@Transactional(readOnly = true)
	public R streamPlay(Integer sceneId) {
		if (sceneId == null) {
			R.error("参数错误");
		}
		LiveSceneEntity sceneEntity = selectById(sceneId);
		if (sceneEntity == null || !SceneConstants.SceneType.isAllowLive(sceneEntity.getSceneType())) {
			return R.error("现场不存在，无法播放");
		}
		if(sceneEntity.getCasterId() != null) {

			LiveCasterEntity casterEntity = liveCasterService.selectById(sceneEntity.getCasterId());
			if(casterEntity == null)
				return R.error("未找到导播台，无法播放");

			RpcResponse<List<CasterStream>> listRpcResponse = liveClient.liveCaster().describeCasterStreamUrl(casterEntity.getCasterId());
			if(listRpcResponse.getResult() != ResponseResult.SUCCESS)
				return R.error("获取导播台播放地址错误，无法播放");
			List<CasterStream> casterStreams = listRpcResponse.getResponse();
			if(casterStreams == null || casterStreams.size() <= 0)
				return R.error("获取导播台播放地址错误，无法找到播放地址");
			R result = R.ok();
			for (CasterStream casterStream : casterStreams) {
				if (CasterStream.PVW_OUTPUTTYPE.equals(casterStream.getOutputType()))
					continue;
				List<StreamInfo> streamInfos = casterStream.getStreamInfos();
				if (streamInfos != null && streamInfos.size() > 0) {
					for (StreamInfo streamInfo : streamInfos) {
						if (SceneConstants.TRANSCODECONFIG_ORIGINAL.equals(streamInfo.getTranscodeConfig())) {
							String url = streamInfo.getOutputStreamUrl();
							String videoFormat = streamInfo.getVideoFormat();
							switch (videoFormat) {
								case "flv":
									result.put("playUrlFlv", url);
									break;
								case "rtmp":
									result.put("playUrlRmtp", url);
									break;
								case "m3u8":
									result.put("playUrlHls", url);
									break;
								default:
									break;
							}
						}
					}
				}
			}
			result.put("pushState", sceneEntity.getDirectState());
			return result;
		}
		// 20190307 TROY 现场流信息获取，增加现场ID过滤
		EntityWrapper ew = new EntityWrapper<LiveSceneLiveInfoEntity>();
		ew.eq("scene_id", sceneId);
		ew.eq("is_default", 1);
		LiveSceneLiveInfoEntity entity = liveSceneLiveInfoService.selectOne(ew);
		if (entity == null) {
			return R.error("默认流不存在，请先配置默认流");
		}
		LiveSceneLiveInfoExtEntity extEntity = liveSceneLiveInfoExtService.selectByInfoId(entity.getId());
		R result = R.ok();
		result.put("playUrlRmtp", extEntity.getPlayUrlRmtp());
		result.put("playUrlHls", extEntity.getPlayUrlHls());
		result.put("playUrlFlv", extEntity.getPlayUrlFlv());
		result.put("pushState", entity.getPushState());
		return result;

	}

	/**
	 * 现场Lucene索引重建
	 *
	 * @return
	 */
	@Override
	public R indexRebuild(Integer begin) {
		if (ShiroUtils.getUserId() != Constant.SUPER_ADMIN) {
			return R.error("没有权限，请联系管理员授权");
		}
		int pageNo = 0;
		int pageSize = 500;
		EntityWrapper wrapper = new EntityWrapper<>(new LiveSceneEntity());
		wrapper.eq("scene_state", SceneConstants.SCENE_PROD);
		wrapper.eq("delete_flag", SceneConstants.NOT_DELETE);
		if (begin != null && begin > 0) {
			wrapper.ge("id", begin);
		}

		Page<LiveSceneEntity> page = new Page<>(pageNo, pageSize);
		try {
			while (pageNo == 0 || page.hasNext()) {
				page = new Page<>(++pageNo, pageSize);
				page = this.selectPage(page, wrapper);
				if (page.getRecords().size() > 0) {
					for (int i=0; i<page.getRecords().size(); i++) {
						createSceneIndex(page.getRecords().get(i), null, null, null, null, i==0?true:false);
						log.info("现场 ["+ page.getRecords().get(i).getId() + "] 索引创建成功");
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return R.ok("更新索引成功");
	}

	/**
	 * 创建现场列表索引
	 *
	 * @param scene
	 *            现场数据
	 * @param createDate
	 *            创建时间
	 * @param sceneState
	 *            现场状态
	 * @param liveState
	 *            直播状态
	 * @param thumb
	 *            标题图
	 * @param create
	 *            是否创建索引
	 */
	@Override
	public void createSceneIndex(LiveSceneEntity scene, Date createDate, Integer sceneState, Integer liveState,
								  String thumb, Boolean create) {
		LiveSceneEntity tmpScene = new LiveSceneEntity();
		tmpScene.setId(scene.getId());
		tmpScene.setTitleImage(scene.getTitleImage());
		tmpScene.setTitle(scene.getTitle());
		tmpScene.setCreateDate(createDate != null ? createDate : scene.getCreateDate());
		tmpScene.setLiveStart(scene.getLiveStart());
		tmpScene.setSceneState(sceneState != null ? sceneState : scene.getSceneState());
		tmpScene.setLiveState(liveState !=null ? liveState : scene.getLiveState());
		tmpScene.setPriority(scene.getPriority());
		tmpScene.setIsTop(scene.getIsTop());
		tmpScene.setSceneType(scene.getSceneType());
		tmpScene.setTitleImage(StringUtils.isBlank(thumb) ? scene.getTitleImage() : thumb);

		// 获取栏目信息
		if(tmpScene.getChannelIdList()==null || tmpScene.getChannelIdList().size()<=0 || tmpScene.getChannelNameList()==null || tmpScene.getChannelNameList().size()<=0){
			EntityWrapper<LiveSceneChannelEntity> wrapper = new EntityWrapper<LiveSceneChannelEntity>();
			wrapper.eq("scene_id", scene.getId());
			List<LiveSceneChannelEntity> channelEntities = liveSceneChannelService.selectList(wrapper);
			if (null != channelEntities && channelEntities.size() > 0) {
				List<Integer> channelIdList = new ArrayList<>();
				List<String> channelNameList = new ArrayList<>();
				for (LiveSceneChannelEntity sceneChannelEntity : channelEntities) {
					if (null == sceneChannelEntity || null == sceneChannelEntity.getChannelId()) {
						continue;
					}
					LiveChannelEntity channelEntity = liveChannelService.selectById(sceneChannelEntity.getChannelId());
					if (channelEntity != null && channelEntity.getId() != null) {
						channelIdList.add(channelEntity.getId());
						channelNameList.add(channelEntity.getName());
					}
				}
				tmpScene.setChannelIdList(channelIdList);
				tmpScene.setChannelNameList(channelNameList);
			}
		}

		tmpScene.setChannelsName(scene.getChannelsName());
		try {
//			luceneService.createIndex(tmpScene, null==create?false:create);
			luceneService.createIndex(tmpScene, false);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 显示或隐藏流
	 *
	 * @param sceneId
	 * @param infoIds
	 * @param isShow
	 */
	@Override
	public void streamShow(Integer sceneId, Integer[] infoIds, Integer isShow) {
		if (sceneId == null || infoIds == null || infoIds.length <= 0 || isShow == null) {
			throw new NullPointerException();
		}
		List<LiveSceneLiveInfoEntity> list = new ArrayList<>();
		for (Integer infoId : infoIds) {
			LiveSceneLiveInfoEntity infoEntity = liveSceneLiveInfoService.selectById(infoId);
			if (infoEntity == null) {
				continue;
			}
			infoEntity.setIsShow(isShow);
			list.add(infoEntity);
		}
		redisUtils.delete(SceneConstants.SCENE_REDIS_PREFIX + sceneId);
		liveSceneLiveInfoService.updateBatchById(list);
	}

	/**
	 * 现场送审
	 *
	 * @param id
	 */
	public void submit(Integer id) {
		LiveSceneEntity entity = selectById(id);
		if (entity == null)
			throw new NullPointerException();

		entity.setSceneState(SceneConstants.SCENE_ONE);
		entity.setSubmitDate(new Date());
		updateById(entity);

		// 更新check记录
		createOrUpdateSceneCheck(entity, SceneConstants.SCENE_ONE, ShiroUtils.getUserEntity());
	}

	/**
	 * 首页 近期现场
	 *
	 * @param params
	 * @return
	 */
	@Override
	@Transactional(readOnly = true)
	public List<SceneEntityVo> recentScene(Map<String, Object> params) {
		Wrapper wrapper = new EntityWrapper<LiveSceneEntity>();
		Integer sceneType = (Integer) params.get("sceneType");
		Integer liveState = (Integer) params.get("liveState");
		if (sceneType != null)
			wrapper.eq("scene_type", sceneType);

		if (liveState != null)
			wrapper.eq("live_state", liveState);
		// 成品现场-按开始时间倒序
		wrapper.eq("delete_flag", 0).eq("scene_state", SceneConstants.SCENE_PROD).orderBy("is_top", false)
				.orderBy("priority", false).orderBy("live_start", false).orderBy("id", false);

		Page<LiveSceneEntity> page = this.selectPage(new Query<LiveSceneEntity>(params).getPage(), wrapper);
		if (page == null || page.getRecords() == null || page.getRecords().size() <= 0) {
			return null;
		}
		List<SceneEntityVo> list = new ArrayList<>();
		SceneEntityVo tmpVo = null;
		for (LiveSceneEntity entity : page.getRecords()) {
			tmpVo = new SceneEntityVo(entity);
			// 创建人姓名
			if (null != entity.getCreatorId()) {
				SysUserEntity user = sysUserService.selectBaseById(Long.valueOf(entity.getCreatorId()));
				if (null != user) {
					tmpVo.setCreatorName(user.getRealname());
				}
			}
			tmpVo.setTitleImageShow(MaterialUtils.getMaterialUrl(entity.getTitleImage(), foreignProperties.getMediaurl()));
			// 查询阅读量
			SceneCountVo sceneCountVo = liveSceneCountService.findRedisById(entity.getId());
			tmpVo.setViewsShow(sceneCountVo == null ? 0 : sceneCountVo.getViewsShow());

			// 查询记者
			// 20190309 TROY 过滤记者，增加类型判断
			List<LiveSceneLiveInfoEntity> infoEntities = liveSceneLiveInfoService
					.selectList(new EntityWrapper<LiveSceneLiveInfoEntity>().eq("scene_id", entity.getId())
							.eq("info_type", SceneConstants.InfoTypeEnum.REPORTER.getType()));
			if (infoEntities == null || infoEntities.size() <= 0){
			    // 20190318 Anine 过滤记者后仍返回该数据，不查询后续记者信息
                list.add(tmpVo);
				continue;
			}
			Set<ReporterVo> reporterVos = new HashSet<>();
			for (LiveSceneLiveInfoEntity infoEntity : infoEntities) {
				if (null == infoEntity.getUserId()) {
					continue;
				}
				SysUserEntity user = sysUserService.selectBaseById(Long.valueOf(infoEntity.getUserId()));
				if (user == null)
					continue;
				ReporterVo reporterVo = new ReporterVo(user);
				reporterVos.add(reporterVo);
			}
			tmpVo.setReporterVos(reporterVos);
			list.add(tmpVo);
		}
		return list;
	}

	@Override
	@Transactional(readOnly = true)
	public List<SceneEntityVo> recentLiveReport(Map<String, Object> params) {
		List<SceneEntityVo> list = recentScene(params);
		if (list != null && list.size() > 0) {
			for (SceneEntityVo entityVo : list) {
				List<LiveReportVo> voList = liveReportService.recentLiveSceneReport(entityVo.getId());
				entityVo.setReportList(voList);
			}
		}
		return list;
	}

	@Override
	public void topBatch(Integer[] ids, Long userId) {
		if (ids == null || ids.length == 0) {
			return;
		}
		LiveSceneEntity entity = new LiveSceneEntity();
		entity.setIsTop(TopEnum.TOP.getKey());
		entity.setUpdatorId(userId.intValue());
		entity.setUpdateDate(new Date());

		EntityWrapper wrapper = new EntityWrapper<>(new LiveSceneEntity());
		wrapper.in("id", ids);
		this.baseMapper.update(entity, wrapper);
	}

	@Override
	public void cancelTopBatch(Integer[] ids, Long userId) {
		if (ids == null || ids.length == 0) {
			return;
		}
		LiveSceneEntity entity = new LiveSceneEntity();
		entity.setIsTop(TopEnum.UNTOP.getKey());
		entity.setUpdatorId(userId.intValue());
		entity.setUpdateDate(new Date());

		EntityWrapper wrapper = new EntityWrapper<>(new LiveSceneEntity());
		wrapper.in("id", ids);
		this.baseMapper.update(entity, wrapper);
	}

	@Override
	public void priority(Integer[] ids, Integer[] prioritys, Long userId) {
		if (ids == null || ids.length == 0 || prioritys == null || prioritys.length == 0) {
			return;
		}
		for (int i = 0; i < ids.length; i++) {
			if (ids[i] != null && prioritys[i] != null) {
				LiveSceneEntity entity = new LiveSceneEntity();
				entity.setPriority(prioritys[i]);
				entity.setUpdatorId(userId.intValue());
				entity.setUpdateDate(new Date());
				entity.setId(ids[i]);
				this.baseMapper.updateById(entity);
			}
		}
	}

	/**
	 * 导播台分配
	 *
	 * @param id
	 *            现场ID
	 */
	@Override
	public R distribute(Integer id) {
		if (null == id) {
			return R.error("参数错误");
		}
		LiveSceneEntity liveSceneEntity = selectById(id);
		if (liveSceneEntity == null || liveSceneEntity.getSceneState() != SceneConstants.SCENE_PROD
				|| liveSceneEntity.getLiveState() != SceneConstants.LIVE_STATE_NOTICE
				|| liveSceneEntity.getSceneType() != SceneConstants.SceneType.MERGE.getKey())
			return R.error("未找到现场或现场为非预告成品混合现场");
		if (liveSceneEntity.getCasterId() != null)
			return R.error("已分配导播台，请不要重复分配");
		if(liveSceneEntity.getLiveState() != 0){
			return R.error("该现场已经开始直播，不能分配导播台");
		}
		RpcResponse<Caster> response = liveClient.liveCaster()
				.createCasterAndInitCasterConfig(liveSceneEntity.getTitle());
		if (response.getResult() == ResponseResult.ERROR)
			return R.error(response.getErrorCode() + " : " + response.getErrorMsg());

		Caster caster = response.getResponse();

		EntityWrapper<LiveCasterEntity> ew = new EntityWrapper<>();
		ew.eq("caster_id", caster.getCasterId());

		LiveCasterEntity tmpCaster = new LiveCasterEntity();
		tmpCaster.setCasterId(caster.getCasterId());
		tmpCaster.setCasterName(caster.getCasterName());
		tmpCaster.setDataState(caster.getStatus());
		tmpCaster.setNormType(caster.getNormType());
		try {
			DateFormat df = new UTCDateFormat();
			if (StringUtils.isNotBlank(caster.getStartTime()))
				tmpCaster.setStartTime(df.parse(caster.getStartTime()));
			tmpCaster.setCreateTime(df.parse(caster.getCreateTime()));
		} catch (ParseException e) {
			Date now = new Date();
			if (StringUtils.isNotBlank(caster.getStartTime()))
				tmpCaster.setStartTime(now);
			tmpCaster.setCreateTime(new Date());
		}

		tmpCaster.setSceneId(id);
		tmpCaster.setIsDelete(SceneConstants.NOT_DELETE);
		liveCasterService.insert(tmpCaster);

		liveSceneEntity.setCasterId(tmpCaster.getId());
		liveSceneEntity.setDirectState(SceneConstants.DIRECT_STATE_OFF);
		this.updateById(liveSceneEntity);
		return R.ok("导播台分配成功");
	}

	@Override
	@Transactional(readOnly = true)
	public R getLiveStreamsOnlineList(Integer id) {
		if (null == id) {
			return R.error("参数错误");
		}
		LiveSceneEntity liveSceneEntity = selectById(id);
		if (liveSceneEntity == null || liveSceneEntity.getSceneState() != SceneConstants.SCENE_PROD)
			return R.error("未找到现场或现场为非成品现场");

		List<LiveInfoVo> infoList = liveSceneLiveInfoService.selectOnlineLiveStreamList(id,
				SceneConstants.PushEnum.PUSHING.getState());

		for(LiveInfoVo vo : infoList){
			vo.setTitleImageShow(MaterialUtils.getMaterialUrl(vo.getTitleImage(), foreignProperties.getMediaurl()));
		}

		return R.ok().put("streams", infoList);
	}

	@Override
	public RpcResponse setCasterConfig(Integer sceneId, CasterConfig casterConfig) {
		RpcResponse errorResponse = new RpcResponse(RpcResponse.ERROR_STATUS, ResponseResult.ERROR);
		errorResponse.setErrorCode(ErrorCode.BussinessError.toString());
		if (null == sceneId) {
			errorResponse.setErrorMsg("参数错误sceneId为空");
			return errorResponse;
		}
		LiveSceneEntity liveSceneEntity = selectById(sceneId);
		if (liveSceneEntity == null || liveSceneEntity.getCasterId() == null
				|| liveSceneEntity.getSceneState() != SceneConstants.SCENE_PROD) {
			errorResponse.setErrorMsg("未找到现场或现场为非成品现场或未配置导播台");
			return errorResponse;
		}
		LiveCasterEntity casterEntity = liveCasterService.selectById(liveSceneEntity.getCasterId());
		if (casterEntity == null || SceneConstants.IS_DELETE.equals(casterEntity.getIsDelete()) || StringUtils.isBlank(casterEntity.getCasterId()) || !casterEntity.getCasterId().equals(casterConfig.getCasterId())) {
			errorResponse.setErrorMsg("未找到导播台或导播台已失效或导播台不匹配");
			return errorResponse;
		}
		RpcResponse response = liveClient.liveCaster().setCasterConfig(casterConfig);
		if(response.getResult() != ResponseResult.SUCCESS)
			return response;

		List<String> liveTemplateIds = casterConfig.getTranscodeConfig().getLiveTemplate();
		String liveTemplateIdsStr = "";
		for(int index=0; index<liveTemplateIds.size(); index++) {
			if(index > 0)
				liveTemplateIdsStr += ",";
			liveTemplateIdsStr += liveTemplateIds.get(index);
		}
		if(StringUtils.isNotBlank(liveTemplateIdsStr)) {
			casterEntity.setTemplateIds(liveTemplateIdsStr);
			liveCasterService.updateById(casterEntity);
		}
		return response;
	}

	@Override
	public RpcResponse startCaster(Integer id) {
		RpcResponse errorResponse = new RpcResponse(RpcResponse.ERROR_STATUS, ResponseResult.ERROR);
		errorResponse.setErrorCode(ErrorCode.BussinessError.toString());
		if (null == id) {
			errorResponse.setErrorMsg("参数错误");
			return errorResponse;
		}
		LiveSceneEntity liveSceneEntity = selectById(id);
		if (liveSceneEntity == null || liveSceneEntity.getCasterId() == null
				|| liveSceneEntity.getSceneState() != SceneConstants.SCENE_PROD
				|| liveSceneEntity.getLiveState() != SceneConstants.LIVE_STATE_NOTICE) {
			errorResponse.setErrorMsg("未找到现场或现场为非预告成品现场或未配置导播台");
			return errorResponse;
		}
		LiveCasterEntity liveCasterEntity = liveCasterService.selectById(liveSceneEntity.getCasterId());
		if (liveCasterEntity == null || SceneConstants.IS_DELETE.equals(liveCasterEntity.getIsDelete())) {
			errorResponse.setErrorMsg("未找到导播台或导播台已失效");
			return errorResponse;
		}
		if (SceneConstants.DIRECT_STATE_ON.equals(liveCasterEntity.getDataState())
				|| SceneConstants.DIRECT_STATE_ON.equals(liveSceneEntity.getDirectState())) {
			errorResponse.setErrorMsg("导播台正在导播中，请勿重复开启导播");
			return errorResponse;
		}
		String casterId = liveCasterEntity.getCasterId();
		// 开启导播台
		RpcResponse<StartCaster> response = liveClient.liveCaster().startCaster(casterId);
		if (response.getResult() != ResponseResult.SUCCESS)
			return response;
		if (StringUtils.isBlank(liveCasterEntity.getAppName())
				|| StringUtils.isBlank(liveCasterEntity.getStreamName())) {
			// 第一次开播从播流地址获取appName和streamName，并开启录制
			// 获取播流地址
			RpcResponse<List<CasterStream>> streamResponse = liveClient.liveCaster().describeCasterStreamUrl(casterId);
			if (streamResponse.getResult() != ResponseResult.SUCCESS) {// 停播
				liveClient.liveCaster().stopCaster(casterId);
				return streamResponse;
			}
			String appName = null;
			String streamName = null;
			List<CasterStream> casterStreams = streamResponse.getResponse();
			if (casterStreams != null && casterStreams.size() > 0) {
				for (CasterStream casterStream : casterStreams) {
					if (casterStream.getOutputType() == CasterStream.PVW_OUTPUTTYPE)
						continue;
					List<StreamInfo> streamInfos = casterStream.getStreamInfos();
					if (streamInfos != null && streamInfos.size() > 0)
						for (StreamInfo streamInfo : streamInfos) {
							if (SceneConstants.TRANSCODECONFIG_ORIGINAL.equals(streamInfo.getTranscodeConfig())) {
								String url = streamInfo.getOutputStreamUrl();
								url = url.substring(url.indexOf("//") + 2, url.indexOf("?"));
								String[] params = url.split("/");
								appName = params[1];
								streamName = params[2];
								if (streamName.indexOf(".") > 0)
									streamName = streamName.substring(0, streamName.indexOf("."));
								break;
							}
						}
					if (StringUtils.isNotBlank(appName) && StringUtils.isNotBlank(streamName))
						break;
				}
			}
			// 开启录制
//			RpcResponse recordResponse = liveClient.liveRecord().addLiveRecordVodMp4Config(appName, streamName);
//
//			if (recordResponse.getResult() != ResponseResult.SUCCESS) {
//				liveClient.liveCaster().stopCaster(casterId);
//				liveClient.liveRecord().deleteLiveRecordVodConfig(appName, streamName);
//				return streamResponse;
//			}
			liveCasterEntity.setAppName(appName);
			liveCasterEntity.setStreamName(streamName);
		}
		// 更新业务表
		liveCasterEntity.setDataState(SceneConstants.DIRECT_STATE_ON);
		Date now = new Date();
		liveCasterEntity.setStartTime(now);
		liveCasterService.updateById(liveCasterEntity);

		//20200311 weiyan 导播台开播后更新现场状态
//		LiveSceneEntity scene = new LiveSceneEntity(id);
		liveSceneEntity.setDirectState(SceneConstants.DIRECT_STATE_ON);
		liveSceneEntity.setDirectStart(now);
//		liveSceneEntity.setLiveState(SceneConstants.LIVE_STATE_DIRECT);
//		liveSceneEntity.setActualLiveStart(new Date());
		this.updateById(liveSceneEntity);
//		createSceneIndex(liveSceneEntity, null, null, liveSceneEntity.getLiveState(), null, null);
//		redisUtils.delete(SceneConstants.SCENE_REDIS_PREFIX + id);

		return response;
	}

	@Override
	public R stopCaster(Integer id, Boolean close) {
		if (null == id) {
			return R.error("参数错误");
		}
		LiveSceneEntity liveSceneEntity = selectById(id);
		if (liveSceneEntity == null || liveSceneEntity.getCasterId() == null
				|| liveSceneEntity.getSceneState() != SceneConstants.SCENE_PROD
				|| liveSceneEntity.getDirectState() != SceneConstants.LIVE_STATE_DIRECT) {
			return R.error("未找到现场或现场为非成品现场或现场为非导播状态");
		}

		LiveCasterEntity liveCasterEntity = liveCasterService.selectById(liveSceneEntity.getCasterId());
		if (liveCasterEntity == null || liveCasterEntity.getIsDelete() == SceneConstants.IS_DELETE) {
			return R.error("未找到导播台或导播台已失效");
		}
		RpcResponse response = liveClient.liveCaster().stopCaster(liveCasterEntity.getCasterId());
		if (response.getResult() != ResponseResult.SUCCESS) {
			return R.error(response.getErrorCode() + " : " + response.getErrorMsg());
		}
		Date now = new Date();
//		LiveSceneEntity scene = new LiveSceneEntity(id);
		liveSceneEntity.setDirectState(SceneConstants.DIRECT_STATE_OFF);
		liveSceneEntity.setDirectEnd(now);
		LiveCasterEntity caster = new LiveCasterEntity(liveCasterEntity.getId());
		caster.setDataState(0);// 导播台空闲
//		if (close != null && close) {

			liveSceneEntity.setLiveState(SceneConstants.LIVE_STATE_REVIEW);
			liveSceneEntity.setActualLiveEnd(now);
			updateById(liveSceneEntity);
			caster.setIsDelete(SceneConstants.IS_DELETE);

			liveClient.liveCaster().deleteCaster(liveCasterEntity.getCasterId());

			redisUtils.delete(SceneConstants.CASTER_LIVETEMPLATEIDS + id);

			redisUtils.delete(SceneConstants.SCENE_REDIS_PREFIX + id);

			// 20190401 TROY lucene数据刷新
			createSceneIndex(liveSceneEntity, null, null, liveSceneEntity.getLiveState(), null, null);
//		}
		liveCasterService.updateById(caster);
		this.updateById(liveSceneEntity);
		return R.ok("操作成功");
	}

	@Override
	public R copyCasterSceneConfig(Integer id, String casterId, String fromSceneId, String toSceneId) {

		if (null == id || StringUtils.isBlank(casterId) || StringUtils.isBlank(fromSceneId)
				|| StringUtils.isBlank(toSceneId)) {
			return R.error("参数错误");
		}
		LiveSceneEntity liveSceneEntity = selectById(id);
		if (liveSceneEntity == null || liveSceneEntity.getSceneState() != SceneConstants.SCENE_PROD
				|| liveSceneEntity.getDirectState() != SceneConstants.DIRECT_STATE_ON) {
			return R.error("未找到现场或现场为非成品现场或未导播");
		}
		LiveCasterEntity liveCasterEntity = liveCasterService.selectById(liveSceneEntity.getCasterId());
		if (liveCasterEntity == null || liveCasterEntity.getIsDelete() == SceneConstants.IS_DELETE
				|| !liveCasterEntity.getCasterId().equals(casterId)) {
			return R.error("未找到导播台或导播台已失效或导播台与现场不匹配");
		}

		RpcResponse response = liveClient.liveCaster().copyCasterSceneConfig(casterId, fromSceneId, toSceneId);
		if (response.getResult() != ResponseResult.SUCCESS) {
			return R.error(response.getErrorCode() + " : " + response.getErrorMsg());
		}
		if (liveSceneEntity.getActualLiveStart() == null) {
			// 开启录制
			String appName = liveCasterEntity.getAppName();
			String streamName = liveCasterEntity.getStreamName();

//			String key = "copyCasterSceneConfig_" + requestId + "_" + casterId;
//			String value = appName + "||" + streamName;
//			redisUtils.set(key, value);
			RpcResponse recordResponse = liveClient.liveRecord().addLiveRecordVodMp4Config(appName, streamName);

			if (recordResponse.getResult() != ResponseResult.SUCCESS) {
				liveClient.liveRecord().deleteLiveRecordVodConfig(appName, streamName);
				return R.error(recordResponse.getErrorCode() + " : " + recordResponse.getErrorMsg());
			}

			new Thread() {
				public void run() {
					try {
						Thread.sleep(6000);
						for(int i=0; i<3; i++) {
							// 开始录制
							RpcResponse startRecordResponse = liveClient.liveRecord().startRealTimeRecordCommand(appName, streamName);
							if (startRecordResponse.getResult() == ResponseResult.SUCCESS) return;
							liveClient.liveRecord().stopRealTimeRecordCommand(appName, streamName);
							log.error("startRealTimeRecordCommand error : " + recordResponse.getErrorCode() + " : " + recordResponse.getErrorMsg());
						}
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}.start();
			// 开始录制
//			RpcResponse startRecordResponse = liveClient.liveRecord().startRealTimeRecordCommand(appName, streamName);
//			if (startRecordResponse.getResult() != ResponseResult.SUCCESS) {
//				liveClient.liveRecord().deleteLiveRecordVodConfig(appName, streamName);
//				return R.error(recordResponse.getErrorCode() + " : " + recordResponse.getErrorMsg());
//			}

			Date now = new Date();
			LiveSceneEntity scene = new LiveSceneEntity(id);
			scene.setActualLiveStart(now);
			scene.setLiveState(SceneConstants.LIVE_STATE_DIRECT);
			scene.setChannelsName(liveSceneEntity.getChannelsName());
			scene.setChannelsId(liveSceneEntity.getChannelsId());
			updateById(scene);

			redisUtils.delete(SceneConstants.SCENE_REDIS_PREFIX + id);

			// 20190401 TROY lucene数据刷新
			createSceneIndex(liveSceneEntity, null, null, scene.getLiveState(), null, null);
		}
		return R.ok();
	}

	@Override
	@Transactional(readOnly = true)
	public Page<SceneCommentCountVo> querySceneCommentPage(Integer page, Integer limit) {
		Page<SceneCommentCountVo> sceneCommentCountVoPage = new Page<>(page, limit);
		List<SceneCommentCountVo> list = this.baseMapper.querySceneCommentCountByParams(sceneCommentCountVoPage);
		if(list!=null && list.size()>0){
			for(SceneCommentCountVo bean : list){
				bean.setTitleImageShow(MaterialUtils.getMaterialUrl(bean.getTitleImage(), foreignProperties.getMediaurl()));
			}
		}
		return sceneCommentCountVoPage.setRecords(list);
	}

	@Override
	public RpcResponse startCasterScene(Integer id) {
		return null;
	}

	@Override
	public RpcResponse stopCasterScene(Integer id) {
		return null;
	}

	@Override
	@Transactional(readOnly = true)
	public LiveSceneEntity selectBySign(String appName) {
		EntityWrapper<LiveSceneEntity> wrapper = new EntityWrapper<>();
		wrapper.eq("scene_sign", appName);
		List<LiveSceneEntity> liveSceneEntities = this.baseMapper.selectList(wrapper);
		if(liveSceneEntities != null && liveSceneEntities.size() == 1)
			return liveSceneEntities.get(0);
		return null;
	}

	@Override
	@Transactional(readOnly = true)
	public R getCasterStreamsUrl(Integer id) {

        if (null == id) {
            return R.error("参数错误");
        }
        String key = SceneConstants.CASTER_LIVETEMPLATEIDS + id;
        List<CasterStreamVo> result = new ArrayList<>();
        String liveTemplateIds = redisUtils.get(key);
        if(StringUtils.isBlank(liveTemplateIds)) {
            LiveSceneEntity liveSceneEntity = selectById(id);
            if (liveSceneEntity == null || liveSceneEntity.getCasterId() == null) {
                return R.error("未找到现场或未分配导播台");
            }
            LiveCasterEntity caster = liveCasterService.selectById(liveSceneEntity.getCasterId());
            if(caster == null)
                return R.error("未找到导播台");
            if(StringUtils.isBlank(caster.getAppName()) || StringUtils.isBlank(caster.getStreamName()))
                return R.ok().put("streams", result).put("msg", "未开播的导播台无法分配播流地址");
            liveTemplateIds = caster.getAppName() + "#" + caster.getStreamName() + "#" + (StringUtils.isBlank(caster.getTemplateIds())? "":caster.getTemplateIds());
            redisUtils.set(key, liveTemplateIds, -1);
        }
        String[] params = liveTemplateIds.split("#");
        String appName = params[0], streamName = params[1], templateIds = "";
        if(params.length == 3) templateIds = params[2];
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.DAY_OF_YEAR, 1);
		Date endDate = calendar.getTime();
        CasterStreamVo original = new CasterStreamVo();
        original.setTemplate(SceneConstants.TRANSCODECONFIG_ORIGINAL);
        String[] streamsOriginal = liveClient.liveStream().generateLiveUrl(appName, streamName, endDate);
        String playUrlHls = streamsOriginal[2];
        original.setPlayUrlRmtp(streamsOriginal[0]);
        original.setPlayUrlFlv(streamsOriginal[1]);
        original.setPlayUrlHls(playUrlHls);
        result.add(original);
		if(StringUtils.isNotBlank(templateIds)) {
            String[] templates = templateIds.split(",");
            if(templateIds != null && templates.length > 0)
				for(String template : templates) {
					String[] streamsTemplate = liveClient.liveStream().generateLiveUrl(appName, streamName + "_" + template, endDate);
					CasterStreamVo casterStreamVo = new CasterStreamVo();
					casterStreamVo.setTemplate(template);
					casterStreamVo.setPlayUrlRmtp(streamsTemplate[0]);
					casterStreamVo.setPlayUrlFlv(streamsTemplate[1]);
					casterStreamVo.setPlayUrlHls(playUrlHls);
					result.add(casterStreamVo);
				}
		}
		return R.ok().put("streams", result);
	}

	@Override
	public void recycle(Integer[] ids){
//		LiveSceneEntity entity = new LiveSceneEntity();
//		entity.setDeleteFlag(SceneConstants.NOT_DELETE);
//		entity.setUpdateDate(new Date());
//		EntityWrapper<LiveSceneEntity> wrapper = new EntityWrapper<LiveSceneEntity>(new LiveSceneEntity());
//		wrapper.in("id", ids);
//		this.baseMapper.update(entity, wrapper);
		for(Integer id : ids) {
			LiveSceneEntity scene = this.baseMapper.selectById(id);

			if (null != scene){
                scene.setDeleteFlag(SceneConstants.NOT_DELETE);
                scene.setUpdateDate(new Date());
                this.updateById(scene);

				List<LiveSceneLiveInfoEntity> liveInfos = liveSceneLiveInfoService.selectLiveInfoByInfoType(scene.getId(),SceneConstants.InfoTypeEnum.THIRD.getType());
				if(liveInfos!=null && liveInfos.size()>0){
					for(LiveSceneLiveInfoEntity liveInfo : liveInfos){
						Date now = new Date();
						if(liveInfo.getPullEnd().getTime()>now.getTime()){
							try {
								LiveSceneLiveInfoExtEntity ext = liveSceneLiveInfoExtService.selectByInfoId(liveInfo.getId());
								SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
								TimeZone utcZone = TimeZone.getTimeZone("UTC");
								sf.setTimeZone(utcZone);
								liveClient.livePullStream().addLivePullStreamInfoConfig(liveInfo.getAppName(), liveInfo.getStreamName(), ext.getPullUrl(), sf.format(liveInfo.getPullStart()), sf.format(liveInfo.getPullEnd()));
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
					}
				}

            }

			if(scene != null && scene.getId()!=null && (scene.getDeleteFlag()==0 || scene.getDeleteFlag().equals(0)) && (scene.getSceneState()==SceneConstants.SCENE_PROD || scene.getSceneState().equals(SceneConstants.SCENE_PROD))) {
				// 增加列表索引
				createSceneIndex(scene, null, null, null, null, null);
			}
		}

	}

	@Override
	public void cycleDelete(Integer[] ids){
		this.baseMapper.deleteBatchIds(Arrays.asList(ids));
	}

	private void saveSceneChannels(LiveSceneEntity liveScene, List<Integer> channelsId) {
		if (channelsId == null || channelsId.size() <= 0) {
			return;
		}
		for (Integer channelId : channelsId) {
			LiveChannelEntity channel = liveChannelService.selectById(channelId);
			if (channel == null || channel.getId()==null) {
				continue;
			}
			LiveSceneChannelEntity liveSceneChannelEntity = new LiveSceneChannelEntity();
			liveSceneChannelEntity.setSceneId(liveScene.getId());
			liveSceneChannelEntity.setChannelId(channel.getId());
			// 20200331_Mxy 设置拖动排序标识
//			liveSceneChannelEntity.setDragSort(null == liveScene.getAuditDate() ? new Date().getTime() / 1000 : liveScene.getAuditDate().getTime() / 1000);
			liveSceneChannelEntity.setDragSort(new Date().getTime() / 1000);
			liveSceneChannelService.save(liveSceneChannelEntity);
		}
	}

	@Override
	public R dragSort(Integer cid, Integer[] sceneIds, long[] dragSorts) {

		List<LiveSceneChannelEntity> entityList = liveSceneChannelService.selectList(
				new EntityWrapper<LiveSceneChannelEntity>().eq("channel_id", cid).in("scene_id", sceneIds)
		);

		if (null == entityList || entityList.size() == 0)
		    return R.error("现场与栏目关系信息获取失败");

		// 维护栏目现场关系表
		entityList.forEach(entity -> {
			for (int i = 0; i < sceneIds.length; i++){
				if (entity.getSceneId().equals(sceneIds[i])){
					entity.setDragSort(dragSorts[i]);
					break;
				}
			}
		});

		liveSceneChannelService.updateBatchById(entityList);

		// 刷新Lucene
		Arrays.stream(sceneIds).forEach(sceneId -> {
			LiveSceneEntity sceneEntity = this.selectById(sceneId);
			createSceneIndex(sceneEntity, sceneEntity.getCreateDate(), sceneEntity.getSceneState(), sceneEntity.getLiveState(), StringUtils.isBlank(sceneEntity.getTitleImage()) ? null : sceneEntity.getTitleImage(), null);
		});

		return R.ok();
	}

	@Override
	public PageUtils sortScenePage(Integer cid, Integer pageSize, Integer pageNo, String title, Integer sceneType, Integer liveState, Integer deleteFlag, Long tenantId) {

		Map<String, Object> params = new HashMap<>();
		Page<SceneSortEntityVo> page = new Page<>(pageNo, pageSize);

		// 栏目id
		params.put("cid", cid);
		// 标题
		if (StringUtils.isNotBlank(title)) {
			params.put("title", title);
		}
		// 现场类型
		if (null != sceneType) {
			params.put("sceneType", sceneType);
		}
		// 直播状态
		if (null != liveState){
			params.put("liveState", liveState);
		}
		// 审核状态
		params.put("sceneState", SceneConstants.SCENE_PROD);
		// 机构名称
		if (null != tenantId){
			params.put("tenantId", tenantId);
		}

//		if (SceneConstants.SCENE_ONE.equals(sceneState)) {
//			params.put("sceneState", SceneConstants.SCENE_ONE);
//		} else if (SceneConstants.SCENE_PROD.equals(sceneState)) {
//		} else if (SceneConstants.SCENE_DRAFT.equals(sceneState)) {
//			// 除超级管理员，草稿只能查看自己创建的现场
//			if (ShiroUtils.getUserId() != Constant.SUPER_ADMIN) {
//				params.put("creatorId", ShiroUtils.getUserId());
//			}
//		} else {
//			params.put("sceneState", SceneConstants.SCENE_PROD);
//		}
		// 删除状态
		if (null != deleteFlag){
			params.put("deleteFlag", deleteFlag);
		}else {
			params.put("deleteFlag", 0);
		}

		List<SceneSortEntityVo> sceneEntityList = this.baseMapper.querySort(page, params);

		if (null == sceneEntityList || sceneEntityList.size() == 0)
			return null;

		// 查询阅读量
		sceneEntityList.stream().
				filter(entity -> SceneConstants.SCENE_PROD.equals(entity.getSceneState())).
				forEach(entity -> {
					// 查询阅读量
					SceneCountVo sceneCountVo = liveSceneCountService.findRedisById(entity.getId());
					entity.setViewsShow(sceneCountVo == null ? 0 : sceneCountVo.getViewsShow());
					// 设置导播台ID
					entity.setCaster(entity.getCasterId());
				});

		// 设置机构名称
		sceneEntityList.stream().
				filter(entity -> null != entity.getTenantId()).
				forEach(entity -> {
					if (redisUtils.hexists(Constant.REDIS_SYS_TENANT_ENTITY, entity.getTenantId().toString())){
						entity.setTenantName(redisUtils.hget(Constant.REDIS_SYS_TENANT_ENTITY, entity.getTenantId().toString(), SysTenantEntity.class).getTenantName());
					}else {
						SysTenantEntity tenantEntity = tenantService.selectById(entity.getTenantId());
						if (tenantEntity != null) {
							redisUtils.hset(Constant.REDIS_SYS_TENANT_ENTITY, tenantEntity.getId().toString(), tenantEntity);
							entity.setTenantName(tenantEntity.getTenantName());
						}
					}
				});

		page.setRecords(sceneEntityList);

		return new PageUtils(page);
	}

	@Override
	public void lockSort(boolean flag, Integer cid) {

		if (flag){
			redisUtils.delete(cid.toString());
			redisUtils.set(cid.toString(), "lock", 30);
		}else {
			redisUtils.delete(cid.toString());
		}
	}

	@Override
	public boolean isLockSort(Integer cid){

		if (redisUtils.hasKey(cid.toString()))
			return false;

		redisUtils.set(cid.toString(), "lock", 30);
		return true;
	}

	private void updateSceneChannels(LiveSceneEntity liveScene, List<Integer> channelsId) {
		List<LiveSceneChannelEntity> entityList = liveSceneChannelService.selectList(new EntityWrapper<LiveSceneChannelEntity>().eq("scene_id", liveScene.getId()));
		List<Integer> oldChannelIdList = new ArrayList<>();
		List<Integer> listForAdd = new ArrayList<>();
		if (entityList != null && entityList.size() > 0) {
			// 删除新记者列表中不存在的原记者列表中存在的
			for (LiveSceneChannelEntity infoEntity : entityList) {
				Integer channelId = infoEntity.getChannelId();
				oldChannelIdList.add(channelId);
				if (channelId != null && (channelsId == null || !channelsId.contains(channelId))) {
					liveSceneChannelService.delete(new EntityWrapper<LiveSceneChannelEntity>()
							.eq("scene_id", liveScene.getId()).eq("channel_id", channelId));
				}
			}
		}
		// 增加原记者列表中不存在的，新记者列表中存在的
		if (channelsId != null && channelsId.size() > 0) {
			for (Integer channelId : channelsId) {
				if (oldChannelIdList == null || oldChannelIdList.size() <= 0 || !oldChannelIdList.contains(channelId)) {
					listForAdd.add(channelId);
				}
			}
		}
		saveSceneChannels(liveScene, listForAdd);
	}
	/**
	 * 刷新记者流
	 * @param sceneEntity
	 * @param liveEnd
	 * weiyan
	 */
	private void resetSceneReportersStream(LiveSceneEntity sceneEntity, Date liveEnd) {
		//20200225 用于判断录制配置是否有效，如果有效，则不刷新记者流、不添加录制配置
		RpcResponse<List<LiveRecordVodConfig>> liveRecordVodResponse = liveClient.liveRecord().describeLiveRecordVodConfig(sceneEntity.getSceneSign());
		if(ResponseResult.SUCCESS == liveRecordVodResponse.getResult()){
			List<LiveRecordVodConfig> configs = liveRecordVodResponse.getResponse();
			if(configs != null && configs.size() > 0)
				return;
		}
		//20200206 如果现场的结束时间小于当前时间，流的有效时间改为当前时间+1天
		Date date = new Date();
		if(liveEnd.before(date)){
			Calendar c = Calendar.getInstance();
			c.add(Calendar.DAY_OF_MONTH, 1);
			liveEnd = c.getTime();
		}

		//刷新记者流
		List<LiveSceneLiveInfoEntity> entityList = liveSceneLiveInfoService.selectList(new EntityWrapper<LiveSceneLiveInfoEntity>().eq("scene_id", sceneEntity.getId()));
		if (entityList != null && entityList.size() > 0) {
			for (LiveSceneLiveInfoEntity infoEntity : entityList) {

//				if("默认现场源"==infoEntity.getInfoName() || "默认现场源".equals(infoEntity.getInfoName())){
//					infoEntity.setStreamName(DigestUtils.md5Hex(sceneEntity.getSceneSign()));
//				}else{
//					infoEntity.setStreamName(DigestUtils.md5Hex(infoEntity.getUserId().toString()));
//				}
				
				String streamName = UUID.randomUUID().toString().replaceAll("-", "");
				if(infoEntity.getUserId()!=null){
					streamName = DigestUtils.md5Hex(infoEntity.getUserId().toString());
				}
				infoEntity.setStreamName(streamName);
					
				infoEntity.setPushState(SceneConstants.PushEnum.NOT_START.getState());
				liveSceneLiveInfoService.updateById(infoEntity);
				// 成品状态现场生成流地址
				// 20190307 TROY 增加现场类型允许直播判断
				if (SceneConstants.SceneType.isAllowLive(sceneEntity.getSceneType())
						&& SceneConstants.SCENE_PROD.equals(sceneEntity.getSceneState())) {
					saveOrUpdateInfoExt(infoEntity.getId(), infoEntity.getAppName(), infoEntity.getStreamName(), liveEnd, sceneEntity.getSceneType(), null,infoEntity.getPullUrl());
				}
			}
		}
		// 添加录制配置
		RpcResponse response = null;
		// TODO 根据现场类型状态进行控制
		if (SceneConstants.SceneType.AUDIO.getKey().equals(sceneEntity.getSceneType()) || SceneConstants.SceneType.MERGE.getKey().equals(sceneEntity.getSceneType()) || SceneConstants.SceneType.VIDEO.getKey().equals(sceneEntity.getSceneType())) {
			if (SceneConstants.SceneType.AUDIO.getKey().equals(sceneEntity.getSceneType()))
				response = liveClient.liveRecord().addLiveRecordVodMp3Config(sceneEntity.getSceneSign(), "*");
			else
				response = liveClient.liveRecord().addLiveRecordVodMp4Config(sceneEntity.getSceneSign(), "*");
			if (response == null || response.getResult() != ResponseResult.SUCCESS) {
				log.error("startLive error , status : " + response.getStatus() + ", msg : " + response.getData());
				throw new RuntimeException("添加录制配置错误");
			}
		}
	}

	/**
	 * 20200316_Mxy 图片压缩
	 *
	 * @param sourceUrl 图片地址
	 * */
	private String compressImage(String sourceUrl){
		// 返回拼接压缩后地址
		return sourceUrl + liveProperties.getCompressImage().getGeometricFormat();
	}
	
	/**
	 * 成品现场【全部】
	 */
	@Override
	@Transactional(readOnly = true)
	public Page<SceneEntityVo> pageProd(String title, Integer sceneType, String ltype,Integer liveState, Integer pageNo, Integer pageSize, Long tenantId) {
		// 检索记录
		Page<SceneEntityVo> page = new Page<SceneEntityVo>(pageNo, pageSize);
		Map<String, Object> params = new HashMap<String, Object>();
		// 标题
		if (StringUtils.isNotBlank(title)) {
			params.put("title", title);
		}
		// 现场类型
		if (null != sceneType) {
			params.put("sceneType", sceneType);
		}
		
		params.put("deleteFlag", 0);
		// 现场状态
		params.put("ltype", SceneConstants.SCENE_PROD);

		if (liveState != null) {
			params.put("liveState", liveState);
		}

		if (null != tenantId){
			params.put("tenantId", tenantId);
		}
		params.put("isProd", 1);
		List<SceneEntityVo> pageList = this.baseMapper.queryPageMap(page, params);
		List<SceneEntityVo> list = new ArrayList<SceneEntityVo>();
		if (pageList != null && pageList.size() > 0) {
			SceneEntityVo tmpVo;
			for (int i = 0; i < pageList.size(); i++) {
				SceneEntityVo bean = pageList.get(i);
				if (bean == null) {
					continue;
				}
				if (null != bean.getTenantId()){
					if (redisUtils.hexists(Constant.REDIS_SYS_TENANT_ENTITY, bean.getTenantId().toString())){
						bean.setTenantName(redisUtils.hget(Constant.REDIS_SYS_TENANT_ENTITY, bean.getTenantId().toString(), SysTenantEntity.class).getTenantName());
					}else {
						SysTenantEntity tenantEntity = tenantService.selectById(bean.getTenantId());
						if (tenantEntity != null) {
							redisUtils.hset(Constant.REDIS_SYS_TENANT_ENTITY, tenantEntity.getId().toString(), tenantEntity);
							bean.setTenantName(tenantEntity.getTenantName());
						}
					}
				}
				// 创建人姓名
				if (null != bean.getCreatorId()) {
					SysUserEntity user = sysUserService.selectBaseById(Long.valueOf(bean.getCreatorId()));
					if (null != user) {
						bean.setCreatorName(user.getRealname());
					}
				}
				bean.setTitleImageShow(MaterialUtils.getMaterialUrl(bean.getTitleImage(), foreignProperties.getMediaurl()));
				// 查询阅读量
				// 20190305 TROY 优化：成品后获取对外点击量
				if (SceneConstants.SCENE_PROD.equals(bean.getSceneState())) {
					// 查询阅读量
					SceneCountVo sceneCountVo = liveSceneCountService.findRedisById(bean.getId());
					bean.setViewsShow(sceneCountVo == null ? 0 : sceneCountVo.getViewsShow());
				}
				// END
				list.add(bean);
			}
		}
		page.setRecords(list);
		return page;
	}

	@Override
	public List<LiveSceneEntity> freshLiveStateByAutoLive() {

		LocalDateTime localDateTime = LocalDateTime.now();
		LocalDateTime localDateTimePlusOne = localDateTime.plusMinutes(1);

		//改为数据库查询
		List<LiveSceneEntity> liveSceneEntityList = this.baseMapper.selectList(new EntityWrapper<LiveSceneEntity>()
				.eq("is_auto_live", SceneConstants.IsAutoLive.OPEN)
				.eq("delete_flag",SceneConstants.IsDelete.NOTISDELETE).eq("scene_state", SceneConstants.SCENE_PROD)
				.eq("live_state", SceneConstants.LIVE_STATE_NOTICE).le("live_start", localDateTimePlusOne)
				.or().eq("is_auto_live", SceneConstants.IsAutoLive.OPEN)
				.eq("delete_flag",SceneConstants.IsDelete.NOTISDELETE).eq("scene_state", SceneConstants.SCENE_PROD)
				.eq("live_state", SceneConstants.LIVE_STATE_DIRECT).le("live_end", localDateTime));

		List<LiveSceneEntity> result = new ArrayList<>();
		if (CollectionUtil.isNotEmpty(liveSceneEntityList)) {
			//log.info("自动开关播的现场：" + JSONObject.toJSONString(liveSceneEntityList));
			liveSceneEntityList.forEach(entity -> {
				if (entity == null || entity.getLiveStart() == null || entity.getLiveEnd() == null) return;
				log.info("自动开关播的现场：" + JSONObject.toJSONString(entity.getId()));
				if (entity.getLiveStart().after(entity.getLiveEnd())) return;
				long now = System.currentTimeMillis() / 1000;
				long liveStart = entity.getLiveStart().getTime() / 1000;
				long liveEnd = entity.getLiveEnd().getTime() / 1000;
				if (now >= liveEnd) {
					log.info("自动关播现场：" + entity.getId());
					entity.setLiveState(SceneConstants.LIVE_STATE_REVIEW);
					entity.setActualLiveEnd(new Date());
					this.updateById(entity);
					//yang 20210803  关闭直播时关闭第三方流
					List<LiveSceneLiveInfoEntity> list = liveSceneLiveInfoService.selectList(new EntityWrapper<LiveSceneLiveInfoEntity>().eq("scene_id", entity.getId()));
					if (CollectionUtil.isNotEmpty(list))
						for (LiveSceneLiveInfoEntity liveSceneLiveInfoEntity : list)
							streamPullEndEntity(liveSceneLiveInfoEntity);
					result.add(entity);
				}else if (SceneConstants.LIVE_STATE_NOTICE.equals(entity.getLiveState()) && now + 20 >= liveStart) {
					log.info("自动开播现场：" + entity.getId());
					entity.setLiveState(SceneConstants.LIVE_STATE_DIRECT);
					entity.setActualLiveStart(new Date());
					this.updateById(entity);
					//yang 20210803  开始直播时拉取第三方流
					List<LiveSceneLiveInfoEntity> list = liveSceneLiveInfoService.selectList(new EntityWrapper<LiveSceneLiveInfoEntity>().eq("scene_id", entity.getId()));
					if (CollectionUtil.isNotEmpty(list))
						for (LiveSceneLiveInfoEntity liveSceneLiveInfoEntity : list)
							streamPullStartEntity(liveSceneLiveInfoEntity);
					result.add(entity);
				}
			});
		}
		return result;
	}

	/**
	 * 现场重置为预告状态
	 * <p>
	 * 1.更新数据库，设置直播状态为预告
	 * 2.刷新记者流
	 * 3.删除缓存，在下一次查询时重新获取、更新索引
	 *
	 * @param id 直播id
	 * @return 是否重置成功
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public R resetLiveState(LiveSceneEntity entity) {

		entity.setLiveState(SceneConstants.LIVE_STATE_NOTICE);
		this.updateById(entity);
		// yang  如果当前为直播中 则关闭第三方拉流
		if (!SceneConstants.LIVE_STATE_DIRECT.equals(entity.getLiveState())) {
			List<LiveSceneLiveInfoEntity> list = liveSceneLiveInfoService.selectList(new EntityWrapper<LiveSceneLiveInfoEntity>().eq("scene_id", entity.getId()));
			if (CollectionUtil.isNotEmpty(list)) {
				for (LiveSceneLiveInfoEntity liveSceneLiveInfoEntity : list) {
					streamPullEndEntity(liveSceneLiveInfoEntity);
				}
			}
		}

		resetSceneReportersStream(entity, entity.getLiveEnd());
		redisUtils.delete(SceneConstants.SCENE_REDIS_PREFIX + entity.getId());
		createSceneIndex(entity, null, null, entity.getLiveState(), null, null);
		return R.ok();
	}
}