Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2f9cba87b5 | |||
| 6ba8318b8a | |||
| 7565e51f95 | |||
| 230aec370c | |||
| 0d894d5977 | |||
| 099758f02d | |||
| e0480ce8c3 | |||
| 4cab34e06c | |||
| 3aefee3ce0 | |||
| f645440c12 | |||
| 72ac3c275c | |||
| d14cf0ccea | |||
| c2963709cd | |||
| 18d3615e6f | |||
| 326489fef3 |
@@ -3,7 +3,7 @@
|
|||||||
I acknowledge that:
|
I acknowledge that:
|
||||||
|
|
||||||
- I have updated:
|
- I have updated:
|
||||||
- To the latest version of the app (stable is v1.9.2)
|
- To the latest version of the app (stable is v1.9.4)
|
||||||
- All extensions
|
- All extensions
|
||||||
- I have tried the troubleshooting guide: https://tachiyomi.org/help/guides/troubleshooting-problems/
|
- I have tried the troubleshooting guide: https://tachiyomi.org/help/guides/troubleshooting-problems/
|
||||||
- If this is an issue with an extension, that I should be opening an issue in https://github.com/tachiyomiorg/tachiyomi-extensions
|
- If this is an issue with an extension, that I should be opening an issue in https://github.com/tachiyomiorg/tachiyomi-extensions
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ body:
|
|||||||
label: Tachiyomi version
|
label: Tachiyomi version
|
||||||
description: You can find your Tachiyomi version in **More → About**.
|
description: You can find your Tachiyomi version in **More → About**.
|
||||||
placeholder: |
|
placeholder: |
|
||||||
Example: "1.9.2"
|
Example: "1.9.4"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ body:
|
|||||||
required: true
|
required: true
|
||||||
- label: I have tried the [troubleshooting guide](https://tachiyomi.org/help/guides/troubleshooting/).
|
- label: I have tried the [troubleshooting guide](https://tachiyomi.org/help/guides/troubleshooting/).
|
||||||
required: true
|
required: true
|
||||||
- label: I have updated the app to version **[1.9.2](https://github.com/jobobby04/tachiyomisy/releases/latest)**.
|
- label: I have updated the app to version **[1.9.4](https://github.com/jobobby04/tachiyomisy/releases/latest)**.
|
||||||
required: true
|
required: true
|
||||||
- label: I have updated all installed extensions.
|
- label: I have updated all installed extensions.
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ body:
|
|||||||
required: true
|
required: true
|
||||||
- label: If this is an issue with an extension, I should be opening an issue in the [extensions repository](https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose).
|
- label: If this is an issue with an extension, I should be opening an issue in the [extensions repository](https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose).
|
||||||
required: true
|
required: true
|
||||||
- label: I have updated the app to version **[1.9.2](https://github.com/jobobby04/tachiyomisy/releases/latest)**.
|
- label: I have updated the app to version **[1.9.4](https://github.com/jobobby04/tachiyomisy/releases/latest)**.
|
||||||
required: true
|
required: true
|
||||||
- label: I will fill out all of the requested information in this form.
|
- label: I will fill out all of the requested information in this form.
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
+1
-1
@@ -30,7 +30,7 @@ Before you start, please note that the ability to use following technologies is
|
|||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
|
|
||||||
Translations are done externally via Weblate. See [our website](https://tachiyomi.org/help/contribution/#translation) for more details.
|
Translations are done externally via Weblate. See [our website](https://tachiyomi.org/docs/contribute#translation) for more details.
|
||||||
|
|
||||||
|
|
||||||
# Forks
|
# Forks
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ android {
|
|||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "eu.kanade.tachiyomi.sy"
|
applicationId = "eu.kanade.tachiyomi.sy"
|
||||||
versionCode = 49
|
versionCode = 51
|
||||||
versionName = "1.9.2"
|
versionName = "1.9.4"
|
||||||
|
|
||||||
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
|
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
|
||||||
buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"")
|
buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"")
|
||||||
|
|||||||
+1
-1
@@ -171,7 +171,7 @@ fun BrowseSourceEHentaiListItem(
|
|||||||
drawRect(overlayColor)
|
drawRect(overlayColor)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data = manga.thumbnailUrl,
|
data = manga,
|
||||||
)
|
)
|
||||||
if (manga.favorite) {
|
if (manga.favorite) {
|
||||||
BadgeGroup(
|
BadgeGroup(
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ fun MoreScreen(
|
|||||||
WarningBanner(
|
WarningBanner(
|
||||||
textRes = R.string.fdroid_warning,
|
textRes = R.string.fdroid_warning,
|
||||||
modifier = Modifier.clickable {
|
modifier = Modifier.clickable {
|
||||||
uriHandler.openUri("https://tachiyomi.org/help/faq/#how-do-i-migrate-from-the-f-droid-version")
|
uriHandler.openUri("https://tachiyomi.org/docs/faq/general#how-do-i-update-from-the-f-droid-builds")
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ object AboutScreen : Screen {
|
|||||||
item {
|
item {
|
||||||
TextPreferenceWidget(
|
TextPreferenceWidget(
|
||||||
title = stringResource(R.string.help_translate),
|
title = stringResource(R.string.help_translate),
|
||||||
onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/help/contribution/#translation") },
|
onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/docs/contribute#translation") },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,7 +143,7 @@ object AboutScreen : Screen {
|
|||||||
item {
|
item {
|
||||||
TextPreferenceWidget(
|
TextPreferenceWidget(
|
||||||
title = stringResource(R.string.privacy_policy),
|
title = stringResource(R.string.privacy_policy),
|
||||||
onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/privacy") },
|
onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/privacy/") },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -124,6 +124,12 @@ fun WebViewScreenContent(
|
|||||||
request: WebResourceRequest?,
|
request: WebResourceRequest?,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
request?.let {
|
request?.let {
|
||||||
|
// Don't attempt to open blobs as webpages
|
||||||
|
if (it.url.toString().startsWith("blob:http")) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue with request, but with custom headers
|
||||||
view?.loadUrl(it.url.toString(), headers)
|
view?.loadUrl(it.url.toString(), headers)
|
||||||
}
|
}
|
||||||
return super.shouldOverrideUrlLoading(view, request)
|
return super.shouldOverrideUrlLoading(view, request)
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ import eu.kanade.tachiyomi.util.storage.saveTo
|
|||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.Response
|
import logcat.LogPriority
|
||||||
|
import okio.Source
|
||||||
import okio.buffer
|
import okio.buffer
|
||||||
import okio.sink
|
import okio.sink
|
||||||
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -159,7 +161,7 @@ class PagePreviewCache(private val context: Context) {
|
|||||||
* @throws IOException page error.
|
* @throws IOException page error.
|
||||||
*/
|
*/
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun putImageToCache(imageUrl: String, response: Response) {
|
fun putImageToCache(imageUrl: String, source: Source) {
|
||||||
// Initialize editor (edits the values for an entry).
|
// Initialize editor (edits the values for an entry).
|
||||||
var editor: DiskLruCache.Editor? = null
|
var editor: DiskLruCache.Editor? = null
|
||||||
|
|
||||||
@@ -169,12 +171,12 @@ class PagePreviewCache(private val context: Context) {
|
|||||||
editor = diskCache.edit(key) ?: throw IOException("Unable to edit key")
|
editor = diskCache.edit(key) ?: throw IOException("Unable to edit key")
|
||||||
|
|
||||||
// Get OutputStream and write page with Okio.
|
// Get OutputStream and write page with Okio.
|
||||||
response.body.source().saveTo(editor.newOutputStream(0))
|
source.buffer().saveTo(editor.newOutputStream(0))
|
||||||
|
|
||||||
diskCache.flush()
|
diskCache.flush()
|
||||||
editor.commit()
|
editor.commit()
|
||||||
} finally {
|
} finally {
|
||||||
response.body.close()
|
source.close()
|
||||||
editor?.abortUnlessCommitted()
|
editor?.abortUnlessCommitted()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -207,6 +209,7 @@ class PagePreviewCache(private val context: Context) {
|
|||||||
// Remove file from cache.
|
// Remove file from cache.
|
||||||
diskCache.remove(key)
|
diskCache.remove(key)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
logcat(LogPriority.WARN, e) { "Failed to remove file from cache" }
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ import okhttp3.Response
|
|||||||
import okhttp3.internal.http.HTTP_NOT_MODIFIED
|
import okhttp3.internal.http.HTTP_NOT_MODIFIED
|
||||||
import okio.Path.Companion.toOkioPath
|
import okio.Path.Companion.toOkioPath
|
||||||
import okio.Source
|
import okio.Source
|
||||||
import okio.buffer
|
|
||||||
import okio.sink
|
|
||||||
import tachiyomi.core.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -39,7 +37,9 @@ import java.io.File
|
|||||||
class PagePreviewFetcher(
|
class PagePreviewFetcher(
|
||||||
private val page: PagePreview,
|
private val page: PagePreview,
|
||||||
private val options: Options,
|
private val options: Options,
|
||||||
private val pagePreviewFileLazy: Lazy<File>,
|
private val pagePreviewFile: () -> File,
|
||||||
|
private val isInCache: () -> Boolean,
|
||||||
|
private val writeToCache: (Source) -> Unit,
|
||||||
private val diskCacheKeyLazy: Lazy<String>,
|
private val diskCacheKeyLazy: Lazy<String>,
|
||||||
private val sourceLazy: Lazy<PagePreviewSource?>,
|
private val sourceLazy: Lazy<PagePreviewSource?>,
|
||||||
private val callFactoryLazy: Lazy<Call.Factory>,
|
private val callFactoryLazy: Lazy<Call.Factory>,
|
||||||
@@ -62,14 +62,14 @@ class PagePreviewFetcher(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun httpLoader(): FetchResult {
|
private suspend fun httpLoader(): FetchResult {
|
||||||
if (pagePreviewFileLazy.value.exists() && options.diskCachePolicy.readEnabled) {
|
if (isInCache() && options.diskCachePolicy.readEnabled) {
|
||||||
return fileLoader(pagePreviewFileLazy.value)
|
return fileLoader(pagePreviewFile())
|
||||||
}
|
}
|
||||||
var snapshot = readFromDiskCache()
|
var snapshot = readFromDiskCache()
|
||||||
try {
|
try {
|
||||||
// Fetch from disk cache
|
// Fetch from disk cache
|
||||||
if (snapshot != null) {
|
if (snapshot != null) {
|
||||||
val snapshotPagePreviewCache = moveSnapshotToPagePreviewCache(snapshot, pagePreviewFileLazy.value)
|
val snapshotPagePreviewCache = moveSnapshotToPagePreviewCache(snapshot)
|
||||||
if (snapshotPagePreviewCache != null) {
|
if (snapshotPagePreviewCache != null) {
|
||||||
// Read from page preview cache
|
// Read from page preview cache
|
||||||
return fileLoader(snapshotPagePreviewCache)
|
return fileLoader(snapshotPagePreviewCache)
|
||||||
@@ -88,7 +88,7 @@ class PagePreviewFetcher(
|
|||||||
val responseBody = checkNotNull(response.body) { "Null response source" }
|
val responseBody = checkNotNull(response.body) { "Null response source" }
|
||||||
try {
|
try {
|
||||||
// Read from page preview cache after page preview updated
|
// Read from page preview cache after page preview updated
|
||||||
val responsePagePreviewCache = writeResponseToPagePreviewCache(response, pagePreviewFileLazy.value)
|
val responsePagePreviewCache = writeResponseToPagePreviewCache(response)
|
||||||
if (responsePagePreviewCache != null) {
|
if (responsePagePreviewCache != null) {
|
||||||
return fileLoader(responsePagePreviewCache)
|
return fileLoader(responsePagePreviewCache)
|
||||||
}
|
}
|
||||||
@@ -153,45 +153,44 @@ class PagePreviewFetcher(
|
|||||||
return request.build()
|
return request.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun moveSnapshotToPagePreviewCache(snapshot: DiskCache.Snapshot, cacheFile: File): File? {
|
private fun moveSnapshotToPagePreviewCache(snapshot: DiskCache.Snapshot): File? {
|
||||||
return try {
|
return try {
|
||||||
diskCacheLazy.value.run {
|
diskCacheLazy.value.run {
|
||||||
fileSystem.source(snapshot.data).use { input ->
|
fileSystem.source(snapshot.data).use { input ->
|
||||||
writeSourceToPagePreviewCache(input, cacheFile)
|
writeSourceToPagePreviewCache(input)
|
||||||
}
|
}
|
||||||
remove(diskCacheKey)
|
remove(diskCacheKey)
|
||||||
}
|
}
|
||||||
cacheFile.takeIf { it.exists() }
|
return if (isInCache()) {
|
||||||
|
pagePreviewFile()
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logcat(LogPriority.ERROR, e) { "Failed to write snapshot data to page preview cache ${cacheFile.name}" }
|
logcat(LogPriority.ERROR, e) { "Failed to write snapshot data to page preview cache $diskCacheKey" }
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writeResponseToPagePreviewCache(response: Response, cacheFile: File): File? {
|
private fun writeResponseToPagePreviewCache(response: Response): File? {
|
||||||
if (!options.diskCachePolicy.writeEnabled) return null
|
if (!options.diskCachePolicy.writeEnabled) return null
|
||||||
return try {
|
return try {
|
||||||
response.peekBody(Long.MAX_VALUE).source().use { input ->
|
response.peekBody(Long.MAX_VALUE).source().use { input ->
|
||||||
writeSourceToPagePreviewCache(input, cacheFile)
|
writeSourceToPagePreviewCache(input)
|
||||||
|
}
|
||||||
|
return if (isInCache()) {
|
||||||
|
pagePreviewFile()
|
||||||
|
} else {
|
||||||
|
null
|
||||||
}
|
}
|
||||||
cacheFile.takeIf { it.exists() }
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logcat(LogPriority.ERROR, e) { "Failed to write response data to page preview cache ${cacheFile.name}" }
|
logcat(LogPriority.ERROR, e) { "Failed to write response data to page preview cache $diskCacheKey" }
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writeSourceToPagePreviewCache(input: Source, cacheFile: File) {
|
private fun writeSourceToPagePreviewCache(input: Source) {
|
||||||
cacheFile.parentFile?.mkdirs()
|
writeToCache(input)
|
||||||
cacheFile.delete()
|
|
||||||
try {
|
|
||||||
cacheFile.sink().buffer().use { output ->
|
|
||||||
output.writeAll(input)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
cacheFile.delete()
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readFromDiskCache(): DiskCache.Snapshot? {
|
private fun readFromDiskCache(): DiskCache.Snapshot? {
|
||||||
@@ -232,7 +231,9 @@ class PagePreviewFetcher(
|
|||||||
return PagePreviewFetcher(
|
return PagePreviewFetcher(
|
||||||
page = data,
|
page = data,
|
||||||
options = options,
|
options = options,
|
||||||
pagePreviewFileLazy = lazy { pagePreviewCache.getImageFile(data.imageUrl) },
|
pagePreviewFile = { pagePreviewCache.getImageFile(data.imageUrl) },
|
||||||
|
isInCache = { pagePreviewCache.isImageInCache(data.imageUrl) },
|
||||||
|
writeToCache = { pagePreviewCache.putImageToCache(data.imageUrl, it) },
|
||||||
diskCacheKeyLazy = lazy { PagePreviewKeyer().key(data, options) },
|
diskCacheKeyLazy = lazy { PagePreviewKeyer().key(data, options) },
|
||||||
sourceLazy = lazy { sourceManager.get(data.source) as? PagePreviewSource },
|
sourceLazy = lazy { sourceManager.get(data.source) as? PagePreviewSource },
|
||||||
callFactoryLazy = callFactoryLazy,
|
callFactoryLazy = callFactoryLazy,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ open class MangaImpl : Manga {
|
|||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
private val customManga: CustomMangaInfo?
|
private val customManga: CustomMangaInfo?
|
||||||
get() = getCustomMangaInfo.get(id!!)
|
get() = id?.let { getCustomMangaInfo.get(it) }
|
||||||
|
|
||||||
override var title: String
|
override var title: String
|
||||||
get() = if (favorite) {
|
get() = if (favorite) {
|
||||||
|
|||||||
@@ -340,11 +340,11 @@ class LibraryUpdateNotifier(private val context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val HELP_WARNING_URL = "https://tachiyomi.org/help/faq/#why-does-the-app-warn-about-large-bulk-updates-and-downloads"
|
const val HELP_WARNING_URL = "https://tachiyomi.org/docs/faq/library#why-am-i-warned-about-large-bulk-updates-and-downloads"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val NOTIF_MAX_CHAPTERS = 5
|
private const val NOTIF_MAX_CHAPTERS = 5
|
||||||
private const val NOTIF_TITLE_MAX_LEN = 45
|
private const val NOTIF_TITLE_MAX_LEN = 45
|
||||||
private const val NOTIF_ICON_SIZE = 192
|
private const val NOTIF_ICON_SIZE = 192
|
||||||
private const val HELP_SKIPPED_URL = "https://tachiyomi.org/help/faq/#why-does-global-update-skip-some-entries"
|
private const val HELP_SKIPPED_URL = "https://tachiyomi.org/docs/faq/library#why-is-global-update-skipping-entries"
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
|
|||||||
private const val clientId = "1aaf4cf232372708e98b5abc813d795b539c5a916dbbfe9ac61bf02a360832cc"
|
private const val clientId = "1aaf4cf232372708e98b5abc813d795b539c5a916dbbfe9ac61bf02a360832cc"
|
||||||
private const val clientSecret = "229942c742dd4cde803125d17d64501d91c0b12e14cb1e5120184d77d67024c0"
|
private const val clientSecret = "229942c742dd4cde803125d17d64501d91c0b12e14cb1e5120184d77d67024c0"
|
||||||
|
|
||||||
private const val baseUrl = "https://shikimori.me"
|
private const val baseUrl = "https://shikimori.one"
|
||||||
private const val apiUrl = "$baseUrl/api"
|
private const val apiUrl = "$baseUrl/api"
|
||||||
private const val oauthUrl = "$baseUrl/oauth/token"
|
private const val oauthUrl = "$baseUrl/oauth/token"
|
||||||
private const val loginUrl = "$baseUrl/oauth/authorize"
|
private const val loginUrl = "$baseUrl/oauth/authorize"
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ internal class AppUpdateNotifier(private val context: Context) {
|
|||||||
setContentTitle(context.getString(R.string.update_check_notification_update_available))
|
setContentTitle(context.getString(R.string.update_check_notification_update_available))
|
||||||
setContentText(context.getString(R.string.update_check_fdroid_migration_info))
|
setContentText(context.getString(R.string.update_check_fdroid_migration_info))
|
||||||
setSmallIcon(R.drawable.ic_tachi)
|
setSmallIcon(R.drawable.ic_tachi)
|
||||||
setContentIntent(NotificationHandler.openUrl(context, "https://tachiyomi.org/help/faq/#how-do-i-migrate-from-the-f-droid-version"))
|
setContentIntent(NotificationHandler.openUrl(context, "https://tachiyomi.org/docs/faq/general#how-do-i-update-from-the-f-droid-builds"))
|
||||||
}
|
}
|
||||||
notificationBuilder.show(Notifications.ID_APP_UPDATE_PROMPT)
|
notificationBuilder.show(Notifications.ID_APP_UPDATE_PROMPT)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ internal class ExtensionGithubApi {
|
|||||||
hasChangelog = it.hasChangelog == 1,
|
hasChangelog = it.hasChangelog == 1,
|
||||||
sources = it.sources?.toExtensionSources() ?: emptyList(),
|
sources = it.sources?.toExtensionSources() ?: emptyList(),
|
||||||
apkName = it.apk,
|
apkName = it.apk,
|
||||||
iconUrl = "${/* SY --> */ repoUrl /* SY <-- */}icon/${it.apk.replace(".apk", ".png")}",
|
iconUrl = "${/* SY --> */ repoUrl /* SY <-- */}icon/${it.pkg}.png",
|
||||||
// SY -->
|
// SY -->
|
||||||
repoUrl = repoUrl,
|
repoUrl = repoUrl,
|
||||||
isRepoSource = repoSource,
|
isRepoSource = repoSource,
|
||||||
|
|||||||
@@ -410,7 +410,7 @@ class LocalSource(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val ID = 0L
|
const val ID = 0L
|
||||||
const val HELP_URL = "https://tachiyomi.org/help/guides/local-manga/"
|
const val HELP_URL = "https://tachiyomi.org/docs/guides/local-source/"
|
||||||
|
|
||||||
private const val DEFAULT_COVER_NAME = "cover.jpg"
|
private const val DEFAULT_COVER_NAME = "cover.jpg"
|
||||||
private val LATEST_THRESHOLD = TimeUnit.MILLISECONDS.convert(7, TimeUnit.DAYS)
|
private val LATEST_THRESHOLD = TimeUnit.MILLISECONDS.convert(7, TimeUnit.DAYS)
|
||||||
|
|||||||
@@ -1143,18 +1143,23 @@ class EHentai(
|
|||||||
.toString(),
|
.toString(),
|
||||||
),
|
),
|
||||||
).awaitSuccess().asJsoup()
|
).awaitSuccess().asJsoup()
|
||||||
val previews = if (doc.selectFirst("div#gdo4 .ths")!!.attr("onClick").contains("inline_set=ts_l")) {
|
|
||||||
doc.body()
|
val body = doc.body()
|
||||||
.select("#gdt div a")
|
val previews = body
|
||||||
.map {
|
.select("#gdt div div")
|
||||||
PagePreviewInfo(it.text().toInt(), imageUrl = it.select("img").attr("src"))
|
.map {
|
||||||
}
|
val preview = parseNormalPreview(it)
|
||||||
} else {
|
PagePreviewInfo(preview.index, imageUrl = preview.toUrl())
|
||||||
parseNormalPreviewSet(doc)
|
}
|
||||||
.map { preview ->
|
.ifEmpty {
|
||||||
PagePreviewInfo(preview.index, imageUrl = preview.toUrl())
|
body.select("#gdt div a img")
|
||||||
}
|
.map {
|
||||||
}
|
PagePreviewInfo(
|
||||||
|
it.attr("alt").toInt(),
|
||||||
|
imageUrl = it.attr("src"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return PagePreviewPage(
|
return PagePreviewPage(
|
||||||
page = page,
|
page = page,
|
||||||
@@ -1175,37 +1180,33 @@ class EHentai(
|
|||||||
/**
|
/**
|
||||||
* Parse normal previews with regular expressions
|
* Parse normal previews with regular expressions
|
||||||
*/
|
*/
|
||||||
private fun parseNormalPreviewSet(doc: Document): List<EHentaiThumbnailPreview> {
|
private fun parseNormalPreview(element: Element): EHentaiThumbnailPreview {
|
||||||
return doc.body()
|
val index = element.selectFirst("img")!!.attr("alt").toInt()
|
||||||
.select("#gdt div div")
|
val styles = element.attr("style").split(";").mapNotNull { it.trimOrNull() }
|
||||||
.map { it.selectFirst("img")!!.attr("alt").toInt() to it.attr("style") }
|
val width = styles.first { it.startsWith("width:") }
|
||||||
.map { (index, style) ->
|
.removePrefix("width:")
|
||||||
val styles = style.split(";").mapNotNull { it.trimOrNull() }
|
.removeSuffix("px")
|
||||||
val width = styles.first { it.startsWith("width:") }
|
.toInt()
|
||||||
.removePrefix("width:")
|
|
||||||
.removeSuffix("px")
|
|
||||||
.toInt()
|
|
||||||
|
|
||||||
val height = styles.first { it.startsWith("height:") }
|
val height = styles.first { it.startsWith("height:") }
|
||||||
.removePrefix("height:")
|
.removePrefix("height:")
|
||||||
.removeSuffix("px")
|
.removeSuffix("px")
|
||||||
.toInt()
|
.toInt()
|
||||||
|
|
||||||
val background = styles.first { it.startsWith("background:") }
|
val background = styles.first { it.startsWith("background:") }
|
||||||
.removePrefix("background:")
|
.removePrefix("background:")
|
||||||
.split(" ")
|
.split(" ")
|
||||||
|
|
||||||
val url = background.first { it.startsWith("url(") }
|
val url = background.first { it.startsWith("url(") }
|
||||||
.removePrefix("url(")
|
.removePrefix("url(")
|
||||||
.removeSuffix(")")
|
.removeSuffix(")")
|
||||||
|
|
||||||
val widthOffset = background.first { it.startsWith("-") }
|
val widthOffset = background.first { it.startsWith("-") }
|
||||||
.removePrefix("-")
|
.removePrefix("-")
|
||||||
.removeSuffix("px")
|
.removeSuffix("px")
|
||||||
.toInt()
|
.toInt()
|
||||||
|
|
||||||
EHentaiThumbnailPreview(url, width, height, widthOffset, index)
|
return EHentaiThumbnailPreview(url, width, height, widthOffset, index).also(::println)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
data class EHentaiThumbnailPreview(
|
data class EHentaiThumbnailPreview(
|
||||||
val imageUrl: String,
|
val imageUrl: String,
|
||||||
|
|||||||
+1
-1
@@ -102,7 +102,7 @@ class ExtensionDetailsScreenModel(
|
|||||||
val extension = state.value.extension ?: return ""
|
val extension = state.value.extension ?: return ""
|
||||||
|
|
||||||
if (!extension.hasReadme) {
|
if (!extension.hasReadme) {
|
||||||
return "https://tachiyomi.org/help/faq/#extensions"
|
return "https://tachiyomi.org/docs/faq/browse/extensions"
|
||||||
}
|
}
|
||||||
|
|
||||||
val pkgName = extension.pkgName.substringAfter("eu.kanade.tachiyomi.extension.")
|
val pkgName = extension.pkgName.substringAfter("eu.kanade.tachiyomi.extension.")
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ class MainActivity : BaseActivity() {
|
|||||||
libraryPreferences = libraryPreferences,
|
libraryPreferences = libraryPreferences,
|
||||||
readerPreferences = Injekt.get(),
|
readerPreferences = Injekt.get(),
|
||||||
backupPreferences = Injekt.get(),
|
backupPreferences = Injekt.get(),
|
||||||
|
pagePreviewCache = Injekt.get(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ import eu.kanade.tachiyomi.util.system.toShareIntent
|
|||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import exh.md.similar.MangaDexSimilarScreen
|
import exh.md.similar.MangaDexSimilarScreen
|
||||||
import exh.pagepreview.PagePreviewScreen
|
import exh.pagepreview.PagePreviewScreen
|
||||||
|
import exh.pref.DelegateSourcePreferences
|
||||||
import exh.recs.RecommendsScreen
|
import exh.recs.RecommendsScreen
|
||||||
import exh.source.MERGED_SOURCE_ID
|
import exh.source.MERGED_SOURCE_ID
|
||||||
import exh.source.getMainSource
|
import exh.source.getMainSource
|
||||||
@@ -503,7 +504,7 @@ class MangaScreen(
|
|||||||
// AZ -->
|
// AZ -->
|
||||||
private fun openRecommends(context: Context, navigator: Navigator, source: Source?, manga: Manga) {
|
private fun openRecommends(context: Context, navigator: Navigator, source: Source?, manga: Manga) {
|
||||||
source ?: return
|
source ?: return
|
||||||
if (source.isMdBasedSource()) {
|
if (source.isMdBasedSource() && Injekt.get<DelegateSourcePreferences>().delegateSources().get()) {
|
||||||
MaterialAlertDialogBuilder(context)
|
MaterialAlertDialogBuilder(context)
|
||||||
.setTitle(R.string.az_recommends)
|
.setTitle(R.string.az_recommends)
|
||||||
.setSingleChoiceItems(
|
.setSingleChoiceItems(
|
||||||
|
|||||||
@@ -322,7 +322,7 @@ class ReaderViewModel(
|
|||||||
|
|
||||||
val context = Injekt.get<Application>()
|
val context = Injekt.get<Application>()
|
||||||
// val source = sourceManager.getOrStub(manga.source)
|
// val source = sourceManager.getOrStub(manga.source)
|
||||||
loader = ChapterLoader(context, downloadManager, downloadProvider, manga, source, /* SY --> */sourceManager, mergedReferences, mergedManga/* SY <-- */)
|
loader = ChapterLoader(context, downloadManager, downloadProvider, manga, source, /* SY --> */sourceManager, readerPreferences, mergedReferences, mergedManga/* SY <-- */)
|
||||||
|
|
||||||
loadChapter(loader!!, chapterList.first { chapterId == it.chapter.id } /* SY --> */, page/* SY <-- */)
|
loadChapter(loader!!, chapterList.first { chapterId == it.chapter.id } /* SY --> */, page/* SY <-- */)
|
||||||
Result.success(true)
|
Result.success(true)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.source.SourceManager
|
|||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.source.online.all.MergedSource
|
import eu.kanade.tachiyomi.source.online.all.MergedSource
|
||||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||||
import exh.debug.DebugFunctions.readerPrefs
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||||
import tachiyomi.core.util.lang.withIOContext
|
import tachiyomi.core.util.lang.withIOContext
|
||||||
import tachiyomi.core.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
@@ -28,6 +28,7 @@ class ChapterLoader(
|
|||||||
private val source: Source,
|
private val source: Source,
|
||||||
// SY -->
|
// SY -->
|
||||||
private val sourceManager: SourceManager,
|
private val sourceManager: SourceManager,
|
||||||
|
private val readerPrefs: ReaderPreferences,
|
||||||
private val mergedReferences: List<MergedMangaReference>,
|
private val mergedReferences: List<MergedMangaReference>,
|
||||||
private val mergedManga: Map<Long, Manga>,
|
private val mergedManga: Map<Long, Manga>,
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import eu.kanade.domain.ui.UiPreferences
|
|||||||
import eu.kanade.tachiyomi.BuildConfig
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
|
import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
|
||||||
|
import eu.kanade.tachiyomi.data.cache.PagePreviewCache
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||||
import eu.kanade.tachiyomi.data.preference.MANGA_NON_COMPLETED
|
import eu.kanade.tachiyomi.data.preference.MANGA_NON_COMPLETED
|
||||||
@@ -56,6 +57,7 @@ import kotlinx.serialization.json.JsonObject
|
|||||||
import kotlinx.serialization.json.contentOrNull
|
import kotlinx.serialization.json.contentOrNull
|
||||||
import kotlinx.serialization.json.jsonArray
|
import kotlinx.serialization.json.jsonArray
|
||||||
import kotlinx.serialization.json.jsonPrimitive
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.preference.PreferenceStore
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
import tachiyomi.core.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.data.DatabaseHandler
|
import tachiyomi.data.DatabaseHandler
|
||||||
@@ -102,6 +104,7 @@ object EXHMigrations {
|
|||||||
libraryPreferences: LibraryPreferences,
|
libraryPreferences: LibraryPreferences,
|
||||||
readerPreferences: ReaderPreferences,
|
readerPreferences: ReaderPreferences,
|
||||||
backupPreferences: BackupPreferences,
|
backupPreferences: BackupPreferences,
|
||||||
|
pagePreviewCache: PagePreviewCache,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val lastVersionCode = preferenceStore.getInt("eh_last_version_code", 0)
|
val lastVersionCode = preferenceStore.getInt("eh_last_version_code", 0)
|
||||||
val oldVersion = lastVersionCode.get()
|
val oldVersion = lastVersionCode.get()
|
||||||
@@ -515,6 +518,20 @@ object EXHMigrations {
|
|||||||
val trackManager = Injekt.get<TrackManager>()
|
val trackManager = Injekt.get<TrackManager>()
|
||||||
trackManager.mdList.logout()
|
trackManager.mdList.logout()
|
||||||
}
|
}
|
||||||
|
if (oldVersion under 51) {
|
||||||
|
pagePreviewCache.clear()
|
||||||
|
File(context.cacheDir, PagePreviewCache.PARAMETER_CACHE_DIRECTORY).listFiles()?.forEach {
|
||||||
|
if (it.name == "journal" || it.name.startsWith("journal.")) {
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
it.delete()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logcat(LogPriority.WARN, e) { "Failed to remove file from cache" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if (oldVersion under 1) { } (1 is current release version)
|
// if (oldVersion under 1) { } (1 is current release version)
|
||||||
// do stuff here when releasing changed crap
|
// do stuff here when releasing changed crap
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import eu.kanade.domain.source.service.SourcePreferences
|
|||||||
import eu.kanade.domain.ui.UiPreferences
|
import eu.kanade.domain.ui.UiPreferences
|
||||||
import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
||||||
import eu.kanade.tachiyomi.data.backup.models.Backup
|
import eu.kanade.tachiyomi.data.backup.models.Backup
|
||||||
|
import eu.kanade.tachiyomi.data.cache.PagePreviewCache
|
||||||
import eu.kanade.tachiyomi.network.NetworkPreferences
|
import eu.kanade.tachiyomi.network.NetworkPreferences
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.source.online.all.NHentai
|
import eu.kanade.tachiyomi.source.online.all.NHentai
|
||||||
@@ -57,17 +58,42 @@ object DebugFunctions {
|
|||||||
val getExhFavoriteMangaWithMetadata: GetExhFavoriteMangaWithMetadata by injectLazy()
|
val getExhFavoriteMangaWithMetadata: GetExhFavoriteMangaWithMetadata by injectLazy()
|
||||||
val getSearchMetadata: GetSearchMetadata by injectLazy()
|
val getSearchMetadata: GetSearchMetadata by injectLazy()
|
||||||
val getAllManga: GetAllManga by injectLazy()
|
val getAllManga: GetAllManga by injectLazy()
|
||||||
|
val pagePreviewCache: PagePreviewCache by injectLazy()
|
||||||
|
|
||||||
fun forceUpgradeMigration() {
|
fun forceUpgradeMigration() {
|
||||||
val lastVersionCode = prefsStore.getInt("eh_last_version_code", 0)
|
val lastVersionCode = prefsStore.getInt("eh_last_version_code", 0)
|
||||||
lastVersionCode.set(1)
|
lastVersionCode.set(1)
|
||||||
EXHMigrations.upgrade(app, prefsStore, basePrefs, uiPrefs, networkPrefs, sourcePrefs, securityPrefs, libraryPrefs, readerPrefs, backupPrefs)
|
EXHMigrations.upgrade(
|
||||||
|
context = app,
|
||||||
|
preferenceStore = prefsStore,
|
||||||
|
basePreferences = basePrefs,
|
||||||
|
uiPreferences = uiPrefs,
|
||||||
|
networkPreferences = networkPrefs,
|
||||||
|
sourcePreferences = sourcePrefs,
|
||||||
|
securityPreferences = securityPrefs,
|
||||||
|
libraryPreferences = libraryPrefs,
|
||||||
|
readerPreferences = readerPrefs,
|
||||||
|
backupPreferences = backupPrefs,
|
||||||
|
pagePreviewCache = pagePreviewCache,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun forceSetupJobs() {
|
fun forceSetupJobs() {
|
||||||
val lastVersionCode = prefsStore.getInt("eh_last_version_code", 0)
|
val lastVersionCode = prefsStore.getInt("eh_last_version_code", 0)
|
||||||
lastVersionCode.set(0)
|
lastVersionCode.set(0)
|
||||||
EXHMigrations.upgrade(app, prefsStore, basePrefs, uiPrefs, networkPrefs, sourcePrefs, securityPrefs, libraryPrefs, readerPrefs, backupPrefs)
|
EXHMigrations.upgrade(
|
||||||
|
context = app,
|
||||||
|
preferenceStore = prefsStore,
|
||||||
|
basePreferences = basePrefs,
|
||||||
|
uiPreferences = uiPrefs,
|
||||||
|
networkPreferences = networkPrefs,
|
||||||
|
sourcePreferences = sourcePrefs,
|
||||||
|
securityPreferences = securityPrefs,
|
||||||
|
libraryPreferences = libraryPrefs,
|
||||||
|
readerPreferences = readerPrefs,
|
||||||
|
backupPreferences = backupPrefs,
|
||||||
|
pagePreviewCache = pagePreviewCache,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resetAgedFlagInEXHManga() {
|
fun resetAgedFlagInEXHManga() {
|
||||||
@@ -187,7 +213,7 @@ object DebugFunctions {
|
|||||||
"""
|
"""
|
||||||
{
|
{
|
||||||
id: ${info.id},
|
id: ${info.id},
|
||||||
isPeriodic: ${j.extras["EXTRA_IS_PERIODIC"]},
|
isPeriodic: ${j.extras.getBoolean("EXTRA_IS_PERIODIC")},
|
||||||
state: ${info.state.name},
|
state: ${info.state.name},
|
||||||
tags: [
|
tags: [
|
||||||
${info.tags.joinToString(separator = ",\n ")}
|
${info.tags.joinToString(separator = ",\n ")}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ data class ChapterAttributesDto(
|
|||||||
val createdAt: String,
|
val createdAt: String,
|
||||||
val updatedAt: String,
|
val updatedAt: String,
|
||||||
val publishAt: String,
|
val publishAt: String,
|
||||||
|
val readableAt: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ class ApiMangaParser(
|
|||||||
|
|
||||||
val name = chapterName.toString()
|
val name = chapterName.toString()
|
||||||
// Convert from unix time
|
// Convert from unix time
|
||||||
val dateUpload = MdUtil.parseDate(attributes.publishAt)
|
val dateUpload = MdUtil.parseDate(attributes.readableAt)
|
||||||
|
|
||||||
val scanlatorName = networkChapter.relationships
|
val scanlatorName = networkChapter.relationships
|
||||||
.filter {
|
.filter {
|
||||||
|
|||||||
@@ -1,7 +1,19 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<changelog bulletedList="true">
|
<changelog bulletedList="true">
|
||||||
|
<changelogversion versionName="1.9.4" changeDate="Oct 29,2023">
|
||||||
|
<changelogtext>[b]Based on Tachiyomi stable 0.14.7(from 0.14.6)[/b]</changelogtext>
|
||||||
|
<changelogtext>Use ReadableAt for MangaDex dates</changelogtext>
|
||||||
|
<changelogtext>Fix E-H/Exh page previews</changelogtext>
|
||||||
|
<changelogtext>Fix page previews cache</changelogtext>
|
||||||
|
<changelogtext>Fix E-H/Exh browse thumbnails</changelogtext>
|
||||||
|
<changelogtext>Fix crash on Chinese</changelogtext>
|
||||||
|
<changelogtext>Fix Mangadex Recommendations when Delegation is off</changelogtext>
|
||||||
|
</changelogversion>
|
||||||
|
<changelogversion versionName="1.9.3" changeDate="Apr 18,2023">
|
||||||
|
<changelogtext>Hotfix for 1.9.2, fix backup restore</changelogtext>
|
||||||
|
</changelogversion>
|
||||||
<changelogversion versionName="1.9.2" changeDate="Apr 17,2023">
|
<changelogversion versionName="1.9.2" changeDate="Apr 17,2023">
|
||||||
<changelogtext>Hotfix for 1.9.1</changelogtext>
|
<changelogtext>Hotfix for 1.9.1, fix tag editing</changelogtext>
|
||||||
</changelogversion>
|
</changelogversion>
|
||||||
<changelogversion versionName="1.9.1" changeDate="Apr 16,2023">
|
<changelogversion versionName="1.9.1" changeDate="Apr 16,2023">
|
||||||
<changelogtext>[b]Based on Tachiyomi stable 0.14.6(from 0.14.3)[/b]</changelogtext>
|
<changelogtext>[b]Based on Tachiyomi stable 0.14.6(from 0.14.3)[/b]</changelogtext>
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ class NetworkPreferences(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun defaultUserAgent(): Preference<String> {
|
fun defaultUserAgent(): Preference<String> {
|
||||||
return preferenceStore.getString("default_user_agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:110.0) Gecko/20100101 Firefox/110.0")
|
return preferenceStore.getString(
|
||||||
|
"default_user_agent",
|
||||||
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,7 +135,7 @@
|
|||||||
<string name="data_saver_ignore_jpeg">忽略 JPEG 图像</string>
|
<string name="data_saver_ignore_jpeg">忽略 JPEG 图像</string>
|
||||||
<string name="data_saver_ignore_gif">忽略 Gif 动画</string>
|
<string name="data_saver_ignore_gif">忽略 Gif 动画</string>
|
||||||
<string name="data_saver_image_quality">图像质量</string>
|
<string name="data_saver_image_quality">图像质量</string>
|
||||||
<string name="data_saver_image_quality_summary">更高值意味着更高的保存的图像质量,但这意味着更大的文件大小,80% 可以很好地平衡图片质量和文件大小</string>
|
<string name="data_saver_image_quality_summary">更高值意味着更高的保存的图像质量,但这意味着更大的文件大小,80\% 可以很好地平衡图片质量和文件大小</string>
|
||||||
<string name="data_saver_image_format">压缩为 JPEG</string>
|
<string name="data_saver_image_format">压缩为 JPEG</string>
|
||||||
<string name="data_saver_image_format_summary_on">JPEG 文件的大小要比 Webp 小得多(意味着节省了更多的流量),但它也会使图像损失更多的质量。\n目前压缩为 JPEG</string>
|
<string name="data_saver_image_format_summary_on">JPEG 文件的大小要比 Webp 小得多(意味着节省了更多的流量),但它也会使图像损失更多的质量。\n目前压缩为 JPEG</string>
|
||||||
<string name="data_saver_image_format_summary_off">JPEG 文件的大小要比 Webp 小得多(意味着节省了更多的流量),但它也会使图像损失更多的质量。\n目前压缩为 Webp</string>
|
<string name="data_saver_image_format_summary_off">JPEG 文件的大小要比 Webp 小得多(意味着节省了更多的流量),但它也会使图像损失更多的质量。\n目前压缩为 Webp</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user