music-lens 0.1.0 → 0.1.1

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.
package/README.md CHANGED
@@ -23,12 +23,16 @@ $node = "C:\Users\86173\Documents\deepseek-harness\default-workspace\snowluma\Sn
23
23
  & $node .\bin\music-lens.mjs analyze "song.mp3" --model medium
24
24
  ```
25
25
 
26
- `setup` 会自己装 python 依赖并从 hf-mirror 下模型:
26
+ `setup` 会自己装 python 依赖并从 hf-mirror 下模型,**默认只下 small(461 MB)**:
27
27
 
28
28
  ```powershell
29
- & $node .\bin\music-lens.mjs setup --models small,medium
29
+ & $node .\bin\music-lens.mjs setup # small,约 500 MB 依赖 + 461 MB 模型
30
+ & $node .\bin\music-lens.mjs setup --models medium # 中文效果更好,再下 1.46 GB
30
31
  ```
31
32
 
33
+ 跨平台:Windows 用 `winget`,macOS 用 `brew`,Linux 用 `apt-get`;
34
+ 都不行时会打印手工安装命令,也可以用 `MUSIC_LENS_PYTHON` 直接指定解释器路径。
35
+
32
36
  模型和缓存默认放 `~/.music-lens`,可用 `MUSIC_LENS_HOME` 覆盖。
33
37
 
34
38
  > 本机注意:**node 不在 PATH 里,也没有 npm**,所以 `npx music-lens` 目前跑不了,
@@ -57,13 +57,15 @@ function parseArgs(argv) {
57
57
  function candidates() {
58
58
  const list = []
59
59
  if (process.env.MUSIC_LENS_PYTHON) list.push(process.env.MUSIC_LENS_PYTHON)
60
- const la = process.env.LOCALAPPDATA
61
- if (la) {
62
- for (const v of ['313', '312', '311']) {
63
- list.push(path.join(la, 'Programs', 'Python', `Python${v}`, 'python.exe'))
60
+ if (process.platform === 'win32') {
61
+ const la = process.env.LOCALAPPDATA
62
+ if (la) {
63
+ for (const v of ['313', '312', '311']) {
64
+ list.push(path.join(la, 'Programs', 'Python', `Python${v}`, 'python.exe'))
65
+ }
64
66
  }
65
67
  }
66
- list.push('python', 'python3')
68
+ list.push('python3.12', 'python3', 'python')
67
69
  return list
68
70
  }
69
71
 
@@ -135,8 +137,8 @@ function cmdDoctor() {
135
137
  const py = findPython()
136
138
  if (!py) {
137
139
  log('python : MISSING')
138
- log(' install: winget install --id Python.Python.3.12 --scope user')
139
- log(' or set MUSIC_LENS_PYTHON=C:\\path\\to\\python.exe')
140
+ log(` install: ${pythonInstallCommand().manual}`)
141
+ log(' or set MUSIC_LENS_PYTHON=/path/to/python')
140
142
  } else {
141
143
  const v = capture(py, ['-c', 'import sys;print(sys.version.split()[0])']).out.trim()
142
144
  log(`python : ${py} (${v})`)
@@ -151,16 +153,38 @@ function cmdDoctor() {
151
153
  return 0
152
154
  }
153
155
 
156
+ function pythonInstallCommand() {
157
+ if (process.platform === 'win32') {
158
+ return {
159
+ cmd: 'winget',
160
+ args: ['install', '--id', 'Python.Python.3.12', '-e', '--scope', 'user',
161
+ '--accept-package-agreements', '--accept-source-agreements'],
162
+ manual: 'winget install --id Python.Python.3.12 -e --scope user',
163
+ }
164
+ }
165
+ if (process.platform === 'darwin') {
166
+ return { cmd: 'brew', args: ['install', 'python@3.12'], manual: 'brew install python@3.12' }
167
+ }
168
+ return {
169
+ cmd: 'sudo',
170
+ args: ['apt-get', 'install', '-y', 'python3', 'python3-pip', 'python3-venv'],
171
+ manual: 'sudo apt-get install -y python3 python3-pip python3-venv',
172
+ }
173
+ }
174
+
154
175
  async function cmdSetup(args) {
155
176
  const py = findPython()
156
177
  let use = py
157
178
  if (!use) {
158
- log('python not found -- trying winget (per-user install)')
159
- const st = run('winget', ['install', '--id', 'Python.Python.3.12', '-e', '--scope', 'user',
160
- '--accept-package-agreements', '--accept-source-agreements'])
161
- if (st !== 0) die('python install failed; install it manually then re-run `music-lens setup`')
179
+ const inst = pythonInstallCommand()
180
+ log(`python not found -- trying ${inst.cmd}`)
181
+ let st = 1
182
+ try { st = run(inst.cmd, inst.args) } catch { st = 1 }
183
+ if (st !== 0) {
184
+ die(`could not install python automatically.\n run manually: ${inst.manual}\n then re-run: music-lens setup\n (or point MUSIC_LENS_PYTHON at an existing python 3.9+)`)
185
+ }
162
186
  use = findPython()
163
- if (!use) die('python installed but still not found; set MUSIC_LENS_PYTHON')
187
+ if (!use) die('python installed but still not on PATH; set MUSIC_LENS_PYTHON')
164
188
  }
165
189
  log(`python: ${use}`)
166
190
 
@@ -175,10 +199,11 @@ async function cmdSetup(args) {
175
199
  '--index-url', 'https://download.pytorch.org/whl/cpu'])
176
200
  }
177
201
 
178
- const wanted = (args.models || 'small,medium').split(',').map(s => s.trim()).filter(Boolean)
202
+ const wanted = (args.models || 'small').split(',').map(s => s.trim()).filter(Boolean)
179
203
  for (const m of wanted) await ensureModel(m)
180
204
 
181
205
  log('\nready. try: music-lens analyze "<song.mp3>" --model medium')
206
+ log('(medium is ~1.5 GB and a lot better on Chinese; download it with: music-lens setup --models medium)')
182
207
  return 0
183
208
  }
184
209
 
@@ -212,7 +237,7 @@ function usage() {
212
237
  log(`music-lens ${JSON.parse(fs.readFileSync(path.join(PKG, 'package.json'), 'utf8')).version}
213
238
 
214
239
  music-lens doctor check environment
215
- music-lens setup [--models small,medium] install python deps + models
240
+ music-lens setup [--models small] install python deps + models
216
241
  music-lens analyze <audio> transcribe + analyse
217
242
  [--model medium] small | medium | large-v3 | path
218
243
  [--lang auto] language code or auto
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "music-lens",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Let a text-only model read a song: lyrics + timestamps, loudness, brightness, key, tempo, sections. Local, no API keys.",
5
5
  "type": "module",
6
6
  "bin": {