java基礎(chǔ)欄目介紹去水印工具的方法。
相關(guān)學(xué)習(xí)推薦:java基礎(chǔ)
百因必有果
說(shuō)一下我為什么要做個(gè)抖音視頻去水印工具,其實(shí)是因?yàn)槲业纳车衽眩尤粍偽襼
有天晚上她在抖音看見(jiàn)一個(gè)非常具有 教育意義
的視頻,“男人疼媳婦就該承包全部家務(wù)活”,然后它就想把視頻下載下來(lái),分享到她的姐妹群交流 馭夫
心得。
可是大家都知道抖音下載的視頻是帶水印,作為一個(gè)重度強(qiáng)迫癥選手這是不被允許的,沒(méi)辦法那就找找有沒(méi)有去水印工具吧,找了一圈要不就是收費(fèi),要么下載不下來(lái),主上臉上的笑容也在逐漸消失。
我在邊上調(diào)侃了一句:也沒(méi)多難,要不我給你做一個(gè)!“你行嗎?” 然后投來(lái)了一個(gè)不屑的眼神。
哎呀!本來(lái)就開(kāi)個(gè)玩笑,居然說(shuō)我不行,這就不能忍了,我得證明給你看看!男人嘛,就受不了這話
先看下我做的去水印工具線上預(yù)覽效果: 47.93.6.5:8888/index
下邊和大家一起分析下做這個(gè)去水印工具的思路,很多人乍一聽(tīng) 去水印
,下意識(shí)的覺(jué)得是一種什么牛比的算法,其實(shí)這是一種假象~
刨根問(wèn)底
雖說(shuō)要爭(zhēng)口氣,可剛開(kāi)始做的時(shí)候我也真是一臉懵逼,因?yàn)楦静恢涝搹哪娜胧?,去水印什么原理啊?難不成我還要寫個(gè)算法?
找了一個(gè)抖音視頻的分享鏈接,一點(diǎn)點(diǎn)分析,不難發(fā)現(xiàn)這是個(gè)經(jīng)過(guò)處理的短鏈接,那這個(gè)短鏈接一定會(huì)重定向到真實(shí)的視頻地址 URL
。
https://v.douyin.com/JSkuhE4/
瀏覽器中輸入短鏈接得到了下邊這個(gè) URL
,以我的經(jīng)驗(yàn)判斷URL
中的 6820792802394262795
很有可能是視頻的唯一ID,而唯一ID通常用來(lái)作為獲取詳情接口的入?yún)ⅲズ賬 好像有點(diǎn)頭緒了。
https://www.iesdouyin.com/share/video/6820792802394262795/
趕緊祭出 F12
大法打開(kāi)控制臺(tái),在眾多請(qǐng)求中發(fā)現(xiàn)這么一個(gè)接口,它居然用到了上邊的唯一ID。
https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=6820792802394262795
更驚喜的是接口返回的數(shù)據(jù)那叫一個(gè)詳細(xì),作者信息、音頻地址、視頻地址、平面圖都有。但唯獨(dú)沒(méi)有無(wú)水印的視頻 URL
。
只找到一個(gè)有水印的視頻 URL
,有點(diǎn)小失落,我又看了看這個(gè)地址,發(fā)現(xiàn) wm
和我項(xiàng)目名有點(diǎn)像啊,不就是watermark
水印的縮寫嗎?
https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f030000bqk54kg2saj3lso3oh20&ratio=720p&line=0
好像又看到了一絲希望,我趕緊修改URL
在瀏覽器中又試了一下,果然真的沒(méi)水印了。
https://aweme.snssdk.com/aweme/v1/play/?video_id=v0200f030000bqk54kg2saj3lso3oh20&ratio=720p&line=0
到這才發(fā)現(xiàn)抖音去水印
簡(jiǎn)單的讓人感動(dòng),哈哈哈~
身體力行
既然原理都清晰了,剩下的就是一步一步實(shí)現(xiàn)功能了,原理看著挺簡(jiǎn)單的,但實(shí)現(xiàn)中還是遇到一點(diǎn)點(diǎn)小坑,浪費(fèi)了不少時(shí)間。
實(shí)現(xiàn)過(guò)程只有簡(jiǎn)單的三步:
- 1、從輸入框中過(guò)濾取出視頻短連接
- 2、短連接傳到后端解析出無(wú)水印的視頻
URL
- 3、視頻
URL
傳遞給前端預(yù)覽、下載
后端并沒(méi)有什么難度,一步一步按照上邊分析的流程解析真實(shí)視頻 URL
就可以了。
注意 :我們想得到的地址
URL
,都是當(dāng)前短連接URL
經(jīng)過(guò)重定向后的URL
。而抖音有些鏈接是不支持瀏覽器訪問(wèn)的,所以要手動(dòng)修改User-agent
屬性模擬移動(dòng)端訪問(wèn)才可以。
/** *?@param?url *?@author?xiaofu *?@description?獲取當(dāng)前鏈接重定向后的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");//模擬手機(jī)連接 ????????????conn.connect(); ????????????String?location?=?conn.getHeaderField("Location"); ????????????return?location; ????????}?catch?(Exception?e)?{ ????????????e.printStackTrace(); ????????} ????????return?""; ????}
下邊是完整的后端實(shí)現(xiàn),可以看到代碼量非常的少。
/** ?*?@author?xiaofu-公眾號(hào):程序員內(nèi)點(diǎn)事 ?*?@description?抖音無(wú)水印視頻下載 ?*?@date?2020/9/15?18:44 ?*/@Slf4j @Controllerpublic?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?解析抖音無(wú)水印視頻 ?????*?@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、拿到視頻對(duì)應(yīng)的?ItemId ?????????????*/ ????????????String?videoUrl?=?""; ????????????String?musicUrl?=?""; ????????????String?videoPic?=?""; ????????????String?desc?=?""; ????????????if?(!StringUtils.isEmpty(redirectUrl))?{ ????????????????/** ?????????????????*?3、用?ItemId?拿視頻的詳細(xì)信息,包括無(wú)水印視頻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、無(wú)水印視頻?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); ????}}
前端實(shí)現(xiàn)也比較簡(jiǎn)單,拿到后端解析出來(lái)的視頻URL
預(yù)覽播放、下載就OK了。
為快速實(shí)現(xiàn)我用了老古董JQuery
,我這個(gè)年紀(jì)的人對(duì)它感情還是很深厚的,UI
框架用的 layer.js
。源碼后邊會(huì)分享給大家,就不全貼出來(lái)了。
$.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:?`<p style="overflow:hidden;height: 580px;width: 350px;"><p><p 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></p><p 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')">復(fù)制鏈接</button></p><p class="popButton"><a href="###" rel="noopener nofollow noreferrer" onclick="downloadVideo('${rows['musicUrl']}','${rows['desc']}')"><button class="layui-btn-sm layui-btn">下載音頻</button></a></p><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></p></p>` ????????????????//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('錯(cuò)誤信息:'?+?error,?{ ????????????????title:?'異常', ????????????????skin:?'layui-layer-lan', ????????????????closeBtn:?0, ????????????????anim:?4?//動(dòng)畫類型 ????????????}); ????????????return?false; ????????} ????}, ????error:?function?(err)?{ ????????console.log(err); ????????layer.close(index); ????????$('.qsy-submit').attr('disabled',?false); ????}, ????done:?function?()?{ ????????layer.close(index); ????}})})
注意:我們?cè)谧约旱木W(wǎng)站中引用其它網(wǎng)站的資源
URL
,由于不在同一個(gè)域名下referrer
不同,通常會(huì)遇到三方網(wǎng)站的防盜鏈攔截,所以要想正常訪問(wèn)三方資源,必須要隱藏請(qǐng)求的referrer
,頁(yè)面中設(shè)置如下參數(shù)。
?<!-- 解決訪問(wèn)視頻url 請(qǐng)求403異常 --> ?<meta name="referrer" content="no-referrer"/>
還簡(jiǎn)單做了下移動(dòng)端適配,樣式看著還可以,但是功能使用起來(lái)有點(diǎn)差強(qiáng)人意,后邊在做優(yōu)化了。
總結(jié)
很多東西就是這樣,沒(méi)認(rèn)真研究之前總感覺(jué)深不可測(cè),可一旦接觸到技術(shù)的本質(zhì),又開(kāi)始笑自己之前好蠢,懂與不懂有時(shí)就查那么一層窗戶紙。
Atas ialah kandungan terperinci java程序員手寫一個(gè)抖音視頻去水印工具. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undress AI Tool
Gambar buka pakaian secara percuma

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Untuk mengendalikan transaksi JDBC dengan betul, anda mesti terlebih dahulu mematikan mod komit automatik, kemudian melakukan pelbagai operasi, dan akhirnya melakukan atau mengembalikan semula hasilnya; 1. Panggil Conn.SetAutOcommit (palsu) untuk memulakan transaksi; 2. Melaksanakan pelbagai operasi SQL, seperti memasukkan dan mengemaskini; 3. Panggil Conn.Commit () jika semua operasi berjaya, dan hubungi conn.rollback () jika pengecualian berlaku untuk memastikan konsistensi data; Pada masa yang sama, cuba-dengan-sumber harus digunakan untuk menguruskan sumber, mengendalikan pengecualian dengan betul dan menutup sambungan untuk mengelakkan kebocoran sambungan; Di samping itu, adalah disyorkan untuk menggunakan kolam sambungan dan menetapkan mata simpan untuk mencapai rollback separa, dan menyimpan urus niaga sesingkat mungkin untuk meningkatkan prestasi.

Gunakan kelas dalam pakej Java.Time untuk menggantikan kelas lama dan kelas kalendar; 2. Dapatkan tarikh dan masa semasa melalui LocalDate, LocalDateTime dan Tempatan Tempatan; 3. Buat tarikh dan masa tertentu menggunakan kaedah (); 4. Gunakan kaedah tambah/tolak untuk meningkatkan dan mengurangkan masa; 5. Gunakan zoneddatetime dan zonid untuk memproses zon waktu; 6. Format dan parse date string melalui DateTimeFormatter; 7. Gunakan segera untuk bersesuaian dengan jenis tarikh lama apabila perlu; pemprosesan tarikh di java moden harus memberi keutamaan untuk menggunakan java.timeapi, yang memberikan jelas, tidak berubah dan linear

Pra-formancetartuptimemoryusage, quarkusandmicronautleadduetocompile-timeprocessingandgraalvsupport, withquarkusoftenperforminglightbetterine serverless scenarios.tyvelopecosyste,

HTTP Log Middleware di GO boleh merakam kaedah permintaan, laluan, IP klien dan memakan masa. 1. Gunakan http.handlerfunc untuk membungkus pemproses, 2. Rekod waktu mula dan masa akhir sebelum dan selepas memanggil next.servehttp, 3. Dapatkan IP pelanggan sebenar melalui r.remoteaddr dan X-forward-for headers, 4. Gunakan log.printf untuk mengeluarkan log permintaan, 5. Kod sampel lengkap telah disahkan untuk dijalankan dan sesuai untuk memulakan projek kecil dan sederhana. Cadangan lanjutan termasuk menangkap kod status, menyokong log JSON dan meminta penjejakan ID.

Koleksi Sampah Java (GC) adalah mekanisme yang secara automatik menguruskan ingatan, yang mengurangkan risiko kebocoran ingatan dengan menuntut semula objek yang tidak dapat dicapai. 1.GC menghakimi kebolehcapaian objek dari objek akar (seperti pembolehubah stack, benang aktif, medan statik, dan lain -lain), dan objek yang tidak dapat dicapai ditandakan sebagai sampah. 2. Berdasarkan algoritma penandaan tanda, tandakan semua objek yang dapat dicapai dan objek yang tidak ditandai. 3. Mengamalkan strategi pengumpulan generasi: Generasi Baru (Eden, S0, S1) sering melaksanakan MinorGC; Orang tua melakukan kurang tetapi mengambil masa lebih lama untuk melakukan MajorGC; Metaspace Stores Metadata kelas. 4. JVM menyediakan pelbagai peranti GC: SerialGC sesuai untuk aplikasi kecil; ParallelGC meningkatkan throughput; CMS mengurangkan

Memilih jenis htmlinput yang betul dapat meningkatkan ketepatan data, meningkatkan pengalaman pengguna, dan meningkatkan kebolehgunaan. 1. Pilih jenis input yang sepadan mengikut jenis data, seperti teks, e -mel, tel, nombor dan tarikh, yang secara automatik boleh menyemak dan menyesuaikan diri dengan papan kekunci; 2. Gunakan HTML5 untuk menambah jenis baru seperti URL, Warna, Julat dan Carian, yang dapat memberikan kaedah interaksi yang lebih intuitif; 3. Gunakan pemegang tempat dan sifat -sifat yang diperlukan untuk meningkatkan kecekapan dan ketepatan pengisian bentuk, tetapi harus diperhatikan bahawa pemegang tempat tidak dapat menggantikan label.

GradleisthebetterChoiceFormostNewProjectSduetoitSsuperiorflexibility, Prestasi, danModernToolingSupport.1.Gradle'sGroovy/KOT lindslismoreconciseandexpressivethanmaven'sverbosexml.2.GradleOutPerformsMaveninBuildSpeedWithIncrementalcompilation, BuildCac

Defer digunakan untuk melaksanakan operasi tertentu sebelum fungsi pulangan, seperti sumber pembersihan; Parameter dinilai dengan serta-merta apabila menangguhkan, dan fungsi-fungsi dilaksanakan mengikut urutan terakhir (LIFO); 1. Pelbagai penahanan dilaksanakan dalam urutan terbalik pengisytiharan; 2. Biasanya digunakan untuk pembersihan yang selamat seperti penutupan fail; 3. Nilai pulangan yang dinamakan boleh diubah suai; 4. Ia akan dilaksanakan walaupun panik berlaku, sesuai untuk pemulihan; 5. Elakkan penyalahgunaan menangguhkan gelung untuk mengelakkan kebocoran sumber; Penggunaan yang betul boleh meningkatkan keselamatan kod dan kebolehbacaan.
