doum
3 小时以前 ce44d803b73a65b2cc31db5bcc662139029463d3
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/collection/CollectionMediaSyncServiceImpl.java
@@ -19,12 +19,13 @@
import com.doumee.dao.business.model.CollectionMedia;
import com.doumee.dao.business.model.CollectionStation;
import com.doumee.service.business.CollectionMediaSyncService;
import com.doumee.service.business.DeliverySnapshotService;
import com.doumee.service.business.collection.CollectionMediaConstants;
import com.doumee.service.business.third.model.PageData;
import com.doumee.service.business.third.model.PageWrap;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@@ -54,6 +55,8 @@
    private CollectionMediaMapper collectionMediaMapper;
    @Autowired
    private CollectionStationMapper collectionStationMapper;
    @Autowired
    private DeliverySnapshotService deliverySnapshotService;
    @Autowired
    private SystemDictDataBiz systemDictDataBiz;
    @Resource(name = "asyncExecutor")
@@ -105,13 +108,19 @@
        if (station == null || Constants.equalsInteger(station.getIsdeleted(), Constants.ONE)) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        List<MediaItemDTO> items = isapiClient.searchMediaAll(station, startTime, endTime, trackId, IsapiConstants.MAX_PAGE_RESULTS);
        List<MediaItemDTO> items = isapiClient.searchMediaAll(station, startTime, endTime,
                resolveSyncTrackId(trackId), IsapiConstants.MAX_PAGE_RESULTS);
        log.info("采集站媒体检索 stationId={} ip={} range={}~{} track={} found={}",
                stationId, station.getIp(), startTime, endTime, trackId, items.size());
                stationId, station.getIp(), startTime, endTime, resolveSyncTrackId(trackId), items.size());
        int count = 0;
        int skipped = 0;
        Date now = new Date();
        for (MediaItemDTO item : items) {
            if (StringUtils.isBlank(item.getFileIndex())) {
                continue;
            }
            if (!isSyncableMp4Video(item)) {
                skipped++;
                continue;
            }
            Long exists = collectionMediaMapper.selectCount(new QueryWrapper<CollectionMedia>().lambda()
@@ -140,7 +149,54 @@
            collectionMediaMapper.insert(media);
            count++;
        }
        if (skipped > 0) {
            log.info("采集站媒体索引跳过非MP4视频 stationId={} skipped={}", stationId, skipped);
        }
        return count;
    }
    /** 同步索引仅检索主码流录像 track(默认 101),不包含抓图 track 103 */
    private String resolveSyncTrackId(String trackId) {
        if (StringUtils.isNotBlank(trackId)) {
            String val = trackId.trim();
            if (!"auto".equalsIgnoreCase(val) && !"*".equals(val) && !"0".equals(val)) {
                return val;
            }
        }
        return IsapiConstants.DEFAULT_TRACK_ID;
    }
    /** 同步入库:仅 MP4 视频(扩展名 .mp4,且非图片/音频类型) */
    private static boolean isSyncableMp4Video(MediaItemDTO item) {
        if (item.getMediaType() != null && item.getMediaType() != 0) {
            return false;
        }
        String trackId = StringUtils.defaultString(item.getTrackId());
        if (trackId.endsWith("3")) {
            return false;
        }
        return isMp4FileName(resolveItemFileName(item));
    }
    private static String resolveItemFileName(MediaItemDTO item) {
        if (StringUtils.isNotBlank(item.getFileName())) {
            return item.getFileName();
        }
        String uri = item.getPlaybackUri();
        if (StringUtils.isBlank(uri)) {
            return null;
        }
        java.util.regex.Matcher m = java.util.regex.Pattern
                .compile("[?&](?:name|filename|fileName)=([^&\\s]+)", java.util.regex.Pattern.CASE_INSENSITIVE)
                .matcher(uri.replace("&amp;", "&"));
        if (m.find()) {
            try {
                return java.net.URLDecoder.decode(m.group(1), StandardCharsets.UTF_8.name());
            } catch (Exception e) {
                return m.group(1);
            }
        }
        return null;
    }
    @Override
@@ -152,7 +208,7 @@
        if (Constants.equalsInteger(media.getDownloadStatus(), Constants.ONE)) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "文件已下载,无需重复下载");
        }
        if (Constants.equalsInteger(media.getDownloadStatus(), Constants.COLLECTION_MEDIA_DOWNLOADING)) {
        if (Constants.equalsInteger(media.getDownloadStatus(), CollectionMediaConstants.DOWNLOAD_STATUS_DOWNLOADING)) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "文件正在下载中,请稍后刷新");
        }
        CollectionStation station = collectionStationMapper.selectById(media.getStationId());
@@ -160,7 +216,7 @@
            throw new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        CollectionMedia downloading = new CollectionMedia();
        downloading.setDownloadStatus(Constants.COLLECTION_MEDIA_DOWNLOADING);
        downloading.setDownloadStatus(CollectionMediaConstants.DOWNLOAD_STATUS_DOWNLOADING);
        int updated = collectionMediaMapper.update(downloading, new QueryWrapper<CollectionMedia>().lambda()
                .eq(CollectionMedia::getId, mediaId)
                .in(CollectionMedia::getDownloadStatus, Constants.ZERO, 2));
@@ -195,6 +251,7 @@
            update.setDownloadTime(new Date());
            collectionMediaMapper.updateById(update);
            log.info("异步下载成功 mediaId={} path={}", mediaId, path);
            deliverySnapshotService.submitAnalyzeAsync(mediaId);
        } catch (Exception e) {
            markDownloadFailed(mediaId);
            log.error("异步下载异常 mediaId={}: {}", mediaId, e.getMessage(), e);