第三方3.0书源导入

pull/21/head
fengyuecanzhu 3 years ago
parent ef475af436
commit 42ccafde13
  1. 19
      app/src/main/java/xyz/fycz/myreader/entity/thirdsource/source3/BookInfoRule3.kt
  2. 15
      app/src/main/java/xyz/fycz/myreader/entity/thirdsource/source3/ContentRule3.kt
  3. 18
      app/src/main/java/xyz/fycz/myreader/entity/thirdsource/source3/ExploreRule3.kt
  4. 19
      app/src/main/java/xyz/fycz/myreader/entity/thirdsource/source3/SearchRule3.kt
  5. 36
      app/src/main/java/xyz/fycz/myreader/entity/thirdsource/source3/Source3.kt
  6. 101
      app/src/main/java/xyz/fycz/myreader/entity/thirdsource/source3/Third3SourceUtil.kt
  7. 15
      app/src/main/java/xyz/fycz/myreader/entity/thirdsource/source3/TocRule3.kt
  8. 12
      app/src/main/java/xyz/fycz/myreader/greendao/entity/rule/BookSource.java
  9. 27
      app/src/main/java/xyz/fycz/myreader/model/sourceAnalyzer/BookSourceManager.java
  10. 8
      app/src/main/java/xyz/fycz/myreader/model/third3/BookType.kt
  11. 318
      app/src/main/java/xyz/fycz/myreader/model/third3/SourceAnalyzer.kt
  12. 20
      app/src/main/java/xyz/fycz/myreader/model/third3/webBook/WebBook.kt
  13. 20
      app/src/main/java/xyz/fycz/myreader/util/utils/JsonExtensions.kt

@ -0,0 +1,19 @@
package xyz.fycz.myreader.entity.thirdsource.source3
/**
* @author fengyue
* @date 2022/1/20 13:49
*/
data class BookInfoRule3(
var init: String? = null,
var name: String? = null,
var author: String? = null,
var intro: String? = null,
var kind: String? = null,
var lastChapter: String? = null,
var updateTime: String? = null,
var coverUrl: String? = null,
var tocUrl: String? = null,
var wordCount: String? = null,
var canReName: String? = null
)

@ -0,0 +1,15 @@
package xyz.fycz.myreader.entity.thirdsource.source3
/**
* @author fengyue
* @date 2022/1/20 13:50
*/
data class ContentRule3(
var content: String? = null,
var nextContentUrl: String? = null,
var webJs: String? = null,
var sourceRegex: String? = null,
var replaceRegex: String? = null, //替换规则
var imageStyle: String? = null, //默认大小居中,FULL最大宽度
var payAction: String? = null, //购买操作,url/js
)

@ -0,0 +1,18 @@
package xyz.fycz.myreader.entity.thirdsource.source3
/**
* @author fengyue
* @date 2022/1/20 13:50
*/
data class ExploreRule3(
var bookList: String? = null,
var name: String? = null,
var author: String? = null,
var intro: String? = null,
var kind: String? = null,
var lastChapter: String? = null,
var updateTime: String? = null,
var bookUrl: String? = null,
var coverUrl: String? = null,
var wordCount: String? = null
)

@ -0,0 +1,19 @@
package xyz.fycz.myreader.entity.thirdsource.source3
/**
* @author fengyue
* @date 2022/1/20 13:48
*/
data class SearchRule3(
var checkKeyWord: String? = null, // 校验关键字
var bookList: String? = null,
var name: String? = null,
var author: String? = null,
var intro: String? = null,
var kind: String? = null,
var lastChapter: String? = null,
var updateTime: String? = null,
var bookUrl: String? = null,
var coverUrl: String? = null,
var wordCount: String? = null
)

@ -0,0 +1,36 @@
package xyz.fycz.myreader.entity.thirdsource.source3
/**
* @author fengyue
* @date 2022/1/20 13:47
*/
data class Source3(
var bookSourceUrl: String = "", // 地址,包括 http/https
var bookSourceName: String = "", // 名称
var bookSourceGroup: String? = null, // 分组
//未加
var bookSourceType: Int = 0, // 类型,0 文本,1 音频, 3 图片
var bookUrlPattern: String? = null, // 详情页url正则
var customOrder: Int = 0, // 手动排序编号
var enabled: Boolean = true, // 是否启用
//未加
var enabledExplore: Boolean = true, // 启用发现
var concurrentRate: String? = null, // 并发率
var header: String? = null, // 请求头
var loginUrl: String? = null, // 登录地址
//未加
var loginUi: String? = null, // 登录UI
var loginCheckJs: String? = null, // 登录检测js
var bookSourceComment: String? = null, // 注释
var lastUpdateTime: Long = 0, // 最后更新时间,用于排序
//未加
var respondTime: Long = 180000L, // 响应时间,用于排序
var weight: Int = 0, // 智能排序的权重
var exploreUrl: String? = null, // 发现url
var ruleExplore: ExploreRule3? = null, // 发现规则
var searchUrl: String? = null, // 搜索url
var ruleSearch: SearchRule3? = null, // 搜索规则
var ruleBookInfo: BookInfoRule3? = null, // 书籍信息页规则
var ruleToc: TocRule3? = null, // 目录页规则
var ruleContent: ContentRule3? = null // 正文页规则
)

@ -0,0 +1,101 @@
package xyz.fycz.myreader.entity.thirdsource.source3
import xyz.fycz.myreader.common.APPCONST
import xyz.fycz.myreader.greendao.entity.rule.*
/**
* @author fengyue
* @date 2022/1/20 13:51
*/
object Third3SourceUtil {
fun source3ToSource(bean: Source3): BookSource {
val bookSource = BookSource()
bookSource.sourceUrl = bean.bookSourceUrl
bookSource.sourceName = bean.bookSourceName
bookSource.sourceGroup = bean.bookSourceGroup
bookSource.sourceType = APPCONST.THIRD_3_SOURCE
bookSource.orderNum = bean.customOrder
bookSource.enable = bean.enabled
bookSource.concurrentRate = bean.concurrentRate
bookSource.sourceHeaders = bean.header
bookSource.loginUrl = bean.loginUrl
bookSource.loginCheckJs = bean.loginCheckJs
bookSource.sourceComment = bean.bookSourceComment
bookSource.lastUpdateTime = bean.lastUpdateTime
bookSource.weight = bean.weight
val searchRule = SearchRule()
val ruleSearch = bean.ruleSearch
searchRule.searchUrl = bean.searchUrl
searchRule.list = ruleSearch?.bookList
searchRule.name = ruleSearch?.name
searchRule.author = ruleSearch?.author
searchRule.desc = ruleSearch?.intro
searchRule.type = ruleSearch?.kind
searchRule.lastChapter = ruleSearch?.lastChapter
searchRule.updateTime = ruleSearch?.updateTime
searchRule.infoUrl = ruleSearch?.bookUrl
searchRule.imgUrl = ruleSearch?.coverUrl
searchRule.wordCount = ruleSearch?.wordCount
searchRule.isRelatedWithInfo = true
bookSource.searchRule = searchRule
val infoRule = InfoRule()
val ruleInfo = bean.ruleBookInfo
infoRule.urlPattern = bean.bookUrlPattern
infoRule.init = ruleInfo?.init
infoRule.name = ruleInfo?.name
infoRule.author = ruleInfo?.author
infoRule.desc = ruleInfo?.intro
infoRule.type = ruleInfo?.kind
infoRule.lastChapter = ruleInfo?.lastChapter
infoRule.updateTime = ruleInfo?.updateTime
infoRule.imgUrl = ruleInfo?.coverUrl
infoRule.tocUrl = ruleInfo?.tocUrl
infoRule.wordCount = ruleInfo?.wordCount
bookSource.infoRule = infoRule
val tocRule = TocRule()
val ruleToc = bean.ruleToc
tocRule.chapterList = ruleToc?.chapterList
tocRule.chapterName = ruleToc?.chapterName
tocRule.chapterUrl = ruleToc?.chapterUrl
tocRule.isVip = ruleToc?.isVip
tocRule.isPay = ruleToc?.isPay
tocRule.updateTime = ruleToc?.updateTime
tocRule.tocUrlNext = ruleToc?.nextTocUrl
bookSource.tocRule = tocRule
val contentRule = ContentRule()
val ruleContent = bean.ruleContent
contentRule.content = ruleContent?.content
contentRule.contentUrlNext = ruleContent?.nextContentUrl
contentRule.replaceRegex = ruleContent?.replaceRegex
bookSource.contentRule = contentRule
val findRule = FindRule()
val ruleFind = bean.ruleExplore
findRule.url = bean.exploreUrl
findRule.list = ruleFind?.bookList
findRule.name = ruleFind?.name
findRule.author = ruleFind?.author
findRule.desc = ruleFind?.intro
findRule.type = ruleFind?.kind
findRule.lastChapter = ruleFind?.lastChapter
findRule.updateTime = ruleFind?.updateTime
findRule.imgUrl = ruleFind?.coverUrl
findRule.infoUrl = ruleFind?.bookUrl
findRule.wordCount = ruleFind?.wordCount
bookSource.findRule = findRule
return bookSource
}
fun source3sToSources(source3s: List<Source3>): List<BookSource> {
val sources = mutableListOf<BookSource>()
source3s.forEach {
sources.add(source3ToSource(it))
}
return sources
}
}

@ -0,0 +1,15 @@
package xyz.fycz.myreader.entity.thirdsource.source3
/**
* @author fengyue
* @date 2022/1/20 13:50
*/
data class TocRule3(
var chapterList: String? = null,
var chapterName: String? = null,
var chapterUrl: String? = null,
var isVip: String? = null,
var isPay: String? = null,
var updateTime: String? = null,
var nextTocUrl: String? = null
)

@ -43,6 +43,7 @@ public class BookSource implements Parcelable, Cloneable {
private String sourceType; private String sourceType;
private String sourceHeaders; private String sourceHeaders;
private String loginUrl; private String loginUrl;
private String loginCheckJs;
private String sourceComment; private String sourceComment;
private String concurrentRate; private String concurrentRate;
private Long lastUpdateTime; private Long lastUpdateTime;
@ -114,6 +115,7 @@ public class BookSource implements Parcelable, Cloneable {
sourceType = in.readString(); sourceType = in.readString();
sourceHeaders = in.readString(); sourceHeaders = in.readString();
loginUrl = in.readString(); loginUrl = in.readString();
loginCheckJs = in.readString();
sourceComment = in.readString(); sourceComment = in.readString();
concurrentRate = in.readString(); concurrentRate = in.readString();
if (in.readByte() == 0) { if (in.readByte() == 0) {
@ -141,6 +143,7 @@ public class BookSource implements Parcelable, Cloneable {
dest.writeString(sourceType); dest.writeString(sourceType);
dest.writeString(sourceHeaders); dest.writeString(sourceHeaders);
dest.writeString(loginUrl); dest.writeString(loginUrl);
dest.writeString(loginCheckJs);
dest.writeString(sourceComment); dest.writeString(sourceComment);
dest.writeString(concurrentRate); dest.writeString(concurrentRate);
if (lastUpdateTime == null) { if (lastUpdateTime == null) {
@ -190,6 +193,7 @@ public class BookSource implements Parcelable, Cloneable {
stringEquals(sourceType, source.sourceType) && stringEquals(sourceType, source.sourceType) &&
stringEquals(sourceHeaders, source.sourceHeaders) && stringEquals(sourceHeaders, source.sourceHeaders) &&
stringEquals(loginUrl, source.loginUrl) && stringEquals(loginUrl, source.loginUrl) &&
stringEquals(loginCheckJs, source.loginCheckJs) &&
stringEquals(sourceComment, source.sourceComment) && stringEquals(sourceComment, source.sourceComment) &&
stringEquals(concurrentRate, source.concurrentRate) && stringEquals(concurrentRate, source.concurrentRate) &&
Objects.equals(searchRule, source.searchRule) && Objects.equals(searchRule, source.searchRule) &&
@ -402,6 +406,14 @@ public class BookSource implements Parcelable, Cloneable {
this.loginUrl = loginUrl; this.loginUrl = loginUrl;
} }
public String getLoginCheckJs() {
return loginCheckJs;
}
public void setLoginCheckJs(String loginCheckJs) {
this.loginCheckJs = loginCheckJs;
}
public String getConcurrentRate() { public String getConcurrentRate() {
return this.concurrentRate; return this.concurrentRate;
} }

@ -18,10 +18,13 @@ import xyz.fycz.myreader.application.App;
import xyz.fycz.myreader.entity.thirdsource.BookSource3Bean; import xyz.fycz.myreader.entity.thirdsource.BookSource3Bean;
import xyz.fycz.myreader.entity.thirdsource.BookSourceBean; import xyz.fycz.myreader.entity.thirdsource.BookSourceBean;
import xyz.fycz.myreader.entity.thirdsource.ThirdSourceUtil; import xyz.fycz.myreader.entity.thirdsource.ThirdSourceUtil;
import xyz.fycz.myreader.entity.thirdsource.source3.Source3;
import xyz.fycz.myreader.entity.thirdsource.source3.Third3SourceUtil;
import xyz.fycz.myreader.enums.LocalBookSource; import xyz.fycz.myreader.enums.LocalBookSource;
import xyz.fycz.myreader.greendao.DbManager; import xyz.fycz.myreader.greendao.DbManager;
import xyz.fycz.myreader.greendao.entity.rule.BookSource; import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.greendao.gen.BookSourceDao; import xyz.fycz.myreader.greendao.gen.BookSourceDao;
import xyz.fycz.myreader.model.third3.SourceAnalyzer;
import xyz.fycz.myreader.util.SharedPreUtils; import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.help.StringHelper; import xyz.fycz.myreader.util.help.StringHelper;
import xyz.fycz.myreader.util.utils.FileUtils; import xyz.fycz.myreader.util.utils.FileUtils;
@ -355,16 +358,17 @@ public class BookSourceManager {
return sources; return sources;
} }
List<Source3> source3s = SourceAnalyzer.INSTANCE.jsonToBookSources(json);
String source3sJson = GsonExtensionsKt.getGSON().toJson(source3s);
if (source3s.size() > 0 && source3sJson.length() > source3s.size() * SOURCE_LENGTH) {
return Third3SourceUtil.INSTANCE.source3sToSources(source3s);
}
List<BookSourceBean> source2s = GsonUtils.parseJArray(json, BookSourceBean.class); List<BookSourceBean> source2s = GsonUtils.parseJArray(json, BookSourceBean.class);
String source2sJson = GsonExtensionsKt.getGSON().toJson(source2s); String source2sJson = GsonExtensionsKt.getGSON().toJson(source2s);
if (source2s.size() > 0 && source2sJson.length() > source2s.size() * SOURCE_LENGTH) { if (source2s.size() > 0 && source2sJson.length() > source2s.size() * SOURCE_LENGTH) {
return ThirdSourceUtil.source2sToSources(source2s); return ThirdSourceUtil.source2sToSources(source2s);
} }
List<BookSource3Bean> source3s = GsonUtils.parseJArray(json, BookSource3Bean.class);
String source3sJson = GsonExtensionsKt.getGSON().toJson(source3s);
if (source3s.size() > 0 && source3sJson.length() > source3s.size() * SOURCE_LENGTH) {
return ThirdSourceUtil.source3sToSources(source3s);
}
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -379,6 +383,13 @@ public class BookSourceManager {
return sources; return sources;
} }
Source3 source3 = SourceAnalyzer.INSTANCE.jsonToBookSource(json);
String source3Json = GsonExtensionsKt.getGSON().toJson(source3);
if (!StringHelper.isEmpty(source3Json) && source3Json.length() > SOURCE_LENGTH) {
sources.add(Third3SourceUtil.INSTANCE.source3ToSource(source3));
return sources;
}
BookSourceBean source2 = GsonUtils.parseJObject(json, BookSourceBean.class); BookSourceBean source2 = GsonUtils.parseJObject(json, BookSourceBean.class);
String source2Json = GsonExtensionsKt.getGSON().toJson(source2); String source2Json = GsonExtensionsKt.getGSON().toJson(source2);
if (!StringHelper.isEmpty(source2Json) && source2Json.length() > SOURCE_LENGTH) { if (!StringHelper.isEmpty(source2Json) && source2Json.length() > SOURCE_LENGTH) {
@ -386,12 +397,6 @@ public class BookSourceManager {
return sources; return sources;
} }
BookSource3Bean source3 = GsonUtils.parseJObject(json, BookSource3Bean.class);
String source3Json = GsonExtensionsKt.getGSON().toJson(source3);
if (!StringHelper.isEmpty(source3Json) && source3Json.length() > SOURCE_LENGTH) {
sources.add(ThirdSourceUtil.source3ToSource(source3));
return sources;
}
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }

@ -0,0 +1,8 @@
package xyz.fycz.myreader.model.third3
object BookType {
const val default = 0 // 0 文本
const val audio = 1 // 1 音频
const val image = 3 //图片
const val local = "loc_book"
}

@ -0,0 +1,318 @@
package xyz.fycz.myreader.model.third3
import android.util.Log
import androidx.annotation.Keep
import com.jayway.jsonpath.JsonPath
import xyz.fycz.myreader.common.APPCONST
import xyz.fycz.myreader.entity.thirdsource.source3.*
import xyz.fycz.myreader.util.utils.*
import java.util.regex.Pattern
@Suppress("RegExpRedundantEscape")
object SourceAnalyzer {
private val headerPattern = Pattern.compile("@Header:\\{.+?\\}", Pattern.CASE_INSENSITIVE)
private val jsPattern = Pattern.compile("\\{\\{.+?\\}\\}", Pattern.CASE_INSENSITIVE)
fun jsonToBookSources(json: String): List<Source3> {
val bookSources = mutableListOf<Source3>()
val items: List<Map<String, Any>> = jsonPath.parse(json).read("$")
for (item in items) {
val jsonItem = jsonPath.parse(item)
jsonToBookSource(jsonItem.jsonString())?.let {
bookSources.add(it)
}
}
return bookSources
}
fun jsonToBookSource(json: String): Source3? {
val source = Source3()
val sourceAny = try {
GSON.fromJsonObject<BookSourceAny>(json.trim())
} catch (e: Exception) {
null
}
try {
if (sourceAny?.ruleToc == null) {
source.apply {
val jsonItem = jsonPath.parse(json.trim())
bookSourceUrl = jsonItem.readString("bookSourceUrl") ?: return null
bookSourceName = jsonItem.readString("bookSourceName") ?: ""
bookSourceGroup = jsonItem.readString("bookSourceGroup")
loginUrl = jsonItem.readString("loginUrl")
loginUi = jsonItem.readString("loginUi")
loginCheckJs = jsonItem.readString("loginCheckJs")
bookSourceComment = jsonItem.readString("bookSourceComment") ?: ""
bookUrlPattern = jsonItem.readString("ruleBookUrlPattern")
customOrder = jsonItem.readInt("serialNumber") ?: 0
header = uaToHeader(jsonItem.readString("httpUserAgent"))
searchUrl = toNewUrl(jsonItem.readString("ruleSearchUrl"))
exploreUrl = toNewUrls(jsonItem.readString("ruleFindUrl"))
bookSourceType =
if (jsonItem.readString("bookSourceType") == "AUDIO") BookType.audio else BookType.default
enabled = jsonItem.readBool("enable") ?: true
if (exploreUrl.isNullOrBlank()) {
enabledExplore = false
}
ruleSearch = SearchRule3(
bookList = toNewRule(jsonItem.readString("ruleSearchList")),
name = toNewRule(jsonItem.readString("ruleSearchName")),
author = toNewRule(jsonItem.readString("ruleSearchAuthor")),
intro = toNewRule(jsonItem.readString("ruleSearchIntroduce")),
kind = toNewRule(jsonItem.readString("ruleSearchKind")),
bookUrl = toNewRule(jsonItem.readString("ruleSearchNoteUrl")),
coverUrl = toNewRule(jsonItem.readString("ruleSearchCoverUrl")),
lastChapter = toNewRule(jsonItem.readString("ruleSearchLastChapter"))
)
ruleExplore = ExploreRule3(
bookList = toNewRule(jsonItem.readString("ruleFindList")),
name = toNewRule(jsonItem.readString("ruleFindName")),
author = toNewRule(jsonItem.readString("ruleFindAuthor")),
intro = toNewRule(jsonItem.readString("ruleFindIntroduce")),
kind = toNewRule(jsonItem.readString("ruleFindKind")),
bookUrl = toNewRule(jsonItem.readString("ruleFindNoteUrl")),
coverUrl = toNewRule(jsonItem.readString("ruleFindCoverUrl")),
lastChapter = toNewRule(jsonItem.readString("ruleFindLastChapter"))
)
ruleBookInfo = BookInfoRule3(
init = toNewRule(jsonItem.readString("ruleBookInfoInit")),
name = toNewRule(jsonItem.readString("ruleBookName")),
author = toNewRule(jsonItem.readString("ruleBookAuthor")),
intro = toNewRule(jsonItem.readString("ruleIntroduce")),
kind = toNewRule(jsonItem.readString("ruleBookKind")),
coverUrl = toNewRule(jsonItem.readString("ruleCoverUrl")),
lastChapter = toNewRule(jsonItem.readString("ruleBookLastChapter")),
tocUrl = toNewRule(jsonItem.readString("ruleChapterUrl"))
)
ruleToc = TocRule3(
chapterList = toNewRule(jsonItem.readString("ruleChapterList")),
chapterName = toNewRule(jsonItem.readString("ruleChapterName")),
chapterUrl = toNewRule(jsonItem.readString("ruleContentUrl")),
nextTocUrl = toNewRule(jsonItem.readString("ruleChapterUrlNext"))
)
var content = toNewRule(jsonItem.readString("ruleBookContent")) ?: ""
if (content.startsWith("$") && !content.startsWith("$.")) {
content = content.substring(1)
}
ruleContent = ContentRule3(
content = content,
replaceRegex = toNewRule(jsonItem.readString("ruleBookContentReplace")),
nextContentUrl = toNewRule(jsonItem.readString("ruleContentUrlNext"))
)
}
} else {
source.bookSourceUrl = sourceAny.bookSourceUrl
source.bookSourceName = sourceAny.bookSourceName
source.bookSourceGroup = sourceAny.bookSourceGroup
source.bookSourceType = sourceAny.bookSourceType
source.bookUrlPattern = sourceAny.bookUrlPattern
source.customOrder = sourceAny.customOrder
source.enabled = sourceAny.enabled
source.enabledExplore = sourceAny.enabledExplore
source.concurrentRate = sourceAny.concurrentRate
source.header = sourceAny.header
source.loginUrl = when (sourceAny.loginUrl) {
null -> null
is String -> sourceAny.loginUrl.toString()
else -> JsonPath.parse(sourceAny.loginUrl).readString("url")
}
source.loginUi = if (sourceAny.loginUi is List<*>) {
GSON.toJson(sourceAny.loginUi)
} else {
sourceAny.loginUi?.toString()
}
source.loginCheckJs = sourceAny.loginCheckJs
source.bookSourceComment = sourceAny.bookSourceComment
source.lastUpdateTime = sourceAny.lastUpdateTime
source.respondTime = sourceAny.respondTime
source.weight = sourceAny.weight
source.exploreUrl = sourceAny.exploreUrl
source.ruleExplore = if (sourceAny.ruleExplore is String) {
GSON.fromJsonObject(sourceAny.ruleExplore.toString())
} else {
GSON.fromJsonObject(GSON.toJson(sourceAny.ruleExplore))
}
source.searchUrl = sourceAny.searchUrl
source.ruleSearch = if (sourceAny.ruleSearch is String) {
GSON.fromJsonObject(sourceAny.ruleSearch.toString())
} else {
GSON.fromJsonObject(GSON.toJson(sourceAny.ruleSearch))
}
source.ruleBookInfo = if (sourceAny.ruleBookInfo is String) {
GSON.fromJsonObject(sourceAny.ruleBookInfo.toString())
} else {
GSON.fromJsonObject(GSON.toJson(sourceAny.ruleBookInfo))
}
source.ruleToc = if (sourceAny.ruleToc is String) {
GSON.fromJsonObject(sourceAny.ruleToc.toString())
} else {
GSON.fromJsonObject(GSON.toJson(sourceAny.ruleToc))
}
source.ruleContent = if (sourceAny.ruleContent is String) {
GSON.fromJsonObject(sourceAny.ruleContent.toString())
} else {
GSON.fromJsonObject(GSON.toJson(sourceAny.ruleContent))
}
}
} catch (e: Exception) {
Log.e("SourceAnalyzer", "" + e.localizedMessage)
}
return source
}
@Keep
data class BookSourceAny(
var bookSourceName: String = "", // 名称
var bookSourceGroup: String? = null, // 分组
var bookSourceUrl: String = "", // 地址,包括 http/https
var bookSourceType: Int = BookType.default, // 类型,0 文本,1 音频
var bookUrlPattern: String? = null, // 详情页url正则
var customOrder: Int = 0, // 手动排序编号
var enabled: Boolean = true, // 是否启用
var enabledExplore: Boolean = true, // 启用发现
var concurrentRate: String? = null, // 并发率
var header: String? = null, // 请求头
var loginUrl: Any? = null, // 登录规则
var loginUi: Any? = null, // 登录UI
var loginCheckJs: String? = null, //登录检测js
var bookSourceComment: String? = "", //书源注释
var lastUpdateTime: Long = 0, // 最后更新时间,用于排序
var respondTime: Long = 180000L, // 响应时间,用于排序
var weight: Int = 0, // 智能排序的权重
var exploreUrl: String? = null, // 发现url
var ruleExplore: Any? = null, // 发现规则
var searchUrl: String? = null, // 搜索url
var ruleSearch: Any? = null, // 搜索规则
var ruleBookInfo: Any? = null, // 书籍信息页规则
var ruleToc: Any? = null, // 目录页规则
var ruleContent: Any? = null // 正文页规则
)
// default规则适配
// #正则#替换内容 替换成 ##正则##替换内容
// | 替换成 ||
// & 替换成 &&
private fun toNewRule(oldRule: String?): String? {
if (oldRule.isNullOrBlank()) return null
var newRule = oldRule
var reverse = false
var allinone = false
if (oldRule.startsWith("-")) {
reverse = true
newRule = oldRule.substring(1)
}
if (newRule.startsWith("+")) {
allinone = true
newRule = newRule.substring(1)
}
if (!newRule.startsWith("@CSS:", true) &&
!newRule.startsWith("@XPath:", true) &&
!newRule.startsWith("//") &&
!newRule.startsWith("##") &&
!newRule.startsWith(":") &&
!newRule.contains("@js:", true) &&
!newRule.contains("<js>", true)
) {
if (newRule.contains("#") && !newRule.contains("##")) {
newRule = oldRule.replace("#", "##")
}
if (newRule.contains("|") && !newRule.contains("||")) {
if (newRule.contains("##")) {
val list = newRule.split("##")
if (list[0].contains("|")) {
newRule = list[0].replace("|", "||")
for (i in 1 until list.size) {
newRule += "##" + list[i]
}
}
} else {
newRule = newRule.replace("|", "||")
}
}
if (newRule.contains("&")
&& !newRule.contains("&&")
&& !newRule.contains("http")
&& !newRule.startsWith("/")
) {
newRule = newRule.replace("&", "&&")
}
}
if (allinone) {
newRule = "+$newRule"
}
if (reverse) {
newRule = "-$newRule"
}
return newRule
}
private fun toNewUrls(oldUrls: String?): String? {
if (oldUrls.isNullOrBlank()) return null
if (oldUrls.startsWith("@js:") || oldUrls.startsWith("<js>")) {
return oldUrls
}
if (!oldUrls.contains("\n") && !oldUrls.contains("&&")) {
return toNewUrl(oldUrls)
}
val urls = oldUrls.split("(&&|\r?\n)+".toRegex())
return urls.map {
toNewUrl(it)?.replace("\n\\s*".toRegex(), "")
}.joinToString("\n")
}
private fun toNewUrl(oldUrl: String?): String? {
if (oldUrl.isNullOrBlank()) return null
var url: String = oldUrl
if (oldUrl.startsWith("<js>", true)) {
url = url.replace("=searchKey", "={{key}}")
.replace("=searchPage", "={{page}}")
return url
}
val map = HashMap<String, String>()
var mather = headerPattern.matcher(url)
if (mather.find()) {
val header = mather.group()
url = url.replace(header, "")
map["headers"] = header.substring(8)
}
var urlList = url.split("|")
url = urlList[0]
if (urlList.size > 1) {
map["charset"] = urlList[1].split("=")[1]
}
mather = jsPattern.matcher(url)
val jsList = arrayListOf<String>()
while (mather.find()) {
jsList.add(mather.group())
url = url.replace(jsList.last(), "$${jsList.size - 1}")
}
url = url.replace("{", "<").replace("}", ">")
url = url.replace("searchKey", "{{key}}")
url = url.replace("<searchPage([-+]1)>".toRegex(), "{{page$1}}")
.replace("searchPage([-+]1)".toRegex(), "{{page$1}}")
.replace("searchPage", "{{page}}")
for ((index, item) in jsList.withIndex()) {
url = url.replace(
"$$index",
item.replace("searchKey", "key").replace("searchPage", "page")
)
}
urlList = url.split("@")
url = urlList[0]
if (urlList.size > 1) {
map["method"] = "POST"
map["body"] = urlList[1]
}
if (map.size > 0) {
url += "," + GSON.toJson(map)
}
return url
}
private fun uaToHeader(ua: String?): String? {
if (ua.isNullOrEmpty()) return null
val map = mapOf(Pair(APPCONST.UA_NAME, ua))
return GSON.toJson(map)
}
}

@ -51,11 +51,11 @@ object WebBook {
) )
var res = analyzeUrl.getStrResponseAwait() var res = analyzeUrl.getStrResponseAwait()
//检测书源是否已登录 //检测书源是否已登录
/*bookSource.loginCheckJs?.let { checkJs -> bookSource.loginCheckJs?.let { checkJs ->
if (checkJs.isNotBlank()) { if (checkJs.isNotBlank()) {
res = analyzeUrl.evalJS(checkJs, res) as StrResponse res = analyzeUrl.evalJS(checkJs, res) as StrResponse
} }
}*/ }
return BookList.analyzeBookList( return BookList.analyzeBookList(
scope, scope,
bookSource, bookSource,
@ -101,11 +101,11 @@ object WebBook {
) )
var res = analyzeUrl.getStrResponseAwait() var res = analyzeUrl.getStrResponseAwait()
//检测书源是否已登录 //检测书源是否已登录
/*bookSource.loginCheckJs?.let { checkJs -> bookSource.loginCheckJs?.let { checkJs ->
if (checkJs.isNotBlank()) { if (checkJs.isNotBlank()) {
res = analyzeUrl.evalJS(checkJs, result = res) as StrResponse res = analyzeUrl.evalJS(checkJs, result = res) as StrResponse
} }
}*/ }
return BookList.analyzeBookList( return BookList.analyzeBookList(
scope, scope,
bookSource, bookSource,
@ -159,11 +159,11 @@ object WebBook {
) )
var res = analyzeUrl.getStrResponseAwait() var res = analyzeUrl.getStrResponseAwait()
//检测书源是否已登录 //检测书源是否已登录
/*bookSource.loginCheckJs?.let { checkJs -> bookSource.loginCheckJs?.let { checkJs ->
if (checkJs.isNotBlank()) { if (checkJs.isNotBlank()) {
res = analyzeUrl.evalJS(checkJs, result = res) as StrResponse res = analyzeUrl.evalJS(checkJs, result = res) as StrResponse
} }
}*/ }
BookInfo.analyzeBookInfo( BookInfo.analyzeBookInfo(
scope, scope,
bookSource, bookSource,
@ -215,11 +215,11 @@ object WebBook {
) )
var res = analyzeUrl.getStrResponseAwait() var res = analyzeUrl.getStrResponseAwait()
//检测书源是否已登录 //检测书源是否已登录
/*bookSource.loginCheckJs?.let { checkJs -> bookSource.loginCheckJs?.let { checkJs ->
if (checkJs.isNotBlank()) { if (checkJs.isNotBlank()) {
res = analyzeUrl.evalJS(checkJs, result = res) as StrResponse res = analyzeUrl.evalJS(checkJs, result = res) as StrResponse
} }
}*/ }
BookChapterList.analyzeChapterList( BookChapterList.analyzeChapterList(
scope, scope,
bookSource, bookSource,
@ -284,11 +284,11 @@ object WebBook {
)*/ )*/
var res = analyzeUrl.getStrResponseAwait() var res = analyzeUrl.getStrResponseAwait()
//检测书源是否已登录 //检测书源是否已登录
/*bookSource.loginCheckJs?.let { checkJs -> bookSource.loginCheckJs?.let { checkJs ->
if (checkJs.isNotBlank()) { if (checkJs.isNotBlank()) {
res = analyzeUrl.evalJS(checkJs, result = res) as StrResponse res = analyzeUrl.evalJS(checkJs, result = res) as StrResponse
} }
}*/ }
BookContent.analyzeContent( BookContent.analyzeContent(
scope, scope,
bookSource, bookSource,

@ -0,0 +1,20 @@
package xyz.fycz.myreader.util.utils
import com.jayway.jsonpath.*
val jsonPath: ParseContext by lazy {
JsonPath.using(
Configuration.builder()
.options(Option.SUPPRESS_EXCEPTIONS)
.build()
)
}
fun ReadContext.readString(path: String): String? = this.read(path, String::class.java)
fun ReadContext.readBool(path: String): Boolean? = this.read(path, Boolean::class.java)
fun ReadContext.readInt(path: String): Int? = this.read(path, Int::class.java)
fun ReadContext.readLong(path: String): Long? = this.read(path, Long::class.java)
Loading…
Cancel
Save