You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+
## Project Overview
6
+
7
+
Windows-only application that reads NetEase Cloud Music (NCM) playback state directly from process memory and displays it as Discord Rich Presence. Single-file Python app (`src/main.py`) with a Tkinter GUI and system tray icon.
# Enable debug logging: create an empty file named debug.log in working directory
25
+
```
26
+
27
+
CI uses GitHub Actions (`.github/workflows/pyinstaller-windows.yml`): Python 3.12, PyInstaller + UPX on Windows.
28
+
29
+
## Architecture
30
+
31
+
The entire application lives in `src/main.py` (~517 lines). There are no tests, no separate modules.
32
+
33
+
### Core Loop
34
+
35
+
`startup()` → connects to Discord via pypresence → starts a `RepeatedTimer` (1-second interval) that calls `update()`:
36
+
37
+
1.**Process discovery**: Uses WMI to find `cloudmusic.exe`, reads file version via `win32api.GetFileVersionInfo`
38
+
2.**Memory reading**: Opens process with pyMeow, reads from `cloudmusic.dll`:
39
+
-**V2.x**: base + hardcoded version-specific offsets (`current` → `r_float64` playback time, `song_array` → `r_uint` → UTF-16 song ID)
40
+
-**V3.x**: AOB (array-of-bytes) pattern scan via `aob_scan_module()` to find `schedule_ptr` and `audio_player_ptr` at runtime (offsets change every launch). Song ID read via SSO string logic, UTF-8 encoded.
41
+
3.**Status detection** (line 354): Compares current song ID and playback time with previous values:
42
+
- Playing: same ID, time advanced ~1s
43
+
- Paused: same ID, time unchanged
44
+
- Changed: different ID or manual seek
45
+
4.**Song info lookup**: Local history cache → playingList file → remote `pyncm` API. Results cached in `song_info_cache` dict.
46
+
5.**Discord update**: Sets presence with title, artist, album art URL, play/pause icon, elapsed time, and a "Listen on NetEase" button link.
47
+
48
+
### Key Design Details
49
+
50
+
-**Version-specific offsets** (line 40-52): Dict mapping NCM V2.x version strings to memory offsets. V3.x uses dynamic AOB scanning (`scan_for_v3_offsets()`) — patterns sourced from [Kxnrl/NetEase-Cloud-Music-DiscordRPC](https://github.com/Kxnrl/NetEase-Cloud-Music-DiscordRPC/blob/d3b77c679379aff1294cc83a285ad4f695376ad6/Vanessa/Players/NetEase.cs#L24).
51
+
-**Pause timeout**: After 30 minutes paused, disconnects RPC. Reconnects on resume.
52
+
-**Locale detection** (line 58): UI text is bilingual (Chinese/English) based on Windows UI language.
53
+
-**Startup on boot**: Writes/removes a `.bat` file in the Windows Startup folder.
54
+
-**`RepeatedTimer`** (line 77): Custom timer that compensates for execution time drift.
55
+
56
+
### Adding Support for New NCM Versions
57
+
58
+
**V2.x**: Use Cheat Engine to find the `current` (float64 playback time) and `song_array` offsets relative to `cloudmusic.dll` base. Add entry to the `offsets` dict with key format `major.minor.patch.build`.
59
+
60
+
**V3.x**: No action needed — all V3 versions are supported automatically via AOB pattern scanning. If NetEase changes their binary significantly, the byte patterns (`V3_AUDIO_PLAYER_PATTERN`, `V3_AUDIO_SCHEDULE_PATTERN`) may need updating.
61
+
62
+
## Dependencies
63
+
64
+
Key non-obvious dependencies:
65
+
-**pyMeow**: Windows process memory reading (installed from GitHub release zip, not PyPI)
66
+
-**pypresence**: Discord IPC Rich Presence client
67
+
-**pyncm**: Unofficial NetEase Cloud Music API wrapper (fallback for song metadata)
68
+
-**orjson**: Fast JSON parsing for local NCM history cache
69
+
-**pystray**: System tray icon (runs in daemon thread to avoid blocking the timer)
70
+
71
+
## Project Conventions
72
+
73
+
- All source code is in a single file `src/main.py` — no module structure
74
+
- Global mutable state for RPC connection, process info, and song cache
75
+
- Chinese comments and UI strings alongside English equivalents
# '3.0.6.5811': {'current': 0x192B7F0, 'song_array': 0x0196DC38, 'song_array_offsets': [0x398, 0x0, 0x0, 0x8, 0x8, 0x50, 0xBA0]}, } # TODO: song array offsets are different for every session, current and song_array stays same
53
+
# V3 byte patterns for dynamic memory scanning (offsets change every launch)
raiseUnsupportedVersionError(f"This version is not supported yet: {version}.\nSupported version: {', '.join(offsets.keys())}"ifnotis_CNelsef"目前不支持此网易云音乐版本: {version}。\n支持的版本: {', '.join(offsets.keys())}")
0 commit comments