-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathbilibili-archive-checker.user.js
248 lines (222 loc) · 8.21 KB
/
bilibili-archive-checker.user.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
// ==UserScript==
// @name Bilibili Archive Checker
// @version 1.4
// @description 检查 BiliBili 视频是否已经存档到 Internet Archive。
// @author yzqzss
// @match https://www.bilibili.com/video/*
// @run-at document-start
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// ==/UserScript==
(function () {
'use strict';
const initialState = unsafeWindow.__INITIAL_STATE__;
const BASEURL = ""; // 运行API的地址,不包括 /archive/ 部分
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function isVideo() {
var url = window.location.href;
var avRegex = /\/video\/av(\d+)/;
var matches = url.match(avRegex);
if (matches && matches.length > 1) {
console.log("AV:", matches[1]);
return true;
}
var bvRegex = /\/video\/(BV\w+)/;
matches = url.match(bvRegex);
if (matches && matches.length > 1) {
console.log("BV:", matches[1]);
return true;
}
return false;
}
// 从 URL 获取当前视频的 BV 号
function getBVNumber() {
return unsafeWindow.__INITIAL_STATE__?.bvid ?? initialState?.bvid ?? unsafeWindow.vd?.bvid;
}
function getPageNumber() {
return unsafeWindow.__INITIAL_STATE__?.p ?? initialState?.p ?? unsafeWindow.vd?.embedPlayer?.p;
}
function humanReadableUpperPartMap(string, backward) {
// 找到字符串中所有的 ASCII 大写字母,并返回一个能表示他们绝对位置的字符串。
// 其中每个非相邻的大写字母之间用数字表示相隔的字符数。
//
// params: backward - 可以表示是正着看还是倒着看。
//
// NOTE: 在我们的用例中,我们 backward = true ,这样产生的 upperPart 就不太像 BV 号或者类似的编号,以免 upperPart 污染全文搜索。
//
// 例如:
// backward = false
// BV1HP411D7Rj -> BV1HP3D1R (长得像 bvid )
// backward = true
// BV1HP411D7Rj -> 1R1D3PH1VB
if (backward) {
string = string.split('').reverse().join('');
}
let result = '';
let steps = 0;
let char_ = '';
for (let i = 0; i < string.length; i++) {
char_ = string[i];
// console.log('char_:', char_);
if (char_ >= 'A' && char_ <= 'Z') {
if (steps === 0) {
result += char_;
} else {
// steps to string
result += steps.toString() + char_;
}
steps = 0;
} else {
steps++;
}
}
console.log("upperPart:", result);
return result;
}
// 查 archive.org
function queryInternetArchive(bvNumber, pageNumber) {
var identifier = "BiliBili-" + bvNumber + "_p" + pageNumber + "-" + humanReadableUpperPartMap(bvNumber, true);
var iaUrl = "https://archive.org/services/check_identifier.php?output=json&identifier=" + identifier;
console.log("Querying:", iaUrl);
showPopup("正在查询 IA (BV: " + bvNumber + ", P:" + pageNumber + ")", "#f3d9a6")
GM_xmlhttpRequest({
method: "GET",
url: iaUrl,
onload: function (response) {
var data = JSON.parse(response.responseText);
if (data.code === "available") {
showPopup("未存档", "#fac7c7");
} else {
showPopup("本视频已存档", "#bdf8bd", "https://archive.org/details/" + identifier);
}
}
});
}
// 创建悬浮窗
function createPopup() {
var popup = document.createElement("div");
popup.id = "archive-popup";
popup.style.position = "fixed";
popup.style.userSelect = "none"; // 否则选中会出现横向滚动条
popup.style.top = "50%";
popup.style.right = "10px";
popup.style.transform = "translateY(-50%)";
popup.style.padding = "10px";
popup.style.backgroundColor = "#f0f0f0";
popup.style.border = "1px solid #ccc";
popup.style.borderRadius = "4px";
popup.style.zIndex = "9999";
popup.style.opacity = "0.9";
popup.style.transition = "background-color 0.25s";
var text = document.createElement("span");
text.style.marginRight = "10px";
text.style.color = "#333";
text.textContent = "";
var status = document.createElement("span");
status.id = "item-status";
var copyButton = document.createElement("button");
copyButton.textContent = "Copy BV";
copyButton.style.marginTop = "10px";
copyButton.style.padding = "5px";
copyButton.style.margin = "auto";
copyButton.style.display = "block";
copyButton.addEventListener("click", function () {
copyBV();
});
var archiveButton = document.createElement("button");
archiveButton.textContent = "Archive Video";
archiveButton.style.marginTop = "10px";
archiveButton.style.padding = "5px";
archiveButton.style.margin = "auto";
archiveButton.style.display = "block"; // initially hidden
archiveButton.addEventListener("click", function () {
archiveVideo();
});
popup.appendChild(text);
popup.appendChild(status);
popup.appendChild(copyButton);
popup.appendChild(archiveButton);
document.body.appendChild(popup);
}
// 显示悬浮窗
function showPopup(message, color, href = null) {
var popup = document.getElementById("archive-popup");
if (!popup) {
createPopup();
}
var status = document.getElementById("item-status");
if (status) {
status.textContent = message;
if (href) {
status.style.color = "#b6e9fe";
status.style.textDecoration = "underline";
status.innerHTML = "<a href=\"" + href + "\" target=\"_blank\">" + message + "</a>";
}
}
popup = document.getElementById("archive-popup");
popup.style.backgroundColor = color;
}
// 复制 BV 号
async function copyBV() {
var bvNumber = getBVNumber();
if (bvNumber) {
navigator.clipboard.writeText(bvNumber)
.then(function () {
alert("BV号已复制到剪贴板: " + bvNumber);
})
.catch(function (error) {
console.error("无法复制BV号:", error);
});
}
}
async function check() {
if (!isVideo()) {
console.log("Not a video page, skip.");
return;
}
var bvNumber = getBVNumber();
var pageNumber = getPageNumber();
if (bvNumber) {
queryInternetArchive(bvNumber, pageNumber);
}
else {
showPopup("无法获取 BV 号", "#f3d9a6");
}
}
async function archiveVideo() {
var bvNumber = getBVNumber();
if (BASEURL === "") {
alert("请先设置存档服务器地址");
return;
}
var url = `${BASEURL}/archive/${bvNumber}`;
console.log("Archive URL:", url);
showPopup("正在发送存档请求", "#f3d9a6");
GM_xmlhttpRequest({
method: "PUT",
url: url,
onload: function (response) {
if (response.status === 200) {
showPopup("存档请求已发送", "#bdf8bd");
} else {
showPopup("存档请求失败", "#fac7c7");
}
}
});
}
async function main() {
var url = null;
while (true) {
url = window.location.href.split('&')[0];
console.log("url:", url);
check();
while (url === window.location.href.split('&')[0]) {
await sleep(5000);
}
showPopup("URL 变化...", "#b6e9fe");
}
}
document.addEventListener("DOMContentLoaded", main);
})();