Skip to content

Commit 7a9b31e

Browse files
committed
TV login preparation
1 parent def1034 commit 7a9b31e

File tree

7 files changed

+288
-82
lines changed

7 files changed

+288
-82
lines changed

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949

5050
4. **[如果从未保存过 SESSDATA 或 cookie 已失效]** 输入所选登录方式的编号。1.1.9 版本不支持 TV 端二维码登录。
5151

52-
5. **[如果选择了登录方式并选择 Web 端二维码登录]** 打开标题为 `二维码登录` 的窗口,使用B站手机客户端扫码并确认登录,完成后关闭该窗口。
52+
5. **[如果选择了登录方式并选择 WEB 端二维码登录]** 打开标题为 `二维码登录` 的窗口,使用B站手机客户端扫码并确认登录,完成后关闭该窗口。
5353

5454
6. **[如果选择了登录方式并选择输入 SESSDATA 登录]** 输入 cookie 中 SESSDATA 的值。
5555

@@ -104,9 +104,9 @@
104104

105105
## 1.1.9
106106

107-
### 添加了 Web 端二维码登录功能
107+
### 添加了 WEB 端二维码登录功能
108108

109-
目前有两种登录方式可选:`Web 端二维码登录``输入 SESSDATA 登录``Web 端二维码登录``TV 端二维码登录` 的区别在于,前者调用 Web 端的 API 进行登录,在调用 Web 端 API
109+
目前有两种登录方式可选:`WEB 端二维码登录``输入 SESSDATA 登录``WEB 端二维码登录``TV 端二维码登录` 的区别在于,前者调用 WEB 端的 API 进行登录,在调用 WEB 端 API
110110
下载视频时将解锁高清晰度;后者调用 TV 端的 API 进行登录,在调用 TV 端 API 下载视频时将解锁高清晰度。
111111

112112
## 1.1.7

src/main/java/me/naptie/bilidownload/Main.java

+89-35
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import me.naptie.bilidownload.utils.ConfigManager;
66
import me.naptie.bilidownload.utils.HttpManager;
77
import me.naptie.bilidownload.utils.LoginManager;
8+
import me.naptie.bilidownload.utils.SignUtil;
89

910
import java.io.*;
1011
import java.net.MalformedURLException;
@@ -29,20 +30,13 @@ public static void main(String[] args) throws IOException, InterruptedException
2930
debug = args.length > 0 && args[0].equalsIgnoreCase("debug");
3031
config = new File("config.yml");
3132
setScanner();
32-
3333
String id = getNumber();
34-
35-
String cookie = login();
36-
37-
JSONObject info = getVideoInfo(id, cookie);
34+
String[] login = login();
35+
JSONObject info = getVideoInfo(id, login[0], !login[1].isEmpty());
3836
Object[] specified = specify(info);
39-
40-
Object[] details = getResolutions(info, cookie, (int) specified[0]);
41-
37+
Object[] details = getResolutions(info, login, !login[1].isEmpty(), (int) specified[0]);
4238
String[] path = getPath((String) specified[1]);
43-
4439
download(details, path);
45-
4640
System.out.println("\n程序运行结束;总运行时间:" + getFormattedTime(System.currentTimeMillis() - beginTime));
4741
}
4842

@@ -80,9 +74,9 @@ private static String getNumber() {
8074
return input();
8175
}
8276

83-
private static String login() throws IOException {
77+
private static String[] login() throws IOException {
8478
boolean loginSuccess = false;
85-
String sessData, cookie = "#";
79+
String sessData = "#", accessToken = "", cookie = "#";
8680
if (config.exists()) {
8781
ConfigManager.init(config);
8882
Map<String, Object> map = ConfigManager.get();
@@ -91,57 +85,76 @@ private static String login() throws IOException {
9185
if (map.containsKey("sess-data")) {
9286
sessData = (String) map.get("sess-data");
9387
cookie = "SESSDATA=" + sessData + "; Path=/; Domain=bilibili.com;";
94-
JSONObject login = HttpManager.readJsonFromUrl("https://api.bilibili.com/x/web-interface/nav", cookie);
88+
JSONObject login = HttpManager.readJsonFromUrl("https://api.bilibili.com/x/web-interface/nav", cookie, false);
9589
if (login.getIntValue("code") == 0)
9690
if (login.getJSONObject("data").getBoolean("isLogin")) {
9791
if (debug)
9892
System.out.println("检测到配置文件,已自动填充 SESSDATA\nID:" + login.getJSONObject("data").getString("uname") + "\nUID:" + login.getJSONObject("data").getIntValue("mid"));
9993
loginSuccess = true;
10094
}
10195
}
96+
if (map.containsKey("access-token")) {
97+
accessToken = (String) map.get("access-token");
98+
String params = "access_key=" + accessToken + "&appkey=4409e2ce8ffd12b8&ts=" + System.currentTimeMillis();
99+
JSONObject login = HttpManager.readJsonFromUrl("https://app.bilibili.com/x/v2/account/myinfo?" + params + "&sign=" + SignUtil.generate(params), "#", true);
100+
if (login.getIntValue("code") == 0) {
101+
if (debug)
102+
System.out.println("检测到配置文件,已自动填充 token\nID:" + login.getJSONObject("data").getString("name") + "\nUID:" + login.getJSONObject("data").getIntValue("mid"));
103+
loginSuccess = true;
104+
}
105+
}
102106
}
103-
while (!loginSuccess) {
104-
System.out.println("\n登录方式:\n 1. Web 端二维码登录\n 2. TV 端二维码登录\n 3. 输入 SESSDATA 登录\n 4. 跳过登录\n请选择登录方式(输入 1~4 之间的整数):");
107+
do {
108+
System.out.println("\n登录方式:\n 1. WEB 端二维码登录\n 2. TV 端二维码登录\n 3. 输入 SESSDATA 登录\n 4. 跳过登录\n请选择登录方式(输入 1~4 之间的整数):");
105109
int method = inputInt();
106110
if (method < 1) {
107-
System.out.println("输入的数字“" + method + "”太小,已为您选择 Web 端二维码登录");
111+
System.out.println("输入的数字“" + method + "”太小,已为您选择 WEB 端二维码登录");
108112
method = 1;
109113
}
110114
if (method > 4) {
111115
System.out.println("输入的数字“" + method + "”太大,已为您选择跳过登录");
112116
method = 4;
113117
}
114118
if (method == 1) {
115-
LoginManager.showQRCode(false);
116-
while (true) {
119+
LoginManager.showQRCodeFromWeb();
120+
while (true)
117121
if (!LoginManager.sessData.equalsIgnoreCase("*Not_Yet_Prepared*"))
118122
break;
119-
}
120123
sessData = LoginManager.sessData;
121124
if (sessData.isEmpty()) {
122125
System.out.println("登录失败");
123-
continue;
126+
if (hint) System.out.println("请决定是否继续登录(输入“Y”或“N”):");
127+
if (input().equalsIgnoreCase("Y"))
128+
continue;
124129
}
125130
} else if (method == 2) {
126-
sessData = "*TV_Login*";
127-
LoginManager.showQRCode(true);
128-
131+
LoginManager.showQRCodeFromTV();
132+
while (true)
133+
if (!LoginManager.accessToken.equalsIgnoreCase("*Not_Yet_Prepared*"))
134+
break;
135+
accessToken = LoginManager.accessToken;
136+
if (accessToken.isEmpty()) {
137+
System.out.println("登录失败");
138+
if (hint) System.out.println("请决定是否继续登录(输入“Y”或“N”):");
139+
if (input().equalsIgnoreCase("Y"))
140+
continue;
141+
}
129142
} else if (method == 3) {
130143
if (hint) System.out.println("\n请输入 Cookie 中 SESSDATA 的值:");
131144
sessData = input();
132145
} else {
133-
sessData = "#";
146+
break;
134147
}
135148
if (sessData.equals("#")) {
136149
cookie = "#";
137150
break;
138-
} else {
151+
} else if (method != 2) {
139152
cookie = "SESSDATA=" + sessData + "; Path=/; Domain=bilibili.com;";
140-
JSONObject login = HttpManager.readJsonFromUrl("https://api.bilibili.com/x/web-interface/nav", cookie);
153+
JSONObject login = HttpManager.readJsonFromUrl("https://api.bilibili.com/x/web-interface/nav", cookie, false);
141154
if (login.getIntValue("code") == 0)
142155
if (login.getJSONObject("data").getBoolean("isLogin")) {
143156
loginSuccess = true;
144-
System.out.println("登录成功\nID:" + login.getJSONObject("data").getString("uname") + "\nUID:" + login.getJSONObject("data").getIntValue("mid"));
157+
System.out.println("登录成功" + (debug ? "\nID:" + login.getJSONObject("data").getString("uname") + "\nUID:" + login.getJSONObject("data").getIntValue("mid") : ""));
145158
if (hint) System.out.println("请决定是否保存该 SESSDATA(输入“Y”或“N”):");
146159
if (input().equalsIgnoreCase("Y")) {
147160
if (!config.exists()) config.createNewFile();
@@ -153,20 +166,61 @@ private static String login() throws IOException {
153166
ConfigManager.dump(map);
154167
if (hint) System.out.println("已保存 SESSDATA");
155168
}
169+
if (hint) System.out.println("请决定是否继续登录(输入“Y”或“N”):");
170+
if (input().equalsIgnoreCase("Y"))
171+
loginSuccess = false;
156172
} else {
157173
System.out.println("登录失败");
174+
if (loginSuccess) {
175+
if (hint) System.out.println("请决定是否继续登录(输入“Y”或“N”):");
176+
if (input().equalsIgnoreCase("Y"))
177+
loginSuccess = false;
178+
}
158179
}
159180
else {
160181
System.out.println("登录失败");
182+
if (loginSuccess) {
183+
if (hint) System.out.println("请决定是否继续登录(输入“Y”或“N”):");
184+
if (input().equalsIgnoreCase("Y"))
185+
loginSuccess = false;
186+
}
187+
}
188+
} else {
189+
String params = "access_key=" + accessToken + "&appkey=4409e2ce8ffd12b8&ts=" + System.currentTimeMillis();
190+
JSONObject login = HttpManager.readJsonFromUrl("https://app.bilibili.com/x/v2/account/myinfo?" + params + "&sign=" + SignUtil.generate(params), "#", true);
191+
if (login.getIntValue("code") == 0) {
192+
loginSuccess = true;
193+
System.out.println("登录成功" + (debug ? "\nID:" + login.getJSONObject("data").getString("name") + "\nUID:" + login.getJSONObject("data").getIntValue("mid") : ""));
194+
if (hint) System.out.println("请决定是否保存该 token(输入“Y”或“N”):");
195+
if (input().equalsIgnoreCase("Y")) {
196+
if (!config.exists()) config.createNewFile();
197+
ConfigManager.init(config);
198+
Map<String, Object> map = ConfigManager.get();
199+
if (map == null)
200+
map = new LinkedHashMap<>();
201+
map.put("access-token", sessData);
202+
ConfigManager.dump(map);
203+
if (hint) System.out.println("已保存 token");
204+
}
205+
if (hint) System.out.println("请决定是否继续登录(输入“Y”或“N”):");
206+
if (input().equalsIgnoreCase("Y"))
207+
loginSuccess = false;
208+
} else {
209+
System.out.println("登录失败");
210+
if (loginSuccess) {
211+
if (hint) System.out.println("请决定是否继续登录(输入“Y”或“N”):");
212+
if (input().equalsIgnoreCase("Y"))
213+
loginSuccess = false;
214+
}
161215
}
162216
}
163-
}
164-
return cookie;
217+
} while (!loginSuccess);
218+
return new String[]{cookie, accessToken};
165219
}
166220

167-
private static JSONObject getVideoInfo(String id, String cookie) throws IOException {
221+
private static JSONObject getVideoInfo(String id, String cookie, boolean tv) throws IOException {
168222
System.out.println((hint ? "\n" : "") + "正在获取稿件信息······");
169-
JSONObject info = HttpManager.readJsonFromUrl("https://api.bilibili.com/x/web-interface/view?" + (id.toLowerCase().startsWith("av") ? "aid=" + id.substring(2) : "bvid=" + id), cookie);
223+
JSONObject info = HttpManager.readJsonFromUrl("https://api.bilibili.com/x/web-interface/view?" + (id.toLowerCase().startsWith("av") ? "aid=" + id.substring(2) : "bvid=" + id), tv ? "#" : cookie, tv);
170224
if (info.getIntValue("code") != 0) {
171225
System.out.println(info.getString("message"));
172226
System.out.println("\n程序运行结束,错误代码:" + info.getIntValue("code") + ";总运行时间:" + getFormattedTime(System.currentTimeMillis() - beginTime));
@@ -212,12 +266,12 @@ private static Object[] specify(JSONObject info) {
212266
return new Object[]{cid, name};
213267
}
214268

215-
private static Object[] getResolutions(JSONObject info, String cookie, int cid) throws IOException {
269+
private static Object[] getResolutions(JSONObject info, String[] auth, boolean tv, int cid) throws IOException {
216270
System.out.println("\n正在获取清晰度信息······");
217-
String videoUrlTV = "https://api.snm0516.aisee.tv/x/tv/ugc/playurl?avid=" + info.getIntValue("aid") + "&mobi_app=android_tv_yst&fnval=16&qn=120&cid=" + cid + "&platform=android&build=103800&fnver=0";
271+
String videoUrlTV = "https://api.snm0516.aisee.tv/x/tv/ugc/playurl?avid=" + info.getIntValue("aid") + "&mobi_app=android_tv_yst&fnval=80&qn=120&cid=" + cid + (tv ? "&access_key=" + auth[1] : "") + "&fourk=1&platform=android&device=android&build=103800&fnver=0";
218272
String videoUrlWeb = "https://api.bilibili.com/x/player/playurl?avid=" + info.getIntValue("aid") + "&cid=" + cid + "&fnval=80&fourk=1";
219-
JSONObject videoTV = HttpManager.readJsonFromUrl(videoUrlTV, cookie);
220-
JSONObject videoWeb = HttpManager.readJsonFromUrl(videoUrlWeb, cookie).getJSONObject("data");
273+
JSONObject videoTV = HttpManager.readJsonFromUrl(videoUrlTV, "#", true);
274+
JSONObject videoWeb = HttpManager.readJsonFromUrl(videoUrlWeb, auth[0], false).getJSONObject("data");
221275
JSONArray qualitiesTV = videoTV.getJSONArray("accept_description");
222276
JSONArray qualitiesWeb = videoWeb.getJSONArray("accept_description");
223277
JSONArray qualities = summarize(qualitiesTV, qualitiesWeb, videoTV);

src/main/java/me/naptie/bilidownload/objects/Frame.java

+7-5
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,21 @@
88

99
public class Frame extends java.awt.Frame {
1010

11-
public Frame(String title, String image, Dimension size) {
12-
11+
public Frame(String title, String image, Dimension size, boolean tv) {
1312
this.setTitle(title);
1413
Panel panel = new Panel(image, size);
1514
this.add(panel);
1615
this.addWindowListener(new WindowAdapter() {
1716
public void windowClosing(WindowEvent e) {
18-
if (LoginManager.sessData.equalsIgnoreCase("*Not_Yet_Prepared*"))
19-
LoginManager.login();
17+
if (LoginManager.sessData.equalsIgnoreCase("*Not_Yet_Prepared*")) {
18+
LoginManager.loginWeb();
19+
}
20+
if (tv && LoginManager.accessToken.equalsIgnoreCase("*Not_Yet_Prepared*")) {
21+
LoginManager.loginTV();
22+
}
2023
dispose();
2124
}
2225
});
23-
2426
this.pack();
2527
this.setVisible(true);
2628
this.setResizable(false);

src/main/java/me/naptie/bilidownload/utils/HttpManager.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313

1414
public class HttpManager {
1515

16-
public static HttpURLConnection readUrl(String url, String cookie, boolean post) throws IOException {
17-
String userAgent = UserAgentManager.getUserAgent();
16+
public static HttpURLConnection readUrl(String url, String cookie, boolean post, boolean tv) throws IOException {
17+
String userAgent = tv ? UserAgentManager.getTVUserAgent() : UserAgentManager.getUserAgent();
1818
if (Main.debug) System.out.println("正在访问 " + url + ",使用 UA“" + userAgent + "”");
1919
HttpURLConnection request = (HttpURLConnection) (new URL(url)).openConnection();
2020
request.setRequestProperty("User-Agent", userAgent);
@@ -29,7 +29,7 @@ public static HttpURLConnection readUrl(String url, String cookie, boolean post)
2929
return request;
3030
}
3131

32-
public static JSONObject readJsonFromUrl(String url, String cookie) throws IOException {
33-
return JSON.parseObject(IOUtils.toString((InputStream) readUrl(url, cookie, false).getContent(), StandardCharsets.UTF_8));
32+
public static JSONObject readJsonFromUrl(String url, String cookie, boolean tv) throws IOException {
33+
return JSON.parseObject(IOUtils.toString((InputStream) readUrl(url, cookie, false, tv).getContent(), StandardCharsets.UTF_8));
3434
}
3535
}

0 commit comments

Comments
 (0)