Skip to content

fix: own messages from native did not show custom emojis#220

Merged
highesttt merged 1 commit into
mainfrom
highest/plat-38019
Jul 20, 2026
Merged

fix: own messages from native did not show custom emojis#220
highesttt merged 1 commit into
mainfrom
highest/plat-38019

Conversation

@highesttt

Copy link
Copy Markdown
Collaborator

No description provided.

@linear-code

linear-code Bot commented Jul 20, 2026

Copy link
Copy Markdown

PLAT-38019

@indent-zero

indent-zero Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor
PR Summary

Fixes rendering of inline custom emoji in own outbound messages echoed back from the native LINE app. Previously the bridge only extracted REPLACE.sticon.resources from decrypted E2EE bodies, so plaintext echoes carrying only EMTVER3/4 code points (or a top-level REPLACE map) rendered as [Emoji] / (alt text) placeholders. The bridge now merges three sources of sticon resources (body JSON, plaintext ContentMetadata["REPLACE"], and derived-from-text) and expands the CDN download to cover Chrome's EMTVER _k.png and animation-first URLs.

  • handle_message.go: adds handlers.HasSticonMetadata(ContentMetadata["REPLACE"]) as an extra trigger for the inline-emoji branch.
  • emoji.go: introduces parseSticonReplace for the plaintext {"sticon":{"resources":...}} shape, deriveSticonResources that reconstructs SticonResource values from EMTVER3/4 code points (MD5-based product hash + sticon ID), and collectSticonResources that merges body → metadata → derived and deduplicates by Start.
  • emoji.go: refactors tryUploadEmoji to take a full SticonResource and iterate over inlineSticonURLs — trying _k.png for derived EMTVER resources and _animation.png.png for sticker-shop ANIMATION types.
  • Adds unit tests for derivation, metadata precedence, and animation-URL fallback, plus an end-to-end TestConvertLineMessageRendersPlaintextCustomEmoji covering both the REPLACE-metadata and EMTVER4-text paths.

Issues

2 potential issues found:

  • sticonProductHash MD5s the uppercase-hex representation of the product rune (fmt.Sprintf("%X", productCode)), so EMTVER4 product codes containing hex letters (e.g. U+1001AB) hash the string "1001AB" instead of "1001ab". If Chrome hashes the lowercase form, derived URLs 404 for that subset and inline emoji silently fall back to plaintext — the current test only covers 0x100101, which has no ambiguous digits. → Autofix
  • appendUniqueSticonResources deduplicates only on Start, so if two sources (body JSON, plaintext REPLACE, or derived text) declare a resource at the same UTF-16 offset with different End/ProductID/SticonID, the second is silently discarded without any comparison. This holds fine today because LINE senders emit consistent offsets, but a sender whose explicit metadata diverges from Chrome-style derivation would render the wrong image with no warning. → Autofix

CI Checks

Waiting for CI checks...


⚡ Autofix All Issues

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 69e18b0a-d534-41b3-8385-952a97cad58e

📥 Commits

Reviewing files that changed from the base of the PR and between bfc7f2f and 24b8bd3.

📒 Files selected for processing (4)
  • pkg/connector/handle_message.go
  • pkg/connector/handle_message_test.go
  • pkg/connector/handlers/emoji.go
  • pkg/connector/handlers/emoji_test.go

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.


📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Improved rendering of inline custom emojis and stickers from plaintext and encrypted message metadata.
    • Added support for additional LINE sticker formats and embedded sticker placeholders.
    • Improved image retrieval with fallback URLs when the primary sticker image is unavailable.
    • Ensured custom emoji images are uploaded and displayed correctly in messages.
  • Tests
    • Expanded coverage for custom emoji rendering, sticker metadata handling, URL fallbacks, and multiple sticker formats.

Walkthrough

The change expands LINE inline sticon detection and conversion. It parses plaintext and encrypted metadata, reconstructs EMTVER3/4 resources, tries multiple CDN URLs, uploads valid images, and renders custom emoji with integration coverage.

Changes

Inline sticon conversion

Layer / File(s) Summary
Resource discovery and reconstruction
pkg/connector/handlers/emoji.go, pkg/connector/handlers/emoji_test.go
Sticon resources are parsed, validated, deduplicated, or reconstructed from EMTVER3/4 text with UTF-16 offsets and derived identifiers.
Emoji download and conversion
pkg/connector/handlers/emoji.go, pkg/connector/handlers/emoji_test.go
Conversion generates CDN URL variants, retries failed downloads, uploads valid image data, and renders inline emoji.
Message routing and integration validation
pkg/connector/handle_message.go, pkg/connector/handle_message_test.go
Messages with validated plaintext sticon metadata enter inline conversion, with tests covering HTML output, URL requests, retries, and upload counts.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant convertLineMessage
  participant ConvertInlineEmoji
  participant LINECDN
  participant Matrix
  convertLineMessage->>ConvertInlineEmoji: detect validated REPLACE sticon metadata
  ConvertInlineEmoji->>LINECDN: request candidate image URLs
  LINECDN-->>ConvertInlineEmoji: return image bytes or failure
  ConvertInlineEmoji->>Matrix: upload image media
  Matrix-->>ConvertInlineEmoji: return uploaded media URI
Loading

Possibly related PRs

  • beeper/line#218: Both changes update LINE sticon detection and inline emoji conversion behavior.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch highest/plat-38019

Comment @coderabbitai help to get the list of available commands.

}

func sticonProductHash(productCode rune) string {
sum := md5.Sum([]byte(fmt.Sprintf("%X", productCode)))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uppercase-hex MD5 input may not match Chrome: fmt.Sprintf("%X", productCode) produces "1001AB" for a product rune like U+1001AB. If Chrome's real derivation hashes the lowercase representation (%x"1001ab"), the two MD5s differ and the resulting CDN URL 404s for any EMTVER4 product whose code point contains hex letters (A–F). The existing tests only exercise 0x100101, which is all digits, so this wouldn't surface. Worth verifying against a Chrome capture that includes a product rune with a hex-letter nibble; if lowercase is correct, switch both this and the SticonID formatting on lines 479/496 to %x.

return resources
}

func appendUniqueSticonResources(dst, src []SticonResource) []SticonResource {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dedup key is Start only: If body/metadata declare a resource at Start=X with product A, and deriveSticonResources also produces Start=X with product B, the derived entry is dropped without a mismatch warning. This is intentional ("explicit wins") and correct when the sources agree on the visible token, but there's no invariant enforced — mismatched sender data would silently pick the earlier source. Consider logging when a duplicate Start carries different Product/Sticon IDs so future regressions surface, or documenting the assumption explicitly.

@highesttt
highesttt merged commit 2ddfe44 into main Jul 20, 2026
9 of 10 checks passed
@highesttt
highesttt deleted the highest/plat-38019 branch July 20, 2026 17:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant