Added importing book shelf from YueDu

pull/32/head
atbest 6 years ago
parent 4b8f6e3f9b
commit 5f2991373b
  1. 4
      app/src/main/java/com/jayway/jsonpath/spi/json/GsonJsonProvider.java
  2. 11
      app/src/main/java/io/legado/app/data/dao/BookDao.kt
  3. 2
      app/src/main/java/io/legado/app/data/entities/Book.kt
  4. 78
      app/src/main/java/io/legado/app/ui/main/MainActivity.kt
  5. 14
      app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt
  6. 8
      app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt
  7. 3
      app/src/main/java/io/legado/app/utils/MiscExtensions.kt
  8. 6
      app/src/main/res/drawable/ic_divider.xml
  9. 4
      app/src/main/res/layout/activity_replace_rule.xml
  10. 12
      app/src/main/res/layout/item_relace_rule.xml

@ -247,8 +247,8 @@ public class GsonJsonProvider extends AbstractJsonProvider {
}
}
throw new JsonPathException("length operation can not applied to " + obj != null ? obj.getClass().getName()
: "null");
throw new JsonPathException("length operation can not applied to " + (obj != null ? obj.getClass().getName()
: "null"));
}
@Override

@ -3,6 +3,8 @@ package io.legado.app.data.dao
import androidx.lifecycle.LiveData
import androidx.paging.DataSource
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import io.legado.app.data.entities.Book
@ -19,4 +21,13 @@ interface BookDao {
@Query("SELECT * FROM books WHERE `name` in (:names)")
fun findByName(vararg names: String): List<Book>
@get:Query("SELECT descUrl FROM books")
val allBookUrls: List<String>
@get:Query("SELECT COUNT(*) FROM books")
val allBookCount: Int
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(vararg books: Book)
}

@ -35,6 +35,8 @@ data class Book(@PrimaryKey
var durChapterPos: Int = 0, // 当前阅读的进度(首行字符的索引位置)
var durChapterTime: Long = 0, // 最近一次阅读书籍的时间(打开正文的时间)
var canUpdate: Boolean = true, // 刷新书架时更新书籍信息
var order: Int = 0, // 手动排序
var useReplaceRule: Boolean = true, // 正文使用净化替换规则
var variable: String? = null // 自定义书籍变量信息(用于书源规则检索书籍信息)
) : Parcelable {

@ -16,6 +16,7 @@ import io.legado.app.App
import io.legado.app.R
import io.legado.app.base.BaseActivity
import io.legado.app.constant.AppConst.APP_TAG
import io.legado.app.data.entities.Book
import io.legado.app.data.entities.ReplaceRule
import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat
@ -107,30 +108,85 @@ class MainActivity : BaseActivity<MainDataBinding, MainViewModel>(), NavigationV
.build()
)
// 导入书架
val shelfFile = File(yuedu, "myBookShelf.json")
val books = mutableListOf<Book>()
if (shelfFile.exists()) try {
doAsync {
val items: List<Map<String, Any>> = jsonPath.parse(shelfFile.readText()).read("$")
val existingBooks = App.db.bookDao().allBookUrls.toSet()
for (item in items) {
val jsonItem = jsonPath.parse(item)
val book = Book()
book.descUrl = jsonItem.readString("$.noteUrl") ?: ""
if (book.descUrl.isBlank()) continue
book.name = jsonItem.readString("$.bookInfoBean.name")
if (book.descUrl in existingBooks) {
Log.d(APP_TAG, "Found existing book: ${book.name}")
continue
}
book.author = jsonItem.readString("$.bookInfoBean.author")
book.type = if (jsonItem.readString("$.bookInfoBean.bookSourceType") == "AUDIO") 1 else 0
book.tocUrl = jsonItem.readString("$.bookInfoBean.chapterUrl") ?: book.descUrl
book.coverUrl = jsonItem.readString("$.bookInfoBean.coverUrl")
book.customCoverUrl = jsonItem.readString("$.customCoverPath")
book.lastCheckTime = jsonItem.readLong("$.bookInfoBean.finalRefreshData") ?: 0
book.canUpdate = jsonItem.readBool("$.allowUpdate") == true
book.totalChapterNum = jsonItem.readInt("$.chapterListSize") ?: 0
book.durChapterIndex = jsonItem.readInt("$.durChapter") ?: 0
book.durChapterTitle = jsonItem.readString("$.durChapterName")
book.durChapterPos = jsonItem.readInt("$.durChapterPage") ?: 0
book.durChapterTime = jsonItem.readLong("$.finalDate") ?: 0
book.group = jsonItem.readInt("$.group") ?: 0
// book. = jsonItem.readString("$.hasUpdate")
// book. = jsonItem.readString("$.isLoading")
book.latestChapterTitle = jsonItem.readString("$.lastChapterName")
book.lastCheckCount = jsonItem.readInt("$.newChapters") ?: 0
book.order = jsonItem.readInt("$.serialNumber") ?: 0
book.useReplaceRule = jsonItem.readBool("$.useReplaceRule") == true
book.variable = jsonItem.readString("$.variable")
books.add(book)
Log.d(APP_TAG, "Added ${book.name}")
}
App.db.bookDao().insert(*books.toTypedArray())
val count = books.size
uiThread {
toast(if (count > 0) "成功地导入 $count 本新书和音频" else "没有发现新书或音频")
}
}
} catch (e: Exception) {
Log.e(APP_TAG, "Failed to import book shelf.", e)
toast("Unable to import books:\n${e.localizedMessage}")
}
// Replace rules
val rFile = File(yuedu, "myBookReplaceRule.json")
val ruleFile = File(yuedu, "myBookReplaceRule.json")
val replaceRules = mutableListOf<ReplaceRule>()
if (rFile.exists()) try {
val items: List<Map<String, Any>> = jsonPath.parse(rFile.readText()).read("$.*")
if (ruleFile.exists()) try {
doAsync {
val items: List<Map<String, Any>> = jsonPath.parse(ruleFile.readText()).read("$")
val existingRules = App.db.replaceRuleDao().all.map { it.pattern }.toSet()
for (item in items) {
val jsonItem = jsonPath.parse(item)
val rRule = ReplaceRule()
rRule.name = jsonItem.readString("$.replaceSummary")
rRule.pattern = jsonItem.readString("$.regex")
if (rRule.pattern.isNullOrEmpty() || rRule.pattern in existingRules) continue
rRule.name = jsonItem.readString("$.replaceSummary")
rRule.replacement = jsonItem.readString("$.replacement")
rRule.isRegex = jsonItem.readBool("$.isRegex")
rRule.isRegex = jsonItem.readBool("$.isRegex") == true
rRule.scope = jsonItem.readString("$.useTo")
rRule.isEnabled = jsonItem.readBool("$.enable")
rRule.order = jsonItem.readInt("$.serialNumber")
rRule.isEnabled = jsonItem.readBool("$.enable") == true
rRule.order = jsonItem.readInt("$.serialNumber") ?: 0
replaceRules.add(rRule)
}
doAsync {
App.db.replaceRuleDao().insert(*replaceRules.toTypedArray())
val count = items.size
val count = replaceRules.size
val maxId = App.db.replaceRuleDao().maxOrder
uiThread {
toast("成功地导入 $count 条净化替换规则")
toast(if (count > 0) "成功地导入 $count净化替换规则" else "没有发现新的净化替换规则")
}
}

@ -1,11 +1,14 @@
package io.legado.app.ui.replacerule
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import io.legado.app.App
import io.legado.app.R
@ -15,6 +18,8 @@ import org.jetbrains.anko.doAsync
import org.jetbrains.anko.toast
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.ItemTouchHelper
import io.legado.app.constant.AppConst.APP_TAG
import kotlinx.android.synthetic.main.item_relace_rule.*
class ReplaceRuleActivity : AppCompatActivity() {
@ -25,7 +30,6 @@ class ReplaceRuleActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_replace_rule)
rv_replace_rule.layoutManager = LinearLayoutManager(this)
initRecyclerView()
initDataObservers()
initSwipeToDelete()
@ -57,6 +61,12 @@ class ReplaceRuleActivity : AppCompatActivity() {
}
}
rv_replace_rule.adapter = adapter
rv_replace_rule.addItemDecoration(
DividerItemDecoration(this, DividerItemDecoration.VERTICAL).apply {
ContextCompat.getDrawable(baseContext, R.drawable.ic_divider)?.let {
Log.e(APP_TAG, it.toString())
this.setDrawable(it) }
})
}
private fun initDataObservers() {
@ -90,7 +100,7 @@ class ReplaceRuleActivity : AppCompatActivity() {
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
toast("You swiped the item!")
TODO()
// TODO()
// remove((viewHolder as TodoViewHolder).todo)
}
}).attachToRecyclerView(rv_replace_rule)

@ -1,6 +1,7 @@
package io.legado.app.ui.replacerule
import android.content.Context
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -9,6 +10,7 @@ import androidx.paging.PagedListAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import io.legado.app.R
import io.legado.app.constant.AppConst.APP_TAG
import io.legado.app.data.entities.ReplaceRule
import kotlinx.android.synthetic.main.item_relace_rule.view.*
import org.jetbrains.anko.sdk27.listeners.onClick
@ -45,14 +47,14 @@ class ReplaceRuleAdapter(context: Context) :
}
override fun onBindViewHolder(holder: MyViewHolder, pos: Int) {
getItem(pos)?.let { holder.bind(it, onClickListener, pos == itemCount - 1) }
getItem(pos)?.let { holder.bind(it, onClickListener) }
}
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind(rule: ReplaceRule, listener: OnClickListener?, hideDivider: Boolean) = with(itemView) {
fun bind(rule: ReplaceRule, listener: OnClickListener?) = with(itemView) {
tv_name.text = rule.name
swt_enabled.isChecked = rule.isEnabled
divider.isGone = hideDivider
// divider.isGone = hideDivider
iv_delete.isGone = true
iv_edit.isGone = true
// iv_delete.onClick { listener?.delete(rule) }

@ -7,3 +7,6 @@ fun ReadContext.readString(path: String): String? = this.read(path, String::clas
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)

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size android:height="0.5dp" />
<solid android:color="@color/divider" />
</shape>

@ -18,8 +18,8 @@
android:id="@+id/rv_replace_rule"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:layout_marginBottom="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"

@ -4,9 +4,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="8dp"
android:paddingEnd="8dp">
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_edit"
@ -42,7 +40,7 @@
android:text=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingStart="8dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
app:layout_constraintStart_toStartOf="parent"
@ -54,7 +52,8 @@
android:id="@+id/tv_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="16dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:textSize="16sp"
android:text="Item Name"
android:textColor="@color/text_default"
@ -77,12 +76,13 @@
app:layout_constraintStart_toEndOf="@id/tv_name"
app:layout_constraintHorizontal_bias="1"/>
<!--
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/divider"
app:layout_constraintBottom_toBottomOf="parent"/>
-->
</androidx.constraintlayout.widget.ConstraintLayout>

Loading…
Cancel
Save