|
|
@ -17,7 +17,6 @@ import kotlinx.coroutines.CoroutineScope |
|
|
|
import java.text.SimpleDateFormat |
|
|
|
import java.text.SimpleDateFormat |
|
|
|
import java.util.* |
|
|
|
import java.util.* |
|
|
|
import java.util.concurrent.ConcurrentHashMap |
|
|
|
import java.util.concurrent.ConcurrentHashMap |
|
|
|
import java.util.concurrent.CopyOnWriteArraySet |
|
|
|
|
|
|
|
import kotlin.coroutines.CoroutineContext |
|
|
|
import kotlin.coroutines.CoroutineContext |
|
|
|
|
|
|
|
|
|
|
|
class CacheBook(val bookSource: BookSource, val book: Book) { |
|
|
|
class CacheBook(val bookSource: BookSource, val book: Book) { |
|
|
@ -117,63 +116,79 @@ class CacheBook(val bookSource: BookSource, val book: Book) { |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
val waitDownloadSet = CopyOnWriteArraySet<Int>() |
|
|
|
val waitDownloadSet = hashSetOf<Int>() |
|
|
|
val onDownloadSet = CopyOnWriteArraySet<Int>() |
|
|
|
val onDownloadSet = hashSetOf<Int>() |
|
|
|
val successDownloadSet = CopyOnWriteArraySet<Int>() |
|
|
|
val successDownloadSet = hashSetOf<Int>() |
|
|
|
|
|
|
|
|
|
|
|
fun addDownload(start: Int, end: Int) { |
|
|
|
fun addDownload(start: Int, end: Int) { |
|
|
|
for (i in start..end) { |
|
|
|
synchronized(this) { |
|
|
|
waitDownloadSet.add(i) |
|
|
|
for (i in start..end) { |
|
|
|
|
|
|
|
waitDownloadSet.add(i) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fun isRun(): Boolean { |
|
|
|
fun isRun(): Boolean { |
|
|
|
return waitDownloadSet.size > 0 || onDownloadSet.size > 0 |
|
|
|
return synchronized(this) { |
|
|
|
|
|
|
|
waitDownloadSet.size > 0 || onDownloadSet.size > 0 |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Synchronized |
|
|
|
private fun onSuccess(index: Int) { |
|
|
|
fun download(scope: CoroutineScope, context: CoroutineContext): Boolean { |
|
|
|
synchronized(this) { |
|
|
|
val chapterIndex = waitDownloadSet.firstOrNull() ?: return false |
|
|
|
onDownloadSet.remove(index) |
|
|
|
if (onDownloadSet.contains(chapterIndex)) { |
|
|
|
successDownloadSet.add(index) |
|
|
|
waitDownloadSet.remove(chapterIndex) |
|
|
|
|
|
|
|
return download(scope, context) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
val chapter = appDb.bookChapterDao.getChapter(book.bookUrl, chapterIndex) ?: let { |
|
|
|
} |
|
|
|
waitDownloadSet.remove(chapterIndex) |
|
|
|
|
|
|
|
return download(scope, context) |
|
|
|
private fun onErrorOrCancel(index: Int) { |
|
|
|
|
|
|
|
synchronized(this) { |
|
|
|
|
|
|
|
onDownloadSet.remove(index) |
|
|
|
|
|
|
|
waitDownloadSet.add(index) |
|
|
|
} |
|
|
|
} |
|
|
|
if (BookHelp.hasContent(book, chapter)) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fun download(scope: CoroutineScope, context: CoroutineContext): Boolean { |
|
|
|
|
|
|
|
synchronized(this) { |
|
|
|
|
|
|
|
val chapterIndex = waitDownloadSet.firstOrNull() ?: return false |
|
|
|
|
|
|
|
if (onDownloadSet.contains(chapterIndex)) { |
|
|
|
|
|
|
|
waitDownloadSet.remove(chapterIndex) |
|
|
|
|
|
|
|
return download(scope, context) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
val chapter = appDb.bookChapterDao.getChapter(book.bookUrl, chapterIndex) ?: let { |
|
|
|
|
|
|
|
waitDownloadSet.remove(chapterIndex) |
|
|
|
|
|
|
|
return download(scope, context) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (BookHelp.hasContent(book, chapter)) { |
|
|
|
|
|
|
|
waitDownloadSet.remove(chapterIndex) |
|
|
|
|
|
|
|
return download(scope, context) |
|
|
|
|
|
|
|
} |
|
|
|
waitDownloadSet.remove(chapterIndex) |
|
|
|
waitDownloadSet.remove(chapterIndex) |
|
|
|
return download(scope, context) |
|
|
|
onDownloadSet.add(chapterIndex) |
|
|
|
} |
|
|
|
WebBook.getContent( |
|
|
|
waitDownloadSet.remove(chapterIndex) |
|
|
|
scope, |
|
|
|
onDownloadSet.add(chapterIndex) |
|
|
|
bookSource, |
|
|
|
WebBook.getContent( |
|
|
|
book, |
|
|
|
scope, |
|
|
|
chapter, |
|
|
|
bookSource, |
|
|
|
context = context |
|
|
|
book, |
|
|
|
).onSuccess { content -> |
|
|
|
chapter, |
|
|
|
onSuccess(chapterIndex) |
|
|
|
context = context |
|
|
|
addLog("${book.name}-${chapter.title} getContentSuccess") |
|
|
|
).onSuccess { content -> |
|
|
|
downloadFinish(chapter, content.ifBlank { "No content" }) |
|
|
|
onDownloadSet.remove(chapterIndex) |
|
|
|
}.onError { |
|
|
|
successDownloadSet.add(chapterIndex) |
|
|
|
onErrorOrCancel(chapterIndex) |
|
|
|
addLog("${book.name}-${chapter.title} getContentSuccess") |
|
|
|
print(it.localizedMessage) |
|
|
|
downloadFinish(chapter, content.ifBlank { "No content" }) |
|
|
|
addLog("${book.name}-${chapter.title} getContentError${it.localizedMessage}") |
|
|
|
}.onError { |
|
|
|
downloadFinish(chapter, it.localizedMessage ?: "download error") |
|
|
|
onDownloadSet.remove(chapterIndex) |
|
|
|
}.onCancel { |
|
|
|
waitDownloadSet.add(chapterIndex) |
|
|
|
onErrorOrCancel(chapterIndex) |
|
|
|
print(it.localizedMessage) |
|
|
|
}.onFinally { |
|
|
|
addLog("${book.name}-${chapter.title} getContentError${it.localizedMessage}") |
|
|
|
if (waitDownloadSet.isEmpty() && onDownloadSet.isEmpty()) { |
|
|
|
downloadFinish(chapter, it.localizedMessage ?: "download error") |
|
|
|
postEvent(EventBus.UP_DOWNLOAD, "") |
|
|
|
}.onCancel { |
|
|
|
} |
|
|
|
onDownloadSet.remove(chapterIndex) |
|
|
|
|
|
|
|
waitDownloadSet.add(chapterIndex) |
|
|
|
|
|
|
|
}.onFinally { |
|
|
|
|
|
|
|
if (waitDownloadSet.isEmpty() && onDownloadSet.isEmpty()) { |
|
|
|
|
|
|
|
postEvent(EventBus.UP_DOWNLOAD, "") |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return true |
|
|
|
} |
|
|
|
} |
|
|
|
return true |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Synchronized |
|
|
|
@Synchronized |
|
|
@ -182,19 +197,27 @@ class CacheBook(val bookSource: BookSource, val book: Book) { |
|
|
|
chapter: BookChapter, |
|
|
|
chapter: BookChapter, |
|
|
|
resetPageOffset: Boolean = false |
|
|
|
resetPageOffset: Boolean = false |
|
|
|
) { |
|
|
|
) { |
|
|
|
if (onDownloadSet.contains(chapter.index)) { |
|
|
|
synchronized(this) { |
|
|
|
return |
|
|
|
if (onDownloadSet.contains(chapter.index)) { |
|
|
|
} |
|
|
|
return |
|
|
|
onDownloadSet.add(chapter.index) |
|
|
|
|
|
|
|
WebBook.getContent(scope, bookSource, book, chapter) |
|
|
|
|
|
|
|
.onSuccess { content -> |
|
|
|
|
|
|
|
downloadFinish(chapter, content.ifBlank { "No content" }, resetPageOffset) |
|
|
|
|
|
|
|
}.onError { |
|
|
|
|
|
|
|
downloadFinish(chapter, it.localizedMessage ?: "download error", resetPageOffset) |
|
|
|
|
|
|
|
}.onFinally { |
|
|
|
|
|
|
|
onDownloadSet.remove(chapter.index) |
|
|
|
|
|
|
|
ReadBook.removeLoading(chapter.index) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
onDownloadSet.add(chapter.index) |
|
|
|
|
|
|
|
WebBook.getContent(scope, bookSource, book, chapter) |
|
|
|
|
|
|
|
.onSuccess { content -> |
|
|
|
|
|
|
|
downloadFinish(chapter, content.ifBlank { "No content" }, resetPageOffset) |
|
|
|
|
|
|
|
}.onError { |
|
|
|
|
|
|
|
downloadFinish( |
|
|
|
|
|
|
|
chapter, |
|
|
|
|
|
|
|
it.localizedMessage ?: "download error", |
|
|
|
|
|
|
|
resetPageOffset |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
}.onFinally { |
|
|
|
|
|
|
|
synchronized(this) { |
|
|
|
|
|
|
|
onDownloadSet.remove(chapter.index) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
ReadBook.removeLoading(chapter.index) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private fun downloadFinish( |
|
|
|
private fun downloadFinish( |
|
|
|