BookSource.kt 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. package io.legato.kazusa.data.entities
  2. import android.os.Parcelable
  3. import android.text.TextUtils
  4. import androidx.room.ColumnInfo
  5. import androidx.room.Entity
  6. import androidx.room.Index
  7. import androidx.room.PrimaryKey
  8. import androidx.room.TypeConverter
  9. import androidx.room.TypeConverters
  10. import io.legato.kazusa.constant.AppPattern
  11. import io.legato.kazusa.constant.BookSourceType
  12. import io.legato.kazusa.data.entities.rule.BookInfoRule
  13. import io.legato.kazusa.data.entities.rule.ContentRule
  14. import io.legato.kazusa.data.entities.rule.ExploreRule
  15. import io.legato.kazusa.data.entities.rule.ReviewRule
  16. import io.legato.kazusa.data.entities.rule.SearchRule
  17. import io.legato.kazusa.data.entities.rule.TocRule
  18. import io.legato.kazusa.utils.GSON
  19. import io.legato.kazusa.utils.fromJsonObject
  20. import io.legato.kazusa.utils.splitNotBlank
  21. import kotlinx.parcelize.Parcelize
  22. @Suppress("unused")
  23. @Parcelize
  24. @TypeConverters(BookSource.Converters::class)
  25. @Entity(
  26. tableName = "book_sources",
  27. indices = [(Index(value = ["bookSourceUrl"], unique = false))]
  28. )
  29. data class BookSource(
  30. // 地址,包括 http/https
  31. @PrimaryKey
  32. var bookSourceUrl: String = "",
  33. // 名称
  34. var bookSourceName: String = "",
  35. // 分组
  36. var bookSourceGroup: String? = null,
  37. // 类型,0 文本,1 音频, 2 图片, 3 文件(指的是类似知轩藏书只提供下载的网站)
  38. @BookSourceType.Type
  39. var bookSourceType: Int = 0,
  40. // 详情页url正则
  41. var bookUrlPattern: String? = null,
  42. // 手动排序编号
  43. @ColumnInfo(defaultValue = "0")
  44. var customOrder: Int = 0,
  45. // 是否启用
  46. @ColumnInfo(defaultValue = "1")
  47. var enabled: Boolean = true,
  48. // 启用发现
  49. @ColumnInfo(defaultValue = "1")
  50. var enabledExplore: Boolean = true,
  51. // js库
  52. override var jsLib: String? = null,
  53. // 启用okhttp CookieJAr 自动保存每次请求的cookie
  54. @ColumnInfo(defaultValue = "0")
  55. override var enabledCookieJar: Boolean? = true,
  56. // 并发率
  57. override var concurrentRate: String? = null,
  58. // 请求头
  59. override var header: String? = null,
  60. // 登录地址
  61. override var loginUrl: String? = null,
  62. // 登录UI
  63. override var loginUi: String? = null,
  64. // 登录检测js
  65. var loginCheckJs: String? = null,
  66. // 封面解密js
  67. var coverDecodeJs: String? = null,
  68. // 注释
  69. var bookSourceComment: String? = null,
  70. // 自定义变量说明
  71. var variableComment: String? = null,
  72. // 最后更新时间,用于排序
  73. var lastUpdateTime: Long = 0,
  74. // 响应时间,用于排序
  75. var respondTime: Long = 180000L,
  76. // 智能排序的权重
  77. var weight: Int = 0,
  78. // 发现url
  79. var exploreUrl: String? = null,
  80. // 发现筛选规则
  81. var exploreScreen: String? = null,
  82. // 发现规则
  83. var ruleExplore: ExploreRule? = null,
  84. // 搜索url
  85. var searchUrl: String? = null,
  86. // 搜索规则
  87. var ruleSearch: SearchRule? = null,
  88. // 书籍信息页规则
  89. var ruleBookInfo: BookInfoRule? = null,
  90. // 目录页规则
  91. var ruleToc: TocRule? = null,
  92. // 正文页规则
  93. var ruleContent: ContentRule? = null,
  94. // 段评规则
  95. var ruleReview: ReviewRule? = null
  96. ) : Parcelable, BaseSource {
  97. override fun getTag(): String {
  98. return bookSourceName
  99. }
  100. override fun getKey(): String {
  101. return bookSourceUrl
  102. }
  103. override fun hashCode(): Int {
  104. return bookSourceUrl.hashCode()
  105. }
  106. override fun equals(other: Any?): Boolean {
  107. return if (other is BookSource) other.bookSourceUrl == bookSourceUrl else false
  108. }
  109. fun getSearchRule(): SearchRule {
  110. ruleSearch?.let { return it }
  111. val rule = SearchRule()
  112. ruleSearch = rule
  113. return rule
  114. }
  115. fun getExploreRule(): ExploreRule {
  116. ruleExplore?.let { return it }
  117. val rule = ExploreRule()
  118. ruleExplore = rule
  119. return rule
  120. }
  121. fun getBookInfoRule(): BookInfoRule {
  122. ruleBookInfo?.let { return it }
  123. val rule = BookInfoRule()
  124. ruleBookInfo = rule
  125. return rule
  126. }
  127. fun getTocRule(): TocRule {
  128. ruleToc?.let { return it }
  129. val rule = TocRule()
  130. ruleToc = rule
  131. return rule
  132. }
  133. fun getContentRule(): ContentRule {
  134. ruleContent?.let { return it }
  135. val rule = ContentRule()
  136. ruleContent = rule
  137. return rule
  138. }
  139. // fun getReviewRule(): ReviewRule {
  140. // ruleReview?.let { return it }
  141. // val rule = ReviewRule()
  142. // ruleReview = rule
  143. // return rule
  144. // }
  145. fun getDisPlayNameGroup(): String {
  146. return if (bookSourceGroup.isNullOrBlank()) {
  147. bookSourceName
  148. } else {
  149. String.format("%s (%s)", bookSourceName, bookSourceGroup)
  150. }
  151. }
  152. fun addGroup(groups: String): BookSource {
  153. bookSourceGroup?.splitNotBlank(AppPattern.splitGroupRegex)?.toHashSet()?.let {
  154. it.addAll(groups.splitNotBlank(AppPattern.splitGroupRegex))
  155. bookSourceGroup = TextUtils.join(",", it)
  156. }
  157. if (bookSourceGroup.isNullOrBlank()) bookSourceGroup = groups
  158. return this
  159. }
  160. fun removeGroup(groups: String): BookSource {
  161. bookSourceGroup?.splitNotBlank(AppPattern.splitGroupRegex)?.toHashSet()?.let {
  162. it.removeAll(groups.splitNotBlank(AppPattern.splitGroupRegex).toSet())
  163. bookSourceGroup = TextUtils.join(",", it)
  164. }
  165. return this
  166. }
  167. fun hasGroup(group: String): Boolean {
  168. bookSourceGroup?.splitNotBlank(AppPattern.splitGroupRegex)?.toHashSet()?.let {
  169. return it.indexOf(group) != -1
  170. }
  171. return false
  172. }
  173. fun removeInvalidGroups() {
  174. removeGroup(getInvalidGroupNames())
  175. }
  176. fun removeErrorComment() {
  177. bookSourceComment = bookSourceComment
  178. ?.split("\n\n")
  179. ?.filterNot {
  180. it.startsWith("// Error: ")
  181. }?.joinToString("\n")
  182. }
  183. fun addErrorComment(e: Throwable) {
  184. bookSourceComment =
  185. "// Error: ${e.localizedMessage}" + if (bookSourceComment.isNullOrBlank())
  186. "" else "\n\n${bookSourceComment}"
  187. }
  188. fun getCheckKeyword(default: String): String {
  189. ruleSearch?.checkKeyWord?.let {
  190. if (it.isNotBlank()) {
  191. return it
  192. }
  193. }
  194. return default
  195. }
  196. fun getInvalidGroupNames(): String {
  197. return bookSourceGroup?.splitNotBlank(AppPattern.splitGroupRegex)?.toHashSet()?.filter {
  198. "失效" in it || it == "校验超时"
  199. }?.joinToString() ?: ""
  200. }
  201. fun getDisplayVariableComment(otherComment: String): String {
  202. return if (variableComment.isNullOrBlank()) {
  203. otherComment
  204. } else {
  205. "${variableComment}\n$otherComment"
  206. }
  207. }
  208. fun equal(source: BookSource): Boolean {
  209. return equal(bookSourceName, source.bookSourceName)
  210. && equal(bookSourceUrl, source.bookSourceUrl)
  211. && equal(bookSourceGroup, source.bookSourceGroup)
  212. && bookSourceType == source.bookSourceType
  213. && equal(bookUrlPattern, source.bookUrlPattern)
  214. && equal(bookSourceComment, source.bookSourceComment)
  215. && customOrder == source.customOrder
  216. && enabled == source.enabled
  217. && enabledExplore == source.enabledExplore
  218. && enabledCookieJar == source.enabledCookieJar
  219. && equal(variableComment, source.variableComment)
  220. && equal(concurrentRate, source.concurrentRate)
  221. && equal(jsLib, source.jsLib)
  222. && equal(header, source.header)
  223. && equal(loginUrl, source.loginUrl)
  224. && equal(loginUi, source.loginUi)
  225. && equal(loginCheckJs, source.loginCheckJs)
  226. && equal(coverDecodeJs, source.coverDecodeJs)
  227. && equal(exploreUrl, source.exploreUrl)
  228. && equal(searchUrl, source.searchUrl)
  229. && getSearchRule() == source.getSearchRule()
  230. && getExploreRule() == source.getExploreRule()
  231. && getBookInfoRule() == source.getBookInfoRule()
  232. && getTocRule() == source.getTocRule()
  233. && getContentRule() == source.getContentRule()
  234. }
  235. private fun equal(a: String?, b: String?) = a == b || (a.isNullOrEmpty() && b.isNullOrEmpty())
  236. class Converters {
  237. @TypeConverter
  238. fun exploreRuleToString(exploreRule: ExploreRule?): String =
  239. GSON.toJson(exploreRule)
  240. @TypeConverter
  241. fun stringToExploreRule(json: String?) =
  242. GSON.fromJsonObject<ExploreRule>(json).getOrNull()
  243. @TypeConverter
  244. fun searchRuleToString(searchRule: SearchRule?): String =
  245. GSON.toJson(searchRule)
  246. @TypeConverter
  247. fun stringToSearchRule(json: String?) =
  248. GSON.fromJsonObject<SearchRule>(json).getOrNull()
  249. @TypeConverter
  250. fun bookInfoRuleToString(bookInfoRule: BookInfoRule?): String =
  251. GSON.toJson(bookInfoRule)
  252. @TypeConverter
  253. fun stringToBookInfoRule(json: String?) =
  254. GSON.fromJsonObject<BookInfoRule>(json).getOrNull()
  255. @TypeConverter
  256. fun tocRuleToString(tocRule: TocRule?): String =
  257. GSON.toJson(tocRule)
  258. @TypeConverter
  259. fun stringToTocRule(json: String?) =
  260. GSON.fromJsonObject<TocRule>(json).getOrNull()
  261. @TypeConverter
  262. fun contentRuleToString(contentRule: ContentRule?): String =
  263. GSON.toJson(contentRule)
  264. @TypeConverter
  265. fun stringToContentRule(json: String?) =
  266. GSON.fromJsonObject<ContentRule>(json).getOrNull()
  267. @TypeConverter
  268. fun stringToReviewRule(json: String?): ReviewRule? = null
  269. @TypeConverter
  270. fun reviewRuleToString(reviewRule: ReviewRule?): String = "null"
  271. }
  272. }