• 后端并没有什么难度,一步一步按照上边分析的流程解析真实视频 URL 就可以了。

    /**
    * @param url
    * @author xiaofu
    * @description 获取当前链接重定向后的url
    * @date 2020/9/15 12:43
    */

    public static String getLocation(String url) {
            try {
                URL serverUrl = new URL(url);
                HttpURLConnection conn = (HttpURLConnection) serverUrl.openConnection();
                conn.setRequestMethod("GET");
                conn.setInstanceFollowRedirects(false);
                conn.setRequestProperty("User-agent""ua");//模拟手机连接
                conn.connect();
                String location = conn.getHeaderField("Location");
                return location;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return "";
        }

    下边是完整的后端实现,可以看到代码量非常的少。

    /**
     * @author xiaofu-公众号:程序员内点事
     * @description 抖音无水印视频下载
     * @date 2020/9/15 18:44
     */

    @Slf4j
    @Controller
    public class DYController {
        public static String DOU_YIN_BASE_URL = "https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=";
        /**
         * @param url
         * @author xiaofu
         * @description 解析抖音无水印视频
         * @date 2020/9/15 12:43
         */

        @RequestMapping("/parseVideoUrl")
        @ResponseBody
        public String parseVideoUrl(@RequestBody String url) throws Exception {
            DYDto dyDto = new DYDto();
            try {
                url = URLDecoder.decode(url).replace("url=""");
                /**
                 * 1、短连接重定向后的 URL
                 */

                String redirectUrl = CommonUtils.getLocation(url);

                /**
                 * 2、拿到视频对应的 ItemId
                 */

                String videoUrl = "";
                String musicUrl = "";
                String videoPic = "";
                String desc = "";
                if (!StringUtils.isEmpty(redirectUrl)) {
                    /**
                     * 3、用 ItemId 拿视频的详细信息,包括无水印视频url
                     */

                    String itemId = CommonUtils.matchNo(redirectUrl);
                    StringBuilder sb = new StringBuilder();
                    sb.append(DOU_YIN_BASE_URL).append(itemId);
                    String videoResult = CommonUtils.httpGet(sb.toString());
                    DYResult dyResult = JSON.parseObject(videoResult, DYResult.class);
                    /**
                     * 4、无水印视频 url
                     */

                    videoUrl = dyResult.getItem_list().get(0)
                            .getVideo().getPlay_addr().getUrl_list().get(0)
                            .replace("playwm""play");
                    String videoRedirectUrl = CommonUtils.getLocation(videoUrl);
                    dyDto.setVideoUrl(videoRedirectUrl);
                    /**
                     * 5、音频 url
                     */

                    musicUrl = dyResult.getItem_list().get(0).getMusic().getPlay_url().getUri();
                    dyDto.setMusicUrl(musicUrl);
                    /**
                     * 6、封面
                     */

                    videoPic = dyResult.getItem_list().get(0).getVideo().getDynamic_cover().getUrl_list().get(0);
                    dyDto.setVideoPic(videoPic);
                    /**
                     * 7、视频文案
                     */

                    desc = dyResult.getItem_list().get(0).getDesc();
                    dyDto.setDesc(desc);
                }
            } catch (Exception e) {
                log.error("去水印异常 {}", e);
            }
            return JSON.toJSONString(dyDto);
        }
    }

    前端实现也比较简单,拿到后端解析出来的视频URL 预览播放、下载就OK了。

    为快速实现我用了老古董JQuery,我这个年纪的人对它感情还是很深厚的,UI 框架用的 layer.js。源码后边会分享给大家,就不全贴出来了。

    $.ajax({
        url'/parseVideoUrl',
        type'POST',
        data: {"url": link},
        successfunction (data{
            $('.qsy-submit').attr('disabled'false);
            try {
                var rows = JSON.parse(data);
                layer.close(index);
                layer.open({
                    type1,
                    titlefalse,
                    closeBtn1,
                    shadeClosetrue,
                    skin'yourclass',
                    content`<div style="overflow:hidden;height: 580px;width: 350px;"><div><div class="popButton"><a href="###" rel="noopener nofollow noreferrer" onclick="downloadVideo('${rows['videoUrl']}','${rows['desc']}')"><button class="layui-bg-red layui-btn-sm layui-btn">下载视频</button></a></div><div class="popButton"><textarea id="videourl" cols="1" rows="1" style="height:0;width:0;position: absolute;">${rows['videoUrl']}</textarea><button class="layui-btn-sm layui-bg-blue layui-btn" onclick="copy('videourl')">复制链接</button></div><div class="popButton"><a href="###" rel="noopener nofollow noreferrer" onclick="downloadVideo('${rows['musicUrl']}','${rows['desc']}')"><button class="layui-btn-sm layui-btn">下载音频</button></a></div><video id="video" width="360px" height="500px" src="${rows['videoUrl']}" controls = "true" poster="${rows['videoPic']}" preload="auto" webkit-playsinline="true" playsinline="true" x-webkit-airplay="allow" x5-video-player-type="h5" x5-video-player-fullscreen="true" x5-video-orientation="portraint" style="object-fit:fill"><source src="${rows['videoUrl']}" type="video/mp4"> </video></div></div>`
                    //content: `<video id="video" src="${rows['videoUrl']}" controls = "true" poster="${rows['videoPic']}" preload="auto" webkit-playsinline="true" playsinline="true" x-webkit-airplay="allow" x5-video-player-type="h5" x5-video-player-fullscreen="true" x5-video-orientation="portraint" style="object-fit:fill"><source src="${rows['videoUrl']}" type="video/mp4"> </video>`
                });

            } catch (error) {
                layer.alert('错误信息:' + error, {
                    title'异常',
                    skin'layui-layer-lan',
                    closeBtn0,
                    anim4 //动画类型
                });
                return false;
            }
        },
        errorfunction (err{
            console.log(err);
            layer.close(index);
            $('.qsy-submit').attr('disabled'false);
        },
        donefunction ({
            layer.close(index);
        }
    })
    })
     <!-- 解决访问视频url 请求403异常 -->
     <meta name="referrer" content="no-referrer"/>

    还简单做了下移动端适配,样式看着还可以,但是功能使用起来有点差强人意,后边在做优化了。

    总结

    很多东西就是这样,没认真研究之前总感觉深不可测,可一旦接触到技术的本质,又开始笑自己之前好蠢,懂与不懂有时就查那么一层窗户纸。

    好了今天就到这,本文源码在 公众号回复【源码】自取


    如果对你有用,欢迎 在看、点赞、转发 ,您的认可是我最大的动力。

    整理了几百本各类技术电子书,送给小伙伴们。关注公号回复【666】自行领取。和一些小伙伴们建了一个技术交流群,一起探讨技术、分享技术资料,旨在共同学习进步,如果感兴趣就加入我们吧!


    本文分享自微信公众号 - 程序员内点事(chengxy-nds)。
    如有侵权,请联系 support@oschina.cn 删除。
    本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

    03-17 12:26