Android初学 抖音短视频无水印下载APP的实现

  • Post author:
  • Post category:其他



实现效果:

  1. 在抖音复制分享链接

    点击抖音分享复制分享链接
  2. 粘贴分享链接到App, 点击解析

    粘贴分享链接到App, 点击解析
  3. 点击

    去下载

    进入浏览器下载

    点击去下载进入浏览器下载



获取无水印视频链接

首先我们使用浏览器打开分享的链接


8.97 teO:/ 一起玩水吧 在这炽热的夏天%%蓝色治愈系 %%夏天 %%游泳 https://v.douyin.com/Y5SpHKD/ 复制此链接,打开Dou音搜索,直接观看视频!

然后打开控制台找到对应的视频, 右键检查可以找到视频的链接


https://www.douyin.com/aweme/v1/play/?video_id=v0200fg10000ca08sgbc77udtm7m06p0


F12查看视频原链接

然后在浏览器中打开此链接发现是没有水印的视频, 稍后下载的视频使用的是此链接.

打开此链接发现是没有水印的视频

通过测试其他分享的视频发现不同视频对应的video_id不同, 于是需要找到获取video_id的请求.


https://www.douyin.com/aweme/v1/play/?video_id=xxx


通过控制台将设备改成移动端设备, 点击分享的链接

https://v.douyin.com/Y5SpHKD/

, 这时有一条请求进入我们的视线:


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


在这里插入图片描述

该请求的响应有我们需要的video_id

该请求有一个参数

item_ids

, 此参数正是点击分享链接后重定向链接的一部分

在重定向链接中找到item_ids

因此我们只需要解析该链接就可以拿到item_ids


至此,

就得到了下载无水印视频的全过程。

  1. 根据

    https://v.douyin.com/Y5SpHKD/

    的重定向地址

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

    获取item_ids=7097830584419962125
  2. 根据

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

    的响应拿到vid
  3. 根据

    www.douyin.com/aweme/v1/play/?video_id=v0200fg10000ca08sgbc77udtm7m06p0

    下载视频



实现



model层

通过传入的分享链接, 获取无水印视频链接

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层



View层


源代码 + Apk



参考


  1. 重定向的链接在谷歌F12中看不到

  2. 认识Android中的MVP设计模式



版权声明:本文为qq_41359651原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。