快手分享链接,实战解析无水印视频源码

java 249 2019-06-06 07:52

 

package blog.rs1314.cn.test;

import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.script.ScriptException;


import blog.rs1314.cn.kuaishou.*;
import org.json.JSONArray;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class KuaiShouTest {
    public static void main(String[] args) throws IOException, ScriptException {
        long time = new Date().getTime();
        long nextPageTime = KuaiShouNextPage.getNextPageTime(time);
        KuaishouUserVo inputClientUrl = inputClientUrl("http://www.gifshow.com/s/6vyyITXo",0,time,nextPageTime);
       List userVideoList = inputClientUrl.getUserVideoList();
       System.out.println(userVideoList.size());
      ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 4, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10000), Executors.defaultThreadFactory());

        for(int j=0;j                 KuaiShou kuaiShou = userVideoList.get(j);
                executor.execute(new ThreadLoadKuaiShouData(kuaiShou));

        }

     executor.shutdown();

    }


    /**
     * 解析json得到该用户的List
     *
     * @param kuaishouUserVo
     */
    private static List getVideoList(KuaishouUserVo kuaishouUserVo) {

        KuaiShou kuaiShou = null;
        String readVideoPlayUrl = kuaishouUserVo.getReadVideoPlayUrl();
        JSONObject jsonObject = new JSONObject(readVideoPlayUrl);
        System.out.println(jsonObject);
        JSONArray feeds = jsonObject.getJSONArray("feeds");

        int length = feeds.length();
        List kuaiShouList = new ArrayList(length);
        for (int j = 0; j < length; j++) {
            kuaiShou = new blog.rs1314.cn.kuaishou.KuaiShou();
            try {
                JSONObject jsonObject1 = feeds.getJSONObject(j);


                //无水印频地址
                JSONArray main_mv_urls = jsonObject1.getJSONArray("main_mv_urls");
                JSONObject jsonObject2 = main_mv_urls.getJSONObject(0);
                String videoUrl = jsonObject2.getString("url");
                kuaiShou.setVideoUrl(videoUrl);
                //share_info  ("userId=3xwvjr74prbhz9s&photoId=3xfvvjb92hqpgdq",)
                String share_info = jsonObject1.getString("share_info");
                kuaiShou.setShare_info(share_info);

                String photoId = String.valueOf(jsonObject1.get("photo_id"));
                kuaiShou.setPhotoId(photoId);

                //视频名称
                String videoName = jsonObject1.getString("caption");
                videoName = videoName.replaceAll("\n", "").replaceAll(" ", "");
                kuaiShou.setVideoName(videoName);
            }catch (Exception e){}
            kuaiShouList.add(kuaiShou);
        }
        return kuaiShouList;
    }


    /**
     * 获取真实无水印视频地址json
     *
     * @param kuaishouUserVo
     * @return
     */
    private static String getReadVideoPlayUrl(KuaishouUserVo kuaishouUserVo) {
        Map sigUrlamap = kuaishouUserVo.getSigUrl();
        String queryStringUrl = sigUrlamap.get(QUERYSTRING);
        String bodyString = sigUrlamap.get(BODYSTRING);


        OkHttpClient okHttpClient = new OkHttpClient();

        FormBody.Builder requestBody = new FormBody.Builder();
        Map params = getMapFromStr(bodyString);
        Set keySet = params.keySet();
        for (String key : keySet) {
            String value = params.get(key);
            requestBody.add(key, value);
        }
        FormBody formBody = requestBody.build();


        Request request = new Request.Builder()
                .url(READURL + queryStringUrl)
                .post(formBody)
                .addHeader("Cookie", "token=988045ae46624450873917df582dfd43-1355462031")
                .addHeader("User-Agent", "kwai-android")
                .addHeader("Connection", "keep-alive")
                .addHeader("Accept-Language", "zh-cn")
                .addHeader("X-REQUESTID", randomRequestId())
                .addHeader("Content-Type", "application/x-www-form-urlencoded")
                .addHeader("Host", "api.ksapisrv.com")
                .build();
        Call call = okHttpClient.newCall(request);

        try {
            Response response = call.execute();
            return response.body().string();

        } catch (IOException e) {
            throw new RuntimeException("地址错误或者获取失败,联系Q群号414572608");
        }

    }


    /**
     * 第二步
     * 1. 用户输入的分享地址 ,获取重定向后的地址
     * 2. 获取用户加密id和加密后作品id
     * 3. 获取真实的用户id
     * 4. 得到sig后的请求连接,post请求
     * 5.获取真实无水印视频地址json
     * 6.获取List
     */
    private static KuaishouUserVo inputClientUrl(String url,int temp,long time,long nexttime) {
        KuaishouUserVo kuaishouUserVo = new KuaishouUserVo();

        try {
            //用户输入的分享地址 ,获取重定向后的地址
            String redirectUrl = new OkHttpClient().newCall(new Request.Builder().url(url).build()).execute().request().url().toString();
            redirectUrl = redirectUrl.substring(0, redirectUrl.indexOf("?"));
            //获取用户加密id和加密后作品id
            String regex = "https://live.kuaishou.com/u/";
            redirectUrl = redirectUrl.substring(redirectUrl.indexOf(regex) + regex.length());
            String[] split = redirectUrl.split("/");
            kuaishouUserVo.setUserIdJiaMi(split[0]);
            kuaishouUserVo.setPhotoId(split[1]);
            //获取真实的用户id
            kuaishouUserVo.setUserId(getUserId(split[0]));
            if(temp ==0){
                //得到sig后的请求连接,post请求
                Map sigUrl = getSigUrl(kuaishouUserVo.getUserId());
                kuaishouUserVo.setSigUrl(sigUrl);
            }else{

                Map sigUrl = getSigUrl(kuaishouUserVo.getUserId(),time,1,nexttime);
                kuaishouUserVo.setSigUrl(sigUrl);
            }

            //获取真实无水印视频地址json
            String readVideoPlayUrl = getReadVideoPlayUrl(kuaishouUserVo);
            kuaishouUserVo.setReadVideoPlayUrl(readVideoPlayUrl);
            //获取list
            List videoList = getVideoList(kuaishouUserVo);
            kuaishouUserVo.setUserVideoList(videoList);


            return kuaishouUserVo;
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("地址错误或者获取失败,联系Q群号414572608");
        }
    }


    /**
     * 第一步:: 设置存活时间   token   建议60分钟请求一次
     *
     * @throws IOException
     */
    private static void setttingLiveTime() {

        String url = "http://api.ksapisrv.com/rest/n/hybrid/version?mod=HUAWEI%28COL-AL10%29&appver=6.4.1.9151&isp=CMCC&lon=0&language=zh-cn&sys=ANDROID_9&__NStokensig=30384a09fe4d364d48a9be9f182f80e76e964f870fedbd537a7a009ecd5dd60d&max_memory=384&ud=1355462031&sig=9c303bd81cc2c0575cecb7bc385c89c5&client_key=3c2cd3f3&oc=HUAWEI_KWAI&net=WIFI&lat=0&app=0&kpf=ANDROID_PHONE&ver=6.4&c=HUAWEI_KWAI&os=android&ftt=&kpn=KUAISHOU&token=988045ae46624450873917df582dfd43-1355462031&country_code=cn&hotfix_ver=&did_gt=1557994638922&iuid=&did=ANDROID_03c600e64ee0e3a7";
        Request build = new Request.Builder().url(url).addHeader("Cookie", "token=988045ae46624450873917df582dfd43-1355462031")
                .addHeader("User-Agent", "kwai-android")
                .addHeader("Connection", "keep-alive")
                .addHeader("Accept-Language", "zh-cn")
                .addHeader("X-REQUESTID", randomRequestId())
                .addHeader("Host", "api.ksapisrv.com")
                .build();

        String html = "";
        try {
            html = new OkHttpClient().newCall(build).execute().body().string();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println(html);


    }

    /**
     * 随机请求id  //范围是   436650000 - 436669999
     *
     * @return
     */
    private static String randomRequestId() {

        int temp = 436669999 - 436650000;

        int nextInt = new Random().nextInt(temp) + 436650000;
        return String.valueOf(nextInt);
    }


    /**
     * https://live.kuaishou.com/u/3xwvjr74prbhz9s
     * 获取真实的用户id
     *
     * @param userIdjiaMi 3xwvjr74prbhz9s
     * @return
     */
    public static String getUserId(String userIdjiaMi) {
        String url = "https://live.kuaishou.com/u/" + userIdjiaMi;
        String temp = "";
        try {
            String html = new OkHttpClient().newCall(new Request.Builder().url(url).build()).execute().body().string();
            Document parse = Jsoup.parse(html);

            Elements eles = parse.getElementsByTag("script");
            for (Element ele : eles) {  //configModel
                String script = ele.toString();
                if (script.indexOf("configModel") > -1) {
                    script = script.substring(script.indexOf("liveDetailModel") + 18, script.lastIndexOf("webSocketInfo") + 18);
                    JSONObject jsonObject = new JSONObject(script);

                    jsonObject = jsonObject.getJSONObject("user");
                    Object object = jsonObject.get("userId");

                    temp = String.valueOf(object);
                }
            }

            return temp;
        } catch (IOException e) {
            throw new RuntimeException("地址错误或者获取失败,联系Q群号414572608");
        }


    }


    /**
     * 获取签名后的请求连接
     *
     * @param userid 真实的用户id    post请求
     * @return
     */
    public static Map getSigUrl(String userid) {
        long time = new Date().getTime();

        return getSigUrl(userid,time,0,0);
    }


    public static Map getSigUrl(String userid,long time,int temp,long nexttime) {
       if(temp == 0){
           Map sig = getSig(userid, time, 30);

           String genSignature = genSignature(getMapFromStr(sig.get(SIGSTRING)), FANS_SALT);
           sig = getSigUrlT(userid, time, 30, genSignature);
           return sig;
       }else{
           Map sig = getSignextPage(userid, time, 30,nexttime);

           String genSignature = genSignature(getMapFromStr(sig.get(SIGSTRING)), FANS_SALT);
           sig = getSigUrlT(userid, time, 30, genSignature);
           return sig;
       }
    }


    /**
     * Post请求 异步
     * 使用 Callback 回调可返回子线程中获得的网络数据
     *
     * @param url
     * @param params 参数
     */
    public static void httpPost(final String url, final Map params, final Callback callback) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                OkHttpClient okHttpClient = new OkHttpClient();
                FormBody.Builder formBodyBuilder = new FormBody.Builder();
                Set keySet = params.keySet();
                for (String key : keySet) {
                    String value = params.get(key);
                    formBodyBuilder.add(key, value);
                }
                FormBody formBody = formBodyBuilder.build();
                Request request = new Request
                        .Builder()
                        .post(formBody)
                        .url(url)
                        .build();
                //Response response = null;
                okHttpClient.newCall(request).enqueue(callback);
            }
        }).start();
    }


    public static String genSignature(Map params, String salt) {
        if (params == null) {
            return null;
        }
        String sign = "";
        StringBuffer sb = new StringBuffer();
        try {
            // 1. 字典升序排序
            SortedMap sortedMap = new TreeMap<>(params);
            // 2. 拼按URL键值对
            Set keySet = sortedMap.keySet();
            for (String key : keySet) {
                //sign不参与算法
                if (key.equals("sig") || key.equals("__NStokensig")) {
                    continue;
                }
                String value = sortedMap.get(key);
                sb.append(key + "=" + URLDecoder.decode(value, "UTF-8"));
            }
            String uriString = sb.toString();
            uriString = uriString + salt;
            //System.out.println("My String: \n" + uriString);
            // 3. MD5运算得到请求签名
            sign = MD5.md5(uriString);
            //System.out.println("My Sign:\n" +sign);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sign;
    }

    public static Map getMapFromStr(String str) {
        if (str == null || "".equalsIgnoreCase(str)) {
            return null;
        }
        String[] arr = str.split("\\&");
        Map map = new HashMap<>();
        for (String item : arr) {
            String[] itemArr = item.split("=", 2);
            map.put(itemArr[0], itemArr[1]);
        }
        return map;
    }

    private static Map getSig(String userid, long time, int size) {
        return getSigUrlT(userid, time, size, "001a0805a029a8a466f8492a37d077ae");
    }
    private static Map getSignextPage(String userid, long time, int size,long neexrtime) {
        return getSigUrlTnextPage(userid, time, size, "001a0805a029a8a466f8492a37d077ae",neexrtime);
    }


    private static Map getSigUrlTnextPage(String userid, long time, int size, String sig,long neexrtime) {
        String queryString = "app=0&kpf=ANDROID_PHONE&ver=6.4&c=HUAWEI_KWAI&mod=HUAWEI%28COL-AL10%29&appver=6.4.1.9151&ftt=&isp=CMCC&kpn=KUAISHOU&lon=0&language=zh-cn&sys=ANDROID_9&max_memory=384&ud=1355462031&country_code=cn&oc=HUAWEI_KWAI&hotfix_ver=&did_gt=" + time + "&iuid=&net=WIFI&did=ANDROID_03c600e64ee0e3a7&lat=0";
        String bodyString = "token=988045ae46624450873917df582dfd43-1355462031&user_id=" + userid + "&lang=zh&count=" + size + "&privacy=public&pcursor="+neexrtime+"&referer=1&browseType=1&sig=" + sig + "&client_key=3c2cd3f3&os=android&__NStokensig=8581c63e468fa7829def9cf79fdebae7fc8f15dd021aa68724928c86872dc554";

        String sigString = new StringBuilder().append(queryString).append("&").append(bodyString).toString();
        Map map = new HashMap();

        map.put(QUERYSTRING, queryString);
        map.put(BODYSTRING, bodyString);
        map.put(SIGSTRING, sigString);

        return map;


    }

    private static Map getSigUrlT(String userid, long time, int size, String sig) {
        String queryString = "app=0&kpf=ANDROID_PHONE&ver=6.4&c=HUAWEI_KWAI&mod=HUAWEI%28COL-AL10%29&appver=6.4.1.9151&ftt=&isp=CMCC&kpn=KUAISHOU&lon=0&language=zh-cn&sys=ANDROID_9&max_memory=384&ud=1355462031&country_code=cn&oc=HUAWEI_KWAI&hotfix_ver=&did_gt=" + time + "&iuid=&net=WIFI&did=ANDROID_03c600e64ee0e3a7&lat=0";
        String bodyString = "token=988045ae46624450873917df582dfd43-1355462031&user_id=" + userid + "&lang=zh&count=" + size + "&privacy=public&referer=1&browseType=1&sig=" + sig + "&client_key=3c2cd3f3&os=android&__NStokensig=8581c63e468fa7829def9cf79fdebae7fc8f15dd021aa68724928c86872dc554";

        String sigString = new StringBuilder().append(queryString).append("&").append(bodyString).toString();
        Map map = new HashMap();

        map.put(QUERYSTRING, queryString);
        map.put(BODYSTRING, bodyString);
        map.put(SIGSTRING, sigString);

        return map;


    }

    private static final String QUERYSTRING = "queryString";
    private static final String BODYSTRING = "bodyString";
    private static final String SIGSTRING = "sigString";
    private static final String FANS_SALT = "382700b563f4";
    private static final String READURL = "http://api.ksapisrv.com/rest/n/feed/profile2?";
}
 

文章评论