1、调试log修改 2、增加书源字符串分享(RSS未包含) 3、增加导出选中的源(包含书源、RSS、替换规则)

pull/51/head
Celeter 5 years ago
parent 32223620fc
commit ff7a03cbc5
  1. 13
      app/build.gradle
  2. 4
      app/src/main/java/io/legado/app/constant/BookType.kt
  3. 3
      app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt
  4. 13
      app/src/main/java/io/legado/app/data/entities/BookSource.kt
  5. 4
      app/src/main/java/io/legado/app/help/storage/Backup.kt
  6. 2
      app/src/main/java/io/legado/app/help/storage/OldRule.kt
  7. 18
      app/src/main/java/io/legado/app/model/Debug.kt
  8. 2
      app/src/main/java/io/legado/app/model/WebBook.kt
  9. 11
      app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt
  10. 2
      app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt
  11. 23
      app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt
  12. 1
      app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt
  13. 19
      app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt
  14. 1
      app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt
  15. 21
      app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt
  16. 1
      app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt
  17. 2
      app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceAdapter.kt
  18. 16
      app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt
  19. 5
      app/src/main/res/menu/book_source.xml
  20. 5
      app/src/main/res/menu/replace_rule.xml
  21. 5
      app/src/main/res/menu/rss_source.xml
  22. 5
      app/src/main/res/menu/source_edit.xml
  23. 12
      app/src/main/res/values/strings.xml
  24. 4
      build.gradle

@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-kapt'
apply plugin: "de.timfreiheit.resourceplaceholders" apply plugin: "de.timfreiheit.resourceplaceholders"
apply plugin: 'io.fabric' //apply plugin: 'io.fabric'
androidExtensions { androidExtensions {
experimental = true experimental = true
@ -30,8 +30,9 @@ android {
} }
} }
defaultConfig { defaultConfig {
applicationId "io.legado.app" applicationId "io.legado.apps"
minSdkVersion 21 //minSdkVersion 21
minSdkVersion 28
targetSdkVersion 29 targetSdkVersion 29
versionCode gitCommits versionCode gitCommits
versionName version versionName version
@ -87,8 +88,8 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
//fireBase //fireBase
implementation 'com.google.firebase:firebase-core:17.2.1' //implementation 'com.google.firebase:firebase-core:17.2.1'
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1' //implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
//androidX //androidX
implementation 'androidx.core:core-ktx:1.2.0-rc01' implementation 'androidx.core:core-ktx:1.2.0-rc01'
@ -161,4 +162,4 @@ dependencies {
implementation 'ru.noties.markwon:core:3.0.2' implementation 'ru.noties.markwon:core:3.0.2'
} }
apply plugin: 'com.google.gms.google-services' //apply plugin: 'com.google.gms.google-services'

@ -1,7 +1,7 @@
package io.legado.app.constant package io.legado.app.constant
object BookType { object BookType {
const val default = 0 const val default = 0 // 0 文本
const val audio = 1 const val audio = 1 // 1 音频
const val local = "loc_book" const val local = "loc_book"
} }

@ -10,6 +10,9 @@ interface RssSourceDao {
@Query("select * from rssSources where sourceUrl = :key") @Query("select * from rssSources where sourceUrl = :key")
fun getByKey(key: String): RssSource? fun getByKey(key: String): RssSource?
@Query("select * from rssSources where sourceUrl in (:sourceUrls)")
fun getRssSources(vararg sourceUrls: String):List<RssSource>
@get:Query("SELECT * FROM rssSources") @get:Query("SELECT * FROM rssSources")
val all: List<RssSource> val all: List<RssSource>

@ -8,6 +8,7 @@ import androidx.room.PrimaryKey
import io.legado.app.App import io.legado.app.App
import io.legado.app.constant.AppConst import io.legado.app.constant.AppConst
import io.legado.app.constant.AppConst.userAgent import io.legado.app.constant.AppConst.userAgent
import io.legado.app.constant.BookType
import io.legado.app.data.entities.rule.* import io.legado.app.data.entities.rule.*
import io.legado.app.help.JsExtensions import io.legado.app.help.JsExtensions
import io.legado.app.utils.ACache import io.legado.app.utils.ACache
@ -29,18 +30,18 @@ data class BookSource(
var bookSourceGroup: String? = null, // 分组 var bookSourceGroup: String? = null, // 分组
@PrimaryKey @PrimaryKey
var bookSourceUrl: String = "", // 地址,包括 http/https var bookSourceUrl: String = "", // 地址,包括 http/https
var bookSourceType: Int = 0, // 类型,0 文本,1 音频 var bookSourceType: Int = BookType.default, // 类型,0 文本,1 音频
var bookUrlPattern: String? = null, //详情页url正则 var bookUrlPattern: String? = null, // 详情页url正则
var customOrder: Int = 0, // 手动排序编号 var customOrder: Int = 0, // 手动排序编号
var enabled: Boolean = true, // 是否启用 var enabled: Boolean = true, // 是否启用
var enabledExplore: Boolean = true, //启用发现 var enabledExplore: Boolean = true, // 启用发现
var header: String? = null, var header: String? = null, // 请求头
var loginUrl: String? = null, // 登录地址 var loginUrl: String? = null, // 登录地址
var lastUpdateTime: Long = 0, // 最后更新时间,用于排序 var lastUpdateTime: Long = 0, // 最后更新时间,用于排序
var weight: Int = 0, // 智能排序的权重 var weight: Int = 0, // 智能排序的权重
var exploreUrl: String? = null, //发现url var exploreUrl: String? = null, // 发现url
var ruleExplore: String? = null, // 发现规则 var ruleExplore: String? = null, // 发现规则
var searchUrl: String? = null, //搜索url var searchUrl: String? = null, // 搜索url
var ruleSearch: String? = null, // 搜索规则 var ruleSearch: String? = null, // 搜索规则
var ruleBookInfo: String? = null, // 书籍信息页规则 var ruleBookInfo: String? = null, // 书籍信息页规则
var ruleToc: String? = null, // 目录页规则 var ruleToc: String? = null, // 目录页规则

@ -23,6 +23,10 @@ object Backup {
defaultPath + File.separator + "legadoBackUp" defaultPath + File.separator + "legadoBackUp"
} }
val exportPath by lazy {
legadoPath + File.separator + "Export"
}
fun backup() { fun backup() {
doAsync { doAsync {
val path = legadoPath val path = legadoPath

@ -118,7 +118,7 @@ object OldRule {
} }
if (newRule.contains("|") && !newRule.contains("||")) { if (newRule.contains("|") && !newRule.contains("||")) {
if (newRule.contains("##")) { if (newRule.contains("##")) {
var list = newRule.split("##") val list = newRule.split("##")
if (list[0].contains("|")) { if (list[0].contains("|")) {
newRule = list[0].replace("|", "||") newRule = list[0].replace("|", "||")
for (i in 1 until list.size) { for (i in 1 until list.size) {

@ -53,18 +53,26 @@ object Debug {
fun startDebug(rssSource: RssSource) { fun startDebug(rssSource: RssSource) {
cancelDebug() cancelDebug()
debugSource = rssSource.sourceUrl debugSource = rssSource.sourceUrl
log(debugSource, "︾开始解析RSS") log(debugSource, "︾开始解析")
Rss.getArticles(rssSource, null) Rss.getArticles(rssSource, null)
.onSuccess { .onSuccess {
if (it == null) { if (it == null) {
log(debugSource, "︽解析失败", state = -1) log(debugSource, "︽解析失败", state = -1)
} else if(it.articles.isEmpty()) {
log(debugSource, "⇒列表页解析成功,为空")
log(debugSource, "︽解析完成", state = 1000)
} else { } else {
val ruleContent = rssSource.ruleContent val ruleContent = rssSource.ruleContent
if (it.articles.isNotEmpty() && it.articles[0].description.isNullOrEmpty() && !ruleContent.isNullOrEmpty()) { if (!rssSource.ruleArticles.isNullOrBlank() && rssSource.ruleDescription.isNullOrBlank()) {
log(debugSource, "︽解析完成") log(debugSource, "列表页解析完成")
log(debugSource, showTime = false) log(debugSource, showTime = false)
if (ruleContent.isNullOrEmpty()) {
log(debugSource, "⇒内容规则为空,默认获取整个网页", state = 1000)
} else {
rssContentDebug(it.articles[0], ruleContent) rssContentDebug(it.articles[0], ruleContent)
}
} else { } else {
log(debugSource, "⇒存在描述规则,不解析内容页")
log(debugSource, "︽解析完成", state = 1000) log(debugSource, "︽解析完成", state = 1000)
} }
} }
@ -75,11 +83,11 @@ object Debug {
} }
private fun rssContentDebug(rssArticle: RssArticle, ruleContent: String) { private fun rssContentDebug(rssArticle: RssArticle, ruleContent: String) {
log(debugSource, "︾开始解析内容") log(debugSource, "︾开始解析内容")
Rss.getContent(rssArticle, ruleContent) Rss.getContent(rssArticle, ruleContent)
.onSuccess { .onSuccess {
log(debugSource, it) log(debugSource, it)
log(debugSource, "︽解析完成", state = 1000) log(debugSource, "内容页解析完成", state = 1000)
} }
.onError { .onError {
log(debugSource, it.localizedMessage, state = -1) log(debugSource, it.localizedMessage, state = -1)

@ -138,7 +138,7 @@ class WebBook(val bookSource: BookSource) {
): Coroutine<String> { ): Coroutine<String> {
return Coroutine.async(scope, context) { return Coroutine.async(scope, context) {
if (bookSource.getContentRule().content.isNullOrEmpty()) { if (bookSource.getContentRule().content.isNullOrEmpty()) {
Debug.log(sourceUrl, "内容规则为空,直接返回目录Url:${bookChapter.url}") Debug.log(sourceUrl, "⇒正文规则为空,使用章节链接:${bookChapter.url}")
return@async bookChapter.url return@async bookChapter.url
} }
val body = if (bookChapter.url == book.bookUrl && !book.tocHtml.isNullOrEmpty()) { val body = if (bookChapter.url == book.bookUrl && !book.tocHtml.isNullOrEmpty()) {

@ -25,7 +25,7 @@ object RssParserByRule {
Debug.log(sourceUrl, "≡获取成功:$sourceUrl") Debug.log(sourceUrl, "≡获取成功:$sourceUrl")
var ruleArticles = rssSource.ruleArticles var ruleArticles = rssSource.ruleArticles
if (ruleArticles.isNullOrBlank()) { if (ruleArticles.isNullOrBlank()) {
Debug.log(sourceUrl, "列表规则为空, 使用默认规则解析") Debug.log(sourceUrl, "列表规则为空, 使用默认规则解析")
return RssParser.parseXML(body, sourceUrl) return RssParser.parseXML(body, sourceUrl)
} else { } else {
val articleList = mutableListOf<RssArticle>() val articleList = mutableListOf<RssArticle>()
@ -40,12 +40,12 @@ object RssParserByRule {
val collections = analyzeRule.getElements(ruleArticles) val collections = analyzeRule.getElements(ruleArticles)
Debug.log(sourceUrl, "└列表大小:${collections.size}") Debug.log(sourceUrl, "└列表大小:${collections.size}")
if (!rssSource.ruleNextPage.isNullOrEmpty()) { if (!rssSource.ruleNextPage.isNullOrEmpty()) {
Debug.log(sourceUrl, "┌获取下一页Url") Debug.log(sourceUrl, "┌获取下一页链接")
nextUrl = analyzeRule.getString(rssSource.ruleNextPage) nextUrl = analyzeRule.getString(rssSource.ruleNextPage)
if (nextUrl.isNotEmpty()) { if (nextUrl.isNotEmpty()) {
nextUrl = NetworkUtils.getAbsoluteURL(sourceUrl, nextUrl) nextUrl = NetworkUtils.getAbsoluteURL(sourceUrl, nextUrl)
} }
Debug.log(sourceUrl, "获取下一页Url:$nextUrl") Debug.log(sourceUrl, "$nextUrl")
} }
val ruleTitle = analyzeRule.splitSourceRule(rssSource.ruleTitle) val ruleTitle = analyzeRule.splitSourceRule(rssSource.ruleTitle)
val rulePubDate = analyzeRule.splitSourceRule(rssSource.rulePubDate) val rulePubDate = analyzeRule.splitSourceRule(rssSource.rulePubDate)
@ -88,8 +88,13 @@ object RssParserByRule {
rssArticle.pubDate = analyzeRule.getString(rulePubDate) rssArticle.pubDate = analyzeRule.getString(rulePubDate)
Debug.log(sourceUrl, "${rssArticle.pubDate}", log) Debug.log(sourceUrl, "${rssArticle.pubDate}", log)
Debug.log(sourceUrl, "┌获取描述", log) Debug.log(sourceUrl, "┌获取描述", log)
if (ruleDescription.isNullOrEmpty()) {
rssArticle.description = null
Debug.log(sourceUrl, "└描述规则为空,将会解析内容页", log)
} else {
rssArticle.description = analyzeRule.getString(ruleDescription) rssArticle.description = analyzeRule.getString(ruleDescription)
Debug.log(sourceUrl, "${rssArticle.description}", log) Debug.log(sourceUrl, "${rssArticle.description}", log)
}
Debug.log(sourceUrl, "┌获取图片url", log) Debug.log(sourceUrl, "┌获取图片url", log)
rssArticle.image = analyzeRule.getString(ruleImage, true) rssArticle.image = analyzeRule.getString(ruleImage, true)
Debug.log(sourceUrl, "${rssArticle.image}", log) Debug.log(sourceUrl, "${rssArticle.image}", log)

@ -167,6 +167,8 @@ object BookChapterList {
Debug.log(bookSource.bookSourceUrl, "${chapterList[0].title}", log) Debug.log(bookSource.bookSourceUrl, "${chapterList[0].title}", log)
Debug.log(bookSource.bookSourceUrl, "┌获取首章链接", log) Debug.log(bookSource.bookSourceUrl, "┌获取首章链接", log)
Debug.log(bookSource.bookSourceUrl, "${chapterList[0].url}", log) Debug.log(bookSource.bookSourceUrl, "${chapterList[0].url}", log)
Debug.log(bookSource.bookSourceUrl, "┌获取首章信息", log)
Debug.log(bookSource.bookSourceUrl, "${chapterList[0].tag}", log)
} }
return ChapterData(chapterList, nextUrlList) return ChapterData(chapterList, nextUrlList)
} }

@ -4,7 +4,9 @@ import android.app.Activity
import android.content.ClipData import android.content.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
import android.content.Context import android.content.Context
import android.content.Intent
import android.graphics.Rect import android.graphics.Rect
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.Gravity import android.view.Gravity
import android.view.Menu import android.view.Menu
@ -85,6 +87,27 @@ class BookSourceEditActivity :
} }
} }
R.id.menu_paste_source -> viewModel.pasteSource { upRecyclerView(it) } R.id.menu_paste_source -> viewModel.pasteSource { upRecyclerView(it) }
R.id.menu_share_str -> {
GSON.toJson(getSource())?.let { sourceStr ->
try {
val textIntent = Intent(Intent.ACTION_SEND)
textIntent.setType("text/plain")
textIntent.putExtra(Intent.EXTRA_TEXT, sourceStr)
startActivity(Intent.createChooser(textIntent, "Source Share"))
} catch (e: Exception) {
toast(R.string.can_not_share)
}
}
}
R.id.menu_rule_summary -> {
try {
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse(getString(R.string.source_rule_url))
startActivity(intent)
} catch (e: Exception) {
toast(R.string.can_not_open)
}
}
} }
return super.onCompatOptionsItemSelected(item) return super.onCompatOptionsItemSelected(item)
} }

@ -92,6 +92,7 @@ class BookSourceActivity : VMBaseActivity<BookSourceViewModel>(R.layout.activity
R.id.menu_enable_explore -> viewModel.enableSelectExplore(adapter.getSelectionIds()) R.id.menu_enable_explore -> viewModel.enableSelectExplore(adapter.getSelectionIds())
R.id.menu_disable_explore -> viewModel.disableSelectExplore(adapter.getSelectionIds()) R.id.menu_disable_explore -> viewModel.disableSelectExplore(adapter.getSelectionIds())
R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelectionIds()) R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelectionIds())
R.id.menu_export_selection -> viewModel.exportSelection(adapter.getSelectionIds())
R.id.menu_check_source -> R.id.menu_check_source ->
startService<CheckSourceService>(Pair("data", adapter.getSelectionIds())) startService<CheckSourceService>(Pair("data", adapter.getSelectionIds()))
R.id.menu_import_source_onLine -> showImportDialog() R.id.menu_import_source_onLine -> showImportDialog()

@ -7,12 +7,15 @@ import io.legado.app.App
import io.legado.app.base.BaseViewModel import io.legado.app.base.BaseViewModel
import io.legado.app.data.api.IHttpGetApi import io.legado.app.data.api.IHttpGetApi
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.help.FileHelp
import io.legado.app.help.http.HttpHelper import io.legado.app.help.http.HttpHelper
import io.legado.app.help.storage.Backup
import io.legado.app.help.storage.OldRule import io.legado.app.help.storage.OldRule
import io.legado.app.help.storage.Restore.jsonPath import io.legado.app.help.storage.Restore.jsonPath
import io.legado.app.utils.* import io.legado.app.utils.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.jetbrains.anko.toast
import java.io.File import java.io.File
class BookSourceViewModel(application: Application) : BaseViewModel(application) { class BookSourceViewModel(application: Application) : BaseViewModel(application) {
@ -82,6 +85,22 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
} }
} }
fun exportSelection(ids: LinkedHashSet<String>) {
execute {
ids.map {
App.db.bookSourceDao().getBookSource(it)
}.let {
val json = GSON.toJson(it)
val file = FileHelp.getFile(Backup.exportPath + File.separator + "exportBookSource.json")
file.writeText(json)
}
}.onSuccess {
context.toast("成功导出至\n${Backup.exportPath}")
}.onError {
context.toast("导出失败\n${it.localizedMessage}")
}
}
fun addGroup(group: String) { fun addGroup(group: String) {
execute { execute {
val sources = App.db.bookSourceDao().noGroup val sources = App.db.bookSourceDao().noGroup

@ -66,6 +66,7 @@ class ReplaceRuleActivity : VMBaseActivity<ReplaceRuleViewModel>(R.layout.activi
R.id.menu_enable_selection -> viewModel.enableSelection(adapter.getSelectionIds()) R.id.menu_enable_selection -> viewModel.enableSelection(adapter.getSelectionIds())
R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelectionIds()) R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelectionIds())
R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelectionIds()) R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelectionIds())
R.id.menu_export_selection -> viewModel.exportSelection(adapter.getSelectionIds())
} }
return super.onCompatOptionsItemSelected(item) return super.onCompatOptionsItemSelected(item)
} }

@ -5,7 +5,12 @@ import android.text.TextUtils
import io.legado.app.App import io.legado.app.App
import io.legado.app.base.BaseViewModel import io.legado.app.base.BaseViewModel
import io.legado.app.data.entities.ReplaceRule import io.legado.app.data.entities.ReplaceRule
import io.legado.app.help.FileHelp
import io.legado.app.help.storage.Backup
import io.legado.app.utils.GSON
import io.legado.app.utils.splitNotBlank import io.legado.app.utils.splitNotBlank
import org.jetbrains.anko.toast
import java.io.File
class ReplaceRuleViewModel(application: Application) : BaseViewModel(application) { class ReplaceRuleViewModel(application: Application) : BaseViewModel(application) {
@ -57,6 +62,22 @@ class ReplaceRuleViewModel(application: Application) : BaseViewModel(application
} }
} }
fun exportSelection(ids: LinkedHashSet<Long>) {
execute {
ids.map {
App.db.replaceRuleDao().findById(it)
}.let {
val json = GSON.toJson(it)
val file = FileHelp.getFile(Backup.exportPath + File.separator + "exportReplaceRule.json")
file.writeText(json)
}
}.onSuccess {
context.toast("成功导出至\n${Backup.exportPath}")
}.onError {
context.toast("导出失败\n${it.localizedMessage}")
}
}
fun addGroup(group: String) { fun addGroup(group: String) {
execute { execute {
val sources = App.db.replaceRuleDao().noGroup val sources = App.db.replaceRuleDao().noGroup

@ -81,6 +81,7 @@ class RssSourceActivity : VMBaseActivity<RssSourceViewModel>(R.layout.activity_r
R.id.menu_enable_selection -> viewModel.enableSelection(adapter.getSelectionIds()) R.id.menu_enable_selection -> viewModel.enableSelection(adapter.getSelectionIds())
R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelectionIds()) R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelectionIds())
R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelectionIds()) R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelectionIds())
R.id.menu_export_selection -> viewModel.exportSelection(adapter.getSelectionIds())
R.id.menu_import_source_local -> selectFile() R.id.menu_import_source_local -> selectFile()
R.id.menu_import_source_onLine -> showImportDialog() R.id.menu_import_source_onLine -> showImportDialog()
R.id.menu_import_source_qr -> startActivityForResult<QrCodeActivity>(qrRequestCode) R.id.menu_import_source_qr -> startActivityForResult<QrCodeActivity>(qrRequestCode)

@ -38,7 +38,7 @@ class RssSourceAdapter(context: Context, val callBack: CallBack) :
fun getSelectionIds(): LinkedHashSet<String> { fun getSelectionIds(): LinkedHashSet<String> {
val selection = linkedSetOf<String>() val selection = linkedSetOf<String>()
getItems().map { getItems().forEach {
if (selectedIds.contains(it.sourceUrl)) { if (selectedIds.contains(it.sourceUrl)) {
selection.add(it.sourceUrl) selection.add(it.sourceUrl)
} }

@ -7,9 +7,12 @@ import io.legado.app.App
import io.legado.app.base.BaseViewModel import io.legado.app.base.BaseViewModel
import io.legado.app.data.api.IHttpGetApi import io.legado.app.data.api.IHttpGetApi
import io.legado.app.data.entities.RssSource import io.legado.app.data.entities.RssSource
import io.legado.app.help.FileHelp
import io.legado.app.help.http.HttpHelper import io.legado.app.help.http.HttpHelper
import io.legado.app.help.storage.Backup
import io.legado.app.help.storage.Restore.jsonPath import io.legado.app.help.storage.Restore.jsonPath
import io.legado.app.utils.* import io.legado.app.utils.*
import org.jetbrains.anko.toast
import java.io.File import java.io.File
class RssSourceViewModel(application: Application) : BaseViewModel(application) { class RssSourceViewModel(application: Application) : BaseViewModel(application) {
@ -57,6 +60,19 @@ class RssSourceViewModel(application: Application) : BaseViewModel(application)
} }
} }
fun exportSelection(ids: LinkedHashSet<String>) {
execute {
App.db.rssSourceDao().getRssSources(*ids.toTypedArray()).let {
val json = GSON.toJson(it)
val file = FileHelp.getFile(Backup.exportPath + File.separator + "exportRssSource.json")
file.writeText(json)
}
}.onSuccess {
context.toast("成功导出至\n${Backup.exportPath}")
}.onError {
context.toast("导出失败\n${it.localizedMessage}")
}
}
fun addGroup(group: String) { fun addGroup(group: String) {
execute { execute {

@ -47,6 +47,11 @@
android:title="@string/del_select" android:title="@string/del_select"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/menu_export_selection"
android:title="@string/export_selection"
app:showAsAction="never" />
</menu> </menu>
</item> </item>

@ -37,6 +37,11 @@
android:title="@string/del_select" android:title="@string/del_select"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/menu_export_selection"
android:title="@string/export_selection"
app:showAsAction="never" />
</menu> </menu>
</item> </item>

@ -37,6 +37,11 @@
android:title="@string/del_select" android:title="@string/del_select"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/menu_export_selection"
android:title="@string/export_selection"
app:showAsAction="never" />
</menu> </menu>
</item> </item>

@ -39,6 +39,11 @@
android:title="@string/qr_share" android:title="@string/qr_share"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/menu_share_str"
android:title="@string/str_share"
app:showAsAction="never" />
<item <item
android:id="@+id/menu_share_wifi" android:id="@+id/menu_share_wifi"
android:title="@string/wifi_share" android:title="@string/wifi_share"

@ -367,9 +367,9 @@
<string name="source_no_login">当前源没有配置登陆地址</string> <string name="source_no_login">当前源没有配置登陆地址</string>
<!-- source start--> <!-- source start-->
<string name="source_name">书源名称(bookSourceName)</string> <string name="source_name">源名称(sourceName)</string>
<string name="source_url">书源URL(bookSourceUrl)</string> <string name="source_url">源URL(sourceUrl)</string>
<string name="source_group">书源分组(bookSourceGroup)</string> <string name="source_group">源分组(sourceGroup)</string>
<string name="login_url">登录URL(loginUrl)</string> <string name="login_url">登录URL(loginUrl)</string>
<string name="r_search_url">搜索地址(url)</string> <string name="r_search_url">搜索地址(url)</string>
<string name="r_find_url">发现地址规则(url)</string> <string name="r_find_url">发现地址规则(url)</string>
@ -389,8 +389,8 @@
<string name="rule_chapter_list">目录列表规则(chapterList)</string> <string name="rule_chapter_list">目录列表规则(chapterList)</string>
<string name="rule_chapter_name">章节名称规则(ChapterName)</string> <string name="rule_chapter_name">章节名称规则(ChapterName)</string>
<string name="rule_chapter_url">章节URL规则(chapterUrl)</string> <string name="rule_chapter_url">章节URL规则(chapterUrl)</string>
<string name="rule_is_vip">是否VIP(isVip)</string> <string name="rule_is_vip">VIP标识(isVip)</string>
<string name="rule_update_time">更新时间(updateTime)</string> <string name="rule_update_time">章节信息(ChapterInfo)</string>
<string name="rule_book_content">正文规则(content)</string> <string name="rule_book_content">正文规则(content)</string>
<string name="rule_next_content">正文下一页URL规则(nextContentUrl)</string> <string name="rule_next_content">正文下一页URL规则(nextContentUrl)</string>
<string name="rule_web_js">webJs</string> <string name="rule_web_js">webJs</string>
@ -501,6 +501,7 @@
<string name="web_port_title">web端口</string> <string name="web_port_title">web端口</string>
<string name="web_port_summary">当前端口 %s</string> <string name="web_port_summary">当前端口 %s</string>
<string name="qr_share">二维码分享</string> <string name="qr_share">二维码分享</string>
<string name="str_share">字符串分享</string>
<string name="wifi_share">wifi分享</string> <string name="wifi_share">wifi分享</string>
<string name="please_grant_storage_permission">请给于存储权限</string> <string name="please_grant_storage_permission">请给于存储权限</string>
<string name="fast_rewind">减速</string> <string name="fast_rewind">减速</string>
@ -543,6 +544,7 @@
<string name="disable_explore">禁用发现</string> <string name="disable_explore">禁用发现</string>
<string name="enable_selection">启用所选</string> <string name="enable_selection">启用所选</string>
<string name="disable_selection">禁用所选</string> <string name="disable_selection">禁用所选</string>
<string name="export_selection">导出所选</string>
<string name="tts">TTS</string> <string name="tts">TTS</string>
<string name="web_dav_pw_s">输入你的WebDav授权密码</string> <string name="web_dav_pw_s">输入你的WebDav授权密码</string>
<string name="web_dav_url_s">输入你的服务器地址</string> <string name="web_dav_url_s">输入你的服务器地址</string>

@ -12,8 +12,8 @@ buildscript {
classpath 'com.android.tools.build:gradle:3.5.2' classpath 'com.android.tools.build:gradle:3.5.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'de.timfreiheit.resourceplaceholders:placeholders:0.3' classpath 'de.timfreiheit.resourceplaceholders:placeholders:0.3'
classpath 'com.google.gms:google-services:4.3.3' //classpath 'com.google.gms:google-services:4.3.3'
classpath 'io.fabric.tools:gradle:1.31.0' //classpath 'io.fabric.tools:gradle:1.31.0'
} }
} }

Loading…
Cancel
Save