Drop torrent download in favor of magnet links

This commit is contained in:
FooIbar committed 2024-10-12 15:26:37 +08:00
1 parent 49edbb8185
commit e485d79bb1
10 files changed
+85 -35

No files matched your search

@@ -33,6 +33,8 @@ object EhCookieStore : CookiesStorage {
)
}
fun getUserId() = getCookies(EhUrl.HOST_E)?.get(KEY_IPB_MEMBER_ID)
fun getIdentityCookies(): List<Pair<String, String?>> {
val eCookies = getCookies(EhUrl.HOST_E)
val exCookies = getCookies(EhUrl.HOST_EX)
@@ -48,8 +50,6 @@ object EhCookieStore : CookiesStorage {
fun flush() = manager.flush()
fun getCookieHeader(url: String): String? = manager.getCookie(url)
// See https://github.com/Ehviewer-Overhauled/Ehviewer/issues/873
override suspend fun addCookie(requestUrl: Url, cookie: Cookie) {
if (cookie.name != KEY_UTMP_NAME) {
@@ -180,6 +180,11 @@ object EhEngine {
return ehRequest(url, referer).fetchUsingAsByteBuffer(TorrentParser::parse)
}
suspend fun getTorrentKey() = EhCookieStore.getUserId()?.let { id ->
val key = ehRequest(EhUrl.URL_HOME).fetchUsingAsText(HomeParser::parseTorrentKey)
"${id}x$key"
}
suspend fun getArchiveList(url: String, gid: Long, token: String): ArchiveParser.Result {
val funds = if (EhUtils.isExHentai) getFunds() else null
return ehRequest(url, EhUrl.getGalleryDetailUrl(gid, token))
@@ -133,6 +133,11 @@ object EhUrl {
}.buildString()
fun getTagDefinitionUrl(tag: String) = "https://ehwiki.org/wiki/" + tag.replace(' ', '_')
fun getTrackerUrl(gid: Long, key: String?) = ehUrl(
path = listOfNotNull("$gid", key, "announce"),
host = "ehtracker.org",
).buildString()
}
inline fun ehUrl(path: String? = null, host: String = EhUrl.domain, builder: ParametersBuilder.() -> Unit) = ehUrl(
@@ -8,7 +8,8 @@ import kotlinx.parcelize.Parcelize
import kotlinx.serialization.Serializable
object HomeParser {
private val PATTERN_FUNDS = Regex("Available: ([\\d,]+) Credits.*Available: ([\\d,]+) kGP", RegexOption.DOT_MATCHES_ALL)
private val TorrentKeyRegex = Regex("Your current key is: <[^>]*>([^<]*)<")
private val FundsRegex = Regex("Available: ([\\d,]+) Credits.*Available: ([\\d,]+) kGP", RegexOption.DOT_MATCHES_ALL)
private const val INSUFFICIENT_FUNDS = "Insufficient funds."
fun parse(body: ByteBuffer) = runCatching {
@@ -21,8 +22,11 @@ object HomeParser {
}
}
fun parseTorrentKey(body: String) = TorrentKeyRegex.find(body)?.run { groupValues[1] }
?: throw ParseException("Parse torrent key error")
fun parseFunds(body: String): Funds {
PATTERN_FUNDS.find(body)?.groupValues?.run {
FundsRegex.find(body)?.groupValues?.run {
val fundsC = ParserUtils.parseInt(get(1), 0)
val fundsGP = ParserUtils.parseInt(get(2), 0) * 1000
return Funds("%,d+".format(fundsGP), "%,d".format(fundsC))
@@ -0,0 +1,42 @@
package com.hippo.ehviewer.icons.filled
import androidx.compose.foundation.Image
import androidx.compose.material.icons.materialIcon
import androidx.compose.material.icons.materialPath
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.hippo.ehviewer.icons.EhIcons
import com.hippo.ehviewer.util.unsafeLazy
val EhIcons.Filled.Magnet by unsafeLazy {
materialIcon(name = "Magnet") {
materialPath {
moveTo(3.0F, 7.0F)
verticalLineTo(13.0F)
arcTo(9.0F, 9.0F, 0.0F, false, false, 12.0F, 22.0F)
arcTo(9.0F, 9.0F, 0.0F, false, false, 21.0F, 13.0F)
verticalLineTo(7.0F)
horizontalLineTo(17.0F)
verticalLineTo(13.0F)
arcTo(5.0F, 5.0F, 0.0F, false, true, 12.0F, 18.0F)
arcTo(5.0F, 5.0F, 0.0F, false, true, 7.0F, 13.0F)
verticalLineTo(7.0F)
moveTo(17.0F, 5.0F)
horizontalLineTo(21.0F)
verticalLineTo(2.0F)
horizontalLineTo(17.0F)
moveTo(3.0F, 5.0F)
horizontalLineTo(7.0F)
verticalLineTo(2.0F)
horizontalLineTo(3.0F)
close()
}
}
}
@Preview
@Composable
@Suppress("UnusedPrivateMember")
private fun IconMagnetPreview() {
Image(imageVector = EhIcons.Default.Magnet, contentDescription = null)
}
@@ -1,8 +1,9 @@
package com.hippo.ehviewer.ui.screen
import android.Manifest
import android.content.ActivityNotFoundException
import android.content.Context
import android.os.Environment
import android.content.Intent
import android.text.TextUtils.TruncateAt.END
import androidx.annotation.StringRes
import androidx.compose.animation.SharedTransitionScope
@@ -29,7 +30,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ImageSearch
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.filled.SwapVerticalCircle
import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.FilledTonalButton
@@ -68,10 +68,10 @@ import androidx.paging.compose.itemKey
import androidx.window.core.layout.WindowWidthSizeClass
import arrow.core.partially1
import arrow.fx.coroutines.parMap
import arrow.fx.coroutines.parZip
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhCookieStore
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.EhFilter.remember
import com.hippo.ehviewer.client.EhUrl
@@ -92,6 +92,8 @@ import com.hippo.ehviewer.dao.DownloadInfo
import com.hippo.ehviewer.dao.Filter
import com.hippo.ehviewer.dao.FilterMode
import com.hippo.ehviewer.download.DownloadManager
import com.hippo.ehviewer.icons.EhIcons
import com.hippo.ehviewer.icons.filled.Magnet
import com.hippo.ehviewer.ktbuilder.imageRequest
import com.hippo.ehviewer.ktbuilder.launchIn
import com.hippo.ehviewer.ui.GalleryInfoBottomSheet
@@ -126,11 +128,10 @@ import com.hippo.ehviewer.ui.tools.getClippedRefreshKey
import com.hippo.ehviewer.ui.tools.getLimit
import com.hippo.ehviewer.ui.tools.getOffset
import com.hippo.ehviewer.ui.tools.rememberInVM
import com.hippo.ehviewer.util.AppConfig
import com.hippo.ehviewer.util.FavouriteStatusRouter
import com.hippo.ehviewer.util.FileUtils
import com.hippo.ehviewer.util.addTextToClipboard
import com.hippo.ehviewer.util.bgWork
import com.hippo.ehviewer.util.displayString
import com.hippo.ehviewer.util.flattenForEach
import com.hippo.ehviewer.util.isAtLeastQ
import com.hippo.ehviewer.util.requestPermission
@@ -140,6 +141,7 @@ import eu.kanade.tachiyomi.util.lang.launchUI
import eu.kanade.tachiyomi.util.lang.withIOContext
import eu.kanade.tachiyomi.util.lang.withUIContext
import eu.kanade.tachiyomi.util.system.logcat
import io.ktor.http.encodeURLParameter
import kotlin.math.roundToInt
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
@@ -148,7 +150,6 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import moe.tarsin.coroutines.runSuspendCatching
import splitties.systemservices.downloadManager
context(CoroutineScope, DestinationsNavigator, DialogState, MainActivity, SnackbarHostState, SharedTransitionScope, TransitionsVisibilityScope)
@Composable
@@ -542,16 +543,18 @@ fun BelowHeader(galleryDetail: GalleryDetail) {
)
val torrentText = stringResource(R.string.torrent_count, galleryDetail.torrentCount)
val permissionDenied = stringResource(R.string.permission_denied)
val downloadTorrentFailed = stringResource(R.string.download_torrent_failure)
val downloadTorrentStarted = stringResource(R.string.download_torrent_started)
val noTorrents = stringResource(R.string.no_torrents)
val torrentResult = remember(galleryDetail) {
async(Dispatchers.IO + Job(), CoroutineStart.LAZY) {
EhEngine.getTorrentList(galleryDetail.torrentUrl!!, galleryDetail.gid, galleryDetail.token)
parZip(
{ EhEngine.getTorrentList(galleryDetail.torrentUrl!!, galleryDetail.gid, galleryDetail.token) },
{ EhEngine.getTorrentKey() },
{ list, key -> list to key },
)
}
}
suspend fun showTorrentDialog() {
val torrentList = bgWork { torrentResult.await() }
val (torrentList, key) = bgWork { torrentResult.await() }
if (torrentList.isEmpty()) {
showSnackbar(noTorrents)
} else {
@@ -561,21 +564,20 @@ fun BelowHeader(galleryDetail: GalleryDetail) {
onItemClick = { dismissWith(it) },
)
}
val url = selected.url
val name = "${selected.name}.torrent"
val r = android.app.DownloadManager.Request(url.toUri())
r.setDestinationInExternalPublicDir(
Environment.DIRECTORY_DOWNLOADS,
AppConfig.APP_DIRNAME + "/" + FileUtils.sanitizeFilename(name),
)
r.setNotificationVisibility(android.app.DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
EhCookieStore.getCookieHeader(url)?.let { r.addRequestHeader("Cookie", it) }
downloadManager.enqueue(r)
showSnackbar(downloadTorrentStarted)
val hash = selected.url.dropLast(8).takeLast(40)
val name = selected.name.encodeURLParameter()
val tracker = EhUrl.getTrackerUrl(galleryDetail.gid, key).encodeURLParameter()
val link = "magnet:?xt=urn:btih:$hash&dn=$name&tr=$tracker"
val intent = Intent(Intent.ACTION_VIEW, link.toUri())
try {
startActivity(intent)
} catch (_: ActivityNotFoundException) {
withUIContext { addTextToClipboard(link, true) }
}
}
}
EhIconButton(
icon = Icons.Default.SwapVerticalCircle,
icon = EhIcons.Default.Magnet,
text = torrentText,
onClick = {
launchIO {
@@ -585,8 +587,7 @@ fun BelowHeader(galleryDetail: GalleryDetail) {
runSuspendCatching {
showTorrentDialog()
}.onFailure {
logcat(it)
showSnackbar(downloadTorrentFailed)
showSnackbar(it.displayString())
}
} else {
showSnackbar(permissionDenied)
@@ -60,7 +60,6 @@
<string name="tag_vote_up">Stem opp</string>
<string name="pref_grayscale">Gråskala</string>
<string name="action_share">Del</string>
<string name="download_torrent_started">Nedlasting av torrent startet</string>
<string name="filter_the_tag">Blokker etiketten «%s»\?</string>
<string name="rating9">Underbar</string>
<string name="error_invalid_url">Ugyldig nettadresse</string>
@@ -126,8 +126,6 @@
<string name="rate_successfully">评分成功</string>
<string name="rate_failed">评分失败</string>
<string name="no_torrents">没有种子</string>
<string name="download_torrent_started">开始下载种子</string>
<string name="download_torrent_failure">无法下载种子</string>
<string name="torrents">种子</string>
<string name="not_favorited">未收藏</string>
<string name="add_favorites_dialog_title">添加收藏</string>
@@ -126,8 +126,6 @@
<string name="rate_successfully">評分成功</string>
<string name="rate_failed">評分失敗</string>
<string name="no_torrents">沒有種子</string>
<string name="download_torrent_started">開始下載種子</string>
<string name="download_torrent_failure">無法下載種子</string>
<string name="torrents">種子</string>
<string name="not_favorited">未收藏</string>
<string name="add_favorites_dialog_title">新增到收藏裡</string>
-2
View File
@@ -142,8 +142,6 @@
<string name="rate_successfully">Rate successfully</string>
<string name="rate_failed">Rate failed</string>
<string name="no_torrents">No torrents</string>
<string name="download_torrent_started">Torrent download started</string>
<string name="download_torrent_failure">Failed to download torrent</string>
<string name="torrents">Torrents</string>
<string name="not_favorited">Not favorited</string>
<string name="add_favorites_dialog_title">Add to favorites</string>