Repository navigation
Conversation
The Apple scraper deleted every decimal reference in a page's `<title>` and left hex ones as written, so a title written as `It’s here` was stored as `Its here`. The title is written into the push's envelope and read by every device, so the garbled one stayed for good, and it disagreed with Android, whose Jsoup decodes them. The title extraction moves from `TitleScraperService` into `PushTitle` in `PushContent.swift`, which the tests already compile, and decodes in one pass from the left: decimal and hex references (the `;` optional, 0x80 to 0x9F read as Windows-1252, as browsers and Jsoup do), and the named ones it already knew, now to their own characters rather than ASCII stand-ins, so `—` and `—` give the same title. A reference that names no character is left as text. Decoding now comes before the whitespace is collapsed, as it does in Jsoup. `PushTitleTests` covers decimal, hex, invalid and mixed cases, with expected strings checked against Jsoup 1.23.2. This makes the same change in both apps: `apps/macos` is a fork of `apps/ios`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Apple scraper knew ten names, so a title holding `’`, `…` or `é` was stored with the reference as literal text, while Android's Jsoup decoded it. The title is stored for every device, so the two disagreed for good. `PushTitle` now knows HTML 4's 252 names and `'`, with `⟨` and `⟩` at HTML5's code points as Jsoup has them. That covers what titles use without carrying HTML5's two thousand, nearly all mathematical symbols. It also drops the soft hyphen and the zero-width space from the title, as Jsoup does when it collapses whitespace. Every name was checked against Jsoup 1.23.2. This makes the same change in both apps: `apps/macos` is a fork of `apps/ios`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`PushTitle` collapsed and trimmed with ICU's `\s` and `.whitespacesAndNewlines`, which take every Unicode space. Jsoup, which Android scrapes with, collapses only space, tab, newline, form feed, carriage return and the no-break space, and trims what is at or below U+0020. Now that references are decoded, a title with ` `, the narrow no-break space French writes before `!`, or an ideographic space was stored as a plain space on Apple and as written on Android, and the first device to scrape decided which every device saw. The title is now collapsed over Jsoup's six and trimmed as Java's `trim()` does, checked against Jsoup 1.23.2. This makes the same change in both apps: `apps/macos` is a fork of `apps/ios`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… macOS `PushTitle` required a `;` after every name, on the claim that no page writes one without it. Hand-written titles do: `© 2024` and `Fish & Chips` were stored as written on Apple, while Android's Jsoup decodes them as HTML says to, and the first device to scrape decided which every device saw. The uppercase aliases (`&`, `©`) were missing too. A name now decodes with its `;` from the table, or else as the longest start of it that is one of HTML's 106 legacy names, the rest left as text (`¬it;` is `¬it;`), which is HTML's rule and Jsoup's. The aliases join the table. Checked against Jsoup 1.23.2. This makes the same change in both apps: `apps/macos` is a fork of `apps/ios`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An HTML parser reads a NUL in a `<title>` as U+FFFD, and Jsoup on Android does. `PushTitle` kept it, and since the title is now trimmed as Java's `trim()` does, one at either end was dropped instead. The title is stored for every device, so the two clients stored different titles for the same page. The NUL now becomes U+FFFD before anything else, checked against Jsoup 1.23.2. This makes the same change in both apps: `apps/macos` is a fork of `apps/ios`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…macOS The comment on `PushTitle.decodingEntities` listed where Jsoup's answer for an invalid numeric reference differs from keeping it as written, and left out `�`, which Jsoup drops. A reader checking the two clients against each other would take that difference for a bug. Comment only. This makes the same change in both apps: `apps/macos` is a fork of `apps/ios`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
The Apple scraper deleted decimal character references from a page's
<title>, so a title written asIt’s herewas stored asIts here. It also left hex references and most named ones (’,…) as literal text. The scraped title is written into the push's envelope and read by every device, so a garbled title stayed for good, and it disagreed with Android, whose Jsoup decodes all of them.What changes
Title extraction moves from
TitleScraperServiceintoPushTitleinServices/PushContent.swift, which the test target already compiles (asPushIcondoes), so no project file changes. It now produces the title Jsoup'sdoc.title()gives for the same page:&#39;stays the text'. The;is optional, and 0x80 to 0x9F are read as Windows-1252, as browsers and Jsoup do.'and HTML5's uppercase aliases (&), each to its own character.–,—and©used to become-and(c).;(© 2024), by the longest legacy prefix (¬it;is¬it;).trim()does, so a thin or ideographic space is kept. Soft hyphens and zero-width spaces are dropped, and a NUL becomes U+FFFD, as in Jsoup.apps/macosis a hand-maintained fork ofapps/ios, and every commit makes the same change in both.Where Apple still differs from Android
Documented in the code: a numeric reference that names no character (
�, a surrogate, past U+10FFFF) stays as written, where Jsoup drops it or makes U+FFFD of it, and HTML5-only names such as∥are not decoded. No real title should hit either.PushIcon.decodeEntitieskeeps its own decoder on purpose: in an attribute, HTML leaves a legacy name before=or a letter as text, so sharing this one would turn?a=1©=2into©=2.Verification
PushTitleTestscovers decimal, hex, invalid, legacy and mixed references, and whitespace. Every expected string was checked against Jsoup 1.23.2, the version Android uses. A review pass also compared about 23,000 generated titles between the two, and found no differences beyond the documented ones.xcodebuild teston the iPhone 15 Pro simulator passes.xcodebuild testwithMACOSX_DEPLOYMENT_TARGET=14.0passes (the plain build fails on the known deployment-target issue, seedocs/macos.md).CI runs no Xcode builds, so these were run locally.
🤖 Generated with Claude Code