Skip to content

Releases: Yhazrin/reapple

Reapple Music 0.3.0 Beta 2 — 歌词响应优化 · Stage 134

Choose a tag to compare

@Yhazrin Yhazrin released this 28 Oct 18:09

播放页修复 · Stage 134(同版更新)

  • 本次覆盖更新:当前行与上方退场行响应加快,下方歌词继续保持原来的延迟跟随。受控100px滚动检查中,当前行到90%位置由352ms缩短至212ms;不是Apple原生参数测量。
  • 歌词由整列同步滚动改为逐行延迟跟随;当前行先行,下方行随后跟上。保留手动浏览、减少动态效果与清理逻辑。
  • 背景预处理从 256 提高至 1024,等比例保持模糊半径,并在最终缩放层之后加入静态细粒度抖动以减轻色带。不逐帧生成噪声。
  • 修正动画超时退出可能未提交最终滚动位置的问题。

原生逆向已定位逐行布局动画器及 delay 状态,但当前逐行延迟参数仍为重建值,并非完整移植 Apple 私有算法。Canvas 仍是8-bit路径;此次是抗色带优化,不声称恢复了原生浮点渲染链或彻底消除了所有显示器上的色带。

实际网易云播放采样7.5秒:跨4个当前行,899帧中454帧具有逐行不同位移。基线/修改/回滚检查均退出0,回滚字节与基线一致。尚未完成同歌曲同相位的 Apple 动效对齐及色带定量验收。

Apple Silicon 内测版;临时签名,未公证。安装方式与 Beta1 相同。更新前先退出 Reapple Music,再替换应用并按设置重新安装组件。

本 Release 已在用户确认后以 Stage 134 重新打包,覆盖此前 Stage 133 的 Beta 2 安装包。文件名与下载链接不变,SHA-256 已更新;此前下载者请重新下载并核对新的 SHA256SUMS-beta2.txt。

Reapple Music 0.3.0 Beta 1 — 更轻盈的音乐体验

Choose a tag to compare

@Yhazrin Yhazrin released this 23 Oct 15:41

Reapple Music 0.3.0 Beta 1

更轻盈的网易云音乐桌面体验。本次更新包含原生菜单栏管理器、引导与设置、播放页与悬浮栏优化,以及内置运行环境的 DMG。

更新

  • 原生引导、启动偏好和集中设置;提供卸载入口。
  • 播放页歌词滚动、封面播放/暂停动效及音质卡片优化。
  • 悬浮栏 hover 与进度显示调整。
  • 安装事务、并发保护和中断恢复入口。
  • 内置 Node.js 22.23.4,不需要用户安装 Homebrew 或 Node。
  • 全新 README,使用《Childhood》的真实播放页面截图。

安装

下载 DMG,拖动 Reapple Music 到 Applications,再按应用内引导安装组件。需要重启网易云时会影响当前播放。

重要限制

内测版 / Apple Silicon / macOS 14+ 部署目标。临时签名,未经过 Apple 公证。 不代表已在所有 macOS 或网易云版本上验证。请勿关闭系统安全保护或公开本地调试端口。

已检查本机运行、隔离安装/升级/回滚,以及 DMG 完整性和应用临时签名。全新机器、系统重启后的自动启动,以及最新管理器安装失败后的会话恢复仍需进一步验收。不承诺与 Apple Music 完全一致;未包含逐字歌词功能。

校验下载文件可运行 shasum -a 256 Reapple-Music-0.3.0-beta.1-arm64.dmg,与 SHA256SUMS.txt 对照。

Reapple Music 0.1.2 — 自动注入恢复与独立安装包

Choose a tag to compare

@Yhazrin Yhazrin released this 22 Oct 09:32

修复正常退出重开网易云后注入丢失。完整运行目录安装至 ~/.reapple/runtime,下载文件夹删除后仍可运行;提供双击安装、启动、关闭和卸载入口。修复胶囊对测试标记的依赖与样式丢失后的恢复。需要 macOS、网易云音乐、Node.js 22+;本包为可审阅脚本,非签名/公证 app。网易云丢失调试参数时会温和重开一次,并非零延迟注入。已在网易云3.1.12验证实际退出重开、卸载后不复活及完整包重装。

reapple 0.1.1 — the queue rows work, and the song info is measured

Choose a tag to compare

@Yhazrin Yhazrin released this 17 Oct 19:53

Two of v0.1.0's Known gaps were not gaps. They were wrong, in the same way twice, and this
release says so rather than quietly shipping past it.

The rows work now

v0.1.0 claimed the queue row … had no menu and that rows were not clickable to play,
and put the reason beyond repair: "NetEase's player runs through a native command bridge,
not the JS store. store.dispatch never sees playback at all."

That conclusion came from watching the wrong thing. Double-clicking one of NetEase's own
rows puts exactly four types across store.dispatch — host/onUpdate,
playing/onUpdate, playing/onUpdateCurPlaying, page:vinylPage/setColor — and every
one of them is an effect. The action that actually starts the audio is dispatched from a
component, not from the row handler you would think to instrument. So the tap found the
smoke and not the fire, and playback looked like it bypassed the store entirely. It does
not.

Reading NetEase's own bundle instead of guessing at it turned up the four commands that
matter, and all four were then verified against the running page:

action drives
playing/switchResumeOrPause play / pause
playingList/jump2Track next / previous
playing/playOneTrackInPlayingList play one queue row
async:action/popMenu NetEase's own menu, for a track

One trap worth keeping: jump2Track lives under playingList/, not playing/. The
playing/ form is accepted by the dispatcher and does nothing at all, which on screen is
indistinguishable from a dead button.

So rows play, the transport dispatches instead of clicking hidden host DOM, and play state
is read from the store rather than scraped out of NetEase's CSS class names. The … opens
NetEase's real menu with real actions — 播放, 下一首播放, 查看评论, 收藏, 下载, 分享,
复制链接 — because the row asks the host to build it rather than reimplementing one that
would drift out of step with a menu we cannot see.

The menu still lands in the wrong place, and that is stated as unverified rather than
fixed. winhelper.popupMenu is handed {content, hotkey, left_border_size, menu_type} and
no coordinates at all, so the position has to arrive some other way. The row now sends the
click point the way the host's own row does; the last confirmed behaviour was the window's
bottom-left corner, and that has not been re-checked since.

The song info was measured, not scaled

Separate bug, same root cause as everything being subtly small: --u is the artwork
column's scale, width × 0.28 / 423.4, and 423.4 is the column width at a 1512pt
window
. At 1291pt it comes out .8538, so the title rendered at 12.8pt against Apple's
18.2. u also entered a second time through - 58.4 * u in the stack's pin, which is why
the rail sat 22–40pt below Apple's rows rather than merely looking small.

The type size took two instruments to get. Apple exposes no font for that string at all —
the whole block is one AXButton with both lines folded into its description, AXFont
empty, no AXStaticText child — so it came off pixels, and the two pixel methods
disagreed by 5pt: 18.2 from cap height, 13.4 from advance widths. What settled it was
calibrating against a face whose size is already known, and the replica is one. Its
subtitle renders HOYO-MiX at exactly 9.8187pt, so the cap band is a direct reading of
SF Pro's cap ratio:

7.00 ÷ 9.8187 = .7129      against a documented .71

Apple's caps then measure 13.00pt and 11.00pt, giving 18.2 and 15.4. Line heights
are solved from Apple's baselines rather than chosen as a ratio, which puts both baselines
on 612.4 and 629.1 with nothing left over.

Also taken off the same capture: the two tool buttons were 22 × 22 on a 26pt pitch against
Apple's 26 × 26 on 34, and the transport buttons were sized by their own glyphs, so the hit
targets were whatever the mark happened to be. They now carry Apple's boxes —
30 / 48 / 28 / 48 / 30, all five centres on page y 715, with gaps of 80, 86, 86, 79.5 that
are wider in the middle and tighter at the ends.

After the change, head top, both timestamps and all five transport boxes match Apple to
within a rounding step.

Still open

  • The transport glyphs are the marks that were already rendering. The boxes are measured;
    the marks inside them are not.
  • The queue row menu's position, as above.
  • The backdrop wash reads greyer than Apple's on some albums.
  • Motion on the song info and playback bar is faithful in kind but not dug as deep as the
    layout now is.

Full notes in docs/MEASUREMENTS.md.

reapple 0.1.0

Choose a tag to compare

@Yhazrin Yhazrin released this 17 Oct 18:46

reapple 0.1.0

Apple Music's Now Playing page, rebuilt inside NetEase Cloud Music on macOS.

Open NetEase Cloud Music, click the album cover in the bottom bar, and you get Apple's
playback page — the album wash, the floating artwork, the scrubber, the synced lyrics,
and the Up Next queue — laid out and animated against NetEase's own playback state.

Install

git clone https://github.com/Yhazrin/reapple.git
cd reapple && ./install.sh

Needs macOS, NetEase Cloud Music in /Applications, and Node. Nothing is written inside
NeteaseMusic.app; reapple uninstall reverses all of it.

Switches

Every component turns off independently, and a change lands on the next animation frame:

reapple config               # list them
reapple config lyrics off
reapple off                  # the escape hatch; NetEase keeps playing

playPage is the master. The rest — backdrop, artwork, songInfo, playbackBar,
lyrics, footer, queue — are independent, and each stands alone: turning lyrics off
does not disturb the playback bar.

What "measured, not reasoned" means here

Every visual constant was read off a running copy of Apple Music. Geometry comes from the
accessibility tree, because the AX frame is what Apple's layout is written against; colour
and mark shape come from thresholded screenshots at 2 device pixels per point, because there
is no accessibility attribute for "how bright is this dot".

It has already caught real errors rather than confirming the code:

  • the AutoPlay glyph was two rings with a visible gap between them, sitting next to a comment
    claiming they crossed — reading the ink run per scanline showed one continuous blob through
    the middle, i.e. a lemniscate
  • the queue … was 2.6pt dots at alpha .59; it is 2.00pt at .193, neutral across all three
    channels, set 31pt in from the panel edge rather than 25pt
  • the queue pills were 10pt apart with 9pt margins; Apple's are 17.5pt apart with 13pt margins
    and an opaque rgb(209,208,204) fill

Full notes, including the traps, are in docs/MEASUREMENTS.md.

Known gaps

Stated in the README rather than glossed:

  • The queue row … has Apple's styling, including a hover state that takes the artwork's own
    colour, but no menu yet. NetEase's player runs through a native command bridge rather
    than the JS store — store.dispatch never sees playback, and window.api, the bridge
    handle, is an empty object — and the playing list has no rendered rows anywhere in the DOM,
    so there is no host menu to delegate to.
  • Queue rows are not clickable to play, for the same reason.
  • The backdrop wash reads greyer than Apple's on some albums.
  • Motion on the song info and playback bar is faithful in curve and duration but not dug as
    deep as the layout and the queue.

Licence

MIT. Not affiliated with Apple or NetEase; contains no code from either. Apple Music is
read the way a person reads it — by looking at it and measuring.