nnnotes 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nnnotes-0.1.0/LICENSE +21 -0
- nnnotes-0.1.0/PKG-INFO +200 -0
- nnnotes-0.1.0/README.en.md +170 -0
- nnnotes-0.1.0/README.md +132 -0
- nnnotes-0.1.0/pyproject.toml +50 -0
- nnnotes-0.1.0/setup.cfg +4 -0
- nnnotes-0.1.0/src/nnnotes/__init__.py +7 -0
- nnnotes-0.1.0/src/nnnotes/__main__.py +4 -0
- nnnotes-0.1.0/src/nnnotes/acb.py +190 -0
- nnnotes-0.1.0/src/nnnotes/addressables.py +413 -0
- nnnotes-0.1.0/src/nnnotes/adv.py +243 -0
- nnnotes-0.1.0/src/nnnotes/advcommand.py +29 -0
- nnnotes-0.1.0/src/nnnotes/advmedia.py +178 -0
- nnnotes-0.1.0/src/nnnotes/advscene.py +113 -0
- nnnotes-0.1.0/src/nnnotes/advui.py +1154 -0
- nnnotes-0.1.0/src/nnnotes/advvideo.py +684 -0
- nnnotes-0.1.0/src/nnnotes/atoms/__init__.py +151 -0
- nnnotes-0.1.0/src/nnnotes/atoms/astc.py +52 -0
- nnnotes-0.1.0/src/nnnotes/atoms/gltf.py +290 -0
- nnnotes-0.1.0/src/nnnotes/atoms/mesh.py +289 -0
- nnnotes-0.1.0/src/nnnotes/atoms/png.py +28 -0
- nnnotes-0.1.0/src/nnnotes/atoms/reader.py +269 -0
- nnnotes-0.1.0/src/nnnotes/atoms/sniff.py +198 -0
- nnnotes-0.1.0/src/nnnotes/atoms/sprite.py +236 -0
- nnnotes-0.1.0/src/nnnotes/atoms/texture.py +80 -0
- nnnotes-0.1.0/src/nnnotes/cache.py +289 -0
- nnnotes-0.1.0/src/nnnotes/catalog.py +373 -0
- nnnotes-0.1.0/src/nnnotes/catalogdb.py +457 -0
- nnnotes-0.1.0/src/nnnotes/census.py +276 -0
- nnnotes-0.1.0/src/nnnotes/cli.py +744 -0
- nnnotes-0.1.0/src/nnnotes/cli_assets.py +1539 -0
- nnnotes-0.1.0/src/nnnotes/config.py +238 -0
- nnnotes-0.1.0/src/nnnotes/contract.py +497 -0
- nnnotes-0.1.0/src/nnnotes/cri.py +371 -0
- nnnotes-0.1.0/src/nnnotes/crikey.py +71 -0
- nnnotes-0.1.0/src/nnnotes/crilips.py +265 -0
- nnnotes-0.1.0/src/nnnotes/cristages.py +558 -0
- nnnotes-0.1.0/src/nnnotes/deckdata.py +462 -0
- nnnotes-0.1.0/src/nnnotes/export.py +1462 -0
- nnnotes-0.1.0/src/nnnotes/gameapi.py +318 -0
- nnnotes-0.1.0/src/nnnotes/jsonio.py +98 -0
- nnnotes-0.1.0/src/nnnotes/languages.py +44 -0
- nnnotes-0.1.0/src/nnnotes/layout.py +596 -0
- nnnotes-0.1.0/src/nnnotes/link.py +418 -0
- nnnotes-0.1.0/src/nnnotes/live.py +115 -0
- nnnotes-0.1.0/src/nnnotes/live2d.py +235 -0
- nnnotes-0.1.0/src/nnnotes/liveaudio.py +331 -0
- nnnotes-0.1.0/src/nnnotes/livenotes.py +291 -0
- nnnotes-0.1.0/src/nnnotes/liveoptions.py +250 -0
- nnnotes-0.1.0/src/nnnotes/livescene.py +450 -0
- nnnotes-0.1.0/src/nnnotes/liveui.py +328 -0
- nnnotes-0.1.0/src/nnnotes/master.py +251 -0
- nnnotes-0.1.0/src/nnnotes/modelstages.py +424 -0
- nnnotes-0.1.0/src/nnnotes/motion.py +131 -0
- nnnotes-0.1.0/src/nnnotes/objexport.py +1564 -0
- nnnotes-0.1.0/src/nnnotes/orchestrate.py +630 -0
- nnnotes-0.1.0/src/nnnotes/plan.py +218 -0
- nnnotes-0.1.0/src/nnnotes/player.py +392 -0
- nnnotes-0.1.0/src/nnnotes/room.py +391 -0
- nnnotes-0.1.0/src/nnnotes/score.py +1139 -0
- nnnotes-0.1.0/src/nnnotes/shader.py +217 -0
- nnnotes-0.1.0/src/nnnotes/spot.py +201 -0
- nnnotes-0.1.0/src/nnnotes/stages.py +285 -0
- nnnotes-0.1.0/src/nnnotes/store.py +518 -0
- nnnotes-0.1.0/src/nnnotes/story.py +142 -0
- nnnotes-0.1.0/src/nnnotes/storyfonts.py +1258 -0
- nnnotes-0.1.0/src/nnnotes/storyhost.py +1190 -0
- nnnotes-0.1.0/src/nnnotes/storysite.py +662 -0
- nnnotes-0.1.0/src/nnnotes/storyvoices.py +102 -0
- nnnotes-0.1.0/src/nnnotes/textstyle.py +355 -0
- nnnotes-0.1.0/src/nnnotes/tmpfont.py +636 -0
- nnnotes-0.1.0/src/nnnotes/typetrees/6000.3.12f1.json +19 -0
- nnnotes-0.1.0/src/nnnotes/unity.py +368 -0
- nnnotes-0.1.0/src/nnnotes/viewrules.json +441 -0
- nnnotes-0.1.0/src/nnnotes/views.py +966 -0
- nnnotes-0.1.0/src/nnnotes/voices.py +1363 -0
- nnnotes-0.1.0/src/nnnotes/web.py +1624 -0
- nnnotes-0.1.0/src/nnnotes/webaudio.py +14 -0
- nnnotes-0.1.0/src/nnnotes/webmodel.py +397 -0
- nnnotes-0.1.0/src/nnnotes.egg-info/PKG-INFO +200 -0
- nnnotes-0.1.0/src/nnnotes.egg-info/SOURCES.txt +138 -0
- nnnotes-0.1.0/src/nnnotes.egg-info/dependency_links.txt +1 -0
- nnnotes-0.1.0/src/nnnotes.egg-info/entry_points.txt +2 -0
- nnnotes-0.1.0/src/nnnotes.egg-info/requires.txt +15 -0
- nnnotes-0.1.0/src/nnnotes.egg-info/top_level.txt +1 -0
- nnnotes-0.1.0/tests/test_advvideo.py +522 -0
- nnnotes-0.1.0/tests/test_atom_eval.py +231 -0
- nnnotes-0.1.0/tests/test_atoms_mesh.py +357 -0
- nnnotes-0.1.0/tests/test_atoms_sprite.py +235 -0
- nnnotes-0.1.0/tests/test_atoms_texture.py +272 -0
- nnnotes-0.1.0/tests/test_blob_memo.py +101 -0
- nnnotes-0.1.0/tests/test_cache.py +107 -0
- nnnotes-0.1.0/tests/test_catalog.py +206 -0
- nnnotes-0.1.0/tests/test_catalog_lazy.py +194 -0
- nnnotes-0.1.0/tests/test_catalogdb.py +320 -0
- nnnotes-0.1.0/tests/test_census.py +211 -0
- nnnotes-0.1.0/tests/test_cli.py +372 -0
- nnnotes-0.1.0/tests/test_cli_assets.py +1007 -0
- nnnotes-0.1.0/tests/test_config.py +163 -0
- nnnotes-0.1.0/tests/test_contract.py +240 -0
- nnnotes-0.1.0/tests/test_crilips.py +198 -0
- nnnotes-0.1.0/tests/test_cristages.py +554 -0
- nnnotes-0.1.0/tests/test_deckdata.py +461 -0
- nnnotes-0.1.0/tests/test_gameapi.py +393 -0
- nnnotes-0.1.0/tests/test_goldens.py +125 -0
- nnnotes-0.1.0/tests/test_jsonio.py +45 -0
- nnnotes-0.1.0/tests/test_layout.py +363 -0
- nnnotes-0.1.0/tests/test_link.py +279 -0
- nnnotes-0.1.0/tests/test_live_options.py +298 -0
- nnnotes-0.1.0/tests/test_live_options_web.py +166 -0
- nnnotes-0.1.0/tests/test_master.py +132 -0
- nnnotes-0.1.0/tests/test_mesh_texture_guards.py +94 -0
- nnnotes-0.1.0/tests/test_modelstages.py +422 -0
- nnnotes-0.1.0/tests/test_objexport.py +1016 -0
- nnnotes-0.1.0/tests/test_orchestrate.py +305 -0
- nnnotes-0.1.0/tests/test_pipeline.py +163 -0
- nnnotes-0.1.0/tests/test_plan.py +149 -0
- nnnotes-0.1.0/tests/test_player.py +140 -0
- nnnotes-0.1.0/tests/test_readsets.py +442 -0
- nnnotes-0.1.0/tests/test_regions.py +246 -0
- nnnotes-0.1.0/tests/test_repo.py +50 -0
- nnnotes-0.1.0/tests/test_room.py +204 -0
- nnnotes-0.1.0/tests/test_sniff.py +137 -0
- nnnotes-0.1.0/tests/test_speed_exact.py +521 -0
- nnnotes-0.1.0/tests/test_spot.py +159 -0
- nnnotes-0.1.0/tests/test_stages.py +274 -0
- nnnotes-0.1.0/tests/test_store.py +181 -0
- nnnotes-0.1.0/tests/test_story_closure.py +137 -0
- nnnotes-0.1.0/tests/test_story_fonts.py +842 -0
- nnnotes-0.1.0/tests/test_story_host.py +474 -0
- nnnotes-0.1.0/tests/test_story_kinds.py +100 -0
- nnnotes-0.1.0/tests/test_story_site.py +510 -0
- nnnotes-0.1.0/tests/test_story_ui.py +551 -0
- nnnotes-0.1.0/tests/test_textstyle.py +253 -0
- nnnotes-0.1.0/tests/test_typetrees.py +382 -0
- nnnotes-0.1.0/tests/test_views.py +749 -0
- nnnotes-0.1.0/tests/test_voices.py +756 -0
- nnnotes-0.1.0/tests/test_voices_story.py +541 -0
- nnnotes-0.1.0/tests/test_web.py +134 -0
- nnnotes-0.1.0/tests/test_webmodel.py +447 -0
nnnotes-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MetaMiku, emptysekai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
nnnotes-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nnnotes
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Offline data toolkit for BanG Dream! Our Notes game files: catalogs, bundles, master data, stories, Live2D, audio and live charts
|
|
5
|
+
Author: MetaMiku, emptysekai
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/MetaSekaiLab/nnnotes
|
|
8
|
+
Project-URL: Source, https://github.com/MetaSekaiLab/nnnotes
|
|
9
|
+
Project-URL: Issues, https://github.com/MetaSekaiLab/nnnotes/issues
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Topic :: Multimedia
|
|
13
|
+
Requires-Python: >=3.11
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: UnityPy>=1.25
|
|
17
|
+
Requires-Dist: numpy>=2.0
|
|
18
|
+
Requires-Dist: Pillow>=10.0
|
|
19
|
+
Requires-Dist: pycryptodome>=3.20
|
|
20
|
+
Requires-Dist: grpcio>=1.49.1
|
|
21
|
+
Provides-Extra: test
|
|
22
|
+
Requires-Dist: pytest>=8; extra == "test"
|
|
23
|
+
Requires-Dist: pyflakes>=3.2; extra == "test"
|
|
24
|
+
Requires-Dist: jsonschema>=4.18; extra == "test"
|
|
25
|
+
Provides-Extra: fonts
|
|
26
|
+
Requires-Dist: fonttools>=4.50; extra == "fonts"
|
|
27
|
+
Requires-Dist: freetype-py>=2.5; extra == "fonts"
|
|
28
|
+
Requires-Dist: scipy>=1.13; extra == "fonts"
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# nnnotes?!
|
|
32
|
+
|
|
33
|
+
[简体中文](https://github.com/MetaSekaiLab/nnnotes/blob/main/README.md) | [English](https://github.com/MetaSekaiLab/nnnotes/blob/main/README.en.md)
|
|
34
|
+
|
|
35
|
+
nnnotes is an offline data toolkit for the game files of BanG Dream! Our Notes: it reads Addressables catalogs,
|
|
36
|
+
downloads and decrypts asset bundles, downloads and decodes master data, and exports stories, Live2D models, spots,
|
|
37
|
+
shaders, CRI audio and live charts as structured JSON and common file formats. The chart export is the data that
|
|
38
|
+
[ournotes-player](https://github.com/empty-sekai/ournotes-player) reads. The naming was inspired by [mos9527/sssekai](https://github.com/mos9527/sssekai).
|
|
39
|
+
|
|
40
|
+
This is an unofficial fan project, not affiliated with the game's developer or operator. The repository contains no
|
|
41
|
+
game assets, keys or server addresses: users supply the game files, the keys needed for decryption and the server
|
|
42
|
+
addresses in their own configuration, and the exports stay in local directories the user chooses.
|
|
43
|
+
|
|
44
|
+
## Features
|
|
45
|
+
|
|
46
|
+
| Command | Input | Output |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| `catalog` | the region's catalog | addressable keys (optionally by prefix) |
|
|
49
|
+
| `browse` | the configured regions' catalogs | a local web page to browse catalogs and bundles (`--host` / `--port`) |
|
|
50
|
+
| `pull` | addressable keys | every bundle of each key's dependency closure, decrypted into the local cache |
|
|
51
|
+
| `servers` | the bootstrap API root `[bootstrap] api` | the game API's server list: each region's name, area id and CDN / API roots (the roots only with `--show-hosts`) |
|
|
52
|
+
| `master version` | region | the master data version and resource version the region serves now (anonymous game API call) |
|
|
53
|
+
| `master download` | master data version, or `--latest` (the region's current one) | that version's `MasterManifest.json` and every `.bin` file (SHA-256 checked) |
|
|
54
|
+
| `master decode` | master data `.bin` files or directories | one JSON per table (Rijndael-256 CBC decryption + gzip) |
|
|
55
|
+
| `adv` | episode ID | `episode.json`: command list, lines in five languages, voice / sound / video index |
|
|
56
|
+
| `story` | episode ID | a full story directory: episode, every Live2D model, audio, stage scene and shaders, story UI, frames / particle effects / post effects / stills / talk windows / chat assets, videos (WebM) |
|
|
57
|
+
| `live2d` | model key or model id | a Live2D (Cubism) runtime directory: moc3, textures, motion3, physics, expressions, prefab parameters |
|
|
58
|
+
| `spot` | spot ID | `spot.json` + Spine characters + the room as `room.glb` + shaders |
|
|
59
|
+
| `room` | background prefab key | the room model (binary glTF) |
|
|
60
|
+
| `shader` | key or APK bundles | every platform variant of the shaders (GLSL ES and others) with an index |
|
|
61
|
+
| `audio` | CRI cue sheet | one audio file per cue (FLAC / Ogg / WAV) + cue metadata |
|
|
62
|
+
| `crikey` | APK | the CRI HCA keycode from the game's boot data (shows whether it was found; can write a `.hcakey`) |
|
|
63
|
+
| `player` | APK | render-related global settings (color space, quality levels, renderers) as JSON |
|
|
64
|
+
| `live` | music ID + difficulty | a full chart directory: chart and runtime notes, 3D scene, note and effect assets, BGM and sounds, sound routing |
|
|
65
|
+
| `web` | `--pair music:difficulty` (repeatable) or `--all`; `--live2d model` (repeatable) or `--all-live2d`; `--story episode` (repeatable) or `--all-stories`; `--region region` (repeatable) or `--all-regions` | an ournotes-player static site: shared player + per-chart / per-model / per-episode manifests + content-addressed assets; one site can serve several regions, with listing texts in five languages; a story's interface texts are grouped by language, with TextMeshPro font assets generated from open fonts (the game's fonts with `--fonts game`) |
|
|
66
|
+
| `deck-data` | master data files (`--master-files` directory or `--apk-master`) | one JSON file for deck-building tools: every chart's runtime notes, skill events and fever ranges, and the master data tables about cards, skills, bonuses, scores and events ([format](https://github.com/MetaSekaiLab/nnnotes/blob/main/docs/deck-data.md)) |
|
|
67
|
+
|
|
68
|
+
Export conventions:
|
|
69
|
+
|
|
70
|
+
- Commands that write files take the output path with `-o` (required); `web` takes the site directory as a
|
|
71
|
+
positional argument.
|
|
72
|
+
- JSON is always UTF-8 with LF line endings; infinity is written as `1e999`.
|
|
73
|
+
- Exports are deterministic for a given installation: the same input with the same versions of nnnotes, its Python
|
|
74
|
+
dependencies (UnityPy, Pillow, numpy, ...) and the external tools (vgmstream, FFmpeg) gives byte-identical files.
|
|
75
|
+
Other versions can encode the same content into other bytes: PNG files written by another Pillow version can
|
|
76
|
+
differ in their bytes while their pixels are equal.
|
|
77
|
+
- Values keep Unity's serialized values and field names (`m_LocalPosition`, `_bandIDs`, ...), so they can be
|
|
78
|
+
compared with the game data.
|
|
79
|
+
- Textures are exported as PNG, shaders keep the game's own compiled programs, audio is decoded from the CRI formats
|
|
80
|
+
to common formats.
|
|
81
|
+
|
|
82
|
+
## Status
|
|
83
|
+
|
|
84
|
+
Based on all data of the Taiwan server, version 1.0.1 (zh-Hant):
|
|
85
|
+
|
|
86
|
+
| Part | Status |
|
|
87
|
+
|---|---|
|
|
88
|
+
| catalog / bundle decryption / dependency closure | working |
|
|
89
|
+
| master data decoding | working |
|
|
90
|
+
| stories, `adv` | 946 / 946 episodes |
|
|
91
|
+
| stories, `story` (full directory) | 946 / 946 episodes have all their resources in the catalog and of supported kinds (the resource closure equals the game's own per-episode download list); 759 exported one by one, the other 187 (with frames, effects, post effects, stills and the like) not yet one by one |
|
|
92
|
+
| Live2D models | 239 / 239 (every model of the catalog; episodes use 185 of them) |
|
|
93
|
+
| CRI audio | 681 / 681 cue sheets |
|
|
94
|
+
| charts, `live` | 336 / 336 (music, difficulty) pairs |
|
|
95
|
+
| web site, `web` | 336 / 336 charts, 239 / 239 Live2D models, 946 / 946 story episodes (two full builds in English without audio are byte-identical and 946 / 946 pass the data validation; a 27-episode sample in five languages with AAC audio is likewise identical across two builds and valid) |
|
|
96
|
+
| spots, `spot` / `room` | one spot verified, the others not individually checked |
|
|
97
|
+
| other regions (en / kr) and languages | checked: the regions serve the same catalog for a language and the same bundles, and the keys are shared; the master tables the charts use are the same in the three regions, and the text tables have all five languages; the chart exports checked match the Taiwan server's. A full multi-region site build is not verified yet |
|
|
98
|
+
|
|
99
|
+
## Requirements
|
|
100
|
+
|
|
101
|
+
- Python 3.11+, 3.13 recommended (a `web` build reads and writes a lot of JSON, and the standard library encodes
|
|
102
|
+
JSON faster on 3.13); `pip install nnnotes` (for development `pip install -e .` in the repository)
|
|
103
|
+
- the game's `base.apk`: APK-local bundles, the CRI keycode, boot settings. `player`, `story`, `live` and `web` read
|
|
104
|
+
MonoBehaviours of its boot data with type trees that ship with nnnotes; supported now: game version 1.0.1
|
|
105
|
+
(Unity 6000.3.12f1). With an APK of another version whose classes do not match, these commands stop with an
|
|
106
|
+
error naming the class, the game version and the Unity version
|
|
107
|
+
- a decoded master data directory (from `master download` + `master decode`): needed by `adv`, `story`, `spot`,
|
|
108
|
+
`live` and the charts of `web`; the Live2D models of `web` use it only for their character names (optional)
|
|
109
|
+
- external tools: [vgmstream](https://vgmstream.org/) (CRI HCA decoding), [FFmpeg](https://ffmpeg.org/)
|
|
110
|
+
(transcoding, including the WebM muxing and Opus audio of story videos); `web` also needs Node.js 20+ and a built
|
|
111
|
+
ournotes-player
|
|
112
|
+
|
|
113
|
+
## Configuration
|
|
114
|
+
|
|
115
|
+
The code contains no keys, server addresses or default paths. Settings are read in this order, later sources
|
|
116
|
+
overriding earlier ones:
|
|
117
|
+
|
|
118
|
+
1. config file: `--config <file>`, else `NNNOTES_CONFIG`, else `nnnotes.toml` in the working directory
|
|
119
|
+
2. environment variables: `NNNOTES_<SECTION>_<KEY>` (e.g. `NNNOTES_BUNDLE_KEY`, `NNNOTES_SERVERS_TW_CDN`)
|
|
120
|
+
3. command-line flags: `--region`, `--language`, `--catalog`, `--cache`, `--master`, `--apk`, `--ffmpeg`,
|
|
121
|
+
`--vgmstream`, `--node` go before the command name; `--player` is an option of `web`
|
|
122
|
+
|
|
123
|
+
Copy [`nnnotes.example.toml`](https://github.com/MetaSekaiLab/nnnotes/blob/main/nnnotes.example.toml) to `nnnotes.toml` and fill it in. The settings are: the bundle
|
|
124
|
+
key and nonce seed, the master data key and IV, the region in use (`[catalog] region`) and the catalog language
|
|
125
|
+
(`[catalog] language`), the CDN base and API root of each region (`cdn`, `api` of `[servers.<region>]`), the client
|
|
126
|
+
version (`[client] version`; unset: the APK's versionName), optionally the bootstrap API root (`[bootstrap] api`, for
|
|
127
|
+
`servers`), and the paths of the cache, the APK, the master data directory, ournotes-player and vgmstream / FFmpeg /
|
|
128
|
+
Node.js (the three tools are looked up on `PATH` when unset). All values come from the game client you own.
|
|
129
|
+
|
|
130
|
+
A missing or malformed setting stops the command with exit status 2 and one line naming the TOML key, the
|
|
131
|
+
environment variable and the flag; no setting value is printed. `nnnotes.toml` is in `.gitignore`; do not commit it.
|
|
132
|
+
|
|
133
|
+
See [docs/configuration.md](https://github.com/MetaSekaiLab/nnnotes/blob/main/docs/configuration.md) for the full reference.
|
|
134
|
+
|
|
135
|
+
## Examples
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
nnnotes catalog --prefix Live/MusicScore/ --limit 20
|
|
139
|
+
nnnotes browse --port 8000
|
|
140
|
+
nnnotes pull Live/MusicScore/0001/0001_03
|
|
141
|
+
nnnotes master version
|
|
142
|
+
nnnotes master download --latest -o work/master-bin
|
|
143
|
+
nnnotes master decode work/master-bin -o work/master
|
|
144
|
+
nnnotes --master work/master adv 10462 -o out/adv_10462.json
|
|
145
|
+
nnnotes story 10462 -o out/story_10462
|
|
146
|
+
nnnotes live 100001 --difficulty expert -o out/live_100001
|
|
147
|
+
nnnotes web out/site --all --player <ournotes-player dir> --workers 5
|
|
148
|
+
nnnotes web out/site --pair 100001:expert --pair 100001:hard --player <ournotes-player dir>
|
|
149
|
+
nnnotes web out/site --all --region tw --region en --region kr --player <ournotes-player dir>
|
|
150
|
+
nnnotes web out/site --live2d adv_live2d_rana_003_casual_spring_01 --player <ournotes-player dir>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`web` builds incrementally: charts and models whose manifest exists are skipped (`--force` rebuilds them) and assets
|
|
154
|
+
no longer referenced are removed. Common options:
|
|
155
|
+
|
|
156
|
+
- `--format aac|opus|vorbis|mp3|flac`: BGM format, default AAC; `--no-audio`: no audio files
|
|
157
|
+
- `--band` / `--leader-card`: the band of the LightWeight background and the start timeline; default: the band of
|
|
158
|
+
the music's first vocal character
|
|
159
|
+
- `--workers`: parallel music processes (default a quarter of the CPUs, up to 8) and model processes (default up
|
|
160
|
+
to 4); `--read-workers`: chart read sets at a time (Node.js processes; default half the CPUs, up to 16); `--tmp`:
|
|
161
|
+
temporary build directory (default `<site>.tmp`)
|
|
162
|
+
- `--live2d MODEL` (model id or key, repeatable) / `--all-live2d`: add Live2D models (every model of the catalog);
|
|
163
|
+
charts and models can be added in the same run
|
|
164
|
+
- `--region REGION` (repeatable) / `--all-regions`: the regions the site serves (default: `[catalog] region`);
|
|
165
|
+
each region's master data is `[servers.<region>] master`. Regions with the same chart data share one manifest;
|
|
166
|
+
the chart list page switches region and language with `?region=&lang=`
|
|
167
|
+
- `--player-only`: rewrite the player files, `charts.json` and `models.json` only; `--reingest-json`: store every
|
|
168
|
+
chart's and model's JSON files again under the current rules
|
|
169
|
+
|
|
170
|
+
See [docs/commands.md](https://github.com/MetaSekaiLab/nnnotes/blob/main/docs/commands.md) for every command's options and output layout.
|
|
171
|
+
|
|
172
|
+
## Architecture
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
settings (TOML / environment / flags)
|
|
176
|
+
└─ access addressables (catalog parsing, bundle decryption, local browser)
|
|
177
|
+
catalog (dependency closures, remote and APK bundles, local cache)
|
|
178
|
+
master (master data download and decoding)
|
|
179
|
+
gameapi (anonymous game API calls: current master data version, server list)
|
|
180
|
+
└─ reading unity (UnityPy type trees and TextAssets)
|
|
181
|
+
export (prefabs / components / references resolved to JSON, textures and shaders alongside)
|
|
182
|
+
shader, textstyle (text layout and style), tmpfont (TextMesh Pro fonts), player (boot settings), cri + crikey (CRI audio)
|
|
183
|
+
└─ content stories: adv, advscene, advmedia (frames / effects / post effects / stills / chat),
|
|
184
|
+
advvideo (USM videos), advui, story
|
|
185
|
+
Live2D: live2d, motion
|
|
186
|
+
spots: spot, room
|
|
187
|
+
charts: score (chart parsing and a reimplementation of the game's chart converter),
|
|
188
|
+
livescene, livenotes, liveui, liveaudio, live
|
|
189
|
+
site: web, webmodel (ournotes-player data)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Every JSON file is written by one writer (`jsonio`), so encoding, line endings and number formatting are the same
|
|
193
|
+
everywhere.
|
|
194
|
+
|
|
195
|
+
See [docs/performance.md](https://github.com/MetaSekaiLab/nnnotes/blob/main/docs/performance.md) for where a
|
|
196
|
+
`web` build spends its time and which parts of it run in compiled code.
|
|
197
|
+
|
|
198
|
+
## License
|
|
199
|
+
|
|
200
|
+
MIT, see [LICENSE](https://github.com/MetaSekaiLab/nnnotes/blob/main/LICENSE).
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# nnnotes?!
|
|
2
|
+
|
|
3
|
+
[简体中文](https://github.com/MetaSekaiLab/nnnotes/blob/main/README.md) | [English](https://github.com/MetaSekaiLab/nnnotes/blob/main/README.en.md)
|
|
4
|
+
|
|
5
|
+
nnnotes is an offline data toolkit for the game files of BanG Dream! Our Notes: it reads Addressables catalogs,
|
|
6
|
+
downloads and decrypts asset bundles, downloads and decodes master data, and exports stories, Live2D models, spots,
|
|
7
|
+
shaders, CRI audio and live charts as structured JSON and common file formats. The chart export is the data that
|
|
8
|
+
[ournotes-player](https://github.com/empty-sekai/ournotes-player) reads. The naming was inspired by [mos9527/sssekai](https://github.com/mos9527/sssekai).
|
|
9
|
+
|
|
10
|
+
This is an unofficial fan project, not affiliated with the game's developer or operator. The repository contains no
|
|
11
|
+
game assets, keys or server addresses: users supply the game files, the keys needed for decryption and the server
|
|
12
|
+
addresses in their own configuration, and the exports stay in local directories the user chooses.
|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
|
|
16
|
+
| Command | Input | Output |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| `catalog` | the region's catalog | addressable keys (optionally by prefix) |
|
|
19
|
+
| `browse` | the configured regions' catalogs | a local web page to browse catalogs and bundles (`--host` / `--port`) |
|
|
20
|
+
| `pull` | addressable keys | every bundle of each key's dependency closure, decrypted into the local cache |
|
|
21
|
+
| `servers` | the bootstrap API root `[bootstrap] api` | the game API's server list: each region's name, area id and CDN / API roots (the roots only with `--show-hosts`) |
|
|
22
|
+
| `master version` | region | the master data version and resource version the region serves now (anonymous game API call) |
|
|
23
|
+
| `master download` | master data version, or `--latest` (the region's current one) | that version's `MasterManifest.json` and every `.bin` file (SHA-256 checked) |
|
|
24
|
+
| `master decode` | master data `.bin` files or directories | one JSON per table (Rijndael-256 CBC decryption + gzip) |
|
|
25
|
+
| `adv` | episode ID | `episode.json`: command list, lines in five languages, voice / sound / video index |
|
|
26
|
+
| `story` | episode ID | a full story directory: episode, every Live2D model, audio, stage scene and shaders, story UI, frames / particle effects / post effects / stills / talk windows / chat assets, videos (WebM) |
|
|
27
|
+
| `live2d` | model key or model id | a Live2D (Cubism) runtime directory: moc3, textures, motion3, physics, expressions, prefab parameters |
|
|
28
|
+
| `spot` | spot ID | `spot.json` + Spine characters + the room as `room.glb` + shaders |
|
|
29
|
+
| `room` | background prefab key | the room model (binary glTF) |
|
|
30
|
+
| `shader` | key or APK bundles | every platform variant of the shaders (GLSL ES and others) with an index |
|
|
31
|
+
| `audio` | CRI cue sheet | one audio file per cue (FLAC / Ogg / WAV) + cue metadata |
|
|
32
|
+
| `crikey` | APK | the CRI HCA keycode from the game's boot data (shows whether it was found; can write a `.hcakey`) |
|
|
33
|
+
| `player` | APK | render-related global settings (color space, quality levels, renderers) as JSON |
|
|
34
|
+
| `live` | music ID + difficulty | a full chart directory: chart and runtime notes, 3D scene, note and effect assets, BGM and sounds, sound routing |
|
|
35
|
+
| `web` | `--pair music:difficulty` (repeatable) or `--all`; `--live2d model` (repeatable) or `--all-live2d`; `--story episode` (repeatable) or `--all-stories`; `--region region` (repeatable) or `--all-regions` | an ournotes-player static site: shared player + per-chart / per-model / per-episode manifests + content-addressed assets; one site can serve several regions, with listing texts in five languages; a story's interface texts are grouped by language, with TextMeshPro font assets generated from open fonts (the game's fonts with `--fonts game`) |
|
|
36
|
+
| `deck-data` | master data files (`--master-files` directory or `--apk-master`) | one JSON file for deck-building tools: every chart's runtime notes, skill events and fever ranges, and the master data tables about cards, skills, bonuses, scores and events ([format](https://github.com/MetaSekaiLab/nnnotes/blob/main/docs/deck-data.md)) |
|
|
37
|
+
|
|
38
|
+
Export conventions:
|
|
39
|
+
|
|
40
|
+
- Commands that write files take the output path with `-o` (required); `web` takes the site directory as a
|
|
41
|
+
positional argument.
|
|
42
|
+
- JSON is always UTF-8 with LF line endings; infinity is written as `1e999`.
|
|
43
|
+
- Exports are deterministic for a given installation: the same input with the same versions of nnnotes, its Python
|
|
44
|
+
dependencies (UnityPy, Pillow, numpy, ...) and the external tools (vgmstream, FFmpeg) gives byte-identical files.
|
|
45
|
+
Other versions can encode the same content into other bytes: PNG files written by another Pillow version can
|
|
46
|
+
differ in their bytes while their pixels are equal.
|
|
47
|
+
- Values keep Unity's serialized values and field names (`m_LocalPosition`, `_bandIDs`, ...), so they can be
|
|
48
|
+
compared with the game data.
|
|
49
|
+
- Textures are exported as PNG, shaders keep the game's own compiled programs, audio is decoded from the CRI formats
|
|
50
|
+
to common formats.
|
|
51
|
+
|
|
52
|
+
## Status
|
|
53
|
+
|
|
54
|
+
Based on all data of the Taiwan server, version 1.0.1 (zh-Hant):
|
|
55
|
+
|
|
56
|
+
| Part | Status |
|
|
57
|
+
|---|---|
|
|
58
|
+
| catalog / bundle decryption / dependency closure | working |
|
|
59
|
+
| master data decoding | working |
|
|
60
|
+
| stories, `adv` | 946 / 946 episodes |
|
|
61
|
+
| stories, `story` (full directory) | 946 / 946 episodes have all their resources in the catalog and of supported kinds (the resource closure equals the game's own per-episode download list); 759 exported one by one, the other 187 (with frames, effects, post effects, stills and the like) not yet one by one |
|
|
62
|
+
| Live2D models | 239 / 239 (every model of the catalog; episodes use 185 of them) |
|
|
63
|
+
| CRI audio | 681 / 681 cue sheets |
|
|
64
|
+
| charts, `live` | 336 / 336 (music, difficulty) pairs |
|
|
65
|
+
| web site, `web` | 336 / 336 charts, 239 / 239 Live2D models, 946 / 946 story episodes (two full builds in English without audio are byte-identical and 946 / 946 pass the data validation; a 27-episode sample in five languages with AAC audio is likewise identical across two builds and valid) |
|
|
66
|
+
| spots, `spot` / `room` | one spot verified, the others not individually checked |
|
|
67
|
+
| other regions (en / kr) and languages | checked: the regions serve the same catalog for a language and the same bundles, and the keys are shared; the master tables the charts use are the same in the three regions, and the text tables have all five languages; the chart exports checked match the Taiwan server's. A full multi-region site build is not verified yet |
|
|
68
|
+
|
|
69
|
+
## Requirements
|
|
70
|
+
|
|
71
|
+
- Python 3.11+, 3.13 recommended (a `web` build reads and writes a lot of JSON, and the standard library encodes
|
|
72
|
+
JSON faster on 3.13); `pip install nnnotes` (for development `pip install -e .` in the repository)
|
|
73
|
+
- the game's `base.apk`: APK-local bundles, the CRI keycode, boot settings. `player`, `story`, `live` and `web` read
|
|
74
|
+
MonoBehaviours of its boot data with type trees that ship with nnnotes; supported now: game version 1.0.1
|
|
75
|
+
(Unity 6000.3.12f1). With an APK of another version whose classes do not match, these commands stop with an
|
|
76
|
+
error naming the class, the game version and the Unity version
|
|
77
|
+
- a decoded master data directory (from `master download` + `master decode`): needed by `adv`, `story`, `spot`,
|
|
78
|
+
`live` and the charts of `web`; the Live2D models of `web` use it only for their character names (optional)
|
|
79
|
+
- external tools: [vgmstream](https://vgmstream.org/) (CRI HCA decoding), [FFmpeg](https://ffmpeg.org/)
|
|
80
|
+
(transcoding, including the WebM muxing and Opus audio of story videos); `web` also needs Node.js 20+ and a built
|
|
81
|
+
ournotes-player
|
|
82
|
+
|
|
83
|
+
## Configuration
|
|
84
|
+
|
|
85
|
+
The code contains no keys, server addresses or default paths. Settings are read in this order, later sources
|
|
86
|
+
overriding earlier ones:
|
|
87
|
+
|
|
88
|
+
1. config file: `--config <file>`, else `NNNOTES_CONFIG`, else `nnnotes.toml` in the working directory
|
|
89
|
+
2. environment variables: `NNNOTES_<SECTION>_<KEY>` (e.g. `NNNOTES_BUNDLE_KEY`, `NNNOTES_SERVERS_TW_CDN`)
|
|
90
|
+
3. command-line flags: `--region`, `--language`, `--catalog`, `--cache`, `--master`, `--apk`, `--ffmpeg`,
|
|
91
|
+
`--vgmstream`, `--node` go before the command name; `--player` is an option of `web`
|
|
92
|
+
|
|
93
|
+
Copy [`nnnotes.example.toml`](https://github.com/MetaSekaiLab/nnnotes/blob/main/nnnotes.example.toml) to `nnnotes.toml` and fill it in. The settings are: the bundle
|
|
94
|
+
key and nonce seed, the master data key and IV, the region in use (`[catalog] region`) and the catalog language
|
|
95
|
+
(`[catalog] language`), the CDN base and API root of each region (`cdn`, `api` of `[servers.<region>]`), the client
|
|
96
|
+
version (`[client] version`; unset: the APK's versionName), optionally the bootstrap API root (`[bootstrap] api`, for
|
|
97
|
+
`servers`), and the paths of the cache, the APK, the master data directory, ournotes-player and vgmstream / FFmpeg /
|
|
98
|
+
Node.js (the three tools are looked up on `PATH` when unset). All values come from the game client you own.
|
|
99
|
+
|
|
100
|
+
A missing or malformed setting stops the command with exit status 2 and one line naming the TOML key, the
|
|
101
|
+
environment variable and the flag; no setting value is printed. `nnnotes.toml` is in `.gitignore`; do not commit it.
|
|
102
|
+
|
|
103
|
+
See [docs/configuration.md](https://github.com/MetaSekaiLab/nnnotes/blob/main/docs/configuration.md) for the full reference.
|
|
104
|
+
|
|
105
|
+
## Examples
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
nnnotes catalog --prefix Live/MusicScore/ --limit 20
|
|
109
|
+
nnnotes browse --port 8000
|
|
110
|
+
nnnotes pull Live/MusicScore/0001/0001_03
|
|
111
|
+
nnnotes master version
|
|
112
|
+
nnnotes master download --latest -o work/master-bin
|
|
113
|
+
nnnotes master decode work/master-bin -o work/master
|
|
114
|
+
nnnotes --master work/master adv 10462 -o out/adv_10462.json
|
|
115
|
+
nnnotes story 10462 -o out/story_10462
|
|
116
|
+
nnnotes live 100001 --difficulty expert -o out/live_100001
|
|
117
|
+
nnnotes web out/site --all --player <ournotes-player dir> --workers 5
|
|
118
|
+
nnnotes web out/site --pair 100001:expert --pair 100001:hard --player <ournotes-player dir>
|
|
119
|
+
nnnotes web out/site --all --region tw --region en --region kr --player <ournotes-player dir>
|
|
120
|
+
nnnotes web out/site --live2d adv_live2d_rana_003_casual_spring_01 --player <ournotes-player dir>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`web` builds incrementally: charts and models whose manifest exists are skipped (`--force` rebuilds them) and assets
|
|
124
|
+
no longer referenced are removed. Common options:
|
|
125
|
+
|
|
126
|
+
- `--format aac|opus|vorbis|mp3|flac`: BGM format, default AAC; `--no-audio`: no audio files
|
|
127
|
+
- `--band` / `--leader-card`: the band of the LightWeight background and the start timeline; default: the band of
|
|
128
|
+
the music's first vocal character
|
|
129
|
+
- `--workers`: parallel music processes (default a quarter of the CPUs, up to 8) and model processes (default up
|
|
130
|
+
to 4); `--read-workers`: chart read sets at a time (Node.js processes; default half the CPUs, up to 16); `--tmp`:
|
|
131
|
+
temporary build directory (default `<site>.tmp`)
|
|
132
|
+
- `--live2d MODEL` (model id or key, repeatable) / `--all-live2d`: add Live2D models (every model of the catalog);
|
|
133
|
+
charts and models can be added in the same run
|
|
134
|
+
- `--region REGION` (repeatable) / `--all-regions`: the regions the site serves (default: `[catalog] region`);
|
|
135
|
+
each region's master data is `[servers.<region>] master`. Regions with the same chart data share one manifest;
|
|
136
|
+
the chart list page switches region and language with `?region=&lang=`
|
|
137
|
+
- `--player-only`: rewrite the player files, `charts.json` and `models.json` only; `--reingest-json`: store every
|
|
138
|
+
chart's and model's JSON files again under the current rules
|
|
139
|
+
|
|
140
|
+
See [docs/commands.md](https://github.com/MetaSekaiLab/nnnotes/blob/main/docs/commands.md) for every command's options and output layout.
|
|
141
|
+
|
|
142
|
+
## Architecture
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
settings (TOML / environment / flags)
|
|
146
|
+
└─ access addressables (catalog parsing, bundle decryption, local browser)
|
|
147
|
+
catalog (dependency closures, remote and APK bundles, local cache)
|
|
148
|
+
master (master data download and decoding)
|
|
149
|
+
gameapi (anonymous game API calls: current master data version, server list)
|
|
150
|
+
└─ reading unity (UnityPy type trees and TextAssets)
|
|
151
|
+
export (prefabs / components / references resolved to JSON, textures and shaders alongside)
|
|
152
|
+
shader, textstyle (text layout and style), tmpfont (TextMesh Pro fonts), player (boot settings), cri + crikey (CRI audio)
|
|
153
|
+
└─ content stories: adv, advscene, advmedia (frames / effects / post effects / stills / chat),
|
|
154
|
+
advvideo (USM videos), advui, story
|
|
155
|
+
Live2D: live2d, motion
|
|
156
|
+
spots: spot, room
|
|
157
|
+
charts: score (chart parsing and a reimplementation of the game's chart converter),
|
|
158
|
+
livescene, livenotes, liveui, liveaudio, live
|
|
159
|
+
site: web, webmodel (ournotes-player data)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Every JSON file is written by one writer (`jsonio`), so encoding, line endings and number formatting are the same
|
|
163
|
+
everywhere.
|
|
164
|
+
|
|
165
|
+
See [docs/performance.md](https://github.com/MetaSekaiLab/nnnotes/blob/main/docs/performance.md) for where a
|
|
166
|
+
`web` build spends its time and which parts of it run in compiled code.
|
|
167
|
+
|
|
168
|
+
## License
|
|
169
|
+
|
|
170
|
+
MIT, see [LICENSE](https://github.com/MetaSekaiLab/nnnotes/blob/main/LICENSE).
|
nnnotes-0.1.0/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# nnnotes?!
|
|
2
|
+
|
|
3
|
+
[简体中文](README.md) | [English](README.en.md)
|
|
4
|
+
|
|
5
|
+
nnnotes 是 BanG Dream! Our Notes 游戏文件的离线数据工具包:读取 Addressables catalog、下载并解密资源包、下载与解码 masterdata,再把剧情、Live2D、据点场景、着色器、CRI 音频和谱面导出成结构化的 JSON 与通用格式文件。谱面导出结果就是 [ournotes-player](https://github.com/empty-sekai/ournotes-player) 读取的数据。命名灵感来自 [mos9527/sssekai](https://github.com/mos9527/sssekai)。
|
|
6
|
+
|
|
7
|
+
本项目为非官方爱好者项目,与游戏的开发和运营方无关。仓库不包含任何游戏资源、密钥或服务器地址:游戏文件、解密所需的密钥和服务器地址都由使用者在配置中自行提供,导出结果只保存在使用者指定的本地目录。
|
|
8
|
+
|
|
9
|
+
## 功能
|
|
10
|
+
|
|
11
|
+
| 命令 | 输入 | 输出 |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `catalog` | 区服 catalog | 列出 Addressables 资源键(可按前缀过滤) |
|
|
14
|
+
| `browse` | 已配置的各区服 catalog | 本地网页浏览 catalog 与资源包(`--host` / `--port`) |
|
|
15
|
+
| `pull` | 资源键 | 下载并解密该键依赖闭包中的全部资源包到本地缓存 |
|
|
16
|
+
| `servers` | 引导 API 根地址 `[bootstrap] api` | 游戏 API 的服务器列表:各区服名称、区域 ID 与 CDN / API 根地址(地址仅在 `--show-hosts` 时输出) |
|
|
17
|
+
| `master version` | 区服 | 该区服当前的 masterdata 版本与资源版本(游戏 API 匿名调用) |
|
|
18
|
+
| `master download` | masterdata 版本号,或 `--latest`(区服当前版本) | 该版本的 `MasterManifest.json` 与全部 `.bin` 文件(SHA-256 校验) |
|
|
19
|
+
| `master decode` | masterdata `.bin` 文件或目录 | 每张表一个 JSON(Rijndael-256 CBC 解密 + gzip 解压) |
|
|
20
|
+
| `adv` | 剧情 ID | `episode.json`:命令表、五语台词、语音 / 音效 / 视频索引 |
|
|
21
|
+
| `story` | 剧情 ID | 完整剧情目录:episode、全部 Live2D 模型、音频、舞台场景与着色器、剧情 UI、Frame / 粒子特效 / 后处理 / 静帧 / 对话框 / 聊天资源、视频(WebM) |
|
|
22
|
+
| `live2d` | 模型资源键或模型 ID | Live2D(Cubism)运行时目录:moc3、贴图、motion3、物理、表情、预制体参数 |
|
|
23
|
+
| `spot` | 据点 ID | `spot.json` + Spine 角色 + 房间 `room.glb` + 着色器 |
|
|
24
|
+
| `room` | 背景预制体键 | 房间模型(binary glTF) |
|
|
25
|
+
| `shader` | 资源键或 APK 内资源包 | 着色器各平台变体(GLSL ES 等)与索引 |
|
|
26
|
+
| `audio` | CRI cue sheet | 每个 cue 一个音频文件(FLAC / Ogg / WAV)+ cue 元数据 |
|
|
27
|
+
| `crikey` | APK | 读出游戏启动数据中的 CRI HCA 解码密钥(只显示是否找到,可写成 `.hcakey`) |
|
|
28
|
+
| `player` | APK | 渲染相关的全局设置(色彩空间、画质等级、渲染器)JSON |
|
|
29
|
+
| `live` | 曲目 ID + 难度 | 完整谱面目录:谱面与运行时音符、3D 场景、音符与特效资源、BGM 与音效、声音路由 |
|
|
30
|
+
| `web` | `--pair 曲目:难度`(可重复)或 `--all`;`--live2d 模型`(可重复)或 `--all-live2d`;`--story 剧情 ID`(可重复)或 `--all-stories`;`--region 区服`(可重复)或 `--all-regions` | ournotes-player 静态站点:共享播放器 + 每谱 / 每模型 / 每集剧情清单 + 内容寻址资源;一个站点可服务多个区服,列表文本含五种语言;剧情的界面文字按语言分组,字形由开源字体生成 TextMeshPro 字体资源(`--fonts game` 时用游戏字体) |
|
|
31
|
+
| `deck-data` | masterdata 文件(`--master-files` 目录或 `--apk-master`) | 供组卡工具读取的单个 JSON:每张谱面的运行时音符、技能事件与 fever 区间,以及卡牌、技能、加成、分数与活动相关的 masterdata 表([格式](docs/deck-data.md)) |
|
|
32
|
+
|
|
33
|
+
导出约定:
|
|
34
|
+
|
|
35
|
+
- 写文件的命令都用 `-o` 指定输出路径(必填);`web` 的站点目录是位置参数。
|
|
36
|
+
- JSON 一律 UTF-8、LF 换行;无穷大写作 `1e999`。
|
|
37
|
+
- 在同一套环境下导出是确定的:同样的输入,在 nnnotes、Python 依赖库(UnityPy、Pillow、numpy 等)和外部工具(vgmstream、FFmpeg)版本都相同时,导出文件逐字节相同。版本不同时,相同内容可能写成不同的字节:例如不同版本的 Pillow 写出的 PNG 像素相同,字节可能不同。
|
|
38
|
+
- 数值保留 Unity 序列化值与字段名(`m_LocalPosition`、`_bandIDs` 等),便于与游戏数据对照。
|
|
39
|
+
- 贴图导出为 PNG,着色器保留游戏自带的编译结果,音频由 CRI 格式解码为通用格式。
|
|
40
|
+
|
|
41
|
+
## 完成度
|
|
42
|
+
|
|
43
|
+
以下结果基于台服 1.0.1(zh-Hant)的全部数据:
|
|
44
|
+
|
|
45
|
+
| 部分 | 状态 |
|
|
46
|
+
|---|---|
|
|
47
|
+
| catalog / 资源包解密 / 依赖闭包 | 可用 |
|
|
48
|
+
| masterdata 解码 | 可用 |
|
|
49
|
+
| 剧情 `adv` | 946 / 946 集可导出 |
|
|
50
|
+
| 剧情 `story`(完整目录) | 946 / 946 集的资源都在 catalog 中且类型均受支持(资源闭包与游戏自带的每集下载清单一致);已逐集导出验证 759 集,其余 187 集(用到 Frame / Effect / PostEffect / Still 等资源)未逐一验证 |
|
|
51
|
+
| Live2D 模型 | 239 / 239 个可导出(catalog 中的全部模型,剧情用到其中 185 个) |
|
|
52
|
+
| CRI 音频 | 681 / 681 个 cue sheet 可解码 |
|
|
53
|
+
| 谱面 `live` | 336 / 336 个(曲目, 难度)组合可导出 |
|
|
54
|
+
| 网页站点 `web` | 336 / 336 张谱面,239 / 239 个 Live2D 模型,946 / 946 集剧情(英语、无音频的全量构建两次结果逐字节一致,946 / 946 集通过数据校验;五种语言含 AAC 音频的 27 集抽样同样一致,并通过数据校验) |
|
|
55
|
+
| 据点 `spot` / `room` | 已验证单个据点,其余未逐一验证 |
|
|
56
|
+
| 其他区服(en / kr)与其他语言 | 已核对:各区服同一语言的 catalog 相同、资源包相同,密钥通用;谱面用到的 masterdata 表在三个区服间一致,文本表五种语言齐全;抽查的谱面导出与台服一致。多区服整站构建未做全量验证 |
|
|
57
|
+
|
|
58
|
+
## 需要准备
|
|
59
|
+
|
|
60
|
+
- Python 3.11+,推荐 3.13(`web` 构建读写大量 JSON,3.13 的标准库 JSON 编码更快),`pip install nnnotes`(开发时在仓库内 `pip install -e .`)
|
|
61
|
+
- 游戏安装包 `base.apk`:APK 内置资源包、CRI 解码密钥、启动设置。`player`、`story`、`live`、`web` 用 nnnotes 自带的类型树读取 APK 启动数据中的 MonoBehaviour,目前支持游戏版本 1.0.1(Unity 6000.3.12f1);其他版本的 APK 若类型不符,这些命令会报错并给出类名、游戏版本和 Unity 版本
|
|
62
|
+
- 解码后的 masterdata 目录(可用 `master download` + `master decode` 生成):`adv`、`story`、`spot`、`live` 和 `web` 的谱面需要;`web` 的 Live2D 模型只用它取角色名(可选)
|
|
63
|
+
- 外部工具:[vgmstream](https://vgmstream.org/)(CRI HCA 解码)、[FFmpeg](https://ffmpeg.org/)(转码,含剧情视频的 WebM 封装与 Opus 音频);`web` 另需 Node.js 20+ 与构建好的 ournotes-player
|
|
64
|
+
|
|
65
|
+
## 配置
|
|
66
|
+
|
|
67
|
+
代码中没有任何密钥、服务器地址和默认路径。所有设置按以下顺序读取,后者覆盖前者:
|
|
68
|
+
|
|
69
|
+
1. 配置文件:`--config <文件>`,否则 `NNNOTES_CONFIG`,否则当前目录的 `nnnotes.toml`
|
|
70
|
+
2. 环境变量:`NNNOTES_<节>_<键>`(如 `NNNOTES_BUNDLE_KEY`、`NNNOTES_SERVERS_TW_CDN`)
|
|
71
|
+
3. 命令行参数:`--region`、`--language`、`--catalog`、`--cache`、`--master`、`--apk`、`--ffmpeg`、`--vgmstream`、`--node` 写在命令名之前;`--player` 是 `web` 的参数
|
|
72
|
+
|
|
73
|
+
复制 [`nnnotes.example.toml`](nnnotes.example.toml) 为 `nnnotes.toml` 后填写。需要的设置包括:资源包解密密钥与 nonce 种子、masterdata 的密钥与 IV、使用的区服 `[catalog] region` 与 catalog 语言 `[catalog] language`、每个区服的 CDN 地址与 API 根地址(`[servers.<区服>]` 的 `cdn`、`api`)、客户端版本 `[client] version`(未设置时读取 APK 的 versionName)、可选的引导 API 根地址 `[bootstrap] api`(`servers` 使用),以及缓存目录、APK、masterdata 目录、ournotes-player 和 vgmstream / FFmpeg / Node.js 的路径(三个工具未设置时在 `PATH` 中查找)。这些值都来自使用者自己的游戏客户端。
|
|
74
|
+
|
|
75
|
+
缺少或格式错误的设置会让命令以退出码 2 结束,并用一行说明对应的配置键、环境变量和命令行参数,不会输出任何设置值。`nnnotes.toml` 已在 `.gitignore` 中,请勿提交。
|
|
76
|
+
|
|
77
|
+
完整说明见 [docs/configuration.md](docs/configuration.md)。
|
|
78
|
+
|
|
79
|
+
## 使用示例
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
nnnotes catalog --prefix Live/MusicScore/ --limit 20
|
|
83
|
+
nnnotes browse --port 8000
|
|
84
|
+
nnnotes pull Live/MusicScore/0001/0001_03
|
|
85
|
+
nnnotes master version
|
|
86
|
+
nnnotes master download --latest -o work/master-bin
|
|
87
|
+
nnnotes master decode work/master-bin -o work/master
|
|
88
|
+
nnnotes --master work/master adv 10462 -o out/adv_10462.json
|
|
89
|
+
nnnotes story 10462 -o out/story_10462
|
|
90
|
+
nnnotes live 100001 --difficulty expert -o out/live_100001
|
|
91
|
+
nnnotes web out/site --all --player <ournotes-player 目录> --workers 5
|
|
92
|
+
nnnotes web out/site --pair 100001:expert --pair 100001:hard --player <ournotes-player 目录>
|
|
93
|
+
nnnotes web out/site --all --region tw --region en --region kr --player <ournotes-player 目录>
|
|
94
|
+
nnnotes web out/site --live2d adv_live2d_rana_003_casual_spring_01 --player <ournotes-player 目录>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`web` 可以增量构建:清单已存在的谱面和模型会跳过(`--force` 重建),不再被引用的资源会被清理。常用参数:
|
|
98
|
+
|
|
99
|
+
- `--format aac|opus|vorbis|mp3|flac`:BGM 格式,默认 AAC;`--no-audio`:不导出音频
|
|
100
|
+
- `--band` / `--leader-card`:轻量背景与开场时间轴所用乐队;默认取曲目第一位演唱角色的乐队
|
|
101
|
+
- `--workers`:并行处理的曲目进程数(默认为 CPU 数的四分之一,最多 8)与模型进程数(默认最多 4);`--read-workers`:同时运行的谱面读取集(Node.js 进程)数(默认为 CPU 数的一半,最多 16);`--tmp`:临时构建目录(默认 `<站点>.tmp`)
|
|
102
|
+
- `--live2d 模型`(模型 ID 或资源键,可重复)/ `--all-live2d`:加入 Live2D 模型(catalog 中全部模型),可与谱面在同一次构建中加入
|
|
103
|
+
- `--region 区服`(可重复)/ `--all-regions`:站点服务的区服(默认 `[catalog] region`);每个区服的 masterdata 由 `[servers.<区服>] master` 指定。谱面数据相同的区服共用一份清单,列表页用 `?region=&lang=` 切换区服与语言
|
|
104
|
+
- `--player-only`:只重写播放器文件与 `charts.json`、`models.json`;`--reingest-json`:按当前规则重新存储所有谱面与模型的 JSON
|
|
105
|
+
|
|
106
|
+
各命令的参数与输出目录结构见 [docs/commands.md](docs/commands.md)。
|
|
107
|
+
|
|
108
|
+
## 架构
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
配置(TOML / 环境变量 / 参数)
|
|
112
|
+
└─ 访问层 addressables(catalog 解析、资源包解密、本地浏览)
|
|
113
|
+
catalog(依赖闭包、远端与 APK 内资源、本地缓存)
|
|
114
|
+
master(masterdata 下载与解码)
|
|
115
|
+
gameapi(游戏 API 匿名调用:当前 masterdata 版本、服务器列表)
|
|
116
|
+
└─ 读取层 unity(UnityPy 读取 typetree 与 TextAsset)
|
|
117
|
+
export(预制体 / 组件 / 引用全部解析为 JSON,贴图与着色器随同导出)
|
|
118
|
+
shader、textstyle(文字排版与样式)、tmpfont(TextMesh Pro 字体)、player(启动设置)、cri + crikey(CRI 音频)
|
|
119
|
+
└─ 内容层 剧情:adv、advscene、advmedia(Frame / 特效 / 后处理 / 静帧 / 聊天)、advvideo(USM 视频)、advui、story
|
|
120
|
+
Live2D:live2d、motion
|
|
121
|
+
据点:spot、room
|
|
122
|
+
谱面:score(谱面解析与游戏谱面转换器的复现)、livescene、livenotes、liveui、liveaudio、live
|
|
123
|
+
站点:web、webmodel(ournotes-player 数据)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
所有 JSON 由同一个写出器生成(`jsonio`),保证编码、换行与数值格式一致。
|
|
127
|
+
|
|
128
|
+
`web` 构建的耗时分布,以及其中哪些部分已由编译代码执行,见 [docs/performance.md](docs/performance.md)。
|
|
129
|
+
|
|
130
|
+
## License
|
|
131
|
+
|
|
132
|
+
MIT,见 [LICENSE](LICENSE)。
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "nnnotes"
|
|
7
|
+
description = "Offline data toolkit for BanG Dream! Our Notes game files: catalogs, bundles, master data, stories, Live2D, audio and live charts"
|
|
8
|
+
readme = "README.en.md"
|
|
9
|
+
license = "MIT"
|
|
10
|
+
license-files = ["LICENSE"]
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
authors = [{ name = "MetaMiku" }, { name = "emptysekai" }]
|
|
13
|
+
dependencies = [
|
|
14
|
+
"UnityPy>=1.25",
|
|
15
|
+
"numpy>=2.0",
|
|
16
|
+
"Pillow>=10.0",
|
|
17
|
+
"pycryptodome>=3.20",
|
|
18
|
+
"grpcio>=1.49.1",
|
|
19
|
+
]
|
|
20
|
+
classifiers = [
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
"Topic :: Multimedia",
|
|
24
|
+
]
|
|
25
|
+
dynamic = ["version"]
|
|
26
|
+
|
|
27
|
+
[project.optional-dependencies]
|
|
28
|
+
test = ["pytest>=8", "pyflakes>=3.2", "jsonschema>=4.18"]
|
|
29
|
+
fonts = ["fonttools>=4.50", "freetype-py>=2.5", "scipy>=1.13"]
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
nnnotes = "nnnotes.cli:main"
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://github.com/MetaSekaiLab/nnnotes"
|
|
36
|
+
Source = "https://github.com/MetaSekaiLab/nnnotes"
|
|
37
|
+
Issues = "https://github.com/MetaSekaiLab/nnnotes/issues"
|
|
38
|
+
|
|
39
|
+
[tool.setuptools.dynamic]
|
|
40
|
+
version = { attr = "nnnotes.__version__" }
|
|
41
|
+
|
|
42
|
+
[tool.setuptools.packages.find]
|
|
43
|
+
where = ["src"]
|
|
44
|
+
|
|
45
|
+
[tool.setuptools.package-data]
|
|
46
|
+
nnnotes = ["typetrees/*.json", "viewrules.json"]
|
|
47
|
+
|
|
48
|
+
[tool.pytest.ini_options]
|
|
49
|
+
testpaths = ["tests"]
|
|
50
|
+
addopts = "-ra"
|
nnnotes-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"""nnnotes: offline data toolkit for BanG Dream! Our Notes game files.
|
|
2
|
+
|
|
3
|
+
Reads Addressables catalogs, fetches and decrypts asset bundles, decodes master data and exports stories, Live2D
|
|
4
|
+
models, spots, shaders, CRI audio and live charts as JSON and common file formats. Game files, keys and server
|
|
5
|
+
addresses are supplied by the user through the configuration; nothing of the game is included.
|
|
6
|
+
"""
|
|
7
|
+
__version__ = "0.1.0"
|