From 03c4c45e84ed553e891fbc60b941239369cc86e2 Mon Sep 17 00:00:00 2001
From: My-Responsitories <107370289+My-Responsitories@users.noreply.github.com>
Date: Wed, 17 Jan 2024 13:17:32 +0800
Subject: [PATCH] fix app subtitle download
---
BBDown.Core/APP/Response/dmviewreply.proto | 2 +-
BBDown.Core/AppHelper.cs | 31 +--------
BBDown.Core/Util/HTTPUtil.cs | 38 ++++++++---
BBDown.Core/Util/SubUtil.cs | 77 +++++++++++-----------
4 files changed, 70 insertions(+), 78 deletions(-)
diff --git a/BBDown.Core/APP/Response/dmviewreply.proto b/BBDown.Core/APP/Response/dmviewreply.proto
index eb6e73940..35362bd22 100644
--- a/BBDown.Core/APP/Response/dmviewreply.proto
+++ b/BBDown.Core/APP/Response/dmviewreply.proto
@@ -26,7 +26,7 @@ message VideoMask {
message VideoSubtitle {
optional string lan = 1;
optional string lanDoc = 2;
- optional SubtitleItem subtitles = 3;
+ repeated SubtitleItem subtitles = 3;
}
diff --git a/BBDown.Core/AppHelper.cs b/BBDown.Core/AppHelper.cs
index 35a310947..9b84704f4 100644
--- a/BBDown.Core/AppHelper.cs
+++ b/BBDown.Core/AppHelper.cs
@@ -3,9 +3,9 @@
using System.Buffers.Binary;
using System.IO.Compression;
using System.Linq;
-using System.Net.Http.Headers;
using System.Text.Json;
using System.Text.Json.Serialization;
+using static BBDown.Core.Util.HTTPUtil;
using static BBDown.Core.Logger;
namespace BBDown.Core
@@ -322,7 +322,7 @@ private static string GenerateFawkesReqBin()
///
///
/// 字节流
- private static byte[] ReadMessage(byte[] data)
+ public static byte[] ReadMessage(byte[] data)
{
byte first;
int size;
@@ -348,7 +348,7 @@ private static (byte first, int size) ReadInfo(byte[] data)
///
///
///
- private static byte[] PackMessage(byte[] input)
+ public static byte[] PackMessage(byte[] input)
{
using var stream = new MemoryStream();
using (var writer = new BinaryWriter(stream))
@@ -393,31 +393,6 @@ private static byte[] GzipDecompress(byte[] data)
}
return output.ToArray();
}
-
- public static async Task GetPostResponseAsync(string Url, byte[] postData, Dictionary headers)
- {
- LogDebug("Post to: {0}, data: {1}", Url, Convert.ToBase64String(postData));
-
- ByteArrayContent content = new(postData);
- content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/grpc");
-
- HttpRequestMessage request = new()
- {
- RequestUri = new Uri(Url),
- Method = HttpMethod.Post,
- Content = content,
- //Version = HttpVersion.Version20
- };
-
- if (headers != null)
- foreach (KeyValuePair header in headers)
- request.Headers.TryAddWithoutValidation(header.Key, header.Value);
-
- HttpResponseMessage response = await Util.HTTPUtil.AppHttpClient.SendAsync(request);
- byte[] bytes = await response.Content.ReadAsByteArrayAsync();
-
- return bytes;
- }
}
diff --git a/BBDown.Core/Util/HTTPUtil.cs b/BBDown.Core/Util/HTTPUtil.cs
index c80e953b2..77342c47c 100644
--- a/BBDown.Core/Util/HTTPUtil.cs
+++ b/BBDown.Core/Util/HTTPUtil.cs
@@ -70,18 +70,36 @@ public static async Task GetWebLocationAsync(string url)
return location;
}
- public static async Task GetPostResponseAsync(string Url, byte[] postData)
+ public static async Task GetPostResponseAsync(string Url, byte[] postData, Dictionary headers = null)
{
LogDebug("Post to: {0}, data: {1}", Url, Convert.ToBase64String(postData));
- using HttpRequestMessage request = new(HttpMethod.Post, Url);
- request.Headers.TryAddWithoutValidation("Content-Type", "application/grpc");
- request.Headers.TryAddWithoutValidation("Content-Length", postData.Length.ToString());
- request.Headers.TryAddWithoutValidation("User-Agent", "Dalvik/2.1.0 (Linux; U; Android 6.0.1; oneplus a5010 Build/V417IR) 6.10.0 os/android model/oneplus a5010 mobi_app/android build/6100500 channel/bili innerVer/6100500 osVer/6.0.1 network/2");
- request.Headers.TryAddWithoutValidation("Cookie", Config.COOKIE);
- request.Content = new ByteArrayContent(postData);
- var webResponse = await AppHttpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
- string htmlCode = await webResponse.Content.ReadAsStringAsync();
- return htmlCode;
+
+ ByteArrayContent content = new(postData);
+ content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/grpc");
+
+ HttpRequestMessage request = new()
+ {
+ RequestUri = new Uri(Url),
+ Method = HttpMethod.Post,
+ Content = content,
+ //Version = HttpVersion.Version20
+ };
+
+ if (headers != null)
+ {
+ foreach (KeyValuePair header in headers)
+ request.Headers.TryAddWithoutValidation(header.Key, header.Value);
+ }
+ else
+ {
+ request.Headers.TryAddWithoutValidation("User-Agent", "Dalvik/2.1.0 (Linux; U; Android 6.0.1; oneplus a5010 Build/V417IR) 6.10.0 os/android model/oneplus a5010 mobi_app/android build/6100500 channel/bili innerVer/6100500 osVer/6.0.1 network/2");
+ request.Headers.TryAddWithoutValidation("grpc-encoding", "gzip");
+ }
+
+ HttpResponseMessage response = await AppHttpClient.SendAsync(request);
+ byte[] bytes = await response.Content.ReadAsByteArrayAsync();
+
+ return bytes;
}
}
}
diff --git a/BBDown.Core/Util/SubUtil.cs b/BBDown.Core/Util/SubUtil.cs
index 641ac4028..32e903494 100644
--- a/BBDown.Core/Util/SubUtil.cs
+++ b/BBDown.Core/Util/SubUtil.cs
@@ -1,4 +1,6 @@
-using System.Text;
+using BBDown.Core.Protobuf;
+using Google.Protobuf;
+using System.Text;
using static BBDown.Core.Entity.Entity;
using static BBDown.Core.Util.HTTPUtil;
using System.Text.RegularExpressions;
@@ -356,6 +358,18 @@ public static (string, string) GetSubtitleCode(string key)
}
}
+ private static byte[] GetPayload(long aid, long cid)
+ {
+ var obj = new DmViewReq
+ {
+ Pid = aid,
+ Oid = cid,
+ Type = 1,
+ Spmid = "main.ugc-video-detail.0.0",
+ };
+ return AppHelper.PackMessage(obj.ToByteArray());
+ }
+
private static async Task?> GetSubtitlesFromApi3Async(string aid, string cid, string epId, int index)
{
try
@@ -363,41 +377,20 @@ public static (string, string) GetSubtitleCode(string key)
List subtitles = new();
//grpc调用接口 protobuf
string api = "https://app.biliapi.net/bilibili.community.service.dm.v1.DM/DmView";
- int _aid = Convert.ToInt32(aid);
- int _cid = Convert.ToInt32(cid);
- int _type = 1;
- byte[] data = new byte[18];
- data[0] = 0x0; data[1] = 0x0; data[2] = 0x0; data[3] = 0x0; data[4] = 0xD; //先固定死了
- int i = 5;
- data[i++] = Convert.ToByte((1 << 3) | 0); // index=1
- while ((_aid & -128) != 0)
- {
- data[i++] = Convert.ToByte((_aid & 127) | 128);
- _aid >>= 7;
- }
- data[i++] = Convert.ToByte(_aid);
- data[i++] = Convert.ToByte((2 << 3) | 0); // index=2
- while ((_cid & -128) != 0)
+
+ var data = GetPayload(Convert.ToInt64(aid), Convert.ToInt64(cid));
+
+ var t = AppHelper.ReadMessage(await GetPostResponseAsync(api, data));
+ var resp = new MessageParser(() => new DmViewReply()).ParseFrom(t);
+
+ if (resp.Subtitle != null && resp.Subtitle.Subtitles != null)
{
- data[i++] = Convert.ToByte((_cid & 127) | 128);
- _cid >>= 7;
+ subtitles.AddRange(resp.Subtitle.Subtitles.Select(item => new Subtitle() {
+ url = item.SubtitleUrl,
+ lan = item.Lan,
+ path = $"{aid}/{aid}.{cid}.{item.Lan}.srt"
+ }));
}
- data[i++] = Convert.ToByte(_cid);
- data[i++] = Convert.ToByte((3 << 3) | 0); // index=3
- data[i++] = Convert.ToByte(_type);
- string t = await GetPostResponseAsync(api, data);
- Regex reg = CnJsonRegex();
- foreach (Match m in reg.Matches(t).Cast())
- {
- Subtitle subtitle = new()
- {
- url = m.Groups[2].Value,
- lan = m.Groups[1].Value,
- path = $"{aid}/{aid}.{cid}.{m.Groups[1].Value}.srt"
- };
- subtitles.Add(subtitle);
- }
-
//有空的URL 不合法
if (subtitles.Any(s => string.IsNullOrEmpty(s.url)))
throw new Exception("Bad url");
@@ -421,9 +414,17 @@ public static async Task> GetSubtitlesAsync(string aid, string ci
}
else
{
- subtitles = await GetSubtitlesFromApi2Async(aid, cid, epId, index)
- ?? await GetSubtitlesFromApi1Async(aid, cid, epId, index)
- ?? await GetSubtitlesFromApi3Async(aid, cid, epId, index);
+ if (Config.COOKIE == "")
+ {
+ subtitles = await GetSubtitlesFromApi3Async(aid, cid, epId, index); // 未登录只有APP可以拿到字幕了
+ }
+ else
+ {
+ subtitles = await GetSubtitlesFromApi2Async(aid, cid, epId, index)
+ ?? await GetSubtitlesFromApi1Async(aid, cid, epId, index)
+ ?? await GetSubtitlesFromApi3Async(aid, cid, epId, index);
+ }
+
}
if (subtitles == null)
@@ -480,7 +481,5 @@ private static string FormatTime(double sec) //64.13
[GeneratedRegex("-[a-z]")]
private static partial Regex NonCapsRegex();
- [GeneratedRegex("(zh-Han[st]).*?(http.*?\\.json)")]
- private static partial Regex CnJsonRegex();
}
}