Android初学 抖音短视频无水印下载APP的实现(抖音接口更换, 已不可用)

抖音接口更换, 已不可用

实现效果:

  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设计模式
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值