[Add] 为搜索命令优化翻页功能;

[Change] BotCommandProcess 重制search命令, 增加用于获取范围相关搜索结果页面的`getSearchResult`方法, 调整消息格式;
This commit is contained in:
LamGC 2020-07-29 02:43:49 +08:00
parent d23bae5306
commit 2f3417705d
Signed by: LamGC
GPG Key ID: 6C5AE2A913941E1D

View File

@ -13,8 +13,10 @@ import net.lamgc.cgj.bot.sort.PreLoadDataAttribute;
import net.lamgc.cgj.bot.sort.PreLoadDataAttributeComparator; import net.lamgc.cgj.bot.sort.PreLoadDataAttributeComparator;
import net.lamgc.cgj.pixiv.PixivDownload; import net.lamgc.cgj.pixiv.PixivDownload;
import net.lamgc.cgj.pixiv.PixivDownload.PageQuality; import net.lamgc.cgj.pixiv.PixivDownload.PageQuality;
import net.lamgc.cgj.pixiv.PixivSearchAttribute;
import net.lamgc.cgj.pixiv.PixivSearchLinkBuilder; import net.lamgc.cgj.pixiv.PixivSearchLinkBuilder;
import net.lamgc.cgj.pixiv.PixivURL; import net.lamgc.cgj.pixiv.PixivURL;
import net.lamgc.cgj.util.PixivUtils;
import net.lamgc.utils.base.runner.Argument; import net.lamgc.utils.base.runner.Argument;
import net.lamgc.utils.base.runner.Command; import net.lamgc.utils.base.runner.Command;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -40,6 +42,8 @@ public class BotCommandProcess {
private final static RankingUpdateTimer updateTimer = new RankingUpdateTimer(); private final static RankingUpdateTimer updateTimer = new RankingUpdateTimer();
private final static int SEARCH_PAGE_MAX_ITEM = 60;
public static void initialize() { public static void initialize() {
log.info("正在初始化..."); log.info("正在初始化...");
@ -321,12 +325,9 @@ public class BotCommandProcess {
@Argument(name = "option", force = false) String contentOption, @Argument(name = "option", force = false) String contentOption,
@Argument(name = "p", force = false, defaultValue = "1") int pagesIndex @Argument(name = "p", force = false, defaultValue = "1") int pagesIndex
) throws IOException, InterruptedException { ) throws IOException, InterruptedException {
PixivSearchLinkBuilder searchLinkBuilder = PixivUtils.buildSearchLinkBuilderFromString(content, type, area,
includeKeywords, excludeKeywords, contentOption, pagesIndex);
log.debug("正在执行搜索..."); log.debug("正在执行搜索...");
JsonObject resultBody = CacheStoreCentral.getCentral()
.getSearchBody(content, type, area, includeKeywords, excludeKeywords, contentOption, pagesIndex);
StringBuilder result = new StringBuilder("内容 " + content + " 的搜索结果:\n");
log.debug("正在处理信息...");
int limit = 8; int limit = 8;
try { try {
limit = Integer.parseInt(SettingProperties. limit = Integer.parseInt(SettingProperties.
@ -334,95 +335,121 @@ public class BotCommandProcess {
} catch (Exception e) { } catch (Exception e) {
log.warn("参数转换异常!将使用默认值(" + limit + ")", e); log.warn("参数转换异常!将使用默认值(" + limit + ")", e);
} }
int totalCount = 0; int totalCount = 0;
for (PixivSearchLinkBuilder.SearchArea searchArea : PixivSearchLinkBuilder.SearchArea.values()) { StringBuilder result = new StringBuilder("内容 " + content + " 的搜索结果:\n");
if (!resultBody.has(searchArea.jsonKey) || List<JsonObject> artworkList = getSearchResult(searchLinkBuilder, fromGroup, limit, pagesIndex);
resultBody.getAsJsonObject(searchArea.jsonKey).getAsJsonArray("data").size() == 0) { artworkList.sort(new PreLoadDataAttributeComparator(PreLoadDataAttribute.LIKE));
log.debug("返回数据不包含 {}", searchArea.jsonKey); int startIndex = limit * pagesIndex - limit + 1;
continue; int pageStartIndex = startIndex % SEARCH_PAGE_MAX_ITEM;
} for(int index = pageStartIndex; totalCount < limit && index < artworkList.size(); index++) {
JsonArray illustsArray = resultBody int illustId = artworkList.get(index - 1).get("illustId").getAsInt();
.getAsJsonObject(searchArea.jsonKey).getAsJsonArray("data"); // 预加载数据有更多信息可以提供
ArrayList<JsonElement> illustsList = new ArrayList<>(); JsonObject artworkPreLoadData = CacheStoreCentral.getCentral()
illustsArray.forEach(illustsList::add);
illustsList.sort(new PreLoadDataAttributeComparator(PreLoadDataAttribute.BOOKMARK));
log.debug("已找到与 {} 相关插图信息({})", content, searchArea.name().toLowerCase());
int count = 1;
for (JsonElement jsonElement : illustsList) {
if (count > limit) {
break;
}
JsonObject illustObj = jsonElement.getAsJsonObject();
if (!illustObj.has("illustId")) {
continue;
}
int illustId = illustObj.get("illustId").getAsInt();
StringBuilder builder = new StringBuilder("[");
illustObj.get("tags").getAsJsonArray().forEach(el -> builder.append(el.getAsString()).append(", "));
builder.replace(builder.length() - 2, builder.length(), "]");
log.debug("{} ({} / {})\n\t作品id: {}, \n\t作者名(作者id): {} ({}), \n\t" +
"作品标题: {}, \n\t作品Tags: {}, \n\t页数: {}页, \n\t作品链接: {}",
searchArea.name(),
count,
illustsList.size(),
illustId,
illustObj.get("userName").getAsString(),
illustObj.get("userId").getAsInt(),
illustObj.get("illustTitle").getAsString(),
builder,
illustObj.get("pageCount").getAsInt(),
PixivURL.getPixivRefererLink(illustId)
);
String imageMsg;
try {
imageMsg = CacheStoreCentral.getCentral()
.getImageById(fromGroup, illustId, PixivDownload.PageQuality.REGULAR, 1);
} catch (NoSuchElementException e) {
if(e.getMessage().startsWith("No work found: ")) {
log.warn("作品 {} 不存在, 跳过该作品...", illustId);
continue;
}
throw e;
}
if (isNoSafe(illustId, SettingProperties.getProperties(fromGroup), false)) {
log.warn("作品Id {} 为R-18作品, 跳过.", illustId);
continue;
} else if(isReported(illustId)) {
log.warn("作品Id {} 被报告, 正在等待审核, 跳过该作品.", illustId);
continue;
}
JsonObject illustPreLoadData = CacheStoreCentral.getCentral()
.getIllustPreLoadData(illustId, false); .getIllustPreLoadData(illustId, false);
result.append(searchArea.name()).append(" (").append(count).append(" / ")
.append(limit).append(")\n\t作品id: ").append(illustId) // 构造消息内容
.append(", \n\t作者名: ").append(illustObj.get("userName").getAsString()) result.append(startIndex++).append(". ").append(artworkPreLoadData.get("illustId").getAsInt()).append(" ")
.append("\n\t作品标题: ").append(illustObj.get("illustTitle").getAsString()) .append(artworkPreLoadData.get("illustTitle").getAsString());
.append("\n\t作品页数: ").append(illustObj.get("pageCount").getAsInt()).append("") result.append("\n\t").append("作者:").append(artworkPreLoadData.get("userName").getAsString());
.append("\n\t点赞数") result.append("\n\t").append("作品页数:").append(artworkPreLoadData.get("pageCount").getAsInt()).append("");
.append(illustPreLoadData.get(PreLoadDataAttribute.LIKE.attrName).getAsInt()) result.append("\n\t").append("点赞数:")
.append("\n\t收藏数") .append(artworkPreLoadData.get(PreLoadDataAttribute.LIKE.attrName).getAsInt()).append("");
.append(illustPreLoadData.get(PreLoadDataAttribute.BOOKMARK.attrName).getAsInt()) result.append("\n\t").append("收藏数:")
.append("\n\t围观数") .append(artworkPreLoadData.get(PreLoadDataAttribute.BOOKMARK.attrName).getAsInt()).append("");
.append(illustPreLoadData.get(PreLoadDataAttribute.VIEW.attrName).getAsInt()) result.append("\n\t").append("围观数:")
.append("\n\t评论数") .append(artworkPreLoadData.get(PreLoadDataAttribute.VIEW.attrName).getAsInt()).append("");
.append(illustPreLoadData.get(PreLoadDataAttribute.COMMENT.attrName).getAsInt()) result.append("\n\t").append("评论数:")
.append("\n").append(imageMsg).append("\n"); .append(artworkPreLoadData.get(PreLoadDataAttribute.COMMENT.attrName).getAsInt()).append("");
count++; result.append(CacheStoreCentral.getCentral()
.getImageById(fromGroup, illustId, PageQuality.REGULAR, 1)).append("\n");
totalCount++; totalCount++;
} }
if (count > limit) {
break;
}
}
return totalCount <= 0 ? return totalCount <= 0 ?
"搜索完成,未找到相关作品。" : "搜索完成,未找到相关作品。" :
Strings.nullToEmpty(result.toString()) + "预览图片并非原图,使用“.cgj image -id 作品id”获取原图\n" + Strings.nullToEmpty(result.toString()) + "预览图片并非原图,使用“.cgj image -id 作品id”获取原图\n" +
"如有不当作品,可使用\".cgj report -id 作品id\"向色图姬反馈。"; "如有不当作品,可使用\".cgj report -id 作品id\"向色图姬反馈。";
} }
/**
* 获取 length 涉及的多个页的搜索结果.
* 例如:
* pageMaxItem = 60;
* length = 150;
* page = 3;
* 那么:
* endItemIndex = length * page = 450;
* startItemIndex = endItemIndex - length + 1 = 301;
* startPageIndex = ceil(startItemIndex / pageMaxItem) = 6;
* pageRange = ceil((endItemIndex - length + 1) / pageMaxItem) = 3;
* endPageIndex = startPageIndex - pageRange - 1 = 8;
* 该方法将会取搜索结果的 6 ~ 8 页结果并返回;
* @param searchLinkBuilder 已构造好除 Page 参数外其他参数的 {@link PixivSearchLinkBuilder}
* @param length 所需结果的范围
* @param page 所需结果的页数
* @return 返回包含范围的涉及页面所有搜索结果.
* @throws IOException 如获取发生异常则抛出.
*/
private static List<JsonObject> getSearchResult(PixivSearchLinkBuilder searchLinkBuilder, long groupId, int length, int page) throws IOException {
List<JsonObject> artworkList = new ArrayList<>(length);
int endsItemIndex = length * page;
int startsItemIndex = endsItemIndex - length + 1;
int startPageIndex = (int) Math.ceil(startsItemIndex / (double) SEARCH_PAGE_MAX_ITEM);
int pageRange = (int) Math.ceil((endsItemIndex - startsItemIndex) / (double) SEARCH_PAGE_MAX_ITEM);
PixivSearchAttribute areaAttribute = PixivSearchAttribute.valueOf(searchLinkBuilder.getSearchArea().toString());
Properties properties = SettingProperties.getProperties(groupId);
int expectedQuantity = pageRange * SEARCH_PAGE_MAX_ITEM;
// 一个可能不算最好的去重方法?我已经对Pixiv搜索结果完全重复的情况感到无语了 :(
Set<Integer> artworkIdSet = new HashSet<>();
int addItemCount = 0;
for(int pageIndex = startPageIndex;
pageIndex <= startPageIndex + pageRange - 1 || artworkList.size() < length || artworkList.size() < expectedQuantity;
pageIndex++) {
searchLinkBuilder.setPage(pageIndex);
JsonObject searchBody = CacheStoreCentral.getCentral().getSearchBody(searchLinkBuilder);
for(String areaAttributeName : areaAttribute.attributeNames) {
JsonObject areaResult = searchBody.getAsJsonObject(areaAttributeName);
if(areaResult == null || !areaResult.has("data")) {
log.debug("作品类型属性 {} 无搜索结果, 跳过...", areaAttributeName);
continue;
}
JsonArray areaArray = areaResult.getAsJsonArray("data");
for(JsonElement element : areaArray) {
JsonObject artworkInfo = element.getAsJsonObject();
if(!artworkInfo.has("illustId")) {
log.warn("发现未含有illustId的JsonObject: '{}'", artworkInfo.toString());
continue;
}
final int illustId = artworkInfo.get("illustId").getAsInt();
if(isNoSafe(illustId, properties, false)) {
log.warn("作品 {} 为R18作品, 跳过.", illustId);
continue;
} else if(isReported(illustId)) {
log.warn("作品 {} 被报告, 跳过.", illustId);
continue;
}
if(artworkIdSet.contains(illustId)) {
continue;
}
artworkIdSet.add(illustId);
artworkList.add(artworkInfo);
addItemCount++;
}
}
if(addItemCount == 0) {
log.warn("已无法获取更多作品, 停止搜索.");
break;
}
addItemCount = 0;
}
return artworkList;
}
/** /**
* 获取作品页面的下载链接 * 获取作品页面的下载链接
* @param illustId 作品Id * @param illustId 作品Id