Skip to content

Commit

Permalink
feat: 新增 webdav 书仓功能,新增修改目录规则功能,优化本地书籍换源功能
Browse files Browse the repository at this point in the history
  • Loading branch information
hectorqin committed Jul 11, 2022
1 parent 261285c commit bc88e41
Show file tree
Hide file tree
Showing 17 changed files with 401 additions and 145 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.2"
version = "2.5.3"

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.2'
version = '2.5.3'
sourceCompatibility = '1.8'

repositories {
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/htmake/reader/api/YueduApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,8 @@ class YueduApi : RestVerticle() {
// 删除书仓文件
router.post("/reader3/deleteLocalStoreFile").coroutineHandler { bookController.deleteLocalStoreFile(it) }
router.post("/reader3/deleteLocalStoreFileList").coroutineHandler { bookController.deleteLocalStoreFileList(it) }
// 从书仓导入
router.post("/reader3/importFromLocalStorePreview").coroutineHandler { bookController.importFromLocalStorePreview(it) }
// 从本地书仓/webdav导入
router.post("/reader3/importFromLocalPathPreview").coroutineHandler { bookController.importFromLocalPathPreview(it) }
// 上传文件到书仓
router.post("/reader3/uploadFileToLocalStore").coroutineHandler { bookController.uploadFileToLocalStore(it) }

Expand Down
98 changes: 81 additions & 17 deletions src/main/java/com/htmake/reader/api/controller/BookController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1117,11 +1117,15 @@ class BookController(coroutineContext: CoroutineContext): BaseController(corouti
val userBookSourceStringList = loadBookSourceStringList(userNameSpace)
limitConcurrent(concurrentCount, 0, bookSourceList.size(), {it ->
var searchBook = bookSourceList.getJsonObject(it).mapTo(SearchBook::class.java)
var bookSource = getBookSourceStringBySourceURL(searchBook.origin, userNameSpace, userBookSourceStringList)
if (bookSource != null) {
searchBookWithSource(bookSource, book, userNameSpace = userNameSpace)
if (searchBook.origin.equals("loc_book")) {
arrayListOf(searchBook)
} else {
arrayListOf<SearchBook>()
var bookSource = getBookSourceStringBySourceURL(searchBook.origin, userNameSpace, userBookSourceStringList)
if (bookSource != null) {
searchBookWithSource(bookSource, book, userNameSpace = userNameSpace)
} else {
arrayListOf<SearchBook>()
}
}
}) {list, _->
// logger.info("list: {}", list)
Expand Down Expand Up @@ -1259,6 +1263,26 @@ class BookController(coroutineContext: CoroutineContext): BaseController(corouti
val relativeLocalFilePath = Paths.get("storage", "data", userNameSpace, book.name + "_" + book.author, tempFile.name).toString()
book.bookUrl = relativeLocalFilePath

if (book.isEpub()) {
// 解压文件 index.epub
if (!extractEpub(book)) {
return returnData.setErrorMsg("导入本地Epub书籍失败")
}
} else if (book.isCbz()) {
// 解压文件 index.cbz
if (!extractCbz(book)) {
return returnData.setErrorMsg("导入本地CBZ书籍失败")
}
}
} else if (book.bookUrl.indexOf("webdav/") >= 0) {
// webdav书仓,不用移动书籍
val tempFile = File(getWorkDir(book.bookUrl))
if (!tempFile.exists()) {
return returnData.setErrorMsg("webdav书仓书籍不存在")
}
val relativeLocalFilePath = Paths.get("storage", "data", userNameSpace, book.name + "_" + book.author, tempFile.name).toString()
book.bookUrl = relativeLocalFilePath

if (book.isEpub()) {
// 解压文件 index.epub
if (!extractEpub(book)) {
Expand Down Expand Up @@ -1294,6 +1318,10 @@ class BookController(coroutineContext: CoroutineContext): BaseController(corouti
} else {
bookshelf.add(JsonObject.mapFrom(book))
}
// 保存书源信息
val sourceList = listOf(book.toSearchBook())
saveBookSources(book, sourceList, userNameSpace)

// logger.info("bookshelf: {}", bookshelf)
saveUserStorage(userNameSpace, "bookshelf", bookshelf)
return returnData.setData(book)
Expand Down Expand Up @@ -1335,32 +1363,53 @@ class BookController(coroutineContext: CoroutineContext): BaseController(corouti
// 查找是否存在该书源
var bookSourceString = getBookSourceStringBySourceURL(bookSourceUrl, userNameSpace)

var searchBook: Book? = null
if (bookSourceString.isNullOrEmpty()) {
return returnData.setErrorMsg("书源信息错误")
}
// 判断是不是本地书籍
val localBookSourceList = asJsonArray(getUserStorage(userNameSpace, book.name + "_" + book.author, "bookSource"))

var newBookInfo = WebBook(bookSourceString, appConfig.debugLog).getBookInfo(newBookUrl)
// 遍历判断书本是否存在
if (localBookSourceList != null) {
for (i in 0 until localBookSourceList.size()) {
var _searchBook = localBookSourceList.getJsonObject(i).mapTo(SearchBook::class.java)
if (_searchBook.bookUrl.equals(newBookUrl)) {
searchBook = _searchBook.toBook()
break;
}
}
}
if (searchBook == null) {
return returnData.setErrorMsg("书源信息错误")
}
}

var bookSource: BookSource = bookSourceString.toMap().toDataClass()
var newBookInfo = if (searchBook != null) {
searchBook
} else {
if (bookSourceString.isNullOrEmpty()) {
return returnData.setErrorMsg("书源信息错误")
}
WebBook(bookSourceString, appConfig.debugLog).getBookInfo(newBookUrl)
}

editShelfBook(book, userNameSpace) { existBook ->
existBook.origin = bookSource.bookSourceUrl
existBook.originName = bookSource.bookSourceName
existBook.bookUrl = newBookUrl
existBook.origin = newBookInfo.origin
existBook.originName = newBookInfo.originName
existBook.bookUrl = newBookInfo.bookUrl
existBook.tocUrl = newBookInfo.tocUrl
if (existBook.coverUrl.isNullOrEmpty() && !newBookInfo.coverUrl.isNullOrEmpty()) {
existBook.coverUrl = newBookInfo.coverUrl
}

logger.info("saveBookSource: {}", existBook)
logger.info("setBookSource: {}", existBook)

newBookInfo = existBook

existBook
}

// 更新目录
getLocalChapterList(newBookInfo, bookSourceString, true, userNameSpace)
getLocalChapterList(newBookInfo, bookSourceString ?: "", true, userNameSpace)
return returnData.setData(newBookInfo)
}

Expand Down Expand Up @@ -1926,6 +1975,10 @@ class BookController(coroutineContext: CoroutineContext): BaseController(corouti
// 本地书仓的源文件
localEpubFile = File(getWorkDir(book.originName))
}
if (book.originName.indexOf("webdav") > 0) {
// webdav 书仓的源文件
localEpubFile = File(getWorkDir(book.originName))
}
if (!localEpubFile.unzip(epubExtractDir.toString())) {
return false
}
Expand All @@ -1942,6 +1995,10 @@ class BookController(coroutineContext: CoroutineContext): BaseController(corouti
// 本地书仓的源文件
localFile = File(getWorkDir(book.originName))
}
if (book.originName.indexOf("webdav") > 0) {
// webdav 书仓的源文件
localFile = File(getWorkDir(book.originName))
}
if (!localFile.unzip(extractDir.toString())) {
return false
}
Expand Down Expand Up @@ -2155,8 +2212,8 @@ class BookController(coroutineContext: CoroutineContext): BaseController(corouti
return latestZipFile
}

// 本地书仓功能
suspend fun importFromLocalStorePreview(context: RoutingContext): ReturnData {
// 从本地导入文件预览
suspend fun importFromLocalPathPreview(context: RoutingContext): ReturnData {
val returnData = ReturnData()
if (!checkAuth(context)) {
return returnData.setData("NEED_LOGIN").setErrorMsg("请登录后使用")
Expand All @@ -2165,17 +2222,24 @@ class BookController(coroutineContext: CoroutineContext): BaseController(corouti
if (paths == null) {
return returnData.setErrorMsg("参数错误")
}
var webdav = context.bodyAsJson.getBoolean("webdav", false)
if (appConfig.secure) {
var userInfo = context.get("userInfo") as User?
if (userInfo == null) {
return returnData.setData("NEED_LOGIN").setErrorMsg("请登录后使用")
}
if (!userInfo.enable_local_store) {
if (webdav && !userInfo.enable_webdav) {
return returnData.setErrorMsg("未开启 Webdav 功能")
} else if (!userInfo.enable_local_store) {
return returnData.setErrorMsg("未开启本地书仓功能")
}
}
var userNameSpace = getUserNameSpace(context)
var home = getWorkDir("storage", "localStore")
var home = if (webdav) {
getUserWebdavHome(context)
} else {
getWorkDir("storage", "localStore")
}
var fileList = arrayListOf<Map<String, Any>>()
paths.forEach {
var path = it as String? ?: ""
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/io/legado/app/data/entities/Book.kt
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,12 @@ data class Book(
}

fun getLocalFile(): File {
if (isEpub() && originName.indexOf("localStore") < 0) {
// 非本地书仓的 epub文件
if (isEpub() && originName.indexOf("localStore") < 0 && originName.indexOf("webdav") < 0) {
// 非本地/webdav书仓的 epub文件
return FileUtils.getFile(File(rootDir + originName), "index.epub")
}
if (isCbz() && originName.indexOf("localStore") < 0) {
// 非本地书仓的 cbz文件
if (isCbz() && originName.indexOf("localStore") < 0 && originName.indexOf("webdav") < 0) {
// 非本地/webdav书仓的 cbz文件
return FileUtils.getFile(File(rootDir + originName), "index.cbz")
}
return File(rootDir + originName)
Expand Down
2 changes: 1 addition & 1 deletion web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "reader",
"version": "2.5.2",
"version": "2.5.3",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
Expand Down
6 changes: 3 additions & 3 deletions web/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -777,9 +777,9 @@ export default {
},
getBookContent(chapterIndex, options, refresh, cache, book) {
book = book || {
name: this.$store.state.readingBook.bookName,
author: this.$store.state.readingBook.author,
bookUrl: this.$store.state.readingBook.bookUrl
name: this.$store.getters.readingBook.name,
author: this.$store.getters.readingBook.author,
bookUrl: this.$store.getters.readingBook.bookUrl
};
const params = {
url: book.bookUrl,
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/BookInfo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ export default {
},
error => {
this.$message.error(
(isAdd ? "加入书架成功" : "操作成功") + (error && error.toString())
(isAdd ? "加入书架失败" : "操作失败") + (error && error.toString())
);
}
);
Expand Down
17 changes: 11 additions & 6 deletions web/src/components/BookShelf.vue
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export default {
},
methods: {
isSelected(book) {
return book.bookUrl == this.$store.state.readingBook.bookUrl;
return book.bookUrl == this.$store.getters.readingBook.bookUrl;
},
getBookshelf(refresh) {
if (this.shelfBooks.length) {
Expand Down Expand Up @@ -115,12 +115,17 @@ export default {
},
changeBook(book) {
const readingBook = {
bookName: book.name,
name: book.name,
bookUrl: book.bookUrl,
index: book.durChapterIndex,
index: book.index ?? book.durChapterIndex ?? 0,
type: book.type,
coverUrl: book.coverUrl,
author: book.author
coverUrl: book.customCoverUrl || book.coverUrl,
tocUrl: book.tocUrl,
author: book.author,
origin: book.origin,
originName: book.originName,
latestChapterTitle: book.latestChapterTitle,
intro: book.intro
};
this.$emit("changeBook", readingBook);
},
Expand All @@ -133,7 +138,7 @@ export default {
this.$nextTick(() => {
let index = -1;
this.shelfBooks.some((v, i) => {
if (v.bookUrl == this.$store.state.readingBook.bookUrl) {
if (v.bookUrl == this.$store.getters.readingBook.bookUrl) {
index = i;
return true;
}
Expand Down
20 changes: 10 additions & 10 deletions web/src/components/BookSource.vue
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export default {
name: "BookSource",
data() {
return {
index: this.$store.state.readingBook.index,
index: this.$store.getters.readingBook.index,
bookSource: [],
bookSourceGroup: "",
bookSourceGroupIndexMap: {},
Expand All @@ -96,7 +96,7 @@ export default {
}, {});
},
readingBook() {
return this.$store.state.readingBook || {};
return this.$store.getters.readingBook || {};
}
},
mounted() {},
Expand All @@ -114,11 +114,11 @@ export default {
},
methods: {
isSelected(searchBook) {
return searchBook.bookUrl == this.$store.state.readingBook.bookUrl;
return searchBook.bookUrl == this.$store.getters.readingBook.bookUrl;
},
getBookSource(refresh) {
Axios.post(this.api + `/getAvailableBookSource`, {
url: this.$store.state.readingBook.bookUrl,
url: this.$store.getters.readingBook.bookUrl,
refresh: refresh ? 1 : 0
}).then(
res => {
Expand Down Expand Up @@ -147,21 +147,21 @@ export default {
},
async changeBookSource(searchBook) {
const isInShelf = await this.$root.$children[0].isInShelf(
this.$store.state.readingBook,
this.$store.getters.readingBook,
"加入书架之后才能切换书源, 是否加入书架?"
);
if (!isInShelf) {
return;
}
Axios.post(this.api + `/setBookSource`, {
bookUrl: this.$store.state.readingBook.bookUrl,
bookUrl: this.$store.getters.readingBook.bookUrl,
newUrl: searchBook.bookUrl,
bookSourceUrl: searchBook.origin
}).then(
res => {
if (res.data.isSuccess) {
this.$message.info("换源成功");
var book = Object.assign({}, this.$store.state.readingBook);
var book = Object.assign({}, this.$store.getters.readingBook);
book.bookUrl = searchBook.bookUrl;
book.type =
typeof searchBook.type !== "undefined"
Expand Down Expand Up @@ -202,7 +202,7 @@ export default {
if (this.loadingMore) return;
this.loadingMore = true;
Axios.post(this.api + `/searchBookSource`, {
url: this.$store.state.readingBook.bookUrl,
url: this.$store.getters.readingBook.bookUrl,
bookSourceGroup: this.bookSourceGroup,
lastIndex: this.bookSourceGroupIndexMap[this.bookSourceGroup]
}).then(
Expand Down Expand Up @@ -253,7 +253,7 @@ export default {
const params = {
accessToken: this.$store.state.token,
concurrentCount: this.$store.state.searchConfig.concurrentCount,
url: this.$store.state.readingBook.bookUrl,
url: this.$store.getters.readingBook.bookUrl,
bookSourceGroup: this.bookSourceGroup,
lastIndex: this.bookSourceGroupIndexMap[this.bookSourceGroup]
};
Expand Down Expand Up @@ -325,7 +325,7 @@ export default {
this.$nextTick(() => {
let index = -1;
this.bookSource.some((v, i) => {
if (v.bookUrl == this.$store.state.readingBook.bookUrl) {
if (v.bookUrl == this.$store.getters.readingBook.bookUrl) {
index = i;
return true;
}
Expand Down
Loading

0 comments on commit bc88e41

Please sign in to comment.