diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index c327795f1..b7d51d201 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -3,6 +3,14 @@ * 关注合作公众号 **[小说拾遗]** 获取好看的小说。 * 旧版数据导入教程:先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】。 +**2021/02/26** +* 添加反转内容功能 +* 更新章节是如果没有目录url自动加载详情页 +* 添加变量nextChapterUrl +* 订阅跳转外部应用时提示 +* 修复恢复bug +* 详情页拼接url改为重定向后的地址 + **2021/02/21** * 下一页规则改为在内容规则之后执行 * 书籍导出增加编码设置和导出文件夹设置,使用替换设置 diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index fbf05f538..803d11a9a 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -191,6 +191,25 @@ object BookHelp { 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) { if (book.isLocalBook()) { return diff --git a/app/src/main/java/io/legado/app/model/Debug.kt b/app/src/main/java/io/legado/app/model/Debug.kt index 4697ae48b..d96aaa42b 100644 --- a/app/src/main/java/io/legado/app/model/Debug.kt +++ b/app/src/main/java/io/legado/app/model/Debug.kt @@ -186,6 +186,12 @@ object Debug { } 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, "︾开始解析详情页") val info = webBook.getBookInfo(scope, book) .onSuccess { diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index d316fcc08..b1dce05fa 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -30,7 +30,7 @@ class AnalyzeRule(val ruleData: RuleDataInterface) : JsExtensions { var nextChapterUrl: String? = null private var content: Any? = null private var baseUrl: String? = null - private var baseURL: URL? = null + private var redirectUrl: URL? = null private var isJSON: Boolean = false private var isRegex: Boolean = false @@ -63,11 +63,13 @@ class AnalyzeRule(val ruleData: RuleDataInterface) : JsExtensions { fun setBaseUrl(baseUrl: String?): AnalyzeRule { baseUrl?.let { 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 } @@ -170,7 +172,7 @@ class AnalyzeRule(val ruleData: RuleDataInterface) : JsExtensions { val urlList = ArrayList() if (result is 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)) { urlList.add(absoluteURL) } @@ -239,7 +241,7 @@ class AnalyzeRule(val ruleData: RuleDataInterface) : JsExtensions { return if (str.isBlank()) { baseUrl ?: "" } else { - NetworkUtils.getAbsoluteURL(baseURL, str) + NetworkUtils.getAbsoluteURL(redirectUrl, str) } } return str diff --git a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt index b162f37e1..e2b702cce 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt @@ -39,6 +39,7 @@ object RssParserByRule { val articleList = mutableListOf() val analyzeRule = AnalyzeRule(ruleData) analyzeRule.setContent(body).setBaseUrl(sortUrl) + analyzeRule.setRedirectUrl(sortUrl) var reverse = false if (ruleArticles.startsWith("-")) { reverse = true diff --git a/app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt index ff37f6ffd..1fe21c3f8 100644 --- a/app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt @@ -24,7 +24,8 @@ object BookChapterList { book: Book, body: String?, bookSource: BookSource, - baseUrl: String + baseUrl: String, + redirectUrl: String ): List = suspendCancellableCoroutine { block -> kotlin.runCatching { val chapterList = ArrayList() @@ -46,7 +47,15 @@ object BookChapterList { } var chapterData = analyzeChapterList( - scope, book, baseUrl, body, tocRule, listRule, bookSource, log = true + scope, + book, + baseUrl, + redirectUrl, + body, + tocRule, + listRule, + bookSource, + log = true ) chapterData.chapterList?.let { chapterList.addAll(it) @@ -66,7 +75,14 @@ object BookChapterList { headerMapF = bookSource.getHeaderMap() ).getStrResponse(bookSource.bookSourceUrl).body?.let { nextBody -> chapterData = analyzeChapterList( - this, book, nextUrl, nextBody, tocRule, listRule, bookSource + this, + book, + nextUrl, + nextUrl, + nextBody, + tocRule, + listRule, + bookSource ) nextUrl = chapterData.nextUrl.firstOrNull() ?: "" chapterData.chapterList?.let { @@ -128,7 +144,15 @@ object BookChapterList { ).getStrResponse(bookSource.bookSourceUrl).body ?: throw Exception("${chapterData.nextUrl}, 下载失败") 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) { val isFinished = addChapterListIsFinish( @@ -195,6 +219,7 @@ object BookChapterList { scope: CoroutineScope, book: Book, baseUrl: String, + redirectUrl: String, body: String, tocRule: TocRule, listRule: String, @@ -204,6 +229,7 @@ object BookChapterList { ): ChapterData> { val analyzeRule = AnalyzeRule(book) analyzeRule.setContent(body).setBaseUrl(baseUrl) + analyzeRule.setRedirectUrl(redirectUrl) //获取目录列表 val chapterList = arrayListOf() Debug.log(bookSource.bookSourceUrl, "┌获取目录列表", log) diff --git a/app/src/main/java/io/legado/app/model/webBook/BookContent.kt b/app/src/main/java/io/legado/app/model/webBook/BookContent.kt index e0aecc781..e305d1d4a 100644 --- a/app/src/main/java/io/legado/app/model/webBook/BookContent.kt +++ b/app/src/main/java/io/legado/app/model/webBook/BookContent.kt @@ -41,6 +41,7 @@ object BookContent { val nextUrlList = arrayListOf(baseUrl) val contentRule = bookSource.getContentRule() val analyzeRule = AnalyzeRule(book).setContent(body, baseUrl) + analyzeRule.setRedirectUrl(baseUrl) analyzeRule.nextChapterUrl = mNextChapterUrl var contentData = analyzeContent( book, baseUrl, body, contentRule, bookChapter, bookSource, mNextChapterUrl diff --git a/app/src/main/java/io/legado/app/model/webBook/BookInfo.kt b/app/src/main/java/io/legado/app/model/webBook/BookInfo.kt index c8bf93e71..aaabf18fa 100644 --- a/app/src/main/java/io/legado/app/model/webBook/BookInfo.kt +++ b/app/src/main/java/io/legado/app/model/webBook/BookInfo.kt @@ -22,6 +22,7 @@ object BookInfo { body: String?, bookSource: BookSource, baseUrl: String, + redirectUrl: String, canReName: Boolean, ) { body ?: throw Exception( @@ -31,6 +32,7 @@ object BookInfo { val infoRule = bookSource.getBookInfoRule() val analyzeRule = AnalyzeRule(book) analyzeRule.setContent(body).setBaseUrl(baseUrl) + analyzeRule.setRedirectUrl(redirectUrl) infoRule.init?.let { if (it.isNotBlank()) { scope.ensureActive() @@ -84,7 +86,7 @@ object BookInfo { scope.ensureActive() Debug.log(bookSource.bookSourceUrl, "┌获取封面链接") 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}") scope.ensureActive() diff --git a/app/src/main/java/io/legado/app/model/webBook/BookList.kt b/app/src/main/java/io/legado/app/model/webBook/BookList.kt index 0dbde453e..c486c6e98 100644 --- a/app/src/main/java/io/legado/app/model/webBook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webBook/BookList.kt @@ -37,6 +37,7 @@ object BookList { Debug.log(bookSource.bookSourceUrl, "≡获取成功:${analyzeUrl.ruleUrl}") val analyzeRule = AnalyzeRule(variableBook) analyzeRule.setContent(body).setBaseUrl(baseUrl) + analyzeRule.setRedirectUrl(baseUrl) bookSource.bookUrlPattern?.let { scope.ensureActive() if (baseUrl.matches(it.toRegex())) { diff --git a/app/src/main/java/io/legado/app/model/webBook/WebBook.kt b/app/src/main/java/io/legado/app/model/webBook/WebBook.kt index bafc0ca0f..8e9e549ed 100644 --- a/app/src/main/java/io/legado/app/model/webBook/WebBook.kt +++ b/app/src/main/java/io/legado/app/model/webBook/WebBook.kt @@ -127,6 +127,7 @@ class WebBook(val bookSource: BookSource) { book.infoHtml, bookSource, book.bookUrl, + book.bookUrl, canReName ) } else { @@ -136,7 +137,15 @@ class WebBook(val bookSource: BookSource) { headerMapF = bookSource.getHeaderMap(), book = book ).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 } @@ -160,7 +169,14 @@ class WebBook(val bookSource: BookSource) { ): List { book.type = bookSource.bookSourceType 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 { val res = AnalyzeUrl( book = book, @@ -168,7 +184,14 @@ class WebBook(val bookSource: BookSource) { baseUrl = book.bookUrl, headerMapF = bookSource.getHeaderMap() ).getStrResponse(bookSource.bookSourceUrl) - BookChapterList.analyzeChapterList(scope, book, res.body, bookSource, book.tocUrl) + BookChapterList.analyzeChapterList( + scope, + book, + res.body, + bookSource, + book.tocUrl, + res.url + ) } } diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index 9ec9fbaf3..732c1b902 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -242,6 +242,9 @@ class ReadBookActivity : ReadBookBaseActivity(), supportFragmentManager, ReadBook.book?.tocUrl ) + R.id.menu_reverse_content -> ReadBook.book?.let { + viewModel.reverseContent(it) + } R.id.menu_set_charset -> showCharsetConfig() R.id.menu_get_progress -> ReadBook.book?.let { viewModel.syncBookProgress(it) { progress -> diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt index 5fff40d5c..5b6281320 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt @@ -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) + } + } + } + /** * 替换规则变化 */ diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt index 59344bfdc..c3fab473d 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt @@ -103,6 +103,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { alert(title = getString(R.string.group_edit)) { val alertBinding = DialogEditTextBinding.inflate(layoutInflater) alertBinding.editView.setHint(R.string.group_name) + alertBinding.editView.setText(group) customView { alertBinding.root } yesButton { viewModel.upGroup(group, alertBinding.editView.text?.toString()) diff --git a/app/src/main/res/menu/book_read.xml b/app/src/main/res/menu/book_read.xml index b34861c5a..e2cdb3f45 100644 --- a/app/src/main/res/menu/book_read.xml +++ b/app/src/main/res/menu/book_read.xml @@ -73,6 +73,11 @@ android:title="@string/get_book_progress" app:showAsAction="never" /> + + 导出文件夹 导出编码 导出到WebDav + 反转内容 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 762318f9f..0f4e05286 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -808,5 +808,6 @@ 匯出資料夾 匯出編碼 匯出到WebDav + 反转内容 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index d4dad82b7..cf60feffd 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -808,5 +808,6 @@ 导出文件夹 导出编码 导出到WebDav + 反转内容 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 227aeb400..0e1c150cd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -811,5 +811,6 @@ 导出文件夹 导出编码 导出到WebDav + 反转内容 diff --git a/build.gradle b/build.gradle index e4a3e9d2e..228c51fa0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.4.30' + ext.kotlin_version = '1.4.31' repositories { google() jcenter()