|
|
@ -6,9 +6,10 @@ import androidx.core.app.NotificationCompat |
|
|
|
import io.legado.app.App |
|
|
|
import io.legado.app.App |
|
|
|
import io.legado.app.R |
|
|
|
import io.legado.app.R |
|
|
|
import io.legado.app.base.BaseService |
|
|
|
import io.legado.app.base.BaseService |
|
|
|
import io.legado.app.constant.IntentAction |
|
|
|
|
|
|
|
import io.legado.app.constant.AppConst |
|
|
|
import io.legado.app.constant.AppConst |
|
|
|
import io.legado.app.constant.EventBus |
|
|
|
import io.legado.app.constant.EventBus |
|
|
|
|
|
|
|
import io.legado.app.constant.IntentAction |
|
|
|
|
|
|
|
import io.legado.app.data.entities.BookChapter |
|
|
|
import io.legado.app.help.AppConfig |
|
|
|
import io.legado.app.help.AppConfig |
|
|
|
import io.legado.app.help.BookHelp |
|
|
|
import io.legado.app.help.BookHelp |
|
|
|
import io.legado.app.help.IntentHelp |
|
|
|
import io.legado.app.help.IntentHelp |
|
|
@ -17,6 +18,7 @@ import io.legado.app.model.WebBook |
|
|
|
import io.legado.app.utils.postEvent |
|
|
|
import io.legado.app.utils.postEvent |
|
|
|
import kotlinx.coroutines.Dispatchers.IO |
|
|
|
import kotlinx.coroutines.Dispatchers.IO |
|
|
|
import kotlinx.coroutines.asCoroutineDispatcher |
|
|
|
import kotlinx.coroutines.asCoroutineDispatcher |
|
|
|
|
|
|
|
import org.jetbrains.anko.toast |
|
|
|
import java.util.concurrent.Executors |
|
|
|
import java.util.concurrent.Executors |
|
|
|
|
|
|
|
|
|
|
|
class DownloadService : BaseService() { |
|
|
|
class DownloadService : BaseService() { |
|
|
@ -25,6 +27,8 @@ class DownloadService : BaseService() { |
|
|
|
private var tasks: ArrayList<Coroutine<*>> = arrayListOf() |
|
|
|
private var tasks: ArrayList<Coroutine<*>> = arrayListOf() |
|
|
|
private val handler = Handler() |
|
|
|
private val handler = Handler() |
|
|
|
private var runnable: Runnable = Runnable { upDownload() } |
|
|
|
private var runnable: Runnable = Runnable { upDownload() } |
|
|
|
|
|
|
|
private val downloadMap = hashMapOf<String, LinkedHashSet<BookChapter>>() |
|
|
|
|
|
|
|
private val finalMap = hashMapOf<String, LinkedHashSet<BookChapter>>() |
|
|
|
private var notificationContent = "正在启动下载" |
|
|
|
private var notificationContent = "正在启动下载" |
|
|
|
private val notificationBuilder by lazy { |
|
|
|
private val notificationBuilder by lazy { |
|
|
|
val builder = NotificationCompat.Builder(this, AppConst.channelIdDownload) |
|
|
|
val builder = NotificationCompat.Builder(this, AppConst.channelIdDownload) |
|
|
@ -48,7 +52,7 @@ class DownloadService : BaseService() { |
|
|
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { |
|
|
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { |
|
|
|
intent?.action?.let { action -> |
|
|
|
intent?.action?.let { action -> |
|
|
|
when (action) { |
|
|
|
when (action) { |
|
|
|
IntentAction.start -> download( |
|
|
|
IntentAction.start -> addDownloadData( |
|
|
|
intent.getStringExtra("bookUrl"), |
|
|
|
intent.getStringExtra("bookUrl"), |
|
|
|
intent.getIntExtra("start", 0), |
|
|
|
intent.getIntExtra("start", 0), |
|
|
|
intent.getIntExtra("end", 0) |
|
|
|
intent.getIntExtra("end", 0) |
|
|
@ -67,28 +71,63 @@ class DownloadService : BaseService() { |
|
|
|
postEvent(EventBus.UP_DOWNLOAD, false) |
|
|
|
postEvent(EventBus.UP_DOWNLOAD, false) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private fun download(bookUrl: String?, start: Int, end: Int) { |
|
|
|
private fun addDownloadData(bookUrl: String?, start: Int, end: Int) { |
|
|
|
if (bookUrl == null) return |
|
|
|
bookUrl ?: return |
|
|
|
val task = Coroutine.async(this) { |
|
|
|
if (downloadMap.containsKey(bookUrl)) { |
|
|
|
val book = App.db.bookDao().getBook(bookUrl) ?: return@async |
|
|
|
toast("该书已在下载列表") |
|
|
|
val bookSource = App.db.bookSourceDao().getBookSource(book.origin) ?: return@async |
|
|
|
return |
|
|
|
val webBook = WebBook(bookSource) |
|
|
|
} |
|
|
|
for (index in start..end) { |
|
|
|
execute { |
|
|
|
App.db.bookChapterDao().getChapter(bookUrl, index)?.let { chapter -> |
|
|
|
val chapterMap = downloadMap[bookUrl] ?: linkedSetOf<BookChapter>().apply { |
|
|
|
if (!BookHelp.hasContent(book, chapter)) { |
|
|
|
downloadMap[bookUrl] = this |
|
|
|
webBook.getContent(book, chapter, scope = this, context = searchPool) |
|
|
|
} |
|
|
|
.onStart { |
|
|
|
App.db.bookChapterDao().getChapterList(bookUrl, start, end).let { |
|
|
|
notificationContent = chapter.title |
|
|
|
chapterMap.addAll(it) |
|
|
|
} |
|
|
|
} |
|
|
|
.onSuccess(IO) { content -> |
|
|
|
download() |
|
|
|
content?.let { |
|
|
|
} |
|
|
|
BookHelp.saveContent(book, chapter, content) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private fun download() { |
|
|
|
|
|
|
|
val task = Coroutine.async(this, context = searchPool) { |
|
|
|
|
|
|
|
downloadMap.forEach { entry -> |
|
|
|
|
|
|
|
if (!finalMap.containsKey(entry.key)) { |
|
|
|
|
|
|
|
val book = App.db.bookDao().getBook(entry.key) ?: return@async |
|
|
|
|
|
|
|
val bookSource = |
|
|
|
|
|
|
|
App.db.bookSourceDao().getBookSource(book.origin) ?: return@async |
|
|
|
|
|
|
|
val webBook = WebBook(bookSource) |
|
|
|
|
|
|
|
entry.value.forEach { chapter -> |
|
|
|
|
|
|
|
if (!BookHelp.hasContent(book, chapter)) { |
|
|
|
|
|
|
|
webBook.getContent(book, chapter, scope = this, context = searchPool) |
|
|
|
|
|
|
|
.onStart { |
|
|
|
|
|
|
|
notificationContent = chapter.title |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
.onSuccess(IO) { content -> |
|
|
|
|
|
|
|
content?.let { |
|
|
|
|
|
|
|
BookHelp.saveContent(book, chapter, content) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
.onFinally(IO) { |
|
|
|
|
|
|
|
synchronized(this@DownloadService) { |
|
|
|
|
|
|
|
val chapterMap = |
|
|
|
|
|
|
|
finalMap[book.bookUrl] |
|
|
|
|
|
|
|
?: linkedSetOf<BookChapter>().apply { |
|
|
|
|
|
|
|
finalMap[book.bookUrl] = this |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
chapterMap.add(chapter) |
|
|
|
|
|
|
|
if (chapterMap.size == entry.value.size) { |
|
|
|
|
|
|
|
downloadMap.remove(book.bookUrl) |
|
|
|
|
|
|
|
finalMap.remove(book.bookUrl) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
tasks.add(task) |
|
|
|
tasks.add(task) |
|
|
|
task.invokeOnCompletion { |
|
|
|
task.invokeOnCompletion { |
|
|
|
tasks.remove(task) |
|
|
|
tasks.remove(task) |
|
|
|