mirror of
https://github.com/LamGC/ContentGrabbingJi.git
synced 2025-07-03 22:07:26 +00:00
initial commit
This commit is contained in:
69
src/main/java/net/lamgc/cgj/pixiv/IllustInfo.java
Normal file
69
src/main/java/net/lamgc/cgj/pixiv/IllustInfo.java
Normal file
@ -0,0 +1,69 @@
|
||||
package net.lamgc.cgj.pixiv;
|
||||
|
||||
/**
|
||||
* 插图(集)的信息
|
||||
*/
|
||||
public class IllustInfo{
|
||||
|
||||
/**
|
||||
* 插图(集)ID
|
||||
*/
|
||||
public final int illustID;
|
||||
|
||||
/**
|
||||
* 第几页
|
||||
*/
|
||||
public final int page;
|
||||
|
||||
/**
|
||||
* 插图标题
|
||||
*/
|
||||
public final String title;
|
||||
|
||||
/**
|
||||
* 插图说明
|
||||
*/
|
||||
public final String description;
|
||||
|
||||
/**
|
||||
* 插图标签
|
||||
*/
|
||||
public final String[] tags;
|
||||
|
||||
/**
|
||||
* 插图图片长度
|
||||
*/
|
||||
public final int width;
|
||||
|
||||
/**
|
||||
* 插图图片高度
|
||||
*/
|
||||
public final int height;
|
||||
|
||||
/**
|
||||
* 作者名
|
||||
*/
|
||||
public final String authorName;
|
||||
|
||||
/**
|
||||
* 作者用户ID
|
||||
*/
|
||||
public final int authorUserID;
|
||||
|
||||
public IllustInfo(int illustID, String title, String description, String[] tags, int width, int height, String authorName, int authorUserID){
|
||||
this(illustID, 0, title, description, tags, width, height, authorName, authorUserID);
|
||||
}
|
||||
|
||||
public IllustInfo(int illustID, int p, String title, String description, String[] tags, int width, int height, String authorName, int authorUserID){
|
||||
this.illustID = illustID;
|
||||
this.page = p;
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.tags = tags;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.authorName = authorName;
|
||||
this.authorUserID = authorUserID;
|
||||
}
|
||||
|
||||
}
|
267
src/main/java/net/lamgc/cgj/pixiv/Pixiv.java
Normal file
267
src/main/java/net/lamgc/cgj/pixiv/Pixiv.java
Normal file
@ -0,0 +1,267 @@
|
||||
package net.lamgc.cgj.pixiv;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.conn.ConnectionPoolTimeoutException;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
public class Pixiv {
|
||||
|
||||
/**
|
||||
* illust Link
|
||||
*/
|
||||
public final static String ATTR_LINK = "link";
|
||||
|
||||
/**
|
||||
* illust Id
|
||||
*/
|
||||
public final static String ATTR_ILLUST_ID = "illustId";
|
||||
|
||||
/**
|
||||
* illust Title
|
||||
*/
|
||||
public final static String ATTR_TITLE = "title";
|
||||
|
||||
/**
|
||||
* illust Author Name
|
||||
*/
|
||||
public final static String ATTR_AUTHOR_NAME = "authorName";
|
||||
|
||||
/**
|
||||
* illust Author UserID
|
||||
*/
|
||||
public final static String ATTR_AUTHOR_ID = "authorId";
|
||||
|
||||
private final HttpClient httpClient;
|
||||
|
||||
public Pixiv(HttpClient client){
|
||||
this.httpClient = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用帐号密码登录Pixiv
|
||||
* @param PixivID Pixiv账户登录名
|
||||
* @param Password Pixiv帐号密码
|
||||
* @throws IOException 当登录连接出现异常时抛出
|
||||
* @deprecated {@link PixivSession#Login(String, String)} 已经废除, 故本方法不可用
|
||||
*/
|
||||
public Pixiv(String PixivID, String Password) throws IOException {
|
||||
this(PixivID, Password, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用帐号密码登录Pixiv
|
||||
* @param PixivID Pixiv账户登录名
|
||||
* @param Password Pixiv帐号密码
|
||||
* @param proxy 代理设置
|
||||
* @throws IOException 当登录连接出现异常时抛出
|
||||
* @deprecated {@link PixivSession#Login(String, String)} 已经废除, 故本方法不可用
|
||||
*/
|
||||
public Pixiv(String PixivID, String Password, HttpHost proxy) throws IOException {
|
||||
PixivSession pixivSession = new PixivSession(proxy, null);
|
||||
if(pixivSession.Login(PixivID, Password)){
|
||||
System.out.println("P站登录成功!");
|
||||
}else{
|
||||
System.out.println("P站登录失败!错误信息: " + pixivSession.getErrMsg());
|
||||
throw new RuntimeException(pixivSession.getErrMsg());
|
||||
}
|
||||
//httpClient = pixivSession.getHttpClient();
|
||||
httpClient = HttpClientBuilder.create()
|
||||
.setDefaultCookieStore(pixivSession.getCookieStore())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取首页推荐列表
|
||||
* @return 首页推荐列表, 一个Map对应一个推荐项, 使用<code>ATTR_</code>开头常量访问即可
|
||||
* @throws IOException
|
||||
*/
|
||||
public List<Map<String, String>> getRecommend() throws IOException {
|
||||
HttpGet getRequest = new HttpGet(PixivURL.PIXIV_INDEX_URL);
|
||||
HttpResponse response = httpClient.execute(getRequest);
|
||||
String pageAsXML = EntityUtils.toString(response.getEntity(),"utf-8");
|
||||
|
||||
//获取推荐图列表(li)
|
||||
//System.out.println(pageAsXML);
|
||||
|
||||
Document document = Jsoup.parse(pageAsXML);
|
||||
|
||||
List<String> links = document.select("._image-items.gtm-illust-recommend-zone>li>.gtm-illust-recommend-thumbnail-link").eachAttr("href");
|
||||
List<String> illustId = document.select("._image-items.gtm-illust-recommend-zone>li>.gtm-illust-recommend-thumbnail-link").eachAttr("data-gtm-recommend-illust-id");
|
||||
List<String> title = document.select("._image-items.gtm-illust-recommend-zone>li>.gtm-illust-recommend-title>h1").eachAttr("title");
|
||||
List<String> authorName = document.select("._image-items.gtm-illust-recommend-zone>li>.gtm-illust-recommend-user-name").eachText();
|
||||
List<String> authorId = document.select("._image-items.gtm-illust-recommend-zone>li>.gtm-illust-recommend-user-name").eachAttr("data-user_id");
|
||||
|
||||
List<Map<String, String>> recommendList = new ArrayList<>();
|
||||
for(int i = 0; i < links.size(); i++){
|
||||
//System.out.println(links.get(i));
|
||||
Map<String, String> info = new HashMap<>();
|
||||
info.put(ATTR_LINK, PixivURL.PIXIV_INDEX_URL + links.get(i));
|
||||
info.put(ATTR_ILLUST_ID, illustId.get(i));
|
||||
info.put(ATTR_TITLE, title.get(i));
|
||||
info.put(ATTR_AUTHOR_NAME, authorName.get(i));
|
||||
info.put(ATTR_AUTHOR_ID, authorId.get(i));
|
||||
recommendList.add(info);
|
||||
}
|
||||
return recommendList;
|
||||
}
|
||||
|
||||
public String[] getAllDownloadLink(int illustID) throws IOException {
|
||||
HttpGet illustPage = new HttpGet(PixivURL.PIXIV_ILLUST_API_URL.replaceAll("\\{illustId}", String.valueOf(illustID)));
|
||||
HttpResponse response = httpClient.execute(illustPage);
|
||||
String pageAsXML = EntityUtils.toString(response.getEntity(),"utf-8");
|
||||
//System.out.println(pageAsXML);
|
||||
JsonObject resultObj = (JsonObject) new JsonParser().parse(pageAsXML);
|
||||
if(!resultObj.get("error").getAsBoolean()){
|
||||
JsonArray bodyArray = resultObj.get("body").getAsJsonArray();
|
||||
int length = bodyArray.size();
|
||||
String[] result = new String[length];
|
||||
for(int i = 0; i < length; i++){
|
||||
JsonObject childObj = bodyArray.get(i).getAsJsonObject();
|
||||
result[i] = childObj.get("urls").getAsJsonObject().get("original").getAsString();
|
||||
}
|
||||
return result;
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 下载P站图片
|
||||
* @param illustID 插图ID
|
||||
* @return 成功返回图片输入流,失败或为多图则返回null
|
||||
*/
|
||||
public InputStream[] downloadIllustImage(int illustID) throws IOException {
|
||||
String[] links = getAllDownloadLink(illustID);
|
||||
List<InputStream> inputStreamList = new ArrayList<>();
|
||||
int count = 1;
|
||||
boolean retry = false;
|
||||
for(int i = 0; i < links.length; i++){
|
||||
try {
|
||||
long sleepTime = (new Random().nextInt(4) + 2) * 1000;
|
||||
System.out.println("nextTime: " + (float)(sleepTime / 1000));
|
||||
Thread.sleep(sleepTime);
|
||||
} catch (InterruptedException ignored) {}
|
||||
String link = links[i];
|
||||
System.out.print("page:" + count++ + "/" + links.length + " ...");
|
||||
HttpGet imgGet = new HttpGet(link);
|
||||
//关键!如果不加上Referer的话,会返回403
|
||||
imgGet.setHeader("Referer", PixivURL.PIXIV_ILLUST_MEDIUM_URL.replaceAll("\\{illustId}", String.valueOf(illustID)));
|
||||
RequestConfig config = RequestConfig.custom()
|
||||
.setConnectTimeout(20 * 1000)
|
||||
.setConnectionRequestTimeout(20 * 1000)
|
||||
.setSocketTimeout(30 * 1000)
|
||||
.build();
|
||||
imgGet.setConfig(config);
|
||||
HttpResponse response;
|
||||
try {
|
||||
response = httpClient.execute(imgGet);
|
||||
}catch(ConnectionPoolTimeoutException e){
|
||||
if(retry){
|
||||
retry = false;
|
||||
System.out.println("获取失败,跳过...");
|
||||
continue;
|
||||
}
|
||||
System.out.println("连接超时,重新获取...");
|
||||
retry = true;
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
retry = false;
|
||||
|
||||
ByteArrayOutputStream cacheOutputStream = new ByteArrayOutputStream((int)response.getEntity().getContentLength());
|
||||
InputStream content = response.getEntity().getContent();
|
||||
int readLength;
|
||||
byte[] cache = new byte[4096];
|
||||
while((readLength = content.read(cache)) != -1){
|
||||
cacheOutputStream.write(cache, 0, readLength);
|
||||
}
|
||||
byte[] data = cacheOutputStream.toByteArray();
|
||||
//System.out.println("读到数据: " + data.length);
|
||||
inputStreamList.add(new ByteArrayInputStream(data));
|
||||
System.out.println("done!(length: " + response.getEntity().getContentLength() + ")");
|
||||
|
||||
}
|
||||
return inputStreamList.toArray(new InputStream[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载P站图片
|
||||
* @param illustID 插图ID
|
||||
* @return 成功返回图片输入流,失败或为多图则返回null
|
||||
*/
|
||||
public InputStream downloadIllustImages(int illustID){
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过解析插图详情页获取
|
||||
* - 插图标题
|
||||
* - 插图作者(及其UserId)
|
||||
* - 插图上传时间
|
||||
* - 插图标签(原始标签)
|
||||
* ...
|
||||
* @return 成功返回IllustInfo对象,失败返回null
|
||||
*/
|
||||
public IllustInfo[] getIllustInfo(int[] illustIDs) throws IOException {
|
||||
//获取Api
|
||||
HttpGet apiRequest = new HttpGet(PixivURL.getPixivIllustInfoAPI(illustIDs));
|
||||
HttpResponse response = httpClient.execute(apiRequest);
|
||||
String resultText = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
|
||||
System.out.println(resultText);
|
||||
JsonObject resultObj = ((JsonObject) new JsonParser().parse(resultText));
|
||||
if(resultObj.get("error").getAsBoolean()){
|
||||
System.err.println("获取失败!");
|
||||
return null;
|
||||
}
|
||||
List<IllustInfo> illustInfoList = new ArrayList<>();
|
||||
JsonArray illustArray = resultObj.get("body").getAsJsonObject().get("illusts").getAsJsonArray();
|
||||
illustArray.forEach(jsonElement -> {
|
||||
JsonObject illustInfoObj = jsonElement.getAsJsonObject();
|
||||
JsonArray tagsArray = illustInfoObj.get("tags").getAsJsonArray();
|
||||
String[] tags = new String[tagsArray.size()];
|
||||
for(int i = 0; i < tags.length; i++){
|
||||
tags[i] = tagsArray.get(i).getAsString();
|
||||
}
|
||||
//TODO: 通过不需要作者id就能获取图片信息的api无法获取图片尺寸
|
||||
IllustInfo illustInfo = new IllustInfo(
|
||||
illustInfoObj.get("workId").getAsInt(),
|
||||
illustInfoObj.get("title").getAsString(),
|
||||
null,
|
||||
tags,
|
||||
-1,
|
||||
-1,
|
||||
illustInfoObj.get("userName").getAsString(),
|
||||
illustInfoObj.get("userId").getAsInt()
|
||||
);
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定用户的所有插画
|
||||
*/
|
||||
public void getUserAllIllustTest() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
533
src/main/java/net/lamgc/cgj/pixiv/PixivDownload.java
Normal file
533
src/main/java/net/lamgc/cgj/pixiv/PixivDownload.java
Normal file
@ -0,0 +1,533 @@
|
||||
package net.lamgc.cgj.pixiv;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.CookieStore;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.select.Elements;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class PixivDownload {
|
||||
|
||||
private final static Logger log = LoggerFactory.getLogger("PixivDownload");
|
||||
|
||||
private final HttpClient httpClient;
|
||||
|
||||
private final CookieStore cookieStore;
|
||||
|
||||
/**
|
||||
* 构造一个PixivDownload对象
|
||||
* @param cookieStore 存在已登录Pixiv的CookieStore对象
|
||||
*/
|
||||
public PixivDownload(CookieStore cookieStore) {
|
||||
this(cookieStore, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造一个PixivDownload对象
|
||||
* @param cookieStore 存在已登录Pixiv的CookieStore对象
|
||||
* @param proxy 访问代理
|
||||
*/
|
||||
public PixivDownload(CookieStore cookieStore, HttpHost proxy) {
|
||||
this.cookieStore = cookieStore;
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setDefaultCookieStore(cookieStore);
|
||||
// UA: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36
|
||||
ArrayList<Header> defaultHeaders = new ArrayList<>(2);
|
||||
defaultHeaders.add(new BasicHeader("User-Agent",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36"));
|
||||
builder.setDefaultHeaders(defaultHeaders);
|
||||
builder.setProxy(proxy);
|
||||
httpClient = builder.build();
|
||||
}
|
||||
|
||||
public HttpClient getHttpClient() {
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
public CookieStore getCookieStore() {
|
||||
return cookieStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取帐号所有的收藏插画,并以输入流形式提供
|
||||
* @param fn 回调函数,函数传进的InputStream无需手动关闭
|
||||
* @throws IOException 当获取时发生异常则直接抛出
|
||||
*/
|
||||
public void getCollectionAsInputStream(PageQuality quality, BiConsumer<String, InputStream> fn) throws IOException {
|
||||
int pageIndex = 0;
|
||||
HttpGet request;
|
||||
Document document;
|
||||
ArrayList<String> linkList = new ArrayList<>();
|
||||
do {
|
||||
request = new HttpGet(PixivURL.PIXIV_USER_COLLECTION_PAGE.replace("{pageIndex}", Integer.toString(++pageIndex)));
|
||||
setCookieInRequest(request, cookieStore);
|
||||
log.info("Request Link: " + request.getURI().toString());
|
||||
HttpResponse response = httpClient.execute(request);
|
||||
// 解析网页内容,获得所有的收藏信息
|
||||
document = Jsoup.parse(EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
|
||||
Elements items = document.select(".display_editable_works .image-item a.work");
|
||||
List<String> hrefList = items.eachAttr("href");
|
||||
log.info("第 {} 页获取到的图片项数量: {}", pageIndex, hrefList.size());
|
||||
if(hrefList.size() == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
Gson gson = new Gson();
|
||||
for (String href : hrefList) {
|
||||
HttpGet linkApiRequest = createHttpGetRequest(PixivURL.PIXIV_ILLUST_API_URL.replace("{illustId}", href.substring(href.lastIndexOf("/") + 1)));
|
||||
log.debug(linkApiRequest.getURI().toString());
|
||||
HttpResponse httpResponse = httpClient.execute(linkApiRequest);
|
||||
JsonObject linkResult = gson.fromJson(EntityUtils.toString(httpResponse.getEntity()), JsonObject.class);
|
||||
if(linkResult.get("error").getAsBoolean()) {
|
||||
log.error("接口返回错误信息: {}", linkResult.get("message").getAsString());
|
||||
continue;
|
||||
}
|
||||
|
||||
JsonArray linkArray = linkResult.get("body").getAsJsonArray();
|
||||
for (int i = 0; i < linkArray.size(); i++) {
|
||||
JsonObject linkObject = linkArray.get(i).getAsJsonObject().get("urls").getAsJsonObject();
|
||||
linkList.add(linkObject.get((quality == null ? PageQuality.ORIGINAL : quality).toString().toLowerCase()).getAsString());
|
||||
}
|
||||
}
|
||||
} while(!document.select(".pager-container>.next").isEmpty());
|
||||
log.info("获取完成.");
|
||||
AtomicInteger count = new AtomicInteger(1);
|
||||
linkList.forEach(link -> {
|
||||
log.info("Next Link [{}]: {}", count.getAndIncrement(), link);
|
||||
InputStream imageInputStream = null;
|
||||
int tryCount = 0;
|
||||
do {
|
||||
try {
|
||||
imageInputStream = getImageAsInputStream(httpClient, link);
|
||||
} catch (IOException e) {
|
||||
log.error("获取图片数据时发生异常", e);
|
||||
if(++tryCount < 5) {
|
||||
log.warn("即将重试[{} / 5]", tryCount);
|
||||
}
|
||||
}
|
||||
} while(imageInputStream == null);
|
||||
|
||||
try(InputStream imageInput = new BufferedInputStream(imageInputStream, 256 * 1024)) {
|
||||
log.debug("调用回调方法...");
|
||||
fn.accept(link, imageInput);
|
||||
log.debug("回调方法调用完成.");
|
||||
} catch (IOException e) {
|
||||
log.error("图片获取失败", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取推荐插图
|
||||
* @param quality 图片质量
|
||||
* @param fn 回调函数
|
||||
* @throws IOException 当获取时发生异常则直接抛出
|
||||
*/
|
||||
public void getRecommendAsInputStream(PageQuality quality, BiConsumer<String, InputStream> fn) throws IOException {
|
||||
HttpResponse response = httpClient.execute(createHttpGetRequest(PixivURL.PIXIV_INDEX_URL));
|
||||
Document document = Jsoup.parse(EntityUtils.toString(response.getEntity()));
|
||||
|
||||
HttpClient imageClient = HttpClientBuilder.create().build();
|
||||
Elements elements = document.select(".gtm-illust-recommend-zone>.image-item>.gtm-illust-recommend-thumbnail-link");
|
||||
for(int illustIndex = 0; illustIndex < elements.size(); illustIndex++){
|
||||
String href = elements.get(illustIndex).attr("href");
|
||||
int illustId = Integer.parseInt(href.substring(href.lastIndexOf("/") + 1));
|
||||
log.info("({}/{}) Href: {}, IllustID: {}", illustIndex + 1, elements.size(), href, illustId);
|
||||
List<String> pageLinkList = getIllustAllPageDownload(httpClient, this.cookieStore, illustId, quality);
|
||||
for (int linkIndex = 0; linkIndex < pageLinkList.size(); linkIndex++) {
|
||||
String link = pageLinkList.get(linkIndex);
|
||||
String fileName = link.substring(link.lastIndexOf("/") + 1);
|
||||
log.info("({}/{})正在处理 {}", linkIndex, pageLinkList.size(), fileName);
|
||||
InputStream imageInputStream = null;
|
||||
int tryCount = 0;
|
||||
do {
|
||||
try {
|
||||
imageInputStream = getImageAsInputStream(imageClient, link);
|
||||
} catch (IOException e) {
|
||||
log.error("获取图片数据时发生异常", e);
|
||||
if(++tryCount < 5) {
|
||||
log.warn("即将重试[{} / 5]", tryCount);
|
||||
}
|
||||
}
|
||||
} while(imageInputStream == null);
|
||||
|
||||
try(InputStream pageInputStream = new BufferedInputStream(imageInputStream, 256 * 1024)) {
|
||||
fn.accept(fileName, pageInputStream);
|
||||
}
|
||||
log.info("Done!");
|
||||
|
||||
}
|
||||
log.info("IllustId {} 处理完成.", illustId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取排行榜
|
||||
* @param contentType 内容类型
|
||||
* @param mode 查询模式
|
||||
* @param time 查询时间
|
||||
* @param range 从第一名开始的范围
|
||||
* @param quality 图片质量
|
||||
* @param fn 回调函数
|
||||
* @throws IOException 当请求发生异常时抛出
|
||||
*/
|
||||
public void getRankingAsInputStream(PixivURL.RankingContentType contentType, PixivURL.RankingMode mode,
|
||||
Date time, int range, PageQuality quality, RankingDownloadFunction fn) throws IOException {
|
||||
getRankingAsInputStream(contentType, mode, time, 1, range, quality, fn);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取排行榜
|
||||
* @param contentType 内容类型
|
||||
* @param mode 查询模式
|
||||
* @param time 查询时间
|
||||
* @param rankStart 开始排行位(包括)
|
||||
* @param range 范围
|
||||
* @param quality 图片质量
|
||||
* @param fn 回调函数
|
||||
* @throws IOException 当请求发生异常时抛出
|
||||
*/
|
||||
public void getRankingAsInputStream(PixivURL.RankingContentType contentType, PixivURL.RankingMode mode,
|
||||
Date time, int rankStart, int range, PageQuality quality, RankingDownloadFunction fn) throws IOException {
|
||||
getRanking(contentType, mode, time, rankStart, range).forEach(rankInfo -> {
|
||||
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.info("当前到第 {}/{} 名(总共 {} 名), IllustID: {}, Author: ({}) {}, Title: {}", rank, rankStart + range - 1, range, illustId, authorId, authorName, title);
|
||||
log.info("正在获取PagesLink...");
|
||||
List<String> linkList;
|
||||
try {
|
||||
linkList = getIllustAllPageDownload(httpClient, this.cookieStore, illustId, quality);
|
||||
} catch (IOException e) {
|
||||
if(e.getMessage().equals("該当作品は削除されたか、存在しない作品IDです。")) {
|
||||
log.warn("作品 {} 不存在.", illustId);
|
||||
} else {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return;
|
||||
}
|
||||
log.info("PagesLink 获取完成, 总数: {}", linkList.size());
|
||||
for (int pageIndex = 0; pageIndex < linkList.size(); pageIndex++) {
|
||||
String downloadLink = linkList.get(pageIndex);
|
||||
log.info("当前Page: {}/{}", pageIndex + 1, linkList.size());
|
||||
try(InputStream imageInputStream = new BufferedInputStream(getImageAsInputStream(HttpClientBuilder.create().build(), downloadLink), 256 * 1024)) {
|
||||
fn.download(rank, downloadLink, rankInfo.deepCopy(), imageInputStream);
|
||||
} catch(IOException e) {
|
||||
log.error("下载插画时发生异常", e);
|
||||
return;
|
||||
}
|
||||
log.info("完成.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public List<JsonObject> getRanking(PixivURL.RankingContentType contentType, PixivURL.RankingMode mode,
|
||||
Date time, int rankStart, int range) throws IOException {
|
||||
if(rankStart <= 0) {
|
||||
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");
|
||||
}
|
||||
|
||||
int startPage = (int) Math.ceil(rankStart / 50F);
|
||||
int requestFrequency = (int) Math.ceil((rankStart + (range - 1)) / 50F);
|
||||
int surplusQuantity = range;
|
||||
boolean firstRequest = true;
|
||||
Gson gson = new Gson();
|
||||
ArrayList<JsonObject> results = new ArrayList<>();
|
||||
for (int requestCount = startPage; requestCount <= requestFrequency && requestCount <= 10; requestCount++) {
|
||||
int rangeStart = (requestCount - 1) * 50 + 1;
|
||||
log.info("正在请求第 {} 到 {} 位排名榜 (第{}次请求, 共 {} 次)", rangeStart, rangeStart + 49, requestCount - startPage + 1, requestFrequency - startPage);
|
||||
HttpGet request = createHttpGetRequest(PixivURL.getRankingLink(contentType, mode, time, requestCount, true));
|
||||
log.info("Request URL: {}", request.getURI());
|
||||
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.info("正在解析数据...");
|
||||
|
||||
//需要添加一个总量, 否则会完整跑完一次.
|
||||
//检查是否为最后一次请求,和剩余量有多少
|
||||
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.info("当前到第 {}/{} 名(总共 {} 名), IllustID: {}, Author: ({}) {}, Title: {}", rank, rankStart + range - 1, range, illustId, authorId, authorName, title);
|
||||
results.add(rankInfo);
|
||||
}
|
||||
firstRequest = false;
|
||||
log.info("第 {} 到 {} 位排名榜完成. (第{}次请求)", rangeStart, rangeStart + 49, requestCount);
|
||||
}
|
||||
|
||||
if(requestFrequency > 10) {
|
||||
log.warn("请求的排名榜范围超出所支持的范围, 已终止请求.");
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取作品的预加载数据
|
||||
* @param illustId 作品id
|
||||
* @return 如果请求成功返回JsonObject, 失败返回null
|
||||
* @throws IOException 当请求响应非200或请求发生异常时抛出.
|
||||
*/
|
||||
public JsonObject getIllustPreLoadDataById(int illustId) throws IOException {
|
||||
HttpGet request = createHttpGetRequest(PixivURL.getPixivRefererLink(illustId));
|
||||
HttpResponse response = httpClient.execute(request);
|
||||
|
||||
if(response.getStatusLine().getStatusCode() != 200) {
|
||||
throw new IOException("Http响应码非200: " + response.getStatusLine());
|
||||
}
|
||||
|
||||
Document document = Jsoup.parse(EntityUtils.toString(response.getEntity()));
|
||||
Elements selectElements = document.select("#meta-preload-data");
|
||||
if(selectElements.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Gson().fromJson(selectElements.attr("content"), JsonObject.class);
|
||||
}
|
||||
|
||||
|
||||
@FunctionalInterface
|
||||
public interface RankingDownloadFunction {
|
||||
/**
|
||||
* 接收图片InputStream
|
||||
* @param rank 当前作品排名
|
||||
* @param link 作品下载链接
|
||||
* @param inputStream 作品下载输入流, InputStream会自动关闭
|
||||
*/
|
||||
void download(int rank, String link, JsonObject rankInfo, InputStream inputStream);
|
||||
}
|
||||
|
||||
public HttpGet createHttpGetRequest(String url) {
|
||||
HttpGet request = new HttpGet(url);
|
||||
setCookieInRequest(request, cookieStore);
|
||||
return request;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 取Illust所有页的原图下载链接
|
||||
* @param httpClient 用于发起请求的HttpClient对象
|
||||
* @param illustId 插画ID
|
||||
* @param quality 页质量, 见{@link PageQuality}
|
||||
* @return 返回该illust所有Page的下载链接
|
||||
* @throws IOException 当HttpClient在请求时发生异常, 或接口报错时抛出, 注意{@link IOException#getMessage()}
|
||||
*/
|
||||
public static List<String> getIllustAllPageDownload(HttpClient httpClient, CookieStore cookieStore, int illustId, PageQuality quality) throws IOException {
|
||||
HttpGet linkApiRequest = new HttpGet(PixivURL.PIXIV_ILLUST_API_URL.replace("{illustId}", Integer.toString(illustId)));
|
||||
setCookieInRequest(linkApiRequest, cookieStore);
|
||||
HttpResponse response = httpClient.execute(linkApiRequest);
|
||||
JsonObject resultObject = new Gson().fromJson(EntityUtils.toString(response.getEntity()), JsonObject.class);
|
||||
|
||||
if(resultObject.get("error").getAsBoolean()) {
|
||||
String message = resultObject.get("message").getAsString();
|
||||
log.info("请求错误, 错误信息: {}", message);
|
||||
throw new IOException(message);
|
||||
}
|
||||
|
||||
JsonArray linkArray = resultObject.getAsJsonArray("body");
|
||||
|
||||
ArrayList<String> resultList = new ArrayList<>();
|
||||
String qualityType = quality == null ? "original" : quality.toString().toLowerCase();
|
||||
log.info("已选择插画类型: {}", qualityType);
|
||||
linkArray.forEach(el -> {
|
||||
JsonObject urlObj = el.getAsJsonObject().getAsJsonObject("urls");
|
||||
resultList.add(urlObj.get(qualityType).getAsString());
|
||||
});
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插图质量
|
||||
*/
|
||||
public enum PageQuality{
|
||||
/**
|
||||
* 原图画质
|
||||
*/
|
||||
ORIGINAL,
|
||||
/**
|
||||
* 常规画质
|
||||
*/
|
||||
REGULAR,
|
||||
/**
|
||||
* 小图画质
|
||||
*/
|
||||
SMALL,
|
||||
/**
|
||||
* 迷你画质
|
||||
*/
|
||||
THUMB_MINI
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取帐号所有的收藏插画,并以输入流形式提供
|
||||
* @return 获取所有链接的InputStream, 请注意关闭InputStream
|
||||
* @throws IOException 当获取时发生异常则直接抛出
|
||||
*/
|
||||
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)));
|
||||
return illustInputStreamSet;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取Pixiv图片
|
||||
* @param httpClient HttpClient对象
|
||||
* @param link Pixiv图片链接
|
||||
* @return 返回图片InputStream,注意关闭InputStream
|
||||
* @throws IOException 获取失败时抛出
|
||||
* @throws IllegalArgumentException 当链接无法处理时抛出
|
||||
*/
|
||||
public static InputStream getImageAsInputStream(HttpClient httpClient, String link) throws IOException {
|
||||
HttpGet request = new HttpGet(link);
|
||||
int startIndex = link.lastIndexOf("/");
|
||||
int endIndex = link.lastIndexOf("_");
|
||||
if(startIndex == -1 || endIndex == -1) {
|
||||
throw new IllegalArgumentException("无法从链接获取illustID: " + link);
|
||||
}
|
||||
|
||||
String referer = PixivURL.getPixivRefererLink(link.substring(startIndex + 1, endIndex));
|
||||
request.addHeader(HttpHeaderNames.REFERER.toString(), referer);
|
||||
|
||||
HttpResponse response = httpClient.execute(request);
|
||||
log.debug("response: {}", response);
|
||||
log.info("Content Length: {}KB", Float.parseFloat(response.getFirstHeader(HttpHeaderNames.CONTENT_LENGTH.toString()).getValue()) / 1024F);
|
||||
log.info("{}", response.getFirstHeader(HttpHeaderNames.CONTENT_TYPE.toString()));
|
||||
return response.getEntity().getContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* 登出当前会话.<br/>
|
||||
* 登出成功后, 该Cookies作废.
|
||||
* @return 返回是否成功登出
|
||||
* @throws IOException 当登出请求异常时抛出
|
||||
*/
|
||||
public boolean logOut() throws IOException {
|
||||
HttpGet request = new HttpGet(PixivURL.PIXIV_LOGOUT_URL);
|
||||
request.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build());
|
||||
setCookieInRequest(request, cookieStore);
|
||||
HttpResponse response = httpClient.execute(request);
|
||||
if (response.getStatusLine().getStatusCode() == 302) {
|
||||
cookieStore.clear();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取作品信息
|
||||
* @param illustId 作品ID
|
||||
* @return 成功获取返回JsonObject, 失败返回null, <br/>
|
||||
* Json示例: <br/>
|
||||
* <pre>
|
||||
* {
|
||||
* "illustId": "79584670",
|
||||
* "illustTitle": "このヤンキーはウブすぎる",
|
||||
* "id": "79584670",
|
||||
* "title": "このヤンキーはウブすぎる",
|
||||
* "illustType": 1,
|
||||
* "xRestrict": 0,
|
||||
* "restrict": 0,
|
||||
* "sl": 2,
|
||||
* "url": "https://i.pximg.net/c/360x360_70/img-master/img/2020/02/19/00/38/23/79584670_p0_square1200.jpg",
|
||||
* "description": "",
|
||||
* "tags": [
|
||||
* "漫画",
|
||||
* "オリジナル",
|
||||
* "創作",
|
||||
* "創作男女",
|
||||
* "コロさん、ポリさん此方です!",
|
||||
* "恋の予感",
|
||||
* "あまずっぺー",
|
||||
* "交換日記",
|
||||
* "続編希望!!",
|
||||
* "オリジナル10000users入り"
|
||||
* ],
|
||||
* "userId": "4778293",
|
||||
* "userName": "隈浪さえ",
|
||||
* "width": 3288,
|
||||
* "height": 4564,
|
||||
* "pageCount": 4,
|
||||
* "isBookmarkable": true,
|
||||
* "bookmarkData": null,
|
||||
* "alt": "#オリジナル このヤンキーはウブすぎる - 隈浪さえ的漫画",
|
||||
* "isAdContainer": false,
|
||||
* "profileImageUrl": "https://i.pximg.net/user-profile/img/2019/12/04/18/56/19/16639046_fea29ce38ea89b0cb2313b40b3a72f9a_50.jpg",
|
||||
* "type": "illust"
|
||||
* }
|
||||
* </pre>
|
||||
* @throws IOException 当请求发生异常, 或接口返回错误信息时抛出.
|
||||
*/
|
||||
public JsonObject getIllustInfoByIllustId(int illustId) throws IOException {
|
||||
HttpGet request = createHttpGetRequest(PixivURL.getPixivIllustInfoAPI(new int[] {illustId}));;
|
||||
HttpResponse response = httpClient.execute(request);
|
||||
String responseStr = EntityUtils.toString(response.getEntity());
|
||||
log.debug("Response Content: {}", responseStr);
|
||||
JsonObject responseObj = new Gson().fromJson(responseStr, JsonObject.class);
|
||||
|
||||
if(responseObj.get("error").getAsBoolean()) {
|
||||
throw new IOException(responseObj.get("message").getAsString());
|
||||
}
|
||||
|
||||
JsonArray illustsArray = responseObj.getAsJsonObject("body").getAsJsonArray("illusts");
|
||||
if(illustsArray.size() == 1) {
|
||||
return illustsArray.get(0).getAsJsonObject();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void setCookieInRequest(HttpRequest request, CookieStore cookieStore) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
cookieStore.getCookies().forEach(cookie -> builder.append(cookie.getName()).append("=").append(cookie.getValue()).append("; "));
|
||||
request.setHeader(HttpHeaderNames.COOKIE.toString(), builder.toString());
|
||||
}
|
||||
|
||||
}
|
340
src/main/java/net/lamgc/cgj/pixiv/PixivSearchBuilder.java
Normal file
340
src/main/java/net/lamgc/cgj/pixiv/PixivSearchBuilder.java
Normal file
@ -0,0 +1,340 @@
|
||||
package net.lamgc.cgj.pixiv;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
|
||||
public class PixivSearchBuilder {
|
||||
|
||||
private final String content;
|
||||
|
||||
private SearchArea searchArea = SearchArea.ARTWORKS;
|
||||
private SearchMode searchMode = SearchMode.TAG_FULL;
|
||||
private SearchType searchType = SearchType.ILLUST_AND_UGOIRA;
|
||||
private SearchOrder searchOrder = SearchOrder.DATE_D;
|
||||
private SearchContentOption searchContentOption = SearchContentOption.ALL;
|
||||
|
||||
private HashSet<String> includeKeywords = new HashSet<>(0);
|
||||
private HashSet<String> excludeKeywords = new HashSet<>(0);
|
||||
|
||||
private int page = 1;
|
||||
|
||||
private int wgt = 0;
|
||||
private int hgt = 0;
|
||||
|
||||
private int wlt = 0;
|
||||
private int hlt = 0;
|
||||
|
||||
private RatioOption ratioOption = null;
|
||||
|
||||
private Date startDate = null;
|
||||
private Date endDate = null;
|
||||
|
||||
public PixivSearchBuilder(String searchContent) {
|
||||
this.content = Objects.requireNonNull(searchContent);
|
||||
}
|
||||
|
||||
public String buildURL() {
|
||||
StringBuilder builder;
|
||||
try {
|
||||
builder = new StringBuilder(PixivURL.PIXIV_SEARCH_CONTENT_URL.replaceAll("\\{area}", searchArea.name().toLowerCase())
|
||||
.replaceAll("\\{content}",
|
||||
URLEncoder.encode(getSearchCondition(), "UTF-8").replaceAll("\\+", "%20")
|
||||
)
|
||||
);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if(searchArea.equals(SearchArea.TOP)) {
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
builder.append("&s_mode=").append(searchMode.name().toLowerCase());
|
||||
builder.append("&type=").append(searchType.name().toLowerCase());
|
||||
builder.append("&p=").append(page);
|
||||
builder.append("&order=").append(searchOrder.name().toLowerCase());
|
||||
builder.append("&mode=").append(searchContentOption.name().toLowerCase());
|
||||
|
||||
//可选参数
|
||||
if(wgt > 0 && hgt > 0) {
|
||||
builder.append("&wgt=").append(wgt);
|
||||
builder.append("&hgt").append(hgt);
|
||||
}
|
||||
|
||||
//可选参数
|
||||
if(wlt > 0 && hlt > 0) {
|
||||
builder.append("&wlt=").append(wlt);
|
||||
builder.append("&hlt").append(hlt);
|
||||
}
|
||||
|
||||
if (ratioOption != null) {
|
||||
builder.append("&ratio=").append(ratioOption.value);
|
||||
}
|
||||
|
||||
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
|
||||
if (startDate != null) {
|
||||
builder.append("&scd=").append(format.format(startDate));
|
||||
}
|
||||
if (endDate != null) {
|
||||
builder.append("&ecd=").append(format.format(endDate));
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public PixivSearchBuilder setSearchArea(SearchArea searchArea) {
|
||||
this.searchArea = searchArea;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取搜索区域
|
||||
* @return 返回搜索区域对象
|
||||
*/
|
||||
public SearchArea getSearchArea() {
|
||||
return searchArea;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取搜索条件.
|
||||
* @return 搜索条件内容
|
||||
*/
|
||||
public String getSearchCondition() {
|
||||
StringBuilder searchContent = new StringBuilder(Strings.nullToEmpty(this.content));
|
||||
if(searchArea.equals(SearchArea.TOP)) {
|
||||
return searchContent.toString();
|
||||
}
|
||||
|
||||
excludeKeywords.forEach(keyword -> searchContent.append(" -").append(keyword));
|
||||
if(!includeKeywords.isEmpty()) {
|
||||
if(!Strings.isNullOrEmpty(searchContent.toString())) {
|
||||
searchContent.append(" (");
|
||||
}
|
||||
includeKeywords.forEach(keyword -> searchContent.append(keyword).append(" OR "));
|
||||
int deleteStart = searchContent.lastIndexOf(" OR ");
|
||||
if(searchContent.length() >= 4 && deleteStart != -1) {
|
||||
searchContent.delete(deleteStart, searchContent.length());
|
||||
}
|
||||
if(!Strings.isNullOrEmpty(searchContent.toString())) {
|
||||
searchContent.append(")");
|
||||
}
|
||||
}
|
||||
|
||||
return searchContent.toString();
|
||||
}
|
||||
|
||||
public PixivSearchBuilder setSearchMode(SearchMode searchMode) {
|
||||
this.searchMode = Objects.requireNonNull(searchMode);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PixivSearchBuilder setSearchType(SearchType searchType) {
|
||||
this.searchType = Objects.requireNonNull(searchType);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PixivSearchBuilder setSearchOrder(SearchOrder searchOrder) {
|
||||
this.searchOrder = Objects.requireNonNull(searchOrder);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PixivSearchBuilder setSearchContentOption(SearchContentOption searchContentOption) {
|
||||
this.searchContentOption = Objects.requireNonNull(searchContentOption);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PixivSearchBuilder setRatioOption(RatioOption ratioOption) {
|
||||
this.ratioOption = Objects.requireNonNull(ratioOption);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PixivSearchBuilder setDateRange(Date startDate, Date endDate) {
|
||||
this.startDate = startDate;
|
||||
this.endDate = endDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PixivSearchBuilder setMaxSize(int width, int height) {
|
||||
this.wgt = width;
|
||||
this.hgt = height;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PixivSearchBuilder setMinSize(int width, int height) {
|
||||
this.wlt = width;
|
||||
this.hlt = height;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PixivSearchBuilder setPage(int pageIndex) {
|
||||
if (pageIndex <= 0) {
|
||||
throw new IllegalArgumentException("Invalid pageIndex: " + pageIndex);
|
||||
}
|
||||
this.page = pageIndex;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PixivSearchBuilder addExcludeKeyword(String keyword) {
|
||||
excludeKeywords.add(keyword);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PixivSearchBuilder removeExcludeKeyword(String keyword) {
|
||||
excludeKeywords.remove(keyword);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PixivSearchBuilder addIncludeKeyword(String keyword) {
|
||||
includeKeywords.add(keyword);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PixivSearchBuilder removeIncludeKeyword(String keyword) {
|
||||
includeKeywords.remove(keyword);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索区域
|
||||
*/
|
||||
public enum SearchArea {
|
||||
/**
|
||||
* 所有(可能是 插画 + 漫画)
|
||||
*/
|
||||
ARTWORKS("illustManga"),
|
||||
/**
|
||||
* 顶部(所有内容)
|
||||
* 同时包含了:
|
||||
* {@link #ILLUSTRATIONS}
|
||||
* {@link #MANGA}
|
||||
* {@link #NOVELS}
|
||||
* 选择此项后, 将直接显示所有与content相关内容, 而忽略所有附加搜索条件.
|
||||
* 因为无法指定pageIndex, 数据只有24项
|
||||
*/
|
||||
TOP(null),
|
||||
/**
|
||||
* 插画
|
||||
*/
|
||||
ILLUSTRATIONS("illust"),
|
||||
/**
|
||||
* 漫画
|
||||
*/
|
||||
MANGA("manga"),
|
||||
/**
|
||||
* 小说
|
||||
*/
|
||||
NOVELS("novel");
|
||||
|
||||
public final String jsonKey;
|
||||
|
||||
SearchArea(String jsonKey) {
|
||||
this.jsonKey = jsonKey;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索模式
|
||||
*/
|
||||
public enum SearchMode {
|
||||
/**
|
||||
* 按标签搜索, 部分一致
|
||||
*/
|
||||
TAG,
|
||||
/**
|
||||
* 按标签搜索, 完全一致
|
||||
*/
|
||||
TAG_FULL,
|
||||
/**
|
||||
* 按标题和说明文字搜索
|
||||
*/
|
||||
TC
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索内容类型
|
||||
*/
|
||||
public enum SearchType {
|
||||
/**
|
||||
* 全部内容(插画、漫画、动图)
|
||||
*/
|
||||
ALL,
|
||||
/**
|
||||
* 插画和动图(不包括漫画)
|
||||
*/
|
||||
ILLUST_AND_UGOIRA,
|
||||
/**
|
||||
* 插图
|
||||
*/
|
||||
ILLUST,
|
||||
/**
|
||||
* 漫画
|
||||
*/
|
||||
MANGA,
|
||||
/**
|
||||
* 动图
|
||||
*/
|
||||
UGOIRA
|
||||
}
|
||||
|
||||
public enum SearchOrder {
|
||||
/**
|
||||
* 按旧排序
|
||||
*/
|
||||
DATE,
|
||||
/**
|
||||
* 按新排序
|
||||
*/
|
||||
DATE_D
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索内容选项
|
||||
*/
|
||||
public enum SearchContentOption {
|
||||
/**
|
||||
* 所有内容
|
||||
*/
|
||||
ALL,
|
||||
/**
|
||||
* 全年龄
|
||||
*/
|
||||
SAFE,
|
||||
/**
|
||||
* R18
|
||||
*/
|
||||
R18
|
||||
}
|
||||
|
||||
public enum RatioOption {
|
||||
/**
|
||||
* 横向
|
||||
*/
|
||||
TRANSVERSE(0.5F),
|
||||
/**
|
||||
* 纵向
|
||||
*/
|
||||
PORTRAIT(-0.5F),
|
||||
/**
|
||||
* 正方形
|
||||
*/
|
||||
SQUARE(0F)
|
||||
;
|
||||
|
||||
public final float value;
|
||||
|
||||
RatioOption(float ratio) {
|
||||
this.value = ratio;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
171
src/main/java/net/lamgc/cgj/pixiv/PixivSession.java
Normal file
171
src/main/java/net/lamgc/cgj/pixiv/PixivSession.java
Normal file
@ -0,0 +1,171 @@
|
||||
package net.lamgc.cgj.pixiv;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.CookieStore;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.BasicCookieStore;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PixivSession {
|
||||
|
||||
public static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36";
|
||||
|
||||
/**
|
||||
* 全登陆过程的关键,
|
||||
* 保存会话用的cookieStore!
|
||||
*/
|
||||
private CookieStore cookieStore = new BasicCookieStore();
|
||||
|
||||
/**
|
||||
* 可以直接使用的HttpClient对象
|
||||
*/
|
||||
private HttpClient httpClient;
|
||||
|
||||
/**
|
||||
* 最后一次登录的错误信息
|
||||
*/
|
||||
private String errMsg;
|
||||
|
||||
public PixivSession(){
|
||||
this(null);
|
||||
}
|
||||
|
||||
public PixivSession(CookieStore cookieStore){
|
||||
this(null, cookieStore);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个Pixiv登录会话
|
||||
*/
|
||||
public PixivSession(HttpHost proxy, CookieStore cookieStore) {
|
||||
if(cookieStore != null){
|
||||
this.cookieStore = cookieStore;
|
||||
}
|
||||
List<Header> defaultHeader = new ArrayList<>();
|
||||
defaultHeader.add(new BasicHeader("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"));
|
||||
defaultHeader.add(new BasicHeader("user-agent", PixivSession.USER_AGENT));
|
||||
defaultHeader.add(new BasicHeader("accept-encoding", "gzip, deflate, br"));
|
||||
defaultHeader.add(new BasicHeader("accept-language", "zh-CN,zh;q=0.9"));
|
||||
|
||||
/*defaultHeader.add(new BasicHeader("sec-fetch-mode", "navigate"));
|
||||
defaultHeader.add(new BasicHeader("sec-fetch-site", "same-origin"));
|
||||
defaultHeader.add(new BasicHeader("upgrade-insecure-requests", "1"));*/
|
||||
//创建一个Http访问器
|
||||
httpClient = HttpClients.custom()
|
||||
.setDefaultCookieStore(cookieStore)
|
||||
.setDefaultHeaders(defaultHeader)
|
||||
.setProxy(proxy)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 程序自行通过帐号密码登录Pixiv.
|
||||
* @param PixivID Pixiv帐号
|
||||
* @param Password Pixiv密码
|
||||
* @return 登录成功返回true
|
||||
* @throws IOException 当登录抛出异常时返回
|
||||
* @deprecated Pixiv已经新增Google人机验证, 程序已无法自行登录Pixiv
|
||||
*/
|
||||
public boolean Login(String PixivID, String Password) throws IOException {
|
||||
// 获取登录接口所需的PostKey
|
||||
String post_key = getPostKey();
|
||||
HttpPost postRequest = new HttpPost(PixivURL.PIXIV_LOGIN_URL); //https://accounts.pixiv.net/api/login?lang=zh
|
||||
List<NameValuePair> params = new ArrayList<>();
|
||||
params.add(new BasicNameValuePair("pixiv_id", PixivID));
|
||||
params.add(new BasicNameValuePair("password", Password));
|
||||
params.add(new BasicNameValuePair("post_key", post_key));
|
||||
//Form编码表单,作为Post的数据
|
||||
postRequest.setEntity(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8));
|
||||
//启动访问
|
||||
HttpResponse response = httpClient.execute(postRequest);
|
||||
//获取接口返回数据
|
||||
String httpXML = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
|
||||
System.out.println(httpXML);
|
||||
JsonObject responseJson = (JsonObject) new JsonParser().parse(httpXML);
|
||||
if(!responseJson.get("error").getAsBoolean() && !responseJson.get("body").getAsJsonObject().has("validation_errors")){
|
||||
errMsg = null;
|
||||
return true;
|
||||
}else{
|
||||
errMsg = responseJson.get("body").getAsJsonObject().get("validation_errors").toString();
|
||||
//System.err.println("登录失败!MSG: " + errMsg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录前准备, 获取PostKey
|
||||
* @return Post_Key
|
||||
*/
|
||||
private String getPostKey() throws IOException {
|
||||
//创建请求,获取PostKey
|
||||
HttpGet getRequest = new HttpGet(PixivURL.PIXIV_LOGIN_PAGE_URL);
|
||||
//设置请求
|
||||
//getRequest.setConfig(config);
|
||||
getRequest.setHeader("User-Agent", USER_AGENT);
|
||||
//启动访问
|
||||
HttpResponse response = httpClient.execute(getRequest);
|
||||
//获取网页内容
|
||||
String pageAsXML = EntityUtils.toString(response.getEntity(),"utf-8");
|
||||
//创建Http解析器
|
||||
Document document = Jsoup.parse(pageAsXML);
|
||||
//获取init-config内容
|
||||
String init_config = document.getElementById("init-config").val();
|
||||
//System.out.println(init_config);
|
||||
//创建Json解析器解析init-config
|
||||
JsonObject initConfigObj = (JsonObject) new JsonParser().parse(init_config);
|
||||
//检查是否有postKey
|
||||
if(!initConfigObj.has("pixivAccount.postKey")){
|
||||
throw new RuntimeException("postKey获取失败!可能是Pixiv修改了登录过程!");
|
||||
}
|
||||
//获取postKey
|
||||
return initConfigObj.get("pixivAccount.postKey").getAsString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取CookieStore
|
||||
* @return CookieStore
|
||||
*/
|
||||
public CookieStore getCookieStore(){
|
||||
return cookieStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可直接使用的HttpClient对象
|
||||
* @return 已配置好的HttpClient对象
|
||||
*/
|
||||
public HttpClient getHttpClient(){
|
||||
return this.httpClient;
|
||||
}
|
||||
|
||||
public boolean hasError(){
|
||||
return errMsg == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取错误信息
|
||||
* @return 返回登录错误信息
|
||||
* @deprecated {@link #Login(String, String)}已经废除, 故本接口废除
|
||||
*/
|
||||
public String getErrMsg(){
|
||||
return errMsg;
|
||||
}
|
||||
|
||||
}
|
16
src/main/java/net/lamgc/cgj/pixiv/PixivTag.java
Normal file
16
src/main/java/net/lamgc/cgj/pixiv/PixivTag.java
Normal file
@ -0,0 +1,16 @@
|
||||
package net.lamgc.cgj.pixiv;
|
||||
|
||||
public class PixivTag {
|
||||
|
||||
public static PixivTag create(String tagName) {
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private PixivTag() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
290
src/main/java/net/lamgc/cgj/pixiv/PixivURL.java
Normal file
290
src/main/java/net/lamgc/cgj/pixiv/PixivURL.java
Normal file
@ -0,0 +1,290 @@
|
||||
package net.lamgc.cgj.pixiv;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
/**
|
||||
* 目前已整理的一些Pixiv接口列表
|
||||
*/
|
||||
public class PixivURL {
|
||||
|
||||
|
||||
public static final String PIXIV_INDEX_URL = "https://www.pixiv.net";
|
||||
|
||||
/**
|
||||
* P站预登陆url
|
||||
*/
|
||||
public static final String PIXIV_LOGIN_PAGE_URL = "https://accounts.pixiv.net/login?lang=zh&source=pc&view_type=page&ref=wwwtop_accounts_index";
|
||||
|
||||
/**
|
||||
* P站登录请求url
|
||||
*/
|
||||
public static final String PIXIV_LOGIN_URL = "https://accounts.pixiv.net/api/login?lang=zh";
|
||||
|
||||
/**
|
||||
* P站搜索请求url
|
||||
*/
|
||||
private static final String PIXIV_SEARCH_URL = "https://www.pixiv.net/search.php";
|
||||
|
||||
/**
|
||||
* P站搜索用户url
|
||||
* 需要替换的参数:
|
||||
* {nick} - 用户昵称、部分名称
|
||||
*/
|
||||
public static final String PIXIV_SEARCH_USER_URL = PIXIV_SEARCH_URL + "?s_mode=s_usr&nick={nick}";
|
||||
|
||||
/**
|
||||
* P站搜索插画url
|
||||
* 需要替换的参数:
|
||||
* {word} - 插画相关文本
|
||||
*/
|
||||
public static final String PIXIV_SEARCH_TAG_URL = PIXIV_SEARCH_URL + "?s_mode=s_tag&word={word}";
|
||||
|
||||
/**
|
||||
* P站插图下载链接获取url
|
||||
* 需要替换的文本:
|
||||
* {illustId} - 插画ID
|
||||
*/
|
||||
public static final String PIXIV_ILLUST_API_URL = "https://www.pixiv.net/ajax/illust/{illustId}/pages";
|
||||
|
||||
/*
|
||||
* P站用户插图列表获取API
|
||||
* 需要替换的文本:
|
||||
* {userId} - 用户ID
|
||||
*/
|
||||
//TODO: 所需数据在 body属性内的 illusts(属性名,属性值不重要), manga(多图) pickup(精选)
|
||||
//{"error":false,"message":"","body":{"illusts":{"74369837":null,"70990542":null,"70608653":null,"69755191":null,"69729450":null,"69729416":null,"69503608":null,"69288766":null,"69083882":null,"69051458":null,"68484200":null,"68216927":null,"68216866":null,"68192333":null,"67915106":null,"67914932":null,"67854803":null,"67854745":null,"67854670":null,"67787211":null,"67772199":null,"67770637":null,"67754861":null,"67754804":null,"67754726":null,"67740486":null,"67740480":null,"67740450":null,"67740434":null,"67726337":null,"67499196":null,"67499163":null,"67499145":null,"67499111":null,"67499085":null,"67499038":null,"67498987":null,"67473178":null,"66271465":null,"63682753":null,"63682697":null,"59385148":null,"59383265":null,"59383240":null,"59383227":null,"59383173":null},"manga":[],"novels":[],"mangaSeries":[],"novelSeries":[],"pickup":[],"bookmarkCount":{"public":{"illust":1,"novel":0},"private":{"illust":0,"novel":0}}}}
|
||||
//public static final String PIXIV_USER_ILLUST_LIST_URL = "https://www.pixiv.net/ajax/user/{userId}/profile/all";
|
||||
|
||||
/**
|
||||
* 能够同时获取插图信息的用户插图列表获取API
|
||||
*/
|
||||
public static final String PIXIV_USER_ILLUSTINFO_LIST_URL = "https://www.pixiv.net/ajax/user/{userId}/profile/top";
|
||||
|
||||
/**
|
||||
* P站单图详情页url
|
||||
* 需要替换的文本:
|
||||
* {illustId} - 插画ID
|
||||
*/
|
||||
public static final String PIXIV_ILLUST_MEDIUM_URL = "https://www.pixiv.net/member_illust.php?mode=medium&illust_id={illustId}";
|
||||
|
||||
/**
|
||||
* P站多图详情页url
|
||||
* 需要替换的文本:
|
||||
* {illustId} - 插画ID
|
||||
*/
|
||||
public static final String PIXIV_ILLUST_MANGA_URL = "https://www.pixiv.net/member_illust.php?mode=manga&illust_id={illustId}";
|
||||
|
||||
/**
|
||||
* P站用户页面url
|
||||
* 需要替换的文本:
|
||||
* {userId} - 用户ID
|
||||
*/
|
||||
public static final String PIXIV_USER_URL = "https://www.pixiv.net/member.php?id={userId}";
|
||||
|
||||
/**
|
||||
* P站插图信息获取API
|
||||
* 这个API能获取插图基本信息,但不能获取大小
|
||||
* 请使用{@link #getPixivIllustInfoAPI(int[])}获取URL
|
||||
*/
|
||||
private static final String PIXIV_GET_ILLUST_INFO_URL = "https://www.pixiv.net/ajax/illust/recommend/illusts?";
|
||||
|
||||
/**
|
||||
* P站获取用户所有插图ID的Api
|
||||
* 这个API只能获取该用户的插图ID,不能获取图片信息(图片信息要另外获取)
|
||||
* 需要替换的文本:
|
||||
* {userId} - 用户ID
|
||||
*/
|
||||
public static final String PIXIV_GET_USER_ALL_ILLUST_ID_URL = "https://www.pixiv.net/ajax/user/{userId}/profile/all";
|
||||
|
||||
/**
|
||||
* P站标签搜索URL
|
||||
* 可以将Tag的大概内容搜索成P站精确的Tag,以搜索其他接口返回的Tags数组;
|
||||
* 需要替换的文本:
|
||||
* {content} - 大致tag内容
|
||||
*/
|
||||
public static final String PIXIV_TAG_SEARCH_URL = "https://www.pixiv.net/ajax/search/tags/{content}";
|
||||
|
||||
/**
|
||||
* 请求时带上需要退出的Cookies
|
||||
* 无论成功与否都会返回302重定向到{@linkplain #PIXIV_LOGIN_PAGE_URL 登录页面}
|
||||
*/
|
||||
public static final String PIXIV_LOGOUT_URL = "https://www.pixiv.net/logout.php";
|
||||
|
||||
/**
|
||||
* 构造P站获取插图信息的Api Url
|
||||
* @param illustIds 要查询的插图ID数组
|
||||
* @return 对应查询的API Url
|
||||
*/
|
||||
public static String getPixivIllustInfoAPI(int[] illustIds){
|
||||
StringBuilder strBuilder = new StringBuilder().append(PIXIV_GET_ILLUST_INFO_URL);
|
||||
for(int illustId : illustIds){
|
||||
strBuilder.append("illust_ids[]=").append(illustId).append("&");
|
||||
}
|
||||
return strBuilder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用于下载图片时防盗链所需Referer的链接
|
||||
* @param illustId 欲下载图片所属illustId
|
||||
* @return 返回Referer链接, 也可以作为作品链接使用
|
||||
*/
|
||||
public static String getPixivRefererLink(int illustId){
|
||||
return "https://www.pixiv.net/artworks/" + illustId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用于下载图片时防盗链所需Referer的链接
|
||||
* @param illustId 欲下载图片所属illustId
|
||||
* @return 返回Referer链接, 也可以作为作品链接使用
|
||||
*/
|
||||
public static String getPixivRefererLink(String illustId){
|
||||
return "https://www.pixiv.net/artworks/" + illustId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 排行榜接口, 需加入"&format=json"
|
||||
*/
|
||||
private final static String PIXIV_RANKING_LINK = "https://www.pixiv.net/ranking.php?";
|
||||
|
||||
/**
|
||||
* 查询用户收藏.<br/>
|
||||
* 该URL返回HTML页面,需要进行解析.<br/>
|
||||
* 需要替换的文本:<br/>
|
||||
* {pageIndex} - 页数, 超出了则结果为空<br/>
|
||||
*/
|
||||
public final static String PIXIV_USER_COLLECTION_PAGE = "https://www.pixiv.net/bookmark.php?rest=show&p={pageIndex}";
|
||||
|
||||
/**
|
||||
* 获取排名榜
|
||||
* @param mode 查询类型, 详细信息看{@link RankingMode}, 如本参数为null, 则为每天
|
||||
* @param contentType 排名榜类型, 如为null则为综合
|
||||
* @param time 欲查询的时间, 最新只能查询昨天, 根据mode不同:
|
||||
* 每天 - 查询指定日期的排名榜
|
||||
* 每周 - 查询指定时间结束(含)到七天前一段时间内的排名榜
|
||||
* 每月 - 查询指定日期结束(含)到28天时间内的排名榜
|
||||
* 新人 - 与每周相同
|
||||
* 受男性欢迎 - 与每天相同
|
||||
* 受女性欢迎 - 与每天相同
|
||||
* 默认值为昨天
|
||||
* @param pageIndex 页数,一页50位,总共10页
|
||||
* @return 返回构建好的链接
|
||||
*/
|
||||
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){
|
||||
linkBuilder.append("&content=").append(contentType.typeName);
|
||||
}
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
|
||||
Date queryDate;
|
||||
if(time == null){
|
||||
GregorianCalendar gregorianCalendar = new GregorianCalendar();
|
||||
gregorianCalendar.setTime(new Date());
|
||||
gregorianCalendar.add(Calendar.DATE, -1);
|
||||
queryDate = gregorianCalendar.getTime();
|
||||
} else {
|
||||
queryDate = time;
|
||||
}
|
||||
linkBuilder.append("&date=").append(format.format(queryDate));
|
||||
if(pageIndex > 0 && pageIndex <= 10) {
|
||||
linkBuilder.append("&p=").append(pageIndex);
|
||||
}
|
||||
if(json) {
|
||||
linkBuilder.append("&format=").append("json");
|
||||
}
|
||||
return linkBuilder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 排名榜模式
|
||||
*/
|
||||
public enum RankingMode{
|
||||
/**
|
||||
* 每天
|
||||
*/
|
||||
MODE_DAILY("daily"),
|
||||
/**
|
||||
* 每周
|
||||
*/
|
||||
MODE_WEEKLY("weekly"),
|
||||
/**
|
||||
* 每月
|
||||
*/
|
||||
MODE_MONTHLY("monthly"),
|
||||
/**
|
||||
* 新人
|
||||
*/
|
||||
MODE_ROOKIE("rookie"),
|
||||
/**
|
||||
* 受男性喜欢
|
||||
*/
|
||||
MODE_MALE("male"),
|
||||
/**
|
||||
* 受女性喜欢
|
||||
*/
|
||||
MODE_FEMALE("female"),
|
||||
|
||||
/**
|
||||
* 每天 - R18
|
||||
*/
|
||||
MODE_DAILY_R18("daily_r18"),
|
||||
/**
|
||||
* 每周 - R18
|
||||
*/
|
||||
MODE_WEEKLY_R18("weekly_r18"),
|
||||
/**
|
||||
* 受男性喜欢 - R18
|
||||
*/
|
||||
MODE_MALE_R18("male_r18"),
|
||||
/**
|
||||
* 受女性喜欢 - R18
|
||||
*/
|
||||
MODE_FEMALE_R18("female_r18"),
|
||||
;
|
||||
public String modeParam;
|
||||
|
||||
RankingMode(String modeParamName){
|
||||
this.modeParam = modeParamName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pixiv搜索接口.<br/>
|
||||
* 要使用该链接请使用{@link PixivSearchBuilder}构造链接.<br/>
|
||||
* 需要替换的参数: <br/>
|
||||
* content - 搜索内容
|
||||
*/
|
||||
final static String PIXIV_SEARCH_CONTENT_URL = "https://www.pixiv.net/ajax/search/{area}/{content}?word={content}";
|
||||
|
||||
/**
|
||||
* 排名榜类型
|
||||
*/
|
||||
public enum RankingContentType{
|
||||
/**
|
||||
* 插画
|
||||
* 支持的时间类型: 每天, 每周, 每月, 新人
|
||||
*/
|
||||
TYPE_ILLUST("illust"),
|
||||
/**
|
||||
* 动图
|
||||
* 支持的时间类型:每天, 每周
|
||||
*/
|
||||
TYPE_UGOIRA("ugoira"),
|
||||
/**
|
||||
* 漫画
|
||||
* 支持的时间类型: 每天, 每周, 每月, 新人
|
||||
*/
|
||||
TYPE_MANGA("manga")
|
||||
;
|
||||
|
||||
String typeName;
|
||||
|
||||
RankingContentType(String typeName){
|
||||
this.typeName = typeName;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user