Fix Download option missing on your own stories - #200
Open
izadiegizabal wants to merge 2 commits into
Open
Conversation
Instagram builds the option list for your own story with a different method than the one used for other users' stories, and dispatches its taps through a different handler. The button injector stopped at the first CharSequence[] candidate — and filtered on paramCount(1), which the 3-arg self-story builder could never match — while the click matcher required "explore_viewer" and "friendships/mute_friend_reel/%s/", two options that only exist on someone else's story. Neither hook ever reached the self-story path, leaving only Instagram's native Save, which drops the music track. Hook every CharSequence[] candidate behind the "[INTERNAL] Pause Playback" anchor, and every void handler that receives the tapped label. Static methods are kept as candidates here: unlike the post overflow menu, the story dispatchers are static helpers that take the outer class as a parameter. Resolving the media also had to change. The self-story dispatcher passes the ReelItem and the Context on separate arguments, so the Context is now looked up across 'this' and every argument instead of on the ReelItem holder alone. No new toggle — folded into the existing enableStoryDownload flag. Others'-story behaviour is unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VY3pmFCvKrxiKWx8ebaF6k
"username".hashCode() matches two zero-arg String getters on com.instagram.user.model.User: the username itself, and a display-name getter that reads username and falls back to full_name. get(0) picked the latter. Nothing downstream could catch it — UserUtils.isValidUsername() accepts any lowercase string, so an all-lowercase display name passes as a handle. Every download from an account whose display name is lowercase was filed under that name instead of the username, across posts, reels, stories and profile pictures. Drop the candidates that also read full_name; the remaining one is the plain username getter. Both field ids are named constants now, with a note that they are just String.hashCode() of the Pando field name and so stay valid across Instagram builds. The cache key is bumped to _v2 because an existing cache would restore the display-name getter, and a cache hit now requires the getter to be present: without it UserUtils falls back to scanning User for any lowercase String, which is the same bug by another route. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VY3pmFCvKrxiKWx8ebaF6k
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Downloading your own story wasn't possible — the module's Download row never appeared there, so the only option was Instagram's native Save, which drops the music track from stories that have one. InstaEclipse's downloader grabs the rendered
video_version, so the music is preserved.Tested on Instagram 439.0.0.37.89 (Pixel 8 Pro, Android 16), own + other users' stories, video and photo.
Two independent fixes, one commit each — happy to split into separate PRs if you'd prefer.
1.
fix(story)— own-story menu —StoryDownloadHook.javaInstagram builds the self-story option list with a different method than the others'-story one, and dispatches its taps through a different handler:
Delete, Archive, Save video, Highlight, Edit AI label, Share, …Report, Mute, AI infoThe button injector filtered on
paramCount(1)and stopped at the firstCharSequence[]candidate, so it only ever found the others'-story builder. The click matcher required"explore_viewer"and"friendships/mute_friend_reel/%s/"— Explore-viewer and Mute only exist on someone else's story, so it could never match the self-story dispatcher.Now every
CharSequence[]candidate behind the"[INTERNAL] Pause Playback"anchor is hooked, and everyvoidhandler that receives the tapped label. Static methods are deliberately kept as candidates: unlike the post overflow menu, the story dispatchers are static helpers taking the outer class as a parameter.Resolving the media needed a change too — the self-story dispatcher passes the ReelItem and the Context on separate arguments, so the Context is now looked up across
thisand every argument rather than on the ReelItem holder alone.No new toggle; folded into the existing
enableStoryDownload. Others'-story behaviour is unchanged.2.
fix(download)— wrong username getter —FeedVideoDownloadHook.javaFound while testing the above, but not story-specific — it affects every download type.
"username".hashCode()(-265713450) matches two zero-argStringgetters oncom.instagram.user.model.User: the username, and a display-name getter that reads username and falls back tofull_name.get(0)picked the latter.Nothing downstream caught it:
UserUtils.isValidUsername()accepts any lowercase string, so an all-lowercase display name passes as a handle. On my account (izadiegizabal, display nameizadi) every download — posts, reels, stories, profile pictures — was filed underizadi. Accounts whose display name has capitals or spaces failed the regex and fell through to the fallback scan, which is why this went unnoticed.The fix drops candidates that also read
full_name, leaving the plain username getter. Both field ids are named constants now, with a note that they're justString.hashCode()of the Pando field name and so stay valid across builds. Cache key bumped to_v2since an existing cache would restore the display-name getter.Notes
StoryMentionHook.javauses the same two anchors with the same take-the-first shape, so View Mentions is likely missing on own stories for the same reason. Left out to keep this diff reviewable.FeatureFlags,SettingsManager,FeatureManager,FeaturesFragment,strings.xml,Module.java,version.json, or the README.