{"_id":"@bilalpm/musicli","_rev":"6-b257f9081d5241670bc161cb79a5fb57","name":"@bilalpm/musicli","dist-tags":{"latest":"0.1.5"},"versions":{"0.1.0":{"name":"@bilalpm/musicli","version":"0.1.0","keywords":["lofi","cli","terminal","music","ambient","focus"],"license":"MIT","_id":"@bilalpm/musicli@0.1.0","maintainers":[{"name":"bilalpm","email":"bilal.tahir89@gmail.com"}],"homepage":"https://github.com/btahir/musicli#readme","bugs":{"url":"https://github.com/btahir/musicli/issues"},"bin":{"musicli":"dist/index.js"},"dist":{"shasum":"d0de21673353cdec1178a1b0fa6de6a196946c10","tarball":"https://registry.npmjs.org/@bilalpm/musicli/-/musicli-0.1.0.tgz","fileCount":20,"integrity":"sha512-GFRRoZrSqwWBjnKTdapde7GbqujPOZZaYyXMzvUEnOhF7drcgjJvbnJvI0/hcrpdORSPuHU9pbQJyLXTYtAZsg==","signatures":[{"sig":"MEYCIQCE4Co87iYKnSWu477Kf/Pt9vY88OnM0RIAR5wwhVrC+gIhAKDotJpdpbFjGVr/obFHjiYylvQSrKvvod+Yx9oO0Vk8","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":14950391},"main":"./dist/index.js","type":"module","engines":{"node":">=22.0.0"},"gitHead":"f06ae71ca85acda176d3f5aeb7d6cbb23295d49b","scripts":{"dev":"tsx src/index.ts","test":"npm run build && node --import tsx --test test/**/*.test.ts","build":"tsup","start":"node dist/index.js","prepack":"npm test","postinstall":"node scripts/patch-speaker-coreaudio.mjs","tracks:build":"node scripts/build-track-library.mjs && node scripts/build-library-manifests.mjs","library:build":"node scripts/build-library-manifests.mjs","library:stage":"node scripts/stage-library-source.mjs","tracks:retitle":"node scripts/retitle-track-pairs.mjs","tracks:normalize":"node scripts/normalize-track-filenames.mjs"},"_npmUser":{"name":"bilalpm","email":"bilal.tahir89@gmail.com"},"repository":{"url":"git+https://github.com/btahir/musicli.git","type":"git"},"_npmVersion":"11.8.0","description":"your focus room in the terminal","directories":{},"_nodeVersion":"24.13.1","dependencies":{"pngjs":"^7.0.0","figlet":"^1.8.0","speaker":"^0.5.4","commander":"^13.1.0","gradient-string":"^3.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","tsup":"^8.4.0","typescript":"^5.7.0","@types/node":"^22.13.0","@types/figlet":"^1.7.0"},"_npmOperationalInternal":{"tmp":"tmp/musicli_0.1.0_1773522310681_0.4727302757066625","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@bilalpm/musicli","version":"0.1.1","keywords":["lofi","cli","terminal","music","ambient","focus"],"license":"MIT","_id":"@bilalpm/musicli@0.1.1","maintainers":[{"name":"bilalpm","email":"bilal.tahir89@gmail.com"}],"homepage":"https://github.com/btahir/musicli#readme","bugs":{"url":"https://github.com/btahir/musicli/issues"},"bin":{"musicli":"dist/index.js"},"dist":{"shasum":"b780286c2abe51c6fbdeda59f88b5fa26a9ec7f6","tarball":"https://registry.npmjs.org/@bilalpm/musicli/-/musicli-0.1.1.tgz","fileCount":20,"integrity":"sha512-d5g/aTSGkmgiK90EBC4jO0CTxQKB4zwsSmcxpX9P5X6rmcHhg2pgBG9S+QtDDXPvcUbJ2yBYuNfbvTVp7541iw==","signatures":[{"sig":"MEYCIQCkgUyib1dTn8bOeG07m7UEE9jDP5MQ4XCcpJNF6t1R7wIhAIi8sAtQI9XT3ofTTZQfVEBn3SIgkC6GxD5Ua/A7MffT","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":14982283},"main":"./dist/index.js","type":"module","engines":{"node":">=22.0.0"},"gitHead":"b2e3a3cf6f727df34c21aa1bc8861e0d67913e7c","scripts":{"dev":"tsx src/index.ts","test":"npm run build && node --import tsx --test test/**/*.test.ts","build":"tsup","start":"node dist/index.js","prepack":"npm test","postinstall":"node scripts/patch-speaker-coreaudio.mjs","tracks:build":"node scripts/build-track-library.mjs && node scripts/build-library-manifests.mjs","library:build":"node scripts/build-library-manifests.mjs","library:stage":"node scripts/stage-library-source.mjs","tracks:retitle":"node scripts/retitle-track-pairs.mjs","tracks:normalize":"node scripts/normalize-track-filenames.mjs"},"_npmUser":{"name":"bilalpm","email":"bilal.tahir89@gmail.com"},"repository":{"url":"git+https://github.com/btahir/musicli.git","type":"git"},"_npmVersion":"11.8.0","description":"your focus room in the terminal","directories":{},"_nodeVersion":"24.13.1","dependencies":{"pngjs":"^7.0.0","figlet":"^1.8.0","speaker":"^0.5.4","commander":"^13.1.0","gradient-string":"^3.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","tsup":"^8.4.0","typescript":"^5.7.0","@types/node":"^22.13.0","@types/figlet":"^1.7.0"},"_npmOperationalInternal":{"tmp":"tmp/musicli_0.1.1_1773525309910_0.9801666607777824","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@bilalpm/musicli","version":"0.1.2","keywords":["lofi","cli","terminal","music","ambient","focus"],"license":"MIT","_id":"@bilalpm/musicli@0.1.2","maintainers":[{"name":"bilalpm","email":"bilal.tahir89@gmail.com"}],"homepage":"https://github.com/btahir/musicli#readme","bugs":{"url":"https://github.com/btahir/musicli/issues"},"bin":{"musicli":"dist/index.js"},"dist":{"shasum":"6174a94a202ca85329ef28b1858f65440420ff78","tarball":"https://registry.npmjs.org/@bilalpm/musicli/-/musicli-0.1.2.tgz","fileCount":20,"integrity":"sha512-L4IgmubPK/vn0zAEgB45jnF8ey9RpLp2Mh643kYV11bFtGFp7W1fL7HK4gaj8ojLAsSeeh6W8EL3mOwovp8/QA==","signatures":[{"sig":"MEUCICH546LWe+CcCnfeQXqxyhjZRTb3F6xm+Gf8lyxkMdZYAiEAnctD507H3bVJUeVKXLpNSpyLH6yk46oj7A1A6wWa4f4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":14986736},"main":"./dist/index.js","type":"module","engines":{"node":">=22.0.0"},"gitHead":"7646d198798ba34e1f3c6cfa9e0e9fc2dbddaef3","scripts":{"dev":"tsx src/index.ts","test":"npm run build && node --import tsx --test test/**/*.test.ts","build":"tsup","start":"node dist/index.js","prepack":"npm test","postinstall":"node scripts/patch-speaker-coreaudio.mjs","tracks:build":"node scripts/build-track-library.mjs && node scripts/build-library-manifests.mjs","library:build":"node scripts/build-library-manifests.mjs","library:stage":"node scripts/stage-library-source.mjs","tracks:retitle":"node scripts/retitle-track-pairs.mjs","tracks:normalize":"node scripts/normalize-track-filenames.mjs"},"_npmUser":{"name":"bilalpm","email":"bilal.tahir89@gmail.com"},"repository":{"url":"git+https://github.com/btahir/musicli.git","type":"git"},"_npmVersion":"11.8.0","description":"your focus room in the terminal","directories":{},"_nodeVersion":"24.13.1","dependencies":{"pngjs":"^7.0.0","figlet":"^1.8.0","speaker":"^0.5.4","commander":"^13.1.0","gradient-string":"^3.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","tsup":"^8.4.0","typescript":"^5.7.0","@types/node":"^22.13.0","@types/figlet":"^1.7.0"},"_npmOperationalInternal":{"tmp":"tmp/musicli_0.1.2_1773526502053_0.21876531099501206","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@bilalpm/musicli","version":"0.1.3","keywords":["lofi","cli","terminal","music","ambient","focus"],"license":"MIT","_id":"@bilalpm/musicli@0.1.3","maintainers":[{"name":"bilalpm","email":"bilal.tahir89@gmail.com"}],"homepage":"https://github.com/btahir/musicli#readme","bugs":{"url":"https://github.com/btahir/musicli/issues"},"bin":{"musicli":"dist/index.js"},"dist":{"shasum":"d58ea81a563af370c83e6d5638b73c6f0a852822","tarball":"https://registry.npmjs.org/@bilalpm/musicli/-/musicli-0.1.3.tgz","fileCount":20,"integrity":"sha512-wxagA8wKRdpgC4e6T+seWSGnR9BBd+eIdJnkWo0NU8f9ep7EwdD4YEbaezbx4QtCaC5yuN150rOkEzmsGA/Ekw==","signatures":[{"sig":"MEUCIAPluPn1uPeost4OK7meojUzbG/vxqLiCzag+4PRDL93AiEAjX7fXgOQLHqHSeaGM7WZss05rNzG7tQlFANSQmgL0tg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":14986997},"main":"./dist/index.js","type":"module","engines":{"node":">=22.0.0"},"gitHead":"3b27e22a13b8550129f6d8b09b8cb126f32f247e","scripts":{"dev":"tsx src/index.ts","test":"npm run build && node --import tsx --test test/**/*.test.ts","build":"tsup","start":"node dist/index.js","prepack":"npm test","postinstall":"node scripts/patch-speaker-coreaudio.mjs","tracks:build":"node scripts/build-track-library.mjs && node scripts/build-library-manifests.mjs","library:build":"node scripts/build-library-manifests.mjs","library:stage":"node scripts/stage-library-source.mjs","tracks:retitle":"node scripts/retitle-track-pairs.mjs","tracks:normalize":"node scripts/normalize-track-filenames.mjs"},"_npmUser":{"name":"bilalpm","email":"bilal.tahir89@gmail.com"},"repository":{"url":"git+https://github.com/btahir/musicli.git","type":"git"},"_npmVersion":"11.8.0","description":"A simple music player in your terminal","directories":{},"_nodeVersion":"24.13.1","dependencies":{"pngjs":"^7.0.0","figlet":"^1.8.0","speaker":"^0.5.4","commander":"^13.1.0","gradient-string":"^3.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","tsup":"^8.4.0","typescript":"^5.7.0","@types/node":"^22.13.0","@types/figlet":"^1.7.0"},"_npmOperationalInternal":{"tmp":"tmp/musicli_0.1.3_1773527222730_0.8255575518375153","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"@bilalpm/musicli","version":"0.1.4","keywords":["lofi","cli","terminal","music","ambient","focus"],"license":"MIT","_id":"@bilalpm/musicli@0.1.4","maintainers":[{"name":"bilalpm","email":"bilal.tahir89@gmail.com"}],"homepage":"https://github.com/btahir/musicli#readme","bugs":{"url":"https://github.com/btahir/musicli/issues"},"bin":{"musicli":"dist/index.js"},"dist":{"shasum":"6ccf995cfe5c372717a40965d57114acba627f3a","tarball":"https://registry.npmjs.org/@bilalpm/musicli/-/musicli-0.1.4.tgz","fileCount":20,"integrity":"sha512-M0G48MikK5lu+lAXDe324inFWkGsoIQx96KC+jqkzW/V2PYUEW+S/sirtpU3sf9pZarvCEeYCU2cccxzpLttng==","signatures":[{"sig":"MEUCIQD9HEby8jcxLaGhEvB3Z0z/h3/VpYD8XZ3oXoGKU1gVegIgG6vwARAKQ9xQeaBCYX7Q6s4eqo6fLk1C1BXUJw7MUDk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":14998625},"main":"./dist/index.js","type":"module","engines":{"node":">=22.0.0"},"gitHead":"8a9a73a1e3d7a81bb0aa49a79c7852688681360c","scripts":{"dev":"tsx src/index.ts","test":"npm run build && node --import tsx --test test/**/*.test.ts","build":"tsup","start":"node dist/index.js","prepack":"npm test","postinstall":"node scripts/patch-speaker-coreaudio.mjs","tracks:build":"node scripts/build-track-library.mjs && node scripts/build-library-manifests.mjs","library:build":"node scripts/build-library-manifests.mjs","library:stage":"node scripts/stage-library-source.mjs","tracks:retitle":"node scripts/retitle-track-pairs.mjs","tracks:normalize":"node scripts/normalize-track-filenames.mjs"},"_npmUser":{"name":"bilalpm","email":"bilal.tahir89@gmail.com"},"repository":{"url":"git+https://github.com/btahir/musicli.git","type":"git"},"_npmVersion":"11.8.0","description":"A simple music player in your terminal","directories":{},"_nodeVersion":"24.13.1","dependencies":{"pngjs":"^7.0.0","figlet":"^1.8.0","speaker":"^0.5.4","commander":"^13.1.0","gradient-string":"^3.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","tsup":"^8.4.0","typescript":"^5.7.0","@types/node":"^22.13.0","@types/figlet":"^1.7.0"},"_npmOperationalInternal":{"tmp":"tmp/musicli_0.1.4_1773528392830_0.8373245649193026","host":"s3://npm-registry-packages-npm-production"}},"0.1.5":{"name":"@bilalpm/musicli","version":"0.1.5","description":"A simple music player in your terminal","type":"module","bin":{"musicli":"dist/index.js"},"main":"./dist/index.js","scripts":{"dev":"tsx src/index.ts","build":"tsup","start":"node dist/index.js","test":"npm run build && node --import tsx --test test/**/*.test.ts","postinstall":"node scripts/patch-speaker-coreaudio.mjs","prepack":"npm test","tracks:normalize":"node scripts/normalize-track-filenames.mjs","tracks:retitle":"node scripts/retitle-track-pairs.mjs","tracks:build":"node scripts/build-track-library.mjs && node scripts/build-library-manifests.mjs","library:build":"node scripts/build-library-manifests.mjs","library:stage":"node scripts/stage-library-source.mjs"},"keywords":["lofi","cli","terminal","music","ambient","focus"],"repository":{"type":"git","url":"git+https://github.com/btahir/musicli.git"},"homepage":"https://github.com/btahir/musicli#readme","bugs":{"url":"https://github.com/btahir/musicli/issues"},"license":"MIT","dependencies":{"commander":"^13.1.0","figlet":"^1.8.0","gradient-string":"^3.0.0","pngjs":"^7.0.0","speaker":"^0.5.4"},"devDependencies":{"@types/figlet":"^1.7.0","@types/node":"^22.13.0","tsup":"^8.4.0","tsx":"^4.19.0","typescript":"^5.7.0"},"engines":{"node":">=22.0.0"},"gitHead":"20534f198869bf32274a5aa67278f187fba84770","_id":"@bilalpm/musicli@0.1.5","_nodeVersion":"24.13.1","_npmVersion":"11.8.0","dist":{"integrity":"sha512-fz8OMI04gno43ZRa/W5fWzkmLrUH+uVtwEDdctEd2+YEn4WN4DMELnqPBEFJHQz34/kVkVLpycB5XSAtcOCF5Q==","shasum":"5764f2243c58a9542de4a49b4d5f0c6c5e04d6f9","tarball":"https://registry.npmjs.org/@bilalpm/musicli/-/musicli-0.1.5.tgz","fileCount":20,"unpackedSize":15001877,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQD9GCDNvlJo1hUnCWadU25SFDzk5BsPMS9OqYPN+uBylQIgVWhMejHTIo3+VsPxtiBmyeRI9XfXboyfPuBMzAHWkIE="}]},"_npmUser":{"name":"bilalpm","email":"bilal.tahir89@gmail.com"},"directories":{},"maintainers":[{"name":"bilalpm","email":"bilal.tahir89@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/musicli_0.1.5_1773528579953_0.18281609331746873"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-14T21:05:10.556Z","modified":"2026-03-14T22:49:40.548Z","0.1.0":"2026-03-14T21:05:11.200Z","0.1.1":"2026-03-14T21:55:10.406Z","0.1.2":"2026-03-14T22:15:02.597Z","0.1.3":"2026-03-14T22:27:03.441Z","0.1.4":"2026-03-14T22:46:33.352Z","0.1.5":"2026-03-14T22:49:40.440Z"},"bugs":{"url":"https://github.com/btahir/musicli/issues"},"license":"MIT","homepage":"https://github.com/btahir/musicli#readme","keywords":["lofi","cli","terminal","music","ambient","focus"],"repository":{"type":"git","url":"git+https://github.com/btahir/musicli.git"},"description":"A simple music player in your terminal","maintainers":[{"name":"bilalpm","email":"bilal.tahir89@gmail.com"}],"readme":"# Musicli\n\n### *A simple music player in your terminal*\n\n![musicli hero](docs/images/hero.png)\n\n> Open your terminal. Set the mood. Stay in flow.\n>\n> `musicli` is a keyboard-first music player for local folders and stream URLs, with scene visuals, long-form ambience loops, and in-terminal search.\n\n[Why Musicli](#why-musicli) · [Quick Start](#quick-start) · [Use It](#use-it) · [Controls](#controls) · [Presets](#presets) · [Library](#library) · [Development](#development)\n\n---\n\n## Why Musicli\n\n- Full-screen terminal playback built for long focus sessions, not playlist management overhead.\n- Live ambience mixing with six long-session layers: `rain`, `cafe`, `fire`, `thunder`, `forest`, and `city`.\n- `Track` volume starts at `0.25` on first run and remembers the last level you used.\n- Search that stays in the terminal and does not interrupt playback.\n- Scene-driven visuals with a portable renderer by default and a sharper `chafa` path when available.\n- One source manager for local folders, saved streams, and recent one-offs.\n- Local-folder-first onboarding with a native folder picker on supported systems.\n- A catalog-first music library with installable packs, ready for a standalone library repo or release assets.\n\n`musicli` is not trying to be a generic music app in a terminal. The point is atmosphere with very little friction.\n\n---\n\n## Quick Start\n\n### Requirements\n\n- `Node.js 22+`\n- `ffmpeg` required for playback\n- `chafa` optional, recommended for better scene detail\n- `yt-dlp` optional, only needed for YouTube URLs passed to `--url`\n- Native folder picker support:\n  - macOS: built-in through `osascript`\n  - Linux: `zenity` or `kdialog` recommended\n\nExample dependency install:\n\n```bash\nbrew install ffmpeg chafa yt-dlp\n# or\nsudo apt install ffmpeg chafa zenity\n```\n\n### Run From Source\n\n```bash\ngit clone https://github.com/btahir/musicli.git\ncd musicli\nnpm install\nnpm run dev\n```\n\n### Run the Built CLI\n\n```bash\nnpm run build\nnode dist/index.js\n```\n\n### Install As a Package\n\n```bash\nnpm install -g @bilalpm/musicli\nmusicli\n```\n\nIf you installed Musicli with npm, you can update it in place later with:\n\n```bash\nmusicli update\n```\n\n### First Session\n\n```bash\nmusicli\nmusicli --folder ~/Music/Lofi\nmusicli --url https://www.youtube.com/watch?v=jfKfPfyJRdk\n```\n\nOn first run, `musicli` opens an idle welcome screen. After you choose a local folder or stream, Musicli remembers the last source and starts there automatically next time. Use `--home` anytime to reopen the welcome screen on launch.\n\n---\n\n## Use It\n\n### Start Listening\n\n```bash\nmusicli\nmusicli --preset chill\nmusicli --preset jazz\nmusicli --preset snow\nmusicli --home\n```\n\nOn first launch, running `musicli` with no source starts idle and opens a welcome screen. After that, Musicli resumes the last source you used unless you pass `--home`.\n\n- `Local Folder` is the default path.\n- On macOS, Musicli opens the system folder picker so you can choose music without typing the path.\n- On Linux, it uses `zenity` or `kdialog` when available.\n- If no native picker is available, Musicli falls back to the in-terminal path editor.\n- If you already know the source, `--folder` and `--url` skip onboarding and go straight in.\n\n### Shape the Room\n\n```bash\nmusicli --rain 0.40 --city 0.20\nmusicli --forest 0.50\nmusicli --fire 0.25 --cafe 0.20\nmusicli --scene alley\nmusicli --scene-renderer chafa\n```\n\nThe `Track` row starts at `0.25` on first run. After that, Musicli remembers the last `Track` level you used in `~/.musicli/settings.json`.\n\nOn local tracks, `[` and `]` seek backward or forward by `10s`. Streams stay live and do not expose seeking.\n\n### Bring Your Own Stream\n\n```bash\nmusicli --url http://myserver:8000/lofi-stream\nmusicli --url https://example.com/stream.m3u8\nmusicli --url https://www.youtube.com/watch?v=jfKfPfyJRdk\n```\n\nStream support is best-effort and meant for user-provided URLs.\n\n- If possible, prefer local folders or openly licensed packs.\n- YouTube support is optional and depends on third-party tooling such as `yt-dlp`.\n- Musicli is not affiliated with YouTube.\n- Accessing YouTube through third-party tools may violate YouTube's Terms of Service. If you use YouTube URLs, you are responsible for complying with YouTube's terms and any applicable law.\n\nInside the app, press `o` to open `Sources`.\n\n- `a` adds a local folder and opens the native folder picker when available\n- `u` opens the stream URL editor\n- `e` edits the selected saved source\n- `d` deletes it\n\nThe source editor still supports manual paths and URLs, but the local-folder flow now starts with browse-first behavior instead of making you remember the path.\n\nIt gives you:\n\n- one place to manage both local folders and stream URLs\n- real cursor editing for the URL or path when you need it\n- saved reusable stream sources alongside recent one-offs\n\nUse `o` anytime to reopen your sources.\n\n### Use a Local Folder\n\n```bash\nmusicli --folder ~/Music/Lofi\nmusicli --folder \"/Volumes/Archive/Focus Mixes\"\n```\n\nInside the app, press `o`, then `a`. On supported systems that opens a native folder picker; otherwise Musicli falls back to a manual path editor.\n\n### Load Open Lo-fi\n\n[`Open Lo-fi`](https://github.com/btahir/open-lofi) is a separate open music pack for Musicli, with `150+` lo-fi songs you can download and listen to locally.\n\nIf you want a ready-made library instead of pointing Musicli at your own folder, this is the easiest local-first option.\n\nThe simplest flow today is:\n\n1. Download `openlofi.zip` from the latest release.\n2. Extract it anywhere on your machine.\n3. Point Musicli at the extracted folder.\n\nExample:\n\n```bash\ncurl -L https://github.com/btahir/open-lofi/releases/latest/download/openlofi.zip -o openlofi.zip\nunzip openlofi.zip -d ~/Music/open-lofi\nmusicli --folder ~/Music/open-lofi\n```\n\nOr just run `musicli`, choose `Local Folder`, and pick the extracted `open-lofi` folder from the welcome flow.\n\nLocal folders can be:\n\n- a single folder full of tracks\n- a nested folder tree with subfolders\n\nMusicli scans recursively and picks up:\n\n- `aac`\n- `flac`\n- `m4a`\n- `mp3`\n- `ogg`\n- `opus`\n- `wav`\n\nFor nested folders, Musicli uses the first subfolder level as the category label inside search and queue metadata.\n\n### Manage the Library\n\n```bash\nmusicli library status\nmusicli library packs --source https://example.com/repository.json\nmusicli library install starter --source https://example.com/repository.json\nmusicli library install full --source https://example.com/repository.json\n```\n\n---\n\n## Controls\n\nThe footer keeps the primary actions visible. Press `?` for the full help card, and `/` to search without stopping playback.\n\n### Playback\n\n| Key | Action |\n|---|---|\n| `Space` | Pause or resume |\n| `n` / `b` | Next or previous track |\n| `[` / `]` | Seek backward or forward `10s` on local tracks |\n| `m` | Mute or unmute all audio |\n| `s` | Reshuffle the queue |\n| `o` | Open the sources manager |\n| `q` | Quit |\n\n### Welcome\n\n| Key | Action |\n|---|---|\n| `Left` / `Right` or `Up` / `Down` | Choose `Local Folder`, `Stream URL`, or `Saved Sources` |\n| `1` / `2` / `3` | Jump straight to the matching welcome option |\n| `Enter` | Continue with the selected option |\n| `q` | Quit from the idle start screen |\n\n### Sources\n\n| Key | Action |\n|---|---|\n| `o` | Open or close the sources manager |\n| `a` | Add a local folder, opening the native picker when available |\n| `u` | Add a stream URL |\n| `e` | Edit the selected source |\n| `d` | Delete the selected saved or recent source |\n| `Type` | Filter sources live as you type |\n| `Enter` | Open or use the selected source |\n| `Esc` | Clear the filter, then close |\n\n### Source Editor\n\n| Key | Action |\n|---|---|\n| `Up` / `Down` or `Tab` / `Shift+Tab` | Move between type, name, and target |\n| `Left` / `Right` | Switch source type or move the text cursor |\n| `Home` / `End` | Jump to the start or end of the field |\n| `Ctrl+a` / `Ctrl+e` | Jump to the start or end of the field |\n| `Ctrl+u` / `Ctrl+k` | Clear before or after the cursor |\n| `g` | Browse for a local folder while editing a local source |\n| `Backspace` / `Delete` | Edit the field under the cursor |\n| `Enter` | Save and use the source |\n| `Esc` | Cancel back to Sources |\n\n### Mixer and Scenes\n\n| Key | Action |\n|---|---|\n| `Up` / `Down` | Move between the `Track` row and `Ambience` rows |\n| `Left` / `Right` | Decrease or increase the selected level |\n| `+` / `-` | Fine-tune the selected level |\n| `1`-`7` | Jump to the `Track` row or ambience rows `01`-`07` |\n| `Tab` / `Shift+Tab` | Cycle scenes forward or back |\n| `v` | Scene-cycle alias |\n\n### Search and Help\n\n| Key | Action |\n|---|---|\n| `/` | Open song search |\n| `?` | Open or close the help overlay |\n| `Type` | Filter songs live as you type |\n| `Up` / `Down` or `j` / `k` | Move through search results |\n| `Tab` / `Shift+Tab` | Change search category scope |\n| `Enter` | Play the selected result |\n| `Esc` | Clear the query, then close |\n\n---\n\n## Presets\n\nThese are starting points, not locked modes. Adjust the ambience live and keep going.\n\n| Preset | Mood | Ambience | Scene |\n|---|---|---|---|\n| `study` | deep focus | none | city |\n| `chill` | coffee shop | cafe `0.30` | balcony |\n| `jazz` | smoky evening | cafe `0.20` | rooftop |\n| `sleep` | ambient drift | rain `0.20`, forest `0.15` | treehouse |\n| `night` | neon reflections | city `0.30`, rain `0.20` | alley |\n| `nature` | bamboo forest | forest `0.40`, rain `0.10` | park |\n| `soul` | warm soul | fire `0.30` | bookshop |\n| `snow` | winter quiet | fire `0.20` | porch |\n\n### Ambient Lanes\n\nThe current ambience set is tuned for longer sessions rather than short one-shot effects:\n\n- `rain`\n- `cafe`\n- `fire`\n- `thunder`\n- `forest`\n- `city`\n\n### Scenes\n\n- `alley`\n- `balcony`\n- `bookshop`\n- `city`\n- `park`\n- `porch`\n- `rooftop`\n- `treehouse`\n\n---\n\n## Library\n\nThe current app flow is local folders and stream URLs first. The `library` commands are there to support installable Musicli-curated packs and a future standalone library repo.\n\nThat gives `musicli` two useful modes:\n\n- it can work with installable Musicli packs\n- it can grow into a larger standalone library without changing the player architecture\n\nPack installs are manifest-driven. The CLI reads a local or remote `repository.json`, installs the selected pack into `~/.musicli/library`, and skips unchanged files on reinstall.\n\nThe main `musicli` package does not ship a music pack by default in this repo state, so `library packs` / `library install` should be used with `--source` unless you set `MUSICLI_LIBRARY_SOURCE`.\n\nUseful library commands:\n\n```bash\nmusicli library path\nmusicli library status\nmusicli library packs --source https://example.com/repository.json\nmusicli library install starter --source https://example.com/repository.json\nmusicli library install full --source https://example.com/repository.json\n```\n\n---\n\n## Development\n\n### Common Commands\n\n```bash\nnpm run dev\nnpm run build\nnpm test\n```\n\n### Library and Catalog Tooling\n\n```bash\nnpm run tracks:build\nnpm run library:stage\n```\n\n`npm run tracks:build` rebuilds the track catalog plus pack manifests.\n\n`npm run library:stage` stages a standalone library source tree in `dist/library-source/` so it can be published separately later.\n\n### How It Works\n\n- **Library**: track metadata lives in a generated catalog and installable packs are defined by manifests.\n- **Audio**: `ffmpeg` decodes and mixes the selected track plus active ambience loops, then streams PCM audio into `speaker`.\n- **Renderer**: a double-buffered ANSI renderer updates only changed terminal cells.\n- **Scenes**: PNG scene art is rendered through a portable cell renderer, with an optional `chafa` path for higher-detail terminal output.\n\n---\n\n## Disclaimer\n\n`musicli` is designed for use with local folders, installable library packs, and user-provided stream URLs. The safest path is to use local music you own or are licensed to play. Stream support is optional and best-effort.\n\n`musicli` is not affiliated with YouTube. Accessing YouTube through third-party tooling may violate YouTube's Terms of Service. If you use YouTube URLs or any other external source, you are responsible for making sure your use complies with the source platform's terms, the rights of the content owners, and any applicable law.\n\n---\n\n## License\n\nMIT\n","readmeFilename":"README.md"}