Search in sources :

Example 1 with VideoDO

use of org.saxing.a0041_wemedia.domain.entity.VideoDO in project java-example by saxingz.

the class VideoLogicImpl method downloadVideo.

@Override
public Boolean downloadVideo(Long id) throws IOException {
    synchronized (DOWNLOAD_LOCK) {
        log.info("downloadVideo: id: " + id);
        try {
            Thread.sleep(500 + new Random().nextInt(1000));
        } catch (InterruptedException ignored) {
        }
        VideoDO videoDO = this.getById(id);
        if (Objects.isNull(videoDO)) {
            return false;
        }
        // 判断是否已下载完成
        if (Objects.equals(videoDO.getDownloadStatus(), DownLoadStatus.DOWNLOADED.getCode())) {
            return true;
        }
        String videoId = videoDO.getVideoId();
        String videoPathStr = BASE_PATH + id;
        Path videoPath = Paths.get(videoPathStr);
        boolean isFirstNull = false;
        if (!Files.exists(videoPath)) {
            isFirstNull = true;
            Files.createDirectories(videoPath);
        }
        List<Path> fileList = Files.list(videoPath).collect(Collectors.toList());
        // 英文字幕
        Path enVtt = fileList.stream().filter(p -> p.getFileName().toString().endsWith("en.vtt")).findFirst().orElse(null);
        // 中文字幕
        Path zhHansvtt = fileList.stream().filter(p -> p.getFileName().toString().endsWith(".zh-Hans.vtt")).findFirst().orElse(null);
        // 原始视频文件
        Path originVideoFile = fileList.stream().filter(p -> p.getFileName().toString().endsWith(".mp4")).findFirst().orElse(null);
        // 原始音频文件
        Path originAudioFile = fileList.stream().filter(p -> p.getFileName().toString().endsWith(".webm") || p.getFileName().toString().endsWith(".m4a")).findFirst().orElse(null);
        // 校验下载项
        if ((Objects.isNull(enVtt) || Objects.isNull(zhHansvtt) || Objects.isNull(originVideoFile) || Objects.isNull(originAudioFile)) && !isFirstNull) {
            // 如果不支持断点续传了,再把这个注释解开
            if (Files.list(videoPath).count() > 0) {
                new File(videoPathStr).renameTo(new File(videoPathStr + "-" + UUID.fastUUID().toString()));
                if (!Files.exists(videoPath)) {
                    Files.createDirectories(videoPath);
                }
            }
        }
        // 下载
        if (Objects.isNull(enVtt) || Objects.isNull(zhHansvtt) || Objects.isNull(originVideoFile) || Objects.isNull(originAudioFile)) {
            String outputFile = videoPathStr + "\\" + id + ".%(ext)s";
            // 重新下载
            List<String> arguments = new ArrayList<>(Arrays.asList(YOUTUBE_DL_PATH, "--write-sub", "--write-auto-sub", "--sub-lang", "en,zh-Hans", "--sub-format", "vtt", "-f", "\"bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best\"", "--no-check-certificate", "-o", "\"" + outputFile + "\"", "--proxy", "socks5://127.0.0.1:51837/", "https://www.youtube.com/watch?v=" + videoId));
            try {
                log.info("arguments: " + String.join(" ", arguments));
                ProcessRunner.run(arguments);
                String videoTitle = videoDO.getVideoTitle();
                String titleFile = videoPathStr + "\\" + id + "-title.txt";
                Path titleFilePath = Paths.get(titleFile);
                if (!Files.exists(titleFilePath)) {
                    Files.write(titleFilePath, videoTitle.getBytes(), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
                }
            } catch (ProcessException | InterruptedException e) {
                e.printStackTrace();
                log.error(e.toString());
            }
        }
        // 刷新列表
        fileList = Files.list(videoPath).collect(Collectors.toList());
        // 英文字幕
        enVtt = fileList.stream().filter(p -> p.getFileName().toString().endsWith("en.vtt")).findFirst().orElse(null);
        // 中文字幕
        zhHansvtt = fileList.stream().filter(p -> p.getFileName().toString().endsWith(".zh-Hans.vtt")).findFirst().orElse(null);
        // 原始视频文件
        originVideoFile = fileList.stream().filter(p -> p.getFileName().toString().endsWith(".mp4")).findFirst().orElse(null);
        // 原始音频文件
        originAudioFile = fileList.stream().filter(p -> p.getFileName().toString().endsWith(".webm") || p.getFileName().toString().endsWith(".m4a")).findFirst().orElse(null);
        // 校验下载项
        if (Objects.isNull(enVtt) || Objects.isNull(zhHansvtt) || Objects.isNull(originVideoFile) || Objects.isNull(originAudioFile)) {
            // 下载失败,返回
            log.error("下载失败,返回 videoId: " + id);
            return false;
        } else {
            log.info("下载成功 videoId: " + id);
            videoDO.setDownloadStatus(DownLoadStatus.DOWNLOADED.getCode());
            this.saveOrUpdate(videoDO);
            return true;
        }
    }
}
Also used : Path(java.nio.file.Path) java.util(java.util) ResourceLock(org.saxing.a0041_wemedia.util.ResourceLock) CommonsLog(lombok.extern.apachecommons.CommonsLog) RebuildStatus(org.saxing.a0041_wemedia.domain.enums.RebuildStatus) DownLoadStatus(org.saxing.a0041_wemedia.domain.enums.DownLoadStatus) IVideoLogic(org.saxing.a0041_wemedia.logic.IVideoLogic) CollectionUtils(org.apache.commons.collections4.CollectionUtils) Charset(java.nio.charset.Charset) ProcessRunner(org.saxing.a0041_wemedia.process.ProcessRunner) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Service(org.springframework.stereotype.Service) Subtitles(org.saxing.a0041_wemedia.logic.subtitles.entities.Subtitles) UUID(cn.hutool.core.lang.UUID) SubtitleMerger(org.saxing.a0041_wemedia.logic.subtitles.SubtitleMerger) Path(java.nio.file.Path) ServiceImpl(com.baomidou.mybatisplus.extension.service.impl.ServiceImpl) Files(java.nio.file.Files) SubFromStart(org.saxing.a0041_wemedia.logic.subtitles.SubFromStart) SubRipWriter(org.saxing.a0041_wemedia.logic.subtitles.SubRipWriter) StandardOpenOption(java.nio.file.StandardOpenOption) FileUtils(org.apache.commons.io.FileUtils) FileOrigin(org.saxing.a0041_wemedia.logic.subtitles.entities.FileOrigin) VideoMapper(org.saxing.a0041_wemedia.mapper.VideoMapper) Collectors(java.util.stream.Collectors) StandardCharsets(java.nio.charset.StandardCharsets) java.io(java.io) Paths(java.nio.file.Paths) VideoDO(org.saxing.a0041_wemedia.domain.entity.VideoDO) ProcessException(org.saxing.a0041_wemedia.process.ProcessException) ProcessException(org.saxing.a0041_wemedia.process.ProcessException) VideoDO(org.saxing.a0041_wemedia.domain.entity.VideoDO)

Example 2 with VideoDO

use of org.saxing.a0041_wemedia.domain.entity.VideoDO in project java-example by saxingz.

the class VideoLogicImpl method rebuild.

@Override
public Boolean rebuild(Long id) throws IOException {
    synchronized (REBUILD_VIDEO_LOCK) {
        log.info("rebuild: id: " + id);
        VideoDO videoDO = this.getById(id);
        if (Objects.isNull(videoDO)) {
            log.error("视频不存在, video表id: " + id);
            return false;
        }
        if (!Objects.equals(videoDO.getDownloadStatus(), DownLoadStatus.DOWNLOADED.getCode())) {
            log.info("视频未下载,开始下载 videoId: " + id);
            downloadVideo(id);
        }
        videoDO = this.getById(id);
        if (!Objects.equals(videoDO.getDownloadStatus(), DownLoadStatus.DOWNLOADED.getCode())) {
            log.info("视频不存在 videoId: " + id);
            return false;
        }
        if (Objects.equals(videoDO.getRebuildStatus(), RebuildStatus.REBUILDED.getCode())) {
            return true;
        }
        String videoPathStr = BASE_PATH + id;
        Path videoPath = Paths.get(videoPathStr);
        if (!Files.exists(videoPath)) {
            Files.createDirectories(videoPath);
        }
        List<Path> fileList = Files.list(videoPath).collect(Collectors.toList());
        // 英文字幕
        Path enVtt = fileList.stream().filter(p -> p.getFileName().toString().endsWith("en.vtt")).findFirst().orElse(null);
        // 中文字幕
        Path zhHansvtt = fileList.stream().filter(p -> p.getFileName().toString().endsWith(".zh-Hans.vtt")).findFirst().orElse(null);
        // 原始视频文件
        Path originVideoFile = fileList.stream().filter(p -> p.getFileName().toString().endsWith(".mp4")).findFirst().orElse(null);
        // 原始音频文件
        Path originAudioFile = fileList.stream().filter(p -> p.getFileName().toString().endsWith(".webm") || p.getFileName().toString().endsWith(".m4a")).findFirst().orElse(null);
        if (Objects.isNull(originAudioFile)) {
            log.error("没有音频文件 videoId: " + id);
            return false;
        }
        // 1. convert to mp3
        log.info("1. convert to mp3, videoId: " + id);
        convertToMp3(originAudioFile);
        // 2. subtitle vtt -> srt
        log.info("2. subtitle vtt -> srt, videoId: " + id);
        convertToSrt(zhHansvtt, "zh");
        convertToSrt(enVtt, "en");
        // 3. merge subtitle
        log.info("3. merge subtitle, videoId: " + id);
        fileList = Files.list(videoPath).collect(Collectors.toList());
        Path enSrt = fileList.stream().filter(p -> p.getFileName().toString().endsWith("en.srt")).findFirst().orElse(null);
        Path zhSrt = fileList.stream().filter(p -> p.getFileName().toString().endsWith("zh.srt")).findFirst().orElse(null);
        if (Objects.isNull(enSrt) || Objects.isNull(zhSrt)) {
            log.error("字幕不全, videoId: " + id);
            return false;
        }
        try {
            mergeSubtitle(enSrt, zhSrt);
        } catch (InterruptedException e) {
            e.printStackTrace();
            log.error("字幕合并失败, videoId: " + id);
        }
        // 4. merge subtitle watermark video
        log.info("4. merge subtitle watermark video, videoId: " + id);
        fileList = Files.list(videoPath).collect(Collectors.toList());
        Path mixedSrt = fileList.stream().filter(p -> p.getFileName().toString().endsWith("mixed.srt")).findFirst().orElse(null);
        mergeSubtitleAndVideo(originVideoFile, mixedSrt);
        // 5. merge video audio
        log.info("5. merge video audio, videoId: " + id);
        fileList = Files.list(videoPath).collect(Collectors.toList());
        Path subtitleVideo = fileList.stream().filter(p -> p.getFileName().toString().endsWith("subtitle.mp4")).findFirst().orElse(null);
        Path mp3Audio = fileList.stream().filter(p -> p.getFileName().toString().endsWith(".mp3")).findFirst().orElse(null);
        if (Objects.isNull(subtitleVideo) || Objects.isNull(mp3Audio)) {
            log.error("subtitleVideo 或 mp3Audio 不存在, videoId: " + id);
            return false;
        }
        mergeVideoAndAudio(subtitleVideo, mp3Audio);
        // 6. merge head and tail
        log.info("6. merge head and tail, videoId: " + id);
        fileList = Files.list(videoPath).collect(Collectors.toList());
        Path audioVideoMp4 = fileList.stream().filter(p -> p.getFileName().toString().endsWith("audio.mp4")).findFirst().orElse(null);
        if (Objects.isNull(audioVideoMp4)) {
            log.error("audioVideo生成失败, videoId: " + id);
            return false;
        }
        mergeHeadTail(audioVideoMp4, Paths.get(VIDEO_HEAD_PATH), Paths.get(VIDEO_TAIL_PATH));
        // 9. 校验生成视频
        log.info("7. 校验生成视频, videoId: " + id);
        fileList = Files.list(videoPath).collect(Collectors.toList());
        Path finalVideo = fileList.stream().filter(p -> p.getFileName().toString().endsWith("final.mp4")).findFirst().orElse(null);
        if (Objects.isNull(finalVideo)) {
            log.error("视频最后生成失败, videoId: " + id);
            return false;
        }
        // 标记生成成功
        videoDO.setRebuildStatus(RebuildStatus.REBUILDED.getCode());
        this.updateById(videoDO);
        log.info("视频生成成功!!!, videoId: " + id);
        return true;
    }
}
Also used : Path(java.nio.file.Path) VideoDO(org.saxing.a0041_wemedia.domain.entity.VideoDO)

Example 3 with VideoDO

use of org.saxing.a0041_wemedia.domain.entity.VideoDO in project java-example by saxingz.

the class VideoController method listVideos.

/**
 * 查看原始视频
 */
@ApiOperation("查看原始视频")
@ApiImplicitParams({ @ApiImplicitParam(name = "page", value = "页码", defaultValue = "1"), @ApiImplicitParam(name = "pageNum", value = "每页条数", defaultValue = "1") })
@PostMapping("/list")
public Page<VideoVO> listVideos(@RequestBody VideoDO video, @RequestParam @Min(value = 1, message = "页码不得少于1") Integer page, @RequestParam @Min(value = 1, message = "每页条数不得少于1") @Max(value = 100, message = "每页条数不大于100") Integer pageNum) {
    LambdaQueryWrapper<VideoDO> queryWrapper = Wrappers.lambdaQuery();
    queryWrapper.setEntity(video);
    queryWrapper.like(StringUtils.isNotBlank(video.getChannelId()), VideoDO::getChannelId, video.getChannelId());
    queryWrapper.like(StringUtils.isNotBlank(video.getChannelTitle()), VideoDO::getChannelTitle, video.getChannelTitle());
    queryWrapper.like(StringUtils.isNotBlank(video.getVideoId()), VideoDO::getVideoId, video.getVideoId());
    queryWrapper.like(StringUtils.isNotBlank(video.getVideoTitle()), VideoDO::getVideoTitle, video.getVideoTitle());
    queryWrapper.like(StringUtils.isNotBlank(video.getDescription()), VideoDO::getDescription, video.getDescription());
    queryWrapper.like(StringUtils.isNotBlank(video.getDownloadedUrl()), VideoDO::getDownloadedUrl, video.getDownloadedUrl());
    video.setChannelId(null).setChannelTitle(null).setVideoId(null).setVideoTitle(null).setDescription(null).setDownloadedUrl(null);
    Page<VideoDO> videoDOPage = videoLogic.page(new Page<>(page, pageNum), queryWrapper).addOrder(OrderItem.desc(TableInfoHelper.getTableInfo(VideoDO.class).getKeyProperty()));
    Page<VideoVO> result = beanMapper.map(videoDOPage, new TypeBuilder<Page<VideoDO>>() {
    }.build(), new TypeBuilder<Page<VideoVO>>() {
    }.build());
    if (result.getSize() > 0) {
        result.getRecords().forEach(r -> r.setTransferList(transferLogic.list(new QueryWrapper<>(new TransferDO().setVideoId(r.getId())))));
    }
    return result;
}
Also used : VideoVO(org.saxing.a0041_wemedia.domain.vo.VideoVO) VideoDO(org.saxing.a0041_wemedia.domain.entity.VideoDO) TypeBuilder(ma.glasnost.orika.metadata.TypeBuilder) Page(com.baomidou.mybatisplus.extension.plugins.pagination.Page) TransferDO(org.saxing.a0041_wemedia.domain.entity.TransferDO) ApiImplicitParams(io.swagger.annotations.ApiImplicitParams) ApiOperation(io.swagger.annotations.ApiOperation)

Example 4 with VideoDO

use of org.saxing.a0041_wemedia.domain.entity.VideoDO in project java-example by saxingz.

the class ChannelLogic method scanChannel.

@Override
public void scanChannel(DateTime startDate, DateTime endDate, String channelId) {
    ChannelDO channelDO = this.lambdaQuery().ge(ChannelDO::getChannelId, channelId).one();
    if (Objects.isNull(channelDO)) {
        log.error("没有本频道: channelId: " + channelId);
        return;
    }
    List<SearchResult> searchResults = scanResult(startDate, endDate, channelId);
    if (CollectionUtils.isEmpty(searchResults)) {
        return;
    }
    searchResults.forEach(searchResult -> {
        String kind = searchResult.getId().getKind();
        if (!Objects.equals(kind, "youtube#video")) {
            return;
        }
        log.info("找到一个youtube视频   " + searchResult);
        String videoId = searchResult.getId().getVideoId();
        VideoDO video = videoLogic.lambdaQuery().eq(VideoDO::getVideoId, videoId).one();
        if (Objects.nonNull(video)) {
            return;
        }
        String channelTitle = searchResult.getSnippet().getChannelTitle();
        String videoTitle = searchResult.getSnippet().getTitle();
        String description = searchResult.getSnippet().getDescription();
        com.google.api.client.util.DateTime publishedAt = searchResult.getSnippet().getPublishedAt();
        String thumbnails = searchResult.getSnippet().getThumbnails().getHigh().getUrl();
        video = new VideoDO().setPlatform(Platform.YOUTUBE.getName()).setChannelId(channelId).setChannelTitle(channelTitle).setVideoId(videoId).setVideoTitle(videoTitle).setDescription(description).setPublishTime(new Date(publishedAt.getValue())).setThumbnails(thumbnails);
        videoLogic.saveOrUpdate(video);
    });
    // 更新channel最后follow时间
    com.google.api.client.util.DateTime lastPublishedAt = searchResults.get(searchResults.size() - 1).getSnippet().getPublishedAt();
    channelDO.setFollowTime(new Date(lastPublishedAt.getValue()));
    this.updateById(channelDO);
}
Also used : VideoDO(org.saxing.a0041_wemedia.domain.entity.VideoDO) java.util(java.util) SearchResult(com.google.api.services.youtube.model.SearchResult) ChannelDO(org.saxing.a0041_wemedia.domain.entity.ChannelDO)

Aggregations

VideoDO (org.saxing.a0041_wemedia.domain.entity.VideoDO)4 Path (java.nio.file.Path)2 java.util (java.util)2 UUID (cn.hutool.core.lang.UUID)1 Page (com.baomidou.mybatisplus.extension.plugins.pagination.Page)1 ServiceImpl (com.baomidou.mybatisplus.extension.service.impl.ServiceImpl)1 SearchResult (com.google.api.services.youtube.model.SearchResult)1 ApiImplicitParams (io.swagger.annotations.ApiImplicitParams)1 ApiOperation (io.swagger.annotations.ApiOperation)1 java.io (java.io)1 Charset (java.nio.charset.Charset)1 StandardCharsets (java.nio.charset.StandardCharsets)1 Files (java.nio.file.Files)1 Paths (java.nio.file.Paths)1 StandardOpenOption (java.nio.file.StandardOpenOption)1 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)1 Collectors (java.util.stream.Collectors)1 CommonsLog (lombok.extern.apachecommons.CommonsLog)1 TypeBuilder (ma.glasnost.orika.metadata.TypeBuilder)1 CollectionUtils (org.apache.commons.collections4.CollectionUtils)1