百因必有果

说一下我为什么要做个抖音视频去水印工具,其实是因为我的沙雕女友,她居然刚我~

有天晚上她在抖音看见一个非常具有 教育意义 的视频,“男人疼媳妇就该承包全部家务活”,然后它就想把视频下载下来,分享到她的姐妹群交流 驭夫 心得。

可是大家都知道抖音下载的视频是带水印,作为一个重度强迫症选手这是不被允许的,没办法那就找找有没有去水印工具吧,找了一圈要不就是收费,要么下载不下来,主上脸上的笑容也在逐渐消失。

我在边上调侃了一句:也没多难,要不我给你做一个!“你行吗?” 然后投来了一个不屑的眼神。

敢说我不行?

哎呀!本来就开个玩笑,居然说我不行,这就不能忍了,我得证明给你看看!男人嘛,就受不了这话

(建议用谷歌浏览器),工具线上预览效果:http://47.93.6.5:8888/index

去水印使用预览

下边和大家一起分析下做这个去水印工具的思路,很多人乍一听 去水印 ,下意识的觉得是一种什么牛比的算法,其实这是一种假象~

刨根问底

虽说要争口气,可刚开始做的时候我也真是一脸懵逼,因为根本不知道该从哪入手,去水印什么原理啊?难不成我还要写个算法?

找了一个抖音视频的分享链接,一点点分析,不难发现这是个经过处理的短链接,那这个短链接一定会重定向到真实的视频地址 URL

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

浏览器中输入短链接得到了下边这个 URL ,以我的经验判断URL中的 6820792802394262795 很有可能是视频的唯一ID,而唯一ID通常用来作为获取详情接口的入参,哎嘿~ 好像有点头绪了。

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

有水印的链接

赶紧祭出 F12 大法打开控制台,在众多请求中发现这么一个接口,它居然用到了上边的唯一ID。

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

更惊喜的是接口返回的数据那叫一个详细,作者信息、音频地址、视频地址、平面图都有。但唯独没有无水印的视频 URL只找到一个有水印的视频 URL,有点小失落,我又看了看这个地址,发现 wm 和我项目名有点像啊,不就是watermark 水印的缩写吗?

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

好像又看到了一丝希望,我赶紧修改URL在浏览器中又试了一下,果然真的没水印了。

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

到这才发现抖音去水印 简单的让人感动,哈哈哈~

身体力行

既然原理都清晰了,剩下的就是一步一步实现功能了,原理看着挺简单的,但实现中还是遇到一点点小坑,浪费了不少时间。

实现过程只有简单的三步:

  • 1、从输入框中过滤取出视频短连接

  • 2、短连接传到后端解析出无水印的视频 URL

  • 3、视频 URL传递给前端预览、下载

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

注意 :我们想得到的地址URL,都是当前短连接URL 经过重定向后的URL。而抖音有些链接是不支持浏览器访问的,所以要手动修改 User-agent 属性模拟移动端访问才可以。

/**
* @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")@ResponseBodypublic 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},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">下载视频</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',closeBtn: 0,anim: 4 //动画类型});return false;}},error: function (err) {console.log(err);layer.close(index);$('.qsy-submit').attr('disabled', false);},done: function () {layer.close(index);}
})
})

注意:我们在自己的网站中引用其它网站的资源URL,由于不在同一个域名下referrer 不同,通常会遇到三方网站的防盗链拦截,所以要想正常访问三方资源,必须要隐藏请求的referrer,页面中设置如下参数。

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

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

在这里插入图片描述

总结

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

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


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


往期推荐

JDK15正式发布,新增功能预览!

URL 去重的 6 种方案!(附详细代码)

图解|查找数组中最大值的5种方法!

关注下方二维码,收获更多干货!

一气之下,手撸了一个抖音去水印的工具!相关推荐

  1. 一个人竟然撸了一个抖音 App

    抖音短视频 App 火速爆红,没几年就成为了国民级 App.低成本的体验方式,不管是大爷大妈,还是刚会玩手机的小孩儿,都沉迷之中无法自拔. 今天推荐两个 GitHub 项目,都是移动端开发者开发的复制 ...

  2. 第二篇-用Flutter手撸一个抖音国内版,看看有多炫

    前言 继上一篇使用Flutter开发的抖音国际版 后再次撸一个国内版抖音,大部分功能已完成,主要是Flutter开发APP速度很爽,  先看下图 项目主要结构介绍 这次主要的改动在api.dart 及 ...

  3. 手写一个抖音视频去水印工具,千万别刚一个程序员

    百因必有果 说一下我为什么要做个抖音视频去水印工具,其实是因为我的沙雕女友,她居然刚我~ 有天晚上她在抖音看见一个非常具有 教育意义 的视频,"男人疼媳妇就该承包全部家务活",然后 ...

  4. 手写一个抖音视频去水印Java工具,千万别刚一个程序员

    关注公众号后台回复pay或mall获取实战项目资料+视频 百因必有果 说一下我为什么要做个抖音视频去水印工具,其实是因为我的沙雕女友,她居然刚我~ 有天晚上她在抖音看见一个非常具有 教育意义 的视频, ...

  5. 用Flutter手撸一个抖音国际版 看看有多炫

    肉眼品世界导读: 本文为启明星技术架构师社群作者投稿,字节跳动选择了flutter作为混合开发的语言,Flutter "一出生"就以"UI 漂亮.像素级可控.性能流畅.可 ...

  6. 从0开发小程序,一个月时间实现盈利!内附抖音去水印原理

    一.开发前奏 1.背景 近几年短视频行业的兴起,涌现出抖音快手等优秀的app,但是在app上发现优秀视频想要下载到本地时,又奈何总是全程有水印又末尾有平台独白,搜索众多app和小程序大部分要嘛广告众多 ...

  7. word无法打开请去应用商店_抖音去水印 | HTTP Catcher方法全解析

    果仁部落 长按二维码关注 前言 最近快捷指令抖音去水印规则已经失效,导致很多小伙伴前来询问,有一些小伙伴也提供了方法,但是因种种原因不能采纳,非常抱歉,不过今天小编为大家分享更好用的去水印方法,可在正 ...

  8. iOS快捷指令最全整理(支持iOS14),抖音去水印捷径快手去水印捷径

    收集整理一波iOS捷径库(使用方法见文末,支持iOS14),包括了大家最想要的抖音去水印捷径和快手去水印捷径.大家使用过程中如果发现有啥问题或者想实现什么快捷指令,关注微信公众号"云峰小罗& ...

  9. iOS12捷径(快捷指令),最新抖音去水印捷径,快手去水印捷径

    之前整理过一波很全(100多个)的iOS快捷指令:iOS12捷径最全整理(100多个捷径汇总),包括抖音视频下载,地图导航等,但是发现读者用得最多的还是抖音无水印下载和快手无水印下载这两个捷径. 因为 ...

最新文章

  1. 【怎样写代码】对象克隆 -- 原型模式(三):原型模式
  2. SSH之IDEA2017整合Struts2+Spring+Hibernate
  3. 使用MyBatis的Generator自动创建实体类和dao的接口与xml
  4. 1、MySQL约束概述
  5. c语言中用于判断ch是否是字符的表达式,最新C语言复习题集资料
  6. 01-Popover跳转
  7. Boost:分配服务的实例
  8. Connected to an idle instance问题的小小仇恨
  9. java log4j 异步_Log4j2异步日志之异步格式化
  10. Ubuntu安装完驱动后进不去界面
  11. 【SPOJ:FAVDICE】Favourite Dice(概率dp)
  12. 《图书管理系统》—需求分析报告
  13. hdu 5211 Mutiple
  14. MySQL之Explain
  15. Java串口通信读写串口导致程序崩溃问题
  16. java一系列图片加载_RxJava系列文章(一) - 网络图片加载水印一般写法
  17. Python 串级PID代码
  18. 河南大学计算机学院会搬到郑州吗,河南新增一所“重量级”本科大学,投资约12.8亿,当地考生有福了...
  19. 一个好的软件,除了给我们带来效率,更重要的是为我们带来了快乐!
  20. 400Gbps 网络面临的挑战

热门文章

  1. 最近刚完成某大学的图书馆个人阅读账单,中间遇到的难题想把总结记下来,下次再做类似的东西就有印象了,叮~
  2. opengl蓝宝书读书笔记七
  3. Docker Meetup 九城联动
  4. 如何完美实现Paxos算法成员组变更
  5. PBOOTCMS的伪静态规则设置方法
  6. Linux系统编程-文件的操作
  7. 不支持项目构面 java v1.7_在eclipse中运行maven项目的问题,未被识别为Java项目
  8. 1号店电商实时数据分析系统(持续更新,未完待续,每天一点点)
  9. 申请android11xColorOS,零时差适配安卓11!ColorOS 11升级公测版体验丝滑顺畅
  10. 金三银四的 Vue 面试准备