pull/5/head
parent
f61af8d6d1
commit
71d38f1bc4
@ -0,0 +1,36 @@ |
||||
<component name="InspectionProjectProfileManager"> |
||||
<profile version="1.0"> |
||||
<option name="myName" value="Project Default" /> |
||||
<inspection_tool class="JavaDoc" enabled="true" level="WARNING" enabled_by_default="true"> |
||||
<option name="TOP_LEVEL_CLASS_OPTIONS"> |
||||
<value> |
||||
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" /> |
||||
<option name="REQUIRED_TAGS" value="" /> |
||||
</value> |
||||
</option> |
||||
<option name="INNER_CLASS_OPTIONS"> |
||||
<value> |
||||
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" /> |
||||
<option name="REQUIRED_TAGS" value="" /> |
||||
</value> |
||||
</option> |
||||
<option name="METHOD_OPTIONS"> |
||||
<value> |
||||
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" /> |
||||
<option name="REQUIRED_TAGS" value="@return@param@throws or @exception" /> |
||||
</value> |
||||
</option> |
||||
<option name="FIELD_OPTIONS"> |
||||
<value> |
||||
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" /> |
||||
<option name="REQUIRED_TAGS" value="" /> |
||||
</value> |
||||
</option> |
||||
<option name="IGNORE_DEPRECATED" value="false" /> |
||||
<option name="IGNORE_JAVADOC_PERIOD" value="true" /> |
||||
<option name="IGNORE_DUPLICATED_THROWS" value="false" /> |
||||
<option name="IGNORE_POINT_TO_ITSELF" value="false" /> |
||||
<option name="myAdditionalJavadocTags" value="date" /> |
||||
</inspection_tool> |
||||
</profile> |
||||
</component> |
@ -0,0 +1,10 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project version="4"> |
||||
<component name="RunConfigurationProducerService"> |
||||
<option name="ignoredProducers"> |
||||
<set> |
||||
<option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" /> |
||||
</set> |
||||
</option> |
||||
</component> |
||||
</project> |
@ -1,16 +0,0 @@ |
||||
package xyz.fycz.myreader.application; |
||||
|
||||
import java.security.cert.X509Certificate; |
||||
|
||||
import javax.net.ssl.X509TrustManager; |
||||
|
||||
public class TrustAllCerts implements X509TrustManager { |
||||
@Override |
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) {} |
||||
|
||||
@Override |
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) {} |
||||
|
||||
@Override |
||||
public X509Certificate[] getAcceptedIssuers() {return new X509Certificate[0];} |
||||
} |
@ -1,34 +0,0 @@ |
||||
package xyz.fycz.myreader.common; |
||||
|
||||
|
||||
|
||||
public class ErrorCode { |
||||
|
||||
public static final int login_not_user = 1; // 用户不存在
|
||||
public static final int login_not_password = 2;// 密码错误
|
||||
public static final int internet_waring = 3;// 网络访问错误
|
||||
public static final int no_security = 4;// 没有权限(登陆过期)
|
||||
public static final int no_login_ = 5;// 没有登录
|
||||
public static final int meeting_user_no = 6;// 报名用户不存在
|
||||
public static final int old_password = 8;// 原密码错误
|
||||
public static final int execute_error = 7;//程序运行异常
|
||||
public static final int order_timeout = 9;// 订餐超时
|
||||
public static final int email_or_emailPwd_empty = 10;//邮箱或邮箱密码为空
|
||||
public static final int email_login_error = 11;//邮箱登陆失败
|
||||
public static final int email_params_error = 12;//邮箱接口参数不完整
|
||||
public static final int suggestion_params_error = 13;//反馈意见接口参数不完整
|
||||
public static final int email_addresses_error = 15;//邮箱地址无效
|
||||
public static final int uploadfile_extend_error = 16;//上传附件后缀不支持
|
||||
public static final int params_overlength = 17;//接口参数过长
|
||||
public static final int leave_error = 18;//请假审批人跟请假人不能相同
|
||||
public static final int login_simple_pwd = 19;//简单登录密码
|
||||
|
||||
|
||||
public static final int more_depart = 1011;//多部门用户
|
||||
public static final int Certificate_sys_no_user = 1012;//认证系统内无此用户
|
||||
public static final int Certificate_no_bind_user = 1013;//用户没绑定证书在系统内
|
||||
public static final int ukey_duplicate_user = 1014;//ukey序列号系统中不存在或存在多笔数据,请联系管理员
|
||||
|
||||
|
||||
|
||||
} |
@ -0,0 +1,266 @@ |
||||
package xyz.fycz.myreader.entity.thirdsource; |
||||
|
||||
import com.google.gson.Gson; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import kotlin.jvm.Transient; |
||||
|
||||
// 解析阅读3.0的书源规则,toBookSourceBean()方法转换为阅读2.0书源规则
|
||||
// https://raw.githubusercontent.com/gedoor/legado/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt
|
||||
public class BookSource3Bean { |
||||
private String bookSourceName = ""; // 名称
|
||||
private String bookSourceGroup; // 分组
|
||||
private String bookSourceUrl = ""; // 地址,包括 http/https
|
||||
private int bookSourceType = 0; // 类型,0 文本,1 音频
|
||||
private String bookUrlPattern; // 详情页url正则
|
||||
private int customOrder = 0; // 手动排序编号
|
||||
private Boolean enabled = true; // 是否启用
|
||||
private Boolean enabledExplore = true; // 启用发现
|
||||
private String header; // 请求头
|
||||
private String loginUrl; // 登录地址
|
||||
private String bookSourceComment; // 注释
|
||||
private Long lastUpdateTime = 0L; // 最后更新时间,用于排序
|
||||
private int weight = 0; // 智能排序的权重
|
||||
private String exploreUrl; // 发现url
|
||||
private ExploreRule ruleExplore; // 发现规则
|
||||
private String searchUrl; // 搜索url
|
||||
private SearchRule ruleSearch; // 搜索规则
|
||||
private BookInfoRule ruleBookInfo; // 书籍信息页规则
|
||||
private TocRule ruleToc; // 目录页规则
|
||||
private ContentRule ruleContent; // 正文页规则
|
||||
|
||||
@Transient |
||||
private String userAgent; |
||||
@Transient |
||||
private String RuleSearchUrl; |
||||
|
||||
class ContentRule { |
||||
String content; |
||||
String nextContentUrl; |
||||
String webJs; |
||||
String sourceRegex; |
||||
String replaceRegex; |
||||
String imageStyle; //默认大小居中,FULL最大宽度
|
||||
} |
||||
|
||||
class TocRule { |
||||
String chapterList; |
||||
String chapterName; |
||||
String chapterUrl; |
||||
String isVip; |
||||
String updateTime; |
||||
String nextTocUrl; |
||||
} |
||||
|
||||
class BookInfoRule { |
||||
String init; |
||||
String name; |
||||
String author; |
||||
String intro; |
||||
String kind; |
||||
String lastChapter; |
||||
String updateTime; |
||||
String coverUrl; |
||||
String tocUrl; |
||||
String wordCount; |
||||
} |
||||
|
||||
class SearchRule { |
||||
String bookList; |
||||
String name; |
||||
String author; |
||||
String intro; |
||||
String kind; |
||||
String lastChapter; |
||||
String updateTime; |
||||
String bookUrl; |
||||
String coverUrl; |
||||
String wordCount; |
||||
} |
||||
|
||||
class ExploreRule { |
||||
String bookList; |
||||
String name; |
||||
String author; |
||||
String intro; |
||||
String kind; |
||||
String lastChapter; |
||||
String updateTime; |
||||
String bookUrl; |
||||
String coverUrl; |
||||
String wordCount; |
||||
} |
||||
|
||||
/* @Override |
||||
public Object clone() { |
||||
try { |
||||
Gson gson = new Gson(); |
||||
String json = gson.toJson(this); |
||||
return gson.fromJson(json, BookSource3Bean.class); |
||||
} catch (Exception ignored) { |
||||
} |
||||
return this; |
||||
}*/ |
||||
|
||||
// 给书源增加一个标签
|
||||
public BookSource3Bean addGroupTag(String tag) { |
||||
if (this.bookSourceGroup != null) { |
||||
//为了避免空格、首尾位置的差异造成影响,这里做循环处理
|
||||
String[] tags = (this.bookSourceGroup + ";" + tag).split(";"); |
||||
|
||||
List<String> list = new ArrayList<>(); |
||||
list.add(tag); |
||||
for (String s : tags) { |
||||
if (!list.contains(s)) { |
||||
list.add(s); |
||||
} |
||||
} |
||||
bookSourceGroup = tag; |
||||
for (int i = 1; i < list.size(); i++) { |
||||
bookSourceGroup = bookSourceGroup + ";" + list.get(i); |
||||
} |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
class httpRequest { |
||||
String method; |
||||
String body; |
||||
String headers; |
||||
String charset; |
||||
} |
||||
|
||||
private String searchUrl2RuleSearchUrl(String searchUrl) { |
||||
String RuleSearchUrl = searchUrl; |
||||
if (searchUrl != null) { |
||||
String q = ""; |
||||
if (searchUrl.replaceAll("\\s", "").matches("^[^,]+,\\{.+\\}")) { |
||||
// 正常网址不包含逗号
|
||||
String[] strings = searchUrl.split(",", 2); |
||||
try { |
||||
Gson gson = new Gson(); |
||||
httpRequest request = gson.fromJson(strings[1], httpRequest.class); |
||||
if (gson.toJson(request).replaceAll("\\s", "").length() > 0) { |
||||
// 阅读2.0没有单独的header,只有useragent
|
||||
if (request.headers != null) { |
||||
if (this.header == null) |
||||
this.header = request.headers; |
||||
else if (request.headers.trim().length() < 1) |
||||
this.header = request.headers; |
||||
} |
||||
|
||||
if (request.charset != null) { |
||||
if (request.charset.trim().length() > 0) |
||||
q = q + "|char=" + request.charset; |
||||
} |
||||
|
||||
if (request.body != null) { |
||||
q = request.body |
||||
.replace("{{key}}", "searchKey") |
||||
.replaceFirst("\\{\\{([^{}]*)page([^{}]*)\\}\\}", "$1searchPage$2") |
||||
+ q; |
||||
|
||||
// post请求的关键词一定在第二部分
|
||||
if (request.method != null) { |
||||
if (request.method.toLowerCase().contains("post")) |
||||
q = "@" + q; |
||||
else |
||||
q = "?" + q; |
||||
} |
||||
return strings[0] + q; |
||||
} |
||||
|
||||
RuleSearchUrl = strings[0] + q; |
||||
} else |
||||
RuleSearchUrl = searchUrl; |
||||
|
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
RuleSearchUrl = searchUrl; |
||||
} |
||||
} |
||||
|
||||
return RuleSearchUrl.replaceAll("\\s", "") |
||||
.replace("{{key}}", "searchKey") |
||||
.replaceFirst("\\{\\{([^{}]*)page([^{}]*)\\}\\}", "$1searchPage$2") |
||||
; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public BookSourceBean toBookSourceBean() { |
||||
// 带注释的行,表示2.0/3.0书源json的数据命名不同。注释后方为2.0名称
|
||||
String bookSourceType = ""; |
||||
if (this.bookSourceType != 0) |
||||
bookSourceType = "" + this.bookSourceType; |
||||
|
||||
RuleSearchUrl = searchUrl2RuleSearchUrl(searchUrl); |
||||
|
||||
if (header != null && userAgent == null) { |
||||
if (header.matches("(?!).*(User-Agent).*")) |
||||
userAgent = header.replaceFirst("(?!).*(User-Agent)[\\s:]+\"([^\"]+)\".*", "$2"); |
||||
} |
||||
|
||||
String ruleFindUrl=null; |
||||
if(exploreUrl!=null){ |
||||
ruleFindUrl=exploreUrl.replaceAll("\\{\\{page\\}\\}","searchPage"); |
||||
} |
||||
|
||||
// 暂时只给发现和搜索添加了header
|
||||
String header=""; |
||||
if(this.header!=null){ |
||||
if(this.header.trim().length()>0) |
||||
header="@Header:"+this.header.replaceAll("\\n"," "); |
||||
} |
||||
|
||||
|
||||
return new BookSourceBean( |
||||
bookSourceUrl, |
||||
bookSourceName, |
||||
bookSourceGroup, |
||||
bookSourceType, |
||||
loginUrl, |
||||
lastUpdateTime, |
||||
0, //u serialNumber,
|
||||
weight, |
||||
true, //u enable,
|
||||
ruleFindUrl+header,//发现规则 ruleFindUrl,
|
||||
ruleExplore.bookList, // 列表 ruleFindList,
|
||||
ruleExplore.name,// ruleFindName,
|
||||
ruleExplore.author,// ruleFindAuthor,
|
||||
ruleExplore.kind,// ruleFindKind,
|
||||
ruleExplore.intro,// ruleFindIntroduce,
|
||||
ruleExplore.lastChapter,// ruleFindLastChapter,
|
||||
ruleExplore.coverUrl,// ruleFindCoverUrl,
|
||||
ruleExplore.bookUrl,//??? ruleFindNoteUrl,
|
||||
RuleSearchUrl+header,// ruleSearchUrl,
|
||||
ruleSearch.bookList,// ruleSearchList,
|
||||
ruleSearch.name,// ruleSearchName,
|
||||
ruleSearch.author,// ruleSearchAuthor,
|
||||
ruleSearch.kind,// ruleSearchKind,
|
||||
ruleSearch.intro,// ruleSearchIntroduce,
|
||||
ruleSearch.lastChapter,// ruleSearchLastChapter,
|
||||
ruleSearch.coverUrl,//ruleSearchCoverUrl,
|
||||
ruleSearch.bookUrl,// ruleSearchNoteUrl,
|
||||
bookUrlPattern, //??? ruleBookUrlPattern,
|
||||
ruleBookInfo.init,// ruleBookInfoInit,
|
||||
ruleBookInfo.name,// ruleBookName,
|
||||
ruleBookInfo.author,// ruleBookAuthor,
|
||||
ruleBookInfo.coverUrl,// ruleCoverUrl,
|
||||
ruleBookInfo.intro,// ruleIntroduce,
|
||||
ruleBookInfo.kind,// ruleBookKind,
|
||||
ruleBookInfo.lastChapter,// ruleBookLastChapter,
|
||||
ruleBookInfo.tocUrl,// ruleChapterUrl,
|
||||
ruleToc.nextTocUrl,// ruleChapterUrlNext,
|
||||
ruleToc.chapterList,// ruleChapterList,
|
||||
ruleToc.chapterName,// ruleChapterName,
|
||||
ruleToc.chapterUrl, // ruleContentUrl,
|
||||
ruleContent.nextContentUrl, //ruleContentUrlNext,
|
||||
ruleContent.content, // ruleBookContent,
|
||||
ruleContent.replaceRegex,// ruleBookContentReplace,
|
||||
userAgent // httpUserAgent
|
||||
); |
||||
} |
||||
} |
@ -0,0 +1,709 @@ |
||||
package xyz.fycz.myreader.entity.thirdsource; |
||||
|
||||
import android.text.TextUtils; |
||||
|
||||
import com.google.gson.Gson; |
||||
|
||||
import org.greenrobot.greendao.annotation.Entity; |
||||
import org.greenrobot.greendao.annotation.Generated; |
||||
import org.greenrobot.greendao.annotation.Id; |
||||
import org.greenrobot.greendao.annotation.NotNull; |
||||
import org.greenrobot.greendao.annotation.OrderBy; |
||||
import org.greenrobot.greendao.annotation.Transient; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Objects; |
||||
|
||||
import xyz.fycz.myreader.util.utils.StringUtils; |
||||
|
||||
import static android.text.TextUtils.isEmpty; |
||||
|
||||
/** |
||||
* Created by GKF on 2017/12/14. |
||||
* 书源信息 |
||||
*/ |
||||
@Entity |
||||
public class BookSourceBean implements Cloneable { |
||||
@Id |
||||
private String bookSourceUrl; |
||||
private String bookSourceName; |
||||
private String bookSourceGroup; |
||||
private String bookSourceType; |
||||
private String loginUrl; |
||||
private Long lastUpdateTime; |
||||
@OrderBy |
||||
private int serialNumber; |
||||
@OrderBy |
||||
@NotNull |
||||
private int weight = 0; |
||||
private boolean enable; |
||||
//发现规则
|
||||
private String ruleFindUrl; |
||||
private String ruleFindList; |
||||
private String ruleFindName; |
||||
private String ruleFindAuthor; |
||||
private String ruleFindKind; |
||||
private String ruleFindIntroduce; |
||||
private String ruleFindLastChapter; |
||||
private String ruleFindCoverUrl; |
||||
private String ruleFindNoteUrl; |
||||
//搜索规则
|
||||
private String ruleSearchUrl; |
||||
private String ruleSearchList; |
||||
private String ruleSearchName; |
||||
private String ruleSearchAuthor; |
||||
private String ruleSearchKind; |
||||
private String ruleSearchIntroduce; |
||||
private String ruleSearchLastChapter; |
||||
private String ruleSearchCoverUrl; |
||||
private String ruleSearchNoteUrl; |
||||
//详情页规则
|
||||
private String ruleBookUrlPattern; |
||||
private String ruleBookInfoInit; |
||||
private String ruleBookName; |
||||
private String ruleBookAuthor; |
||||
private String ruleCoverUrl; |
||||
private String ruleIntroduce; |
||||
private String ruleBookKind; |
||||
private String ruleBookLastChapter; |
||||
private String ruleChapterUrl; |
||||
//目录页规则
|
||||
private String ruleChapterUrlNext; |
||||
private String ruleChapterList; |
||||
private String ruleChapterName; |
||||
private String ruleContentUrl; |
||||
//正文页规则
|
||||
private String ruleContentUrlNext; |
||||
private String ruleBookContent; |
||||
private String ruleBookContentReplace; |
||||
private String httpUserAgent; |
||||
|
||||
@Transient |
||||
private transient ArrayList<String> groupList; |
||||
|
||||
@Generated(hash = 243497779) |
||||
public BookSourceBean(String bookSourceUrl, String bookSourceName, String bookSourceGroup, String bookSourceType, String loginUrl, Long lastUpdateTime, int serialNumber, int weight, boolean enable, String ruleFindUrl, String ruleFindList, |
||||
String ruleFindName, String ruleFindAuthor, String ruleFindKind, String ruleFindIntroduce, String ruleFindLastChapter, String ruleFindCoverUrl, String ruleFindNoteUrl, String ruleSearchUrl, String ruleSearchList, |
||||
String ruleSearchName, String ruleSearchAuthor, String ruleSearchKind, String ruleSearchIntroduce, String ruleSearchLastChapter, String ruleSearchCoverUrl, String ruleSearchNoteUrl, String ruleBookUrlPattern, |
||||
String ruleBookInfoInit, String ruleBookName, String ruleBookAuthor, String ruleCoverUrl, String ruleIntroduce, String ruleBookKind, String ruleBookLastChapter, String ruleChapterUrl, String ruleChapterUrlNext, |
||||
String ruleChapterList, String ruleChapterName, String ruleContentUrl, String ruleContentUrlNext, String ruleBookContent, String ruleBookContentReplace, String httpUserAgent) { |
||||
this.bookSourceUrl = bookSourceUrl; |
||||
this.bookSourceName = bookSourceName; |
||||
this.bookSourceGroup = bookSourceGroup; |
||||
this.bookSourceType = bookSourceType; |
||||
this.loginUrl = loginUrl; |
||||
this.lastUpdateTime = lastUpdateTime; |
||||
this.serialNumber = serialNumber; |
||||
this.weight = weight; |
||||
this.enable = enable; |
||||
this.ruleFindUrl = ruleFindUrl; |
||||
this.ruleFindList = ruleFindList; |
||||
this.ruleFindName = ruleFindName; |
||||
this.ruleFindAuthor = ruleFindAuthor; |
||||
this.ruleFindKind = ruleFindKind; |
||||
this.ruleFindIntroduce = ruleFindIntroduce; |
||||
this.ruleFindLastChapter = ruleFindLastChapter; |
||||
this.ruleFindCoverUrl = ruleFindCoverUrl; |
||||
this.ruleFindNoteUrl = ruleFindNoteUrl; |
||||
this.ruleSearchUrl = ruleSearchUrl; |
||||
this.ruleSearchList = ruleSearchList; |
||||
this.ruleSearchName = ruleSearchName; |
||||
this.ruleSearchAuthor = ruleSearchAuthor; |
||||
this.ruleSearchKind = ruleSearchKind; |
||||
this.ruleSearchIntroduce = ruleSearchIntroduce; |
||||
this.ruleSearchLastChapter = ruleSearchLastChapter; |
||||
this.ruleSearchCoverUrl = ruleSearchCoverUrl; |
||||
this.ruleSearchNoteUrl = ruleSearchNoteUrl; |
||||
this.ruleBookUrlPattern = ruleBookUrlPattern; |
||||
this.ruleBookInfoInit = ruleBookInfoInit; |
||||
this.ruleBookName = ruleBookName; |
||||
this.ruleBookAuthor = ruleBookAuthor; |
||||
this.ruleCoverUrl = ruleCoverUrl; |
||||
this.ruleIntroduce = ruleIntroduce; |
||||
this.ruleBookKind = ruleBookKind; |
||||
this.ruleBookLastChapter = ruleBookLastChapter; |
||||
this.ruleChapterUrl = ruleChapterUrl; |
||||
this.ruleChapterUrlNext = ruleChapterUrlNext; |
||||
this.ruleChapterList = ruleChapterList; |
||||
this.ruleChapterName = ruleChapterName; |
||||
this.ruleContentUrl = ruleContentUrl; |
||||
this.ruleContentUrlNext = ruleContentUrlNext; |
||||
this.ruleBookContent = ruleBookContent; |
||||
this.ruleBookContentReplace = ruleBookContentReplace; |
||||
this.httpUserAgent = httpUserAgent; |
||||
} |
||||
|
||||
public BookSourceBean(BookSourceBean sourceBean) { |
||||
this.bookSourceUrl = sourceBean.bookSourceUrl; |
||||
this.bookSourceName = sourceBean.bookSourceName; |
||||
this.bookSourceGroup = sourceBean.bookSourceGroup; |
||||
this.bookSourceType = sourceBean.bookSourceType; |
||||
this.loginUrl = sourceBean.loginUrl; |
||||
this.lastUpdateTime = sourceBean.lastUpdateTime; |
||||
this.serialNumber = sourceBean.serialNumber; |
||||
this.weight = sourceBean.weight; |
||||
this.enable = sourceBean.enable; |
||||
this.ruleFindUrl = sourceBean.ruleFindUrl; |
||||
this.ruleFindList = sourceBean.ruleFindList; |
||||
this.ruleFindName = sourceBean.ruleFindName; |
||||
this.ruleFindAuthor = sourceBean.ruleFindAuthor; |
||||
this.ruleFindKind = sourceBean.ruleFindKind; |
||||
this.ruleFindIntroduce = sourceBean.ruleFindIntroduce; |
||||
this.ruleFindLastChapter = sourceBean.ruleFindLastChapter; |
||||
this.ruleFindCoverUrl = sourceBean.ruleFindCoverUrl; |
||||
this.ruleFindNoteUrl = sourceBean.ruleFindNoteUrl; |
||||
this.ruleSearchUrl = sourceBean.ruleSearchUrl; |
||||
this.ruleSearchList = sourceBean.ruleSearchList; |
||||
this.ruleSearchName = sourceBean.ruleSearchName; |
||||
this.ruleSearchAuthor = sourceBean.ruleSearchAuthor; |
||||
this.ruleSearchKind = sourceBean.ruleSearchKind; |
||||
this.ruleSearchIntroduce = sourceBean.ruleSearchIntroduce; |
||||
this.ruleSearchLastChapter = sourceBean.ruleSearchLastChapter; |
||||
this.ruleSearchCoverUrl = sourceBean.ruleSearchCoverUrl; |
||||
this.ruleSearchNoteUrl = sourceBean.ruleSearchNoteUrl; |
||||
this.ruleBookUrlPattern = sourceBean.ruleBookUrlPattern; |
||||
this.ruleBookInfoInit = sourceBean.ruleBookInfoInit; |
||||
this.ruleBookName = sourceBean.ruleBookName; |
||||
this.ruleBookAuthor = sourceBean.ruleBookAuthor; |
||||
this.ruleCoverUrl = sourceBean.ruleCoverUrl; |
||||
this.ruleIntroduce = sourceBean.ruleIntroduce; |
||||
this.ruleBookKind = sourceBean.ruleBookKind; |
||||
this.ruleBookLastChapter = sourceBean.ruleBookLastChapter; |
||||
this.ruleChapterUrl = sourceBean.ruleChapterUrl; |
||||
this.ruleChapterUrlNext = sourceBean.ruleChapterUrlNext; |
||||
this.ruleChapterList = sourceBean.ruleChapterList; |
||||
this.ruleChapterName = sourceBean.ruleChapterName; |
||||
this.ruleContentUrl = sourceBean.ruleContentUrl; |
||||
this.ruleContentUrlNext = sourceBean.ruleContentUrlNext; |
||||
this.ruleBookContent = sourceBean.ruleBookContent; |
||||
this.ruleBookContentReplace = sourceBean.ruleBookContentReplace; |
||||
this.httpUserAgent = sourceBean.httpUserAgent; |
||||
} |
||||
|
||||
public BookSourceBean() { |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object obj) { |
||||
if (obj instanceof BookSourceBean) { |
||||
BookSourceBean bs = (BookSourceBean) obj; |
||||
return stringEquals(bookSourceUrl, bs.bookSourceUrl) |
||||
&& stringEquals(bookSourceName, bs.bookSourceName) |
||||
&& stringEquals(bookSourceType, bs.bookSourceType) |
||||
&& stringEquals(loginUrl, bs.loginUrl) |
||||
&& stringEquals(bookSourceGroup, bs.bookSourceGroup) |
||||
&& stringEquals(ruleBookName, bs.ruleBookName) |
||||
&& stringEquals(ruleBookAuthor, bs.ruleBookAuthor) |
||||
&& stringEquals(ruleChapterUrl, bs.ruleChapterUrl) |
||||
&& stringEquals(ruleChapterUrlNext, ruleChapterUrlNext) |
||||
&& stringEquals(ruleCoverUrl, bs.ruleCoverUrl) |
||||
&& stringEquals(ruleIntroduce, bs.ruleIntroduce) |
||||
&& stringEquals(ruleChapterList, bs.ruleChapterList) |
||||
&& stringEquals(ruleChapterName, bs.ruleChapterName) |
||||
&& stringEquals(ruleContentUrl, bs.ruleContentUrl) |
||||
&& stringEquals(ruleContentUrlNext, bs.ruleContentUrlNext) |
||||
&& stringEquals(ruleBookContent, bs.ruleBookContent) |
||||
&& stringEquals(ruleSearchUrl, bs.ruleSearchUrl) |
||||
&& stringEquals(ruleSearchList, bs.ruleSearchList) |
||||
&& stringEquals(ruleSearchName, bs.ruleSearchName) |
||||
&& stringEquals(ruleSearchAuthor, bs.ruleSearchAuthor) |
||||
&& stringEquals(ruleSearchKind, bs.ruleSearchKind) |
||||
&& stringEquals(ruleSearchLastChapter, bs.ruleSearchLastChapter) |
||||
&& stringEquals(ruleSearchCoverUrl, bs.ruleSearchCoverUrl) |
||||
&& stringEquals(ruleSearchNoteUrl, bs.ruleSearchNoteUrl) |
||||
&& stringEquals(httpUserAgent, bs.httpUserAgent) |
||||
&& stringEquals(ruleBookKind, bs.ruleBookKind) |
||||
&& stringEquals(ruleBookLastChapter, bs.ruleBookLastChapter) |
||||
&& stringEquals(ruleBookUrlPattern, bs.ruleBookUrlPattern) |
||||
&& stringEquals(ruleBookContentReplace, bs.ruleBookContentReplace); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
private Boolean stringEquals(String str1, String str2) { |
||||
return Objects.equals(str1, str2) || (isEmpty(str1) && isEmpty(str2)); |
||||
} |
||||
|
||||
@Override |
||||
public Object clone() { |
||||
try { |
||||
Gson gson = new Gson(); |
||||
String json = gson.toJson(this); |
||||
return gson.fromJson(json, BookSourceBean.class); |
||||
} catch (Exception ignored) { |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
public String getBookSourceName() { |
||||
return bookSourceName; |
||||
} |
||||
|
||||
public void setBookSourceName(String bookSourceName) { |
||||
this.bookSourceName = bookSourceName; |
||||
} |
||||
|
||||
public String getBookSourceUrl() { |
||||
return bookSourceUrl; |
||||
} |
||||
|
||||
public void setBookSourceUrl(String bookSourceUrl) { |
||||
this.bookSourceUrl = bookSourceUrl; |
||||
} |
||||
|
||||
public int getSerialNumber() { |
||||
return this.serialNumber; |
||||
} |
||||
|
||||
public void setSerialNumber(int serialNumber) { |
||||
this.serialNumber = serialNumber; |
||||
} |
||||
|
||||
public int getWeight() { |
||||
return this.weight; |
||||
} |
||||
|
||||
public void setWeight(int weight) { |
||||
this.weight = weight; |
||||
} |
||||
|
||||
// 换源时选择的源权重+500
|
||||
public void increaseWeightBySelection() { |
||||
this.weight += 500; |
||||
} |
||||
|
||||
public void increaseWeight(int increase) { |
||||
this.weight += increase; |
||||
} |
||||
|
||||
public boolean getEnable() { |
||||
return this.enable; |
||||
} |
||||
|
||||
public void setEnable(boolean enable) { |
||||
this.enable = enable; |
||||
} |
||||
|
||||
public String getRuleBookName() { |
||||
return this.ruleBookName; |
||||
} |
||||
|
||||
public void setRuleBookName(String ruleBookName) { |
||||
this.ruleBookName = ruleBookName; |
||||
} |
||||
|
||||
public String getRuleBookAuthor() { |
||||
return this.ruleBookAuthor; |
||||
} |
||||
|
||||
public void setRuleBookAuthor(String ruleBookAuthor) { |
||||
this.ruleBookAuthor = ruleBookAuthor; |
||||
} |
||||
|
||||
public String getRuleChapterUrl() { |
||||
return this.ruleChapterUrl; |
||||
} |
||||
|
||||
public void setRuleChapterUrl(String ruleChapterUrl) { |
||||
this.ruleChapterUrl = ruleChapterUrl; |
||||
} |
||||
|
||||
public String getRuleCoverUrl() { |
||||
return this.ruleCoverUrl; |
||||
} |
||||
|
||||
public void setRuleCoverUrl(String ruleCoverUrl) { |
||||
this.ruleCoverUrl = ruleCoverUrl; |
||||
} |
||||
|
||||
public String getRuleIntroduce() { |
||||
return this.ruleIntroduce; |
||||
} |
||||
|
||||
public void setRuleIntroduce(String ruleIntroduce) { |
||||
this.ruleIntroduce = ruleIntroduce; |
||||
} |
||||
|
||||
public String getRuleBookContent() { |
||||
return this.ruleBookContent; |
||||
} |
||||
|
||||
public void setRuleBookContent(String ruleBookContent) { |
||||
this.ruleBookContent = ruleBookContent; |
||||
} |
||||
|
||||
public String getRuleSearchUrl() { |
||||
return this.ruleSearchUrl; |
||||
} |
||||
|
||||
public void setRuleSearchUrl(String ruleSearchUrl) { |
||||
this.ruleSearchUrl = ruleSearchUrl; |
||||
} |
||||
|
||||
public String getRuleContentUrl() { |
||||
return this.ruleContentUrl; |
||||
} |
||||
|
||||
public void setRuleContentUrl(String ruleContentUrl) { |
||||
this.ruleContentUrl = ruleContentUrl; |
||||
} |
||||
|
||||
public String getRuleSearchName() { |
||||
return this.ruleSearchName; |
||||
} |
||||
|
||||
public void setRuleSearchName(String ruleSearchName) { |
||||
this.ruleSearchName = ruleSearchName; |
||||
} |
||||
|
||||
public String getRuleSearchAuthor() { |
||||
return this.ruleSearchAuthor; |
||||
} |
||||
|
||||
public void setRuleSearchAuthor(String ruleSearchAuthor) { |
||||
this.ruleSearchAuthor = ruleSearchAuthor; |
||||
} |
||||
|
||||
public String getRuleSearchKind() { |
||||
return this.ruleSearchKind; |
||||
} |
||||
|
||||
public void setRuleSearchKind(String ruleSearchKind) { |
||||
this.ruleSearchKind = ruleSearchKind; |
||||
} |
||||
|
||||
public String getRuleSearchLastChapter() { |
||||
return this.ruleSearchLastChapter; |
||||
} |
||||
|
||||
public void setRuleSearchLastChapter(String ruleSearchLastChapter) { |
||||
this.ruleSearchLastChapter = ruleSearchLastChapter; |
||||
} |
||||
|
||||
public String getRuleSearchCoverUrl() { |
||||
return this.ruleSearchCoverUrl; |
||||
} |
||||
|
||||
public void setRuleSearchCoverUrl(String ruleSearchCoverUrl) { |
||||
this.ruleSearchCoverUrl = ruleSearchCoverUrl; |
||||
} |
||||
|
||||
public String getRuleSearchNoteUrl() { |
||||
return this.ruleSearchNoteUrl; |
||||
} |
||||
|
||||
public void setRuleSearchNoteUrl(String ruleSearchNoteUrl) { |
||||
this.ruleSearchNoteUrl = ruleSearchNoteUrl; |
||||
} |
||||
|
||||
public String getRuleSearchList() { |
||||
return this.ruleSearchList; |
||||
} |
||||
|
||||
public void setRuleSearchList(String ruleSearchList) { |
||||
this.ruleSearchList = ruleSearchList; |
||||
} |
||||
|
||||
public String getRuleChapterList() { |
||||
return this.ruleChapterList; |
||||
} |
||||
|
||||
public void setRuleChapterList(String ruleChapterList) { |
||||
this.ruleChapterList = ruleChapterList; |
||||
} |
||||
|
||||
public String getRuleChapterName() { |
||||
return this.ruleChapterName; |
||||
} |
||||
|
||||
public void setRuleChapterName(String ruleChapterName) { |
||||
this.ruleChapterName = ruleChapterName; |
||||
} |
||||
|
||||
public String getHttpUserAgent() { |
||||
return this.httpUserAgent; |
||||
} |
||||
|
||||
public void setHttpUserAgent(String httpHeaders) { |
||||
this.httpUserAgent = httpHeaders; |
||||
} |
||||
|
||||
public String getRuleFindUrl() { |
||||
return this.ruleFindUrl; |
||||
} |
||||
|
||||
public void setRuleFindUrl(String ruleFindUrl) { |
||||
this.ruleFindUrl = ruleFindUrl; |
||||
} |
||||
|
||||
public String getBookSourceGroup() { |
||||
return this.bookSourceGroup; |
||||
} |
||||
|
||||
public void setBookSourceGroup(String bookSourceGroup) { |
||||
this.bookSourceGroup = bookSourceGroup; |
||||
upGroupList(); |
||||
this.bookSourceGroup = TextUtils.join("; ", groupList); |
||||
} |
||||
|
||||
public String getRuleChapterUrlNext() { |
||||
return this.ruleChapterUrlNext; |
||||
} |
||||
|
||||
public void setRuleChapterUrlNext(String ruleChapterUrlNext) { |
||||
this.ruleChapterUrlNext = ruleChapterUrlNext; |
||||
} |
||||
|
||||
public String getRuleContentUrlNext() { |
||||
return this.ruleContentUrlNext; |
||||
} |
||||
|
||||
public void setRuleContentUrlNext(String ruleContentUrlNext) { |
||||
this.ruleContentUrlNext = ruleContentUrlNext; |
||||
} |
||||
|
||||
public String getRuleBookUrlPattern() { |
||||
return ruleBookUrlPattern; |
||||
} |
||||
|
||||
public void setRuleBookUrlPattern(String ruleBookUrlPattern) { |
||||
this.ruleBookUrlPattern = ruleBookUrlPattern; |
||||
} |
||||
|
||||
public String getRuleBookKind() { |
||||
return ruleBookKind; |
||||
} |
||||
|
||||
public void setRuleBookKind(String ruleBookKind) { |
||||
this.ruleBookKind = ruleBookKind; |
||||
} |
||||
|
||||
public String getRuleBookLastChapter() { |
||||
return ruleBookLastChapter; |
||||
} |
||||
|
||||
public void setRuleBookLastChapter(String ruleBookLastChapter) { |
||||
this.ruleBookLastChapter = ruleBookLastChapter; |
||||
} |
||||
|
||||
private void upGroupList() { |
||||
if (groupList == null) |
||||
groupList = new ArrayList<>(); |
||||
else |
||||
groupList.clear(); |
||||
if (!TextUtils.isEmpty(bookSourceGroup)) { |
||||
for (String group : bookSourceGroup.split("\\s*[,;,;]\\s*")) { |
||||
group = group.trim(); |
||||
if (TextUtils.isEmpty(group) || groupList.contains(group)) continue; |
||||
groupList.add(group); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public void addGroup(String group) { |
||||
if (groupList == null) |
||||
upGroupList(); |
||||
if (!groupList.contains(group)) { |
||||
groupList.add(group); |
||||
updateModTime(); |
||||
bookSourceGroup = TextUtils.join("; ", groupList); |
||||
} |
||||
} |
||||
|
||||
public void removeGroup(String group) { |
||||
if (groupList == null) |
||||
upGroupList(); |
||||
if (groupList.contains(group)) { |
||||
groupList.remove(group); |
||||
updateModTime(); |
||||
bookSourceGroup = TextUtils.join("; ", groupList); |
||||
} |
||||
} |
||||
|
||||
public boolean containsGroup(String group) { |
||||
if (groupList == null) { |
||||
upGroupList(); |
||||
} |
||||
return groupList.contains(group); |
||||
} |
||||
|
||||
public Long getLastUpdateTime() { |
||||
return lastUpdateTime; |
||||
} |
||||
|
||||
public void setLastUpdateTime(Long lastUpdateTime) { |
||||
this.lastUpdateTime = lastUpdateTime; |
||||
} |
||||
|
||||
public void updateModTime() { |
||||
this.lastUpdateTime = System.currentTimeMillis(); |
||||
} |
||||
|
||||
public String getLoginUrl() { |
||||
return this.loginUrl; |
||||
} |
||||
|
||||
public void setLoginUrl(String loginUrl) { |
||||
this.loginUrl = loginUrl; |
||||
} |
||||
|
||||
public String getBookSourceType() { |
||||
return bookSourceType == null ? "" : bookSourceType; |
||||
} |
||||
|
||||
public void setBookSourceType(String bookSourceType) { |
||||
this.bookSourceType = bookSourceType; |
||||
} |
||||
|
||||
public String getRuleSearchIntroduce() { |
||||
return this.ruleSearchIntroduce; |
||||
} |
||||
|
||||
public void setRuleSearchIntroduce(String ruleSearchIntroduce) { |
||||
this.ruleSearchIntroduce = ruleSearchIntroduce; |
||||
} |
||||
|
||||
public String getRuleFindList() { |
||||
return this.ruleFindList; |
||||
} |
||||
|
||||
public void setRuleFindList(String ruleFindList) { |
||||
this.ruleFindList = ruleFindList; |
||||
} |
||||
|
||||
public String getRuleFindName() { |
||||
return this.ruleFindName; |
||||
} |
||||
|
||||
public void setRuleFindName(String ruleFindName) { |
||||
this.ruleFindName = ruleFindName; |
||||
} |
||||
|
||||
public String getRuleFindAuthor() { |
||||
return this.ruleFindAuthor; |
||||
} |
||||
|
||||
public void setRuleFindAuthor(String ruleFindAuthor) { |
||||
this.ruleFindAuthor = ruleFindAuthor; |
||||
} |
||||
|
||||
public String getRuleFindKind() { |
||||
return this.ruleFindKind; |
||||
} |
||||
|
||||
public void setRuleFindKind(String ruleFindKind) { |
||||
this.ruleFindKind = ruleFindKind; |
||||
} |
||||
|
||||
public String getRuleFindIntroduce() { |
||||
return this.ruleFindIntroduce; |
||||
} |
||||
|
||||
public void setRuleFindIntroduce(String ruleFindIntroduce) { |
||||
this.ruleFindIntroduce = ruleFindIntroduce; |
||||
} |
||||
|
||||
public String getRuleFindLastChapter() { |
||||
return this.ruleFindLastChapter; |
||||
} |
||||
|
||||
public void setRuleFindLastChapter(String ruleFindLastChapter) { |
||||
this.ruleFindLastChapter = ruleFindLastChapter; |
||||
} |
||||
|
||||
public String getRuleFindCoverUrl() { |
||||
return this.ruleFindCoverUrl; |
||||
} |
||||
|
||||
public void setRuleFindCoverUrl(String ruleFindCoverUrl) { |
||||
this.ruleFindCoverUrl = ruleFindCoverUrl; |
||||
} |
||||
|
||||
public String getRuleFindNoteUrl() { |
||||
return this.ruleFindNoteUrl; |
||||
} |
||||
|
||||
public void setRuleFindNoteUrl(String ruleFindNoteUrl) { |
||||
this.ruleFindNoteUrl = ruleFindNoteUrl; |
||||
} |
||||
|
||||
public String getRuleBookInfoInit() { |
||||
return this.ruleBookInfoInit; |
||||
} |
||||
|
||||
public void setRuleBookInfoInit(String ruleBookInfoInit) { |
||||
this.ruleBookInfoInit = ruleBookInfoInit; |
||||
} |
||||
|
||||
public String getRuleBookContentReplace() { |
||||
return ruleBookContentReplace; |
||||
} |
||||
|
||||
public void setRuleBookContentReplace(String ruleBookContentReplace) { |
||||
this.ruleBookContentReplace = ruleBookContentReplace; |
||||
} |
||||
|
||||
public String getJson(int maxLength) { |
||||
try { |
||||
String source = getMinJson(false); |
||||
// 优先直接输出
|
||||
if (source.getBytes("utf-8").length <= maxLength) |
||||
return source; |
||||
source = StringUtils.zipString(source |
||||
.replaceFirst("^\\{", "") |
||||
// 保留末位的括号,用于解压缩后的验证
|
||||
.replaceFirst("(\\s|\n)*\\}$", "}") |
||||
.trim()); |
||||
// 优先输出带发现的书源
|
||||
if (source.getBytes("utf-8").length < maxLength) |
||||
return "{" + source; |
||||
// 去除发现
|
||||
return "{" + StringUtils.zipString(getMinJson(true) |
||||
.replaceFirst("^\\{", "") |
||||
// 保留末位的括号,用于解压缩后的验证
|
||||
.replaceFirst("(\\s|\n)*\\}$", "}") |
||||
.trim()); |
||||
|
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
return ""; |
||||
} |
||||
|
||||
/** |
||||
* 把书源bean转为json,并去除不必要的信息。 |
||||
* |
||||
* @param removeFind false,去除空信息和排序、可用性信息。true,额外去除发现规则 |
||||
* @return |
||||
*/ |
||||
public String getMinJson(Boolean removeFind) { |
||||
BookSourceBean bean = new BookSourceBean(this); |
||||
String json; |
||||
|
||||
if (removeFind) { |
||||
bean.setRuleFindUrl(null); |
||||
bean.setRuleFindList(null); |
||||
bean.setRuleFindName(null); |
||||
bean.setRuleFindAuthor(null); |
||||
bean.setRuleFindKind(null); |
||||
bean.setRuleFindIntroduce(null); |
||||
bean.setRuleFindLastChapter(null); |
||||
bean.setRuleFindCoverUrl(null); |
||||
bean.setRuleFindNoteUrl(null); |
||||
} |
||||
|
||||
try { |
||||
Gson gson = new Gson(); |
||||
json = gson.toJson(bean); |
||||
|
||||
return json.replaceFirst("\n\\s*\"enable\":\\s*\\S+(,)?\\s*", "\n") |
||||
.replaceFirst("\n\\s*\"serialNumber\":\\s*\\d+(,)?\\s*", "\n") |
||||
.replaceFirst("\n\\s*\"\"weight\":\\s*\\d+(,)?\\s*", "\n") |
||||
.replaceAll("\n\\s*\"[a-zA-Z]+\"(:\"\"|: \"\"| :\"\"| : \"\")\\s*,\\s*\n", "\n") |
||||
.replaceAll("\\s*\n\\s*", "") |
||||
; |
||||
} catch (Exception ignored) { |
||||
} |
||||
return ""; |
||||
} |
||||
} |
@ -0,0 +1,205 @@ |
||||
package xyz.fycz.myreader.model.analyzeRule; |
||||
|
||||
import android.text.TextUtils; |
||||
|
||||
import com.jayway.jsonpath.JsonPath; |
||||
import com.jayway.jsonpath.ReadContext; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.regex.Matcher; |
||||
import java.util.regex.Pattern; |
||||
|
||||
public class AnalyzeByJSonPath { |
||||
private static final Pattern jsonRulePattern = Pattern.compile("(?<=\\{)\\$\\..+?(?=\\})"); |
||||
private ReadContext ctx; |
||||
|
||||
public AnalyzeByJSonPath parse(Object json) { |
||||
if (json instanceof String) { |
||||
ctx = JsonPath.parse((String) json); |
||||
} else { |
||||
ctx = JsonPath.parse(json); |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
public String getString(String rule) { |
||||
if (TextUtils.isEmpty(rule)) return null; |
||||
String result = ""; |
||||
String[] rules; |
||||
String elementsType; |
||||
|
||||
if (rule.contains("{$.")) { |
||||
result = rule; |
||||
Matcher matcher = jsonRulePattern.matcher(rule); |
||||
while (matcher.find()) { |
||||
result = result.replace(String.format("{%s}", matcher.group()), getString(matcher.group().trim())); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
if (rule.contains("&&")) { |
||||
rules = rule.split("&&"); |
||||
elementsType = "&"; |
||||
} else { |
||||
rules = rule.split("\\|\\|"); |
||||
elementsType = "|"; |
||||
} |
||||
|
||||
if (rules.length == 1) { |
||||
try { |
||||
Object object = ctx.read(rule); |
||||
if (object instanceof List) { |
||||
StringBuilder builder = new StringBuilder(); |
||||
for (Object o : (List) object) { |
||||
builder.append(o).append("\n"); |
||||
} |
||||
result = builder.toString().replaceAll("\\n$", ""); |
||||
} else { |
||||
result = String.valueOf(object); |
||||
} |
||||
} catch (Exception e) { |
||||
if (!rule.startsWith("$.")) { |
||||
return rule; |
||||
} |
||||
} |
||||
return result; |
||||
} else { |
||||
List<String> textS = new ArrayList<>(); |
||||
for (String rl : rules) { |
||||
String temp = getString(rl); |
||||
if (!TextUtils.isEmpty(temp)) { |
||||
textS.add(temp); |
||||
if (elementsType.equals("|")) { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
return TextUtils.join(",", textS).trim(); |
||||
} |
||||
} |
||||
|
||||
List<String> getStringList(String rule) { |
||||
List<String> result = new ArrayList<>(); |
||||
if (TextUtils.isEmpty(rule)) return result; |
||||
String[] rules; |
||||
String elementsType; |
||||
if (rule.contains("&&")) { |
||||
rules = rule.split("&&"); |
||||
elementsType = "&"; |
||||
} else if (rule.contains("%%")) { |
||||
rules = rule.split("%%"); |
||||
elementsType = "%"; |
||||
} else { |
||||
rules = rule.split("\\|\\|"); |
||||
elementsType = "|"; |
||||
} |
||||
if (rules.length == 1) { |
||||
if (!rule.contains("{$.")) { |
||||
try { |
||||
Object object = ctx.read(rule); |
||||
if (object == null) return result; |
||||
if (object instanceof List) { |
||||
for (Object o : ((List) object)) |
||||
result.add(String.valueOf(o)); |
||||
} else { |
||||
result.add(String.valueOf(object)); |
||||
} |
||||
} catch (Exception ignored) { |
||||
} |
||||
return result; |
||||
} else { |
||||
Matcher matcher = jsonRulePattern.matcher(rule); |
||||
while (matcher.find()) { |
||||
List<String> stringList = getStringList(matcher.group()); |
||||
for (String s : stringList) { |
||||
result.add(rule.replace(String.format("{%s}", matcher.group()), s)); |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
} else { |
||||
List<List<String>> results = new ArrayList<>(); |
||||
for (String rl : rules) { |
||||
List<String> temp = getStringList(rl); |
||||
if (temp != null && !temp.isEmpty()) { |
||||
results.add(temp); |
||||
if (temp.size() > 0 && elementsType.equals("|")) { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
if (results.size() > 0) { |
||||
if ("%".equals(elementsType)) { |
||||
for (int i = 0; i < results.get(0).size(); i++) { |
||||
for (List<String> temp : results) { |
||||
if (i < temp.size()) { |
||||
result.add(temp.get(i)); |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
for (List<String> temp : results) { |
||||
result.addAll(temp); |
||||
} |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
} |
||||
|
||||
Object getObject(String rule) { |
||||
return ctx.read(rule); |
||||
} |
||||
|
||||
List<Object> getList(String rule) { |
||||
List<Object> result = new ArrayList<>(); |
||||
if (TextUtils.isEmpty(rule)) return result; |
||||
String elementsType; |
||||
String[] rules; |
||||
if (rule.contains("&&")) { |
||||
rules = rule.split("&&"); |
||||
elementsType = "&"; |
||||
} else if (rule.contains("%%")) { |
||||
rules = rule.split("%%"); |
||||
elementsType = "%"; |
||||
} else { |
||||
rules = rule.split("\\|\\|"); |
||||
elementsType = "|"; |
||||
} |
||||
if (rules.length == 1) { |
||||
try { |
||||
return ctx.read(rules[0]); |
||||
} catch (Exception e) { |
||||
return null; |
||||
} |
||||
} else { |
||||
List<List> results = new ArrayList<>(); |
||||
for (String rl : rules) { |
||||
List temp = getList(rl); |
||||
if (temp != null && !temp.isEmpty()) { |
||||
results.add(temp); |
||||
if (temp.size() > 0 && elementsType.equals("|")) { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
if (results.size() > 0) { |
||||
if ("%".equals(elementsType)) { |
||||
for (int i = 0; i < results.get(0).size(); i++) { |
||||
for (List temp : results) { |
||||
if (i < temp.size()) { |
||||
result.add(temp.get(i)); |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
for (List temp : results) { |
||||
result.addAll(temp); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
} |
@ -0,0 +1,454 @@ |
||||
package xyz.fycz.myreader.model.analyzeRule; |
||||
|
||||
import android.text.TextUtils; |
||||
|
||||
import org.jsoup.Jsoup; |
||||
import org.jsoup.nodes.Element; |
||||
import org.jsoup.nodes.TextNode; |
||||
import org.jsoup.select.Collector; |
||||
import org.jsoup.select.Elements; |
||||
import org.jsoup.select.Evaluator; |
||||
import org.seimicrawler.xpath.JXNode; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Arrays; |
||||
import java.util.List; |
||||
|
||||
import xyz.fycz.myreader.util.utils.StringUtils; |
||||
|
||||
import static android.text.TextUtils.isEmpty; |
||||
|
||||
/** |
||||
* Created by GKF on 2018/1/25. |
||||
* 书源规则解析 |
||||
*/ |
||||
|
||||
public class AnalyzeByJSoup { |
||||
private Element element; |
||||
|
||||
public AnalyzeByJSoup parse(Object doc) { |
||||
if (doc instanceof Element) { |
||||
element = (Element) doc; |
||||
} else if (doc instanceof JXNode) { |
||||
JXNode jxNode = (JXNode) doc; |
||||
if (jxNode.isElement()) { |
||||
element = jxNode.asElement(); |
||||
} else { |
||||
element = Jsoup.parse(jxNode.value().toString()); |
||||
} |
||||
} else { |
||||
element = Jsoup.parse(doc.toString()); |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* 获取列表 |
||||
*/ |
||||
Elements getElements(String rule) { |
||||
return getElements(element, rule); |
||||
} |
||||
|
||||
/** |
||||
* 合并内容列表,得到内容 |
||||
*/ |
||||
String getString(String ruleStr) { |
||||
if (isEmpty(ruleStr)) { |
||||
return null; |
||||
} |
||||
List<String> textS = getStringList(ruleStr); |
||||
if (textS.size() == 0) { |
||||
return null; |
||||
} |
||||
return TextUtils.join(",", textS).trim(); |
||||
} |
||||
|
||||
/** |
||||
* 获取一个字符串 |
||||
**/ |
||||
String getString0(String ruleStr) { |
||||
List<String> urlList = getStringList(ruleStr); |
||||
if (!urlList.isEmpty()) { |
||||
return urlList.get(0); |
||||
} |
||||
return ""; |
||||
} |
||||
|
||||
/** |
||||
* 获取所有内容列表 |
||||
*/ |
||||
List<String> getStringList(String ruleStr) { |
||||
List<String> textS = new ArrayList<>(); |
||||
if (isEmpty(ruleStr)) { |
||||
return textS; |
||||
} |
||||
//拆分规则
|
||||
SourceRule sourceRule = new SourceRule(ruleStr); |
||||
if (isEmpty(sourceRule.elementsRule)) { |
||||
textS.add(element.data()); |
||||
} else { |
||||
String elementsType; |
||||
String[] ruleStrS; |
||||
if (sourceRule.elementsRule.contains("&")) { |
||||
elementsType = "&"; |
||||
ruleStrS = sourceRule.elementsRule.split("&+"); |
||||
} else if (sourceRule.elementsRule.contains("%%")) { |
||||
elementsType = "%"; |
||||
ruleStrS = sourceRule.elementsRule.split("%%"); |
||||
} else { |
||||
elementsType = "|"; |
||||
if (sourceRule.isCss) { |
||||
ruleStrS = sourceRule.elementsRule.split("\\|\\|"); |
||||
} else { |
||||
ruleStrS = sourceRule.elementsRule.split("\\|+"); |
||||
} |
||||
} |
||||
List<List<String>> results = new ArrayList<>(); |
||||
for (String ruleStrX : ruleStrS) { |
||||
List<String> temp; |
||||
if (sourceRule.isCss) { |
||||
int lastIndex = ruleStrX.lastIndexOf('@'); |
||||
temp = getResultLast(element.select(ruleStrX.substring(0, lastIndex)), ruleStrX.substring(lastIndex + 1)); |
||||
} else { |
||||
temp = getResultList(ruleStrX); |
||||
} |
||||
if (temp != null && !temp.isEmpty()) { |
||||
results.add(temp); |
||||
if (!results.isEmpty() && elementsType.equals("|")) { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
if (results.size() > 0) { |
||||
if ("%".equals(elementsType)) { |
||||
for (int i = 0; i < results.get(0).size(); i++) { |
||||
for (List<String> temp : results) { |
||||
if (i < temp.size()) { |
||||
textS.add(temp.get(i)); |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
for (List<String> temp : results) { |
||||
textS.addAll(temp); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
if (!isEmpty(sourceRule.replaceRegex)) { |
||||
List<String> tempList = new ArrayList<>(textS); |
||||
textS.clear(); |
||||
for (String text : tempList) { |
||||
text = text.replaceAll(sourceRule.replaceRegex, sourceRule.replacement); |
||||
if (text.length() > 0) { |
||||
textS.add(text); |
||||
} |
||||
} |
||||
} |
||||
return textS; |
||||
} |
||||
|
||||
/** |
||||
* 获取Elements |
||||
*/ |
||||
private Elements getElements(Element temp, String rule) { |
||||
Elements elements = new Elements(); |
||||
if (temp == null || isEmpty(rule)) { |
||||
return elements; |
||||
} |
||||
SourceRule sourceRule = new SourceRule(rule); |
||||
String elementsType; |
||||
String[] ruleStrS; |
||||
if (sourceRule.elementsRule.contains("&")) { |
||||
elementsType = "&"; |
||||
ruleStrS = sourceRule.elementsRule.split("&+"); |
||||
} else if (sourceRule.elementsRule.contains("%")) { |
||||
elementsType = "%"; |
||||
ruleStrS = sourceRule.elementsRule.split("%+"); |
||||
} else { |
||||
elementsType = "|"; |
||||
if (sourceRule.isCss) { |
||||
ruleStrS = sourceRule.elementsRule.split("\\|\\|"); |
||||
} else { |
||||
ruleStrS = sourceRule.elementsRule.split("\\|+"); |
||||
} |
||||
} |
||||
List<Elements> elementsList = new ArrayList<>(); |
||||
if (sourceRule.isCss) { |
||||
for (String ruleStr : ruleStrS) { |
||||
Elements tempS = temp.select(ruleStr); |
||||
elementsList.add(tempS); |
||||
if (tempS.size() > 0 && elementsType.equals("|")) { |
||||
break; |
||||
} |
||||
} |
||||
} else { |
||||
for (String ruleStr : ruleStrS) { |
||||
Elements tempS = getElementsSingle(temp, ruleStr); |
||||
elementsList.add(tempS); |
||||
if (tempS.size() > 0 && elementsType.equals("|")) { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
if (elementsList.size() > 0) { |
||||
if ("%".equals(elementsType)) { |
||||
for (int i = 0; i < elementsList.get(0).size(); i++) { |
||||
for (Elements es : elementsList) { |
||||
if (i < es.size()) { |
||||
elements.add(es.get(i)); |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
for (Elements es : elementsList) { |
||||
elements.addAll(es); |
||||
} |
||||
} |
||||
} |
||||
return elements; |
||||
} |
||||
|
||||
private Elements filterElements(Elements elements, String[] rules) { |
||||
if (rules == null || rules.length < 2) return elements; |
||||
Elements selectedEls = new Elements(); |
||||
for (Element ele : elements) { |
||||
boolean isOk = false; |
||||
switch (rules[0]) { |
||||
case "class": |
||||
isOk = ele.getElementsByClass(rules[1]).size() > 0; |
||||
break; |
||||
case "id": |
||||
isOk = ele.getElementById(rules[1]) != null; |
||||
break; |
||||
case "tag": |
||||
isOk = ele.getElementsByTag(rules[1]).size() > 0; |
||||
break; |
||||
case "text": |
||||
isOk = ele.getElementsContainingOwnText(rules[1]).size() > 0; |
||||
break; |
||||
} |
||||
if (isOk) { |
||||
selectedEls.add(ele); |
||||
} |
||||
} |
||||
return selectedEls; |
||||
} |
||||
|
||||
/** |
||||
* 获取Elements按照一个规则 |
||||
*/ |
||||
private Elements getElementsSingle(Element temp, String rule) { |
||||
Elements elements = new Elements(); |
||||
try { |
||||
String[] rs = rule.trim().split("@"); |
||||
if (rs.length > 1) { |
||||
elements.add(temp); |
||||
for (String rl : rs) { |
||||
Elements es = new Elements(); |
||||
for (Element et : elements) { |
||||
es.addAll(getElements(et, rl)); |
||||
} |
||||
elements.clear(); |
||||
elements.addAll(es); |
||||
} |
||||
} else { |
||||
String[] rulePcx = rule.split("!"); |
||||
String[] rulePc = rulePcx[0].trim().split(">"); |
||||
String[] rules = rulePc[0].trim().split("\\."); |
||||
String[] filterRules = null; |
||||
boolean needFilterElements = rulePc.length > 1 && !isEmpty(rulePc[1].trim()); |
||||
if (needFilterElements) { |
||||
filterRules = rulePc[1].trim().split("\\."); |
||||
filterRules[0] = filterRules[0].trim(); |
||||
List<String> validKeys = Arrays.asList("class", "id", "tag", "text"); |
||||
if (filterRules.length < 2 || !validKeys.contains(filterRules[0]) || isEmpty(filterRules[1].trim())) { |
||||
needFilterElements = false; |
||||
} |
||||
filterRules[1] = filterRules[1].trim(); |
||||
} |
||||
switch (rules[0]) { |
||||
case "children": |
||||
Elements children = temp.children(); |
||||
if (needFilterElements) |
||||
children = filterElements(children, filterRules); |
||||
elements.addAll(children); |
||||
break; |
||||
case "class": |
||||
Elements elementsByClass = temp.getElementsByClass(rules[1]); |
||||
if (rules.length == 3) { |
||||
int index = Integer.parseInt(rules[2]); |
||||
if (index < 0) { |
||||
elements.add(elementsByClass.get(elementsByClass.size() + index)); |
||||
} else { |
||||
elements.add(elementsByClass.get(index)); |
||||
} |
||||
} else { |
||||
if (needFilterElements) |
||||
elementsByClass = filterElements(elementsByClass, filterRules); |
||||
elements.addAll(elementsByClass); |
||||
} |
||||
break; |
||||
case "tag": |
||||
Elements elementsByTag = temp.getElementsByTag(rules[1]); |
||||
if (rules.length == 3) { |
||||
int index = Integer.parseInt(rules[2]); |
||||
if (index < 0) { |
||||
elements.add(elementsByTag.get(elementsByTag.size() + index)); |
||||
} else { |
||||
elements.add(elementsByTag.get(index)); |
||||
} |
||||
} else { |
||||
if (needFilterElements) |
||||
elementsByTag = filterElements(elementsByTag, filterRules); |
||||
elements.addAll(elementsByTag); |
||||
} |
||||
break; |
||||
case "id": |
||||
Elements elementsById = Collector.collect(new Evaluator.Id(rules[1]), temp); |
||||
if (rules.length == 3) { |
||||
int index = Integer.parseInt(rules[2]); |
||||
if (index < 0) { |
||||
elements.add(elementsById.get(elementsById.size() + index)); |
||||
} else { |
||||
elements.add(elementsById.get(index)); |
||||
} |
||||
} else { |
||||
if (needFilterElements) |
||||
elementsById = filterElements(elementsById, filterRules); |
||||
elements.addAll(elementsById); |
||||
} |
||||
break; |
||||
case "text": |
||||
Elements elementsByText = temp.getElementsContainingOwnText(rules[1]); |
||||
if (needFilterElements) |
||||
elementsByText = filterElements(elementsByText, filterRules); |
||||
elements.addAll(elementsByText); |
||||
break; |
||||
default: |
||||
elements.addAll(temp.select(rulePcx[0])); |
||||
} |
||||
if (rulePcx.length > 1) { |
||||
String[] rulePcs = rulePcx[1].split(":"); |
||||
for (String pc : rulePcs) { |
||||
int pcInt = Integer.parseInt(pc); |
||||
if (pcInt < 0 && elements.size() + pcInt >= 0) { |
||||
elements.set(elements.size() + pcInt, null); |
||||
} else if (Integer.parseInt(pc) < elements.size()) { |
||||
elements.set(Integer.parseInt(pc), null); |
||||
} |
||||
} |
||||
Elements es = new Elements(); |
||||
es.add(null); |
||||
elements.removeAll(es); |
||||
} |
||||
} |
||||
} catch (Exception ignore) { |
||||
} |
||||
return elements; |
||||
} |
||||
|
||||
/** |
||||
* 获取内容列表 |
||||
*/ |
||||
private List<String> getResultList(String ruleStr) { |
||||
if (isEmpty(ruleStr)) { |
||||
return null; |
||||
} |
||||
Elements elements = new Elements(); |
||||
elements.add(element); |
||||
String[] rules = ruleStr.split("@"); |
||||
for (int i = 0; i < rules.length - 1; i++) { |
||||
Elements es = new Elements(); |
||||
for (Element elt : elements) { |
||||
es.addAll(getElementsSingle(elt, rules[i])); |
||||
} |
||||
elements.clear(); |
||||
elements = es; |
||||
} |
||||
if (elements.isEmpty()) { |
||||
return null; |
||||
} |
||||
return getResultLast(elements, rules[rules.length - 1]); |
||||
} |
||||
|
||||
/** |
||||
* 根据最后一个规则获取内容 |
||||
*/ |
||||
private List<String> getResultLast(Elements elements, String lastRule) { |
||||
List<String> textS = new ArrayList<>(); |
||||
List<String> cText = new ArrayList<>(); |
||||
try { |
||||
switch (lastRule) { |
||||
case "text": |
||||
for (Element element : elements) { |
||||
String text = element.text(); |
||||
cText.add(text); |
||||
} |
||||
textS.add(TextUtils.join("\n", cText)); |
||||
break; |
||||
case "textNodes": |
||||
for (Element element : elements) { |
||||
List<TextNode> contentEs = element.textNodes(); |
||||
for (int i = 0; i < contentEs.size(); i++) { |
||||
String temp = contentEs.get(i).text().trim(); |
||||
if (!isEmpty(temp)) { |
||||
cText.add(temp); |
||||
} |
||||
} |
||||
} |
||||
textS.add(TextUtils.join("\n", cText)); |
||||
break; |
||||
case "ownText": |
||||
for (Element element : elements) { |
||||
cText.add(element.ownText()); |
||||
} |
||||
textS.add(TextUtils.join("\n", cText)); |
||||
break; |
||||
case "html": |
||||
elements.select("script, style").remove(); |
||||
String html = elements.html(); |
||||
textS.add(html); |
||||
break; |
||||
case "all": |
||||
textS.add(elements.outerHtml()); |
||||
break; |
||||
default: |
||||
for (Element element : elements) { |
||||
String url = element.attr(lastRule); |
||||
if (!TextUtils.isEmpty(url) && !textS.contains(url)) { |
||||
textS.add(url); |
||||
} |
||||
} |
||||
} |
||||
} catch (Exception ignore) { |
||||
} |
||||
return textS; |
||||
} |
||||
|
||||
class SourceRule { |
||||
boolean isCss = false; |
||||
String elementsRule; |
||||
String replaceRegex = ""; |
||||
String replacement = ""; |
||||
|
||||
SourceRule(String ruleStr) { |
||||
if (StringUtils.startWithIgnoreCase(ruleStr, "@CSS:")) { |
||||
isCss = true; |
||||
elementsRule = ruleStr.substring(5).trim(); |
||||
return; |
||||
} |
||||
String[] ruleStrS; |
||||
//分离正则表达式
|
||||
ruleStrS = ruleStr.trim().split("#"); |
||||
elementsRule = ruleStrS[0]; |
||||
if (ruleStrS.length > 1) { |
||||
replaceRegex = ruleStrS[1]; |
||||
} |
||||
if (ruleStrS.length > 2) { |
||||
replacement = ruleStrS[2]; |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,194 @@ |
||||
package xyz.fycz.myreader.model.analyzeRule; |
||||
|
||||
import android.text.TextUtils; |
||||
|
||||
import org.jsoup.nodes.Document; |
||||
import org.jsoup.nodes.Element; |
||||
import org.jsoup.select.Elements; |
||||
import org.seimicrawler.xpath.JXDocument; |
||||
import org.seimicrawler.xpath.JXNode; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
public class AnalyzeByXPath { |
||||
private JXDocument jxDocument; |
||||
private JXNode jxNode; |
||||
|
||||
public AnalyzeByXPath parse(Object doc) { |
||||
if (doc instanceof JXNode) { |
||||
jxNode = (JXNode) doc; |
||||
if (!jxNode.isElement()) { |
||||
jxDocument = strToJXDocument(doc.toString()); |
||||
jxNode = null; |
||||
} |
||||
} else if (doc instanceof Document) { |
||||
jxDocument = JXDocument.create((Document) doc); |
||||
jxNode = null; |
||||
} else if (doc instanceof Element) { |
||||
jxDocument = JXDocument.create(new Elements((Element) doc)); |
||||
jxNode = null; |
||||
} else if (doc instanceof Elements) { |
||||
jxDocument = JXDocument.create((Elements) doc); |
||||
jxNode = null; |
||||
} else { |
||||
jxDocument = strToJXDocument(doc.toString()); |
||||
jxNode = null; |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
private JXDocument strToJXDocument(String html) { |
||||
if (html.endsWith("</td>")) { |
||||
html = String.format("<tr>%s</tr>", html); |
||||
} |
||||
if (html.endsWith("</tr>") || html.endsWith("</tbody>")) { |
||||
html = String.format("<table>%s</table>", html); |
||||
} |
||||
return JXDocument.create(html); |
||||
} |
||||
|
||||
List<JXNode> getElements(String xPath) { |
||||
if (TextUtils.isEmpty(xPath)) { |
||||
return null; |
||||
} |
||||
List<JXNode> jxNodes = new ArrayList<>(); |
||||
String elementsType; |
||||
String[] rules; |
||||
if (xPath.contains("&&")) { |
||||
rules = xPath.split("&&"); |
||||
elementsType = "&"; |
||||
} else if (xPath.contains("%%")) { |
||||
rules = xPath.split("%%"); |
||||
elementsType = "%"; |
||||
} else { |
||||
rules = xPath.split("\\|\\|"); |
||||
elementsType = "|"; |
||||
} |
||||
if (rules.length == 1) { |
||||
if (jxNode != null) { |
||||
return jxNode.sel(rules[0]); |
||||
} |
||||
return jxDocument.selN(rules[0]); |
||||
} else { |
||||
List<List<JXNode>> results = new ArrayList<>(); |
||||
for (String rl : rules) { |
||||
List<JXNode> temp = getElements(rl); |
||||
if (temp != null && !temp.isEmpty()) { |
||||
results.add(temp); |
||||
if (temp.size() > 0 && elementsType.equals("|")) { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
if (results.size() > 0) { |
||||
if ("%".equals(elementsType)) { |
||||
for (int i = 0; i < results.get(0).size(); i++) { |
||||
for (List<JXNode> temp : results) { |
||||
if (i < temp.size()) { |
||||
jxNodes.add(temp.get(i)); |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
for (List<JXNode> temp : results) { |
||||
jxNodes.addAll(temp); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return jxNodes; |
||||
} |
||||
|
||||
List<String> getStringList(String xPath) { |
||||
List<String> result = new ArrayList<>(); |
||||
String elementsType; |
||||
String[] rules; |
||||
if (xPath.contains("&&")) { |
||||
rules = xPath.split("&&"); |
||||
elementsType = "&"; |
||||
} else if (xPath.contains("%%")) { |
||||
rules = xPath.split("%%"); |
||||
elementsType = "%"; |
||||
} else { |
||||
rules = xPath.split("\\|\\|"); |
||||
elementsType = "|"; |
||||
} |
||||
if (rules.length == 1) { |
||||
List<JXNode> jxNodes; |
||||
if (jxNode != null) { |
||||
jxNodes = jxNode.sel(xPath); |
||||
} else { |
||||
jxNodes = jxDocument.selN(xPath); |
||||
} |
||||
for (JXNode jxNode : jxNodes) { |
||||
/*if(jxNode.isString()){ |
||||
result.add(String.valueOf(jxNode)); |
||||
}*/ |
||||
result.add(String.valueOf(jxNode)); |
||||
} |
||||
return result; |
||||
} else { |
||||
List<List<String>> results = new ArrayList<>(); |
||||
for (String rl : rules) { |
||||
List<String> temp = getStringList(rl); |
||||
if (temp != null && !temp.isEmpty()) { |
||||
results.add(temp); |
||||
if (temp.size() > 0 && elementsType.equals("|")) { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
if (results.size() > 0) { |
||||
if ("%".equals(elementsType)) { |
||||
for (int i = 0; i < results.get(0).size(); i++) { |
||||
for (List<String> temp : results) { |
||||
if (i < temp.size()) { |
||||
result.add(temp.get(i)); |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
for (List<String> temp : results) { |
||||
result.addAll(temp); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
public String getString(String rule) { |
||||
String[] rules; |
||||
String elementsType; |
||||
if (rule.contains("&&")) { |
||||
rules = rule.split("&&"); |
||||
elementsType = "&"; |
||||
} else { |
||||
rules = rule.split("\\|\\|"); |
||||
elementsType = "|"; |
||||
} |
||||
if (rules.length == 1) { |
||||
List<JXNode> jxNodes; |
||||
if (jxNode != null) { |
||||
jxNodes = jxNode.sel(rule); |
||||
} else { |
||||
jxNodes = jxDocument.selN(rule); |
||||
} |
||||
if (jxNodes == null) return null; |
||||
return TextUtils.join(",", jxNodes); |
||||
} else { |
||||
List<String> textS = new ArrayList<>(); |
||||
for (String rl : rules) { |
||||
String temp = getString(rl); |
||||
if (!TextUtils.isEmpty(temp)) { |
||||
textS.add(temp); |
||||
if (elementsType.equals("|")) { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
return TextUtils.join(",", textS).trim(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,540 @@ |
||||
package xyz.fycz.myreader.model.analyzeRule; |
||||
|
||||
import android.annotation.SuppressLint; |
||||
|
||||
import androidx.annotation.Keep; |
||||
|
||||
import com.google.gson.Gson; |
||||
|
||||
import org.jsoup.nodes.Entities; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Arrays; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.regex.Matcher; |
||||
import java.util.regex.Pattern; |
||||
|
||||
import javax.script.SimpleBindings; |
||||
|
||||
import xyz.fycz.myreader.util.StringHelper; |
||||
import xyz.fycz.myreader.util.utils.JsExtensions; |
||||
import xyz.fycz.myreader.util.utils.NetworkUtils; |
||||
import xyz.fycz.myreader.util.utils.StringUtils; |
||||
|
||||
import static android.text.TextUtils.isEmpty; |
||||
import static xyz.fycz.myreader.common.APPCONST.EXP_PATTERN; |
||||
import static xyz.fycz.myreader.common.APPCONST.JS_PATTERN; |
||||
import static xyz.fycz.myreader.common.APPCONST.MAP_STRING; |
||||
import static xyz.fycz.myreader.common.APPCONST.SCRIPT_ENGINE; |
||||
import static xyz.fycz.myreader.util.utils.NetworkUtils.headerPattern; |
||||
|
||||
|
||||
/** |
||||
* Created by REFGD. |
||||
* 统一解析接口 |
||||
*/ |
||||
@Keep |
||||
@SuppressWarnings({"unused", "WeakerAccess"}) |
||||
public class AnalyzeRule implements JsExtensions { |
||||
/*private static final Pattern putPattern = Pattern.compile("@put:(\\{[^}]+?\\})", Pattern.CASE_INSENSITIVE); |
||||
private static final Pattern getPattern = Pattern.compile("@get:\\{([^}]+?)\\}", Pattern.CASE_INSENSITIVE); |
||||
|
||||
private BaseBookBean book; |
||||
private Object object; |
||||
private Boolean isJSON = false; |
||||
private String baseUrl = null; |
||||
|
||||
private AnalyzeByXPath analyzeByXPath = null; |
||||
private AnalyzeByJSoup analyzeByJSoup = null; |
||||
private AnalyzeByJSonPath analyzeByJSonPath = null; |
||||
|
||||
private boolean objectChangedXP = false; |
||||
private boolean objectChangedJS = false; |
||||
private boolean objectChangedJP = false; |
||||
|
||||
public AnalyzeRule(BaseBookBean bookBean) { |
||||
book = bookBean; |
||||
} |
||||
|
||||
public void setBook(BaseBookBean book) { |
||||
this.book = book; |
||||
} |
||||
|
||||
public AnalyzeRule setContent(Object body) { |
||||
return setContent(body, baseUrl); |
||||
} |
||||
|
||||
public Object getContent() { |
||||
return object; |
||||
} |
||||
|
||||
public AnalyzeRule setContent(Object body, String baseUrl) { |
||||
if (body == null) throw new AssertionError("Content cannot be null"); |
||||
isJSON = StringUtils.isJsonType(String.valueOf(body)); |
||||
object = body; |
||||
if (baseUrl != null) { |
||||
this.baseUrl = headerPattern.matcher(baseUrl).replaceAll(""); |
||||
} |
||||
objectChangedXP = true; |
||||
objectChangedJS = true; |
||||
objectChangedJP = true; |
||||
return this; |
||||
} |
||||
|
||||
public String getBaseUrl() { |
||||
return this.baseUrl; |
||||
} |
||||
|
||||
*//**
|
||||
* 获取XPath解析类 |
||||
*//*
|
||||
private AnalyzeByXPath getAnalyzeByXPath(Object o) { |
||||
if (o != object) { |
||||
return new AnalyzeByXPath().parse(o); |
||||
} |
||||
return getAnalyzeByXPath(); |
||||
} |
||||
|
||||
private AnalyzeByXPath getAnalyzeByXPath() { |
||||
if (analyzeByXPath == null || objectChangedXP) { |
||||
analyzeByXPath = new AnalyzeByXPath(); |
||||
analyzeByXPath.parse(object); |
||||
objectChangedXP = false; |
||||
} |
||||
return analyzeByXPath; |
||||
} |
||||
|
||||
*//**
|
||||
* 获取JSOUP解析类 |
||||
*//*
|
||||
private AnalyzeByJSoup getAnalyzeByJSoup(Object o) { |
||||
if (o != object) { |
||||
return new AnalyzeByJSoup().parse(o); |
||||
} |
||||
return getAnalyzeByJSoup(); |
||||
} |
||||
|
||||
private AnalyzeByJSoup getAnalyzeByJSoup() { |
||||
if (analyzeByJSoup == null || objectChangedJS) { |
||||
analyzeByJSoup = new AnalyzeByJSoup(); |
||||
analyzeByJSoup.parse(object); |
||||
objectChangedJS = false; |
||||
} |
||||
return analyzeByJSoup; |
||||
} |
||||
|
||||
*//**
|
||||
* 获取JSON解析类 |
||||
*//*
|
||||
private AnalyzeByJSonPath getAnalyzeByJSonPath(Object o) { |
||||
if (o != object) { |
||||
return new AnalyzeByJSonPath().parse(o); |
||||
} |
||||
return getAnalyzeByJSonPath(); |
||||
} |
||||
|
||||
private AnalyzeByJSonPath getAnalyzeByJSonPath() { |
||||
if (analyzeByJSonPath == null || objectChangedJP) { |
||||
analyzeByJSonPath = new AnalyzeByJSonPath(); |
||||
analyzeByJSonPath.parse(object); |
||||
objectChangedJP = false; |
||||
} |
||||
return analyzeByJSonPath; |
||||
} |
||||
|
||||
*//**
|
||||
* 获取文本列表 |
||||
*//*
|
||||
public List<String> getStringList(String rule) throws Exception { |
||||
return getStringList(rule, false); |
||||
} |
||||
|
||||
public List<String> getStringList(String rule, boolean isUrl) throws Exception { |
||||
if (isEmpty(rule)) return null; |
||||
List<SourceRule> ruleList = splitSourceRule(rule); |
||||
return getStringList(ruleList, isUrl); |
||||
} |
||||
|
||||
@SuppressWarnings({"unchecked"}) |
||||
public List<String> getStringList(List<SourceRule> ruleList, boolean isUrl) throws Exception { |
||||
Object result = null; |
||||
if (!ruleList.isEmpty()) result = object; |
||||
for (SourceRule rule : ruleList) { |
||||
if (!isEmpty(rule.rule)) { |
||||
switch (rule.mode) { |
||||
case Js: |
||||
result = evalJS(rule.rule, result); |
||||
break; |
||||
case JSon: |
||||
result = getAnalyzeByJSonPath(result).getStringList(rule.rule); |
||||
break; |
||||
case XPath: |
||||
result = getAnalyzeByXPath(result).getStringList(rule.rule); |
||||
break; |
||||
default: |
||||
result = getAnalyzeByJSoup(result).getStringList(rule.rule); |
||||
} |
||||
} |
||||
if (!isEmpty(rule.replaceRegex) && result instanceof List) { |
||||
List<String> newList = new ArrayList<>(); |
||||
//noinspection rawtypes
|
||||
for (Object item : (List) result) { |
||||
newList.add(replaceRegex(String.valueOf(item), rule)); |
||||
} |
||||
result = newList; |
||||
} else if (!isEmpty(rule.replaceRegex)) { |
||||
result = replaceRegex(String.valueOf(result), rule); |
||||
} |
||||
} |
||||
if (result == null) return new ArrayList<>(); |
||||
if (result instanceof String) { |
||||
result = Arrays.asList(StringUtils.formatHtml((String) result).split("\n")); |
||||
} |
||||
if (isUrl && !isEmpty(baseUrl)) { |
||||
List<String> urlList = new ArrayList<>(); |
||||
//noinspection rawtypes
|
||||
for (Object url : (List) result) { |
||||
String absoluteURL = NetworkUtils.getAbsoluteURL(baseUrl, String.valueOf(url)); |
||||
if (!urlList.contains(absoluteURL) && !isEmpty(absoluteURL)) { |
||||
urlList.add(absoluteURL); |
||||
} |
||||
} |
||||
return urlList; |
||||
} |
||||
return (List<String>) result; |
||||
} |
||||
|
||||
*//**
|
||||
* 获取文本 |
||||
*//*
|
||||
public String getString(String rule) throws Exception { |
||||
return getString(rule, false); |
||||
} |
||||
|
||||
public String getString(String ruleStr, boolean isUrl) throws Exception { |
||||
if (isEmpty(ruleStr)) return null; |
||||
List<SourceRule> ruleList = splitSourceRule(ruleStr); |
||||
return getString(ruleList, isUrl); |
||||
} |
||||
|
||||
public String getString(List<SourceRule> ruleList) throws Exception { |
||||
return getString(ruleList, false); |
||||
} |
||||
|
||||
public String getString(List<SourceRule> ruleList, boolean isUrl) throws Exception { |
||||
Object result = null; |
||||
if (!ruleList.isEmpty()) result = object; |
||||
for (SourceRule rule : ruleList) { |
||||
if (!StringHelper.isEmpty(rule.rule)) { |
||||
switch (rule.mode) { |
||||
case Js: |
||||
result = evalJS(rule.rule, result); |
||||
break; |
||||
case JSon: |
||||
result = getAnalyzeByJSonPath(result).getString(rule.rule); |
||||
break; |
||||
case XPath: |
||||
result = getAnalyzeByXPath(result).getString(rule.rule); |
||||
break; |
||||
case Default: |
||||
if (isUrl && !isEmpty(baseUrl)) { |
||||
result = getAnalyzeByJSoup(result).getString0(rule.rule); |
||||
} else { |
||||
result = getAnalyzeByJSoup(result).getString(rule.rule); |
||||
} |
||||
} |
||||
} |
||||
if (!isEmpty(rule.replaceRegex)) { |
||||
result = replaceRegex(String.valueOf(result), rule); |
||||
} |
||||
} |
||||
if (result == null) return ""; |
||||
if (isUrl && !StringHelper.isEmpty(baseUrl)) { |
||||
return NetworkUtils.getAbsoluteURL(baseUrl, Entities.unescape(String.valueOf(result))); |
||||
} |
||||
try { |
||||
return Entities.unescape(String.valueOf(result)); |
||||
} catch (Exception e) { |
||||
return String.valueOf(result); |
||||
} |
||||
} |
||||
|
||||
*//**
|
||||
* 获取Element |
||||
*//*
|
||||
public Object getElement(String ruleStr) throws Exception { |
||||
List<SourceRule> ruleList = splitSourceRule(ruleStr); |
||||
Object result = object; |
||||
for (SourceRule rule : ruleList) { |
||||
switch (rule.mode) { |
||||
case Js: |
||||
result = evalJS(rule.rule, result); |
||||
break; |
||||
case JSon: |
||||
result = getAnalyzeByJSonPath(result).getObject(rule.rule); |
||||
break; |
||||
case XPath: |
||||
result = getAnalyzeByXPath(result).getElements(rule.rule); |
||||
break; |
||||
default: |
||||
result = getAnalyzeByJSoup(result).getElements(rule.rule); |
||||
} |
||||
if (!isEmpty(rule.replaceRegex) && result instanceof String) { |
||||
result = replaceRegex(String.valueOf(result), rule); |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
*//**
|
||||
* 获取列表 |
||||
*//*
|
||||
@SuppressWarnings("unchecked") |
||||
public List<Object> getElements(String ruleStr) throws Exception { |
||||
List<SourceRule> ruleList = splitSourceRule(ruleStr); |
||||
Object result = null; |
||||
if (!ruleList.isEmpty()) result = object; |
||||
for (SourceRule rule : ruleList) { |
||||
switch (rule.mode) { |
||||
case Js: |
||||
result = evalJS(rule.rule, result); |
||||
break; |
||||
case JSon: |
||||
result = getAnalyzeByJSonPath(result).getList(rule.rule); |
||||
break; |
||||
case XPath: |
||||
result = getAnalyzeByXPath(result).getElements(rule.rule); |
||||
break; |
||||
default: |
||||
result = getAnalyzeByJSoup(result).getElements(rule.rule); |
||||
} |
||||
if (!isEmpty(rule.replaceRegex) && result instanceof String) { |
||||
result = replaceRegex(String.valueOf(result), rule); |
||||
} |
||||
} |
||||
if (result == null) { |
||||
return new ArrayList<>(); |
||||
} |
||||
return (List<Object>) result; |
||||
} |
||||
|
||||
*//**
|
||||
* 保存变量 |
||||
*//*
|
||||
private void putRule(Map<String, String> map) throws Exception { |
||||
for (Map.Entry<String, String> entry : map.entrySet()) { |
||||
if (book != null) { |
||||
book.putVariable(entry.getKey(), getString(entry.getValue())); |
||||
} |
||||
} |
||||
} |
||||
|
||||
*//**
|
||||
* 分离并执行put规则 |
||||
*//*
|
||||
private String splitPutRule(String ruleStr) throws Exception { |
||||
Matcher putMatcher = putPattern.matcher(ruleStr); |
||||
while (putMatcher.find()) { |
||||
ruleStr = ruleStr.replace(putMatcher.group(), ""); |
||||
Map<String, String> map = new Gson().fromJson(putMatcher.group(1), MAP_STRING); |
||||
putRule(map); |
||||
} |
||||
return ruleStr; |
||||
} |
||||
|
||||
*//**
|
||||
* 替换@get |
||||
*//*
|
||||
public String replaceGet(String ruleStr) { |
||||
Matcher getMatcher = getPattern.matcher(ruleStr); |
||||
while (getMatcher.find()) { |
||||
String value = ""; |
||||
if (book != null && book.getVariableMap() != null) { |
||||
value = book.getVariableMap().get(getMatcher.group(1)); |
||||
if (value == null) value = ""; |
||||
} |
||||
ruleStr = ruleStr.replace(getMatcher.group(), value); |
||||
} |
||||
return ruleStr; |
||||
} |
||||
|
||||
*//**
|
||||
* 正则替换 |
||||
*//*
|
||||
private String replaceRegex(String result, SourceRule rule) { |
||||
if (!isEmpty(rule.replaceRegex)) { |
||||
if (rule.replaceFirst) { |
||||
Pattern pattern = Pattern.compile(rule.replaceRegex); |
||||
Matcher matcher = pattern.matcher(String.valueOf(result)); |
||||
if (matcher.find()) { |
||||
result = matcher.group(0).replaceFirst(rule.replaceRegex, rule.replacement); |
||||
} else { |
||||
result = ""; |
||||
} |
||||
} else { |
||||
result = String.valueOf(result).replaceAll(rule.replaceRegex, rule.replacement); |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
*//**
|
||||
* 替换JS |
||||
*//*
|
||||
@SuppressLint("DefaultLocale") |
||||
private String replaceJs(String ruleStr) throws Exception { |
||||
if (ruleStr.contains("{{") && ruleStr.contains("}}")) { |
||||
Object jsEval; |
||||
StringBuffer sb = new StringBuffer(ruleStr.length()); |
||||
Matcher expMatcher = EXP_PATTERN.matcher(ruleStr); |
||||
while (expMatcher.find()) { |
||||
jsEval = evalJS(expMatcher.group(1), object); |
||||
if (jsEval instanceof String) { |
||||
expMatcher.appendReplacement(sb, (String) jsEval); |
||||
} else if (jsEval instanceof Double && ((Double) jsEval) % 1.0 == 0) { |
||||
expMatcher.appendReplacement(sb, String.format("%.0f", (Double) jsEval)); |
||||
} else { |
||||
expMatcher.appendReplacement(sb, String.valueOf(jsEval)); |
||||
} |
||||
} |
||||
expMatcher.appendTail(sb); |
||||
ruleStr = sb.toString(); |
||||
} |
||||
return ruleStr; |
||||
} |
||||
|
||||
*//**
|
||||
* 分解规则生成规则列表 |
||||
*//*
|
||||
public List<SourceRule> splitSourceRule(String ruleStr) throws Exception { |
||||
List<SourceRule> ruleList = new ArrayList<>(); |
||||
if (isEmpty(ruleStr)) return ruleList; |
||||
//检测Mode
|
||||
Mode mode; |
||||
if (StringUtils.startWithIgnoreCase(ruleStr, "@XPath:")) { |
||||
mode = Mode.XPath; |
||||
ruleStr = ruleStr.substring(7); |
||||
} else if (StringUtils.startWithIgnoreCase(ruleStr, "@JSon:")) { |
||||
mode = Mode.JSon; |
||||
ruleStr = ruleStr.substring(6); |
||||
} else { |
||||
if (isJSON) { |
||||
mode = Mode.JSon; |
||||
} else { |
||||
mode = Mode.Default; |
||||
} |
||||
} |
||||
//分离put规则
|
||||
ruleStr = splitPutRule(ruleStr); |
||||
//替换get值
|
||||
ruleStr = replaceGet(ruleStr); |
||||
//替换js
|
||||
ruleStr = replaceJs(ruleStr); |
||||
//拆分为列表
|
||||
int start = 0; |
||||
String tmp; |
||||
Matcher jsMatcher = JS_PATTERN.matcher(ruleStr); |
||||
while (jsMatcher.find()) { |
||||
if (jsMatcher.start() > start) { |
||||
tmp = ruleStr.substring(start, jsMatcher.start()).replaceAll("\n", "").trim(); |
||||
if (!isEmpty(tmp)) { |
||||
ruleList.add(new SourceRule(tmp, mode)); |
||||
} |
||||
} |
||||
ruleList.add(new SourceRule(jsMatcher.group(), Mode.Js)); |
||||
start = jsMatcher.end(); |
||||
} |
||||
if (ruleStr.length() > start) { |
||||
tmp = ruleStr.substring(start).replaceAll("\n", "").trim(); |
||||
if (!isEmpty(tmp)) { |
||||
ruleList.add(new SourceRule(tmp, mode)); |
||||
} |
||||
} |
||||
return ruleList; |
||||
} |
||||
|
||||
*//**
|
||||
* 规则类 |
||||
*//*
|
||||
public static class SourceRule { |
||||
Mode mode; |
||||
String rule; |
||||
String replaceRegex = ""; |
||||
String replacement = ""; |
||||
boolean replaceFirst = false; |
||||
|
||||
SourceRule(String ruleStr, Mode mainMode) { |
||||
this.mode = mainMode; |
||||
if (mode == Mode.Js) { |
||||
if (ruleStr.startsWith("<js>")) { |
||||
rule = ruleStr.substring(4, ruleStr.lastIndexOf("<")); |
||||
} else { |
||||
rule = ruleStr.substring(4); |
||||
} |
||||
} else { |
||||
if (StringUtils.startWithIgnoreCase(ruleStr, "@XPath:")) { |
||||
mode = Mode.XPath; |
||||
rule = ruleStr.substring(7); |
||||
} else if (StringUtils.startWithIgnoreCase(ruleStr, "//")) {//XPath特征很明显,无需配置单独的识别标头
|
||||
mode = Mode.XPath; |
||||
rule = ruleStr; |
||||
} else if (StringUtils.startWithIgnoreCase(ruleStr, "@JSon:")) { |
||||
mode = Mode.JSon; |
||||
rule = ruleStr.substring(6); |
||||
} else if (ruleStr.startsWith("$.")) { |
||||
mode = Mode.JSon; |
||||
rule = ruleStr; |
||||
} else { |
||||
rule = ruleStr; |
||||
} |
||||
//分离正则表达式
|
||||
String[] ruleStrS = rule.trim().split("##"); |
||||
rule = ruleStrS[0]; |
||||
if (ruleStrS.length > 1) { |
||||
replaceRegex = ruleStrS[1]; |
||||
} |
||||
if (ruleStrS.length > 2) { |
||||
replacement = ruleStrS[2]; |
||||
} |
||||
if (ruleStrS.length > 3) { |
||||
replaceFirst = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
private enum Mode { |
||||
XPath, JSon, Default, Js |
||||
} |
||||
|
||||
public String put(String key, String value) { |
||||
if (book != null) { |
||||
book.putVariable(key, value); |
||||
} |
||||
return value; |
||||
} |
||||
|
||||
public String get(String key) { |
||||
if (book == null) { |
||||
return null; |
||||
} |
||||
if (book.getVariableMap() == null) { |
||||
return null; |
||||
} |
||||
return book.getVariableMap().get(key); |
||||
} |
||||
|
||||
*//**
|
||||
* 执行JS |
||||
*//*
|
||||
private Object evalJS(String jsStr, Object result) throws Exception { |
||||
SimpleBindings bindings = new SimpleBindings(); |
||||
bindings.put("java", this); |
||||
bindings.put("result", result); |
||||
bindings.put("baseUrl", baseUrl); |
||||
return SCRIPT_ENGINE.eval(jsStr, bindings); |
||||
}*/ |
||||
|
||||
} |
@ -0,0 +1,316 @@ |
||||
package xyz.fycz.myreader.model.analyzeRule; |
||||
|
||||
import android.annotation.SuppressLint; |
||||
import android.text.TextUtils; |
||||
|
||||
import androidx.annotation.Keep; |
||||
|
||||
import com.google.gson.Gson; |
||||
|
||||
import java.net.URLEncoder; |
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
import java.util.regex.Matcher; |
||||
import java.util.regex.Pattern; |
||||
|
||||
import javax.script.SimpleBindings; |
||||
|
||||
import xyz.fycz.myreader.util.StringHelper; |
||||
import xyz.fycz.myreader.util.utils.JsExtensions; |
||||
import xyz.fycz.myreader.util.utils.NetworkUtils; |
||||
import xyz.fycz.myreader.util.utils.StringUtils; |
||||
import xyz.fycz.myreader.util.utils.UrlEncoderUtils; |
||||
|
||||
import static xyz.fycz.myreader.common.APPCONST.EXP_PATTERN; |
||||
import static xyz.fycz.myreader.common.APPCONST.JS_PATTERN; |
||||
import static xyz.fycz.myreader.common.APPCONST.MAP_STRING; |
||||
import static xyz.fycz.myreader.common.APPCONST.SCRIPT_ENGINE; |
||||
import static xyz.fycz.myreader.util.utils.NetworkUtils.headerPattern; |
||||
|
||||
|
||||
/** |
||||
* Created by GKF on 2018/1/24. |
||||
* 搜索URL规则解析 |
||||
*/ |
||||
@Keep |
||||
public class AnalyzeUrl implements JsExtensions { |
||||
private static final Pattern pagePattern = Pattern.compile("\\{(.*?)\\}"); |
||||
private String baseUrl; |
||||
private String url; |
||||
private String host; |
||||
private String urlPath; |
||||
private String queryStr; |
||||
private Map<String, String> queryMap = new LinkedHashMap<>(); |
||||
private Map<String, String> headerMap = new HashMap<>(); |
||||
private String charCode = null; |
||||
private UrlMode urlMode = UrlMode.DEFAULT; |
||||
|
||||
public AnalyzeUrl(String urlRule) throws Exception { |
||||
this(urlRule, null, null, null, null); |
||||
} |
||||
|
||||
public AnalyzeUrl(String urlRule, Map<String, String> headerMapF, String baseUrl) throws Exception { |
||||
this(urlRule, null, null, headerMapF, baseUrl); |
||||
} |
||||
|
||||
@SuppressLint("DefaultLocale") |
||||
public AnalyzeUrl(String ruleUrl, final String key, final Integer page, Map<String, String> headerMapF, String baseUrl) throws Exception { |
||||
if (!TextUtils.isEmpty(baseUrl)) { |
||||
this.baseUrl = headerPattern.matcher(baseUrl).replaceAll(""); |
||||
} |
||||
//替换关键字
|
||||
if (!StringHelper.isEmpty(key)) { |
||||
// 处理searchKey=searchKey的情况
|
||||
if (ruleUrl.matches("=[\\s{(]*searchKey")) |
||||
ruleUrl = ruleUrl.replaceFirst("=[\\s{(]*searchKey", "=" + key); |
||||
else |
||||
ruleUrl = ruleUrl.replace("searchKey", key); |
||||
} |
||||
//判断是否有下一页
|
||||
if (page != null && page > 1 && !ruleUrl.contains("searchPage")) |
||||
throw new Exception("没有下一页"); |
||||
//替换js
|
||||
ruleUrl = replaceJs(ruleUrl, baseUrl, page, key); |
||||
//解析Header
|
||||
ruleUrl = analyzeHeader(ruleUrl, headerMapF); |
||||
//分离编码规则
|
||||
ruleUrl = splitCharCode(ruleUrl); |
||||
//设置页数
|
||||
ruleUrl = analyzePage(ruleUrl, page); |
||||
//执行规则列表
|
||||
List<String> ruleList = splitRule(ruleUrl); |
||||
for (String rule : ruleList) { |
||||
if (rule.startsWith("<js>")) { |
||||
rule = rule.substring(4, rule.lastIndexOf("<")); |
||||
ruleUrl = (String) evalJS(rule, ruleUrl); |
||||
} else if (rule.startsWith("@js:")) { |
||||
rule = rule.substring(4); |
||||
ruleUrl = (String) evalJS(rule, ruleUrl); |
||||
} else { |
||||
ruleUrl = rule.replace("@result", ruleUrl); |
||||
} |
||||
} |
||||
//分离post参数
|
||||
String[] ruleUrlS = ruleUrl.split("@"); |
||||
if (ruleUrlS.length > 1) { |
||||
urlMode = UrlMode.POST; |
||||
} else { |
||||
//分离get参数
|
||||
ruleUrlS = ruleUrlS[0].split("\\?"); |
||||
if (ruleUrlS.length > 1) { |
||||
urlMode = UrlMode.GET; |
||||
} |
||||
} |
||||
generateUrlPath(ruleUrlS[0]); |
||||
if (urlMode != UrlMode.DEFAULT) { |
||||
analyzeQuery(ruleUrlS[1]); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 解析Header |
||||
*/ |
||||
private String analyzeHeader(String ruleUrl, Map<String, String> headerMapF) { |
||||
if (headerMapF != null) { |
||||
headerMap.putAll(headerMapF); |
||||
} |
||||
Matcher matcher = headerPattern.matcher(ruleUrl); |
||||
if (matcher.find()) { |
||||
String find = matcher.group(0); |
||||
ruleUrl = ruleUrl.replace(find, ""); |
||||
find = find.substring(8); |
||||
try { |
||||
Map<String, String> map = new Gson().fromJson(find, MAP_STRING); |
||||
headerMap.putAll(map); |
||||
} catch (Exception ignored) { |
||||
} |
||||
} |
||||
return ruleUrl; |
||||
} |
||||
|
||||
/** |
||||
* 分离编码规则 |
||||
*/ |
||||
private String splitCharCode(String rule) { |
||||
String[] ruleUrlS = rule.split("\\|"); |
||||
if (ruleUrlS.length > 1) { |
||||
if (!TextUtils.isEmpty(ruleUrlS[1])) { |
||||
String[] qtS = ruleUrlS[1].split("&"); |
||||
for (String qt : qtS) { |
||||
String[] gz = qt.split("="); |
||||
if (gz[0].equals("char")) { |
||||
charCode = gz[1]; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return ruleUrlS[0]; |
||||
} |
||||
|
||||
/** |
||||
* 解析页数 |
||||
*/ |
||||
private String analyzePage(String ruleUrl, final Integer searchPage) { |
||||
if (searchPage == null) return ruleUrl; |
||||
Matcher matcher = pagePattern.matcher(ruleUrl); |
||||
while (matcher.find()) { |
||||
String[] pages = matcher.group(1).split(","); |
||||
if (searchPage <= pages.length) { |
||||
ruleUrl = ruleUrl.replace(matcher.group(), pages[searchPage - 1].trim()); |
||||
} else { |
||||
ruleUrl = ruleUrl.replace(matcher.group(), pages[pages.length - 1].trim()); |
||||
} |
||||
} |
||||
return ruleUrl.replace("searchPage-1", String.valueOf(searchPage - 1)) |
||||
.replace("searchPage+1", String.valueOf(searchPage + 1)) |
||||
.replace("searchPage", String.valueOf(searchPage)); |
||||
} |
||||
|
||||
/** |
||||
* 替换js |
||||
*/ |
||||
@SuppressLint("DefaultLocale") |
||||
private String replaceJs(String ruleUrl, String baseUrl, Integer searchPage, String searchKey) throws Exception { |
||||
if (ruleUrl.contains("{{") && ruleUrl.contains("}}")) { |
||||
Object jsEval; |
||||
StringBuffer sb = new StringBuffer(ruleUrl.length()); |
||||
SimpleBindings simpleBindings = new SimpleBindings() {{ |
||||
this.put("baseUrl", baseUrl); |
||||
this.put("searchPage", searchPage); |
||||
this.put("searchKey", searchKey); |
||||
}}; |
||||
Matcher expMatcher = EXP_PATTERN.matcher(ruleUrl); |
||||
while (expMatcher.find()) { |
||||
jsEval = SCRIPT_ENGINE.eval(expMatcher.group(1), simpleBindings); |
||||
if (jsEval instanceof String) { |
||||
expMatcher.appendReplacement(sb, (String) jsEval); |
||||
} else if (jsEval instanceof Double && ((Double) jsEval) % 1.0 == 0) { |
||||
expMatcher.appendReplacement(sb, String.format("%.0f", (Double) jsEval)); |
||||
} else { |
||||
expMatcher.appendReplacement(sb, String.valueOf(jsEval)); |
||||
} |
||||
} |
||||
expMatcher.appendTail(sb); |
||||
ruleUrl = sb.toString(); |
||||
} |
||||
return ruleUrl; |
||||
} |
||||
|
||||
/** |
||||
* 解析QueryMap |
||||
*/ |
||||
private void analyzeQuery(String allQuery) throws Exception { |
||||
queryStr = allQuery; |
||||
String[] queryS = allQuery.split("&"); |
||||
for (String query : queryS) { |
||||
String[] queryM = query.split("="); |
||||
String value = queryM.length > 1 ? queryM[1] : ""; |
||||
if (TextUtils.isEmpty(charCode)) { |
||||
if (UrlEncoderUtils.hasUrlEncoded(value)) { |
||||
queryMap.put(queryM[0], value); |
||||
} else { |
||||
queryMap.put(queryM[0], URLEncoder.encode(value, "UTF-8")); |
||||
} |
||||
} else if (charCode.equals("escape")) { |
||||
queryMap.put(queryM[0], StringUtils.escape(value)); |
||||
} else { |
||||
queryMap.put(queryM[0], URLEncoder.encode(value, charCode)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 拆分规则 |
||||
*/ |
||||
private List<String> splitRule(String ruleStr) { |
||||
List<String> ruleList = new ArrayList<>(); |
||||
Matcher jsMatcher = JS_PATTERN.matcher(ruleStr); |
||||
int start = 0; |
||||
String tmp; |
||||
while (jsMatcher.find()) { |
||||
if (jsMatcher.start() > start) { |
||||
tmp = ruleStr.substring(start, jsMatcher.start()).replaceAll("\n", "").trim(); |
||||
if (!TextUtils.isEmpty(tmp)) { |
||||
ruleList.add(tmp); |
||||
} |
||||
} |
||||
ruleList.add(jsMatcher.group()); |
||||
start = jsMatcher.end(); |
||||
} |
||||
if (ruleStr.length() > start) { |
||||
tmp = ruleStr.substring(start).replaceAll("\n", "").trim(); |
||||
if (!TextUtils.isEmpty(tmp)) { |
||||
ruleList.add(tmp); |
||||
} |
||||
} |
||||
return ruleList; |
||||
} |
||||
|
||||
/** |
||||
* 分解URL |
||||
*/ |
||||
private void generateUrlPath(String ruleUrl) { |
||||
url = NetworkUtils.getAbsoluteURL(baseUrl, ruleUrl); |
||||
host = StringUtils.getBaseUrl(url); |
||||
urlPath = url.substring(host.length()); |
||||
} |
||||
|
||||
/** |
||||
* 执行JS |
||||
*/ |
||||
private Object evalJS(String jsStr, Object result) throws Exception { |
||||
SimpleBindings bindings = new SimpleBindings(); |
||||
bindings.put("result", result); |
||||
return SCRIPT_ENGINE.eval(jsStr, bindings); |
||||
} |
||||
|
||||
public String getCharCode() { |
||||
return charCode; |
||||
} |
||||
|
||||
public String getHost() { |
||||
return host; |
||||
} |
||||
|
||||
public String getPath() { |
||||
return urlPath; |
||||
} |
||||
|
||||
public String getUrl() { |
||||
return url; |
||||
} |
||||
|
||||
public Map<String, String> getQueryMap() { |
||||
return queryMap; |
||||
} |
||||
|
||||
public Map<String, String> getHeaderMap() { |
||||
return headerMap; |
||||
} |
||||
|
||||
public String getQueryStr() { |
||||
return queryStr; |
||||
} |
||||
|
||||
public byte[] getPostData() { |
||||
StringBuilder builder = new StringBuilder(); |
||||
Set<String> keys = queryMap.keySet(); |
||||
for (String key : keys) { |
||||
builder.append(String.format("%s=%s&", key, queryMap.get(key))); |
||||
} |
||||
builder.deleteCharAt(builder.lastIndexOf("&")); |
||||
return builder.toString().getBytes(); |
||||
} |
||||
|
||||
public UrlMode getUrlMode() { |
||||
return urlMode; |
||||
} |
||||
|
||||
public enum UrlMode { |
||||
GET, POST, DEFAULT |
||||
} |
||||
} |
@ -1,186 +0,0 @@ |
||||
package xyz.fycz.myreader.ui.dialog; |
||||
|
||||
import android.annotation.SuppressLint; |
||||
import android.content.Context; |
||||
import android.os.Handler; |
||||
import android.os.Message; |
||||
|
||||
import xyz.fycz.myreader.application.App; |
||||
import xyz.fycz.myreader.webapi.callback.ResultCallback; |
||||
import xyz.fycz.myreader.util.ToastUtils; |
||||
import xyz.fycz.myreader.webapi.crawler.*; |
||||
import xyz.fycz.myreader.entity.SearchBookBean; |
||||
import xyz.fycz.myreader.greendao.entity.Book; |
||||
import xyz.fycz.myreader.model.mulvalmap.ConcurrentMultiValueMap; |
||||
import xyz.fycz.myreader.webapi.CommonApi; |
||||
import xyz.fycz.myreader.webapi.crawler.base.BookInfoCrawler; |
||||
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler; |
||||
|
||||
import java.io.UnsupportedEncodingException; |
||||
import java.net.URLEncoder; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
|
||||
/** |
||||
* @author fengyue |
||||
* @date 2020/5/19 17:35 |
||||
*/ |
||||
public class ChangeSourceDialog { |
||||
private Context context; |
||||
private Book mBook; |
||||
private ConcurrentMultiValueMap<SearchBookBean, Book> mBooks = new ConcurrentMultiValueMap<>(); |
||||
private ArrayList<Book> aBooks; |
||||
private SearchBookBean sbb; |
||||
private boolean isSearchSuccess; |
||||
private int threadCount; |
||||
private ResultCallback rc; |
||||
private boolean isGetOneBook = false; |
||||
private Book oneBook; |
||||
@SuppressLint("HandlerLeak") |
||||
private Handler mHandler = new Handler() { |
||||
@Override |
||||
public void handleMessage(Message msg) { |
||||
switch (msg.what) { |
||||
case 1: |
||||
if (isGetOneBook){ |
||||
rc.onFinish(oneBook, 0); |
||||
}else { |
||||
if (threadCount == 0) { |
||||
createaBooks(); |
||||
} |
||||
} |
||||
break; |
||||
case 2: |
||||
if (!isSearchSuccess && threadCount == 0) { |
||||
if (!isGetOneBook|| oneBook == null) { |
||||
rc.onError(new Exception()); |
||||
} |
||||
}else if (threadCount == 0){ |
||||
if (isGetOneBook){ |
||||
rc.onFinish(oneBook, 0); |
||||
}else { |
||||
createaBooks(); |
||||
} |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
}; |
||||
|
||||
public ChangeSourceDialog(Context context, Book mBook) { |
||||
this.context = context; |
||||
this.mBook = mBook; |
||||
sbb = new SearchBookBean(mBook.getName(), mBook.getAuthor()); |
||||
} |
||||
|
||||
public void init(ResultCallback rc) { |
||||
this.rc = rc; |
||||
getData(); |
||||
} |
||||
|
||||
public void initOneBook(ResultCallback rc){ |
||||
this.rc = rc; |
||||
getData(); |
||||
isGetOneBook = true; |
||||
} |
||||
|
||||
/** |
||||
* 获取搜索数据 |
||||
*/ |
||||
private void getData() { |
||||
mBooks.clear(); |
||||
ArrayList<ReadCrawler> readCrawlers = ReadCrawlerUtil.getReadCrawlers(); |
||||
threadCount = readCrawlers.size(); |
||||
if (threadCount == 0){ |
||||
if (isGetOneBook){ |
||||
ToastUtils.showWarring("当前书源已全部禁用,无法搜索!"); |
||||
}else { |
||||
ToastUtils.showWarring("当前书源已全部禁用,无法换源!"); |
||||
} |
||||
rc.onError(new Exception()); |
||||
return; |
||||
} |
||||
isSearchSuccess = false; |
||||
for (ReadCrawler readCrawler : readCrawlers){ |
||||
searchBookByCrawler(readCrawler, readCrawler.getSearchCharset()); |
||||
} |
||||
} |
||||
|
||||
private void searchBookByCrawler(final ReadCrawler rc, String charset) { |
||||
String searchKey = mBook.getName(); |
||||
if (charset.toLowerCase().equals("gbk")) { |
||||
try { |
||||
searchKey = URLEncoder.encode(mBook.getName(), charset); |
||||
} catch (UnsupportedEncodingException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
CommonApi.search(searchKey, rc, new ResultCallback() { |
||||
@Override |
||||
public void onFinish(Object o, int code) { |
||||
final ConcurrentMultiValueMap<SearchBookBean, Book> cmvm = |
||||
(ConcurrentMultiValueMap<SearchBookBean, Book>) o; |
||||
if (isGetOneBook){ |
||||
if (oneBook != null){ |
||||
return; |
||||
} |
||||
oneBook = cmvm.getValue(sbb, 0); |
||||
threadCount--; |
||||
mHandler.sendMessage(mHandler.obtainMessage(1)); |
||||
App.getApplication().shutdownThreadPool(); |
||||
return; |
||||
} |
||||
if (rc instanceof BookInfoCrawler) { |
||||
BookInfoCrawler bic = (BookInfoCrawler) rc; |
||||
final List<Book> aBooks = cmvm.getValues(sbb); |
||||
if (aBooks != null) { |
||||
for (int i = 0; i < aBooks.size(); i++) { |
||||
Book book = aBooks.get(i); |
||||
final int finalI = i; |
||||
CommonApi.getBookInfo(book, bic, new ResultCallback() { |
||||
@Override |
||||
public void onFinish(Object o, int code) { |
||||
if (finalI == aBooks.size() - 1) { |
||||
mBooks.addAll(cmvm); |
||||
isSearchSuccess = true; |
||||
threadCount--; |
||||
mHandler.sendMessage(mHandler.obtainMessage(1)); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onError(Exception e) { |
||||
threadCount--; |
||||
mHandler.sendMessage(mHandler.obtainMessage(2)); |
||||
} |
||||
}); |
||||
|
||||
} |
||||
} else { |
||||
isSearchSuccess = true; |
||||
threadCount--; |
||||
mHandler.sendMessage(mHandler.obtainMessage(1)); |
||||
} |
||||
} else { |
||||
mBooks.addAll(cmvm); |
||||
isSearchSuccess = true; |
||||
threadCount--; |
||||
mHandler.sendMessage(mHandler.obtainMessage(1)); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onError(Exception e) { |
||||
threadCount--; |
||||
mHandler.sendMessage(mHandler.obtainMessage(2)); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
private void createaBooks() { |
||||
aBooks = (ArrayList<Book>) mBooks.getValues(sbb); |
||||
rc.onFinish(aBooks, 1); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,82 @@ |
||||
package xyz.fycz.myreader.util.utils; |
||||
|
||||
|
||||
import org.jsoup.Connection; |
||||
import org.jsoup.Jsoup; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
import java.util.regex.Matcher; |
||||
import java.util.regex.Pattern; |
||||
|
||||
import xyz.fycz.myreader.model.analyzeRule.AnalyzeUrl; |
||||
import xyz.fycz.myreader.util.HttpUtil; |
||||
|
||||
@SuppressWarnings({"unused", "WeakerAccess"}) |
||||
public interface JsExtensions { |
||||
|
||||
/** |
||||
* js实现跨域访问,不能删 |
||||
*/ |
||||
/*default String ajax(String urlStr) { |
||||
try { |
||||
AnalyzeUrl analyzeUrl = new AnalyzeUrl(urlStr); |
||||
Response<String> response = BaseModelImpl.getInstance().getResponseO(analyzeUrl) |
||||
.blockingFirst(); |
||||
return response.body(); |
||||
} catch (Exception e) { |
||||
return e.getLocalizedMessage(); |
||||
} |
||||
}*/ |
||||
|
||||
/** |
||||
* js实现解码,不能删 |
||||
*/ |
||||
default String base64Decoder(String base64) { |
||||
return StringUtils.base64Decode(base64); |
||||
} |
||||
|
||||
/** |
||||
* 章节数转数字 |
||||
*/ |
||||
default String toNumChapter(String s) { |
||||
if (s == null) { |
||||
return null; |
||||
} |
||||
Pattern pattern = Pattern.compile("(第)(.+?)(章)"); |
||||
Matcher matcher = pattern.matcher(s); |
||||
if (matcher.find()) { |
||||
return matcher.group(1) + StringUtils.stringToInt(matcher.group(2)) + matcher.group(3); |
||||
} |
||||
return s; |
||||
} |
||||
|
||||
/** |
||||
* js实现重定向拦截,不能删 |
||||
*/ |
||||
default Connection.Response get(String urlStr, Map<String, String> headers) throws IOException { |
||||
return Jsoup.connect(urlStr) |
||||
.sslSocketFactory(HttpUtil.createSSLSocketFactory()) |
||||
.ignoreContentType(true) |
||||
.followRedirects(false) |
||||
.headers(headers) |
||||
.method(Connection.Method.GET) |
||||
.execute(); |
||||
} |
||||
|
||||
/** |
||||
* js实现重定向拦截,不能删 |
||||
*/ |
||||
default Connection.Response post(String urlStr, String body, Map<String, String> headers) throws IOException { |
||||
return Jsoup.connect(urlStr) |
||||
.sslSocketFactory(HttpUtil.createSSLSocketFactory()) |
||||
.ignoreContentType(true) |
||||
.followRedirects(false) |
||||
.requestBody(body) |
||||
.headers(headers) |
||||
.method(Connection.Method.POST) |
||||
.execute(); |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,80 @@ |
||||
package xyz.fycz.myreader.util.utils; |
||||
|
||||
import java.util.BitSet; |
||||
|
||||
/** |
||||
* 这里会有误差,比如输入一个字符串 123+456,它到底是原文就是123+456还是123 456做了urlEncode后的内容呢?<br> |
||||
* 其实问题是一样的,比如遇到123%2B456,它到底是原文即使如此,还是123+456 urlEncode后的呢? <br> |
||||
* 在这里,我认为只要符合urlEncode规范的,就当作已经urlEncode过了<br> |
||||
* 毕竟这个方法的初衷就是判断string是否urlEncode过<br> |
||||
*/ |
||||
public class UrlEncoderUtils { |
||||
private static BitSet dontNeedEncoding; |
||||
|
||||
static { |
||||
dontNeedEncoding = new BitSet(256); |
||||
int i; |
||||
for (i = 'a'; i <= 'z'; i++) { |
||||
dontNeedEncoding.set(i); |
||||
} |
||||
for (i = 'A'; i <= 'Z'; i++) { |
||||
dontNeedEncoding.set(i); |
||||
} |
||||
for (i = '0'; i <= '9'; i++) { |
||||
dontNeedEncoding.set(i); |
||||
} |
||||
dontNeedEncoding.set('+'); |
||||
dontNeedEncoding.set('-'); |
||||
dontNeedEncoding.set('_'); |
||||
dontNeedEncoding.set('.'); |
||||
dontNeedEncoding.set('$'); |
||||
dontNeedEncoding.set(':'); |
||||
dontNeedEncoding.set('('); |
||||
dontNeedEncoding.set(')'); |
||||
dontNeedEncoding.set('!'); |
||||
dontNeedEncoding.set('*'); |
||||
dontNeedEncoding.set('@'); |
||||
dontNeedEncoding.set('&'); |
||||
dontNeedEncoding.set('#'); |
||||
dontNeedEncoding.set(','); |
||||
dontNeedEncoding.set('['); |
||||
dontNeedEncoding.set(']'); |
||||
} |
||||
|
||||
/** |
||||
* 支持JAVA的URLEncoder.encode出来的string做判断。 即: 将' '转成'+' |
||||
* 0-9a-zA-Z保留 <br> |
||||
* ! * ' ( ) ; : @ & = + $ , / ? # [ ] 保留 |
||||
* 其他字符转成%XX的格式,X是16进制的大写字符,范围是[0-9A-F] |
||||
*/ |
||||
public static boolean hasUrlEncoded(String str) { |
||||
boolean needEncode = false; |
||||
for (int i = 0; i < str.length(); i++) { |
||||
char c = str.charAt(i); |
||||
if (dontNeedEncoding.get((int) c)) { |
||||
continue; |
||||
} |
||||
if (c == '%' && (i + 2) < str.length()) { |
||||
// 判断是否符合urlEncode规范
|
||||
char c1 = str.charAt(++i); |
||||
char c2 = str.charAt(++i); |
||||
if (isDigit16Char(c1) && isDigit16Char(c2)) { |
||||
continue; |
||||
} |
||||
} |
||||
// 其他字符,肯定需要urlEncode
|
||||
needEncode = true; |
||||
break; |
||||
} |
||||
|
||||
return !needEncode; |
||||
} |
||||
|
||||
/** |
||||
* 判断c是否是16进制的字符 |
||||
*/ |
||||
private static boolean isDigit16Char(char c) { |
||||
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'); |
||||
} |
||||
|
||||
} |
@ -1,231 +0,0 @@ |
||||
package xyz.fycz.myreader.webapi; |
||||
|
||||
import xyz.fycz.myreader.common.ErrorCode; |
||||
import xyz.fycz.myreader.entity.JsonModel; |
||||
import xyz.fycz.myreader.util.HttpUtil; |
||||
import com.google.gson.Gson; |
||||
|
||||
import xyz.fycz.myreader.util.utils.GsonExtensionsKt; |
||||
import xyz.fycz.myreader.webapi.callback.JsonCallback; |
||||
import xyz.fycz.myreader.webapi.callback.ResultCallback; |
||||
import xyz.fycz.myreader.util.ToastUtils; |
||||
|
||||
import java.util.Map; |
||||
|
||||
public class BaseApi { |
||||
|
||||
/** |
||||
* post通用返回实体api |
||||
* @param url |
||||
* @param params |
||||
* @param c 返回的实体类型 |
||||
* @param callback |
||||
*/ |
||||
public static void postCommonApi(String url, Map<String, Object> params, final Class c, final ResultCallback callback) { |
||||
HttpDataSource.httpPost(url, HttpUtil.makePostOutput(params), new JsonCallback() { |
||||
@Override |
||||
public void onFinish(JsonModel jsonModel) { |
||||
if (jsonModel.isSuccess()) { |
||||
callback.onFinish(new Gson().fromJson(jsonModel.getResult(),c), jsonModel.getError()); |
||||
} else { |
||||
noSuccess(jsonModel,callback); |
||||
} |
||||
} |
||||
@Override |
||||
public void onError(Exception e) { |
||||
error(e,callback); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* post通用返回字符串api |
||||
* @param url |
||||
* @param params |
||||
* @param callback |
||||
*/ |
||||
public static void postCommonReturnStringApi(String url, Map<String, Object> params, final ResultCallback callback) { |
||||
HttpDataSource.httpPost(url, HttpUtil.makePostOutput(params), new ResultCallback() { |
||||
@Override |
||||
public void onFinish(Object o, int code) { |
||||
callback.onFinish(o, code); |
||||
} |
||||
|
||||
@Override |
||||
public void onError(Exception e) { |
||||
callback.onError(e); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* get通用返回字符串api |
||||
* 通过api获取蓝奏云直链 |
||||
* @param url |
||||
* @param params |
||||
* @param callback |
||||
*/ |
||||
public static void postLanzousApi(String url, Map<String, Object> params, final ResultCallback callback, final String referer) { |
||||
HttpDataSource.httpPost(url, HttpUtil.makePostOutput(params), new ResultCallback() { |
||||
@Override |
||||
public void onFinish(Object o, int code) { |
||||
callback.onFinish(o, code); |
||||
} |
||||
|
||||
@Override |
||||
public void onError(Exception e) { |
||||
callback.onError(e); |
||||
} |
||||
}, referer); |
||||
} |
||||
/** |
||||
* get通用返回实体api |
||||
* @param url |
||||
* @param params |
||||
* @param c 返回的实体类型 |
||||
* @param callback |
||||
*/ |
||||
public static void getCommonApi(String url, Map<String, Object> params, final Class c, final ResultCallback callback) { |
||||
HttpDataSource.httpGet(HttpUtil.makeURL(url,params), new JsonCallback() { |
||||
@Override |
||||
public void onFinish(JsonModel jsonModel) { |
||||
if (jsonModel.isSuccess()) { |
||||
callback.onFinish(new Gson().fromJson(jsonModel.getResult(),c), jsonModel.getError()); |
||||
} else { |
||||
noSuccess(jsonModel,callback); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onError(Exception e) { |
||||
error(e,callback); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* get通用返回字符串api |
||||
* @param url |
||||
* @param params |
||||
* @param callback |
||||
*/ |
||||
public static void getCommonReturnStringApi(String url, Map<String, Object> params, final ResultCallback callback) { |
||||
HttpDataSource.httpGet(HttpUtil.makeURL(url,params), new JsonCallback() { |
||||
@Override |
||||
public void onFinish(JsonModel jsonModel) { |
||||
if (jsonModel.isSuccess()) { |
||||
callback.onFinish(jsonModel.getResult(), jsonModel.getError()); |
||||
} else { |
||||
noSuccess(jsonModel, callback); |
||||
} |
||||
} |
||||
@Override |
||||
public void onError(Exception e) { |
||||
error(e,callback); |
||||
} |
||||
}); |
||||
} |
||||
/** |
||||
* get通用返回字符串api |
||||
* @param url |
||||
* @param params |
||||
* @param callback |
||||
*/ |
||||
public static void getCommonReturnStringApi2(String url, Map<String, Object> params, final ResultCallback callback) { |
||||
HttpDataSource.httpGet(HttpUtil.makeURL(url, params), new ResultCallback() { |
||||
@Override |
||||
public void onFinish(Object o, int code) { |
||||
callback.onFinish(o,code); |
||||
} |
||||
|
||||
@Override |
||||
public void onError(Exception e) { |
||||
callback.onError(e); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* get通用返回Html字符串api |
||||
* @param url |
||||
* @param params |
||||
* @param callback |
||||
*/ |
||||
public static void getCommonReturnHtmlStringApi(String url, Map<String, Object> params, String charsetName, boolean isRefresh, final ResultCallback callback) { |
||||
HttpDataSource.httpGet_html(HttpUtil.makeURL(url, params), charsetName, isRefresh ,new ResultCallback() { |
||||
@Override |
||||
public void onFinish(Object o, int code) { |
||||
callback.onFinish(o,code); |
||||
} |
||||
|
||||
@Override |
||||
public void onError(Exception e) { |
||||
callback.onError(e); |
||||
// error(e,callback);
|
||||
} |
||||
}); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* get通用获取实体列表api |
||||
* @param url |
||||
* @param params |
||||
* @param c 返回是列表实体类型 |
||||
* @param callback |
||||
*/ |
||||
protected static void getCommonListApi(String url, Map<String, Object> params, final Class c, final ResultCallback callback) { |
||||
HttpDataSource.httpGet(HttpUtil.makeURL(url,params), new JsonCallback() { |
||||
@Override |
||||
public void onFinish(JsonModel jsonModel) { |
||||
if (jsonModel.isSuccess()) { |
||||
try { |
||||
callback.onFinish(GsonExtensionsKt.getGSON().fromJson(jsonModel.getResult(), c), jsonModel.getError()); |
||||
}catch (Exception e){ |
||||
callback.onError(e); |
||||
e.printStackTrace(); |
||||
} |
||||
} else { |
||||
noSuccess(jsonModel,callback); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onError(Exception e) { |
||||
error(e,callback); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* api异常处理 |
||||
* @param e |
||||
* @param callback |
||||
*/ |
||||
private static void error(Exception e, final ResultCallback callback){ |
||||
/* if (e.toString().contains("SocketTimeoutException") || e.toString().contains("UnknownHostException")) { |
||||
TextHelper.showText("网络连接超时,请检查网络"); |
||||
}*/ |
||||
e.printStackTrace(); |
||||
callback.onError(e); |
||||
} |
||||
|
||||
/** |
||||
* api请求失败处理 |
||||
* @param jsonModel |
||||
* @param callback |
||||
*/ |
||||
private static void noSuccess(JsonModel jsonModel, ResultCallback callback){ |
||||
if (!jsonModel.isSuccess()) { |
||||
if (jsonModel.getError() == ErrorCode.no_security) { |
||||
ToastUtils.showWarring("登录过期,请重新登录"); |
||||
} else { |
||||
if (jsonModel.getError() == 0) { |
||||
callback.onFinish(jsonModel.getResult(), -1); |
||||
} else { |
||||
callback.onFinish(jsonModel.getResult(), jsonModel.getError()); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue