From 068b272b5eacbf1a0275db2a530b185c43c014ab Mon Sep 17 00:00:00 2001 From: Majjo <90888719+NoxRare@users.noreply.github.com> Date: Sat, 18 Apr 2026 15:17:12 +0200 Subject: [PATCH] fix: skip overlay merge for stories, highlights, and spotlight --- .../impl/downloader/MediaDownloader.kt | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/core/src/main/kotlin/me/eternal/purrfectsnap/core/features/impl/downloader/MediaDownloader.kt b/core/src/main/kotlin/me/eternal/purrfectsnap/core/features/impl/downloader/MediaDownloader.kt index 9302bba7..3a9e4360 100644 --- a/core/src/main/kotlin/me/eternal/purrfectsnap/core/features/impl/downloader/MediaDownloader.kt +++ b/core/src/main/kotlin/me/eternal/purrfectsnap/core/features/impl/downloader/MediaDownloader.kt @@ -425,7 +425,7 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp } } - private suspend fun downloadOperaMedia(downloadManagerClient: DownloadManagerClient, mediaInfoMap: Map, paramMap: ParamMap) { + private suspend fun downloadOperaMedia(downloadManagerClient: DownloadManagerClient, mediaInfoMap: Map, paramMap: ParamMap, downloadSource: MediaDownloadSource) { val modCtx = this@MediaDownloader.context if (mediaInfoMap.isEmpty()) return paramMap["SNAP_ID"]?.toString()?.let { snapId -> @@ -439,6 +439,17 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp } val originalMediaRef = handleLocalReferences(mediaInfoMap[SplitMediaAssetType.ORIGINAL]!!.uri) mediaInfoMap[SplitMediaAssetType.OVERLAY]?.let { overlay -> + // Skip overlay merging for all story types + if (downloadSource == MediaDownloadSource.PUBLIC_STORY || + downloadSource == MediaDownloadSource.STORY || + downloadSource == MediaDownloadSource.SPOTLIGHT) { + downloadManagerClient.downloadSingleMedia( + originalMediaRef, + DownloadMediaType.fromUri(Uri.parse(originalMediaRef)), + mediaInfoMap[SplitMediaAssetType.ORIGINAL]!!.encryption?.toKeyPair() + ) + return + } val overlayRef = handleLocalReferences(overlay.uri) downloadManagerClient.downloadMediaWithOverlay( InputMedia(originalMediaRef, DownloadMediaType.fromUri(Uri.parse(originalMediaRef)), mediaInfoMap[SplitMediaAssetType.ORIGINAL]!!.encryption?.toKeyPair()), @@ -460,23 +471,23 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp val msg = modCtx.database.getConversationMessageFromId(messageContext.clientMessageId) ?: return@let if (!forceDownload && (!canUseRule(msg.clientConversationId!!) || (modCtx.config.downloader.preventSelfAutoDownload.get() && msg.senderId == modCtx.database.myUserId))) return@let val author = modCtx.database.getFriendInfo(msg.senderId!!) ?: return@let - downloadOperaMedia(provideDownloadManagerClient("${msg.clientConversationId}${msg.senderId}${msg.serverMessageId}", author.usernameForSorting!!, msg.creationTimestamp, MediaDownloadSource.CHAT_MEDIA, author, forceAllowDuplicate, isBatch), mediaInfoMap, paramMap) + downloadOperaMedia(provideDownloadManagerClient("${msg.clientConversationId}${msg.senderId}${msg.serverMessageId}", author.usernameForSorting!!, msg.creationTimestamp, MediaDownloadSource.CHAT_MEDIA, author, forceAllowDuplicate, isBatch), mediaInfoMap, paramMap, MediaDownloadSource.CHAT_MEDIA) return } paramMap["PLAYLIST_V2_GROUP"]?.takeIf { forceDownload || shouldAutoDownload("friend_stories") }?.let { val storyUserId = paramMap["TOPIC_SNAP_CREATOR_USER_ID"]?.toString() ?: paramMap["PLAYABLE_STORY_SNAP_RECORD"]?.toString()?.substringAfter("userId=")?.substringBefore(",") val author = modCtx.database.getFriendInfo(storyUserId ?: modCtx.database.myUserId) ?: return@let if (!forceDownload && ((modCtx.config.downloader.preventSelfAutoDownload.get() && author.userId == modCtx.database.myUserId) || !canUseRule(author.userId!!))) return@let - downloadOperaMedia(provideDownloadManagerClient(paramMap["MEDIA_ID"].toString(), author.usernameForSorting!!, null, MediaDownloadSource.STORY, author, forceAllowDuplicate, isBatch), mediaInfoMap, paramMap) + downloadOperaMedia(provideDownloadManagerClient(paramMap["MEDIA_ID"].toString(), author.usernameForSorting!!, null, MediaDownloadSource.STORY, author, forceAllowDuplicate, isBatch), mediaInfoMap, paramMap, MediaDownloadSource.STORY) return } val snapSource = paramMap["SNAP_SOURCE"].toString() if (snapSource == "SINGLE_SNAP_STORY" && (forceDownload || shouldAutoDownload("spotlight"))) { - downloadOperaMedia(provideDownloadManagerClient(paramMap["SNAP_ID"].toString(), paramMap["CREATOR_DISPLAY_NAME"].toString(), null, MediaDownloadSource.SPOTLIGHT, null, forceAllowDuplicate, isBatch), mediaInfoMap, paramMap); return + downloadOperaMedia(provideDownloadManagerClient(paramMap["SNAP_ID"].toString(), paramMap["CREATOR_DISPLAY_NAME"].toString(), null, MediaDownloadSource.SPOTLIGHT, null, forceAllowDuplicate, isBatch), mediaInfoMap, paramMap, MediaDownloadSource.SPOTLIGHT); return } if (!forceDownload && !shouldAutoDownload("public_stories")) return val author = (paramMap["USER_ID"]?.let { modCtx.database.getFriendInfo(it.toString())?.mutableUsername } ?: paramMap["USERNAME"]?.toString()?.substringAfter("value=")?.substringBefore(")") ?: "unknown").sanitizeForPath() - downloadOperaMedia(provideDownloadManagerClient(paramMap["SNAP_ID"].toString(), author, null, MediaDownloadSource.PUBLIC_STORY, null, forceAllowDuplicate, isBatch), mediaInfoMap, paramMap) + downloadOperaMedia(provideDownloadManagerClient(paramMap["SNAP_ID"].toString(), author, null, MediaDownloadSource.PUBLIC_STORY, null, forceAllowDuplicate, isBatch), mediaInfoMap, paramMap, MediaDownloadSource.PUBLIC_STORY) } private fun shouldAutoDownload(keyFilter: String? = null): Boolean = this@MediaDownloader.context.config.downloader.autoDownloadSources.get().any { keyFilter == null || it.contains(keyFilter, true) } @@ -499,7 +510,12 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp val mediaInfoMap = mutableMapOf() val isVideo = mediaParamMap!!.containsKey("video_media_info_list") mediaInfoMap[SplitMediaAssetType.ORIGINAL] = MediaInfo(mediaParamMap[if (isVideo) "video_media_info_list" else "image_media_info"]!!) - if (modCtx.config.downloader.mergeOverlays.get() && mediaParamMap.containsKey("overlay_image_media_info")) mediaInfoMap[SplitMediaAssetType.OVERLAY] = MediaInfo(mediaParamMap["overlay_image_media_info"]!!) + // Check if this is story-type content (public story, friend story, or spotlight) + // Stories should NOT have overlays merged + val isStoryContent = mediaParamMap.containsKey("PLAYLIST_V2_GROUP") || + mediaParamMap["SNAP_SOURCE"]?.toString() == "SINGLE_SNAP_STORY" || + mediaParamMap.containsKey("SNAP_ID") + if (!isStoryContent && modCtx.config.downloader.mergeOverlays.get() && mediaParamMap.containsKey("overlay_image_media_info")) mediaInfoMap[SplitMediaAssetType.OVERLAY] = MediaInfo(mediaParamMap["overlay_image_media_info"]!!) if (shouldAutoDownload() && lastSeenMediaInfoMap?.get(SplitMediaAssetType.ORIGINAL)?.uri == mediaInfoMap[SplitMediaAssetType.ORIGINAL]?.uri) return@hook lastSeenMapParams = mediaParamMap; lastSeenMediaInfoMap = mediaInfoMap if (pendingBatchDownloadIndices != null) { modCtx.coroutineScope.launch { processNextBatchDownload(mediaParamMap, mediaInfoMap) }; return@hook }