Merge pull request #1 from Celeter/master

merge
pull/871/head
Celeter 4 years ago committed by GitHub
commit a8c637effc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      app/src/main/assets/updateLog.md
  2. 19
      app/src/main/java/io/legado/app/help/BookHelp.kt
  3. 6
      app/src/main/java/io/legado/app/model/Debug.kt
  4. 16
      app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt
  5. 1
      app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt
  6. 34
      app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt
  7. 1
      app/src/main/java/io/legado/app/model/webBook/BookContent.kt
  8. 4
      app/src/main/java/io/legado/app/model/webBook/BookInfo.kt
  9. 1
      app/src/main/java/io/legado/app/model/webBook/BookList.kt
  10. 29
      app/src/main/java/io/legado/app/model/webBook/WebBook.kt
  11. 3
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  12. 10
      app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt
  13. 1
      app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt
  14. 5
      app/src/main/res/menu/book_read.xml
  15. 1
      app/src/main/res/values-zh-rHK/strings.xml
  16. 1
      app/src/main/res/values-zh-rTW/strings.xml
  17. 1
      app/src/main/res/values-zh/strings.xml
  18. 1
      app/src/main/res/values/strings.xml
  19. 2
      build.gradle

@ -3,6 +3,14 @@
* 关注合作公众号 **[小说拾遗]** 获取好看的小说。 * 关注合作公众号 **[小说拾遗]** 获取好看的小说。
* 旧版数据导入教程:先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】。 * 旧版数据导入教程:先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】。
**2021/02/26**
* 添加反转内容功能
* 更新章节是如果没有目录url自动加载详情页
* 添加变量nextChapterUrl
* 订阅跳转外部应用时提示
* 修复恢复bug
* 详情页拼接url改为重定向后的地址
**2021/02/21** **2021/02/21**
* 下一页规则改为在内容规则之后执行 * 下一页规则改为在内容规则之后执行
* 书籍导出增加编码设置和导出文件夹设置,使用替换设置 * 书籍导出增加编码设置和导出文件夹设置,使用替换设置

@ -191,6 +191,25 @@ object BookHelp {
return null return null
} }
fun reverseContent(book: Book, bookChapter: BookChapter) {
if (!book.isLocalBook()) {
val file = FileUtils.getFile(
downloadDir,
cacheFolderName,
book.getFolderName(),
bookChapter.getFileName()
)
if (file.exists()) {
val text = file.readText()
val stringBuilder = StringBuilder()
text.toStringArray().forEach {
stringBuilder.insert(0, it)
}
file.writeText(stringBuilder.toString())
}
}
}
fun delContent(book: Book, bookChapter: BookChapter) { fun delContent(book: Book, bookChapter: BookChapter) {
if (book.isLocalBook()) { if (book.isLocalBook()) {
return return

@ -186,6 +186,12 @@ object Debug {
} }
private fun infoDebug(scope: CoroutineScope, webBook: WebBook, book: Book) { private fun infoDebug(scope: CoroutineScope, webBook: WebBook, book: Book) {
if (book.tocUrl.isNotBlank()) {
log(debugSource, "目录url不为空,详情页已解析")
log(debugSource, showTime = false)
tocDebug(scope, webBook, book)
return
}
log(debugSource, "︾开始解析详情页") log(debugSource, "︾开始解析详情页")
val info = webBook.getBookInfo(scope, book) val info = webBook.getBookInfo(scope, book)
.onSuccess { .onSuccess {

@ -30,7 +30,7 @@ class AnalyzeRule(val ruleData: RuleDataInterface) : JsExtensions {
var nextChapterUrl: String? = null var nextChapterUrl: String? = null
private var content: Any? = null private var content: Any? = null
private var baseUrl: String? = null private var baseUrl: String? = null
private var baseURL: URL? = null private var redirectUrl: URL? = null
private var isJSON: Boolean = false private var isJSON: Boolean = false
private var isRegex: Boolean = false private var isRegex: Boolean = false
@ -63,11 +63,13 @@ class AnalyzeRule(val ruleData: RuleDataInterface) : JsExtensions {
fun setBaseUrl(baseUrl: String?): AnalyzeRule { fun setBaseUrl(baseUrl: String?): AnalyzeRule {
baseUrl?.let { baseUrl?.let {
this.baseUrl = baseUrl this.baseUrl = baseUrl
kotlin.runCatching {
baseURL = URL(baseUrl.substringBefore(","))
}.onFailure {
it.printStackTrace()
} }
return this
}
fun setRedirectUrl(url: String): AnalyzeRule {
kotlin.runCatching {
redirectUrl = URL(url.split(AnalyzeUrl.splitUrlRegex, 1)[0])
} }
return this return this
} }
@ -170,7 +172,7 @@ class AnalyzeRule(val ruleData: RuleDataInterface) : JsExtensions {
val urlList = ArrayList<String>() val urlList = ArrayList<String>()
if (result is List<*>) { if (result is List<*>) {
for (url in result as List<*>) { for (url in result as List<*>) {
val absoluteURL = NetworkUtils.getAbsoluteURL(baseURL, url.toString()) val absoluteURL = NetworkUtils.getAbsoluteURL(redirectUrl, url.toString())
if (absoluteURL.isNotEmpty() && !urlList.contains(absoluteURL)) { if (absoluteURL.isNotEmpty() && !urlList.contains(absoluteURL)) {
urlList.add(absoluteURL) urlList.add(absoluteURL)
} }
@ -239,7 +241,7 @@ class AnalyzeRule(val ruleData: RuleDataInterface) : JsExtensions {
return if (str.isBlank()) { return if (str.isBlank()) {
baseUrl ?: "" baseUrl ?: ""
} else { } else {
NetworkUtils.getAbsoluteURL(baseURL, str) NetworkUtils.getAbsoluteURL(redirectUrl, str)
} }
} }
return str return str

@ -39,6 +39,7 @@ object RssParserByRule {
val articleList = mutableListOf<RssArticle>() val articleList = mutableListOf<RssArticle>()
val analyzeRule = AnalyzeRule(ruleData) val analyzeRule = AnalyzeRule(ruleData)
analyzeRule.setContent(body).setBaseUrl(sortUrl) analyzeRule.setContent(body).setBaseUrl(sortUrl)
analyzeRule.setRedirectUrl(sortUrl)
var reverse = false var reverse = false
if (ruleArticles.startsWith("-")) { if (ruleArticles.startsWith("-")) {
reverse = true reverse = true

@ -24,7 +24,8 @@ object BookChapterList {
book: Book, book: Book,
body: String?, body: String?,
bookSource: BookSource, bookSource: BookSource,
baseUrl: String baseUrl: String,
redirectUrl: String
): List<BookChapter> = suspendCancellableCoroutine { block -> ): List<BookChapter> = suspendCancellableCoroutine { block ->
kotlin.runCatching { kotlin.runCatching {
val chapterList = ArrayList<BookChapter>() val chapterList = ArrayList<BookChapter>()
@ -46,7 +47,15 @@ object BookChapterList {
} }
var chapterData = var chapterData =
analyzeChapterList( analyzeChapterList(
scope, book, baseUrl, body, tocRule, listRule, bookSource, log = true scope,
book,
baseUrl,
redirectUrl,
body,
tocRule,
listRule,
bookSource,
log = true
) )
chapterData.chapterList?.let { chapterData.chapterList?.let {
chapterList.addAll(it) chapterList.addAll(it)
@ -66,7 +75,14 @@ object BookChapterList {
headerMapF = bookSource.getHeaderMap() headerMapF = bookSource.getHeaderMap()
).getStrResponse(bookSource.bookSourceUrl).body?.let { nextBody -> ).getStrResponse(bookSource.bookSourceUrl).body?.let { nextBody ->
chapterData = analyzeChapterList( chapterData = analyzeChapterList(
this, book, nextUrl, nextBody, tocRule, listRule, bookSource this,
book,
nextUrl,
nextUrl,
nextBody,
tocRule,
listRule,
bookSource
) )
nextUrl = chapterData.nextUrl.firstOrNull() ?: "" nextUrl = chapterData.nextUrl.firstOrNull() ?: ""
chapterData.chapterList?.let { chapterData.chapterList?.let {
@ -128,7 +144,15 @@ object BookChapterList {
).getStrResponse(bookSource.bookSourceUrl).body ).getStrResponse(bookSource.bookSourceUrl).body
?: throw Exception("${chapterData.nextUrl}, 下载失败") ?: throw Exception("${chapterData.nextUrl}, 下载失败")
val nextChapterData = analyzeChapterList( val nextChapterData = analyzeChapterList(
this, book, chapterData.nextUrl, nextBody, tocRule, listRule, bookSource, false this,
book,
chapterData.nextUrl,
chapterData.nextUrl,
nextBody,
tocRule,
listRule,
bookSource,
false
) )
synchronized(chapterDataList) { synchronized(chapterDataList) {
val isFinished = addChapterListIsFinish( val isFinished = addChapterListIsFinish(
@ -195,6 +219,7 @@ object BookChapterList {
scope: CoroutineScope, scope: CoroutineScope,
book: Book, book: Book,
baseUrl: String, baseUrl: String,
redirectUrl: String,
body: String, body: String,
tocRule: TocRule, tocRule: TocRule,
listRule: String, listRule: String,
@ -204,6 +229,7 @@ object BookChapterList {
): ChapterData<List<String>> { ): ChapterData<List<String>> {
val analyzeRule = AnalyzeRule(book) val analyzeRule = AnalyzeRule(book)
analyzeRule.setContent(body).setBaseUrl(baseUrl) analyzeRule.setContent(body).setBaseUrl(baseUrl)
analyzeRule.setRedirectUrl(redirectUrl)
//获取目录列表 //获取目录列表
val chapterList = arrayListOf<BookChapter>() val chapterList = arrayListOf<BookChapter>()
Debug.log(bookSource.bookSourceUrl, "┌获取目录列表", log) Debug.log(bookSource.bookSourceUrl, "┌获取目录列表", log)

@ -41,6 +41,7 @@ object BookContent {
val nextUrlList = arrayListOf(baseUrl) val nextUrlList = arrayListOf(baseUrl)
val contentRule = bookSource.getContentRule() val contentRule = bookSource.getContentRule()
val analyzeRule = AnalyzeRule(book).setContent(body, baseUrl) val analyzeRule = AnalyzeRule(book).setContent(body, baseUrl)
analyzeRule.setRedirectUrl(baseUrl)
analyzeRule.nextChapterUrl = mNextChapterUrl analyzeRule.nextChapterUrl = mNextChapterUrl
var contentData = analyzeContent( var contentData = analyzeContent(
book, baseUrl, body, contentRule, bookChapter, bookSource, mNextChapterUrl book, baseUrl, body, contentRule, bookChapter, bookSource, mNextChapterUrl

@ -22,6 +22,7 @@ object BookInfo {
body: String?, body: String?,
bookSource: BookSource, bookSource: BookSource,
baseUrl: String, baseUrl: String,
redirectUrl: String,
canReName: Boolean, canReName: Boolean,
) { ) {
body ?: throw Exception( body ?: throw Exception(
@ -31,6 +32,7 @@ object BookInfo {
val infoRule = bookSource.getBookInfoRule() val infoRule = bookSource.getBookInfoRule()
val analyzeRule = AnalyzeRule(book) val analyzeRule = AnalyzeRule(book)
analyzeRule.setContent(body).setBaseUrl(baseUrl) analyzeRule.setContent(body).setBaseUrl(baseUrl)
analyzeRule.setRedirectUrl(redirectUrl)
infoRule.init?.let { infoRule.init?.let {
if (it.isNotBlank()) { if (it.isNotBlank()) {
scope.ensureActive() scope.ensureActive()
@ -84,7 +86,7 @@ object BookInfo {
scope.ensureActive() scope.ensureActive()
Debug.log(bookSource.bookSourceUrl, "┌获取封面链接") Debug.log(bookSource.bookSourceUrl, "┌获取封面链接")
analyzeRule.getString(infoRule.coverUrl).let { analyzeRule.getString(infoRule.coverUrl).let {
if (it.isNotEmpty()) book.coverUrl = NetworkUtils.getAbsoluteURL(baseUrl, it) if (it.isNotEmpty()) book.coverUrl = NetworkUtils.getAbsoluteURL(redirectUrl, it)
} }
Debug.log(bookSource.bookSourceUrl, "${book.coverUrl}") Debug.log(bookSource.bookSourceUrl, "${book.coverUrl}")
scope.ensureActive() scope.ensureActive()

@ -37,6 +37,7 @@ object BookList {
Debug.log(bookSource.bookSourceUrl, "≡获取成功:${analyzeUrl.ruleUrl}") Debug.log(bookSource.bookSourceUrl, "≡获取成功:${analyzeUrl.ruleUrl}")
val analyzeRule = AnalyzeRule(variableBook) val analyzeRule = AnalyzeRule(variableBook)
analyzeRule.setContent(body).setBaseUrl(baseUrl) analyzeRule.setContent(body).setBaseUrl(baseUrl)
analyzeRule.setRedirectUrl(baseUrl)
bookSource.bookUrlPattern?.let { bookSource.bookUrlPattern?.let {
scope.ensureActive() scope.ensureActive()
if (baseUrl.matches(it.toRegex())) { if (baseUrl.matches(it.toRegex())) {

@ -127,6 +127,7 @@ class WebBook(val bookSource: BookSource) {
book.infoHtml, book.infoHtml,
bookSource, bookSource,
book.bookUrl, book.bookUrl,
book.bookUrl,
canReName canReName
) )
} else { } else {
@ -136,7 +137,15 @@ class WebBook(val bookSource: BookSource) {
headerMapF = bookSource.getHeaderMap(), headerMapF = bookSource.getHeaderMap(),
book = book book = book
).getStrResponse(bookSource.bookSourceUrl) ).getStrResponse(bookSource.bookSourceUrl)
BookInfo.analyzeBookInfo(scope, book, res.body, bookSource, book.bookUrl, canReName) BookInfo.analyzeBookInfo(
scope,
book,
res.body,
bookSource,
book.bookUrl,
res.url,
canReName
)
} }
return book return book
} }
@ -160,7 +169,14 @@ class WebBook(val bookSource: BookSource) {
): List<BookChapter> { ): List<BookChapter> {
book.type = bookSource.bookSourceType book.type = bookSource.bookSourceType
return if (book.bookUrl == book.tocUrl && !book.tocHtml.isNullOrEmpty()) { return if (book.bookUrl == book.tocUrl && !book.tocHtml.isNullOrEmpty()) {
BookChapterList.analyzeChapterList(scope, book, book.tocHtml, bookSource, book.tocUrl) BookChapterList.analyzeChapterList(
scope,
book,
book.tocHtml,
bookSource,
book.tocUrl,
book.tocUrl
)
} else { } else {
val res = AnalyzeUrl( val res = AnalyzeUrl(
book = book, book = book,
@ -168,7 +184,14 @@ class WebBook(val bookSource: BookSource) {
baseUrl = book.bookUrl, baseUrl = book.bookUrl,
headerMapF = bookSource.getHeaderMap() headerMapF = bookSource.getHeaderMap()
).getStrResponse(bookSource.bookSourceUrl) ).getStrResponse(bookSource.bookSourceUrl)
BookChapterList.analyzeChapterList(scope, book, res.body, bookSource, book.tocUrl) BookChapterList.analyzeChapterList(
scope,
book,
res.body,
bookSource,
book.tocUrl,
res.url
)
} }
} }

@ -242,6 +242,9 @@ class ReadBookActivity : ReadBookBaseActivity(),
supportFragmentManager, supportFragmentManager,
ReadBook.book?.tocUrl ReadBook.book?.tocUrl
) )
R.id.menu_reverse_content -> ReadBook.book?.let {
viewModel.reverseContent(it)
}
R.id.menu_set_charset -> showCharsetConfig() R.id.menu_set_charset -> showCharsetConfig()
R.id.menu_get_progress -> ReadBook.book?.let { R.id.menu_get_progress -> ReadBook.book?.let {
viewModel.syncBookProgress(it) { progress -> viewModel.syncBookProgress(it) { progress ->

@ -295,6 +295,16 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
} }
} }
fun reverseContent(book: Book) {
execute {
appDb.bookChapterDao.getChapter(book.bookUrl, ReadBook.durChapterIndex)
?.let { chapter ->
BookHelp.reverseContent(book, chapter)
ReadBook.loadContent(ReadBook.durChapterIndex, resetPageOffset = false)
}
}
}
/** /**
* 替换规则变化 * 替换规则变化
*/ */

@ -103,6 +103,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener {
alert(title = getString(R.string.group_edit)) { alert(title = getString(R.string.group_edit)) {
val alertBinding = DialogEditTextBinding.inflate(layoutInflater) val alertBinding = DialogEditTextBinding.inflate(layoutInflater)
alertBinding.editView.setHint(R.string.group_name) alertBinding.editView.setHint(R.string.group_name)
alertBinding.editView.setText(group)
customView { alertBinding.root } customView { alertBinding.root }
yesButton { yesButton {
viewModel.upGroup(group, alertBinding.editView.text?.toString()) viewModel.upGroup(group, alertBinding.editView.text?.toString())

@ -73,6 +73,11 @@
android:title="@string/get_book_progress" android:title="@string/get_book_progress"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/menu_reverse_content"
android:title="@string/reverse_content"
app:showAsAction="never" />
<item <item
android:id="@+id/menu_enable_replace" android:id="@+id/menu_enable_replace"
android:title="@string/replace_rule_title" android:title="@string/replace_rule_title"

@ -804,5 +804,6 @@
<string name="export_folder">导出文件夹</string> <string name="export_folder">导出文件夹</string>
<string name="export_charset">导出编码</string> <string name="export_charset">导出编码</string>
<string name="export_to_web_dav">导出到WebDav</string> <string name="export_to_web_dav">导出到WebDav</string>
<string name="reverse_content">反转内容</string>
</resources> </resources>

@ -808,5 +808,6 @@
<string name="export_folder">匯出資料夾</string> <string name="export_folder">匯出資料夾</string>
<string name="export_charset">匯出編碼</string> <string name="export_charset">匯出編碼</string>
<string name="export_to_web_dav">匯出到WebDav</string> <string name="export_to_web_dav">匯出到WebDav</string>
<string name="reverse_content">反转内容</string>
</resources> </resources>

@ -808,5 +808,6 @@
<string name="export_folder">导出文件夹</string> <string name="export_folder">导出文件夹</string>
<string name="export_charset">导出编码</string> <string name="export_charset">导出编码</string>
<string name="export_to_web_dav">导出到WebDav</string> <string name="export_to_web_dav">导出到WebDav</string>
<string name="reverse_content">反转内容</string>
</resources> </resources>

@ -811,5 +811,6 @@
<string name="export_folder">导出文件夹</string> <string name="export_folder">导出文件夹</string>
<string name="export_charset">导出编码</string> <string name="export_charset">导出编码</string>
<string name="export_to_web_dav">导出到WebDav</string> <string name="export_to_web_dav">导出到WebDav</string>
<string name="reverse_content">反转内容</string>
</resources> </resources>

@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = '1.4.30' ext.kotlin_version = '1.4.31'
repositories { repositories {
google() google()
jcenter() jcenter()

Loading…
Cancel
Save