diff --git a/src/main/java/com/ycwl/basic/repository/TemplateRepository.java b/src/main/java/com/ycwl/basic/repository/TemplateRepository.java
index 2e29992..5663396 100644
--- a/src/main/java/com/ycwl/basic/repository/TemplateRepository.java
+++ b/src/main/java/com/ycwl/basic/repository/TemplateRepository.java
@@ -33,7 +33,6 @@ public class TemplateRepository {
         return template.getChildren().stream()
                 .filter(item -> item.getIsPlaceholder() == 1)
                 .map(TemplateRespVO::getSourceUrl)
-                .distinct()
                 .collect(Collectors.toList());
     }
 
diff --git a/src/main/java/com/ycwl/basic/service/mobile/impl/GoodsServiceImpl.java b/src/main/java/com/ycwl/basic/service/mobile/impl/GoodsServiceImpl.java
index 9002e14..0f3a4fc 100644
--- a/src/main/java/com/ycwl/basic/service/mobile/impl/GoodsServiceImpl.java
+++ b/src/main/java/com/ycwl/basic/service/mobile/impl/GoodsServiceImpl.java
@@ -55,6 +55,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
 /**
@@ -268,18 +269,22 @@ public class GoodsServiceImpl implements GoodsService {
         }
         TaskEntity task = videoTaskRepository.getTaskById(videoRespVO.getTaskId());
         JSONObject paramJson = JSON.parseObject(task.getTaskParams());
-        long deviceCount;
+        AtomicInteger deviceCount = new AtomicInteger();
         goodsDetailVO.setShotTime(taskTaskService.getTaskShotDate(task.getId()));
         if (paramJson == null) {
-            deviceCount = 1;
+            deviceCount.set(1);
         } else {
             List<String> templatePlaceholder = templateRepository.getTemplatePlaceholder(task.getTemplateId());
-            deviceCount = paramJson.keySet().stream()
-                    .filter(StringUtils::isNumeric)
-                    .filter(templatePlaceholder::contains)
-                    .count();
+            paramJson.entrySet().stream()
+                    .filter(entry -> StringUtils.isNumeric(entry.getKey()))
+                    .forEach(entry -> {
+                        if (templatePlaceholder.contains(entry.getKey())) {
+                            deviceCount.getAndIncrement();
+                            templatePlaceholder.remove(entry.getKey());
+                        }
+                    });
         }
-        goodsDetailVO.setLensNum((int) deviceCount);
+        goodsDetailVO.setLensNum(deviceCount.get());
         return ApiResponse.success(goodsDetailVO);
     }
 
diff --git a/src/main/java/com/ycwl/basic/service/pc/impl/SourceServiceImpl.java b/src/main/java/com/ycwl/basic/service/pc/impl/SourceServiceImpl.java
index ddce799..8207034 100644
--- a/src/main/java/com/ycwl/basic/service/pc/impl/SourceServiceImpl.java
+++ b/src/main/java/com/ycwl/basic/service/pc/impl/SourceServiceImpl.java
@@ -132,6 +132,7 @@ public class SourceServiceImpl implements SourceService {
             // 下载切片
             VideoPieceGetter.Task task = new VideoPieceGetter.Task();
             task.faceSampleIds = Collections.singletonList(source.getFaceSampleId());
+            task.force = true;
             VideoPieceGetter.addTask(task);
         }
         return ApiResponse.success("任务已下发");
diff --git a/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java b/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java
index bfacdab..e93bf6d 100644
--- a/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java
+++ b/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java
@@ -274,10 +274,15 @@ public class TaskTaskServiceImpl implements TaskService {
                 log.info("task callback: 没有视频源");
                 return;
             }
-            sourcesMap.forEach((key, value) -> {
-                // 每个value只保留第一个
-                value.removeIf(item -> !value.get(0).equals(item));
-            });
+            List<String> templatePlaceholder = templateRepository.getTemplatePlaceholder(templateId);
+            if (templatePlaceholder.stream().distinct().count() == templatePlaceholder.size()) {
+                sourcesMap.forEach((key, value) -> {
+                    // 每个value只保留第一个
+                    value.removeIf(item -> !value.get(0).equals(item));
+                });
+            } else {
+                log.info("task callback: 模板占位符有重复,templateId: {}", templateId);
+            }
             TaskReqQuery taskReqQuery = new TaskReqQuery();
             taskReqQuery.setFaceId(faceId);
             taskReqQuery.setTemplateId(templateId);
@@ -469,10 +474,15 @@ public class TaskTaskServiceImpl implements TaskService {
                 log.info("task callback: 没有视频源,templateId: {}", templateId);
                 return;
             }
-            sourcesMap.forEach((key, value) -> {
-                // 每个value只保留第一个
-                value.removeIf(item -> !value.get(0).equals(item));
-            });
+            List<String> templatePlaceholder = templateRepository.getTemplatePlaceholder(templateId);
+            if (templatePlaceholder.stream().distinct().count() == templatePlaceholder.size()) {
+                sourcesMap.forEach((key, value) -> {
+                    // 每个value只保留第一个
+                    value.removeIf(item -> !value.get(0).equals(item));
+                });
+            } else {
+                log.info("task callback: 模板占位符有重复,templateId: {}", templateId);
+            }
             TaskReqQuery taskReqQuery = new TaskReqQuery();
             taskReqQuery.setFaceId(faceId);
             taskReqQuery.setTemplateId(templateId);
diff --git a/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java b/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java
index 0c983c2..def99c5 100644
--- a/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java
+++ b/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java
@@ -75,6 +75,7 @@ public class VideoPieceGetter {
         public Long memberId;
         public Long faceId;
         public Long templateId;
+        public boolean force;
 
         public static interface Callback {
             void onInvoke();
@@ -170,6 +171,7 @@ public class VideoPieceGetter {
                         } catch (InterruptedException ignore) {
                         }
                     }
+                    isFirst.set(false);
                     if (pairDeviceMap.containsValue(faceSample.getDeviceId())) {
                         // 有关联设备!
                         // 找到对应的deviceId
@@ -179,40 +181,18 @@ public class VideoPieceGetter {
                                     log.info("找到同景区关联设备:{} -> {}", pairDeviceId, faceSample.getDeviceId());
                                     if (pairDeviceId != null) {
                                         executor.execute(() -> {
-                                            boolean result = doCut(pairDeviceId, faceSample.getId(), faceSample.getCreateAt(), task);
-                                            if (templatePlaceholder != null) {
-                                                if (templatePlaceholder.contains(faceSample.getDeviceId().toString())) {
-                                                    if (currentUnFinPlaceholder.contains(faceSample.getDeviceId().toString())) {
-                                                        if (result) {
-                                                            currentUnFinPlaceholder.remove(faceSample.getDeviceId().toString());
-                                                        }
-                                                    }
-                                                }
-                                                log.info("当前进度:!{}/{}", currentUnFinPlaceholder.size(), collection.size());
-                                                if (currentUnFinPlaceholder.size() <= 0) {
-                                                    if (!invoke.get()) {
-                                                        invoke.set(true);
-                                                        task.getCallback().onInvoke();
-                                                    }
-                                                }
-                                            }
+                                            doCut(pairDeviceId, faceSample.getId(), faceSample.getCreateAt(), task);
+                                            currentUnFinPlaceholder.remove(faceSample.getDeviceId().toString());
                                         });
                                     }
                                 });
                     }
-                    isFirst.set(false);
                     executor.execute(() -> {
-                        boolean result = doCut(faceSample.getDeviceId(), faceSample.getId(), faceSample.getCreateAt(), task);
+                        doCut(faceSample.getDeviceId(), faceSample.getId(), faceSample.getCreateAt(), task);
+                        currentUnFinPlaceholder.remove(faceSample.getDeviceId().toString());
                         if (templatePlaceholder != null) {
-                            if (templatePlaceholder.contains(faceSample.getDeviceId().toString())) {
-                                if (currentUnFinPlaceholder.contains(faceSample.getDeviceId().toString())) {
-                                    if (result) {
-                                        currentUnFinPlaceholder.remove(faceSample.getDeviceId().toString());
-                                    }
-                                }
-                            }
-                            log.info("当前进度:!{}/{}", currentUnFinPlaceholder.size(), collection.size());
-                            if (currentUnFinPlaceholder.size() <= 0) {
+                            log.info("当前进度:!{}/{}", currentUnFinPlaceholder.size(), templatePlaceholder.size());
+                            if (currentUnFinPlaceholder.isEmpty()) {
                                 if (!invoke.get()) {
                                     invoke.set(true);
                                     task.getCallback().onInvoke();
@@ -250,7 +230,7 @@ public class VideoPieceGetter {
 
         SourceEntity source = sourceMapper.querySameVideo(faceSampleId, device.getId());
 
-        if (source == null) {
+        if (source == null || task.force) {
             BigDecimal cutPre = BigDecimal.valueOf(5L);
             BigDecimal cutPost = BigDecimal.valueOf(4L);
             if (config != null) {
@@ -299,38 +279,44 @@ public class VideoPieceGetter {
                 // 上传成功后删除文件
                 outFile.delete();
             }
-            SourceEntity imgSource = sourceMapper.findBySampleId(faceSampleId);
-            SourceEntity sourceEntity = new SourceEntity();
-            sourceEntity.setId(SnowFlakeUtil.getLongId());
-            sourceEntity.setCreateTime(baseTime);
-            if (imgSource != null) {
-                sourceEntity.setUrl(imgSource.getUrl());
-                sourceEntity.setPosJson(imgSource.getPosJson());
-            }
-            sourceEntity.setVideoUrl(url);
-            sourceEntity.setFaceSampleId(faceSampleId);
-            sourceEntity.setScenicId(device.getScenicId());
-            sourceEntity.setDeviceId(deviceId);
-            sourceEntity.setType(1);
-            if (task.memberId != null && task.faceId != null) {
-                MemberSourceEntity videoSource = new MemberSourceEntity();
-                videoSource.setMemberId(task.getMemberId());
-                videoSource.setType(1);
-                videoSource.setFaceId(task.getFaceId());
-                videoSource.setScenicId(device.getScenicId());
-                videoSource.setSourceId(sourceEntity.getId());
-                IsBuyRespVO isBuy = orderBiz.isBuy(task.getMemberId(), device.getScenicId(), 1, task.getFaceId());
-                if (isBuy.isBuy()) { // 如果用户买过
-                    videoSource.setIsBuy(1);
-                } else if (isBuy.isFree()) { // 全免费逻辑
-                    videoSource.setIsBuy(1);
-                } else {
-                    videoSource.setIsBuy(0);
+            if (source == null) {
+                SourceEntity imgSource = sourceMapper.findBySampleId(faceSampleId);
+                SourceEntity sourceEntity = new SourceEntity();
+                sourceEntity.setId(SnowFlakeUtil.getLongId());
+                sourceEntity.setCreateTime(baseTime);
+                if (imgSource != null) {
+                    sourceEntity.setUrl(imgSource.getUrl());
+                    sourceEntity.setPosJson(imgSource.getPosJson());
                 }
-                sourceMapper.addRelation(videoSource);
+                sourceEntity.setVideoUrl(url);
+                sourceEntity.setFaceSampleId(faceSampleId);
+                sourceEntity.setScenicId(device.getScenicId());
+                sourceEntity.setDeviceId(deviceId);
+                sourceEntity.setType(1);
+                if (task.memberId != null && task.faceId != null) {
+                    MemberSourceEntity videoSource = new MemberSourceEntity();
+                    videoSource.setMemberId(task.getMemberId());
+                    videoSource.setType(1);
+                    videoSource.setFaceId(task.getFaceId());
+                    videoSource.setScenicId(device.getScenicId());
+                    videoSource.setSourceId(sourceEntity.getId());
+                    IsBuyRespVO isBuy = orderBiz.isBuy(task.getMemberId(), device.getScenicId(), 1, task.getFaceId());
+                    if (isBuy.isBuy()) { // 如果用户买过
+                        videoSource.setIsBuy(1);
+                    } else if (isBuy.isFree()) { // 全免费逻辑
+                        videoSource.setIsBuy(1);
+                    } else {
+                        videoSource.setIsBuy(0);
+                    }
+                    sourceMapper.addRelation(videoSource);
+                }
+                sourceMapper.add(sourceEntity);
+                videoReUploader.addTask(url, sourceEntity.getId());
+            } else {
+                source.setVideoUrl(url);
+                sourceMapper.update(source);
+                videoReUploader.addTask(url, source.getId());
             }
-            sourceMapper.add(sourceEntity);
-            videoReUploader.addTask(sourceEntity.getVideoUrl(), sourceEntity.getId());
         } else {
             // 有原视频
             if (task.memberId != null && task.faceId != null) {
diff --git a/src/main/java/com/ycwl/basic/task/VideoTaskGenerator.java b/src/main/java/com/ycwl/basic/task/VideoTaskGenerator.java
index f24691f..aac8cb8 100644
--- a/src/main/java/com/ycwl/basic/task/VideoTaskGenerator.java
+++ b/src/main/java/com/ycwl/basic/task/VideoTaskGenerator.java
@@ -84,7 +84,7 @@ public class VideoTaskGenerator {
                 query.setStartTime(DateUtil.beginOfDay(new Date()));
                 query.setEndTime(DateUtil.endOfDay(new Date()));
                 List<FaceRespVO> list = faceMapper.list(query);
-                list.stream().parallel().forEach(face -> {
+                list.forEach(face -> {
                     faceService.matchFaceId(face.getId(), false);
                     if (Integer.valueOf(3).equals(scenicConfig.getBookRoutine())) {
                         // 全部生成