[Add] AutoSender 增加自动发送器接口;

[Add] RandomIntervalSendTimer 增加随机延迟自动发送器;
[Add] RecommendArtworksSender 增加随机排行榜作品发送器;
[Change] PixivDownload 重新开发 getRanking 方法;
This commit is contained in:
LamGC 2020-04-20 01:32:11 +08:00
parent dd88f2acab
commit 9dfc20a525
4 changed files with 217 additions and 65 deletions

View File

@ -0,0 +1,30 @@
package net.lamgc.cgj.bot;
import java.util.Objects;
/**
* 自动发送器
*/
public abstract class AutoSender {
private MessageSender messageSender;
/**
* 构造一个自动发送器
* @param messageSender 自动发送器所使用的消息发送器
*/
public AutoSender(MessageSender messageSender) {
this.messageSender = Objects.requireNonNull(messageSender);
}
/**
* 获取设置等等消息发送器
* @return 消息发送器
*/
MessageSender getMessageSender() {
return this.messageSender;
}
public abstract void send();
}

View File

@ -0,0 +1,70 @@
package net.lamgc.cgj.bot;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* 随机间隔发送器
*/
public class RandomIntervalSendTimer extends TimerTask {
private final static Timer timer = new Timer("Thread-RIST");
private final static Logger log = LoggerFactory.getLogger("RandomIntervalSendTimer");
private final Random timeRandom = new Random();
private final AutoSender sender;
private final long time;
private final int floatTime;
private AtomicBoolean loop = new AtomicBoolean();
private final AtomicBoolean start = new AtomicBoolean();
public RandomIntervalSendTimer(AutoSender sender, long time, int floatTime) {
this.sender = sender;
this.time = time;
this.floatTime = floatTime;
}
public void start() {
start(this.loop.get());
}
public void start(boolean loop) {
this.loop.set(loop);
long nextDelay = time + timeRandom.nextInt(floatTime);
log.info("定时器 {} 下一延迟: {}ms", Integer.toHexString(this.hashCode()), nextDelay);
if(start.get()) {
try {
Field state = this.getClass().getSuperclass().getDeclaredField("state");
state.setAccessible(true);
state.setInt(this, 0);
state.setAccessible(false);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
return;
}
}
start.set(true);
timer.schedule(this, nextDelay);
}
@Override
public void run() {
sender.send();
if (this.loop.get()) {
start();
}
}
@Override
public boolean cancel() {
start.set(false);
return super.cancel();
}
}

View File

@ -0,0 +1,85 @@
package net.lamgc.cgj.bot;
import com.google.gson.JsonObject;
import net.lamgc.cgj.pixiv.PixivDownload;
import net.lamgc.cgj.pixiv.PixivURL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Random;
/**
* 推荐作品发送器
*/
public class RandomRankingArtworksSender extends AutoSender {
private final Logger log;
private final int rankingStart;
private final int rankingStop;
private final PixivDownload.PageQuality quality;
/**
* 构造一个推荐作品发送器
* @param messageSender 消息发送器
* @param rankingStart 排行榜开始范围(从1开始, 名次)
* @param rankingStop 排名榜结束范围(包括该名次)
* @param quality 图片质量, 详见{@link net.lamgc.cgj.pixiv.PixivDownload.PageQuality}
*/
public RandomRankingArtworksSender(MessageSender messageSender, int rankingStart, int rankingStop, PixivDownload.PageQuality quality) {
super(messageSender);
log = LoggerFactory.getLogger("RecommendArtworksSender@" + Integer.toHexString(this.hashCode()));
this.rankingStart = rankingStart > 0 ? rankingStart : 1;
this.rankingStop = rankingStop > 0 ? rankingStop : 150;
this.quality = quality == null ? PixivDownload.PageQuality.REGULAR : quality;
}
@Override
public void send() {
Date queryDate = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(queryDate);
if(calendar.get(Calendar.HOUR_OF_DAY) < 12) {
calendar.add(Calendar.DAY_OF_YEAR, -2);
} else {
calendar.add(Calendar.DAY_OF_YEAR, -1);
}
queryDate = calendar.getTime();
int selectRanking = rankingStart + new Random().nextInt(rankingStop + 1);
try {
List<JsonObject> rankingList = BotCommandProcess.getRankingInfoByCache(
PixivURL.RankingContentType.TYPE_ILLUST,
PixivURL.RankingMode.MODE_DAILY,
queryDate,
selectRanking,
1, false);
log.info("RankingResult.size: {}", rankingList.size());
if(rankingList.size() != 1) {
log.error("排行榜选取失败!(获取到了多个结果)");
return;
}
JsonObject rankingInfo = rankingList.get(0);
int illustId = rankingInfo.get("illust_id").getAsInt();
if(BotCommandProcess.isNoSafe(illustId, BotCommandProcess.globalProp, false)) {
log.warn("作品为r18作品, 取消本次发送.");
return;
}
StringBuilder message = new StringBuilder();
message.append("#美图推送 - 今日排行榜 第 ").append(rankingInfo.get("rank").getAsInt()).append("\n");
message.append("标题:").append(rankingInfo.get("title").getAsString()).append("(").append(illustId).append(")\n");
message.append("作者:").append(rankingInfo.get("user_name").getAsString()).append("\n");
message.append(BotCommandProcess.getImageById(illustId, quality, 1));
getMessageSender().sendMessage(message.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -4,6 +4,7 @@ import com.google.gson.Gson;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaderNames;
import org.apache.http.Header; import org.apache.http.Header;
import org.apache.http.HttpHost; import org.apache.http.HttpHost;
@ -256,8 +257,8 @@ public class PixivDownload {
public static List<JsonObject> getRanking(List<JsonObject> rankingList, int rankStart, int range) { public static List<JsonObject> getRanking(List<JsonObject> rankingList, int rankStart, int range) {
log.debug("正在读取JsonArray...(rankStart: {}, range: {})", rankStart, range); log.debug("正在读取JsonArray...(rankStart: {}, range: {})", rankStart, range);
ArrayList<JsonObject> results = new ArrayList<>(rankingList.size()); ArrayList<JsonObject> results = new ArrayList<>(rankingList.size());
for (int rankIndex = rankStart; rankIndex < rankingList.size() && rankIndex < range; rankIndex++) { for (int rankIndex = rankStart; rankIndex < rankStart + range; rankIndex++) {
JsonElement jsonElement = rankingList.get(rankIndex); JsonElement jsonElement = rankingList.get(rankIndex - rankStart);
JsonObject rankInfo = jsonElement.getAsJsonObject(); JsonObject rankInfo = jsonElement.getAsJsonObject();
int rank = rankInfo.get("rank").getAsInt(); int rank = rankInfo.get("rank").getAsInt();
int illustId = rankInfo.get("illust_id").getAsInt(); int illustId = rankInfo.get("illust_id").getAsInt();
@ -279,21 +280,8 @@ public class PixivDownload {
* @return 返回List对象 * @return 返回List对象
*/ */
public static List<JsonObject> getRanking(JsonArray rankingArray, int rankStart, int range) { public static List<JsonObject> getRanking(JsonArray rankingArray, int rankStart, int range) {
log.debug("正在读取JsonArray...(rankStart: {}, range: {})", rankStart, range); List<JsonObject> list = new Gson().fromJson(rankingArray, new TypeToken<List<JsonObject>>(){}.getType());
ArrayList<JsonObject> results = new ArrayList<>(rankingArray.size()); return getRanking(list, rankStart, range);
for (int rankIndex = rankStart; rankIndex < rankingArray.size() && rankIndex < range; rankIndex++) {
JsonElement jsonElement = rankingArray.get(rankIndex);
JsonObject rankInfo = jsonElement.getAsJsonObject();
int rank = rankInfo.get("rank").getAsInt();
int illustId = rankInfo.get("illust_id").getAsInt();
int authorId = rankInfo.get("user_id").getAsInt();
String authorName = rankInfo.get("user_name").getAsString();
String title = rankInfo.get("title").getAsString();
log.debug("Array-当前到第 {}/{} 名(总共 {} 名), IllustID: {}, Author: ({}) {}, Title: {}", rank, rankStart + range, range, illustId, authorId, authorName, title);
results.add(rankInfo);
}
log.debug("JsonArray读取完成.");
return results;
} }
/** /**
@ -304,65 +292,44 @@ public class PixivDownload {
* @param rankStart 开始排名, 从1开始 * @param rankStart 开始排名, 从1开始
* @param range 取范围 * @param range 取范围
* @return 成功返回有值List, 失败且无异常返回空 * @return 成功返回有值List, 失败且无异常返回空
* @throws IOException 获取异常时抛出 * @throws IllegalArgumentException {@linkplain net.lamgc.cgj.pixiv.PixivURL.RankingContentType RankingContentType}
* {@linkplain net.lamgc.cgj.pixiv.PixivURL.RankingMode RankingMode}互不兼容时抛出
* @throws IndexOutOfBoundsException 当排行榜选取范围超出排行榜范围时抛出(排行榜范围为 1 ~ 500 )
* @throws IOException 当Http请求发生异常时抛出, 或Http请求响应码非200时抛出
*/ */
public List<JsonObject> getRanking(PixivURL.RankingContentType contentType, PixivURL.RankingMode mode, public List<JsonObject> getRanking(PixivURL.RankingContentType contentType, PixivURL.RankingMode mode,
Date time, int rankStart, int range) throws IOException { Date time, int rankStart, int range) throws IOException {
if(rankStart <= 0) { if(!Objects.requireNonNull(contentType).isSupportedMode(Objects.requireNonNull(mode))) {
throw new IllegalArgumentException("rankStart cannot be less than or equal to zero");
}
if(range <= 0) {
throw new IllegalArgumentException("range cannot be less than or equal to zero");
}
if(!contentType.isSupportedMode(mode)) {
throw new IllegalArgumentException("ContentType不支持指定的RankingMode: ContentType: " + contentType.name() + ", Mode: " + mode.name()); throw new IllegalArgumentException("ContentType不支持指定的RankingMode: ContentType: " + contentType.name() + ", Mode: " + mode.name());
} else if(rankStart <= 0) {
throw new IndexOutOfBoundsException("rankStart cannot be less than or equal to zero: " + rankStart);
} else if(range <= 0) {
throw new IndexOutOfBoundsException("range cannot be less than or equal to zero:" + range);
} else if(rankStart + range - 1 > 500) {
throw new IndexOutOfBoundsException("排名选取范围超出了排行榜范围: rankStart=" + rankStart + ", range=" + range + ", length:" + (rankStart + range - 1));
} }
int startPage = (int) Math.ceil(rankStart / 50F); int startPages = (int) Math.max(1, Math.floor(rankStart / 50F));
int requestFrequency = (int) Math.ceil((rankStart + (range - 1)) / 50F); int endPages = (int) Math.min(10, Math.ceil((rankStart + range) / 50F));
int surplusQuantity = range; int startIndex = rankStart - 1;
boolean firstRequest = true; int count = 0;
Gson gson = new Gson(); Gson gson = new Gson();
ArrayList<JsonObject> results = new ArrayList<>(); ArrayList<JsonObject> results = new ArrayList<>(range);
for (int requestCount = startPage; requestCount <= requestFrequency && requestCount <= 10; requestCount++) { for (int pageIndex = startPages; pageIndex <= endPages && count < range; pageIndex++) {
int rangeStart = (requestCount - 1) * 50 + 1; HttpGet request = createHttpGetRequest(PixivURL.getRankingLink(contentType, mode, time, pageIndex, true));
log.debug("正在请求第 {} 到 {} 位排名榜 (第{}次请求, 共 {} 次)", rangeStart, rangeStart + 49, requestCount - startPage + 1, requestFrequency - startPage + 1);
HttpGet request = createHttpGetRequest(PixivURL.getRankingLink(contentType, mode, time, requestCount, true));
log.debug("Request URL: {}", request.getURI());
HttpResponse response = httpClient.execute(request); HttpResponse response = httpClient.execute(request);
String content = EntityUtils.toString(response.getEntity());
log.debug("Content: " + content);
JsonObject contentObject = gson.fromJson(content, JsonObject.class);
if(contentObject.has("error")) {
log.warn("接口报错, 返回信息: {}", contentObject.get("error").getAsString());
break;
}
JsonArray rankingArray = contentObject.getAsJsonArray("contents");
log.debug("正在解析数据...");
//需要添加一个总量, 否则会完整跑完一次. if(response.getStatusLine().getStatusCode() != 200) {
//检查是否为最后一次请求和剩余量有多少 throw new IOException("Http Response Error: " + response.getStatusLine());
int firstRequestStartIndex = (rankStart % 50) - 1;
for (int rankIndex = firstRequest ? firstRequestStartIndex : 0; rankIndex < rankingArray.size() && surplusQuantity > 0; rankIndex++, surplusQuantity--) {
JsonElement jsonElement = rankingArray.get(rankIndex);
JsonObject rankInfo = jsonElement.getAsJsonObject();
int rank = rankInfo.get("rank").getAsInt();
int illustId = rankInfo.get("illust_id").getAsInt();
int authorId = rankInfo.get("user_id").getAsInt();
String authorName = rankInfo.get("user_name").getAsString();
String title = rankInfo.get("title").getAsString();
log.debug("Download-当前到第 {}/{} 名(总共 {} 名), IllustID: {}, Author: ({}) {}, Title: {}", rank, rankStart + range - 1, range, illustId, authorId, authorName, title);
results.add(rankInfo);
}
firstRequest = false;
log.debug("第 {} 到 {} 位排名榜完成. (第{}次请求)", rangeStart, rangeStart + 49, requestCount);
} }
if(requestFrequency > 10) { JsonArray resultArray = gson.fromJson(EntityUtils.toString(response.getEntity()), JsonObject.class).getAsJsonArray("contents");
log.warn("请求的排名榜范围超出所支持的范围, 已终止请求."); for (int resultIndex = startIndex; resultIndex < resultArray.size() && count < range; resultIndex++, count++) {
results.add(resultArray.get(resultIndex).getAsJsonObject());
}
// 重置索引
startIndex = 0;
} }
return results; return results;
} }