From 5a753108ba8b5208d57b23ce9cbe322bd846375e Mon Sep 17 00:00:00 2001 From: leospring <564892076@qq.com> Date: Wed, 22 Jan 2025 16:12:44 +0800 Subject: [PATCH] Create Living.java --- .../java/com/github/catvod/spider/Living.java | 220 ++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 app/src/main/java/com/github/catvod/spider/Living.java diff --git a/app/src/main/java/com/github/catvod/spider/Living.java b/app/src/main/java/com/github/catvod/spider/Living.java new file mode 100644 index 00000000..f6a5aedb --- /dev/null +++ b/app/src/main/java/com/github/catvod/spider/Living.java @@ -0,0 +1,220 @@ +package com.github.catvod.spider; + +import android.content.Context; +import android.text.TextUtils; +import android.util.Base64; + +import com.github.catvod.bean.Class; +import com.github.catvod.bean.Filter; +import com.github.catvod.bean.Result; +import com.github.catvod.bean.Vod; +import com.github.catvod.crawler.Spider; +import com.github.catvod.crawler.SpiderDebug; +import com.github.catvod.net.OkHttp; +import com.github.catvod.utils.LZString; +import com.github.catvod.utils.Util; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * @author leospring + * 聚合直播 + */ +public class Living extends Spider { + private String host = "https://lemonlive.deno.dev"; + private String cookie = ""; + @Override + public void init(Context context, String extend) throws Exception { + if (!TextUtils.isEmpty(extend)) { + host = extend; + } + } + + @Override + public String homeContent(boolean filter) throws Exception { + List classList = new ArrayList<>(); + LinkedHashMap> filters = new LinkedHashMap<>(); + + classList.add(new Class("huya", "虎牙")); + classList.add(new Class("douyu", "斗鱼")); + classList.add(new Class("douyin", "抖音")); + classList.add(new Class("bilibili", "哔哩哔哩")); + classList.add(new Class("cc", "网易CC")); + + List huyaFilterList = new ArrayList<>(); + List huyaVals = new ArrayList<>(); + huyaVals.add(new Filter.Value("网游", "1")); + huyaVals.add(new Filter.Value("手游", "3")); + huyaVals.add(new Filter.Value("娱乐", "8")); + huyaVals.add(new Filter.Value("单机", "2")); + huyaFilterList.add(new Filter("type", "分类", huyaVals)); + filters.put("huya", huyaFilterList); + + List douyuFilterList = new ArrayList<>(); + List douyuVals = new ArrayList<>(); + douyuVals.add(new Filter.Value("网游竞技", "PCgame")); + douyuVals.add(new Filter.Value("单机热游", "djry")); + douyuVals.add(new Filter.Value("手游休闲", "syxx")); + douyuVals.add(new Filter.Value("娱乐天地", "yl")); + douyuVals.add(new Filter.Value("颜值", "yz")); + douyuVals.add(new Filter.Value("科技文化", "kjwh")); + douyuVals.add(new Filter.Value("语言互动", "yp")); + douyuFilterList.add(new Filter("type", "分类", douyuVals)); + filters.put("douyu", douyuFilterList); + + List douyinFilterList = new ArrayList<>(); + List douyinVals = new ArrayList<>(); + douyinVals.add(new Filter.Value("竞技游戏", "2")); + douyinVals.add(new Filter.Value("射击游戏", "1")); + douyinVals.add(new Filter.Value("单机游戏", "3")); + douyinVals.add(new Filter.Value("棋牌游戏", "4")); + douyinVals.add(new Filter.Value("休闲益智", "5")); + douyinVals.add(new Filter.Value("角色扮演", "6")); + douyinVals.add(new Filter.Value("策略卡牌", "7")); + douyinVals.add(new Filter.Value("娱乐天地", "10000")); + douyinVals.add(new Filter.Value("科技文化", "10001")); + douyinFilterList.add(new Filter("type", "分类", douyinVals)); + filters.put("douyin", douyinFilterList); + + List biliFilterList = new ArrayList<>(); + List biliVals = new ArrayList<>(); + biliVals.add(new Filter.Value("网游", "2")); + biliVals.add(new Filter.Value("手游", "3")); + biliVals.add(new Filter.Value("单机游戏", "6")); + biliVals.add(new Filter.Value("娱乐", "1")); + biliVals.add(new Filter.Value("电台", "5")); + biliVals.add(new Filter.Value("虚拟主播", "9")); + biliVals.add(new Filter.Value("聊天室", "14")); + biliVals.add(new Filter.Value("生活", "10")); + biliVals.add(new Filter.Value("知识", "11")); + biliVals.add(new Filter.Value("赛事", "13")); + biliVals.add(new Filter.Value("互动玩法", "15")); + biliFilterList.add(new Filter("type", "分类", biliVals)); + filters.put("bilibili", biliFilterList); + + List ccFilterList = new ArrayList<>(); + List ccVals = new ArrayList<>(); + ccVals.add(new Filter.Value("网游", "1")); + ccVals.add(new Filter.Value("手游", "2")); + ccVals.add(new Filter.Value("竞技", "4")); + ccVals.add(new Filter.Value("综艺", "5")); + ccFilterList.add(new Filter("type", "分类", ccVals)); + filters.put("cc", ccFilterList); + return Result.string(classList, filters); + } + + @Override + public String categoryContent(String tid, String pg, boolean filter, HashMap extend) throws Exception { + if (!tid.contains("_")) { + String url = host + "/api/" + tid + "/getCategories"; + JSONObject json = request(url); + String type = extend.get("type"); + if (TextUtils.isEmpty(type)) type = json.optJSONArray("data").optJSONObject(0).optString("id"); + List vodList = new ArrayList<>(); + for (int i = 0; i < json.optJSONArray("data").length(); i++) { + JSONObject data = json.optJSONArray("data").optJSONObject(i); + if (type.equals(data.optString("id"))) { + for (int j = 0; j < data.optJSONArray("list").length(); j++) { + JSONObject item = data.optJSONArray("list").optJSONObject(j); + vodList.add(new Vod(tid + "_" + item.optString("cid"), item.optString("name"), item.optString("pic"),data.optString("name"), true)); + } + } + } + return Result.string(vodList); + } else { + String[] split = tid.split("_"); + String url = host + "/api/" + split[0] + "/getCategoryRooms?id=" + split[1] + "&pid=" + (split[0].equals("bilibili") ? "2":"1") + "&page=" + pg; + if (!TextUtils.isEmpty(cookie)) url = url + "&cookie=" + URLDecoder.decode(cookie, "UTF-8"); + JSONObject json = request(url); + if (!TextUtils.isEmpty(json.optJSONObject("data").optString("cookie"))) { + cookie = json.optJSONObject("data").optString("cookie"); + } + List vodList = new ArrayList<>(); + for (int i = 0; i < json.optJSONObject("data").optJSONArray("list").length(); i++) { + JSONObject data = json.optJSONObject("data").optJSONArray("list").optJSONObject(i); + vodList.add(new Vod(split[0] + "_" + data.optString("roomId"), data.optString("title"), data.optString("cover"), data.optString("nickname"), data.optString("online"))); + } + return Result.string(vodList); + } + } + + @Override + public String detailContent(List ids) throws Exception { + String[] split = ids.get(0).split("_"); + String url = host + "/api/" + split[0] + "/getRoomDetail?id=" + split[1]; + JSONObject json = request(url).optJSONObject("data"); + Vod vod = new Vod(); + vod.setVodId(json.optString("roomId")); + vod.setVodName(json.optString("title")); + vod.setVodArea(json.optString("online")); + vod.setVodDirector(json.optString("siteId")); + vod.setVodActor(json.optString("nickname")); + vod.setVodPic(json.optString("cover")); + vod.setVodContent(json.optString("url")); + vod.setTypeName(json.optString("category")); + JSONObject info = json.optJSONObject("info"); + String params = ""; + if (info != null) { + params = getHuyaParam(info.optString("name"), info.optString("code")); + } + List fromList = new ArrayList<>(); + List playList = new ArrayList<>(); + for (int i = 0; i < json.optJSONArray("stream").length(); i++) { + JSONObject data = json.optJSONArray("stream").optJSONObject(i); + fromList.add(data.optString("name")); + List nameUrls = new ArrayList<>(); + for (int j = 0; j < data.optJSONArray("lines").length(); j++) { + JSONObject urls = data.optJSONArray("lines").optJSONObject(j); + String playUrl = urls.optString("url") + params; + nameUrls.add(urls.optString("name") + "$" + playUrl); + } + playList.add(TextUtils.join("#", nameUrls)); + } + vod.setVodPlayFrom(TextUtils.join("$$$", fromList)); + vod.setVodPlayUrl(TextUtils.join("$$$", playList)); + return Result.string(vod); + } + + @Override + public String playerContent(String flag, String id, List vipFlags) throws Exception { + String url = id; + if (!url.startsWith("http")) url = "https:" + url; + return Result.get().url(url).toString(); + } + + private String getHuyaParam(String name, String code) throws UnsupportedEncodingException { + String N = "1063681129617"; + long currentTimeMillis = System.currentTimeMillis(); + String i = String.valueOf(currentTimeMillis % 10000000000L * 1000 + (long)(Math.random() * 4294967295L)); + String r = code.split("fs=")[1].split("&")[0]; + String s = Long.toHexString((currentTimeMillis / 1000) | 21600); + String f = String.valueOf(currentTimeMillis + Long.parseLong(N)); + String fmPart = code.split("fm=")[1].split("&")[0]; + String c = new String(Base64.decode(URLDecoder.decode(fmPart, "UTF-8"), Base64.NO_WRAP)).split("_")[0]; + String u = Util.MD5(f + "|tars_mp|102"); + return String.format("&wsSecret=%s&uuid=%s&wsTime=%s&uid=%s&seqid=%s&fs=%s&ctype=tars_mp&t=102&ver=1&sv=2401310321", + Util.MD5(c + "_" + N + "_" + name + "_" + u + "_" + s), + i, + s, + N, + f, + r); + } + + + private JSONObject request(String url) throws JSONException { + String str = OkHttp.string(url, Map.of("sec-fetch-site", "same-origin")); + String result = LZString.decompressFromBase64(str.replaceAll(" ", "")); + //SpiderDebug.log("result==" + result); + return new JSONObject(result); + } +}