Skip to content

Commit

Permalink
Merge pull request #135 from nICEnnnnnnnLee/dev
Browse files Browse the repository at this point in the history
update v2.29.0
  • Loading branch information
nICEnnnnnnnLee authored Aug 22, 2024
2 parents 21a7fed + b491b8d commit dc378e0
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 137 deletions.
4 changes: 1 addition & 3 deletions .github/release.info
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
* 优化:淘宝:兼容可能的json解析错误。
* 优化:虎牙:通过java代码来计算md5,而不是js。
* 修复:修改虎牙`ctype`、`t`参数,使之不在2分钟时就断开。 #132
* 修复:虎牙:参考[biliup/biliup](https://github.com/biliup/biliup/blob/7c703b936b7a79c134a7af45331d71c32de976a7/biliup/plugins/huya.py#L169),使用微信小程序的参数。 #134
4 changes: 2 additions & 2 deletions .github/release.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"tag_main": "2.28.0",
"tag_latest": "2.28.0"
"tag_main": "2.29.0",
"tag_latest": "2.29.0"
}
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ Go go go, Bilibili Pikachu!
| kuaishou | 2024/08/17 | `flv`清晰度可多选,必须要cookie(可以不登录,只需要过了拖拽验证即可) |
| douyin | 2024/08/17 | `flv`清晰度可多选,可不需要cookie。id为`https://live.douyin.com/1234567`后面的那串数字 |
| douyin2 | 2024/08/17 | 抖音的另一种解析方式,前者失败后可以尝试。`flv`清晰度可多选,必须要cookie(可以不登录,只需要过了拖拽验证即可)。id为`https://live.douyin.com/1234567`后面的那串数字,也可以直接输入短网址类型`https://v.douyin.com/xxxx` |
| huya | 2024/08/17 | `flv`清晰度可多选,可不需要cookie。开播后要过一阵才能检测到|
| huya2 | 2024/08/17 | 虎牙的另一种解析方式,只接受数字id,非数字的需要打开网页寻找(热度值左边)。`flv`清晰度可多选,可不需要cookie。 |
| huya | 2024/08/22 | `flv`清晰度可多选,可不需要cookie。只接受数字id,非数字的需要打开网页寻找(热度值左边)|
| huya2 | 2024/08/22 | 虎牙的另一种解析方式,只接受数字id,非数字的需要打开网页寻找(热度值左边)。`flv`清晰度可多选,可不需要cookie。 |
| taobao | 2023/09/17 | `flv`清晰度可多选,必须要cookie(先试一试不登录)。id建议首次使用类似`https://m.tb.cn/xxxx`的直播或者回访的分享链接,这时会输出回放m3u8链接和可用id,之后建议一直使用该id。当然,建议是使用相关m3u8下载器下载回放,而不是直接录制。 |
| acfun | 2023/02/22 | `flv`清晰度可多选,可不需要cookie |
| yy | 2022/10/09 | `flv`清晰度可多选,必须要cookie(可以不登录,只需要过了拖拽验证即可) |
Expand Down Expand Up @@ -319,6 +319,7 @@ or传入参数: qnPri=蓝光4M>蓝光
+ 使用[JSON.org](https://github.com/stleary/JSON-java)库做简单的Json解析[![](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/stleary/JSON-java/blob/master/LICENSE)
+ 使用[Crypto-js](https://github.com/brix/crypto-js)仿浏览器生成斗鱼直播录制token[![](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/brix/crypto-js/blob/develop/LICENSE)
+ 参考[HuyaSender](https://github.com/xyxyxiaoyan/HuyaSender)解析虎牙[TarsTup](https://github.com/TarsCloud/TarsTup)协议[![](https://img.shields.io/badge/license-Tencent%20Binary%20License-green.svg)](https://tencentdingdang.github.io/dmsdk/licenses/android-wup-sdk/LICENSE.txt)
+ 参考[biliup/biliup](https://github.com/biliup/biliup/blob/7c703b936b7a79c134a7af45331d71c32de976a7/biliup/plugins/huya.py#L169)修改query参数[![](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/biliup/biliup/blob/7c703b936b7a79c134a7af45331d71c32de976a7/LICENSE)

## :smile:LICENSE
```
Expand Down
2 changes: 2 additions & 0 deletions UPDATE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
## 更新
+ V2.29.0
* 修复:虎牙:参考[biliup/biliup](https://github.com/biliup/biliup/blob/7c703b936b7a79c134a7af45331d71c32de976a7/biliup/plugins/huya.py#L169),使用微信小程序的参数。 #134
+ V2.28.0
* 优化:淘宝:兼容可能的json解析错误。
* 优化:虎牙:通过java代码来计算md5,而不是js。
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>top.nicelee</groupId>
<artifactId>live-record</artifactId>
<version>2.28.0</version>
<version>2.29.0</version>
<name>iLiveRecord</name>
<description>B站、Acfun、斗鱼、虎牙、快手、抖音、淘宝直播录制</description>
<properties>
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/nicelee/bilibili/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

public class Main {

final static String version = "v2.28.0";
final static String version = "v2.29.0";
public static Thread thRecord;
public static Thread thMonitor;
public static Thread thCommand;
Expand Down
201 changes: 73 additions & 128 deletions src/main/java/nicelee/bilibili/live/impl/RoomDealerHuya.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
package nicelee.bilibili.live.impl;

import java.io.InputStream;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.json.JSONArray;
import org.json.JSONObject;
Expand Down Expand Up @@ -42,54 +36,28 @@ public RoomInfo getRoomInfo(String shortId) {
roomInfo.setShortId(shortId);
try {
// 获取基础信息
String basicInfoUrl = String.format("https://www.huya.com/%s", shortId);
String html = util.getContent(basicInfoUrl, headers.getCommonHeaders("www.huya.com"), null);

Pattern pJson = Pattern.compile("var TT_ROOM_DATA =(.*?); *var +TT");
Matcher matcher = pJson.matcher(html);
matcher.find();
JSONObject room = new JSONObject(matcher.group(1));
JSONObject all = getLiveObj(shortId);
JSONObject liveData = all.getJSONObject("liveData");
JSONObject profileInfo = all.getJSONObject("profileInfo");

// 直播状态 ON REPLAY
if ("ON".equals(room.getString("state"))) {
if ("ON".equals(all.getString("liveStatus"))) {
roomInfo.setLiveStatus(1);
} else {
roomInfo.setLiveStatus(0);
}

// 真实房间id
roomInfo.setRoomId(shortId);

roomInfo.setDescription(room.getString("introduction"));

// 房间主id
roomInfo.setUserId(room.optLong("profileRoom"));

pJson = Pattern.compile("var hyPlayerConfig = (.*?});");
matcher = pJson.matcher(html);
matcher.find();
// System.out.println(matcher.group(1));
JSONObject obj = new JSONObject(matcher.group(1));
roomInfo.setDescription(liveData.getString("introduction"));
roomInfo.setUserId(profileInfo.optLong("profileRoom"));
roomInfo.setUserName(profileInfo.getString("nick"));
roomInfo.setTitle(liveData.getString("roomName"));


if (roomInfo.getLiveStatus() == 1) {
JSONObject streamDetail = obj.getJSONObject("stream").getJSONArray("data").getJSONObject(0)
.getJSONArray("gameStreamInfoList").getJSONObject(0);
String url = getFlvUrlFromStreamDetail(streamDetail, "");
boolean urlIsValid = test(url, headers.getHeaders());
Logger.println("当前url可用性: " + urlIsValid);
if (!urlIsValid)
roomInfo.setLiveStatus(0);
}
if (roomInfo.getLiveStatus() == 1) {
// String stream = obj.getString("stream");
// stream = new String(Base64.getDecoder().decode(stream), "UTF-8");
// obj = new JSONObject(stream);
obj = obj.getJSONObject("stream");
// 房间主名称
JSONObject liveInfo = obj.getJSONArray("data").getJSONObject(0).getJSONObject("gameLiveInfo");
roomInfo.setUserName(liveInfo.getString("nick"));
roomInfo.setTitle(liveInfo.getString("roomName"));
JSONObject obj = all.getJSONObject("stream").getJSONObject("flv");
// 清晰度
JSONArray jArray = obj.getJSONArray("vMultiStreamInfo");
JSONArray jArray = obj.getJSONArray("rateArray");
String[] qn = new String[jArray.length()];
String[] qnDesc = new String[jArray.length()];
for (int i = 0; i < jArray.length(); i++) {
Expand Down Expand Up @@ -128,6 +96,14 @@ public RoomInfo getRoomInfo(String shortId) {
return roomInfo;
}

public JSONObject getLiveObj(String roomId) {
String basicInfoUrl = "https://mp.huya.com/cache.php?m=Live&do=profileRoom&roomid=" + roomId;
HashMap<String, String> map = headers.getCommonHeaders("www.huya.com");
String j = util.getContent(basicInfoUrl, map, null);
Logger.println(j);
return new JSONObject(j).getJSONObject("data");
}

/**
* 获取直播地址的下载链接
*
Expand All @@ -139,16 +115,8 @@ public RoomInfo getRoomInfo(String shortId) {
public String getLiveUrl(String roomId, String qn, Object... params) {
try {
// 获取基础信息
String basicInfoUrl = String.format("https://www.huya.com/%s", roomId);
HashMap<String, String> map = headers.getCommonHeaders("www.huya.com");
String html = util.getContent(basicInfoUrl, map, null);

Pattern pJson = Pattern.compile("var hyPlayerConfig *= *(.*?});");
Matcher matcher = pJson.matcher(html);
matcher.find();
JSONObject obj = new JSONObject(matcher.group(1)).getJSONObject("stream");
JSONObject streamDetail = null;
JSONArray cdns = obj.getJSONArray("data").getJSONObject(0).getJSONArray("gameStreamInfoList");
JSONArray cdns = getLiveObj(roomId).getJSONObject("stream").getJSONArray("baseSteamInfoList");
for (int i = 0; i < cdns.length(); i++) {
JSONObject cdn = cdns.getJSONObject(i);
// ali CDN 似乎坚持不到5min就会断掉
Expand Down Expand Up @@ -180,39 +148,42 @@ String getFlvUrlFromStreamDetail(JSONObject streamDetail, String qn) {
return url;
}

static String sv, platform, ctype, t, uaSuffix, ua, cdnType;
// static String sv, platform, ctype, t, uaSuffix, ua, cdnType;
static String sv, ctype, t, cdnType;
static {
cdnType = System.getProperty("huya.cdn", "TX");
sv = System.getProperty("huya.sv", "2408161057");
platform = System.getProperty("huya.platform", "adr");
uaSuffix = System.getProperty("huya.uaSuffix", "&huya"); // websocket minigame signalsd
switch (platform) {
case "addr":
t = "2";
break;
case "ios":
t = "3";
break;
case "mini_app":
t = "102";
break;
case "wap":
t = "103";
sv = "1.0.0";
break;
case "huya_liveshareh5":
platform = "liveshareh5";
t = "104";
break;
case "web":
t = "100";
break;
default:
t = System.getProperty("huya.plType", "2");
break;
}
ctype = "huya_" + platform;
ua = platform + "&" + sv + uaSuffix;
// platform = System.getProperty("huya.platform", "adr");
// uaSuffix = System.getProperty("huya.uaSuffix", "&huya"); // websocket minigame signalsd
// switch (platform) {
// case "adr":
// t = "2";
// break;
// case "ios":
// t = "3";
// break;
// case "mini_app":
// t = "102";
// break;
// case "wap":
// t = "103";
// sv = "1.0.0";
// break;
// case "huya_liveshareh5":
// platform = "liveshareh5";
// t = "104";
// break;
// case "web":
// t = "100";
// break;
// default:
// t = System.getProperty("huya.plType", "2");
// break;
// }
// ctype = "huya_" + platform;
// ua = platform + "&" + sv + uaSuffix;
ctype = System.getProperty("huya.force_ctype", "tars_mp");;
t = System.getProperty("huya.force_t", "102");
}

String genFlvAntiCode(String sStreamName, String sFlvAntiCode, String qn) {
Expand All @@ -228,6 +199,7 @@ String genFlvAntiCode(String sStreamName, String sFlvAntiCode, String qn) {
}
// 随机生成uid
long uid = 1462220000000L + new Random().nextInt(1145142333);
long convertUid = (uid << 8 | uid >> (32 - 8)) & 0xFFFFFFFF;
long currentTime = System.currentTimeMillis();
String wsTime = Long.toHexString(currentTime / 1000);
long seqid = uid + currentTime + 216000000L; // 216000000 = 30*1000*60*60 = 30h
Expand All @@ -239,16 +211,26 @@ String genFlvAntiCode(String sStreamName, String sFlvAntiCode, String qn) {
Logger.println(ctype);
// String oe = JSEngine.huyaTrans(String.join("|", "" + seqid, ctype, t));
String oe = md5(String.join("|", "" + seqid, ctype, t));
String r = fm.replace("$0", "" + uid).replace("$1", sStreamName).replace("$2", oe).replace("$3", wsTime);
String r = fm.replace("$0", "" + convertUid).replace("$1", sStreamName).replace("$2", oe).replace("$3",
wsTime);
String wsSecret = md5(r);
StringBuilder sb = new StringBuilder();
sb.append("wsSecret=").append(wsSecret).append("&wsTime=").append(wsTime).append("&seqid=").append(seqid)
.append("&ctype=").append(ctype).append("&ver=1&fs=").append(n.getOrDefault("fs", "")).append("&t=")
.append(t).append("&sphdcdn=").append(n.getOrDefault("sphdcdn", "")).append("&sphdDC=")
.append(n.getOrDefault("sphdDC", "")).append("&sphd=").append(n.getOrDefault("sphd", ""))
.append("&exsphd=").append(n.getOrDefault("exsphd", "")).append("&t=").append(t).append("&sv=")
.append(sv) // .append("&ratio=").append(qn)
.append("&dMod=mseh-32&sdkPcdn=1_1&u=").append(uid).append("&sdk_sid=").append(currentTime);
sb.append("wsSecret=").append(wsSecret)
.append("&wsTime=").append(wsTime)
.append("&seqid=").append(seqid)
.append("&ctype=").append(ctype)
.append("&t=").append(t)
.append("&ver=1&fs=").append(n.getOrDefault("fs", ""))
// .append("&sphdcdn=").append(n.getOrDefault("sphdcdn", "")).append("&sphdDC=")
// .append(n.getOrDefault("sphdDC", "")).append("&sphd=").append(n.getOrDefault("sphd", ""))
// .append("&exsphd=").append(n.getOrDefault("exsphd", ""))
// .append("&t=").append(t)
// .append("&dMod=mseh-32&sdkPcdn=1_1")
.append("&sv=").append(sv) // .append("&ratio=").append(qn)
.append("&uuid=").append(uid / 100) // 随便填的
.append("&codec=264")
.append("&u=").append(convertUid)
.append("&sdk_sid=").append(currentTime);
if (!"".equals(qn) && !"0".equals(qn)) {
sb.append("&ratio=").append(qn);
}
Expand Down Expand Up @@ -283,41 +265,4 @@ public void startRecord(String url, String fileName, String shortId) {
util.download(url, fileName + ".flv", mobile);
}

public boolean test(String url, HashMap<String, String> headers) {
InputStream inn = null;
try {
URL realUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
conn.setConnectTimeout(20000);
conn.setReadTimeout(120000);
for (Map.Entry<String, String> entry : headers.entrySet()) {
conn.setRequestProperty(entry.getKey(), entry.getValue());
// System.out.println(entry.getKey() + ":" + entry.getValue());
}
conn.connect();
// 获取所有响应头字段
// Map<String, List<String>> map = conn.getHeaderFields();
// // 遍历所有的响应头字段
// for (String key : map.keySet()) {
// System.out.println(key + "--->" + map.get(key));
// }
inn = conn.getInputStream();
int rspCode = conn.getResponseCode();
if (rspCode >= 200 && rspCode < 300)
return true;
else
return false;
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e);
return false;
} finally {
try {
if (inn != null) {
inn.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}

0 comments on commit dc378e0

Please sign in to comment.