Skip to content

Commit 9caea50

Browse files
committed
Merge branch 'dev'
2 parents 3cda455 + e2262d6 commit 9caea50

38 files changed

+598
-335
lines changed

app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ android {
4343
minSdkVersion 26
4444
targetSdkVersion 36
4545
versionCode 130 // is updated automatically by BitRise; only used when building locally
46-
versionName '1.21.4c'
46+
versionName '1.21.5'
4747

4848
def includeObjectBoxBrowser = System.getenv("INCLUDE_OBJECTBOX_BROWSER") ?: "false"
4949
def includeLeakCanary = System.getenv("INCLUDE_LEAK_CANARY") ?: "false"

app/src/main/java/me/devsaki/hentoid/activities/IntroActivity.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import me.devsaki.hentoid.fragments.intro.SourcesIntroFragment
2020
import me.devsaki.hentoid.fragments.intro.ThemeIntroFragment
2121
import me.devsaki.hentoid.fragments.intro.WelcomeIntroFragment
2222
import me.devsaki.hentoid.util.Settings
23-
import me.devsaki.hentoid.util.applyTheme
2423

2524
/**
2625
* Welcome (Intro Slide) Activity
@@ -95,7 +94,6 @@ class IntroActivity : AppIntro2() {
9594

9695
fun setThemePrefs(pref: Int) {
9796
Settings.colorTheme = pref
98-
applyTheme()
9997
goToNextSlide(false)
10098
}
10199

app/src/main/java/me/devsaki/hentoid/activities/sources/BaseBrowserActivity.kt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,8 @@ abstract class BaseBrowserActivity : BaseActivity(), CustomWebViewClient.Browser
236236
// Handler for fetch interceptor
237237
protected var fetchHandler: BiConsumer<String, String>? = null
238238
protected var xhrHandler: BiConsumer<String, String>? = null
239-
private var jsInterceptorScript: String? = null
239+
private var fetchInterceptorScript: String? = null
240+
private var xhrInterceptorScript: String? = null
240241
private var internalCustomCss: String? = null
241242

242243

@@ -719,15 +720,15 @@ abstract class BaseBrowserActivity : BaseActivity(), CustomWebViewClient.Browser
719720

720721
// Activate fetch handler
721722
if (fetchHandler != null) {
722-
if (null == jsInterceptorScript) jsInterceptorScript =
723+
if (null == fetchInterceptorScript) fetchInterceptorScript =
723724
webClient.getJsScript(this, "fetch_override.js", null)
724-
webView.loadUrl(jsInterceptorScript!!)
725+
webView.loadUrl(fetchInterceptorScript!!)
725726
}
726727
// Activate XHR handler
727728
if (xhrHandler != null) {
728-
if (null == jsInterceptorScript) jsInterceptorScript =
729+
if (null == xhrInterceptorScript) xhrInterceptorScript =
729730
webClient.getJsScript(this, "xhr_override.js", null)
730-
webView.loadUrl(jsInterceptorScript!!)
731+
webView.loadUrl(xhrInterceptorScript!!)
731732
}
732733

733734
if (isBrowsable) {

app/src/main/java/me/devsaki/hentoid/activities/sources/HitomiActivity.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,11 @@ class HitomiActivity : BaseBrowserActivity() {
7272
"exosrv.com",
7373
"realsrv.com",
7474
"ad-provider",
75-
"adprovider"
75+
"adprovider",
76+
"exovideoslider",
77+
"adsbyexoclick",
78+
"\"ads\"",
79+
"\"adverts\""
7680
)
7781
private val REMOVABLE_ELEMENTS = arrayOf(
7882
".content div[class^=hitomi-]",

app/src/main/java/me/devsaki/hentoid/activities/sources/SimplyActivity.kt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,24 @@ class SimplyActivity : BaseBrowserActivity() {
2323
"api.simply-hentai.com/v3/[%\\w\\-]+/[%\\w\\-]+$",
2424
"api-v3.simply-hentai.com/v3/[%\\w\\-]+/[%\\w\\-]+$"
2525
)
26+
private val JS_CONTENT_BLACKLIST = arrayOf(
27+
"exoloader",
28+
//"popunder",
29+
"ad_trigger_class",
30+
"ad_popup_force",
31+
"exosrv.com",
32+
"realsrv.com",
33+
"ad-provider",
34+
"adprovider",
35+
/*
36+
"exovideoslider"
37+
"adsbyexoclick",
38+
"\"ads\"",
39+
"\"adverts\""
40+
*/
41+
)
2642
}
2743

28-
2944
override fun getStartSite(): Site {
3045
return Site.SIMPLY
3146
}
@@ -34,6 +49,7 @@ class SimplyActivity : BaseBrowserActivity() {
3449
val client = SimplyViewClient(getStartSite(), GALLERY_FILTER, this, webView)
3550
client.restrictTo(DOMAIN_FILTER)
3651
client.adBlocker.addToJsUrlWhitelist(DOMAIN_FILTER)
52+
client.addJsContentBlacklist(*JS_CONTENT_BLACKLIST)
3753
return client
3854
}
3955

app/src/main/java/me/devsaki/hentoid/adapters/ImagePagerAdapter.kt

Lines changed: 48 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import android.content.Context
55
import android.graphics.Bitmap
66
import android.graphics.Point
77
import android.net.Uri
8-
import android.os.Build
98
import android.view.LayoutInflater
109
import android.view.View
1110
import android.view.ViewGroup
@@ -53,17 +52,8 @@ import me.devsaki.hentoid.util.Settings.Value.VIEWER_ORIENTATION_VERTICAL
5352
import me.devsaki.hentoid.util.Settings.Value.VIEWER_SEPARATING_BARS_LARGE
5453
import me.devsaki.hentoid.util.Settings.Value.VIEWER_SEPARATING_BARS_MEDIUM
5554
import me.devsaki.hentoid.util.Settings.Value.VIEWER_SEPARATING_BARS_SMALL
56-
import me.devsaki.hentoid.util.file.getInputStream
5755
import me.devsaki.hentoid.util.getScreenDimensionsPx
58-
import me.devsaki.hentoid.util.image.MIME_IMAGE_AVIF
59-
import me.devsaki.hentoid.util.image.MIME_IMAGE_GIF
60-
import me.devsaki.hentoid.util.image.MIME_IMAGE_JXL
61-
import me.devsaki.hentoid.util.image.MIME_IMAGE_PNG
62-
import me.devsaki.hentoid.util.image.MIME_IMAGE_WEBP
63-
import me.devsaki.hentoid.util.image.MIME_VIDEO_MP4
6456
import me.devsaki.hentoid.util.image.getImageDimensions
65-
import me.devsaki.hentoid.util.image.getMimeTypeFromPictureBinary
66-
import me.devsaki.hentoid.util.image.isImageAnimated
6757
import me.devsaki.hentoid.util.image.needsRotating
6858
import me.devsaki.hentoid.views.ZoomableRecyclerView
6959
import me.devsaki.hentoid.widget.OnZoneTapListener
@@ -92,6 +82,7 @@ class ImagePagerAdapter(context: Context) :
9282
ListAdapter<ImageFile, ImagePagerAdapter.ImageViewHolder>(IMAGE_DIFF_CALLBACK) {
9383

9484
enum class ImageType(val value: Int) {
85+
IMG_TYPE_UNSET(-1),
9586
IMG_TYPE_OTHER(0), // PNGs, JPEGs and WEBPs -> use CustomSubsamplingScaleImageView; will fallback to Coil if animation detected
9687
IMG_TYPE_GIF(1), // Static and animated GIFs -> use Coil
9788
IMG_TYPE_APNG(2), // Animated PNGs -> use Coil
@@ -106,9 +97,6 @@ class ImagePagerAdapter(context: Context) :
10697
SSIV, IMAGEVIEW, VIDEOVIEW
10798
}
10899

109-
// Cached image types
110-
private val cachedImageTypes: MutableMap<Long, ImageType> = HashMap()
111-
112100
private val pageMinHeight = context.resources.getDimension(R.dimen.page_min_height).toInt()
113101
private val screenWidth: Int
114102
private val screenHeight: Int
@@ -181,38 +169,6 @@ class ImagePagerAdapter(context: Context) :
181169
this.itemTouchListener = itemTouchListener
182170
}
183171

184-
private fun getImageType(context: Context, img: ImageFile): ImageType {
185-
if (img.fileUri.isBlank()) return ImageType.IMG_TYPE_OTHER
186-
187-
try {
188-
getInputStream(context, img.fileUri.toUri()).use { input ->
189-
val header = ByteArray(400)
190-
if (input.read(header) > 0) {
191-
val mime = getMimeTypeFromPictureBinary(header)
192-
val isAnimated = isImageAnimated(header)
193-
if (isAnimated) {
194-
when (mime) {
195-
MIME_IMAGE_PNG -> return ImageType.IMG_TYPE_APNG
196-
MIME_IMAGE_WEBP -> return ImageType.IMG_TYPE_AWEBP
197-
MIME_IMAGE_GIF -> return ImageType.IMG_TYPE_GIF
198-
MIME_IMAGE_AVIF -> return ImageType.IMG_TYPE_AAVIF
199-
MIME_VIDEO_MP4 -> return ImageType.IMG_TYPE_VIDEO
200-
}
201-
} else {
202-
when (mime) {
203-
MIME_IMAGE_GIF -> return ImageType.IMG_TYPE_GIF
204-
MIME_IMAGE_JXL -> return ImageType.IMG_TYPE_JXL
205-
MIME_IMAGE_AVIF -> return ImageType.IMG_TYPE_AVIF
206-
}
207-
}
208-
}
209-
}
210-
} catch (e: Exception) {
211-
Timber.w(e, "Unable to open image file")
212-
}
213-
return ImageType.IMG_TYPE_OTHER
214-
}
215-
216172
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ImageViewHolder {
217173
val inflater = LayoutInflater.from(viewGroup.context)
218174
val view = inflater.inflate(R.layout.item_reader_image, viewGroup, false)
@@ -380,7 +336,6 @@ class ImagePagerAdapter(context: Context) :
380336
private var isSmoothRendering = false
381337
private var isHalfWidth = false
382338

383-
//private var isImageView = false
384339
private var activeView: ActiveView = ActiveView.SSIV
385340

386341
private var img: ImageFile? = null
@@ -411,13 +366,9 @@ class ImagePagerAdapter(context: Context) :
411366
ssiv.setIgnoreTouchEvents(isVertical || isHalfWidth)
412367

413368
val img = getImageAt(position)
414-
var imgType: ImageType = ImageType.IMG_TYPE_OTHER
415-
img?.let {
416-
imgType =
417-
if (cachedImageTypes.containsKey(it.id)) cachedImageTypes.getValue(it.id)
418-
else getImageType(rootView.context, it)
419-
}
369+
val imgType = img?.imageType ?: ImageType.IMG_TYPE_UNSET
420370

371+
Timber.d("Picture ${img?.id ?: -1} @ $position : bind $imgType")
421372
if (ImageType.IMG_TYPE_VIDEO == imgType) {
422373
setActiveView(ActiveView.VIDEOVIEW, isClickThrough = true)
423374
} else if (ImageType.IMG_TYPE_GIF == imgType || ImageType.IMG_TYPE_APNG == imgType || ImageType.IMG_TYPE_AWEBP == imgType || ImageType.IMG_TYPE_JXL == imgType || (ImageType.IMG_TYPE_AVIF == imgType) || ImageType.IMG_TYPE_AAVIF == imgType) {
@@ -453,7 +404,7 @@ class ImagePagerAdapter(context: Context) :
453404
}
454405

455406
var imageAvailable = true
456-
if (img != null && img.fileUri.isNotEmpty()) setImage(img, imgType)
407+
if (img != null && img.displayUri.isNotEmpty()) setImage(img, imgType)
457408
else imageAvailable = false
458409

459410
val isStreaming = img != null && !imageAvailable && img.status == StatusContent.ONLINE
@@ -496,10 +447,10 @@ class ImagePagerAdapter(context: Context) :
496447

497448
private fun setImage(img: ImageFile, imgType: ImageType) {
498449
this.img = img
499-
val uri = img.fileUri.toUri()
450+
val uri = img.displayUri.toUri()
500451
isLoading.set(true)
501452
noImgTxt.isVisible = false
502-
Timber.d("Picture $absoluteAdapterPosition : binding viewholder $imgType $uri")
453+
Timber.d("Picture $absoluteAdapterPosition (${img.id}) : binding viewholder $imgType $uri")
503454
when (activeView) {
504455
ActiveView.SSIV -> {
505456
Timber.d("Picture $absoluteAdapterPosition : Using SSIV")
@@ -524,7 +475,11 @@ class ImagePagerAdapter(context: Context) :
524475
}
525476

526477
ActiveView.IMAGEVIEW -> {
527-
imgView?.let { loadImageView(it, uri, imgType) }
478+
imgView?.let {
479+
it.lifecycleScope?.launch {
480+
loadImageView(it, uri, imgType)
481+
}
482+
}
528483
}
529484

530485
ActiveView.VIDEOVIEW -> {
@@ -534,47 +489,47 @@ class ImagePagerAdapter(context: Context) :
534489
Timber.d("Picture $absoluteAdapterPosition : binding viewholder END $imgType $uri")
535490
}
536491

537-
fun loadImageView(view: View, uri: Uri, imgType: ImageType) {
538-
view.lifecycleScope?.launch {
539-
val isChangeDims = when (autoRotate) {
540-
Settings.Value.READER_AUTO_ROTATE_NONE -> false
541-
else -> {
492+
suspend fun loadImageView(view: View, uri: Uri, imgType: ImageType) {
493+
val isChangeDims = when (autoRotate) {
494+
Settings.Value.READER_AUTO_ROTATE_NONE -> false
495+
else -> {
496+
withContext(Dispatchers.IO) {
542497
// Preload the pic to get its dimensions
543498
val dims = getImageDimensions(view.context, uri.toString())
544499
needsRotating(screenWidth, screenHeight, dims.x, dims.y)
545500
}
546501
}
502+
}
547503

548-
recyclerView?.let {
549-
val imgLayoutParams = view.layoutParams
550-
imgLayoutParams.width =
551-
if (isChangeDims) it.height else ViewGroup.LayoutParams.MATCH_PARENT
552-
imgLayoutParams.height =
553-
if (isChangeDims) it.width else ViewGroup.LayoutParams.MATCH_PARENT
554-
view.layoutParams = imgLayoutParams
555-
}
504+
recyclerView?.let {
505+
val imgLayoutParams = view.layoutParams
506+
imgLayoutParams.width =
507+
if (isChangeDims) it.height else ViewGroup.LayoutParams.MATCH_PARENT
508+
imgLayoutParams.height =
509+
if (isChangeDims) it.width else ViewGroup.LayoutParams.MATCH_PARENT
510+
view.layoutParams = imgLayoutParams
511+
}
556512

557-
Timber.d("Picture $absoluteAdapterPosition : Using Coil")
558-
imageView.scaleType = scaleType
559-
560-
// Custom loader to handle JXL and AVIF
561-
// (doesn't support Hardware bitmaps : https://github.com/awxkee/jxl-coder-coil/issues/7)
562-
view.context.let { ctx ->
563-
val imageLoader = SingletonImageLoader.get(ctx)
564-
val request = ImageRequest.Builder(ctx)
565-
.data(uri)
566-
.diskCacheKey(uri.toString())
567-
.memoryCacheKey(uri.toString())
568-
.target(imageView)
569-
.allowHardware(imgType != ImageType.IMG_TYPE_JXL && imgType != ImageType.IMG_TYPE_AVIF)
570-
.listener(
571-
onError = { _, err -> onCoilLoadFailed(err) },
572-
onSuccess = { _, res -> onCoilLoadSuccess(res) }
573-
)
574-
.allowConversionToBitmap(false)
575-
imageLoader.enqueue(request.build())
576-
}
577-
} // Lifecyclescope
513+
Timber.d("Picture $absoluteAdapterPosition : Using Coil")
514+
imageView.scaleType = scaleType
515+
516+
// Custom loader to handle JXL and AVIF
517+
// (doesn't support Hardware bitmaps : https://github.com/awxkee/jxl-coder-coil/issues/7)
518+
view.context.let { ctx ->
519+
val imageLoader = SingletonImageLoader.get(ctx)
520+
val request = ImageRequest.Builder(ctx)
521+
.data(uri)
522+
.diskCacheKey(uri.toString())
523+
.memoryCacheKey(uri.toString())
524+
.target(imageView)
525+
.allowHardware(imgType != ImageType.IMG_TYPE_JXL && imgType != ImageType.IMG_TYPE_AVIF)
526+
.listener(
527+
onError = { _, err -> onCoilLoadFailed(err) },
528+
onSuccess = { _, res -> onCoilLoadSuccess(res) }
529+
)
530+
.allowConversionToBitmap(false)
531+
imageLoader.enqueue(request.build())
532+
}
578533
}
579534

580535
fun loadVideoView(uri: Uri) {
@@ -799,14 +754,12 @@ class ImagePagerAdapter(context: Context) :
799754
override fun onImageLoadError(e: Throwable) {
800755
Timber.d(
801756
e,
802-
"Picture %d : SSIV loading failed: %s",
803-
absoluteAdapterPosition,
804-
img!!.fileUri
757+
"Picture $absoluteAdapterPosition : SSIV loading failed: ${img?.displayUri ?: ""}",
805758
)
806759
}
807760

808761
override fun onTileLoadError(e: Throwable) {
809-
Timber.d(e, "Picture %d : tileLoad error", absoluteAdapterPosition)
762+
Timber.d(e, "Picture $absoluteAdapterPosition : tileLoad error")
810763
}
811764

812765
override fun onPreviewReleased() {
@@ -817,9 +770,7 @@ class ImagePagerAdapter(context: Context) :
817770
private fun onCoilLoadFailed(err: ErrorResult) {
818771
Timber.d(
819772
err.throwable,
820-
"Picture %d : Coil loading failed : %s",
821-
absoluteAdapterPosition,
822-
img!!.fileUri
773+
"Picture $absoluteAdapterPosition : Coil loading failed : ${img?.displayUri ?: ""}"
823774
)
824775
if (activeView == ActiveView.IMAGEVIEW) noImgTxt.visibility = View.VISIBLE
825776
isLoading.set(false)

app/src/main/java/me/devsaki/hentoid/database/domains/Content.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import me.devsaki.hentoid.util.file.getExtension
5656
import me.devsaki.hentoid.util.file.isSupportedArchive
5757
import me.devsaki.hentoid.util.formatAuthor
5858
import me.devsaki.hentoid.util.hash64
59+
import me.devsaki.hentoid.util.image.isSupportedImage
5960
import me.devsaki.hentoid.util.isNumeric
6061
import me.devsaki.hentoid.util.jsonToObject
6162
import me.devsaki.hentoid.util.network.UriParts
@@ -533,11 +534,17 @@ data class Content(
533534
if (images.isEmpty()) {
534535
val makeupCover = fromImageUrl(0, coverImageUrl, StatusContent.ONLINE, 1)
535536
makeupCover.imageHash = Long.MIN_VALUE // Makeup cover is unhashable
537+
makeupCover.isCover = true
536538
return makeupCover
537539
}
538540
for (img in images) if (img.isCover) return img
539-
// If nothing found, get 1st page as cover
540-
return imageList.first()
541+
542+
// If nothing found, get 1st supported image as cover
543+
val makeupCover =
544+
imageList.firstOrNull { isSupportedImage(UriParts(it.fileUri).fileNameFull) }
545+
?: ImageFile()
546+
makeupCover.isCover = true
547+
return makeupCover
541548
}
542549

543550
val errorList: List<ErrorRecord>

0 commit comments

Comments
 (0)