mirror of
https://github.com/Eyre-S/Coeur-Morny-Cono.git
synced 2024-11-22 11:14:55 +08:00
新增了 bilibili 视频分享的内联查询功能
- 添加 bilibili 视频分享的内联查询可以输入 av/bv 号或是视频链接 - 可以输出为带有 av 视频链接的 av 号,或是 bv 视频链接的 bv 号 - 添加 BiliTool 工具可以互转 bilibili av/bv 号
This commit is contained in:
parent
58b6f863bd
commit
2fa6950e4e
@ -1,6 +1,6 @@
|
||||
## Core
|
||||
|
||||
VERSION = 0.8.0.9
|
||||
VERSION = 0.8.0.10
|
||||
|
||||
CODENAME = putian
|
||||
|
||||
|
@ -4,7 +4,7 @@ package cc.sukazyo.cono.morny;
|
||||
* the final field that will be updated by gradle automatically.
|
||||
*/
|
||||
public class GradleProjectConfigures {
|
||||
public static final String VERSION = "0.8.0.9";
|
||||
public static final String VERSION = "0.8.0.10";
|
||||
public static final String CODENAME = "putian";
|
||||
public static final long COMPILE_TIMESTAMP = 1666081545158L;
|
||||
public static final long COMPILE_TIMESTAMP = 1666096021418L;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ public class MornyQueries {
|
||||
queryInstances.add(new RawText());
|
||||
queryInstances.add(new MyInformation());
|
||||
queryInstances.add(new ShareToolTwitter());
|
||||
queryInstances.add(new ShareToolBilibili());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
@ -0,0 +1,80 @@
|
||||
package cc.sukazyo.cono.morny.bot.query;
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit;
|
||||
import cc.sukazyo.cono.morny.util.BiliTool;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.model.request.InlineQueryResultArticle;
|
||||
import com.pengrad.telegrambot.model.request.InputTextMessageContent;
|
||||
import com.pengrad.telegrambot.model.request.ParseMode;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
//import static cc.sukazyo.cono.morny.Log.logger;
|
||||
import static cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds;
|
||||
|
||||
public class ShareToolBilibili implements ITelegramQuery {
|
||||
|
||||
public static final String TITLE_BILI_AV = "[bilibili] Share video / av";
|
||||
public static final String TITLE_BILI_BV = "[bilibili] Share video / BV";
|
||||
public static final String ID_PREFIX_BILI_AV = "[morny/share/bili/av]";
|
||||
public static final String ID_PREFIX_BILI_BV = "[morny/share/bili/bv]";
|
||||
public static final Pattern REGEX_BILI_VIDEO = Pattern.compile("^(?:(?:https?://)?(?:www\\.)?bilibili\\.com(?:/s)?/video/((?:av|AV)(\\d+)|(?:bv|BV)([A-HJ-NP-Za-km-z1-9]+))/?(\\?(?:p=(\\d+))?.*)?|(?:av|AV)(\\d+)|(?:bv|BV)([A-HJ-NP-Za-km-z1-9]+))$");
|
||||
|
||||
private static final String SHARE_FORMAT_HTML = "<a href='%s'>%s</a>";
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<InlineQueryUnit<?>> query (Update event) {
|
||||
if (event.inlineQuery().query() == null) return null;
|
||||
final Matcher regex = REGEX_BILI_VIDEO.matcher(event.inlineQuery().query());
|
||||
if (regex.matches()) {
|
||||
|
||||
// logger.debug(String.format(
|
||||
// "====== ok\n1: %s\n2: %s\n3: %s\n4: %s\n5: %s\n6: %s\n7: %s",
|
||||
// regex.group(1), regex.group(2), regex.group(3), regex.group(4),
|
||||
// regex.group(5), regex.group(6), regex.group(7)
|
||||
// ));
|
||||
|
||||
// get video id from input, also get video part id
|
||||
String av = regex.group(2)==null ? regex.group(6)==null ? null : regex.group(6) : regex.group(2);
|
||||
String bv = regex.group(3)==null ? regex.group(7)==null ? null : regex.group(7) : regex.group(3);
|
||||
// logger.trace(String.format("catch id av[%s] bv[%s]", av, bv));
|
||||
final int part = regex.group(5)==null ? -1 : Integer.parseInt(regex.group(5));
|
||||
// logger.trace(String.format("catch part [%s]", part));
|
||||
if (av == null) {
|
||||
assert bv != null;
|
||||
av = String.valueOf(BiliTool.toAv(bv));
|
||||
// logger.trace(String.format("converted bv[%s] to av[%s]", bv, av));
|
||||
} else {
|
||||
bv = BiliTool.toBv(Long.parseLong(av));
|
||||
// logger.trace(String.format("converted av[%s] to bv[%s]", av, bv));
|
||||
}
|
||||
// build standard share links
|
||||
final String linkPartParam = part==-1 ? "" : "?p="+part;
|
||||
final String linkAv = "https://www.bilibili.com/video/av"+av + linkPartParam;
|
||||
final String linkBv = "https://www.bilibili.com/video/BV"+bv + linkPartParam;
|
||||
final String idAv = "av"+av;
|
||||
final String idBv = "BV"+bv;
|
||||
// logger.trace("built all data.");
|
||||
|
||||
// build share message element
|
||||
List<InlineQueryUnit<?>> result = new ArrayList<>();
|
||||
result.add(new InlineQueryUnit<>(new InlineQueryResultArticle(
|
||||
inlineIds(ID_PREFIX_BILI_AV+av), TITLE_BILI_AV+av,
|
||||
new InputTextMessageContent(String.format(SHARE_FORMAT_HTML, linkAv, idAv)).parseMode(ParseMode.HTML)
|
||||
)));
|
||||
result.add(new InlineQueryUnit<>(new InlineQueryResultArticle(
|
||||
inlineIds(ID_PREFIX_BILI_BV+bv), TITLE_BILI_BV+bv,
|
||||
new InputTextMessageContent(String.format(SHARE_FORMAT_HTML, linkBv, idBv)).parseMode(ParseMode.HTML)
|
||||
)));
|
||||
return result;
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
73
src/main/java/cc/sukazyo/cono/morny/util/BiliTool.java
Normal file
73
src/main/java/cc/sukazyo/cono/morny/util/BiliTool.java
Normal file
@ -0,0 +1,73 @@
|
||||
package cc.sukazyo.cono.morny.util;
|
||||
|
||||
import javax.annotation.Nonnegative;
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class BiliTool {
|
||||
|
||||
private static final long V_CONV_XOR = 177451812L;
|
||||
private static final long V_CONV_ADD = 8728348608L;
|
||||
private static final char[] BV_TABLE = "fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF".toCharArray();
|
||||
private static final int TABLE_INT = BV_TABLE.length;
|
||||
private static final Map<Character, Integer> BV_TABLE_REVERSED = new HashMap<>();
|
||||
static { for (int i = 0; i < BV_TABLE.length; i++) BV_TABLE_REVERSED.put(BV_TABLE[i], i); }
|
||||
private static final char[] BV_TEMPLATE = "1 4 1 7 ".toCharArray();
|
||||
private static final int[] BV_TEMPLATE_FILTER = new int[]{9, 8, 1, 6, 2, 4};
|
||||
|
||||
/**
|
||||
* Convert a <a href="https://www.bilibili.com/">Bilibili</a> AV video id format to BV id format.
|
||||
* <p>
|
||||
* the AV id is a number; the BV id is a special base58 number, it shows as String in programming.<br>
|
||||
* eg:<br>
|
||||
* while the link <i>{@code https://www.bilibili.com/video/BV17x411w7KC/}</i>
|
||||
* shows the same with <i>{@code https://www.bilibili.com/video/av170001/}</i>,
|
||||
* the AV id is <u>{@code 170001}</u>, the BV id is <u>{@code 17x411w7KC}</u>
|
||||
* <p>
|
||||
* for now , the BV id has 10 digits.
|
||||
* the method <b>available while the <u>av-id < 2^27</u></b>, while it theoretically available when the av-id < 2^30.
|
||||
*
|
||||
* @see <a href="https://www.zhihu.com/question/381784377/answer/1099438784">mcfx的回复: 如何看待 2020 年 3 月 23 日哔哩哔哩将稿件的「av 号」变更为「BV 号」?</a>
|
||||
*
|
||||
* @param bv the BV id, a string in (a special) base58 number format, <b>without "BV" prefix</b>.
|
||||
* @return the AV id corresponding to this bv id in <a href="https://www.bilibili.com/">Bilibili</a>, formatted as a number.
|
||||
*/
|
||||
@Nonnegative
|
||||
public static long toAv (@Nonnull String bv) {
|
||||
long av = 0;
|
||||
for (int i = 0; i < BV_TEMPLATE_FILTER.length; i++) {
|
||||
av += BV_TABLE_REVERSED.get(bv.charAt(BV_TEMPLATE_FILTER[i])) * Math.pow(TABLE_INT,i);
|
||||
}
|
||||
return (av-V_CONV_ADD)^V_CONV_XOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a <a href="https://www.bilibili.com/">Bilibili</a> BV video id format to AV id format.
|
||||
* <p>
|
||||
* the AV id is a number; the BV id is a special base58 number, it shows as String in programming.<br>
|
||||
* eg:<br>
|
||||
* while the link <i>{@code https://www.bilibili.com/video/BV17x411w7KC/}</i>
|
||||
* shows the same with <i>{@code https://www.bilibili.com/video/av170001/}</i>,
|
||||
* the AV id is <u>{@code 170001}</u>, the BV id is <u>{@code 17x411w7KC}</u>
|
||||
* <p>
|
||||
* for now , the BV id has 10 digits.
|
||||
* the method <b>available while the <u>av-id < 2^27</u></b>, while it theoretically available when the av-id < 2^30.
|
||||
*
|
||||
* @see <a href="https://www.zhihu.com/question/381784377/answer/1099438784">mcfx的回复: 如何看待 2020 年 3 月 23 日哔哩哔哩将稿件的「av 号」变更为「BV 号」?</a>
|
||||
*
|
||||
* @param av the (base10) AV id.
|
||||
* @return the AV id corresponding to this bv id in <a href="https://www.bilibili.com/">Bilibili</a>,
|
||||
* as a (special) base 58 number format <b>without "BV" prefix</b>.
|
||||
*/
|
||||
@Nonnull
|
||||
public static String toBv (@Nonnegative long av) {
|
||||
av = (av^V_CONV_XOR)+V_CONV_ADD;
|
||||
final char[] bv = BV_TEMPLATE.clone();
|
||||
for (int i = 0; i < BV_TEMPLATE_FILTER.length; i++) {
|
||||
bv[BV_TEMPLATE_FILTER[i]] = BV_TABLE[(int)(Math.floor(av/(Math.pow(TABLE_INT, i)))%TABLE_INT)];
|
||||
}
|
||||
return String.copyValueOf(bv);
|
||||
}
|
||||
|
||||
}
|
30
src/test/java/cc/sukazyo/cono/morny/util/TestBiliTool.java
Normal file
30
src/test/java/cc/sukazyo/cono/morny/util/TestBiliTool.java
Normal file
@ -0,0 +1,30 @@
|
||||
package cc.sukazyo.cono.morny.util;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
import static cc.sukazyo.cono.morny.util.BiliTool.*;
|
||||
|
||||
public class TestBiliTool {
|
||||
|
||||
private static final String AV_BV_DATA_CSV = """
|
||||
17x411w7KC, 170001
|
||||
1Q541167Qg, 455017605
|
||||
1mK4y1C7Bz, 882584971
|
||||
1T24y197V2, 688730800
|
||||
""";
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource(textBlock = AV_BV_DATA_CSV)
|
||||
void testAvToBv (String bv, int av) {
|
||||
Assertions.assertEquals(bv, toBv(av));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource(textBlock = AV_BV_DATA_CSV)
|
||||
void testBvToAv (String bv, int av) {
|
||||
Assertions.assertEquals(av, toAv(bv));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user