书源兼容旧版

pull/1261/head
gedoor 4 years ago
parent 524e548bd9
commit 388d9bc5a2
  1. 18
      app/schemas/io.legado.app.data.AppDatabase/35.json
  2. 4
      app/src/main/java/io/legado/app/data/AppDatabase.kt
  3. 9
      app/src/main/java/io/legado/app/data/DatabaseMigrations.kt
  4. 16
      app/src/main/java/io/legado/app/data/entities/BookSource.kt
  5. 20
      app/src/main/java/io/legado/app/data/entities/rule/LoginRule.kt
  6. 10
      app/src/main/java/io/legado/app/data/entities/rule/RowUi.kt
  7. 12
      app/src/main/java/io/legado/app/help/storage/BookSourceAnalyzer.kt
  8. 4
      app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt
  9. 6
      app/src/main/java/io/legado/app/ui/book/login/SourceLoginDialog.kt
  10. 2
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  11. 2
      app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt
  12. 10
      app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt
  13. 22
      app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt

@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 35,
"identityHash": "cb54781f92ec7a911a363d0bcefa4845",
"identityHash": "25948a8defe4d091514bb725b4db7683",
"entities": [
{
"tableName": "books",
@ -254,7 +254,7 @@
},
{
"tableName": "book_sources",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`bookSourceName` TEXT NOT NULL, `bookSourceGroup` TEXT, `bookSourceUrl` TEXT NOT NULL, `bookSourceType` INTEGER NOT NULL, `bookUrlPattern` TEXT, `concurrentRate` TEXT, `customOrder` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `enabledExplore` INTEGER NOT NULL, `header` TEXT, `loginUrl` TEXT, `bookSourceComment` TEXT, `lastUpdateTime` INTEGER NOT NULL, `weight` INTEGER NOT NULL, `exploreUrl` TEXT, `ruleExplore` TEXT, `searchUrl` TEXT, `ruleSearch` TEXT, `ruleBookInfo` TEXT, `ruleToc` TEXT, `ruleContent` TEXT, PRIMARY KEY(`bookSourceUrl`))",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`bookSourceName` TEXT NOT NULL, `bookSourceGroup` TEXT, `bookSourceUrl` TEXT NOT NULL, `bookSourceType` INTEGER NOT NULL, `bookUrlPattern` TEXT, `concurrentRate` TEXT, `customOrder` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `enabledExplore` INTEGER NOT NULL, `header` TEXT, `loginUrl` TEXT, `loginUi` TEXT, `loginCheckJs` TEXT, `bookSourceComment` TEXT, `lastUpdateTime` INTEGER NOT NULL, `weight` INTEGER NOT NULL, `exploreUrl` TEXT, `ruleExplore` TEXT, `searchUrl` TEXT, `ruleSearch` TEXT, `ruleBookInfo` TEXT, `ruleToc` TEXT, `ruleContent` TEXT, PRIMARY KEY(`bookSourceUrl`))",
"fields": [
{
"fieldPath": "bookSourceName",
@ -322,6 +322,18 @@
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "loginUi",
"columnName": "loginUi",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "loginCheckJs",
"columnName": "loginCheckJs",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "bookSourceComment",
"columnName": "bookSourceComment",
@ -1423,7 +1435,7 @@
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'cb54781f92ec7a911a363d0bcefa4845')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '25948a8defe4d091514bb725b4db7683')"
]
}
}

@ -16,13 +16,13 @@ val appDb by lazy {
}
@Database(
version = 35,
version = 36,
exportSchema = true,
entities = [Book::class, BookGroup::class, BookSource::class, BookChapter::class,
ReplaceRule::class, SearchBook::class, SearchKeyword::class, Cookie::class,
RssSource::class, Bookmark::class, RssArticle::class, RssReadRecord::class,
RssStar::class, TxtTocRule::class, ReadRecord::class, HttpTTS::class, Cache::class,
RuleSub::class],
RuleSub::class]
)
abstract class AppDatabase : RoomDatabase() {

@ -31,7 +31,8 @@ object DatabaseMigrations {
migration_31_32,
migration_32_33,
migration_33_34,
migration_34_35
migration_34_35,
migration_35_36
)
}
@ -280,4 +281,10 @@ object DatabaseMigrations {
}
}
private val migration_35_36 = object : Migration(35, 36) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE `book_sources` ADD `loginUi` TEXT")
database.execSQL("ALTER TABLE `book_sources` ADD`loginCheckJs` TEXT")
}
}
}

@ -31,8 +31,10 @@ data class BookSource(
var customOrder: Int = 0, // 手动排序编号
var enabled: Boolean = true, // 是否启用
var enabledExplore: Boolean = true, // 启用发现
override var header: String? = null, // 请求头
var loginUrl: LoginRule? = null, // 登录地址
override var header: String? = null, // 请求头
var loginUrl: String? = null, // 登录地址
var loginUi: List<RowUi>? = null, //登录UI
var loginCheckJs: String? = null, //登录检测js
var bookSourceComment: String? = null, // 注释
var lastUpdateTime: Long = 0, // 最后更新时间,用于排序
var weight: Int = 0, // 智能排序的权重
@ -153,16 +155,10 @@ data class BookSource(
class Converters {
@TypeConverter
fun loginRuleToString(loginRule: LoginRule?): String = GSON.toJson(loginRule)
fun loginUiRuleToString(loginUi: List<RowUi>?): String = GSON.toJson(loginUi)
@TypeConverter
fun stringToLoginRule(json: String?): LoginRule? {
return when {
json.isNullOrEmpty() -> null
json.isJsonObject() -> GSON.fromJsonObject(json)
else -> LoginRule(url = json)
}
}
fun stringToLoginRule(json: String?): List<RowUi>? = GSON.fromJsonArray(json)
@TypeConverter
fun exploreRuleToString(exploreRule: ExploreRule?): String = GSON.toJson(exploreRule)

@ -1,20 +0,0 @@
package io.legado.app.data.entities.rule
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class LoginRule(
var ui: List<RowUi>? = null,
var url: String? = null, //url或js,js必须使用js标记
var checkJs: String? = null, //只能写js,不用js标记
) : Parcelable {
@Parcelize
data class RowUi(
var name: String,
var type: String,
) : Parcelable
}

@ -0,0 +1,10 @@
package io.legado.app.data.entities.rule
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class RowUi(
var name: String,
var type: String,
) : Parcelable

@ -1,6 +1,7 @@
package io.legado.app.help.storage
import androidx.annotation.Keep
import com.jayway.jsonpath.JsonPath
import io.legado.app.constant.AppConst
import io.legado.app.constant.BookType
import io.legado.app.data.entities.BookSource
@ -28,8 +29,7 @@ object BookSourceAnalyzer {
bookSourceUrl = jsonItem.readString("bookSourceUrl") ?: return null
bookSourceName = jsonItem.readString("bookSourceName") ?: ""
bookSourceGroup = jsonItem.readString("bookSourceGroup")
loginUrl =
BookSource.Converters().stringToLoginRule(jsonItem.readString("loginUrl"))
loginUrl = jsonItem.readString("loginUrl")
bookSourceComment = jsonItem.readString("bookSourceComment") ?: ""
bookUrlPattern = jsonItem.readString("ruleBookUrlPattern")
customOrder = jsonItem.readInt("serialNumber") ?: 0
@ -99,10 +99,12 @@ object BookSourceAnalyzer {
source.enabledExplore = sourceAny.enabledExplore
source.header = sourceAny.header
source.loginUrl = if (sourceAny.loginUrl is String) {
BookSource.Converters().stringToLoginRule(sourceAny.loginUrl.toString())
sourceAny.loginUrl.toString()
} else {
GSON.fromJsonObject(GSON.toJson(sourceAny.loginUrl))
JsonPath.parse(sourceAny.loginUrl).readString("url")
}
source.loginUi = sourceAny.loginUi
source.loginCheckJs = sourceAny.loginCheckJs
source.bookSourceComment = sourceAny.bookSourceComment
source.lastUpdateTime = sourceAny.lastUpdateTime
source.weight = sourceAny.weight
@ -152,6 +154,8 @@ object BookSourceAnalyzer {
var enabledExplore: Boolean = true, // 启用发现
var header: String? = null, // 请求头
var loginUrl: Any? = null, // 登录规则
var loginUi: List<RowUi>? = null, //登录UI
var loginCheckJs: String? = null, //登录检测js
var bookSourceComment: String? = "", //书源注释
var lastUpdateTime: Long = 0, // 最后更新时间,用于排序
var weight: Int = 0, // 智能排序的权重

@ -119,7 +119,7 @@ class BookInfoActivity :
menu.findItem(R.id.menu_can_update)?.isChecked =
viewModel.bookData.value?.canUpdate ?: true
menu.findItem(R.id.menu_login)?.isVisible =
!viewModel.bookSource?.loginUrl?.url.isNullOrBlank()
!viewModel.bookSource?.loginUrl.isNullOrBlank()
return super.onMenuOpened(featureId, menu)
}
@ -156,7 +156,7 @@ class BookInfoActivity :
R.id.menu_login -> viewModel.bookSource?.let {
startActivity<SourceLoginActivity> {
putExtra("sourceUrl", it.bookSourceUrl)
putExtra("loginUrl", it.loginUrl?.url)
putExtra("loginUrl", it.loginUrl)
putExtra("userAgent", it.getHeaderMap()[AppConst.UA_NAME])
}
}

@ -40,8 +40,8 @@ class SourceLoginDialog : BaseDialogFragment() {
val sourceUrl = arguments?.getString("sourceUrl") ?: return
val bookSource = appDb.bookSourceDao.getBookSource(sourceUrl) ?: return
val loginHeader = bookSource.getLoginHeader()
val loginRule = bookSource.loginUrl
loginRule?.ui?.forEachIndexed { index, rowUi ->
val loginUi = bookSource.loginUi
loginUi?.forEachIndexed { index, rowUi ->
when (rowUi.type) {
"text" -> layoutInflater.inflate(R.layout.item_source_edit, binding.root)
.apply {
@ -67,7 +67,7 @@ class SourceLoginDialog : BaseDialogFragment() {
when (it.itemId) {
R.id.menu_ok -> {
val loginData = hashMapOf<String, String?>()
loginRule?.ui?.forEachIndexed { index, rowUi ->
loginUi?.forEachIndexed { index, rowUi ->
when (rowUi.type) {
"text", "password" -> {
val value = binding.root.findViewById<TextInputLayout>(index)

@ -789,7 +789,7 @@ class ReadBookActivity : ReadBookBaseActivity(),
ReadBook.webBook?.bookSource?.let {
startActivity<SourceLoginActivity> {
putExtra("sourceUrl", it.bookSourceUrl)
putExtra("loginUrl", it.loginUrl?.url)
putExtra("loginUrl", it.loginUrl)
putExtra("userAgent", it.getHeaderMap()[AppConst.UA_NAME])
}
}

@ -284,7 +284,7 @@ class ReadMenu @JvmOverloads constructor(
}
fun upBookView() {
binding.tvLogin.isGone = ReadBook.webBook?.bookSource?.loginUrl?.url.isNullOrEmpty()
binding.tvLogin.isGone = ReadBook.webBook?.bookSource?.loginUrl.isNullOrEmpty()
ReadBook.curTextChapter?.let {
binding.tvChapterName.text = it.title
binding.tvChapterName.visible()

@ -41,7 +41,7 @@ class BookSourceEditActivity :
override val binding by viewBinding(ActivityBookSourceEditBinding::inflate)
override val viewModel by viewModels<BookSourceEditViewModel>()
private val converters = BookSource.Converters()
private val adapter = BookSourceEditAdapter()
private val sourceEntities: ArrayList<EditEntity> = ArrayList()
private val searchEntities: ArrayList<EditEntity> = ArrayList()
@ -117,12 +117,12 @@ class BookSourceEditActivity :
R.id.menu_help -> showRuleHelp()
R.id.menu_login -> getSource().let {
if (checkSource(it)) {
if (it.loginUrl?.url.isNullOrEmpty()) {
if (it.loginUrl.isNullOrEmpty()) {
toastOnUi(R.string.source_no_login)
} else {
startActivity<SourceLoginActivity> {
putExtra("sourceUrl", it.bookSourceUrl)
putExtra("loginUrl", it.loginUrl?.url)
putExtra("loginUrl", it.loginUrl)
putExtra("userAgent", it.getHeaderMap()[AppConst.UA_NAME])
}
}
@ -202,7 +202,7 @@ class BookSourceEditActivity :
add(
EditEntity(
"loginUrl",
converters.loginRuleToString(source?.loginUrl),
source?.loginUrl,
R.string.login_url
)
)
@ -302,7 +302,7 @@ class BookSourceEditActivity :
"bookSourceUrl" -> source.bookSourceUrl = it.value ?: ""
"bookSourceName" -> source.bookSourceName = it.value ?: ""
"bookSourceGroup" -> source.bookSourceGroup = it.value
"loginUrl" -> source.loginUrl = converters.stringToLoginRule(it.value)
"loginUrl" -> source.loginUrl = it.value
"bookUrlPattern" -> source.bookUrlPattern = it.value
"header" -> source.header = it.value
"bookSourceComment" -> source.bookSourceComment = it.value ?: ""

@ -6,8 +6,6 @@ import io.legado.app.base.BaseViewModel
import io.legado.app.data.appDb
import io.legado.app.data.entities.BookSource
import io.legado.app.help.storage.BookSourceAnalyzer
import io.legado.app.utils.GSON
import io.legado.app.utils.fromJsonObject
import io.legado.app.utils.getClipText
import io.legado.app.utils.toastOnUi
import kotlinx.coroutines.Dispatchers
@ -54,29 +52,21 @@ class BookSourceEditViewModel(application: Application) : BaseViewModel(applicat
fun pasteSource(onSuccess: (source: BookSource) -> Unit) {
execute(context = Dispatchers.Main) {
var source: BookSource? = null
context.getClipText()?.let { json ->
source = BookSourceAnalyzer.jsonToBookSource(json)
context.getClipText()?.let { text ->
importSource(text, onSuccess)
}
source
}.onError {
context.toastOnUi(it.localizedMessage)
context.toastOnUi(it.localizedMessage ?: "Error")
it.printStackTrace()
}.onSuccess {
if (it != null) {
onSuccess(it)
} else {
context.toastOnUi("格式不对")
}
}
}
fun importSource(text: String, finally: (source: BookSource) -> Unit) {
execute {
val text1 = text.trim()
GSON.fromJsonObject<BookSource>(text1)?.let {
finally.invoke(it)
}
BookSourceAnalyzer.jsonToBookSource(text1)
}.onSuccess {
it?.let(finally) ?: context.toastOnUi("格式不对")
}.onError {
context.toastOnUi(it.localizedMessage ?: "Error")
}

Loading…
Cancel
Save