Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

完成epub导出功能 #142

Merged
merged 5 commits into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .idea/appInsightsSettings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

123 changes: 123 additions & 0 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions .idea/runConfigurations.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ LightNovelReader <sup>*重构版*</sup> 是一款开源的轻小说阅读软件
| ![image](https://github.com/dmzz-yyhyy/LightNovelReader/blob/refactoring/assets/reading_light.png) |
| ![image](https://github.com/dmzz-yyhyy/LightNovelReader/blob/refactoring/assets/reading_dark.png) |

### EpubLib
为了处理epub的导出问题,我们单独创建了一个epub处理模块,如果您感兴趣,可以看[**这里**](https://github.com/dmzz-yyhyy/LightNovelReader/blob/refactoring/epub.md)


## License

```
Expand Down
23 changes: 12 additions & 11 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ android {
minSdk = 24
targetSdk = 34
// 版本号为x.y.z则versionCode为x*1000000+y*10000+z*100+debug版本号(开发需要时迭代, 两位数)
versionCode = 1_00_00_017
versionCode = 1_00_00_018
versionName = "1.0.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
Expand Down Expand Up @@ -78,19 +78,19 @@ android {

dependencies {
// desugaring support
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.2")
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4")
// android lib
implementation("androidx.core:core-ktx:1.13.1")
implementation ("androidx.core:core-splashscreen:1.0.1")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.6")
implementation("androidx.lifecycle:lifecycle-runtime-compose-android:2.8.6")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7")
implementation("androidx.lifecycle:lifecycle-runtime-compose-android:2.8.7")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7")
// compose
implementation("androidx.activity:activity-compose:1.9.2")
implementation("androidx.compose.animation:animation-graphics-android:1.7.1")
implementation(platform("androidx.compose:compose-bom:2024.09.01"))
implementation("androidx.compose.material3:material3:1.3.0")
androidTestImplementation(platform("androidx.compose:compose-bom:2024.09.01"))
implementation("androidx.activity:activity-compose:1.9.3")
implementation("androidx.compose.animation:animation-graphics-android:1.7.6")
implementation(platform("androidx.compose:compose-bom:2024.12.01"))
implementation("androidx.compose.material3:material3:1.3.1")
androidTestImplementation(platform("androidx.compose:compose-bom:2024.12.01"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
Expand All @@ -112,7 +112,7 @@ dependencies {
implementation("androidx.hilt:hilt-work:$androidXHilt")
implementation("androidx.hilt:hilt-navigation-compose:$androidXHilt")
// navigation
val navVersion = "2.8.0"
val navVersion = "2.8.5"
implementation("androidx.navigation:navigation-fragment-ktx:$navVersion")
implementation("androidx.navigation:navigation-ui-ktx:$navVersion")
implementation("androidx.navigation:navigation-dynamic-features-fragment:$navVersion")
Expand Down Expand Up @@ -151,6 +151,7 @@ dependencies {
implementation("androidx.work:work-gcm:$workVersion")
androidTestImplementation("androidx.work:work-testing:$workVersion")
implementation("androidx.work:work-multiprocess:$workVersion")
implementation(project(":epub"))
}

kapt {
Expand Down
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

<application
android:usesCleartextTraffic="true"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package indi.dmzz_yyhyy.lightnovelreader.data.work

import android.content.Context
import android.net.Uri
import androidx.hilt.work.HiltWorker
import androidx.work.Worker
import androidx.work.WorkerParameters
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import indi.dmzz_yyhyy.lightnovelreader.data.book.ChapterContent
import indi.dmzz_yyhyy.lightnovelreader.data.web.WebBookDataSource
import indi.dmzz_yyhyy.lightnovelreader.utils.ImageDownloader
import io.nightfish.potatoepub.builder.EpubBuilder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import java.io.File
import java.time.LocalDateTime

@HiltWorker
class ExportBookToEPUBWork @AssistedInject constructor(
@Assisted appContext: Context,
@Assisted workerParams: WorkerParameters,
private val webBookDataSource: WebBookDataSource
) : Worker(appContext, workerParams) {
val coroutineScope = CoroutineScope(Dispatchers.IO)
override fun doWork(): Result {
val bookId = inputData.getInt("bookId", -1)
val fileUri = inputData.getString("uri")?.let(Uri::parse) ?: return Result.failure()
val tempDir = applicationContext.cacheDir.resolve("epub").resolve(bookId.toString())
val cover = tempDir.resolve("cover.jpg")
if (bookId < 0) return Result.failure()
val tasks = mutableListOf<ImageDownloader.Task>()
val epub = EpubBuilder().apply {
val bookInformation = webBookDataSource.getBookInformation(bookId) ?: return Result.failure()
val bookVolumes = webBookDataSource.getBookVolumes(bookId) ?: return Result.failure()
val bookContentMap = mutableMapOf<Int, ChapterContent>()
bookVolumes.volumes.forEach { volume ->
volume.chapters.forEach {
bookContentMap[it.id] = webBookDataSource.getChapterContent(it.id, bookId) ?: return Result.failure()
}
}
title = bookInformation.title
modifier = LocalDateTime.now()
creator = bookInformation.author
description = bookInformation.description
publisher = bookInformation.publishingHouse
tasks.add(ImageDownloader.Task(cover, bookInformation.coverUrl))
if (!tempDir.exists())
tempDir.mkdirs()
else
tempDir.listFiles()?.forEach(File::delete)
cover(cover)
bookVolumes.volumes.forEach { volume ->
chapter {
title(volume.volumeTitle)
volume.chapters.forEach {
chapter {
title(it.title)
content {
bookContentMap[it.id]!!.content.split("[image]").filter { it.isNotEmpty() }.forEach { singleText ->
if (singleText.startsWith("http://") || singleText.startsWith("https://")) {
val image = tempDir.resolve(singleText.hashCode().toString() + ".jpg")
tasks.add(ImageDownloader.Task(image, singleText))
image(image)
}
else {
singleText.split("\n").forEach {
text(it)
br()
}
}
}
}
}
}
}
}
}
val imageDownloader = ImageDownloader(
tasks = tasks,
coroutineScope = coroutineScope,
onFinished = {
val file = tempDir.resolve("epub")
epub.build().save(file)
applicationContext.contentResolver.openOutputStream(fileUri).use {
it?.write(file.readBytes())
}
tempDir.delete()
}
)
while (!imageDownloader.isDone) { //
}
return Result.success()
}

override fun onStopped() {
super.onStopped()
coroutineScope.cancel()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ fun BookScreen(
}
DetailScreen(
paddingValues = paddingValues,
onClickBackButton = onClickBackButton,
onClickChapter = {
navController.navigate(Screen.Book.Content.createRoute(it))
},
onClickBackButton = onClickBackButton,
topBar = { newTopBar -> topBar = newTopBar },
id = bookId,
cacheBook = cacheBook,
Expand Down
Loading
Loading