Realize the effect:
- Copy and share link on Douyin
- Paste the share link to the App, click Parse
- Click to download to enter the browser to download
Get the video link without watermark
First, we use the browser to open the shared link
Then open the console to find the corresponding video, right-click to check the link to find the video,
https://www.douyin.com/aweme/v1/play/?video_id=v0200fg10000ca08sgbc77udtm7m06p0
then open this link in the browser and find that it is a video without a watermark, and the video downloaded later uses this link.
By testing other shared videos, it is found that it is different The video_id corresponding to the video is different, so we need to find the request to get the video_id.
https://www.douyin.com/aweme/v1/play/?video_id=xxx
Change the device to a mobile device through the console, click the link to share https://v.douyin.com/Y5SpHKD/
, and then a request comes into our sight:
https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=7097830584419962125
the response of the request has the video_id we need
. The request has a parameter item_ids
, which is part of the redirect link after clicking the share link
, so we only need to parse the link to get item_ids
So far, you have obtained the whole process of downloading the video without watermark.
- Obtain item_ids=7097830584419962125 according to
https://v.douyin.com/Y5SpHKD/
the redirection addresshttps://www.iesdouyin.com/share/video/7097830584419962125
https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=7097830584419962125
Get the vid according to the response- According to
www.douyin.com/aweme/v1/play/?video_id=v0200fg10000ca08sgbc77udtm7m06p0
download video
accomplish
model layer
Through the incoming sharing link, get the video link without watermark
public class DouyinDownloadModel {
private final OkHttpClient mOkHttpClient = new OkHttpClient();
public void download(InputBean inputBean, DownloadListener downloadListener) {
Request.Builder builder = new Request.Builder().get().url(inputBean.getShareUrl());
requestInit(builder);
Request request = builder.build();
mOkHttpClient.newBuilder()
.followRedirects(false).build().newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
downloadListener.fail();
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) {
if (response.code() == 302) {
String location = response.header("location");
if (location != null) {
System.out.println(location);
String itemIds = parseItemIds(location);
if (!TextUtils.isEmpty(itemIds)) {
getVidByItemIds(itemIds, new GetVidRequestListener() {
@Override
public void success(JsonRootBean bean) {
Item_list item_list = bean.getItem_list().get(0);
String vid = item_list.getVideo().getVid();
String url = "https://www.douyin.com/aweme/v1/play/?video_id="
+ vid;
DownLoadResult downLoadResult = new DownLoadResult();
downLoadResult.setVideoUrl(url)
.setNickName(item_list.getAuthor().getNickname())
.setVideoDesc(item_list.getDesc());
downloadListener.success(downLoadResult);
}
@Override
public void fail() {
downloadListener.fail();
}
});
} else {
downloadListener.fail();
}
}
}
}
});
}
public void getVidByItemIds(String itemIds, GetVidRequestListener getVidRequestListener) {
String url = "https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=" + itemIds;
System.out.println(url);
Request.Builder builder = new Request.Builder().get().url(url);
requestInit(builder);
Request request = builder.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
getVidRequestListener.fail();
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response)
throws IOException {
if (response.code() == 200) {
response.body();
String jsonString = response.body().string();
Gson gson = new Gson();
System.out.println(jsonString);
JsonRootBean jsonRootBean = gson.fromJson(jsonString, JsonRootBean.class);
System.out.println(jsonRootBean.getItem_list().get(0).getVideo().getVid());
getVidRequestListener.success(jsonRootBean);
}
}
});
}
public interface DownloadListener {
void success(DownLoadResult downLoadResult);
void fail();
void onProgress(int progress);
}
interface GetVidRequestListener {
void success(JsonRootBean bean);
void fail();
}
public void requestInit(Request.Builder builder) {
builder.addHeader("user-agent",
"Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 "
+ "(KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/101.0.4951.41");
}
public String parseItemIds(String text) {
String regex = "\\d{19}";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(text);
if (m.find()) {
return m.group();
}
return null;
}
}
Presenter layer
slightly
View layer
slightly