Handwriting a Douyin video watermarking tool, don’t just be a programmer

A hundred causes will have results

Tell me why I want to make a Douyin video watermarking tool, it is actually because of my sand sculpture girlfriend, she actually just just me~

One night she saw a very unique  教育意义 video on Douyin, "A man who loves his wife should contract all the housework", and then it wants to download the video and share it with her sister group  驭夫 .

But everyone knows that the videos downloaded by Douyin are watermarked. As a player with severe obsessive-compulsive disorder, this is not allowed. If there is no way, then find out if there is a watermarking tool. If you find a circle, you will either charge a fee or download it. Without coming down, the smile on the Lord's face gradually disappeared.

I joked on the side: It’s not too difficult, or I will make one for you! "Can you do it?" Then he cast a disdainful look.

805f240cbe04847f1b115f4e18e71825.pngDare to say I can't?

Damn! I was joking and said that I can't do it. This is unbearable. I have to prove it to you! Man, I can’t stand this

(Google browser is recommended), online preview of the tool: http://47.93.6.5:8888/index

d6588693d4bbbc2fa6d23f3e84cdedea.gifUse preview to remove watermark

Let’s analyze the idea of ​​making this watermark removal tool with everyone. When many people hear it  去水印 , they subconsciously think that it is a better algorithm. In fact, this is an illusion~

Inquire

Although I have to fight for my breath, I was really confused when I first started, because I didn't know where to start and how to remove the watermark? Is it possible that I have to write an algorithm?

I found a sharing link for a TikTok video and analyzed it a little bit. It is not difficult to find that this is a processed short link. Then this short link will definitely redirect to the real video address  URL .

https://v.douyin.com/JSkuhE4/

I entered the short link in the browser and got the following one URL . Judging URLfrom my experience, it is  6820792802394262795 very likely to be the unique ID of the video, and the unique ID is usually used as the input  parameter of the interface for obtaining details. Hey~ It seems to have a clue.

https://www.iesdouyin.com/share/video/6820792802394262795/

82bf9c91c4fbc61d4e3e51f22c6da173.pngWatermarked link

I quickly offered  F12 Dafa to open the console, and found such an interface among many requests, which actually used the unique ID above.

https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=6820792802394262795

a5d7d27965ac0d2828d5910007460af7.pngWhat is more surprising is that the data returned by the interface is called a detailed one, including author information, audio address, video address, and floor plan. But there is no video without watermark  URL. 48aa15e22ea53abe9999eb50842d6507.pngI only found a video URLwith a watermark  . I was a little bit lost. I looked at this address again and found that it was  wm a bit like the name of my project. Isn’t it watermark the abbreviation of the watermark?

https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f030000bqk54kg2saj3lso3oh20&ratio=720p&line=0

51e664a0acf2e7787495c01c71a9c7e2.pngIt seemed that I saw a glimmer of hope again, so I quickly modified URLit and tried it again in the browser. As expected, there was no watermark.

https://aweme.snssdk.com/aweme/v1/play/?video_id=v0200f030000bqk54kg2saj3lso3oh20&ratio=720p&line=0

9cd76f76e1cb1c899ead13cbcbb5e11a.pngOnly then did I find that Douyin is 去水印 simply touching, hahaha~

Practice

Now that the principles are clear, the rest is to implement the functions step by step. The principles seem to be quite simple, but there are still a little pitfalls in the implementation, which wastes a lot of time.

The realization process has only three simple steps:

  • 1. Filter out the short video connection from the input box
  • 2. The short connection is transmitted to the backend to parse the video without watermark URL
  • 3. The video is  URLdelivered to the front end for preview and download

There is no difficulty in the back-end, just step by step to analyze the real video according to the above analysis process  URL .

Note  : The addresses we want URLare all URL after the current short connection is redirected URL. Some links on Douyin do not support browser access, so you have to manually modify the  User-agent attributes to simulate mobile terminal access.

/**
* @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 "";
    }

Below is the complete back-end implementation, you can see that the amount of code is very small.

/**
 * @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);
    }
}

The front-end implementation is also relatively simple, and the video URL preview and download parsed by the back-end will be OK.

f81824e78176e5ce8f9e358625926a95.pngInsert picture description here

In order to realize it quickly, I used an JQueryold antique . People my age still have a deep feeling for it, and I UI use the frame  layer.js. The source code will be shared with everyone, so I won’t post them all.

$.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);
    }
})
})

Note : We quote the resources of other websites in our own website URL. Because they are not under the same domain name referrer , we usually encounter anti-theft interception of third-party websites. Therefore, if you want to access the third-party resources normally, you must hide the requested one referrer, set in the page The following parameters.

 <!-- 解决访问视频url 请求403异常 -->
 <meta name="referrer" content="no-referrer"/>

I also did a simple adaptation of the mobile terminal. The style looks good, but the function is a bit unsatisfactory to use, and I am doing optimization later.

eeac9db346d066a8d2864935d44fb24f.pngInsert picture description here

to sum up

A lot of things are like this. I always feel unfathomable before I study it seriously, but once I get into the essence of technology, I start to laugh at how stupid I was before, and sometimes I check that layer of window paper when I understand it or not.



Guess you like

Origin blog.51cto.com/14989525/2547189