Every cause brings fruit

Talk about why I want to make a video to watermark tool, in fact, because of my sand carving girlfriend, she actually just me ~

One night she saw an educational video on Douyin, “If a man loves his wife, he should do all the housework.” She decided to download the video and share it with her sister group to exchange tips on how to be a good husband.

However, we all know that the video douyin downloaded is watermarked. As a player with severe obsessive-compulsive disorder, this is not allowed. If there is no way, let’s look for a watermarking tool.

I joked at the edge: it’s not too hard, or I’ll make one for you! “Are you good?” Then he gave me a disdainful look.

Oh dear! It was just a joke. I can’t stand it. I have to prove it to you! Men, they can’t stand that

To look at the first I go to watermarking tools online preview of: http://47.93.6.5:8888/index

Below and we analyze the idea of doing this tool to watermark, many people at first listen to watermark, subconsciously think is a kind of what the algorithm, in fact, this is a kind of illusion ~

warren

Although to contend tone, can just start to do when I was really a face meng force, because I do not know where to start from, to watermark what principle ah? Do I have to write an algorithm?

After a bit of analysis, it is not difficult to find that this is a short link that has been processed. Then this short link will definitely redirect to the real video URL.

https://v.douyin.com/JSkuhE4/
Copy the code

In my experience, 6820792802394262795 in the URL is likely to be the unique ID of the video, and the unique ID is usually used as the input parameter of the interface to obtain details. Hey hey ~ seems to have some ideas.

https://www.iesdouyin.com/share/video/6820792802394262795/
Copy the code

I opened the console in F12 and found an interface that used the unique ID.

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

More surprising is the interface returned data that is called a detailed, author information, audio address, video address, plan have. But there were no watermarked videosURL.I only found one video that was watermarkedURL, a little lost, I looked at the address, foundwmIt’s kind of like the name of my project. It’swatermarkShort for watermark?

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

As if to see a glimmer of hope, I quickly modifyURLIn the browser to try again, as expected really no watermark.

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

That’s when TIk Tok was discoveredGo to the watermarkSimple and touching, ha ha ha ~

physically

Now that the principle is clear, the rest is to implement the function step by step, the principle looks very simple, but the implementation is still encountered a little pit, wasted a lot of time.

The implementation process has three simple steps:

  • 1. Filter out the short video link from the input box
  • 2, short connection to the back end to parse the video without watermarkURL
  • 3, videoURLPass to the front end preview, download

The backend is not difficult, step by step according to the above analysis of the process of parsing the real video URL can be.

Note: the URL we want to obtain is the URL of the current short link URL after being redirected. However, some tiktok links do not support browser access, so you need to manually modify user-Agent attributes to simulate mobile access.

/ * * *@param url
* @author xiaofu
* @description Gets the redirected URL * of the current link@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");// Simulate cell phone connection
            conn.connect();
            String location = conn.getHeaderField("Location");
            return location;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
Copy the code

Below is the complete back-end implementation, and you can see how little code there is.

/ * * *@author xiaofu- Public number: programmer internal point *@description Douyin watermarked video download *@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 Parse Douyin watermarked video *@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, the short connection redirected URL */
            String redirectUrl = CommonUtils.getLocation(url);

            /** * 2, ItemId */
            String videoUrl = "";
            String musicUrl = "";
            String videoPic = "";
            String desc = "";
            if(! StringUtils.isEmpty(redirectUrl)) {/** ** ** ** ** ** ** ** ** ** ** ** ** *
                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);
                /** ** /
                videoUrl = dyResult.getItem_list().get(0)
                        .getVideo().getPlay_addr().getUrl_list().get(0)
                        .replace("playwm"."play");
                String videoRedirectUrl = CommonUtils.getLocation(videoUrl);
                dyDto.setVideoUrl(videoRedirectUrl);
                /** **
                musicUrl = dyResult.getItem_list().get(0).getMusic().getPlay_url().getUri();
                dyDto.setMusicUrl(musicUrl);
                /** ** /
                videoPic = dyResult.getItem_list().get(0).getVideo().getDynamic_cover().getUrl_list().get(0);
                dyDto.setVideoPic(videoPic);
                /** ** /
                desc = dyResult.getItem_list().get(0).getDesc(); dyDto.setDesc(desc); }}catch (Exception e) {
            log.error("Watermarking exception {}", e);
        }
        return JSON.toJSONString(dyDto); }}Copy the code

Front-end implementation is also relatively simple, get the back end of the resolution of the video URL preview play, download OK.

For quick implementation I used the old JQuery, which people of my age still have a strong affection for, and the LAYer.js UI framework. Source code behind will be shared with you, not all posted out.

$.ajax({
    url: '/parseVideoUrl'.type: 'POST'.data: {"url": link},
    success: function (data) {$('.qsy-submit').attr('disabled'.false);
        try {
            var rows = JSON.parse(data);
            layer.close(index);
            layer.open({
                type: 1.title: false.closeBtn: 1.shadeClose: true.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" id="videourl" cols="1" rows="1" style="height:0; width:0; position: absolute;" >${rows['videoUrl']}</textarea><button class="layui-btn-sm layui-bbg-blue layui-bTN "onclick="copy('videourl')" class="popButton"><a href="###" rel="noopener nofollow noreferrer" onclick="downloadVideo('${rows['musicUrl']}', '${rows['desc']}</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 message :' + error, {
                title: 'abnormal'.skin: 'layui-layer-lan'.closeBtn: 0.anim: 4 // Animation type
            });
            return false; }},error: function (err) {
        console.log(err);
        layer.close(index);
        $('.qsy-submit').attr('disabled'.false);
    },
    done: function () { layer.close(index); }})})Copy the code

Note: We refer to the resource URL of other websites in our own website. Since the referrer is different under the same domain name, we usually encounter anti-theft chain interception of the third party website. Therefore, in order to access the third party resources normally, we must hide the requested referrer, and set the following parameters in the page.

<! Resolve video URL requests403Exception - ><meta name="referrer" content="no-referrer"/>
Copy the code

Also do a simple mobile adaptation, the style looks ok, but the use of the function is a little unsatisfactory, in the back to do optimization.

conclusion

Many things are like this. They always feel unfathomable before they are studied carefully. However, once they get into contact with the essence of technology, they start to laugh at their stupidity before.

Well today to this, the source of this article in my public number [programmers within the point] reply [source] self


I sorted out hundreds of technical e-books and gave them to my friends. Pay attention to the public number reply [666] to get yourself. I set up a technology exchange group with some friends to discuss technology and share technical information, aiming to learn and progress together. If you are interested, please join us!