mirror of
https://github.com/LamGC/ContentGrabbingJi.git
synced 2025-07-01 21:07:25 +00:00
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
c09b750fe6 | |||
ca479ef1af | |||
c2c49d2355 | |||
22e74e8cd5 | |||
d549c5674d | |||
c6952de84c | |||
410d6c0828 | |||
aaa1bc932b | |||
a1e54e70d9 | |||
16522155e1 | |||
5f796f7da0 | |||
5a52dd9208 | |||
b53aafa81b |
12
pom.xml
12
pom.xml
@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>net.lamgc</groupId>
|
||||
<artifactId>ContentGrabbingJi</artifactId>
|
||||
<version>2.2.0</version>
|
||||
<version>2.2.1</version>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
@ -36,6 +36,16 @@
|
||||
<target>8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>log4j2-test.xml</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
|
@ -8,6 +8,7 @@ import com.google.gson.reflect.TypeToken;
|
||||
import net.lamgc.cgj.bot.message.MessageSenderBuilder;
|
||||
import net.lamgc.cgj.bot.message.MessageSource;
|
||||
import net.lamgc.cgj.pixiv.PixivDownload;
|
||||
import net.lamgc.cgj.pixiv.PixivURL;
|
||||
import net.lamgc.utils.base.runner.Argument;
|
||||
import net.lamgc.utils.base.runner.Command;
|
||||
import org.slf4j.Logger;
|
||||
@ -104,29 +105,46 @@ public class BotAdminCommandProcess {
|
||||
return "操作已完成.";
|
||||
}
|
||||
|
||||
private final static String RANKING_SETTING_TIME_MIN = "time.min";
|
||||
private final static String RANKING_SETTING_TIME_FLOAT = "time.float";
|
||||
private final static String RANKING_SETTING_RANKING_START = "ranking.start";
|
||||
private final static String RANKING_SETTING_RANKING_END = "ranking.end";
|
||||
private final static String RANKING_SETTING_RANKING_MODE = "ranking.mode";
|
||||
private final static String RANKING_SETTING_RANKING_CONTENT_TYPE = "ranking.contentType";
|
||||
private final static String RANKING_SETTING_PAGE_QUALITY = "page.quality";
|
||||
|
||||
@Command
|
||||
public static String addPushGroup(@Argument(name = "group") long groupId,
|
||||
@Argument(name = "minTime", force = false, defaultValue = "21600000") long minTime,
|
||||
@Argument(name = "floatTime", force = false, defaultValue = "10800000") int floatTime,
|
||||
@Argument(name = "rankingStart", force = false, defaultValue = "1") int rankingStart,
|
||||
@Argument(name = "rankingStop", force = false, defaultValue = "150") int rankingStop,
|
||||
@Argument(name = "original", force = false, defaultValue = "false") boolean original
|
||||
public static String addPushGroup(
|
||||
@Argument(name = "$fromGroup") long fromGroup,
|
||||
@Argument(name = "group", force = false, defaultValue = "0") long groupId,
|
||||
@Argument(name = "minTime", force = false, defaultValue = "21600000") long minTime,
|
||||
@Argument(name = "floatTime", force = false, defaultValue = "10800000") int floatTime,
|
||||
@Argument(name = "rankingStart", force = false, defaultValue = "1") int rankingStart,
|
||||
@Argument(name = "rankingStop", force = false, defaultValue = "150") int rankingStop,
|
||||
@Argument(name = "mode", force = false, defaultValue = "DAILY") String rankingMode,
|
||||
@Argument(name = "type", force = false, defaultValue = "ILLUST") String rankingContentType,
|
||||
@Argument(name = "original", force = false, defaultValue = "false") boolean original
|
||||
) {
|
||||
long group = groupId <= 0 ? fromGroup : groupId;
|
||||
JsonObject setting = new JsonObject();
|
||||
setting.addProperty("time.min", minTime);
|
||||
setting.addProperty("time.float", floatTime);
|
||||
setting.addProperty("ranking.start", rankingStart);
|
||||
setting.addProperty("ranking.end", rankingStop);
|
||||
setting.addProperty("pageQuality.original", original);
|
||||
if(pushInfoMap.containsKey(groupId)) {
|
||||
log.info("群 {} 已存在Timer, 删除Timer...", groupId);
|
||||
removePushGroup(groupId);
|
||||
setting.addProperty(RANKING_SETTING_TIME_MIN, minTime);
|
||||
setting.addProperty(RANKING_SETTING_TIME_FLOAT, floatTime);
|
||||
setting.addProperty(RANKING_SETTING_RANKING_START, rankingStart);
|
||||
setting.addProperty(RANKING_SETTING_RANKING_END, rankingStop);
|
||||
setting.addProperty(RANKING_SETTING_RANKING_MODE, rankingMode);
|
||||
setting.addProperty(RANKING_SETTING_RANKING_CONTENT_TYPE, rankingContentType);
|
||||
setting.addProperty(RANKING_SETTING_PAGE_QUALITY, original ?
|
||||
PixivDownload.PageQuality.ORIGINAL.name() :
|
||||
PixivDownload.PageQuality.REGULAR.name());
|
||||
if(pushInfoMap.containsKey(group)) {
|
||||
log.info("群 {} 已存在Timer, 删除Timer...", group);
|
||||
removePushGroup(fromGroup, groupId);
|
||||
}
|
||||
|
||||
log.info("正在增加Timer...(Setting: {})", setting);
|
||||
pushInfoMap.put(groupId, setting);
|
||||
addPushTimer(groupId, setting);
|
||||
return "已在 " + groupId + " 开启定时推送功能。";
|
||||
pushInfoMap.put(group, setting);
|
||||
addPushTimer(group, setting);
|
||||
return "已在 " + group + " 开启定时推送功能。";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -170,14 +188,24 @@ public class BotAdminCommandProcess {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载所有推送Timer
|
||||
* @param flush 是否完全重载, 如为true则加载前会删除所有已加载的Timer
|
||||
*/
|
||||
public static void loadAllPushTimer(boolean flush) {
|
||||
if(flush) {
|
||||
RandomIntervalSendTimer.timerIdSet().forEach(id -> RandomIntervalSendTimer.getTimerById(id).destroy());
|
||||
} else {
|
||||
cleanPushTimer();
|
||||
}
|
||||
cleanPushTimer();
|
||||
pushInfoMap.forEach(BotAdminCommandProcess::addPushTimer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据设置增加Timer
|
||||
* @param id 群组id
|
||||
* @param setting jsonObject设置集
|
||||
*/
|
||||
private static void addPushTimer(long id, JsonObject setting) {
|
||||
try {
|
||||
RandomIntervalSendTimer.getTimerById(id);
|
||||
@ -185,19 +213,65 @@ public class BotAdminCommandProcess {
|
||||
} catch(NoSuchElementException ignored) {
|
||||
}
|
||||
|
||||
int rankingStart = setting.has(RANKING_SETTING_RANKING_START) ? setting.get(RANKING_SETTING_RANKING_START).getAsInt() : 1;
|
||||
int rankingEnd = setting.has(RANKING_SETTING_RANKING_END) ? setting.get(RANKING_SETTING_RANKING_END).getAsInt() : 150;
|
||||
PixivURL.RankingMode rankingMode = PixivURL.RankingMode.MODE_DAILY;
|
||||
PixivURL.RankingContentType rankingContentType = PixivURL.RankingContentType.TYPE_ILLUST;
|
||||
PixivDownload.PageQuality pageQuality = PixivDownload.PageQuality.REGULAR;
|
||||
|
||||
if(rankingStart <= 0 || rankingStart > 500) {
|
||||
log.warn("群组 [{}] - 无效的RankingStart设定值, 将重置为默认设定值(1): {}", id, rankingStart);
|
||||
rankingStart = 1;
|
||||
} else if(rankingEnd > 500 || rankingEnd <= 0) {
|
||||
log.warn("群组 [{}] - 无效的RankingEnd设定值, 将重置为默认设定值(150): {}", id, rankingEnd);
|
||||
rankingEnd = 150;
|
||||
} else if(rankingStart > rankingEnd) {
|
||||
log.warn("群组 [{}] - 无效的排行榜选取范围, 将重置为默认设定值(1 ~ 150): start={}, end={}", id, rankingStart, rankingEnd);
|
||||
rankingStart = 1;
|
||||
rankingEnd = 150;
|
||||
}
|
||||
|
||||
if(setting.has(RANKING_SETTING_RANKING_MODE)) {
|
||||
String value = setting.get(RANKING_SETTING_RANKING_MODE).getAsString().trim().toUpperCase();
|
||||
try {
|
||||
rankingMode = PixivURL.RankingMode.valueOf(value.startsWith("MODE_") ? value : "MODE_" + value);
|
||||
} catch(IllegalArgumentException e) {
|
||||
log.warn("群组ID [{}] - 无效的RankingMode设定值, 将重置为默认值: {}", id, value);
|
||||
}
|
||||
}
|
||||
if(setting.has(RANKING_SETTING_RANKING_CONTENT_TYPE)) {
|
||||
String value = setting.get(RANKING_SETTING_RANKING_CONTENT_TYPE).getAsString().trim().toUpperCase();
|
||||
try {
|
||||
rankingContentType = PixivURL.RankingContentType.valueOf(value.startsWith("TYPE_") ? value : "TYPE_" + value);
|
||||
} catch(IllegalArgumentException e) {
|
||||
log.warn("群组ID [{}] - 无效的RankingContentType设定值: {}", id, value);
|
||||
}
|
||||
}
|
||||
|
||||
if(setting.has(RANKING_SETTING_PAGE_QUALITY)) {
|
||||
String value = setting.get(RANKING_SETTING_PAGE_QUALITY).getAsString().trim().toUpperCase();
|
||||
try {
|
||||
pageQuality = PixivDownload.PageQuality.valueOf(value);
|
||||
} catch(IllegalArgumentException e) {
|
||||
log.warn("群组ID [{}] - 无效的PageQuality设定值: {}", id, value);
|
||||
}
|
||||
}
|
||||
|
||||
AutoSender sender = new RandomRankingArtworksSender(
|
||||
MessageSenderBuilder.getMessageSender(MessageSource.Group, id),
|
||||
setting.get("ranking.start").getAsInt(),
|
||||
setting.get("ranking.end").getAsInt(),
|
||||
setting.get("pageQuality.original").getAsBoolean() ? PixivDownload.PageQuality.ORIGINAL : PixivDownload.PageQuality.REGULAR
|
||||
rankingStart,
|
||||
rankingEnd,
|
||||
rankingMode, rankingContentType,
|
||||
pageQuality
|
||||
);
|
||||
|
||||
RandomIntervalSendTimer.createTimer(
|
||||
RandomIntervalSendTimer timer = RandomIntervalSendTimer.createTimer(
|
||||
id,
|
||||
sender,
|
||||
setting.get("time.min").getAsLong(),
|
||||
setting.get("time.float").getAsInt(),
|
||||
true, true);
|
||||
log.info("群组 {} 已创建对应Timer: {}", id, Integer.toHexString(timer.hashCode()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -206,10 +280,11 @@ public class BotAdminCommandProcess {
|
||||
* @throws NoSuchElementException 当这个群号没有定时器的时候抛出异常
|
||||
*/
|
||||
@Command
|
||||
public static String removePushGroup(@Argument(name = "group") long id) {
|
||||
RandomIntervalSendTimer.getTimerById(id).destroy();
|
||||
pushInfoMap.remove(id);
|
||||
return "已关闭群 " + id + " 的美图推送功能。";
|
||||
public static String removePushGroup(@Argument(name = "$fromGroup") long fromGroup, @Argument(name = "group", force = false) long id) {
|
||||
long group = id <= 0 ? fromGroup : id;
|
||||
RandomIntervalSendTimer.getTimerById(group).destroy();
|
||||
pushInfoMap.remove(group);
|
||||
return "已关闭群 " + group + " 的美图推送功能。";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -229,14 +304,17 @@ public class BotAdminCommandProcess {
|
||||
Set<String> keys = BotCommandProcess.reportStore.keys();
|
||||
StringBuilder msgBuilder = new StringBuilder();
|
||||
msgBuilder.append("当前被报告的作品列表:\n");
|
||||
int count = 1;
|
||||
for(String key : keys) {
|
||||
String illustIdStr = key.substring(key.indexOf(".") + 1);
|
||||
JsonObject report = BotCommandProcess.reportStore.getCache(illustIdStr).getAsJsonObject();
|
||||
log.debug("{} - Report: {}", illustIdStr, report);
|
||||
String reason = report.get("reason").isJsonNull() ? "" : report.get("reason").getAsString();
|
||||
msgBuilder.append(illustIdStr)
|
||||
.append("(").append(dateFormat.format(new Date(report.get("reportTime").getAsLong()))).append("):")
|
||||
.append(reason).append("\n");
|
||||
msgBuilder.append(count).append(". 作品Id: ").append(illustIdStr)
|
||||
.append("(").append(dateFormat.format(new Date(report.get("reportTime").getAsLong()))).append("):\n")
|
||||
.append("报告者QQ:").append(report.get("fromQQ").getAsLong()).append("\n")
|
||||
.append("报告所在群:").append(report.get("fromGroup").getAsLong()).append("\n")
|
||||
.append("报告原因:\n").append(reason).append("\n");
|
||||
}
|
||||
return msgBuilder.toString();
|
||||
}
|
||||
|
@ -113,13 +113,31 @@ public class BotCommandProcess {
|
||||
public static String help() {
|
||||
StringBuilder helpStrBuilder = new StringBuilder();
|
||||
helpStrBuilder.append("CGJ Bot使用指南").append("\n");
|
||||
helpStrBuilder.append("使用方法:.cgj <命令> [参数...]").append("\n");
|
||||
helpStrBuilder.append("例如查询作品信息功能:").append("\n");
|
||||
helpStrBuilder.append(".cgj artwork -id 80846159").append("\n");
|
||||
helpStrBuilder.append("目前可用的命令:").append("\n");
|
||||
helpStrBuilder.append("\t").append("ranking - 获取今天或指定日期排行榜的前10名作品").append("\n");
|
||||
helpStrBuilder.append("\t\t").append("-date - 指定查询日期(年-月-日)").append("\n");
|
||||
helpStrBuilder.append("\t\t").append("-type - 排行榜类型(illust/插画, ugoira/动图, manga/漫画)").append("\n");
|
||||
|
||||
helpStrBuilder.append("\t").append("search - 搜索指定关键词并显示前10个作品").append("\n");
|
||||
helpStrBuilder.append("\t\t").append("-content - 搜索内容").append("\n");
|
||||
helpStrBuilder.append("\t").append("artworks - 获取作品的Pixiv页面").append("\n");
|
||||
|
||||
helpStrBuilder.append("\t").append("link - 获取作品的Pixiv页面").append("\n");
|
||||
helpStrBuilder.append("\t\t").append("-id - 作品id").append("\n");
|
||||
|
||||
helpStrBuilder.append("\t").append("info - 获取Pixiv作品信息").append("\n");
|
||||
helpStrBuilder.append("\t\t").append("-id - 作品id").append("\n");
|
||||
|
||||
helpStrBuilder.append("\t").append("image - 获取指定作品的图片").append("\n");
|
||||
helpStrBuilder.append("\t\t").append("-id - 作品id").append("\n");
|
||||
helpStrBuilder.append("\t\t").append("-quality - 图片质量(original/原图 regular/预览图)").append("\n");
|
||||
helpStrBuilder.append("\t\t").append("-page - 页数").append("\n");
|
||||
|
||||
helpStrBuilder.append("\t").append("report - 报告不当作品").append("\n");
|
||||
helpStrBuilder.append("\t\t").append("-id - 作品Id").append("\n");
|
||||
helpStrBuilder.append("\t\t").append("-msg - 报告原因").append("\n");
|
||||
return helpStrBuilder.toString();
|
||||
}
|
||||
|
||||
@ -259,6 +277,18 @@ public class BotCommandProcess {
|
||||
return "功能未完成";
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索命令
|
||||
* @param content 搜索内容
|
||||
* @param type 搜索类型
|
||||
* @param area 搜索区域
|
||||
* @param includeKeywords 包括关键字
|
||||
* @param excludeKeywords 排除关键字
|
||||
* @param contentOption 搜索选项
|
||||
* @param pagesIndex 搜索页索引
|
||||
* @return 返回搜索内容消息
|
||||
* @throws IOException 当搜索发生异常时抛出
|
||||
*/
|
||||
@Command
|
||||
public static String search(@Argument(name = "content") String content,
|
||||
@Argument(name = "type", force = false) String type,
|
||||
@ -438,7 +468,7 @@ public class BotCommandProcess {
|
||||
}
|
||||
}
|
||||
|
||||
@Command(commandName = "artwork")
|
||||
@Command(commandName = "link")
|
||||
public static String artworksLink(@Argument(name = "id") int illustId) {
|
||||
try {
|
||||
if (isNoSafe(illustId, globalProp, false)) {
|
||||
@ -538,6 +568,12 @@ public class BotCommandProcess {
|
||||
return getImageToBotCode(imageCache.get(fileName), false).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过文件获取图片的BotCode代码
|
||||
* @param targetFile 图片文件
|
||||
* @param updateCache 是否刷新缓存(只是让机器人重新上传, 如果上传接口有重复检测的话是无法处理的)
|
||||
* @return 返回设定好参数的BotCode
|
||||
*/
|
||||
private static BotCode getImageToBotCode(File targetFile, boolean updateCache) {
|
||||
String fileName = targetFile.getName();
|
||||
BotCode code = BotCode.parse(CQCode.image(getImageStoreDir().getName() + "/" + fileName));
|
||||
@ -574,11 +610,13 @@ public class BotCommandProcess {
|
||||
* @return 返回提示信息
|
||||
*/
|
||||
@Command
|
||||
public static String report(@Argument(name = "id") int illustId, @Argument(name = "msg", force = false) String reason) {
|
||||
public static String report(@Argument(name = "$fromGroup") long fromGroup, @Argument(name = "$fromQQ") long fromQQ, @Argument(name = "id") int illustId, @Argument(name = "msg", force = false) String reason) {
|
||||
log.warn("收到作品反馈(IllustId: {}, 原因: {})", illustId, reason);
|
||||
JsonObject reportJson = new JsonObject();
|
||||
reportJson.addProperty("illustId", illustId);
|
||||
reportJson.addProperty("reportTime", new Date().getTime());
|
||||
reportJson.addProperty("fromGroup", fromGroup);
|
||||
reportJson.addProperty("fromQQ", fromQQ);
|
||||
reportJson.addProperty("reason", reason);
|
||||
reportStore.update(String.valueOf(illustId), reportJson, 0);
|
||||
return "色图姬收到了你的报告,将屏蔽该作品并对作品违规情况进行核实,感谢你的反馈!";
|
||||
|
@ -1,9 +1,12 @@
|
||||
package net.lamgc.cgj.bot;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@ -89,6 +92,8 @@ public class RandomIntervalSendTimer extends TimerTask {
|
||||
start(this.loop.get());
|
||||
}
|
||||
|
||||
private final static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-ss HH:mm:ss");
|
||||
|
||||
/**
|
||||
* 启动定时器
|
||||
* @param loop 是否循环, 如果为true, 则任务完成后会自动调用start方法继续循环, 直到被调用{@code #}或总定时器被销毁;
|
||||
@ -96,7 +101,9 @@ public class RandomIntervalSendTimer extends TimerTask {
|
||||
public void start(boolean loop) {
|
||||
this.loop.set(loop);
|
||||
long nextDelay = time + timeRandom.nextInt(floatTime);
|
||||
log.info("定时器 {} 下一延迟: {}ms ({}min)", Integer.toHexString(this.hashCode()), nextDelay, nextDelay / 1000F / 60F);
|
||||
Date nextDate = new Date();
|
||||
nextDate.setTime(nextDate.getTime() + nextDelay);
|
||||
log.info("定时器 {} 下一延迟: {}ms ({})", Integer.toHexString(this.hashCode()), nextDelay, dateFormat.format(nextDate));
|
||||
if(start.get()) {
|
||||
try {
|
||||
Field state = this.getClass().getSuperclass().getDeclaredField("state");
|
||||
@ -114,7 +121,11 @@ public class RandomIntervalSendTimer extends TimerTask {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
sender.send();
|
||||
try {
|
||||
sender.send();
|
||||
} catch (Exception e) {
|
||||
log.error("定时器 {} 执行时发生异常:\n{}", Integer.toHexString(this.hashCode()), Throwables.getStackTraceAsString(e));
|
||||
}
|
||||
if (this.loop.get()) {
|
||||
start();
|
||||
}
|
||||
@ -127,6 +138,7 @@ public class RandomIntervalSendTimer extends TimerTask {
|
||||
@Override
|
||||
public boolean cancel() {
|
||||
start.set(false);
|
||||
loop.set(false);
|
||||
return super.cancel();
|
||||
}
|
||||
|
||||
|
@ -21,20 +21,30 @@ public class RandomRankingArtworksSender extends AutoSender {
|
||||
private final Logger log;
|
||||
private final int rankingStart;
|
||||
private final int rankingStop;
|
||||
private final PixivURL.RankingMode mode;
|
||||
private final PixivURL.RankingContentType contentType;
|
||||
private final PixivDownload.PageQuality quality;
|
||||
|
||||
/**
|
||||
* 构造一个推荐作品发送器
|
||||
* @param messageSender 消息发送器
|
||||
* @param rankingStart 排行榜开始范围(从1开始, 名次)
|
||||
* @param rankingStop 排名榜结束范围(包括该名次)
|
||||
* @param quality 图片质量, 详见{@link net.lamgc.cgj.pixiv.PixivDownload.PageQuality}
|
||||
* @param rankingStart 排行榜开始范围(从1开始, 名次),如传入0或负数则为默认值,默认为1
|
||||
* @param rankingStop 排名榜结束范围(包括该名次),如传入0或负数则为默认值,默认为150
|
||||
* @param mode 排行榜模式
|
||||
* @param contentType 排行榜内容类型
|
||||
* @param quality 图片质量, 详见{@link PixivDownload.PageQuality}
|
||||
* @throws IndexOutOfBoundsException 当 rankingStart > rankingStop时抛出
|
||||
*/
|
||||
public RandomRankingArtworksSender(MessageSender messageSender, int rankingStart, int rankingStop, PixivDownload.PageQuality quality) {
|
||||
public RandomRankingArtworksSender(MessageSender messageSender, int rankingStart, int rankingStop, PixivURL.RankingMode mode, PixivURL.RankingContentType contentType, PixivDownload.PageQuality quality) {
|
||||
super(messageSender);
|
||||
this.mode = mode;
|
||||
this.contentType = contentType;
|
||||
log = LoggerFactory.getLogger("RecommendArtworksSender@" + Integer.toHexString(this.hashCode()));
|
||||
this.rankingStart = rankingStart > 0 ? rankingStart : 1;
|
||||
this.rankingStop = rankingStop > 0 ? rankingStop : 150;
|
||||
if(this.rankingStart > this.rankingStop) {
|
||||
throw new IndexOutOfBoundsException("rankingStart=" + this.rankingStart + ", rankingStop=" + this.rankingStop);
|
||||
}
|
||||
this.quality = quality == null ? PixivDownload.PageQuality.REGULAR : quality;
|
||||
}
|
||||
|
||||
@ -50,11 +60,11 @@ public class RandomRankingArtworksSender extends AutoSender {
|
||||
}
|
||||
queryDate = calendar.getTime();
|
||||
|
||||
int selectRanking = rankingStart + new Random().nextInt(rankingStop + 1);
|
||||
int selectRanking = rankingStart + new Random().nextInt(rankingStop - rankingStart + 1);
|
||||
try {
|
||||
List<JsonObject> rankingList = BotCommandProcess.getRankingInfoByCache(
|
||||
PixivURL.RankingContentType.TYPE_ILLUST,
|
||||
PixivURL.RankingMode.MODE_DAILY,
|
||||
contentType,
|
||||
mode,
|
||||
queryDate,
|
||||
selectRanking,
|
||||
1, false);
|
||||
|
@ -31,7 +31,7 @@ public class RankingUpdateTimer {
|
||||
cal.set(Calendar.DAY_OF_YEAR, cal.get(Calendar.DAY_OF_YEAR) + 1);
|
||||
}
|
||||
cal.set(Calendar.HOUR_OF_DAY, 12);
|
||||
cal.set(Calendar.MINUTE, 10);
|
||||
cal.set(Calendar.MINUTE, 30);
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
cal.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
|
@ -23,10 +23,7 @@ import redis.clients.jedis.JedisPool;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@ -141,7 +138,7 @@ public class BotEventHandler implements EventHandler {
|
||||
|
||||
Pattern pattern = Pattern.compile("/\\s*(\".+?\"|[^:\\s])+((\\s*:\\s*(\".+?\"|[^\\s])+)|)|(\".+?\"|[^\"\\s])+");
|
||||
Matcher matcher = pattern.matcher(Strings.nullToEmpty(msg));
|
||||
ArrayList<String> argsList = new ArrayList<>();
|
||||
List<String> argsList = new ArrayList<>();
|
||||
while (matcher.find()) {
|
||||
String arg = matcher.group();
|
||||
int startIndex = 0;
|
||||
@ -163,6 +160,12 @@ public class BotEventHandler implements EventHandler {
|
||||
String[] args = new String[argsList.size()];
|
||||
argsList.toArray(args);
|
||||
log.debug("传入参数: {}", Arrays.toString(args));
|
||||
argsList.add("-$fromGroup");
|
||||
argsList.add(String.valueOf(event.getFromGroup()));
|
||||
argsList.add("-$fromQQ");
|
||||
argsList.add(String.valueOf(event.getFromQQ()));
|
||||
args = Arrays.copyOf(args, args.length + 4);
|
||||
argsList.toArray(args);
|
||||
|
||||
log.info("正在处理命令...");
|
||||
long time = System.currentTimeMillis();
|
||||
|
@ -56,7 +56,7 @@ public abstract class MessageEvent implements EventObject, MessageSender {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MessageEvent{" +
|
||||
return this.getClass().getSimpleName() + "{" +
|
||||
"fromGroup=" + getFromGroup() +
|
||||
", fromQQ=" + getFromQQ() +
|
||||
", message='" + getMessage() + '\'' +
|
||||
|
33
src/main/java/net/lamgc/cgj/pixiv/AdultContentDetector.java
Normal file
33
src/main/java/net/lamgc/cgj/pixiv/AdultContentDetector.java
Normal file
@ -0,0 +1,33 @@
|
||||
package net.lamgc.cgj.pixiv;
|
||||
|
||||
public interface AdultContentDetector {
|
||||
|
||||
/**
|
||||
* 检查某一作品的成人内容判断指数
|
||||
* @param illustId 作品Id
|
||||
* @param isUgoira 是否为动图
|
||||
* @param pageIndex 指定页数, 设为0或负数则视为单页面作品
|
||||
* @return 返回成人作品判断指数(0 ~ 1), 需按照情况设置阀值.
|
||||
*/
|
||||
double detect(int illustId, boolean isUgoira, int pageIndex) throws Exception;
|
||||
|
||||
/**
|
||||
* 检查某一作品是否为成人内容
|
||||
* @param illustId 作品Id
|
||||
* @param isUgoira 是否为动图
|
||||
* @param pageIndex 指定页数, 设为0或负数则视为单页面作品
|
||||
* @return 如果为true则为成人作品, 该方法将由检测器决定如何为成人作品.
|
||||
*/
|
||||
boolean isAdultContent(int illustId, boolean isUgoira, int pageIndex) throws Exception;
|
||||
|
||||
/**
|
||||
* 检查某一作品是否为成人内容
|
||||
* @param illustId 作品Id
|
||||
* @param isUgoira 是否为动图
|
||||
* @param pageIndex 指定页数, 设为0或负数则视为单页面作品
|
||||
* @param threshold 指数阀值, 当等于或大于该阀值时返回true.
|
||||
* @return 如果为true则为成人作品, 该方法将由 threshold 参数决定是否为成人作品.
|
||||
*/
|
||||
boolean isAdultContent(int illustId, boolean isUgoira, int pageIndex, double threshold) throws Exception;
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package net.lamgc.cgj.pixiv;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 使用ModerateContent服务开发的检测器.<br/>
|
||||
* ModerateContent: www.moderatecontent.com
|
||||
*/
|
||||
public class ModerateContentDetector implements AdultContentDetector {
|
||||
|
||||
private final static HttpClient httpClient = HttpClientBuilder.create().build();
|
||||
private final static Gson gson = new Gson();
|
||||
private final String requestUrl;
|
||||
|
||||
private final static String API_URL = "https://www.moderatecontent.com/api/v2?key={key}&url=https://pixiv.cat/";
|
||||
|
||||
/**
|
||||
* 创建一个使用ModerateContent鉴黄服务的检测器
|
||||
* @param apiKey API密钥
|
||||
*/
|
||||
public ModerateContentDetector(String apiKey) {
|
||||
requestUrl = API_URL.replace("{key}", apiKey);
|
||||
}
|
||||
|
||||
private JsonObject accessInterface(int illustId, boolean isUgoira, int pageIndex) throws IOException {
|
||||
HttpResponse response;
|
||||
if(pageIndex <= 0) {
|
||||
response = httpClient.execute(new HttpGet(requestUrl + illustId + (isUgoira ? ".gif" : ".jpg")));
|
||||
} else {
|
||||
response = httpClient.execute(new HttpGet(requestUrl + illustId + "-" + pageIndex + (isUgoira ? ".gif" : ".jpg")));
|
||||
}
|
||||
if(response.getStatusLine().getStatusCode() != 200) {
|
||||
throw new IOException("Http response error: " + response.getStatusLine());
|
||||
}
|
||||
|
||||
JsonObject result = gson.fromJson(EntityUtils.toString(response.getEntity()), JsonObject.class);
|
||||
if (result.get("error_code").getAsInt() != 0) {
|
||||
throw new IOException("Interface result error: " + (result.has("error") ? result.get("error").getAsString() : "(error message is empty)"));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double detect(int illustId, boolean isUgoira, int pageIndex) throws IOException {
|
||||
return accessInterface(illustId, isUgoira, pageIndex).getAsJsonObject("predictions").get("adult").getAsDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAdultContent(int illustId, boolean isUgoira, int pageIndex) throws IOException {
|
||||
return accessInterface(illustId, isUgoira, pageIndex).get("rating_index").getAsInt() == 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAdultContent(int illustId, boolean isUgoira, int pageIndex, double threshold) throws IOException {
|
||||
return detect(illustId, isUgoira, pageIndex) >= threshold;
|
||||
}
|
||||
}
|
@ -299,6 +299,7 @@ public class PixivDownload {
|
||||
*/
|
||||
public List<JsonObject> getRanking(PixivURL.RankingContentType contentType, PixivURL.RankingMode mode,
|
||||
Date time, int rankStart, int range) throws IOException {
|
||||
Objects.requireNonNull(time);
|
||||
if(!Objects.requireNonNull(contentType).isSupportedMode(Objects.requireNonNull(mode))) {
|
||||
throw new IllegalArgumentException("ContentType不支持指定的RankingMode: ContentType: " + contentType.name() + ", Mode: " + mode.name());
|
||||
} else if(rankStart <= 0) {
|
||||
@ -317,13 +318,15 @@ public class PixivDownload {
|
||||
ArrayList<JsonObject> results = new ArrayList<>(range);
|
||||
for (int pageIndex = startPages; pageIndex <= endPages && count < range; pageIndex++) {
|
||||
HttpGet request = createHttpGetRequest(PixivURL.getRankingLink(contentType, mode, time, pageIndex, true));
|
||||
log.debug("RequestUri: {}", request.getURI());
|
||||
HttpResponse response = httpClient.execute(request);
|
||||
|
||||
String responseBody = EntityUtils.toString(response.getEntity());
|
||||
log.debug("ResponseBody: {}", responseBody);
|
||||
if(response.getStatusLine().getStatusCode() != 200) {
|
||||
throw new IOException("Http Response Error: " + response.getStatusLine());
|
||||
throw new IOException("Http Response Error: '" + response.getStatusLine() + "', ResponseBody: '" + responseBody + '\'');
|
||||
}
|
||||
|
||||
JsonArray resultArray = gson.fromJson(EntityUtils.toString(response.getEntity()), JsonObject.class).getAsJsonArray("contents");
|
||||
JsonArray resultArray = gson.fromJson(responseBody, JsonObject.class).getAsJsonArray("contents");
|
||||
for (int resultIndex = startIndex; resultIndex < resultArray.size() && count < range; resultIndex++, count++) {
|
||||
results.add(resultArray.get(resultIndex).getAsJsonObject());
|
||||
}
|
||||
@ -430,13 +433,14 @@ public class PixivDownload {
|
||||
THUMB_MINI
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取帐号所有的收藏插画,并以输入流形式提供
|
||||
* @return 获取所有链接的InputStream, 请注意关闭InputStream
|
||||
* @throws IOException 当获取时发生异常则直接抛出
|
||||
* @deprecated 该方法可能会导致已经打开的InputStream超时, 使图片获取失败,
|
||||
* 请直接使用{@linkplain #getCollectionAsInputStream(PageQuality, BiConsumer)}
|
||||
*/
|
||||
@Deprecated
|
||||
public Set<Map.Entry<String, InputStream>> getCollectionAsInputStream(PageQuality quality) throws IOException {
|
||||
HashSet<Map.Entry<String, InputStream>> illustInputStreamSet = new HashSet<>();
|
||||
getCollectionAsInputStream(quality, (link, inputStream) -> illustInputStreamSet.add(new AbstractMap.SimpleEntry<>(link, inputStream)));
|
||||
@ -597,12 +601,29 @@ public class PixivDownload {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过预加载数据获取作品类型
|
||||
* @param illustId 作品Id
|
||||
* @param preLoadDataObject 预加载数据(IllustInfo也可以)
|
||||
* @return 如果存在illustType属性, 则返回对应项, 如没有, 或数据内不存在指定作品id的数据, 返回null
|
||||
*/
|
||||
public static PixivIllustType getIllustTypeByPreLoadData(int illustId, JsonObject preLoadDataObject) {
|
||||
JsonObject illustData;
|
||||
JsonObject illustData = null;
|
||||
if(preLoadDataObject.has("illust")) {
|
||||
illustData = preLoadDataObject.getAsJsonObject("illust").getAsJsonObject(String.valueOf(illustId));
|
||||
} else if(preLoadDataObject.has(String.valueOf(illustId))) {
|
||||
illustData = preLoadDataObject.getAsJsonObject(String.valueOf(illustId));
|
||||
} else if(preLoadDataObject.has("body")) { // 解析IllustInfo
|
||||
for (JsonElement jsonElement : preLoadDataObject.getAsJsonObject("body").getAsJsonArray("illusts")) {
|
||||
JsonObject illustInfo = jsonElement.getAsJsonObject();
|
||||
if (illustInfo.get("illustId").getAsInt() == illustId) {
|
||||
illustData = illustInfo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(illustData == null) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
illustData = preLoadDataObject;
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ public class PixivURL {
|
||||
public static String getRankingLink(RankingContentType contentType, RankingMode mode, Date time, int pageIndex, boolean json){
|
||||
StringBuilder linkBuilder = new StringBuilder(PIXIV_RANKING_LINK);
|
||||
linkBuilder.append("mode=").append(mode == null ? RankingMode.MODE_DAILY.modeParam : mode.modeParam);
|
||||
if(contentType != null && !contentType.equals(RankingContentType.ALL)){
|
||||
if(contentType != null && !contentType.equals(RankingContentType.TYPE_ALL)){
|
||||
linkBuilder.append("&content=").append(contentType.typeName);
|
||||
}
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
|
||||
@ -278,7 +278,7 @@ public class PixivURL {
|
||||
* 排名榜类型
|
||||
*/
|
||||
public enum RankingContentType{
|
||||
ALL("", RankingMode.values()),
|
||||
TYPE_ALL("", RankingMode.values()),
|
||||
/**
|
||||
* 插画
|
||||
* 支持的时间类型: 每天, 每周, 每月, 新人
|
||||
@ -336,7 +336,7 @@ public class PixivURL {
|
||||
* @return 如果支持返回true
|
||||
*/
|
||||
public boolean isSupportedMode(RankingMode mode) {
|
||||
return Arrays.binarySearch(supportedMode, mode) != -1;
|
||||
return Arrays.binarySearch(supportedMode, mode) < 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ public final class PixivUgoiraBuilder {
|
||||
image.getRGB(0, 0, image.getWidth(), image.getHeight(), rgb, 0, image.getWidth());
|
||||
log.trace("帧解析完成, 正在插入...");
|
||||
encoder.addImage(Image.fromRgb(rgb, image.getWidth()), new ImageOptions().setDelay(frameInfo.get("delay").getAsLong(), TimeUnit.MILLISECONDS));
|
||||
log.debug("帧 {} 插入完成.", frameFileName);
|
||||
log.trace("帧 {} 插入完成.", frameFileName);
|
||||
} catch (IOException e) {
|
||||
log.error("解析帧图片数据时发生异常", e);
|
||||
}
|
||||
|
39
src/main/resources/log4j2-test.xml
Normal file
39
src/main/resources/log4j2-test.xml
Normal file
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration status="WARN">
|
||||
<properties>
|
||||
<property name="logStorePath">./logs</property>
|
||||
<property name="charset">UTF-8</property>
|
||||
<property name="pattern">[%-d{HH:mm:ss.SSS} %5level][%logger.%method():%-3L][%thread]: %msg%n</property>
|
||||
</properties>
|
||||
|
||||
<Appenders>
|
||||
<Console name="CONSOLE_STDOUT" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="${pattern}" charset="${charset}"/>
|
||||
<Filters>
|
||||
<ThresholdFilter level="WARN" onMatch="DENY" onMismatch="ACCEPT"/>
|
||||
</Filters>
|
||||
</Console>
|
||||
<Console name="CONSOLE_STDERR" target="SYSTEM_ERR">
|
||||
<PatternLayout pattern="${pattern}" charset="${charset}"/>
|
||||
<Filters>
|
||||
<ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||
</Filters>
|
||||
</Console>
|
||||
|
||||
<RollingFile name="rollingFile" fileName="logs/latest.log" filePattern="logs/running.%-d{yyyy-MM-dd_HH-mm-ss}.log.gz">
|
||||
<PatternLayout pattern="${pattern}" charset="${charset}"/>
|
||||
<Policies>
|
||||
<OnStartupTriggeringPolicy />
|
||||
</Policies>
|
||||
</RollingFile>
|
||||
</Appenders>
|
||||
|
||||
<Loggers>
|
||||
<Logger level="INFO" name="org.apache.http"/>
|
||||
<Root level="TRACE">
|
||||
<AppenderRef ref="CONSOLE_STDOUT"/>
|
||||
<AppenderRef ref="CONSOLE_STDERR"/>
|
||||
<AppenderRef ref="rollingFile"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</configuration>
|
@ -10,7 +10,7 @@
|
||||
<Console name="CONSOLE_STDOUT" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="${pattern}" charset="${charset}"/>
|
||||
<Filters>
|
||||
<ThresholdFilter level="WARN" onMatch="DENY" onMismatch="ACCEPT"/>
|
||||
<LevelRangeFilter minLevel="INFO" maxLevel="INFO" />
|
||||
</Filters>
|
||||
</Console>
|
||||
<Console name="CONSOLE_STDERR" target="SYSTEM_ERR">
|
||||
@ -30,7 +30,7 @@
|
||||
|
||||
<Loggers>
|
||||
<Logger level="INFO" name="org.apache.http"/>
|
||||
<Root level="INFO">
|
||||
<Root level="TRACE">
|
||||
<AppenderRef ref="CONSOLE_STDOUT"/>
|
||||
<AppenderRef ref="CONSOLE_STDERR"/>
|
||||
<AppenderRef ref="rollingFile"/>
|
||||
|
@ -0,0 +1,22 @@
|
||||
package net.lamgc.cgj.pixiv;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@Ignore
|
||||
public class ModerateContentDetectorTest {
|
||||
|
||||
private final static AdultContentDetector acd = new ModerateContentDetector("d91b6c3fa2bba9ee8f9e68827ba0d937");
|
||||
private final static Logger log = LoggerFactory.getLogger(ModerateContentDetector.class);
|
||||
|
||||
@Test
|
||||
public void checkTest() throws Exception {
|
||||
log.info("Detect: {}, isAdult: {}",
|
||||
acd.detect(80840411, false, 0),
|
||||
acd.isAdultContent(80840411, false, 0));
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,8 +1,15 @@
|
||||
package net.lamgc.cgj.pixiv;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.client.CookieStore;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
@ -202,4 +209,17 @@ public class PixivDownloadTest {
|
||||
log.info(new PixivDownload(cookieStore, proxy).getIllustPreLoadDataById(64076261).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void illustInfoTest() throws IOException {
|
||||
CloseableHttpClient httpClient = HttpClientBuilder.create().setProxy(new HttpHost("127.0.0.1", 1001)).build();
|
||||
HttpGet request = new HttpGet(PixivURL.getPixivIllustInfoAPI(80880547));
|
||||
CloseableHttpResponse response = httpClient.execute(request);
|
||||
String body = EntityUtils.toString(response.getEntity());
|
||||
JsonObject illustInfoResult = new Gson().fromJson(body, JsonObject.class);
|
||||
log.info("IllustInfoJsonResult: {}", illustInfoResult);
|
||||
PixivDownload.PixivIllustType illustType = PixivDownload.PixivIllustType.getIllustTypeByPreLoadData(80880547, illustInfoResult);
|
||||
log.info("IllustType: {}", illustType);
|
||||
Assert.assertEquals(PixivDownload.PixivIllustType.UGOIRA, illustType);
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user