Animated SVG stats cards for Malody profiles
中文 | English
Warning
This project is unofficial, non-profit, and open source. If you believe any content here is infringing or inappropriate, please contact the maintainer.
Malody Stats Card renders a Malody player's profile as an animated SVG card that can be embedded in blogs, profile pages, or dashboards.
The project currently supports two data providers:
legacy(default): uses the older Malody community API and requires account credentials in.envweb-v2-experimental: uses the newermalody.mugzone.netweb API through a guest session and is marked experimental
Animation note
Cards are animated SVGs. Some preview tools or social platforms may only show the first frame. For visual verification, open the SVG directly in a browser.
- Animated SVG profile cards
- JSON profile endpoints for integrations and debugging
- Provider-based cache isolation between
legacyandweb-v2-experimental - Automatic cache schema migration with backup on first upgrade
- Route and adapter tests for both existing and experimental behavior
| Purpose | Endpoint | Notes |
|---|---|---|
| Legacy profile JSON | /profile?uid=[UID] |
Default provider |
| Legacy card SVG | /card/default/[UID] |
Animated SVG |
| Experimental profile JSON | /profile?uid=[UID]&provider=web-v2-experimental |
Same shape as legacy, normalized from the new web API |
| Experimental card SVG | /card/default/[UID]?provider=web-v2-experimental |
Same card renderer, experimental data source |
| Experimental profile JSON shortcut | /experimental/profile?uid=[UID] |
Shortcut for the experimental provider |
| Experimental card SVG shortcut | /experimental/card/default/[UID] |
Shortcut for the experimental provider |
| Name | Applies to | Description |
|---|---|---|
uid |
/profile, /experimental/profile |
Malody user ID |
hide |
card endpoints | Comma-separated modes to hide, for example hide=4,5 |
provider |
/profile, /card/default/[UID] |
Currently supports legacy and web-v2-experimental |
The card renderer currently recognizes these mode IDs when present: 0, 3, 4, 5, 6, 7, 8, 9. Invalid hide entries are ignored.
| Header | Meaning |
|---|---|
X-Cache |
HIT or MISS for card responses |
X-Malody-Provider |
Which provider served the response |
X-Malody-Experimental |
Present and set to true for experimental responses |
Assuming the service is running at http://127.0.0.1:3000, these URLs are useful for quick manual checks:
- Legacy profile JSON: http://127.0.0.1:3000/profile?uid=178813
- Legacy card SVG: http://127.0.0.1:3000/card/default/178813
- Legacy card with hidden modes: http://127.0.0.1:3000/card/default/178813?hide=4,5,8,9
- Experimental profile JSON: http://127.0.0.1:3000/profile?uid=178813&provider=web-v2-experimental
- Experimental profile shortcut: http://127.0.0.1:3000/experimental/profile?uid=178813
- Experimental card SVG: http://127.0.0.1:3000/experimental/card/default/178813
- Invalid provider example: http://127.0.0.1:3000/profile?uid=178813&provider=future
If you want to inspect headers:
curl -i "http://127.0.0.1:3000/card/default/178813"
curl -i "http://127.0.0.1:3000/profile?uid=178813&provider=web-v2-experimental"
curl -i "http://127.0.0.1:3000/experimental/card/default/178813"Replace https://your-host.example.com and [UID] with your own values.
[](https://malody.mugzone.net/player/[UID])<a href="https://malody.mugzone.net/player/[UID]">
<img src="https://your-host.example.com/card/default/[UID]" alt="Malody Stats Card">
</a>[](https://malody.mugzone.net/player/[UID])- Default behavior for
/profileand/card/default/[UID] - Uses the older Malody API endpoints
- Requires
.envcredentials - Recommended when you want the most established behavior in this project
- Uses the newer
https://malody.mugzone.net/web API through guest access - Does not require account credentials for basic profile fetches
- Response shape is normalized so the current card renderer can keep working
- Experimental by design and may break if the upstream site changes
The current public player page is:
https://malody.mugzone.net/player/[UID]
You can usually obtain a UID by opening a player's profile page and copying the numeric ID from the URL.
-
Clone this repository.
-
If you want to use the default
legacyprovider, create a.envfile in the project root:uid= username= password= PORT=3000
-
Start the service:
docker compose up -d
-
Open
http://localhost:3000/card/default/[UID].
The compose file in this repository is docker-compose.yaml.
The container reads credentials from .env at runtime, and the file is not copied into the image.
By default, profile cache and image cache are persisted with Docker named volumes, which avoids common Linux bind-mount permission issues while keeping the container on a non-root user.
If you want to use host bind mounts instead, prepare the directories on the host before starting the container:
mkdir -p database cache
sudo chown -R 100:101 database cacheThe container runs as UID/GID 100:101.
-
Clone this repository.
-
Install dependencies:
npm install
-
If you want to use the default
legacyprovider, create.env:uid= username= password= PORT=3000
If you only plan to test
web-v2-experimental, the legacy credentials can be omitted. -
Start the service:
npm run start
-
Open
http://localhost:3000/card/default/[UID].
- Profile and token cache are stored in
database/malody.db - Downloaded images are cached in
cache/ - The datastore is schema-versioned
- On the first migration from the old cache schema, the project creates
database/malody.db.bak-v1 - Cache records are isolated by provider so
legacyandweb-v2-experimentaldo not overwrite each other
By default, cached profile and image data are reused for 2 hours.
Run the automated test suite with:
npm testCurrent tests cover:
- Basic route behavior
- Invalid parameter handling
- Card route cache headers
- Experimental provider routing
- New web API normalization
- Datastore migration and provider isolation
This project is licensed under the MIT License. See LICENSE.