Skip to content

Commit

Permalink
feat: 新增分组排序功能,新增朗读定时功能,新增音频音量调整功能,修复书架更新并发bug,修复window环境问题,修复书源调试bug…
Browse files Browse the repository at this point in the history
…,修复音频bug
  • Loading branch information
hectorqin committed Jul 13, 2022
1 parent bc88e41 commit 92d81b8
Show file tree
Hide file tree
Showing 21 changed files with 354 additions and 84 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ apply(plugin = "kotlin")
apply(plugin = "io.github.fvarrui.javapackager.plugin")

group = "com.htmake"
version = "2.5.3"
version = "2.5.4"

java {
sourceCompatibility = JavaVersion.VERSION_1_8
Expand Down
2 changes: 1 addition & 1 deletion cli.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ apply plugin: 'io.spring.dependency-management'
apply plugin: 'kotlin'

group = 'com.htmake'
version = '2.5.3'
version = '2.5.4'
sourceCompatibility = '1.8'

repositories {
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/htmake/reader/api/YueduApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ class YueduApi : RestVerticle() {
router.get("/reader3/getBookGroups").coroutineHandler { bookController.getBookGroups(it) }
router.post("/reader3/saveBookGroup").coroutineHandler { bookController.saveBookGroup(it) }
router.post("/reader3/deleteBookGroup").coroutineHandler { bookController.deleteBookGroup(it) }
router.post("/reader3/saveBookGroupOrder").coroutineHandler { bookController.saveBookGroupOrder(it) }

// 书仓功能
// 获取书仓文件列表
Expand Down
103 changes: 75 additions & 28 deletions src/main/java/com/htmake/reader/api/controller/BookController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ import io.legado.app.model.analyzeRule.AnalyzeUrl
import java.nio.file.Paths
import kotlinx.coroutines.withContext
import kotlinx.coroutines.async
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.CoroutineScope
import me.ag2s.epublib.domain.*
Expand Down Expand Up @@ -1587,10 +1588,16 @@ class BookController(coroutineContext: CoroutineContext): BaseController(corouti
}
var userNameSpace = getUserNameSpace(context)
var bookGroupList: JsonArray? = asJsonArray(getUserStorage(userNameSpace, "bookGroup"))
if (bookGroupList != null) {
return returnData.setData(bookGroupList.getList())
if (bookGroupList == null) {
bookGroupList = asJsonArray("""
[{"groupId":-1,"groupName":"全部","order":-10,"show":true},{"groupId":-2,"groupName":"本地","order":-9,"show":true},{"groupId":-3,"groupName":"音频","order":-8,"show":true},{"groupId":-4,"groupName":"未分组","order":-7,"show":true}]
""")
if (bookGroupList == null) {
return returnData.setData(arrayListOf<Int>())
}
saveUserStorage(userNameSpace, "bookGroup", bookGroupList)
}
return returnData.setData(arrayListOf<Int>())
return returnData.setData(bookGroupList.getList())
}

suspend fun saveBookGroup(context: RoutingContext): ReturnData {
Expand Down Expand Up @@ -1646,6 +1653,40 @@ class BookController(coroutineContext: CoroutineContext): BaseController(corouti
return returnData.setData("")
}

suspend fun saveBookGroupOrder(context: RoutingContext): ReturnData {
val returnData = ReturnData()
if (!checkAuth(context)) {
return returnData.setData("NEED_LOGIN").setErrorMsg("请登录后使用")
}
val bookGroupOrder = context.bodyAsJson.getJsonArray("order", null)
if (bookGroupOrder == null) {
return returnData.setErrorMsg("参数错误")
}

var userNameSpace = getUserNameSpace(context)
var bookGroupList: JsonArray? = asJsonArray(getUserStorage(userNameSpace, "bookGroup"))
if (bookGroupList == null) {
bookGroupList = JsonArray()
}
var orderMap: MutableMap<Int, Int> = mutableMapOf()
for (i in 0 until bookGroupOrder.size()) {
orderMap.put(bookGroupOrder.getJsonObject(i).getInteger("groupId"), bookGroupOrder.getJsonObject(i).getInteger("order"))
}
// 遍历判断书本是否存在
var groupList = bookGroupList.getList()
for (i in 0 until bookGroupList.size()) {
var bookGroup = bookGroupList.getJsonObject(i).mapTo(BookGroup::class.java)
if (orderMap.containsKey(bookGroup.groupId)) {
bookGroup.order = orderMap.get(bookGroup.groupId) as? Int ?: bookGroup.order
groupList.set(i, JsonObject.mapFrom(bookGroup))
}
}
bookGroupList = JsonArray(groupList)

// logger.info("bookGroupList: {}", bookGroupList)
saveUserStorage(userNameSpace, "bookGroup", bookGroupList)
return returnData.setData("")
}

suspend fun deleteBookGroup(context: RoutingContext): ReturnData {
val returnData = ReturnData()
Expand All @@ -1658,7 +1699,7 @@ class BookController(coroutineContext: CoroutineContext): BaseController(corouti
if (bookGroupList == null) {
bookGroupList = JsonArray()
}
// 遍历判断书本是否存在
// 遍历判断分组是否存在
var existIndex: Int = -1
for (i in 0 until bookGroupList.size()) {
var _bookGroup = bookGroupList.getJsonObject(i).mapTo(BookGroup::class.java)
Expand Down Expand Up @@ -1706,14 +1747,15 @@ class BookController(coroutineContext: CoroutineContext): BaseController(corouti
var bookList = arrayListOf<Book>()
val concurrentCount = 16
val userBookSourceStringList = loadBookSourceStringList(userNameSpace)
val mutex = Mutex()
limitConcurrent(concurrentCount, 0, bookshelf.size()) {
var book = bookshelf.getJsonObject(it).mapTo(Book::class.java)
if (!book.isLocalBook() && book.canUpdate && refresh) {
try {
var bookSource = getBookSourceStringBySourceURL(book.origin, userNameSpace, userBookSourceStringList)
if (bookSource != null) {
withContext(Dispatchers.IO) {
var bookChapterList = getLocalChapterList(book, bookSource, refresh, userNameSpace, false)
var bookChapterList = getLocalChapterList(book, bookSource, refresh, userNameSpace, false, mutex)
if (bookChapterList.size > 0) {
var bookChapter = bookChapterList.last()
book.latestChapterTitle = bookChapter.title
Expand All @@ -1735,7 +1777,7 @@ class BookController(coroutineContext: CoroutineContext): BaseController(corouti
}


suspend fun getLocalChapterList(book: Book, bookSource: String, refresh: Boolean = false, userNameSpace: String, debugLog: Boolean = true): List<BookChapter> {
suspend fun getLocalChapterList(book: Book, bookSource: String, refresh: Boolean = false, userNameSpace: String, debugLog: Boolean = true, mutex: Mutex? = null): List<BookChapter> {
val md5Encode = MD5Utils.md5Encode(book.bookUrl).toString()
var chapterList: JsonArray? = asJsonArray(getUserStorage(userNameSpace, book.name + "_" + book.author, md5Encode))

Expand Down Expand Up @@ -1769,7 +1811,7 @@ class BookController(coroutineContext: CoroutineContext): BaseController(corouti
}
}
saveUserStorage(userNameSpace, getRelativePath(book.name + "_" + book.author, md5Encode), newChapterList)
saveShelfBookLatestChapter(book, newChapterList, userNameSpace)
saveShelfBookLatestChapter(book, newChapterList, userNameSpace, mutex)
return newChapterList
}
var localChapterList = arrayListOf<BookChapter>()
Expand Down Expand Up @@ -1879,21 +1921,26 @@ class BookController(coroutineContext: CoroutineContext): BaseController(corouti
}
}

fun saveShelfBookLatestChapter(book: Book, bookChapterList: List<BookChapter>, userNameSpace: String) {
editShelfBook(book, userNameSpace) { existBook ->
if (bookChapterList.size > 0) {
var bookChapter = bookChapterList.last()
existBook.latestChapterTitle = bookChapter.title
}
if (bookChapterList.size - existBook.totalChapterNum > 0) {
existBook.lastCheckCount = bookChapterList.size - existBook.totalChapterNum
existBook.lastCheckTime = System.currentTimeMillis()
}
existBook.totalChapterNum = bookChapterList.size
// TODO 最新章节更新时间
// existBook.latestChapterTime = System.currentTimeMillis()
// logger.info("saveShelfBookLatestChapter: {}", existBook)
existBook
suspend fun saveShelfBookLatestChapter(book: Book, bookChapterList: List<BookChapter>, userNameSpace: String, mutex: Mutex? = null) {
try {
mutex?.lock()
editShelfBook(book, userNameSpace) { existBook ->
if (bookChapterList.size > 0) {
var bookChapter = bookChapterList.last()
existBook.latestChapterTitle = bookChapter.title
}
if (bookChapterList.size - existBook.totalChapterNum > 0) {
existBook.lastCheckCount = bookChapterList.size - existBook.totalChapterNum
existBook.lastCheckTime = System.currentTimeMillis()
}
existBook.totalChapterNum = bookChapterList.size
// TODO 最新章节更新时间
// existBook.latestChapterTime = System.currentTimeMillis()
// logger.info("saveShelfBookLatestChapter: {}", existBook)
existBook
}
} finally {
mutex?.unlock()
}
}

Expand Down Expand Up @@ -2890,19 +2937,19 @@ class BookController(coroutineContext: CoroutineContext): BaseController(corouti
private fun setAssets(book: Book, epubBook: EpubBook): String {
epubBook.resources.add(
Resource(
BookController::class.java.getResource("${File.separator}epub${File.separator}fonts.css").readBytes(),
BookController::class.java.getResource("/epub/fonts.css").readBytes(),
"Styles/fonts.css"
)
)
epubBook.resources.add(
Resource(
BookController::class.java.getResource("${File.separator}epub${File.separator}main.css").readBytes(),
BookController::class.java.getResource("/epub/main.css").readBytes(),
"Styles/main.css"
)
)
epubBook.resources.add(
Resource(
BookController::class.java.getResource("${File.separator}epub${File.separator}logo.png").readBytes(),
BookController::class.java.getResource("/epub/logo.png").readBytes(),
"Images/logo.png"
)
)
Expand All @@ -2914,7 +2961,7 @@ class BookController(coroutineContext: CoroutineContext): BaseController(corouti
book.getDisplayIntro(),
book.kind,
book.wordCount,
String(BookController::class.java.getResource("${File.separator}epub${File.separator}cover.html").readBytes()),
String(BookController::class.java.getResource("/epub/cover.html").readBytes()),
"Text/cover.html"
)
)
Expand All @@ -2926,12 +2973,12 @@ class BookController(coroutineContext: CoroutineContext): BaseController(corouti
book.getDisplayIntro(),
book.kind,
book.wordCount,
String(BookController::class.java.getResource("${File.separator}epub${File.separator}intro.html").readBytes()),
String(BookController::class.java.getResource("/epub/intro.html").readBytes()),
"Text/intro.html"
)
)

return String(BookController::class.java.getResource("${File.separator}epub${File.separator}chapter.html").readBytes())
return String(BookController::class.java.getResource("/epub/chapter.html").readBytes())
}

private suspend fun setCover(book: Book, epubBook: EpubBook, bookSourceString: String) {
Expand Down
8 changes: 5 additions & 3 deletions src/main/java/com/htmake/reader/utils/VertExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,10 @@ fun getWorkDir(subPath: String = ""): String {
var currentDir = System.getProperty("user.dir")
logger.info("osName: {} currentDir: {}", osName, currentDir)
// MacOS 存放目录为用户目录
if (osName.startsWith("Mac OS") && !currentDir.startsWith("/Users/")) {
if (osName.startsWith("Mac OS", true) && !currentDir.startsWith("/Users/")) {
workDirPath = Paths.get(System.getProperty("user.home"), ".reader").toString()
} else {
workDirPath = currentDir
}
workDirInit = true
}
Expand Down Expand Up @@ -141,7 +143,7 @@ fun saveStorage(vararg name: String, value: Any, pretty: Boolean = false) {
val filename = name.last()
val file = File(getRelativePath(storagePath, *name.copyOfRange(0, name.size - 1), "${filename}.json"))
// val file = File(storagePath + "/${name}.json")
logger.info("storage key: {} path: {}", name, file.absoluteFile)
logger.info("Save file to storage name: {} path: {}", name, file.absoluteFile)

if (!file.parentFile.exists()) {
file.parentFile.mkdirs()
Expand All @@ -162,7 +164,7 @@ fun getStorage(vararg name: String): String? {

val filename = name.last()
val file = File(getRelativePath(storagePath, *name.copyOfRange(0, name.size - 1), "${filename}.json"))
logger.info("storage key: {} path: {}", name, file.absoluteFile)
logger.info("Read file from storage name: {} path: {}", name, file.absoluteFile)
if (!file.exists()) {
return null
}
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/io/legado/app/constant/BookType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.legado.app.constant
object BookType {
const val default = 0 // 0 文本
const val audio = 1 // 1 音频
const val image = 3 //图片
const val image = 2 // 2 图片
const val file = 3 // 3 只提供下载服务的网站
const val local = "loc_book"
}
2 changes: 1 addition & 1 deletion src/main/java/io/legado/app/help/DefaultData.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ object DefaultData {
const val txtTocRuleFileName = "txtTocRule.json"

val txtTocRules: List<TxtTocRule> by lazy {
val json = String(DefaultData::class.java.getResource("${File.separator}defaultData${File.separator}$txtTocRuleFileName").readBytes())
val json = String(DefaultData::class.java.getResource("/defaultData/${txtTocRuleFileName}").readBytes())
GSON.fromJsonArray<TxtTocRule>(json).getOrNull() ?: emptyList()
}

Expand Down
1 change: 1 addition & 0 deletions src/main/java/io/legado/app/model/Debugger.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class Debugger(val logMsg: (String) -> Unit) : DebugLog {
suspend fun startDebug(webBook: WebBook, key: String) {
val bookSource = webBook.bookSource
webBook.debugLogger = this@Debugger
startTime = System.currentTimeMillis()
when {
key.isAbsUrl() -> {
val book = Book()
Expand Down
15 changes: 13 additions & 2 deletions src/main/java/io/legado/app/utils/SourceAnalyzer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,19 @@ object SourceAnalyzer {
header = uaToHeader(jsonItem.readString("httpUserAgent"))
searchUrl = toNewUrl(jsonItem.readString("ruleSearchUrl"))
exploreUrl = toNewUrls(jsonItem.readString("ruleFindUrl"))
bookSourceType =
if (jsonItem.readString("bookSourceType") == "AUDIO") BookType.audio else BookType.default
val sourceType = jsonItem.readString("bookSourceType")
bookSourceType = when(sourceType) {
"AUDIO" -> BookType.audio
"audio" -> BookType.audio
"1" -> BookType.audio
"IMAGE" -> BookType.image
"image" -> BookType.image
"2" -> BookType.image
"FILE" -> BookType.file
"file" -> BookType.file
"3" -> BookType.file
else -> BookType.default
}
enabled = jsonItem.readBool("enable") ?: true
if (exploreUrl.isNullOrBlank()) {
enabledExplore = false
Expand Down
3 changes: 2 additions & 1 deletion web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "reader",
"version": "2.5.3",
"version": "2.5.4",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
Expand All @@ -16,6 +16,7 @@
"localforage": "^1.10.0",
"prismjs": "^1.25.0",
"register-service-worker": "^1.7.1",
"sortablejs": "^1.15.0",
"stylus": "^0.54.7",
"stylus-loader": "^3.0.2",
"vue": "^2.6.10",
Expand Down
5 changes: 2 additions & 3 deletions web/public/bookSourceDebug/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,8 @@ function rule2json() {
RuleJSON.customOrder =
RuleJSON.customOrder == "" ? 0 : parseInt(RuleJSON.customOrder);
RuleJSON.weight = RuleJSON.weight == "" ? 0 : parseInt(RuleJSON.weight);
(RuleJSON.bookSourceType == RuleJSON.bookSourceType) == ""
? 0
: parseInt(RuleJSON.bookSourceType);
RuleJSON.bookSourceType =
RuleJSON.bookSourceType == "" ? 0 : parseInt(RuleJSON.bookSourceType);
RuleJSON.enabled =
RuleJSON.enabled == "" ||
String(RuleJSON.enabled)
Expand Down
1 change: 0 additions & 1 deletion web/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
<meta name="x5-page-mode" content="app">
<meta name="msapplication-tap-highlight" content="no">
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<link rel="stylesheet" type="text/css" href="//at.alicdn.com/t/font_2841133_2ey3idoaxcg.css" />
<title>阅读</title>
<script>
// 通用加载脚本方法
Expand Down
1 change: 1 addition & 0 deletions web/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ import { CodeJar } from "codejar";
import Prism from "prismjs";
import "prismjs/components/prism-json";
import "prismjs/themes/prism.css";
import "./assets/fonts/iconfont.css";
import {
cacheFirstRequest,
isMiniInterface,
Expand Down
Loading

0 comments on commit 92d81b8

Please sign in to comment.